5 #include "packager/media/formats/webm/webm_cluster_parser.h"
9 #include "packager/base/logging.h"
10 #include "packager/base/sys_byteorder.h"
11 #include "packager/media/base/decrypt_config.h"
12 #include "packager/media/base/timestamp.h"
13 #include "packager/media/codecs/vp8_parser.h"
14 #include "packager/media/codecs/vp9_parser.h"
15 #include "packager/media/codecs/webvtt_util.h"
16 #include "packager/media/formats/webm/webm_constants.h"
17 #include "packager/media/formats/webm/webm_crypto_helpers.h"
18 #include "packager/media/formats/webm/webm_webvtt_parser.h"
24 const int64_t kMicrosecondsPerMillisecond = 1000;
29 int64_t timecode_scale,
30 scoped_refptr<AudioStreamInfo> audio_stream_info,
31 scoped_refptr<VideoStreamInfo> video_stream_info,
32 int64_t audio_default_duration,
33 int64_t video_default_duration,
34 const WebMTracksParser::TextTracks& text_tracks,
35 const std::set<int64_t>& ignored_tracks,
36 const std::string& audio_encryption_key_id,
37 const std::string& video_encryption_key_id,
41 : timecode_multiplier_(timecode_scale / 1000.0),
42 audio_stream_info_(audio_stream_info),
43 video_stream_info_(video_stream_info),
44 ignored_tracks_(ignored_tracks),
45 audio_encryption_key_id_(audio_encryption_key_id),
46 video_encryption_key_id_(video_encryption_key_id),
47 parser_(kWebMIdCluster, this),
50 cluster_start_time_(kNoTimestamp),
51 audio_(audio_stream_info ? audio_stream_info->track_id() : -1,
53 audio_default_duration,
55 video_(video_stream_info ? video_stream_info->track_id() : -1,
57 video_default_duration,
59 if (decryption_key_source)
61 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
62 it != text_tracks.end();
64 text_track_map_.insert(std::make_pair(
65 it->first, Track(it->first,
false, kNoTimestamp, new_sample_cb)));
69 WebMClusterParser::~WebMClusterParser() {}
72 last_block_timecode_ = -1;
73 cluster_timecode_ = -1;
74 cluster_start_time_ = kNoTimestamp;
75 cluster_ended_ =
false;
84 bool audio_result = audio_.ApplyDurationEstimateIfNeeded();
85 bool video_result = video_.ApplyDurationEstimateIfNeeded();
87 return audio_result && video_result;
91 int result = parser_.
Parse(buf, size);
94 cluster_ended_ =
false;
102 if (cluster_start_time_ == kNoTimestamp) {
105 if (cluster_timecode_ < 0)
108 cluster_start_time_ = cluster_timecode_ * timecode_multiplier_;
116 last_block_timecode_ = -1;
117 cluster_timecode_ = -1;
124 if (
id == kWebMIdCluster) {
125 cluster_timecode_ = -1;
126 cluster_start_time_ = kNoTimestamp;
127 }
else if (
id == kWebMIdBlockGroup) {
129 block_data_size_ = -1;
130 block_duration_ = -1;
131 discard_padding_ = -1;
132 discard_padding_set_ =
false;
133 reference_block_set_ =
false;
134 }
else if (
id == kWebMIdBlockAdditions) {
136 block_additional_data_.reset();
137 block_additional_data_size_ = 0;
143 bool WebMClusterParser::OnListEnd(
int id) {
144 if (
id != kWebMIdBlockGroup)
148 if (block_data_size_ == -1) {
149 LOG(ERROR) <<
"Block missing from BlockGroup.";
153 bool result = ParseBlock(
154 false, block_data_.get(), block_data_size_, block_additional_data_.get(),
155 block_additional_data_size_, block_duration_,
156 discard_padding_set_ ? discard_padding_ : 0, reference_block_set_);
158 block_data_size_ = -1;
159 block_duration_ = -1;
161 block_additional_data_.reset();
162 block_additional_data_size_ = 0;
163 discard_padding_ = -1;
164 discard_padding_set_ =
false;
165 reference_block_set_ =
false;
169 bool WebMClusterParser::OnUInt(
int id, int64_t val) {
172 case kWebMIdTimecode:
173 dst = &cluster_timecode_;
175 case kWebMIdBlockDuration:
176 dst = &block_duration_;
178 case kWebMIdBlockAddID:
179 dst = &block_add_id_;
190 bool WebMClusterParser::ParseBlock(
bool is_simple_block,
193 const uint8_t* additional,
196 int64_t discard_padding,
197 bool reference_block_set) {
203 if (!(buf[0] & 0x80)) {
204 LOG(ERROR) <<
"TrackNumber over 127 not supported";
208 int track_num = buf[0] & 0x7f;
209 int timecode = buf[1] << 8 | buf[2];
210 int flags = buf[3] & 0xff;
211 int lacing = (flags >> 1) & 0x3;
214 LOG(ERROR) <<
"Lacing " << lacing <<
" is not supported yet.";
219 if (timecode & 0x8000)
227 is_simple_block ? (flags & 0x80) != 0 : !reference_block_set;
229 const uint8_t* frame_data = buf + 4;
230 int frame_size = size - (frame_data - buf);
231 return OnBlock(is_simple_block, track_num, timecode, duration, frame_data,
232 frame_size, additional, additional_size, discard_padding,
236 bool WebMClusterParser::OnBinary(
int id,
const uint8_t* data,
int size) {
238 case kWebMIdSimpleBlock:
239 return ParseBlock(
true, data, size, NULL, 0, -1, 0,
false);
243 LOG(ERROR) <<
"More than 1 Block in a BlockGroup is not "
247 block_data_.reset(
new uint8_t[size]);
248 memcpy(block_data_.get(), data, size);
249 block_data_size_ = size;
252 case kWebMIdBlockAdditional: {
253 uint64_t block_add_id = base::HostToNet64(block_add_id_);
254 if (block_additional_data_) {
259 LOG(ERROR) <<
"More than 1 BlockAdditional in a "
260 "BlockGroup is not supported.";
266 block_additional_data_size_ = size +
sizeof(block_add_id);
267 block_additional_data_.reset(
new uint8_t[block_additional_data_size_]);
268 memcpy(block_additional_data_.get(), &block_add_id,
269 sizeof(block_add_id));
270 memcpy(block_additional_data_.get() + 8, data, size);
273 case kWebMIdDiscardPadding: {
274 if (discard_padding_set_ || size <= 0 || size > 8)
276 discard_padding_set_ =
true;
279 discard_padding_ =
static_cast<int8_t
>(data[0]);
280 for (
int i = 1; i < size; ++i)
281 discard_padding_ = (discard_padding_ << 8) | data[i];
285 case kWebMIdReferenceBlock:
289 reference_block_set_ =
true;
296 bool WebMClusterParser::OnBlock(
bool is_simple_block,
302 const uint8_t* additional,
304 int64_t discard_padding,
307 if (cluster_timecode_ == -1) {
308 LOG(ERROR) <<
"Got a block before cluster timecode.";
315 LOG(ERROR) <<
"Got a block with negative timecode offset " << timecode;
319 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
320 LOG(ERROR) <<
"Got a block with a timecode before the previous block.";
325 StreamType stream_type = kStreamUnknown;
326 std::string encryption_key_id;
327 if (track_num == audio_.track_num()) {
329 encryption_key_id = audio_encryption_key_id_;
330 stream_type = kStreamAudio;
331 }
else if (track_num == video_.track_num()) {
333 encryption_key_id = video_encryption_key_id_;
334 stream_type = kStreamVideo;
335 }
else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) {
337 }
else if (Track*
const text_track = FindTextTrack(track_num)) {
340 if (block_duration < 0)
343 stream_type = kStreamText;
345 LOG(ERROR) <<
"Unexpected track number " << track_num;
348 DCHECK_NE(stream_type, kStreamUnknown);
350 last_block_timecode_ = timecode;
352 int64_t timestamp = (cluster_timecode_ + timecode) * timecode_multiplier_;
354 scoped_refptr<MediaSample> buffer;
355 if (stream_type != kStreamText) {
359 std::unique_ptr<DecryptConfig> decrypt_config;
361 if (!encryption_key_id.empty() &&
362 !WebMCreateDecryptConfig(
364 reinterpret_cast<const uint8_t*>(encryption_key_id.data()),
365 encryption_key_id.size(),
366 &decrypt_config, &data_offset)) {
371 additional, additional_size, is_key_frame);
373 if (decrypt_config) {
374 if (!decryptor_source_) {
375 LOG(ERROR) <<
"Encrypted media sample encountered, but decryption is "
379 if (!decryptor_source_->DecryptSampleBuffer(decrypt_config.get(),
380 buffer->writable_data(),
381 buffer->data_size())) {
382 LOG(ERROR) <<
"Cannot decrypt samples";
387 std::string id, settings, content;
390 std::vector<uint8_t> side_data;
391 MakeSideData(
id.begin(),
id.end(),
392 settings.begin(), settings.end(),
396 reinterpret_cast<const uint8_t*>(content.data()), content.length(),
397 &side_data[0], side_data.size(),
true);
400 buffer->set_dts(timestamp);
401 buffer->set_pts(timestamp);
402 if (cluster_start_time_ == kNoTimestamp)
403 cluster_start_time_ = timestamp;
404 buffer->set_duration(block_duration > 0
405 ? (block_duration * timecode_multiplier_)
408 if (!init_cb_.is_null() && !initialized_) {
409 std::vector<scoped_refptr<StreamInfo>> streams;
410 if (audio_stream_info_)
411 streams.push_back(audio_stream_info_);
412 if (video_stream_info_) {
413 if (stream_type == kStreamVideo) {
414 std::unique_ptr<VPxParser> vpx_parser;
415 switch (video_stream_info_->codec()) {
417 vpx_parser.reset(
new VP8Parser);
420 vpx_parser.reset(
new VP9Parser);
423 NOTIMPLEMENTED() <<
"Unsupported codec "
424 << video_stream_info_->codec();
427 std::vector<VPxFrameInfo> vpx_frames;
428 if (!vpx_parser->Parse(buffer->data(), buffer->data_size(),
430 LOG(ERROR) <<
"Failed to parse vpx frame.";
433 if (vpx_frames.size() != 1u || !vpx_frames[0].is_keyframe) {
434 LOG(ERROR) <<
"The first frame should be a key frame.";
438 VPCodecConfigurationRecord codec_config;
439 if (!video_stream_info_->codec_config().empty())
440 codec_config.ParseWebM(video_stream_info_->codec_config());
441 codec_config.MergeFrom(vpx_parser->codec_config());
443 video_stream_info_->set_codec_string(
444 codec_config.GetCodecString(video_stream_info_->codec()));
445 std::vector<uint8_t> config_serialized;
446 codec_config.WriteMP4(&config_serialized);
447 video_stream_info_->set_codec_config(config_serialized);
448 streams.push_back(video_stream_info_);
449 init_cb_.Run(streams);
453 init_cb_.Run(streams);
458 return track->EmitBuffer(buffer);
461 WebMClusterParser::Track::Track(
int track_num,
463 int64_t default_duration,
465 : track_num_(track_num),
467 default_duration_(default_duration),
468 estimated_next_frame_duration_(kNoTimestamp),
469 new_sample_cb_(new_sample_cb) {
470 DCHECK(default_duration_ == kNoTimestamp || default_duration_ > 0);
473 WebMClusterParser::Track::~Track() {}
475 bool WebMClusterParser::Track::EmitBuffer(
476 const scoped_refptr<MediaSample>& buffer) {
477 DVLOG(2) <<
"EmitBuffer() : " << track_num_
478 <<
" ts " << buffer->pts()
479 <<
" dur " << buffer->duration()
480 <<
" kf " << buffer->is_key_frame()
481 <<
" size " << buffer->data_size();
483 if (last_added_buffer_missing_duration_.get()) {
484 int64_t derived_duration =
485 buffer->pts() - last_added_buffer_missing_duration_->pts();
486 last_added_buffer_missing_duration_->set_duration(derived_duration);
488 DVLOG(2) <<
"EmitBuffer() : applied derived duration to held-back buffer : "
490 << last_added_buffer_missing_duration_->pts()
492 << last_added_buffer_missing_duration_->duration()
493 <<
" kf " << last_added_buffer_missing_duration_->is_key_frame()
494 <<
" size " << last_added_buffer_missing_duration_->data_size();
495 scoped_refptr<MediaSample> updated_buffer =
496 last_added_buffer_missing_duration_;
497 last_added_buffer_missing_duration_ = NULL;
498 if (!EmitBufferHelp(updated_buffer))
502 if (buffer->duration() == kNoTimestamp) {
503 last_added_buffer_missing_duration_ = buffer;
504 DVLOG(2) <<
"EmitBuffer() : holding back buffer that is missing duration";
508 return EmitBufferHelp(buffer);
511 bool WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() {
512 if (!last_added_buffer_missing_duration_.get())
515 int64_t estimated_duration = GetDurationEstimate();
516 last_added_buffer_missing_duration_->set_duration(estimated_duration);
518 VLOG(1) <<
"Track " << track_num_ <<
": Estimating WebM block duration to be "
519 << estimated_duration / 1000
520 <<
"ms for the last (Simple)Block in the Cluster for this Track. Use "
521 "BlockGroups with BlockDurations at the end of each Track in a "
522 "Cluster to avoid estimation.";
524 DVLOG(2) <<
" new dur : ts " << last_added_buffer_missing_duration_->pts()
525 <<
" dur " << last_added_buffer_missing_duration_->duration()
526 <<
" kf " << last_added_buffer_missing_duration_->is_key_frame()
527 <<
" size " << last_added_buffer_missing_duration_->data_size();
531 if (!new_sample_cb_.Run(track_num_, last_added_buffer_missing_duration_))
533 last_added_buffer_missing_duration_ = NULL;
537 void WebMClusterParser::Track::Reset() {
538 last_added_buffer_missing_duration_ = NULL;
541 bool WebMClusterParser::Track::EmitBufferHelp(
542 const scoped_refptr<MediaSample>& buffer) {
543 DCHECK(!last_added_buffer_missing_duration_.get());
545 int64_t duration = buffer->duration();
546 if (duration < 0 || duration == kNoTimestamp) {
547 LOG(ERROR) <<
"Invalid buffer duration: " << duration;
554 int64_t orig_duration_estimate = estimated_next_frame_duration_;
555 if (estimated_next_frame_duration_ == kNoTimestamp) {
556 estimated_next_frame_duration_ = duration;
558 estimated_next_frame_duration_ =
559 std::max(duration, estimated_next_frame_duration_);
562 if (orig_duration_estimate != estimated_next_frame_duration_) {
563 DVLOG(3) <<
"Updated duration estimate:"
564 << orig_duration_estimate
566 << estimated_next_frame_duration_
572 return new_sample_cb_.Run(track_num_, buffer);
575 int64_t WebMClusterParser::Track::GetDurationEstimate() {
576 int64_t duration = kNoTimestamp;
577 if (default_duration_ != kNoTimestamp) {
578 duration = default_duration_;
579 DVLOG(3) << __FUNCTION__ <<
" : using track default duration " << duration;
580 }
else if (estimated_next_frame_duration_ != kNoTimestamp) {
581 duration = estimated_next_frame_duration_;
582 DVLOG(3) << __FUNCTION__ <<
" : using estimated duration " << duration;
585 duration = kDefaultVideoBufferDurationInMs * kMicrosecondsPerMillisecond;
587 duration = kDefaultAudioBufferDurationInMs * kMicrosecondsPerMillisecond;
589 DVLOG(3) << __FUNCTION__ <<
" : using hardcoded default duration "
593 DCHECK_GT(duration, 0);
594 DCHECK_NE(duration, kNoTimestamp);
598 void WebMClusterParser::ResetTextTracks() {
599 for (TextTrackMap::iterator it = text_track_map_.begin();
600 it != text_track_map_.end();
606 WebMClusterParser::Track*
607 WebMClusterParser::FindTextTrack(
int track_num) {
608 const TextTrackMap::iterator it = text_track_map_.find(track_num);
610 if (it == text_track_map_.end())