1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/formats/webm/webm_cluster_parser.h"
9 #include "base/logging.h"
10 #include "base/sys_byteorder.h"
11 #include "media/base/buffers.h"
12 #include "media/base/decrypt_config.h"
13 #include "media/filters/webvtt_util.h"
14 #include "media/formats/webm/webm_constants.h"
15 #include "media/formats/webm/webm_crypto_helpers.h"
16 #include "media/formats/webm/webm_webvtt_parser.h"
20 const uint16_t WebMClusterParser::kOpusFrameDurationsMu
[] = {
21 10000, 20000, 40000, 60000, 10000, 20000, 40000, 60000, 10000, 20000, 40000,
22 60000, 10000, 20000, 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000,
23 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000, 10000, 20000};
26 // Limits the number of MEDIA_LOG() calls in the path of reading encoded
27 // duration to avoid spamming for corrupted data.
28 kMaxDurationErrorLogs
= 10,
29 // Limits the number of MEDIA_LOG() calls warning the user that buffer
30 // durations have been estimated.
31 kMaxDurationEstimateLogs
= 10,
34 WebMClusterParser::WebMClusterParser(
37 base::TimeDelta audio_default_duration
,
39 base::TimeDelta video_default_duration
,
40 const WebMTracksParser::TextTracks
& text_tracks
,
41 const std::set
<int64
>& ignored_tracks
,
42 const std::string
& audio_encryption_key_id
,
43 const std::string
& video_encryption_key_id
,
44 const AudioCodec audio_codec
,
46 : num_duration_errors_(0),
47 timecode_multiplier_(timecode_scale
/ 1000.0),
48 ignored_tracks_(ignored_tracks
),
49 audio_encryption_key_id_(audio_encryption_key_id
),
50 video_encryption_key_id_(video_encryption_key_id
),
51 audio_codec_(audio_codec
),
52 parser_(kWebMIdCluster
, this),
53 last_block_timecode_(-1),
57 block_additional_data_size_(0),
59 cluster_timecode_(-1),
60 cluster_start_time_(kNoTimestamp()),
61 cluster_ended_(false),
62 audio_(audio_track_num
, false, audio_default_duration
, log_cb
),
63 video_(video_track_num
, true, video_default_duration
, log_cb
),
64 ready_buffer_upper_bound_(kNoDecodeTimestamp()),
66 for (WebMTracksParser::TextTracks::const_iterator it
= text_tracks
.begin();
67 it
!= text_tracks
.end();
69 text_track_map_
.insert(std::make_pair(
70 it
->first
, Track(it
->first
, false, kNoTimestamp(), log_cb_
)));
74 WebMClusterParser::~WebMClusterParser() {}
76 void WebMClusterParser::Reset() {
77 last_block_timecode_
= -1;
78 cluster_timecode_
= -1;
79 cluster_start_time_
= kNoTimestamp();
80 cluster_ended_
= false;
85 ready_buffer_upper_bound_
= kNoDecodeTimestamp();
88 int WebMClusterParser::Parse(const uint8_t* buf
, int size
) {
89 audio_
.ClearReadyBuffers();
90 video_
.ClearReadyBuffers();
91 ClearTextTrackReadyBuffers();
92 ready_buffer_upper_bound_
= kNoDecodeTimestamp();
94 int result
= parser_
.Parse(buf
, size
);
97 cluster_ended_
= false;
101 cluster_ended_
= parser_
.IsParsingComplete();
102 if (cluster_ended_
) {
103 // If there were no buffers in this cluster, set the cluster start time to
104 // be the |cluster_timecode_|.
105 if (cluster_start_time_
== kNoTimestamp()) {
106 // If the cluster did not even have a |cluster_timecode_|, signal parse
108 if (cluster_timecode_
< 0)
111 cluster_start_time_
= base::TimeDelta::FromMicroseconds(
112 cluster_timecode_
* timecode_multiplier_
);
115 // Reset the parser if we're done parsing so that
116 // it is ready to accept another cluster on the next
120 last_block_timecode_
= -1;
121 cluster_timecode_
= -1;
127 const WebMClusterParser::BufferQueue
& WebMClusterParser::GetAudioBuffers() {
128 if (ready_buffer_upper_bound_
== kNoDecodeTimestamp())
129 UpdateReadyBuffers();
131 return audio_
.ready_buffers();
134 const WebMClusterParser::BufferQueue
& WebMClusterParser::GetVideoBuffers() {
135 if (ready_buffer_upper_bound_
== kNoDecodeTimestamp())
136 UpdateReadyBuffers();
138 return video_
.ready_buffers();
141 const WebMClusterParser::TextBufferQueueMap
&
142 WebMClusterParser::GetTextBuffers() {
143 if (ready_buffer_upper_bound_
== kNoDecodeTimestamp())
144 UpdateReadyBuffers();
146 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in
147 // the output only for non-empty ready_buffer() queues in |text_track_map_|.
148 text_buffers_map_
.clear();
149 for (TextTrackMap::const_iterator itr
= text_track_map_
.begin();
150 itr
!= text_track_map_
.end();
152 const BufferQueue
& text_buffers
= itr
->second
.ready_buffers();
153 if (!text_buffers
.empty())
154 text_buffers_map_
.insert(std::make_pair(itr
->first
, text_buffers
));
157 return text_buffers_map_
;
160 base::TimeDelta
WebMClusterParser::TryGetEncodedAudioDuration(
164 // Duration is currently read assuming the *entire* stream is unencrypted.
165 // The special "Signal Byte" prepended to Blocks in encrypted streams is
166 // assumed to not be present.
167 // TODO(chcunningham): Consider parsing "Signal Byte" for encrypted streams
168 // to return duration for any unencrypted blocks.
170 if (audio_codec_
== kCodecOpus
) {
171 return ReadOpusDuration(data
, size
);
174 // TODO(wolenetz/chcunningham): Implement duration reading for Vorbis. See
175 // motivations in http://crbug.com/396634.
177 return kNoTimestamp();
180 base::TimeDelta
WebMClusterParser::ReadOpusDuration(const uint8_t* data
,
182 // Masks and constants for Opus packets. See
183 // https://tools.ietf.org/html/rfc6716#page-14
184 static const uint8_t kTocConfigMask
= 0xf8;
185 static const uint8_t kTocFrameCountCodeMask
= 0x03;
186 static const uint8_t kFrameCountMask
= 0x3f;
187 static const base::TimeDelta kPacketDurationMax
=
188 base::TimeDelta::FromMilliseconds(120);
191 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
192 kMaxDurationErrorLogs
)
193 << "Invalid zero-byte Opus packet; demuxed block duration may be "
195 return kNoTimestamp();
198 // Frame count type described by last 2 bits of Opus TOC byte.
199 int frame_count_type
= data
[0] & kTocFrameCountCodeMask
;
202 switch (frame_count_type
) {
211 // Type 3 indicates an arbitrary frame count described in the next byte.
213 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
214 kMaxDurationErrorLogs
)
215 << "Second byte missing from 'Code 3' Opus packet; demuxed block "
216 "duration may be imprecise.";
217 return kNoTimestamp();
220 frame_count
= data
[1] & kFrameCountMask
;
222 if (frame_count
== 0) {
223 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
224 kMaxDurationErrorLogs
)
225 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed "
226 "block duration may be imprecise.";
227 return kNoTimestamp();
232 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
233 kMaxDurationErrorLogs
)
234 << "Unexpected Opus frame count type: " << frame_count_type
<< "; "
235 << "demuxed block duration may be imprecise.";
236 return kNoTimestamp();
239 int opusConfig
= (data
[0] & kTocConfigMask
) >> 3;
240 CHECK_GE(opusConfig
, 0);
241 CHECK_LT(opusConfig
, static_cast<int>(arraysize(kOpusFrameDurationsMu
)));
243 DCHECK_GT(frame_count
, 0);
244 base::TimeDelta duration
= base::TimeDelta::FromMicroseconds(
245 kOpusFrameDurationsMu
[opusConfig
] * frame_count
);
247 if (duration
> kPacketDurationMax
) {
248 // Intentionally allowing packet to pass through for now. Decoder should
249 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case
250 // things go sideways.
251 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
252 kMaxDurationErrorLogs
)
253 << "Warning, demuxed Opus packet with encoded duration: " << duration
254 << ". Should be no greater than " << kPacketDurationMax
;
260 WebMParserClient
* WebMClusterParser::OnListStart(int id
) {
261 if (id
== kWebMIdCluster
) {
262 cluster_timecode_
= -1;
263 cluster_start_time_
= kNoTimestamp();
264 } else if (id
== kWebMIdBlockGroup
) {
266 block_data_size_
= -1;
267 block_duration_
= -1;
268 discard_padding_
= -1;
269 discard_padding_set_
= false;
270 } else if (id
== kWebMIdBlockAdditions
) {
272 block_additional_data_
.reset();
273 block_additional_data_size_
= 0;
279 bool WebMClusterParser::OnListEnd(int id
) {
280 if (id
!= kWebMIdBlockGroup
)
283 // Make sure the BlockGroup actually had a Block.
284 if (block_data_size_
== -1) {
285 MEDIA_LOG(ERROR
, log_cb_
) << "Block missing from BlockGroup.";
289 bool result
= ParseBlock(false, block_data_
.get(), block_data_size_
,
290 block_additional_data_
.get(),
291 block_additional_data_size_
, block_duration_
,
292 discard_padding_set_
? discard_padding_
: 0);
294 block_data_size_
= -1;
295 block_duration_
= -1;
297 block_additional_data_
.reset();
298 block_additional_data_size_
= 0;
299 discard_padding_
= -1;
300 discard_padding_set_
= false;
304 bool WebMClusterParser::OnUInt(int id
, int64 val
) {
307 case kWebMIdTimecode
:
308 dst
= &cluster_timecode_
;
310 case kWebMIdBlockDuration
:
311 dst
= &block_duration_
;
313 case kWebMIdBlockAddID
:
314 dst
= &block_add_id_
;
325 bool WebMClusterParser::ParseBlock(bool is_simple_block
,
328 const uint8_t* additional
,
331 int64 discard_padding
) {
335 // Return an error if the trackNum > 127. We just aren't
336 // going to support large track numbers right now.
337 if (!(buf
[0] & 0x80)) {
338 MEDIA_LOG(ERROR
, log_cb_
) << "TrackNumber over 127 not supported";
342 int track_num
= buf
[0] & 0x7f;
343 int timecode
= buf
[1] << 8 | buf
[2];
344 int flags
= buf
[3] & 0xff;
345 int lacing
= (flags
>> 1) & 0x3;
348 MEDIA_LOG(ERROR
, log_cb_
) << "Lacing " << lacing
349 << " is not supported yet.";
353 // Sign extend negative timecode offsets.
354 if (timecode
& 0x8000)
357 const uint8_t* frame_data
= buf
+ 4;
358 int frame_size
= size
- (frame_data
- buf
);
359 return OnBlock(is_simple_block
, track_num
, timecode
, duration
, flags
,
360 frame_data
, frame_size
, additional
, additional_size
,
364 bool WebMClusterParser::OnBinary(int id
, const uint8_t* data
, int size
) {
366 case kWebMIdSimpleBlock
:
367 return ParseBlock(true, data
, size
, NULL
, 0, -1, 0);
371 MEDIA_LOG(ERROR
, log_cb_
) << "More than 1 Block in a BlockGroup is not "
375 block_data_
.reset(new uint8_t[size
]);
376 memcpy(block_data_
.get(), data
, size
);
377 block_data_size_
= size
;
380 case kWebMIdBlockAdditional
: {
381 uint64 block_add_id
= base::HostToNet64(block_add_id_
);
382 if (block_additional_data_
) {
383 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed
384 // as per matroska spec. But for now we don't have a use case to
385 // support parsing of such files. Take a look at this again when such a
387 MEDIA_LOG(ERROR
, log_cb_
) << "More than 1 BlockAdditional in a "
388 "BlockGroup is not supported.";
391 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID
392 // element's value in Big Endian format. This is done to mimic ffmpeg
393 // demuxer's behavior.
394 block_additional_data_size_
= size
+ sizeof(block_add_id
);
395 block_additional_data_
.reset(new uint8_t[block_additional_data_size_
]);
396 memcpy(block_additional_data_
.get(), &block_add_id
,
397 sizeof(block_add_id
));
398 memcpy(block_additional_data_
.get() + 8, data
, size
);
401 case kWebMIdDiscardPadding
: {
402 if (discard_padding_set_
|| size
<= 0 || size
> 8)
404 discard_padding_set_
= true;
406 // Read in the big-endian integer.
407 discard_padding_
= static_cast<int8
>(data
[0]);
408 for (int i
= 1; i
< size
; ++i
)
409 discard_padding_
= (discard_padding_
<< 8) | data
[i
];
418 bool WebMClusterParser::OnBlock(bool is_simple_block
,
425 const uint8_t* additional
,
427 int64 discard_padding
) {
429 if (cluster_timecode_
== -1) {
430 MEDIA_LOG(ERROR
, log_cb_
) << "Got a block before cluster timecode.";
434 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or
435 // only when the absolute timecode is negative? See http://crbug.com/271794
437 MEDIA_LOG(ERROR
, log_cb_
) << "Got a block with negative timecode offset "
442 if (last_block_timecode_
!= -1 && timecode
< last_block_timecode_
) {
443 MEDIA_LOG(ERROR
, log_cb_
)
444 << "Got a block with a timecode before the previous block.";
449 StreamParserBuffer::Type buffer_type
= DemuxerStream::AUDIO
;
450 std::string encryption_key_id
;
451 base::TimeDelta encoded_duration
= kNoTimestamp();
452 if (track_num
== audio_
.track_num()) {
454 encryption_key_id
= audio_encryption_key_id_
;
455 if (encryption_key_id
.empty()) {
456 encoded_duration
= TryGetEncodedAudioDuration(data
, size
);
458 } else if (track_num
== video_
.track_num()) {
460 encryption_key_id
= video_encryption_key_id_
;
461 buffer_type
= DemuxerStream::VIDEO
;
462 } else if (ignored_tracks_
.find(track_num
) != ignored_tracks_
.end()) {
464 } else if (Track
* const text_track
= FindTextTrack(track_num
)) {
465 if (is_simple_block
) // BlockGroup is required for WebVTT cues
467 if (block_duration
< 0) // not specified
470 buffer_type
= DemuxerStream::TEXT
;
472 MEDIA_LOG(ERROR
, log_cb_
) << "Unexpected track number " << track_num
;
476 last_block_timecode_
= timecode
;
478 base::TimeDelta timestamp
= base::TimeDelta::FromMicroseconds(
479 (cluster_timecode_
+ timecode
) * timecode_multiplier_
);
481 scoped_refptr
<StreamParserBuffer
> buffer
;
482 if (buffer_type
!= DemuxerStream::TEXT
) {
483 // The first bit of the flags is set when a SimpleBlock contains only
484 // keyframes. If this is a Block, then inspection of the payload is
485 // necessary to determine whether it contains a keyframe or not.
486 // http://www.matroska.org/technical/specs/index.html
488 is_simple_block
? (flags
& 0x80) != 0 : track
->IsKeyframe(data
, size
);
490 // Every encrypted Block has a signal byte and IV prepended to it. Current
491 // encrypted WebM request for comments specification is here
492 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
493 scoped_ptr
<DecryptConfig
> decrypt_config
;
495 if (!encryption_key_id
.empty() &&
496 !WebMCreateDecryptConfig(
498 reinterpret_cast<const uint8_t*>(encryption_key_id
.data()),
499 encryption_key_id
.size(),
500 &decrypt_config
, &data_offset
)) {
504 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
505 // type with remapped bytestream track numbers and allow multiple tracks as
506 // applicable. See https://crbug.com/341581.
507 buffer
= StreamParserBuffer::CopyFrom(
508 data
+ data_offset
, size
- data_offset
,
509 additional
, additional_size
,
510 is_keyframe
, buffer_type
, track_num
);
513 buffer
->set_decrypt_config(decrypt_config
.Pass());
515 std::string id
, settings
, content
;
516 WebMWebVTTParser::Parse(data
, size
, &id
, &settings
, &content
);
518 std::vector
<uint8_t> side_data
;
519 MakeSideData(id
.begin(), id
.end(),
520 settings
.begin(), settings
.end(),
523 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
524 // type with remapped bytestream track numbers and allow multiple tracks as
525 // applicable. See https://crbug.com/341581.
526 buffer
= StreamParserBuffer::CopyFrom(
527 reinterpret_cast<const uint8_t*>(content
.data()),
531 true, buffer_type
, track_num
);
534 buffer
->set_timestamp(timestamp
);
535 if (cluster_start_time_
== kNoTimestamp())
536 cluster_start_time_
= timestamp
;
538 base::TimeDelta block_duration_time_delta
= kNoTimestamp();
539 if (block_duration
>= 0) {
540 block_duration_time_delta
= base::TimeDelta::FromMicroseconds(
541 block_duration
* timecode_multiplier_
);
544 // Prefer encoded duration over BlockGroup->BlockDuration or
545 // TrackEntry->DefaultDuration when available. This layering violation is a
546 // workaround for http://crbug.com/396634, decreasing the likelihood of
547 // fall-back to rough estimation techniques for Blocks that lack a
548 // BlockDuration at the end of a cluster. Cross cluster durations are not
549 // feasible given flexibility of cluster ordering and MSE APIs. Duration
550 // estimation may still apply in cases of encryption and codecs for which
551 // we do not extract encoded duration. Within a cluster, estimates are applied
552 // as Block Timecode deltas, or once the whole cluster is parsed in the case
553 // of the last Block in the cluster. See Track::AddBuffer and
554 // ApplyDurationEstimateIfNeeded().
555 if (encoded_duration
!= kNoTimestamp()) {
556 DCHECK(encoded_duration
!= kInfiniteDuration());
557 DCHECK(encoded_duration
> base::TimeDelta());
558 buffer
->set_duration(encoded_duration
);
560 DVLOG(3) << __FUNCTION__
<< " : "
561 << "Using encoded duration " << encoded_duration
.InSecondsF();
563 if (block_duration_time_delta
!= kNoTimestamp()) {
564 base::TimeDelta duration_difference
=
565 block_duration_time_delta
- encoded_duration
;
567 const auto kWarnDurationDiff
=
568 base::TimeDelta::FromMicroseconds(timecode_multiplier_
* 2);
569 if (duration_difference
.magnitude() > kWarnDurationDiff
) {
570 LIMITED_MEDIA_LOG(DEBUG
, log_cb_
, num_duration_errors_
,
571 kMaxDurationErrorLogs
)
573 << "(" << block_duration_time_delta
<< ") "
574 << "differs significantly from encoded duration "
575 << "(" << encoded_duration
<< ").";
578 } else if (block_duration_time_delta
!= kNoTimestamp()) {
579 buffer
->set_duration(block_duration_time_delta
);
581 DCHECK_NE(buffer_type
, DemuxerStream::TEXT
);
582 buffer
->set_duration(track
->default_duration());
585 if (discard_padding
!= 0) {
586 buffer
->set_discard_padding(std::make_pair(
588 base::TimeDelta::FromMicroseconds(discard_padding
/ 1000)));
591 return track
->AddBuffer(buffer
);
594 WebMClusterParser::Track::Track(int track_num
,
596 base::TimeDelta default_duration
,
598 : num_duration_estimates_(0),
599 track_num_(track_num
),
601 default_duration_(default_duration
),
602 estimated_next_frame_duration_(kNoTimestamp()),
604 DCHECK(default_duration_
== kNoTimestamp() ||
605 default_duration_
> base::TimeDelta());
608 WebMClusterParser::Track::~Track() {}
610 DecodeTimestamp
WebMClusterParser::Track::GetReadyUpperBound() {
611 DCHECK(ready_buffers_
.empty());
612 if (last_added_buffer_missing_duration_
.get())
613 return last_added_buffer_missing_duration_
->GetDecodeTimestamp();
615 return DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max());
618 void WebMClusterParser::Track::ExtractReadyBuffers(
619 const DecodeTimestamp before_timestamp
) {
620 DCHECK(ready_buffers_
.empty());
621 DCHECK(DecodeTimestamp() <= before_timestamp
);
622 DCHECK(kNoDecodeTimestamp() != before_timestamp
);
624 if (buffers_
.empty())
627 if (buffers_
.back()->GetDecodeTimestamp() < before_timestamp
) {
628 // All of |buffers_| are ready.
629 ready_buffers_
.swap(buffers_
);
630 DVLOG(3) << __FUNCTION__
<< " : " << track_num_
<< " All "
631 << ready_buffers_
.size() << " are ready: before upper bound ts "
632 << before_timestamp
.InSecondsF();
636 // Not all of |buffers_| are ready yet. Move any that are ready to
639 const scoped_refptr
<StreamParserBuffer
>& buffer
= buffers_
.front();
640 if (buffer
->GetDecodeTimestamp() >= before_timestamp
)
642 ready_buffers_
.push_back(buffer
);
643 buffers_
.pop_front();
644 DCHECK(!buffers_
.empty());
647 DVLOG(3) << __FUNCTION__
<< " : " << track_num_
<< " Only "
648 << ready_buffers_
.size() << " ready, " << buffers_
.size()
649 << " at or after upper bound ts " << before_timestamp
.InSecondsF();
652 bool WebMClusterParser::Track::AddBuffer(
653 const scoped_refptr
<StreamParserBuffer
>& buffer
) {
654 DVLOG(2) << "AddBuffer() : " << track_num_
655 << " ts " << buffer
->timestamp().InSecondsF()
656 << " dur " << buffer
->duration().InSecondsF()
657 << " kf " << buffer
->is_key_frame()
658 << " size " << buffer
->data_size();
660 if (last_added_buffer_missing_duration_
.get()) {
661 base::TimeDelta derived_duration
=
662 buffer
->timestamp() - last_added_buffer_missing_duration_
->timestamp();
663 last_added_buffer_missing_duration_
->set_duration(derived_duration
);
665 DVLOG(2) << "AddBuffer() : applied derived duration to held-back buffer : "
667 << last_added_buffer_missing_duration_
->timestamp().InSecondsF()
669 << last_added_buffer_missing_duration_
->duration().InSecondsF()
670 << " kf " << last_added_buffer_missing_duration_
->is_key_frame()
671 << " size " << last_added_buffer_missing_duration_
->data_size();
672 scoped_refptr
<StreamParserBuffer
> updated_buffer
=
673 last_added_buffer_missing_duration_
;
674 last_added_buffer_missing_duration_
= NULL
;
675 if (!QueueBuffer(updated_buffer
))
679 if (buffer
->duration() == kNoTimestamp()) {
680 last_added_buffer_missing_duration_
= buffer
;
681 DVLOG(2) << "AddBuffer() : holding back buffer that is missing duration";
685 return QueueBuffer(buffer
);
688 void WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() {
689 if (!last_added_buffer_missing_duration_
.get())
692 base::TimeDelta estimated_duration
= GetDurationEstimate();
693 last_added_buffer_missing_duration_
->set_duration(estimated_duration
);
696 // Exposing estimation so splicing/overlap frame processing can make
697 // informed decisions downstream.
698 // TODO(chcunningham): Set this for audio as well in later change where
699 // audio is switched to max estimation and splicing is disabled.
700 last_added_buffer_missing_duration_
->set_is_duration_estimated(true);
703 LIMITED_MEDIA_LOG(INFO
, log_cb_
, num_duration_estimates_
,
704 kMaxDurationEstimateLogs
)
705 << "Estimating WebM block duration to be " << estimated_duration
<< " "
706 << "for the last (Simple)Block in the Cluster for this Track. Use "
707 << "BlockGroups with BlockDurations at the end of each Track in a "
708 << "Cluster to avoid estimation.";
710 DVLOG(2) << __FUNCTION__
<< " new dur : ts "
711 << last_added_buffer_missing_duration_
->timestamp().InSecondsF()
713 << last_added_buffer_missing_duration_
->duration().InSecondsF()
714 << " kf " << last_added_buffer_missing_duration_
->is_key_frame()
715 << " size " << last_added_buffer_missing_duration_
->data_size();
717 // Don't use the applied duration as a future estimation (don't use
718 // QueueBuffer() here.)
719 buffers_
.push_back(last_added_buffer_missing_duration_
);
720 last_added_buffer_missing_duration_
= NULL
;
723 void WebMClusterParser::Track::ClearReadyBuffers() {
724 // Note that |buffers_| are kept and |estimated_next_frame_duration_| is not
726 ready_buffers_
.clear();
729 void WebMClusterParser::Track::Reset() {
732 last_added_buffer_missing_duration_
= NULL
;
735 bool WebMClusterParser::Track::IsKeyframe(const uint8_t* data
, int size
) const {
736 // For now, assume that all blocks are keyframes for datatypes other than
737 // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
741 // Make sure the block is big enough for the minimal keyframe header size.
745 // The LSb of the first byte must be a 0 for a keyframe.
746 // http://tools.ietf.org/html/rfc6386 Section 19.1
747 if ((data
[0] & 0x01) != 0)
750 // Verify VP8 keyframe startcode.
751 // http://tools.ietf.org/html/rfc6386 Section 19.1
752 if (data
[3] != 0x9d || data
[4] != 0x01 || data
[5] != 0x2a)
758 bool WebMClusterParser::Track::QueueBuffer(
759 const scoped_refptr
<StreamParserBuffer
>& buffer
) {
760 DCHECK(!last_added_buffer_missing_duration_
.get());
762 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing
763 // block timecode detection within a cluster. Therefore, we should not see
765 DecodeTimestamp previous_buffers_timestamp
= buffers_
.empty() ?
766 DecodeTimestamp() : buffers_
.back()->GetDecodeTimestamp();
767 CHECK(previous_buffers_timestamp
<= buffer
->GetDecodeTimestamp());
769 base::TimeDelta duration
= buffer
->duration();
770 if (duration
< base::TimeDelta() || duration
== kNoTimestamp()) {
771 MEDIA_LOG(ERROR
, log_cb_
)
772 << "Invalid buffer duration: " << duration
.InSecondsF();
776 // The estimated frame duration is the minimum (for audio) or the maximum
777 // (for video) non-zero duration since the last initialization segment. The
778 // minimum is used for audio to ensure frame durations aren't overestimated,
779 // triggering unnecessary frame splicing. For video, splicing does not apply,
780 // so maximum is used and overlap is simply resolved by showing the
781 // later of the overlapping frames at its given PTS, effectively trimming down
782 // the over-estimated duration of the previous frame.
783 // TODO(chcunningham): Use max for audio and disable splicing whenever
784 // estimated buffers are encountered.
785 if (duration
> base::TimeDelta()) {
786 base::TimeDelta orig_duration_estimate
= estimated_next_frame_duration_
;
787 if (estimated_next_frame_duration_
== kNoTimestamp()) {
788 estimated_next_frame_duration_
= duration
;
789 } else if (is_video_
) {
790 estimated_next_frame_duration_
=
791 std::max(duration
, estimated_next_frame_duration_
);
793 estimated_next_frame_duration_
=
794 std::min(duration
, estimated_next_frame_duration_
);
797 if (orig_duration_estimate
!= estimated_next_frame_duration_
) {
798 DVLOG(3) << "Updated duration estimate:"
799 << orig_duration_estimate
801 << estimated_next_frame_duration_
803 << buffer
->GetDecodeTimestamp().InSecondsF();
807 buffers_
.push_back(buffer
);
811 base::TimeDelta
WebMClusterParser::Track::GetDurationEstimate() {
812 base::TimeDelta duration
= estimated_next_frame_duration_
;
813 if (duration
!= kNoTimestamp()) {
814 DVLOG(3) << __FUNCTION__
<< " : using estimated duration";
816 DVLOG(3) << __FUNCTION__
<< " : using hardcoded default duration";
818 duration
= base::TimeDelta::FromMilliseconds(
819 kDefaultVideoBufferDurationInMs
);
821 duration
= base::TimeDelta::FromMilliseconds(
822 kDefaultAudioBufferDurationInMs
);
826 DCHECK(duration
> base::TimeDelta());
827 DCHECK(duration
!= kNoTimestamp());
831 void WebMClusterParser::ClearTextTrackReadyBuffers() {
832 text_buffers_map_
.clear();
833 for (TextTrackMap::iterator it
= text_track_map_
.begin();
834 it
!= text_track_map_
.end();
836 it
->second
.ClearReadyBuffers();
840 void WebMClusterParser::ResetTextTracks() {
841 ClearTextTrackReadyBuffers();
842 for (TextTrackMap::iterator it
= text_track_map_
.begin();
843 it
!= text_track_map_
.end();
849 void WebMClusterParser::UpdateReadyBuffers() {
850 DCHECK(ready_buffer_upper_bound_
== kNoDecodeTimestamp());
851 DCHECK(text_buffers_map_
.empty());
853 if (cluster_ended_
) {
854 audio_
.ApplyDurationEstimateIfNeeded();
855 video_
.ApplyDurationEstimateIfNeeded();
856 // Per OnBlock(), all text buffers should already have valid durations, so
857 // there is no need to call ApplyDurationEstimateIfNeeded() on text tracks
859 ready_buffer_upper_bound_
=
860 DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max());
861 DCHECK(ready_buffer_upper_bound_
== audio_
.GetReadyUpperBound());
862 DCHECK(ready_buffer_upper_bound_
== video_
.GetReadyUpperBound());
864 ready_buffer_upper_bound_
= std::min(audio_
.GetReadyUpperBound(),
865 video_
.GetReadyUpperBound());
866 DCHECK(DecodeTimestamp() <= ready_buffer_upper_bound_
);
867 DCHECK(kNoDecodeTimestamp() != ready_buffer_upper_bound_
);
870 // Prepare each track's ready buffers for retrieval.
871 audio_
.ExtractReadyBuffers(ready_buffer_upper_bound_
);
872 video_
.ExtractReadyBuffers(ready_buffer_upper_bound_
);
873 for (TextTrackMap::iterator itr
= text_track_map_
.begin();
874 itr
!= text_track_map_
.end();
876 itr
->second
.ExtractReadyBuffers(ready_buffer_upper_bound_
);
880 WebMClusterParser::Track
*
881 WebMClusterParser::FindTextTrack(int track_num
) {
882 const TextTrackMap::iterator it
= text_track_map_
.find(track_num
);
884 if (it
== text_track_map_
.end())