Shaka Packager SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
ts_segmenter.cc
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/formats/mp2t/ts_segmenter.h"
8 
9 #include <memory>
10 
11 #include "packager/media/base/muxer_util.h"
12 #include "packager/media/event/muxer_listener.h"
13 #include "packager/status.h"
14 
15 namespace shaka {
16 namespace media {
17 namespace mp2t {
18 
19 namespace {
20 const double kTsTimescale = 90000;
21 } // namespace
22 
24  : muxer_options_(options),
25  listener_(listener),
26  ts_writer_(new TsWriter()),
27  pes_packet_generator_(new PesPacketGenerator()) {}
28 TsSegmenter::~TsSegmenter() {}
29 
31  if (muxer_options_.segment_template.empty())
32  return Status(error::MUXER_FAILURE, "Segment template not specified.");
33  if (!ts_writer_->Initialize(stream_info))
34  return Status(error::MUXER_FAILURE, "Failed to initialize TsWriter.");
35  if (!pes_packet_generator_->Initialize(stream_info)) {
36  return Status(error::MUXER_FAILURE,
37  "Failed to initialize PesPacketGenerator.");
38  }
39 
40  timescale_scale_ = kTsTimescale / stream_info.time_scale();
41  return Status::OK;
42 }
43 
45  return Status::OK;
46 }
47 
49  if (sample.is_encrypted())
50  ts_writer_->SignalEncrypted();
51 
52  if (!ts_writer_file_opened_ && !sample.is_key_frame())
53  LOG(WARNING) << "A segment will start with a non key frame.";
54 
55  if (!pes_packet_generator_->PushSample(sample)) {
56  return Status(error::MUXER_FAILURE,
57  "Failed to add sample to PesPacketGenerator.");
58  }
59  return WritePesPacketsToFile();
60 }
61 
62 void TsSegmenter::InjectTsWriterForTesting(std::unique_ptr<TsWriter> writer) {
63  ts_writer_ = std::move(writer);
64 }
65 
67  std::unique_ptr<PesPacketGenerator> generator) {
68  pes_packet_generator_ = std::move(generator);
69 }
70 
72  ts_writer_file_opened_ = value;
73 }
74 
75 Status TsSegmenter::OpenNewSegmentIfClosed(uint32_t next_pts) {
76  if (ts_writer_file_opened_)
77  return Status::OK;
78  const std::string segment_name =
79  GetSegmentName(muxer_options_.segment_template, next_pts,
80  segment_number_++, muxer_options_.bandwidth);
81  if (!ts_writer_->NewSegment(segment_name))
82  return Status(error::MUXER_FAILURE, "Failed to initilize TsPacketWriter.");
83  current_segment_path_ = segment_name;
84  ts_writer_file_opened_ = true;
85  return Status::OK;
86 }
87 
88 Status TsSegmenter::WritePesPacketsToFile() {
89  while (pes_packet_generator_->NumberOfReadyPesPackets() > 0u) {
90  std::unique_ptr<PesPacket> pes_packet =
91  pes_packet_generator_->GetNextPesPacket();
92 
93  Status status = OpenNewSegmentIfClosed(pes_packet->pts());
94  if (!status.ok())
95  return status;
96 
97  if (!ts_writer_->AddPesPacket(std::move(pes_packet)))
98  return Status(error::MUXER_FAILURE, "Failed to add PES packet.");
99  }
100  return Status::OK;
101 }
102 
103 Status TsSegmenter::FinalizeSegment(uint64_t start_timestamp,
104  uint64_t duration) {
105  if (!pes_packet_generator_->Flush()) {
106  return Status(error::MUXER_FAILURE,
107  "Failed to flush PesPacketGenerator.");
108  }
109  Status status = WritePesPacketsToFile();
110  if (!status.ok())
111  return status;
112 
113  // This method may be called from Finalize() so ts_writer_file_opened_ could
114  // be false.
115  if (ts_writer_file_opened_) {
116  if (!ts_writer_->FinalizeSegment()) {
117  return Status(error::MUXER_FAILURE, "Failed to finalize TsWriter.");
118  }
119  if (listener_) {
120  const int64_t file_size =
121  File::GetFileSize(current_segment_path_.c_str());
122  listener_->OnNewSegment(current_segment_path_,
123  start_timestamp * timescale_scale_,
124  duration * timescale_scale_, file_size);
125  }
126  ts_writer_file_opened_ = false;
127  }
128  current_segment_path_.clear();
129  return Status::OK;
130 }
131 
132 } // namespace mp2t
133 } // namespace media
134 } // namespace shaka
virtual void OnNewSegment(const std::string &segment_name, uint64_t start_time, uint64_t duration, uint64_t segment_file_size)=0
Abstract class holds stream information.
Definition: stream_info.h:58
Status Initialize(const StreamInfo &stream_info)
Definition: ts_segmenter.cc:30
static int64_t GetFileSize(const char *file_name)
Definition: file.cc:207
This structure contains the list of configuration options for Muxer.
Definition: muxer_options.h:20
Status AddSample(const MediaSample &sample)
Definition: ts_segmenter.cc:48
TsSegmenter(const MuxerOptions &options, MuxerListener *listener)
Definition: ts_segmenter.cc:23
void InjectPesPacketGeneratorForTesting(std::unique_ptr< PesPacketGenerator > generator)
Only for testing.
Definition: ts_segmenter.cc:66
void SetTsWriterFileOpenedForTesting(bool value)
Only for testing.
Definition: ts_segmenter.cc:71
void InjectTsWriterForTesting(std::unique_ptr< TsWriter > writer)
Only for testing.
Definition: ts_segmenter.cc:62
Class to hold a media sample.
Definition: media_sample.h:22
Status FinalizeSegment(uint64_t start_timestamp, uint64_t duration)