7 #include "packager/media/formats/webm/segmenter.h"
9 #include "packager/base/time/time.h"
10 #include "packager/media/base/audio_stream_info.h"
11 #include "packager/media/base/media_sample.h"
12 #include "packager/media/base/media_stream.h"
13 #include "packager/media/base/muxer_options.h"
14 #include "packager/media/base/muxer_util.h"
15 #include "packager/media/base/stream_info.h"
16 #include "packager/media/base/video_stream_info.h"
17 #include "packager/media/codecs/vp_codec_configuration_record.h"
18 #include "packager/media/event/muxer_listener.h"
19 #include "packager/media/event/progress_listener.h"
20 #include "packager/third_party/libwebm/src/mkvmuxerutil.hpp"
21 #include "packager/third_party/libwebm/src/webmids.hpp"
27 int64_t kTimecodeScale = 1000000;
28 int64_t kSecondsToNs = 1000000000L;
31 Segmenter::Segmenter(
const MuxerOptions& options)
32 : reference_frame_timestamp_(0),
35 muxer_listener_(NULL),
36 progress_listener_(NULL),
38 accumulated_progress_(0),
41 segment_payload_pos_(0),
42 cluster_length_sec_(0),
43 segment_length_sec_(0),
46 Segmenter::~Segmenter() {}
53 uint32_t max_sd_pixels,
54 double clear_lead_in_seconds) {
55 muxer_listener_ = muxer_listener;
57 clear_lead_ = clear_lead_in_seconds;
60 progress_target_ = info_->duration();
61 progress_listener_ = progress_listener;
63 const std::string version_string =
64 "https://github.com/google/shaka-packager version " +
68 segment_info_.set_timecode_scale(kTimecodeScale);
69 segment_info_.set_writing_app(version_string.c_str());
74 segment_info_.set_duration(1);
78 if (encryption_key_source) {
79 status = InitializeEncryptor(encryption_key_source, max_sd_pixels);
85 switch (info_->stream_type()) {
87 status = CreateVideoTrack(static_cast<VideoStreamInfo*>(info_));
90 status = CreateAudioTrack(static_cast<AudioStreamInfo*>(info_));
93 NOTIMPLEMENTED() <<
"Not implemented for stream type: "
94 << info_->stream_type();
95 status =
Status(error::UNIMPLEMENTED,
"Not implemented for stream type");
100 return DoInitialize(writer.Pass());
104 Status status = WriteFrame(
true );
109 prev_sample_->pts() - first_timestamp_ + prev_sample_->duration();
110 segment_info_.set_duration(FromBMFFTimescale(duration));
115 if (sample_duration_ == 0) {
116 first_timestamp_ = sample->pts();
117 sample_duration_ = sample->duration();
131 bool wrote_frame =
false;
133 status = NewSegment(sample->pts());
138 status = WriteFrame(
true );
139 status.Update(NewSegment(sample->pts()));
140 segment_length_sec_ = 0;
141 cluster_length_sec_ = 0;
146 status = WriteFrame(
true );
147 status.Update(NewSubsegment(sample->pts()));
148 cluster_length_sec_ = 0;
153 status = WriteFrame(
false );
160 const bool encrypt_frame =
161 static_cast<double>(sample->pts() - first_timestamp_) /
162 info_->time_scale() >=
164 status = encryptor_->EncryptFrame(sample, encrypt_frame);
166 LOG(ERROR) <<
"Error encrypting frame.";
175 const double duration_sec =
176 static_cast<double>(sample->duration()) / info_->time_scale();
177 cluster_length_sec_ += duration_sec;
178 segment_length_sec_ += duration_sec;
180 prev_sample_ = sample;
185 return static_cast<float>(segment_info_.duration()) *
186 segment_info_.timecode_scale() / kSecondsToNs;
189 uint64_t Segmenter::FromBMFFTimescale(uint64_t time_timescale) {
191 const int64_t time_ns =
192 kSecondsToNs * time_timescale / info_->time_scale();
193 return time_ns / segment_info_.timecode_scale();
196 uint64_t Segmenter::FromWebMTimecode(uint64_t time_webm_timecode) {
198 const int64_t time_ns = time_webm_timecode * segment_info_.timecode_scale();
199 return time_ns * info_->time_scale() / kSecondsToNs;
203 Status error_status(error::FILE_FAILURE,
"Error writing segment header.");
205 if (!WriteEbmlHeader(writer))
208 if (WriteID(writer, mkvmuxer::kMkvSegment) != 0)
211 const uint64_t segment_size_size = 8;
212 segment_payload_pos_ = writer->
Position() + segment_size_size;
215 if (WriteUIntSize(writer, file_size - segment_payload_pos_,
216 segment_size_size) != 0)
218 if (!seek_head_.Write(writer))
221 if (SerializeInt(writer, mkvmuxer::kEbmlUnknownValue, segment_size_size) !=
225 if (!seek_head_.WriteVoid(writer))
229 seek_head_.set_info_pos(writer->
Position() - segment_payload_pos_);
230 if (!segment_info_.Write(writer))
233 seek_head_.set_tracks_pos(writer->
Position() - segment_payload_pos_);
234 if (!tracks_.Write(writer))
240 Status Segmenter::SetCluster(uint64_t start_webm_timecode,
243 const uint64_t scale = segment_info_.timecode_scale();
244 cluster_.reset(
new mkvmuxer::Cluster(start_webm_timecode, position, scale));
245 cluster_->Init(writer);
250 accumulated_progress_ += progress;
251 if (!progress_listener_ || progress_target_ == 0)
256 if (accumulated_progress_ >= progress_target_) {
259 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
266 unsigned int seed = 0;
267 mkvmuxer::VideoTrack* track =
new mkvmuxer::VideoTrack(&seed);
269 return Status(error::INTERNAL_ERROR,
"Failed to create video track.");
271 if (info->codec() == kCodecVP8) {
272 track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId);
273 }
else if (info->codec() == kCodecVP9) {
274 track->set_codec_id(mkvmuxer::Tracks::kVp9CodecId);
279 if (!vp_config.
ParseMP4(info->extra_data())) {
280 return Status(error::INTERNAL_ERROR,
281 "Unable to parse VP9 codec configuration");
284 std::vector<uint8_t> extra_data;
286 if (!track->SetCodecPrivate(extra_data.data(), extra_data.size())) {
287 return Status(error::INTERNAL_ERROR,
288 "Private codec data required for VP9 streams");
291 LOG(ERROR) <<
"Only VP8 and VP9 video codecs are supported.";
292 return Status(error::UNIMPLEMENTED,
293 "Only VP8 and VP9 video codecs are supported.");
296 track->set_uid(info->track_id());
297 if (!info->language().empty())
298 track->set_language(info->language().c_str());
299 track->set_type(mkvmuxer::Tracks::kVideo);
300 track->set_width(info->width());
301 track->set_height(info->height());
302 track->set_display_height(info->height());
303 track->set_display_width(info->width() * info->
pixel_width() /
307 encryptor_->AddTrackInfo(track);
309 tracks_.AddTrack(track, info->track_id());
310 track_id_ = track->number();
314 Status Segmenter::CreateAudioTrack(AudioStreamInfo* info) {
316 unsigned int seed = 0;
317 mkvmuxer::AudioTrack* track =
new mkvmuxer::AudioTrack(&seed);
319 return Status(error::INTERNAL_ERROR,
"Failed to create audio track.");
321 if (info->codec() == kCodecOpus) {
322 track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId);
323 }
else if (info->codec() == kCodecVorbis) {
324 track->set_codec_id(mkvmuxer::Tracks::kVorbisCodecId);
326 LOG(ERROR) <<
"Only Vorbis and Opus audio codec is supported.";
327 return Status(error::UNIMPLEMENTED,
328 "Only Vorbis and Opus audio codecs are supported.");
330 if (!track->SetCodecPrivate(info->extra_data().data(),
331 info->extra_data().size())) {
332 return Status(error::INTERNAL_ERROR,
333 "Private codec data required for audio streams");
336 track->set_uid(info->track_id());
337 if (!info->language().empty())
338 track->set_language(info->language().c_str());
339 track->set_type(mkvmuxer::Tracks::kAudio);
340 track->set_sample_rate(info->sampling_frequency());
341 track->set_channels(info->num_channels());
342 track->set_seek_pre_roll(info->seek_preroll_ns());
343 track->set_codec_delay(info->codec_delay_ns());
346 encryptor_->AddTrackInfo(track);
348 tracks_.AddTrack(track, info->track_id());
349 track_id_ = track->number();
353 Status Segmenter::InitializeEncryptor(KeySource* key_source,
354 uint32_t max_sd_pixels) {
355 encryptor_.reset(
new Encryptor());
356 const KeySource::TrackType track_type =
357 GetTrackTypeForEncryption(*info_, max_sd_pixels);
358 if (track_type == KeySource::TrackType::TRACK_TYPE_UNKNOWN)
360 return encryptor_->Initialize(muxer_listener_, track_type, key_source);
363 Status Segmenter::WriteFrame(
bool write_duration) {
367 mkvmuxer::Frame frame;
369 if (!frame.Init(prev_sample_->data(), prev_sample_->data_size())) {
370 return Status(error::MUXER_FAILURE,
371 "Error adding sample to segment: Frame::Init failed");
374 if (write_duration) {
375 const uint64_t duration_ns =
376 prev_sample_->duration() * kSecondsToNs / info_->time_scale();
377 frame.set_duration(duration_ns);
379 frame.set_is_key(prev_sample_->is_key_frame());
380 frame.set_timestamp(prev_sample_->pts() * kSecondsToNs / info_->time_scale());
381 frame.set_track_number(track_id_);
383 if (prev_sample_->side_data_size() > 0) {
384 uint64_t block_add_id;
387 CHECK_GT(prev_sample_->side_data_size(),
sizeof(block_add_id));
388 memcpy(&block_add_id, prev_sample_->side_data(),
sizeof(block_add_id));
389 if (!frame.AddAdditionalData(
390 prev_sample_->side_data() +
sizeof(block_add_id),
391 prev_sample_->side_data_size() -
sizeof(block_add_id),
394 error::MUXER_FAILURE,
395 "Error adding sample to segment: Frame::AddAditionalData Failed");
399 if (!prev_sample_->is_key_frame() && !frame.CanBeSimpleBlock()) {
400 const int64_t timestamp_ns =
401 reference_frame_timestamp_ * kSecondsToNs / info_->time_scale();
402 frame.set_reference_block_timestamp(timestamp_ns);
407 if (cluster_->GetRelativeTimecode(frame.timestamp() /
408 cluster_->timecode_scale()) < 0) {
409 const double segment_duration =
410 static_cast<double>(frame.timestamp()) / kSecondsToNs;
411 LOG(ERROR) <<
"Error adding sample to segment: segment too large, "
412 << segment_duration <<
" seconds.";
413 return Status(error::MUXER_FAILURE,
414 "Error adding sample to segment: segment too large");
417 if (!cluster_->AddFrame(&frame)) {
418 return Status(error::MUXER_FAILURE,
419 "Error adding sample to segment: Cluster::AddFrame failed");
425 reference_frame_timestamp_ = prev_sample_->pts();