5 #include "packager/media/formats/webm/webm_cluster_parser.h"
10 #include "packager/base/logging.h"
11 #include "packager/base/sys_byteorder.h"
12 #include "packager/media/base/decrypt_config.h"
13 #include "packager/media/base/timestamp.h"
14 #include "packager/media/codecs/vp8_parser.h"
15 #include "packager/media/codecs/vp9_parser.h"
16 #include "packager/media/codecs/webvtt_util.h"
17 #include "packager/media/formats/webm/webm_constants.h"
18 #include "packager/media/formats/webm/webm_crypto_helpers.h"
19 #include "packager/media/formats/webm/webm_webvtt_parser.h"
25 const int64_t kMicrosecondsPerMillisecond = 1000;
30 int64_t timecode_scale,
31 std::shared_ptr<AudioStreamInfo> audio_stream_info,
32 std::shared_ptr<VideoStreamInfo> video_stream_info,
34 int64_t audio_default_duration,
35 int64_t video_default_duration,
36 const WebMTracksParser::TextTracks& text_tracks,
37 const std::set<int64_t>& ignored_tracks,
38 const std::string& audio_encryption_key_id,
39 const std::string& video_encryption_key_id,
43 : timecode_multiplier_(timecode_scale /
44 static_cast<double>(kMicrosecondsPerMillisecond)),
45 audio_stream_info_(audio_stream_info),
46 video_stream_info_(video_stream_info),
47 vp_config_(vp_config),
48 ignored_tracks_(ignored_tracks),
49 audio_encryption_key_id_(audio_encryption_key_id),
50 video_encryption_key_id_(video_encryption_key_id),
51 parser_(kWebMIdCluster, this),
54 cluster_start_time_(kNoTimestamp),
55 audio_(audio_stream_info ? audio_stream_info->track_id() : -1,
57 audio_default_duration,
59 video_(video_stream_info ? video_stream_info->track_id() : -1,
61 video_default_duration,
63 if (decryption_key_source) {
65 if (audio_stream_info_)
66 audio_stream_info_->set_is_encrypted(
false);
67 if (video_stream_info_)
68 video_stream_info_->set_is_encrypted(
false);
70 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
71 it != text_tracks.end();
73 text_track_map_.insert(std::make_pair(
74 it->first, Track(it->first,
false, kNoTimestamp, new_sample_cb)));
78 WebMClusterParser::~WebMClusterParser() {}
81 last_block_timecode_ = -1;
82 cluster_timecode_ = -1;
83 cluster_start_time_ = kNoTimestamp;
84 cluster_ended_ =
false;
93 bool audio_result = audio_.ApplyDurationEstimateIfNeeded();
94 bool video_result = video_.ApplyDurationEstimateIfNeeded();
96 return audio_result && video_result;
100 int result = parser_.
Parse(buf, size);
103 cluster_ended_ =
false;
108 if (cluster_ended_) {
111 if (cluster_start_time_ == kNoTimestamp) {
114 if (cluster_timecode_ < 0)
117 cluster_start_time_ = cluster_timecode_ * timecode_multiplier_;
125 last_block_timecode_ = -1;
126 cluster_timecode_ = -1;
133 if (
id == kWebMIdCluster) {
134 cluster_timecode_ = -1;
135 cluster_start_time_ = kNoTimestamp;
136 }
else if (
id == kWebMIdBlockGroup) {
138 block_data_size_ = -1;
139 block_duration_ = -1;
140 discard_padding_ = -1;
141 discard_padding_set_ =
false;
142 reference_block_set_ =
false;
143 }
else if (
id == kWebMIdBlockAdditions) {
145 block_additional_data_.reset();
146 block_additional_data_size_ = 0;
152 bool WebMClusterParser::OnListEnd(
int id) {
153 if (
id != kWebMIdBlockGroup)
157 if (block_data_size_ == -1) {
158 LOG(ERROR) <<
"Block missing from BlockGroup.";
162 bool result = ParseBlock(
163 false, block_data_.get(), block_data_size_, block_additional_data_.get(),
164 block_additional_data_size_, block_duration_,
165 discard_padding_set_ ? discard_padding_ : 0, reference_block_set_);
167 block_data_size_ = -1;
168 block_duration_ = -1;
170 block_additional_data_.reset();
171 block_additional_data_size_ = 0;
172 discard_padding_ = -1;
173 discard_padding_set_ =
false;
174 reference_block_set_ =
false;
178 bool WebMClusterParser::OnUInt(
int id, int64_t val) {
181 case kWebMIdTimecode:
182 dst = &cluster_timecode_;
184 case kWebMIdBlockDuration:
185 dst = &block_duration_;
187 case kWebMIdBlockAddID:
188 dst = &block_add_id_;
199 bool WebMClusterParser::ParseBlock(
bool is_simple_block,
202 const uint8_t* additional,
205 int64_t discard_padding,
206 bool reference_block_set) {
212 if (!(buf[0] & 0x80)) {
213 LOG(ERROR) <<
"TrackNumber over 127 not supported";
217 int track_num = buf[0] & 0x7f;
218 int timecode = buf[1] << 8 | buf[2];
219 int flags = buf[3] & 0xff;
220 int lacing = (flags >> 1) & 0x3;
223 LOG(ERROR) <<
"Lacing " << lacing <<
" is not supported yet.";
228 if (timecode & 0x8000)
236 is_simple_block ? (flags & 0x80) != 0 : !reference_block_set;
238 const uint8_t* frame_data = buf + 4;
239 int frame_size = size - (frame_data - buf);
240 return OnBlock(is_simple_block, track_num, timecode, duration, frame_data,
241 frame_size, additional, additional_size, discard_padding,
245 bool WebMClusterParser::OnBinary(
int id,
const uint8_t* data,
int size) {
247 case kWebMIdSimpleBlock:
248 return ParseBlock(
true, data, size, NULL, 0, -1, 0,
false);
252 LOG(ERROR) <<
"More than 1 Block in a BlockGroup is not "
256 block_data_.reset(
new uint8_t[size]);
257 memcpy(block_data_.get(), data, size);
258 block_data_size_ = size;
261 case kWebMIdBlockAdditional: {
262 uint64_t block_add_id = base::HostToNet64(block_add_id_);
263 if (block_additional_data_) {
268 LOG(ERROR) <<
"More than 1 BlockAdditional in a "
269 "BlockGroup is not supported.";
275 block_additional_data_size_ = size +
sizeof(block_add_id);
276 block_additional_data_.reset(
new uint8_t[block_additional_data_size_]);
277 memcpy(block_additional_data_.get(), &block_add_id,
278 sizeof(block_add_id));
279 memcpy(block_additional_data_.get() + 8, data, size);
282 case kWebMIdDiscardPadding: {
283 if (discard_padding_set_ || size <= 0 || size > 8)
285 discard_padding_set_ =
true;
288 discard_padding_ =
static_cast<int8_t
>(data[0]);
289 for (
int i = 1; i < size; ++i)
290 discard_padding_ = (discard_padding_ << 8) | data[i];
294 case kWebMIdReferenceBlock:
298 reference_block_set_ =
true;
305 bool WebMClusterParser::OnBlock(
bool is_simple_block,
311 const uint8_t* additional,
313 int64_t discard_padding,
316 if (cluster_timecode_ == -1) {
317 LOG(ERROR) <<
"Got a block before cluster timecode.";
324 LOG(ERROR) <<
"Got a block with negative timecode offset " << timecode;
328 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
329 LOG(ERROR) <<
"Got a block with a timecode before the previous block.";
334 StreamType stream_type = kStreamUnknown;
335 std::string encryption_key_id;
336 if (track_num == audio_.track_num()) {
338 encryption_key_id = audio_encryption_key_id_;
339 stream_type = kStreamAudio;
340 }
else if (track_num == video_.track_num()) {
342 encryption_key_id = video_encryption_key_id_;
343 stream_type = kStreamVideo;
344 }
else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) {
346 }
else if (Track*
const text_track = FindTextTrack(track_num)) {
349 if (block_duration < 0)
352 stream_type = kStreamText;
354 LOG(ERROR) <<
"Unexpected track number " << track_num;
357 DCHECK_NE(stream_type, kStreamUnknown);
359 last_block_timecode_ = timecode;
361 int64_t timestamp = (cluster_timecode_ + timecode) * timecode_multiplier_;
363 std::shared_ptr<MediaSample> buffer;
364 if (stream_type != kStreamText) {
368 std::unique_ptr<DecryptConfig> decrypt_config;
370 if (!encryption_key_id.empty() &&
371 !WebMCreateDecryptConfig(
373 reinterpret_cast<const uint8_t*
>(encryption_key_id.data()),
374 encryption_key_id.size(),
375 &decrypt_config, &data_offset)) {
379 const uint8_t* media_data = data + data_offset;
380 const size_t media_data_size = size - data_offset;
383 const size_t kDummyDataSize = 0;
385 additional_size, is_key_frame);
387 if (decrypt_config) {
388 if (!decryptor_source_) {
389 buffer->SetData(media_data, media_data_size);
392 buffer->set_decrypt_config(std::move(decrypt_config));
393 buffer->set_is_encrypted(
true);
395 std::shared_ptr<uint8_t> decrypted_media_data(
396 new uint8_t[media_data_size], std::default_delete<uint8_t[]>());
397 if (!decryptor_source_->DecryptSampleBuffer(
398 decrypt_config.get(), media_data, media_data_size,
399 decrypted_media_data.get())) {
400 LOG(ERROR) <<
"Cannot decrypt samples";
403 buffer->TransferData(std::move(decrypted_media_data), media_data_size);
406 buffer->SetData(media_data, media_data_size);
409 std::string id, settings, content;
412 std::vector<uint8_t> side_data;
413 MakeSideData(
id.begin(),
id.end(),
414 settings.begin(), settings.end(),
418 reinterpret_cast<const uint8_t*
>(content.data()), content.length(),
419 &side_data[0], side_data.size(),
true);
422 buffer->set_dts(timestamp);
423 buffer->set_pts(timestamp);
424 if (cluster_start_time_ == kNoTimestamp)
425 cluster_start_time_ = timestamp;
426 buffer->set_duration(block_duration > 0
427 ? (block_duration * timecode_multiplier_)
430 if (!init_cb_.is_null() && !initialized_) {
431 std::vector<std::shared_ptr<StreamInfo>> streams;
432 if (audio_stream_info_)
433 streams.push_back(audio_stream_info_);
434 if (video_stream_info_) {
435 if (stream_type == kStreamVideo) {
439 if (video_stream_info_->codec() != kCodecAV1) {
440 std::unique_ptr<VPxParser> vpx_parser;
441 switch (video_stream_info_->codec()) {
443 vpx_parser.reset(
new VP8Parser);
446 vpx_parser.reset(
new VP9Parser);
450 <<
"Unsupported codec " << video_stream_info_->codec();
453 std::vector<VPxFrameInfo> vpx_frames;
454 if (!vpx_parser->Parse(buffer->data(), buffer->data_size(),
456 LOG(ERROR) <<
"Failed to parse vpx frame.";
459 if (vpx_frames.size() != 1u || !vpx_frames[0].is_keyframe) {
460 LOG(ERROR) <<
"The first frame should be a key frame.";
464 vp_config_.
MergeFrom(vpx_parser->codec_config());
465 video_stream_info_->set_codec_string(
467 std::vector<uint8_t> config_serialized;
468 vp_config_.
WriteMP4(&config_serialized);
469 video_stream_info_->set_codec_config(config_serialized);
472 streams.push_back(video_stream_info_);
473 init_cb_.Run(streams);
477 init_cb_.Run(streams);
482 return track->EmitBuffer(buffer);
485 WebMClusterParser::Track::Track(
488 int64_t default_duration,
490 : track_num_(track_num),
492 default_duration_(default_duration),
493 estimated_next_frame_duration_(kNoTimestamp),
494 new_sample_cb_(new_sample_cb) {
495 DCHECK(default_duration_ == kNoTimestamp || default_duration_ > 0);
498 WebMClusterParser::Track::~Track() {}
500 bool WebMClusterParser::Track::EmitBuffer(
501 const std::shared_ptr<MediaSample>& buffer) {
502 DVLOG(2) <<
"EmitBuffer() : " << track_num_
503 <<
" ts " << buffer->pts()
504 <<
" dur " << buffer->duration()
505 <<
" kf " << buffer->is_key_frame()
506 <<
" size " << buffer->data_size();
508 if (last_added_buffer_missing_duration_.get()) {
509 int64_t derived_duration =
510 buffer->pts() - last_added_buffer_missing_duration_->pts();
511 last_added_buffer_missing_duration_->set_duration(derived_duration);
513 DVLOG(2) <<
"EmitBuffer() : applied derived duration to held-back buffer : "
515 << last_added_buffer_missing_duration_->pts()
517 << last_added_buffer_missing_duration_->duration()
518 <<
" kf " << last_added_buffer_missing_duration_->is_key_frame()
519 <<
" size " << last_added_buffer_missing_duration_->data_size();
520 std::shared_ptr<MediaSample> updated_buffer =
521 last_added_buffer_missing_duration_;
522 last_added_buffer_missing_duration_ = NULL;
523 if (!EmitBufferHelp(updated_buffer))
527 if (buffer->duration() == kNoTimestamp) {
528 last_added_buffer_missing_duration_ = buffer;
529 DVLOG(2) <<
"EmitBuffer() : holding back buffer that is missing duration";
533 return EmitBufferHelp(buffer);
536 bool WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() {
537 if (!last_added_buffer_missing_duration_.get())
540 int64_t estimated_duration = GetDurationEstimate();
541 last_added_buffer_missing_duration_->set_duration(estimated_duration);
543 VLOG(1) <<
"Track " << track_num_ <<
": Estimating WebM block duration to be "
544 << estimated_duration / 1000
545 <<
"ms for the last (Simple)Block in the Cluster for this Track. Use "
546 "BlockGroups with BlockDurations at the end of each Track in a "
547 "Cluster to avoid estimation.";
549 DVLOG(2) <<
" new dur : ts " << last_added_buffer_missing_duration_->pts()
550 <<
" dur " << last_added_buffer_missing_duration_->duration()
551 <<
" kf " << last_added_buffer_missing_duration_->is_key_frame()
552 <<
" size " << last_added_buffer_missing_duration_->data_size();
556 if (!new_sample_cb_.Run(track_num_, last_added_buffer_missing_duration_))
558 last_added_buffer_missing_duration_ = NULL;
562 void WebMClusterParser::Track::Reset() {
563 last_added_buffer_missing_duration_ = NULL;
566 bool WebMClusterParser::Track::EmitBufferHelp(
567 const std::shared_ptr<MediaSample>& buffer) {
568 DCHECK(!last_added_buffer_missing_duration_.get());
570 int64_t duration = buffer->duration();
571 if (duration < 0 || duration == kNoTimestamp) {
572 LOG(ERROR) <<
"Invalid buffer duration: " << duration;
579 int64_t orig_duration_estimate = estimated_next_frame_duration_;
580 if (estimated_next_frame_duration_ == kNoTimestamp) {
581 estimated_next_frame_duration_ = duration;
583 estimated_next_frame_duration_ =
584 std::max(duration, estimated_next_frame_duration_);
587 if (orig_duration_estimate != estimated_next_frame_duration_) {
588 DVLOG(3) <<
"Updated duration estimate:"
589 << orig_duration_estimate
591 << estimated_next_frame_duration_
597 return new_sample_cb_.Run(track_num_, buffer);
600 int64_t WebMClusterParser::Track::GetDurationEstimate() {
601 int64_t duration = kNoTimestamp;
602 if (default_duration_ != kNoTimestamp) {
603 duration = default_duration_;
604 DVLOG(3) << __FUNCTION__ <<
" : using track default duration " << duration;
605 }
else if (estimated_next_frame_duration_ != kNoTimestamp) {
606 duration = estimated_next_frame_duration_;
607 DVLOG(3) << __FUNCTION__ <<
" : using estimated duration " << duration;
610 duration = kDefaultVideoBufferDurationInMs * kMicrosecondsPerMillisecond;
612 duration = kDefaultAudioBufferDurationInMs * kMicrosecondsPerMillisecond;
614 DVLOG(3) << __FUNCTION__ <<
" : using hardcoded default duration "
618 DCHECK_GT(duration, 0);
619 DCHECK_NE(duration, kNoTimestamp);
623 void WebMClusterParser::ResetTextTracks() {
624 for (TextTrackMap::iterator it = text_track_map_.begin();
625 it != text_track_map_.end();
631 WebMClusterParser::Track*
632 WebMClusterParser::FindTextTrack(
int track_num) {
633 const TextTrackMap::iterator it = text_track_map_.find(track_num);
635 if (it == text_track_map_.end())