DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
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/base/status.h"
13 
14 namespace edash_packager {
15 namespace media {
16 namespace mp2t {
17 
18 namespace {
19 const double kTsTimescale = 90000;
20 } // namespace
21 
23  : muxer_options_(options),
24  ts_writer_(new TsWriter()),
25  pes_packet_generator_(new PesPacketGenerator()) {}
26 TsSegmenter::~TsSegmenter() {}
27 
29  if (muxer_options_.segment_template.empty())
30  return Status(error::MUXER_FAILURE, "Segment template not specified.");
31  if (!ts_writer_->Initialize(stream_info))
32  return Status(error::MUXER_FAILURE, "Failed to initialize TsWriter.");
33  if (!pes_packet_generator_->Initialize(stream_info)) {
34  return Status(error::MUXER_FAILURE,
35  "Failed to initialize PesPacketGenerator.");
36  }
37 
38  timescale_scale_ = kTsTimescale / stream_info.time_scale();
39  return Status::OK;
40 }
41 
43  return Flush();
44 }
45 
46 // First checks whether the sample is a key frame. If so and the segment has
47 // passed the segment duration, then flush the generator and write all the data
48 // to file.
49 Status TsSegmenter::AddSample(scoped_refptr<MediaSample> sample) {
50  const bool passed_segment_duration =
51  current_segment_total_sample_duration_ > muxer_options_.segment_duration;
52  if (sample->is_key_frame() && passed_segment_duration) {
53  Status status = Flush();
54  if (!status.ok())
55  return status;
56  }
57 
58  if (!ts_writer_file_opened_ && !sample->is_key_frame())
59  LOG(WARNING) << "A segment will start with a non key frame.";
60 
61  if (!pes_packet_generator_->PushSample(sample)) {
62  return Status(error::MUXER_FAILURE,
63  "Failed to add sample to PesPacketGenerator.");
64  }
65 
66  const double scaled_sample_duration = sample->duration() * timescale_scale_;
67  current_segment_total_sample_duration_ +=
68  scaled_sample_duration / kTsTimescale;
69 
70  return WritePesPacketsToFile();
71 }
72 
73 void TsSegmenter::InjectTsWriterForTesting(scoped_ptr<TsWriter> writer) {
74  ts_writer_ = writer.Pass();
75 }
76 
78  scoped_ptr<PesPacketGenerator> generator) {
79  pes_packet_generator_ = generator.Pass();
80 }
81 
83  ts_writer_file_opened_ = value;
84 }
85 
86 Status TsSegmenter::OpenNewSegmentIfClosed(uint32_t next_pts) {
87  if (ts_writer_file_opened_)
88  return Status::OK;
89  const std::string segment_name =
90  GetSegmentName(muxer_options_.segment_template, next_pts,
91  segment_number_++, muxer_options_.bandwidth);
92  if (!ts_writer_->NewSegment(segment_name))
93  return Status(error::MUXER_FAILURE, "Failed to initilize TsPacketWriter.");
94  ts_writer_file_opened_ = true;
95  return Status::OK;
96 }
97 
98 Status TsSegmenter::WritePesPacketsToFile() {
99  while (pes_packet_generator_->NumberOfReadyPesPackets() > 0u) {
100  scoped_ptr<PesPacket> pes_packet =
101  pes_packet_generator_->GetNextPesPacket();
102 
103  Status status = OpenNewSegmentIfClosed(pes_packet->pts());
104  if (!status.ok())
105  return status;
106 
107  if (!ts_writer_->AddPesPacket(pes_packet.Pass()))
108  return Status(error::MUXER_FAILURE, "Failed to add PES packet.");
109  }
110  return Status::OK;
111 }
112 
113 Status TsSegmenter::Flush() {
114  if (!pes_packet_generator_->Flush()) {
115  return Status(error::MUXER_FAILURE,
116  "Failed to flush PesPacketGenerator.");
117  }
118  Status status = WritePesPacketsToFile();
119  if (!status.ok())
120  return status;
121 
122  // This method may be called from Finalize() so ts_writer_file_opened_ could
123  // be false.
124  if (ts_writer_file_opened_) {
125  if (!ts_writer_->FinalizeSegment()) {
126  return Status(error::MUXER_FAILURE, "Failed to finalize TsWriter.");
127  }
128  ts_writer_file_opened_ = false;
129  }
130  current_segment_total_sample_duration_ = 0.0;
131  return Status::OK;
132 }
133 
134 } // namespace mp2t
135 } // namespace media
136 } // namespace edash_packager
Status Initialize(const StreamInfo &stream_info)
Definition: ts_segmenter.cc:28
Abstract class holds stream information.
Definition: stream_info.h:26
void SetTsWriterFileOpenedForTesting(bool value)
Only for testing.
Definition: ts_segmenter.cc:82
void InjectTsWriterForTesting(scoped_ptr< TsWriter > writer)
Only for testing.
Definition: ts_segmenter.cc:73
Status AddSample(scoped_refptr< MediaSample > sample)
Definition: ts_segmenter.cc:49
void InjectPesPacketGeneratorForTesting(scoped_ptr< PesPacketGenerator > generator)
Only for testing.
Definition: ts_segmenter.cc:77
TsSegmenter(const MuxerOptions &options)
Definition: ts_segmenter.cc:22
This structure contains the list of configuration options for Muxer.
Definition: muxer_options.h:18