7 #include "packager/media/formats/mp2t/ts_segmenter.h" 11 #include "packager/media/base/audio_stream_info.h" 12 #include "packager/media/base/muxer_util.h" 13 #include "packager/media/base/video_stream_info.h" 14 #include "packager/media/event/muxer_listener.h" 15 #include "packager/media/formats/mp2t/pes_packet.h" 16 #include "packager/media/formats/mp2t/program_map_table_writer.h" 17 #include "packager/status.h" 24 const double kTsTimescale = 90000;
26 bool IsAudioCodec(Codec codec) {
27 return codec >= kCodecAudio && codec < kCodecAudioMaxPlusOne;
30 bool IsVideoCodec(Codec codec) {
31 return codec >= kCodecVideo && codec < kCodecVideoMaxPlusOne;
37 : muxer_options_(options),
40 TsSegmenter::~TsSegmenter() {}
44 return Status(error::MUXER_FAILURE,
"Segment template not specified.");
45 if (!pes_packet_generator_->Initialize(stream_info)) {
46 return Status(error::MUXER_FAILURE,
47 "Failed to initialize PesPacketGenerator.");
50 const StreamType stream_type = stream_info.stream_type();
51 if (stream_type != StreamType::kStreamVideo &&
52 stream_type != StreamType::kStreamAudio) {
53 LOG(ERROR) <<
"TsWriter cannot handle stream type " << stream_type
55 return Status(error::MUXER_FAILURE,
"Unsupported stream type.");
58 codec_ = stream_info.codec();
59 if (stream_type == StreamType::kStreamAudio)
60 audio_codec_config_ = stream_info.codec_config();
62 timescale_scale_ = kTsTimescale / stream_info.time_scale();
72 std::unique_ptr<ProgramMapTableWriter> pmt_writer;
73 if (codec_ == kCodecAC3) {
80 const size_t kSetupDataSize = 10u;
81 if (sample.data_size() < kSetupDataSize) {
82 LOG(ERROR) <<
"Sample is too small for AC3: " << sample.data_size();
83 return Status(error::MUXER_FAILURE,
"Sample is too small for AC3.");
85 const std::vector<uint8_t> setup_data(sample.data(),
86 sample.data() + kSetupDataSize);
88 }
else if (IsAudioCodec(codec_)) {
92 DCHECK(IsVideoCodec(codec_));
95 ts_writer_.reset(
new TsWriter(std::move(pmt_writer)));
98 if (sample.is_encrypted())
99 ts_writer_->SignalEncrypted();
101 if (!ts_writer_file_opened_ && !sample.is_key_frame())
102 LOG(WARNING) <<
"A segment will start with a non key frame.";
104 if (!pes_packet_generator_->PushSample(sample)) {
105 return Status(error::MUXER_FAILURE,
106 "Failed to add sample to PesPacketGenerator.");
108 return WritePesPacketsToFile();
112 ts_writer_ = std::move(writer);
116 std::unique_ptr<PesPacketGenerator> generator) {
117 pes_packet_generator_ = std::move(generator);
121 ts_writer_file_opened_ = value;
124 Status TsSegmenter::OpenNewSegmentIfClosed(uint32_t next_pts) {
125 if (ts_writer_file_opened_)
127 const std::string segment_name =
129 segment_number_++, muxer_options_.
bandwidth);
130 if (!ts_writer_->NewSegment(segment_name))
131 return Status(error::MUXER_FAILURE,
"Failed to initilize TsPacketWriter.");
132 current_segment_path_ = segment_name;
133 ts_writer_file_opened_ =
true;
137 Status TsSegmenter::WritePesPacketsToFile() {
138 while (pes_packet_generator_->NumberOfReadyPesPackets() > 0u) {
139 std::unique_ptr<PesPacket> pes_packet =
140 pes_packet_generator_->GetNextPesPacket();
142 Status status = OpenNewSegmentIfClosed(pes_packet->pts());
146 if (listener_ && IsVideoCodec(codec_) && pes_packet->is_key_frame()) {
147 base::Optional<uint64_t> start_pos = ts_writer_->GetFilePosition();
149 const int64_t timestamp = pes_packet->pts();
150 if (!ts_writer_->AddPesPacket(std::move(pes_packet)))
151 return Status(error::MUXER_FAILURE,
"Failed to add PES packet.");
153 base::Optional<uint64_t> end_pos = ts_writer_->GetFilePosition();
154 if (!start_pos || !end_pos) {
155 return Status(error::MUXER_FAILURE,
156 "Failed to get file position in WritePesPacketsToFile.");
158 listener_->
OnKeyFrame(timestamp, *start_pos, *end_pos - *start_pos);
160 if (!ts_writer_->AddPesPacket(std::move(pes_packet)))
161 return Status(error::MUXER_FAILURE,
"Failed to add PES packet.");
169 if (!pes_packet_generator_->Flush()) {
170 return Status(error::MUXER_FAILURE,
171 "Failed to flush PesPacketGenerator.");
173 Status status = WritePesPacketsToFile();
179 if (ts_writer_file_opened_) {
180 if (!ts_writer_->FinalizeSegment()) {
181 return Status(error::MUXER_FAILURE,
"Failed to finalize TsWriter.");
184 const int64_t file_size =
187 start_timestamp * timescale_scale_,
188 duration * timescale_scale_, file_size);
190 ts_writer_file_opened_ =
false;
192 current_segment_path_.clear();
All the methods that are virtual are virtual for mocking.
static int64_t GetFileSize(const char *file_name)