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