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_handler.h"
12 #include "packager/media/base/media_sample.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"
22 #include "packager/version/version.h"
28 int64_t kTimecodeScale = 1000000;
29 int64_t kSecondsToNs = 1000000000L;
32 Segmenter::Segmenter(
const MuxerOptions& options) : options_(options) {}
34 Segmenter::~Segmenter() {}
41 uint32_t max_sd_pixels,
42 uint32_t max_hd_pixels,
43 uint32_t max_uhd1_pixels,
44 double clear_lead_in_seconds) {
45 muxer_listener_ = muxer_listener;
47 clear_lead_ = clear_lead_in_seconds;
50 progress_target_ = info_->duration();
51 progress_listener_ = progress_listener;
54 segment_info_.set_timecode_scale(kTimecodeScale);
56 const std::string version = GetPackagerVersion();
57 if (!version.empty()) {
58 segment_info_.set_writing_app(
59 (GetPackagerProjectUrl() +
" version " + version).c_str());
62 if (options().segment_template.empty()) {
66 segment_info_.set_duration(1);
70 if (encryption_key_source) {
71 status = InitializeEncryptor(encryption_key_source,
80 switch (info_->stream_type()) {
82 status = CreateVideoTrack(static_cast<VideoStreamInfo*>(info_));
85 status = CreateAudioTrack(static_cast<AudioStreamInfo*>(info_));
88 NOTIMPLEMENTED() <<
"Not implemented for stream type: "
89 << info_->stream_type();
90 status =
Status(error::UNIMPLEMENTED,
"Not implemented for stream type");
95 return DoInitialize(std::move(writer));
100 prev_sample_->pts() - first_timestamp_ + prev_sample_->duration();
101 segment_info_.set_duration(FromBMFFTimescale(duration));
106 if (sample_duration_ == 0) {
107 first_timestamp_ = sample->pts();
108 sample_duration_ = sample->duration();
122 if (new_segment_ || new_subsegment_) {
123 status = NewSegment(sample->pts(), new_subsegment_);
125 status = WriteFrame(
false );
134 if (new_segment_ && !enable_encryption_) {
135 if (sample->pts() - first_timestamp_ >=
136 clear_lead_ * info_->time_scale()) {
137 enable_encryption_ =
true;
143 status = encryptor_->EncryptFrame(sample, enable_encryption_);
145 LOG(ERROR) <<
"Error encrypting frame.";
150 new_subsegment_ =
false;
151 new_segment_ =
false;
152 prev_sample_ = sample;
157 uint64_t duration_timescale,
158 bool is_subsegment) {
160 new_subsegment_ =
true;
163 return WriteFrame(
true );
167 return static_cast<float>(segment_info_.duration()) *
168 segment_info_.timecode_scale() / kSecondsToNs;
171 uint64_t Segmenter::FromBMFFTimescale(uint64_t time_timescale) {
173 const int64_t time_ns =
174 kSecondsToNs * time_timescale / info_->time_scale();
175 return time_ns / segment_info_.timecode_scale();
178 uint64_t Segmenter::FromWebMTimecode(uint64_t time_webm_timecode) {
180 const int64_t time_ns = time_webm_timecode * segment_info_.timecode_scale();
181 return time_ns * info_->time_scale() / kSecondsToNs;
185 Status error_status(error::FILE_FAILURE,
"Error writing segment header.");
187 if (!WriteEbmlHeader(writer))
190 if (WriteID(writer, mkvmuxer::kMkvSegment) != 0)
193 const uint64_t segment_size_size = 8;
194 segment_payload_pos_ = writer->
Position() + segment_size_size;
197 if (WriteUIntSize(writer, file_size - segment_payload_pos_,
198 segment_size_size) != 0)
200 if (!seek_head_.Write(writer))
203 if (SerializeInt(writer, mkvmuxer::kEbmlUnknownValue, segment_size_size) !=
207 if (!seek_head_.WriteVoid(writer))
211 seek_head_.set_info_pos(writer->
Position() - segment_payload_pos_);
212 if (!segment_info_.Write(writer))
215 seek_head_.set_tracks_pos(writer->
Position() - segment_payload_pos_);
216 if (!tracks_.Write(writer))
222 Status Segmenter::SetCluster(uint64_t start_webm_timecode,
225 const uint64_t scale = segment_info_.timecode_scale();
226 cluster_.reset(
new mkvmuxer::Cluster(start_webm_timecode, position, scale));
227 cluster_->Init(writer);
232 accumulated_progress_ += progress;
233 if (!progress_listener_ || progress_target_ == 0)
238 if (accumulated_progress_ >= progress_target_) {
241 progress_listener_->
OnProgress(static_cast<double>(accumulated_progress_) /
248 unsigned int seed = 0;
249 mkvmuxer::VideoTrack* track =
new mkvmuxer::VideoTrack(&seed);
251 return Status(error::INTERNAL_ERROR,
"Failed to create video track.");
253 if (info->codec() == kCodecVP8) {
254 track->set_codec_id(mkvmuxer::Tracks::kVp8CodecId);
255 }
else if (info->codec() == kCodecVP9) {
256 track->set_codec_id(mkvmuxer::Tracks::kVp9CodecId);
261 if (!vp_config.
ParseMP4(info->codec_config())) {
262 return Status(error::INTERNAL_ERROR,
263 "Unable to parse VP9 codec configuration");
266 std::vector<uint8_t> codec_config;
268 if (!track->SetCodecPrivate(codec_config.data(), codec_config.size())) {
269 return Status(error::INTERNAL_ERROR,
270 "Private codec data required for VP9 streams");
273 LOG(ERROR) <<
"Only VP8 and VP9 video codecs are supported.";
274 return Status(error::UNIMPLEMENTED,
275 "Only VP8 and VP9 video codecs are supported.");
278 track->set_uid(info->track_id());
279 if (!info->language().empty())
280 track->set_language(info->language().c_str());
281 track->set_type(mkvmuxer::Tracks::kVideo);
282 track->set_width(info->width());
283 track->set_height(info->height());
284 track->set_display_height(info->height());
285 track->set_display_width(info->width() * info->
pixel_width() /
289 encryptor_->AddTrackInfo(track);
291 tracks_.AddTrack(track, info->track_id());
292 track_id_ = track->number();
296 Status Segmenter::CreateAudioTrack(AudioStreamInfo* info) {
298 unsigned int seed = 0;
299 mkvmuxer::AudioTrack* track =
new mkvmuxer::AudioTrack(&seed);
301 return Status(error::INTERNAL_ERROR,
"Failed to create audio track.");
303 if (info->codec() == kCodecOpus) {
304 track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId);
305 }
else if (info->codec() == kCodecVorbis) {
306 track->set_codec_id(mkvmuxer::Tracks::kVorbisCodecId);
308 LOG(ERROR) <<
"Only Vorbis and Opus audio codec is supported.";
309 return Status(error::UNIMPLEMENTED,
310 "Only Vorbis and Opus audio codecs are supported.");
312 if (!track->SetCodecPrivate(info->codec_config().data(),
313 info->codec_config().size())) {
314 return Status(error::INTERNAL_ERROR,
315 "Private codec data required for audio streams");
318 track->set_uid(info->track_id());
319 if (!info->language().empty())
320 track->set_language(info->language().c_str());
321 track->set_type(mkvmuxer::Tracks::kAudio);
322 track->set_sample_rate(info->sampling_frequency());
323 track->set_channels(info->num_channels());
324 track->set_seek_pre_roll(info->seek_preroll_ns());
325 track->set_codec_delay(info->codec_delay_ns());
328 encryptor_->AddTrackInfo(track);
330 tracks_.AddTrack(track, info->track_id());
331 track_id_ = track->number();
335 Status Segmenter::InitializeEncryptor(KeySource* key_source,
336 uint32_t max_sd_pixels,
337 uint32_t max_hd_pixels,
338 uint32_t max_uhd1_pixels) {
339 encryptor_.reset(
new Encryptor());
340 const KeySource::TrackType track_type =
341 GetTrackTypeForEncryption(*info_, max_sd_pixels, max_hd_pixels,
343 if (track_type == KeySource::TrackType::TRACK_TYPE_UNKNOWN)
345 return encryptor_->Initialize(muxer_listener_, track_type, info_->codec(),
346 key_source, options_.webm_subsample_encryption);
349 Status Segmenter::WriteFrame(
bool write_duration) {
353 mkvmuxer::Frame frame;
355 if (!frame.Init(prev_sample_->data(), prev_sample_->data_size())) {
356 return Status(error::MUXER_FAILURE,
357 "Error adding sample to segment: Frame::Init failed");
360 if (write_duration) {
361 const uint64_t duration_ns =
362 prev_sample_->duration() * kSecondsToNs / info_->time_scale();
363 frame.set_duration(duration_ns);
365 frame.set_is_key(prev_sample_->is_key_frame());
366 frame.set_timestamp(prev_sample_->pts() * kSecondsToNs / info_->time_scale());
367 frame.set_track_number(track_id_);
369 if (prev_sample_->side_data_size() > 0) {
370 uint64_t block_add_id;
373 CHECK_GT(prev_sample_->side_data_size(),
sizeof(block_add_id));
374 memcpy(&block_add_id, prev_sample_->side_data(),
sizeof(block_add_id));
375 if (!frame.AddAdditionalData(
376 prev_sample_->side_data() +
sizeof(block_add_id),
377 prev_sample_->side_data_size() -
sizeof(block_add_id),
380 error::MUXER_FAILURE,
381 "Error adding sample to segment: Frame::AddAditionalData Failed");
385 if (!prev_sample_->is_key_frame() && !frame.CanBeSimpleBlock()) {
386 const int64_t timestamp_ns =
387 reference_frame_timestamp_ * kSecondsToNs / info_->time_scale();
388 frame.set_reference_block_timestamp(timestamp_ns);
393 if (cluster_->GetRelativeTimecode(frame.timestamp() /
394 cluster_->timecode_scale()) < 0) {
395 const double segment_duration =
396 static_cast<double>(frame.timestamp()) / kSecondsToNs;
397 LOG(ERROR) <<
"Error adding sample to segment: segment too large, "
398 << segment_duration <<
" seconds.";
399 return Status(error::MUXER_FAILURE,
400 "Error adding sample to segment: segment too large");
403 if (!cluster_->AddFrame(&frame)) {
404 return Status(error::MUXER_FAILURE,
405 "Error adding sample to segment: Cluster::AddFrame failed");
411 reference_frame_timestamp_ = prev_sample_->pts();