Home | History | Annotate | Download | only in webm
      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.
      4 
      5 #include "media/formats/webm/webm_cluster_parser.h"
      6 
      7 #include <vector>
      8 
      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"
     17 
     18 namespace media {
     19 
     20 WebMClusterParser::WebMClusterParser(
     21     int64 timecode_scale,
     22     int audio_track_num,
     23     base::TimeDelta audio_default_duration,
     24     int video_track_num,
     25     base::TimeDelta video_default_duration,
     26     const WebMTracksParser::TextTracks& text_tracks,
     27     const std::set<int64>& ignored_tracks,
     28     const std::string& audio_encryption_key_id,
     29     const std::string& video_encryption_key_id,
     30     const LogCB& log_cb)
     31     : timecode_multiplier_(timecode_scale / 1000.0),
     32       ignored_tracks_(ignored_tracks),
     33       audio_encryption_key_id_(audio_encryption_key_id),
     34       video_encryption_key_id_(video_encryption_key_id),
     35       parser_(kWebMIdCluster, this),
     36       last_block_timecode_(-1),
     37       block_data_size_(-1),
     38       block_duration_(-1),
     39       block_add_id_(-1),
     40       block_additional_data_size_(-1),
     41       discard_padding_(-1),
     42       cluster_timecode_(-1),
     43       cluster_start_time_(kNoTimestamp()),
     44       cluster_ended_(false),
     45       audio_(audio_track_num, false, audio_default_duration, log_cb),
     46       video_(video_track_num, true, video_default_duration, log_cb),
     47       ready_buffer_upper_bound_(kNoTimestamp()),
     48       log_cb_(log_cb) {
     49   for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
     50        it != text_tracks.end();
     51        ++it) {
     52     text_track_map_.insert(std::make_pair(
     53         it->first, Track(it->first, false, kNoTimestamp(), log_cb_)));
     54   }
     55 }
     56 
     57 WebMClusterParser::~WebMClusterParser() {}
     58 
     59 void WebMClusterParser::Reset() {
     60   last_block_timecode_ = -1;
     61   cluster_timecode_ = -1;
     62   cluster_start_time_ = kNoTimestamp();
     63   cluster_ended_ = false;
     64   parser_.Reset();
     65   audio_.Reset();
     66   video_.Reset();
     67   ResetTextTracks();
     68   ready_buffer_upper_bound_ = kNoTimestamp();
     69 }
     70 
     71 int WebMClusterParser::Parse(const uint8* buf, int size) {
     72   audio_.ClearReadyBuffers();
     73   video_.ClearReadyBuffers();
     74   ClearTextTrackReadyBuffers();
     75   ready_buffer_upper_bound_ = kNoTimestamp();
     76 
     77   int result = parser_.Parse(buf, size);
     78 
     79   if (result < 0) {
     80     cluster_ended_ = false;
     81     return result;
     82   }
     83 
     84   cluster_ended_ = parser_.IsParsingComplete();
     85   if (cluster_ended_) {
     86     // If there were no buffers in this cluster, set the cluster start time to
     87     // be the |cluster_timecode_|.
     88     if (cluster_start_time_ == kNoTimestamp()) {
     89       // If the cluster did not even have a |cluster_timecode_|, signal parse
     90       // error.
     91       if (cluster_timecode_ < 0)
     92         return -1;
     93 
     94       cluster_start_time_ = base::TimeDelta::FromMicroseconds(
     95           cluster_timecode_ * timecode_multiplier_);
     96     }
     97 
     98     // Reset the parser if we're done parsing so that
     99     // it is ready to accept another cluster on the next
    100     // call.
    101     parser_.Reset();
    102 
    103     last_block_timecode_ = -1;
    104     cluster_timecode_ = -1;
    105   }
    106 
    107   return result;
    108 }
    109 
    110 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() {
    111   if (ready_buffer_upper_bound_ == kNoTimestamp())
    112     UpdateReadyBuffers();
    113 
    114   return audio_.ready_buffers();
    115 }
    116 
    117 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() {
    118   if (ready_buffer_upper_bound_ == kNoTimestamp())
    119     UpdateReadyBuffers();
    120 
    121   return video_.ready_buffers();
    122 }
    123 
    124 const WebMClusterParser::TextBufferQueueMap&
    125 WebMClusterParser::GetTextBuffers() {
    126   if (ready_buffer_upper_bound_ == kNoTimestamp())
    127     UpdateReadyBuffers();
    128 
    129   // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in
    130   // the output only for non-empty ready_buffer() queues in |text_track_map_|.
    131   text_buffers_map_.clear();
    132   for (TextTrackMap::const_iterator itr = text_track_map_.begin();
    133        itr != text_track_map_.end();
    134        ++itr) {
    135     const BufferQueue& text_buffers = itr->second.ready_buffers();
    136     if (!text_buffers.empty())
    137       text_buffers_map_.insert(std::make_pair(itr->first, text_buffers));
    138   }
    139 
    140   return text_buffers_map_;
    141 }
    142 
    143 WebMParserClient* WebMClusterParser::OnListStart(int id) {
    144   if (id == kWebMIdCluster) {
    145     cluster_timecode_ = -1;
    146     cluster_start_time_ = kNoTimestamp();
    147   } else if (id == kWebMIdBlockGroup) {
    148     block_data_.reset();
    149     block_data_size_ = -1;
    150     block_duration_ = -1;
    151     discard_padding_ = -1;
    152     discard_padding_set_ = false;
    153   } else if (id == kWebMIdBlockAdditions) {
    154     block_add_id_ = -1;
    155     block_additional_data_.reset();
    156     block_additional_data_size_ = -1;
    157   }
    158 
    159   return this;
    160 }
    161 
    162 bool WebMClusterParser::OnListEnd(int id) {
    163   if (id != kWebMIdBlockGroup)
    164     return true;
    165 
    166   // Make sure the BlockGroup actually had a Block.
    167   if (block_data_size_ == -1) {
    168     MEDIA_LOG(log_cb_) << "Block missing from BlockGroup.";
    169     return false;
    170   }
    171 
    172   bool result = ParseBlock(false, block_data_.get(), block_data_size_,
    173                            block_additional_data_.get(),
    174                            block_additional_data_size_, block_duration_,
    175                            discard_padding_set_ ? discard_padding_ : 0);
    176   block_data_.reset();
    177   block_data_size_ = -1;
    178   block_duration_ = -1;
    179   block_add_id_ = -1;
    180   block_additional_data_.reset();
    181   block_additional_data_size_ = -1;
    182   discard_padding_ = -1;
    183   discard_padding_set_ = false;
    184   return result;
    185 }
    186 
    187 bool WebMClusterParser::OnUInt(int id, int64 val) {
    188   int64* dst;
    189   switch (id) {
    190     case kWebMIdTimecode:
    191       dst = &cluster_timecode_;
    192       break;
    193     case kWebMIdBlockDuration:
    194       dst = &block_duration_;
    195       break;
    196     case kWebMIdBlockAddID:
    197       dst = &block_add_id_;
    198       break;
    199     default:
    200       return true;
    201   }
    202   if (*dst != -1)
    203     return false;
    204   *dst = val;
    205   return true;
    206 }
    207 
    208 bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf,
    209                                    int size, const uint8* additional,
    210                                    int additional_size, int duration,
    211                                    int64 discard_padding) {
    212   if (size < 4)
    213     return false;
    214 
    215   // Return an error if the trackNum > 127. We just aren't
    216   // going to support large track numbers right now.
    217   if (!(buf[0] & 0x80)) {
    218     MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported";
    219     return false;
    220   }
    221 
    222   int track_num = buf[0] & 0x7f;
    223   int timecode = buf[1] << 8 | buf[2];
    224   int flags = buf[3] & 0xff;
    225   int lacing = (flags >> 1) & 0x3;
    226 
    227   if (lacing) {
    228     MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet.";
    229     return false;
    230   }
    231 
    232   // Sign extend negative timecode offsets.
    233   if (timecode & 0x8000)
    234     timecode |= ~0xffff;
    235 
    236   const uint8* frame_data = buf + 4;
    237   int frame_size = size - (frame_data - buf);
    238   return OnBlock(is_simple_block, track_num, timecode, duration, flags,
    239                  frame_data, frame_size, additional, additional_size,
    240                  discard_padding);
    241 }
    242 
    243 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
    244   switch (id) {
    245     case kWebMIdSimpleBlock:
    246       return ParseBlock(true, data, size, NULL, -1, -1, 0);
    247 
    248     case kWebMIdBlock:
    249       if (block_data_) {
    250         MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not "
    251                               "supported.";
    252         return false;
    253       }
    254       block_data_.reset(new uint8[size]);
    255       memcpy(block_data_.get(), data, size);
    256       block_data_size_ = size;
    257       return true;
    258 
    259     case kWebMIdBlockAdditional: {
    260       uint64 block_add_id = base::HostToNet64(block_add_id_);
    261       if (block_additional_data_) {
    262         // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed
    263         // as per matroska spec. But for now we don't have a use case to
    264         // support parsing of such files. Take a look at this again when such a
    265         // case arises.
    266         MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is "
    267                               "not supported.";
    268         return false;
    269       }
    270       // First 8 bytes of side_data in DecoderBuffer is the BlockAddID
    271       // element's value in Big Endian format. This is done to mimic ffmpeg
    272       // demuxer's behavior.
    273       block_additional_data_size_ = size + sizeof(block_add_id);
    274       block_additional_data_.reset(new uint8[block_additional_data_size_]);
    275       memcpy(block_additional_data_.get(), &block_add_id,
    276              sizeof(block_add_id));
    277       memcpy(block_additional_data_.get() + 8, data, size);
    278       return true;
    279     }
    280     case kWebMIdDiscardPadding: {
    281       if (discard_padding_set_ || size <= 0 || size > 8)
    282         return false;
    283       discard_padding_set_ = true;
    284 
    285       // Read in the big-endian integer.
    286       discard_padding_ = static_cast<int8>(data[0]);
    287       for (int i = 1; i < size; ++i)
    288         discard_padding_ = (discard_padding_ << 8) | data[i];
    289 
    290       return true;
    291     }
    292     default:
    293       return true;
    294   }
    295 }
    296 
    297 bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num,
    298                                 int timecode,
    299                                 int  block_duration,
    300                                 int flags,
    301                                 const uint8* data, int size,
    302                                 const uint8* additional, int additional_size,
    303                                 int64 discard_padding) {
    304   DCHECK_GE(size, 0);
    305   if (cluster_timecode_ == -1) {
    306     MEDIA_LOG(log_cb_) << "Got a block before cluster timecode.";
    307     return false;
    308   }
    309 
    310   // TODO(acolwell): Should relative negative timecode offsets be rejected?  Or
    311   // only when the absolute timecode is negative?  See http://crbug.com/271794
    312   if (timecode < 0) {
    313     MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset "
    314                        << timecode;
    315     return false;
    316   }
    317 
    318   if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
    319     MEDIA_LOG(log_cb_)
    320         << "Got a block with a timecode before the previous block.";
    321     return false;
    322   }
    323 
    324   Track* track = NULL;
    325   StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO;
    326   std::string encryption_key_id;
    327   if (track_num == audio_.track_num()) {
    328     track = &audio_;
    329     encryption_key_id = audio_encryption_key_id_;
    330   } else if (track_num == video_.track_num()) {
    331     track = &video_;
    332     encryption_key_id = video_encryption_key_id_;
    333     buffer_type = DemuxerStream::VIDEO;
    334   } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) {
    335     return true;
    336   } else if (Track* const text_track = FindTextTrack(track_num)) {
    337     if (is_simple_block)  // BlockGroup is required for WebVTT cues
    338       return false;
    339     if (block_duration < 0)  // not specified
    340       return false;
    341     track = text_track;
    342     buffer_type = DemuxerStream::TEXT;
    343   } else {
    344     MEDIA_LOG(log_cb_) << "Unexpected track number " << track_num;
    345     return false;
    346   }
    347 
    348   last_block_timecode_ = timecode;
    349 
    350   base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
    351       (cluster_timecode_ + timecode) * timecode_multiplier_);
    352 
    353   scoped_refptr<StreamParserBuffer> buffer;
    354   if (buffer_type != DemuxerStream::TEXT) {
    355     // The first bit of the flags is set when a SimpleBlock contains only
    356     // keyframes. If this is a Block, then inspection of the payload is
    357     // necessary to determine whether it contains a keyframe or not.
    358     // http://www.matroska.org/technical/specs/index.html
    359     bool is_keyframe =
    360         is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size);
    361 
    362     // Every encrypted Block has a signal byte and IV prepended to it. Current
    363     // encrypted WebM request for comments specification is here
    364     // http://wiki.webmproject.org/encryption/webm-encryption-rfc
    365     scoped_ptr<DecryptConfig> decrypt_config;
    366     int data_offset = 0;
    367     if (!encryption_key_id.empty() &&
    368         !WebMCreateDecryptConfig(
    369              data, size,
    370              reinterpret_cast<const uint8*>(encryption_key_id.data()),
    371              encryption_key_id.size(),
    372              &decrypt_config, &data_offset)) {
    373       return false;
    374     }
    375 
    376     // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
    377     // type with remapped bytestream track numbers and allow multiple tracks as
    378     // applicable. See https://crbug.com/341581.
    379     buffer = StreamParserBuffer::CopyFrom(
    380         data + data_offset, size - data_offset,
    381         additional, additional_size,
    382         is_keyframe, buffer_type, track_num);
    383 
    384     if (decrypt_config)
    385       buffer->set_decrypt_config(decrypt_config.Pass());
    386   } else {
    387     std::string id, settings, content;
    388     WebMWebVTTParser::Parse(data, size, &id, &settings, &content);
    389 
    390     std::vector<uint8> side_data;
    391     MakeSideData(id.begin(), id.end(),
    392                  settings.begin(), settings.end(),
    393                  &side_data);
    394 
    395     // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
    396     // type with remapped bytestream track numbers and allow multiple tracks as
    397     // applicable. See https://crbug.com/341581.
    398     buffer = StreamParserBuffer::CopyFrom(
    399         reinterpret_cast<const uint8*>(content.data()),
    400         content.length(),
    401         &side_data[0],
    402         side_data.size(),
    403         true, buffer_type, track_num);
    404   }
    405 
    406   buffer->set_timestamp(timestamp);
    407   if (cluster_start_time_ == kNoTimestamp())
    408     cluster_start_time_ = timestamp;
    409 
    410   if (block_duration >= 0) {
    411     buffer->set_duration(base::TimeDelta::FromMicroseconds(
    412         block_duration * timecode_multiplier_));
    413   } else {
    414     DCHECK_NE(buffer_type, DemuxerStream::TEXT);
    415     buffer->set_duration(track->default_duration());
    416   }
    417 
    418   if (discard_padding != 0) {
    419     buffer->set_discard_padding(std::make_pair(
    420         base::TimeDelta(),
    421         base::TimeDelta::FromMicroseconds(discard_padding / 1000)));
    422   }
    423 
    424   return track->AddBuffer(buffer);
    425 }
    426 
    427 WebMClusterParser::Track::Track(int track_num,
    428                                 bool is_video,
    429                                 base::TimeDelta default_duration,
    430                                 const LogCB& log_cb)
    431     : track_num_(track_num),
    432       is_video_(is_video),
    433       default_duration_(default_duration),
    434       estimated_next_frame_duration_(kNoTimestamp()),
    435       log_cb_(log_cb) {
    436   DCHECK(default_duration_ == kNoTimestamp() ||
    437          default_duration_ > base::TimeDelta());
    438 }
    439 
    440 WebMClusterParser::Track::~Track() {}
    441 
    442 base::TimeDelta WebMClusterParser::Track::GetReadyUpperBound() {
    443   DCHECK(ready_buffers_.empty());
    444   if (last_added_buffer_missing_duration_)
    445     return last_added_buffer_missing_duration_->GetDecodeTimestamp();
    446 
    447   return kInfiniteDuration();
    448 }
    449 
    450 void WebMClusterParser::Track::ExtractReadyBuffers(
    451     const base::TimeDelta before_timestamp) {
    452   DCHECK(ready_buffers_.empty());
    453   DCHECK(base::TimeDelta() <= before_timestamp);
    454   DCHECK(kNoTimestamp() != before_timestamp);
    455 
    456   if (buffers_.empty())
    457     return;
    458 
    459   if (buffers_.back()->GetDecodeTimestamp() < before_timestamp) {
    460     // All of |buffers_| are ready.
    461     ready_buffers_.swap(buffers_);
    462     DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " All "
    463              << ready_buffers_.size() << " are ready: before upper bound ts "
    464              << before_timestamp.InSecondsF();
    465     return;
    466   }
    467 
    468   // Not all of |buffers_| are ready yet. Move any that are ready to
    469   // |ready_buffers_|.
    470   while (true) {
    471     const scoped_refptr<StreamParserBuffer>& buffer = buffers_.front();
    472     if (buffer->GetDecodeTimestamp() >= before_timestamp)
    473       break;
    474     ready_buffers_.push_back(buffer);
    475     buffers_.pop_front();
    476     DCHECK(!buffers_.empty());
    477   }
    478 
    479   DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " Only "
    480            << ready_buffers_.size() << " ready, " << buffers_.size()
    481            << " at or after upper bound ts " << before_timestamp.InSecondsF();
    482 }
    483 
    484 bool WebMClusterParser::Track::AddBuffer(
    485     const scoped_refptr<StreamParserBuffer>& buffer) {
    486   DVLOG(2) << "AddBuffer() : " << track_num_
    487            << " ts " << buffer->timestamp().InSecondsF()
    488            << " dur " << buffer->duration().InSecondsF()
    489            << " kf " << buffer->IsKeyframe()
    490            << " size " << buffer->data_size();
    491 
    492   if (last_added_buffer_missing_duration_) {
    493     base::TimeDelta derived_duration =
    494         buffer->timestamp() - last_added_buffer_missing_duration_->timestamp();
    495     last_added_buffer_missing_duration_->set_duration(derived_duration);
    496 
    497     DVLOG(2) << "AddBuffer() : applied derived duration to held-back buffer : "
    498              << " ts "
    499              << last_added_buffer_missing_duration_->timestamp().InSecondsF()
    500              << " dur "
    501              << last_added_buffer_missing_duration_->duration().InSecondsF()
    502              << " kf " << last_added_buffer_missing_duration_->IsKeyframe()
    503              << " size " << last_added_buffer_missing_duration_->data_size();
    504     scoped_refptr<StreamParserBuffer> updated_buffer =
    505         last_added_buffer_missing_duration_;
    506     last_added_buffer_missing_duration_ = NULL;
    507     if (!QueueBuffer(updated_buffer))
    508       return false;
    509   }
    510 
    511   if (buffer->duration() == kNoTimestamp()) {
    512     last_added_buffer_missing_duration_ = buffer;
    513     DVLOG(2) << "AddBuffer() : holding back buffer that is missing duration";
    514     return true;
    515   }
    516 
    517   return QueueBuffer(buffer);
    518 }
    519 
    520 void WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() {
    521   if (!last_added_buffer_missing_duration_)
    522     return;
    523 
    524   last_added_buffer_missing_duration_->set_duration(GetDurationEstimate());
    525 
    526   DVLOG(2) << "ApplyDurationEstimateIfNeeded() : new dur : "
    527            << " ts "
    528            << last_added_buffer_missing_duration_->timestamp().InSecondsF()
    529            << " dur "
    530            << last_added_buffer_missing_duration_->duration().InSecondsF()
    531            << " kf " << last_added_buffer_missing_duration_->IsKeyframe()
    532            << " size " << last_added_buffer_missing_duration_->data_size();
    533 
    534   // Don't use the applied duration as a future estimation (don't use
    535   // QueueBuffer() here.)
    536   buffers_.push_back(last_added_buffer_missing_duration_);
    537   last_added_buffer_missing_duration_ = NULL;
    538 }
    539 
    540 void WebMClusterParser::Track::ClearReadyBuffers() {
    541   // Note that |buffers_| are kept and |estimated_next_frame_duration_| is not
    542   // reset here.
    543   ready_buffers_.clear();
    544 }
    545 
    546 void WebMClusterParser::Track::Reset() {
    547   ClearReadyBuffers();
    548   buffers_.clear();
    549   last_added_buffer_missing_duration_ = NULL;
    550 }
    551 
    552 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const {
    553   // For now, assume that all blocks are keyframes for datatypes other than
    554   // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
    555   if (!is_video_)
    556     return true;
    557 
    558   // Make sure the block is big enough for the minimal keyframe header size.
    559   if (size < 7)
    560     return false;
    561 
    562   // The LSb of the first byte must be a 0 for a keyframe.
    563   // http://tools.ietf.org/html/rfc6386 Section 19.1
    564   if ((data[0] & 0x01) != 0)
    565     return false;
    566 
    567   // Verify VP8 keyframe startcode.
    568   // http://tools.ietf.org/html/rfc6386 Section 19.1
    569   if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a)
    570     return false;
    571 
    572   return true;
    573 }
    574 
    575 bool WebMClusterParser::Track::QueueBuffer(
    576     const scoped_refptr<StreamParserBuffer>& buffer) {
    577   DCHECK(!last_added_buffer_missing_duration_);
    578 
    579   // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing
    580   // block timecode detection within a cluster. Therefore, we should not see
    581   // those here.
    582   base::TimeDelta previous_buffers_timestamp = buffers_.empty() ?
    583       base::TimeDelta() : buffers_.back()->GetDecodeTimestamp();
    584   CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp());
    585 
    586   base::TimeDelta duration = buffer->duration();
    587   if (duration < base::TimeDelta() || duration == kNoTimestamp()) {
    588     MEDIA_LOG(log_cb_) << "Invalid buffer duration: " << duration.InSecondsF();
    589     return false;
    590   }
    591 
    592   // The estimated frame duration is the minimum non-zero duration since the
    593   // last initialization segment.  The minimum is used to ensure frame durations
    594   // aren't overestimated.
    595   if (duration > base::TimeDelta()) {
    596     if (estimated_next_frame_duration_ == kNoTimestamp()) {
    597       estimated_next_frame_duration_ = duration;
    598     } else {
    599       estimated_next_frame_duration_ =
    600           std::min(duration, estimated_next_frame_duration_);
    601     }
    602   }
    603 
    604   buffers_.push_back(buffer);
    605   return true;
    606 }
    607 
    608 base::TimeDelta WebMClusterParser::Track::GetDurationEstimate() {
    609   base::TimeDelta duration = estimated_next_frame_duration_;
    610   if (duration != kNoTimestamp()) {
    611     DVLOG(3) << __FUNCTION__ << " : using estimated duration";
    612   } else {
    613     DVLOG(3) << __FUNCTION__ << " : using hardcoded default duration";
    614     if (is_video_) {
    615       duration = base::TimeDelta::FromMilliseconds(
    616           kDefaultVideoBufferDurationInMs);
    617     } else {
    618       duration = base::TimeDelta::FromMilliseconds(
    619           kDefaultAudioBufferDurationInMs);
    620     }
    621   }
    622 
    623   DCHECK(duration > base::TimeDelta());
    624   DCHECK(duration != kNoTimestamp());
    625   return duration;
    626 }
    627 
    628 void WebMClusterParser::ClearTextTrackReadyBuffers() {
    629   text_buffers_map_.clear();
    630   for (TextTrackMap::iterator it = text_track_map_.begin();
    631        it != text_track_map_.end();
    632        ++it) {
    633     it->second.ClearReadyBuffers();
    634   }
    635 }
    636 
    637 void WebMClusterParser::ResetTextTracks() {
    638   ClearTextTrackReadyBuffers();
    639   for (TextTrackMap::iterator it = text_track_map_.begin();
    640        it != text_track_map_.end();
    641        ++it) {
    642     it->second.Reset();
    643   }
    644 }
    645 
    646 void WebMClusterParser::UpdateReadyBuffers() {
    647   DCHECK(ready_buffer_upper_bound_ == kNoTimestamp());
    648   DCHECK(text_buffers_map_.empty());
    649 
    650   if (cluster_ended_) {
    651     audio_.ApplyDurationEstimateIfNeeded();
    652     video_.ApplyDurationEstimateIfNeeded();
    653     // Per OnBlock(), all text buffers should already have valid durations, so
    654     // there is no need to call ApplyDurationEstimateIfNeeded() on text tracks
    655     // here.
    656     ready_buffer_upper_bound_ = kInfiniteDuration();
    657     DCHECK(ready_buffer_upper_bound_ == audio_.GetReadyUpperBound());
    658     DCHECK(ready_buffer_upper_bound_ == video_.GetReadyUpperBound());
    659   } else {
    660     ready_buffer_upper_bound_ = std::min(audio_.GetReadyUpperBound(),
    661                                          video_.GetReadyUpperBound());
    662     DCHECK(base::TimeDelta() <= ready_buffer_upper_bound_);
    663     DCHECK(kNoTimestamp() != ready_buffer_upper_bound_);
    664   }
    665 
    666   // Prepare each track's ready buffers for retrieval.
    667   audio_.ExtractReadyBuffers(ready_buffer_upper_bound_);
    668   video_.ExtractReadyBuffers(ready_buffer_upper_bound_);
    669   for (TextTrackMap::iterator itr = text_track_map_.begin();
    670        itr != text_track_map_.end();
    671        ++itr) {
    672     itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_);
    673   }
    674 }
    675 
    676 WebMClusterParser::Track*
    677 WebMClusterParser::FindTextTrack(int track_num) {
    678   const TextTrackMap::iterator it = text_track_map_.find(track_num);
    679 
    680   if (it == text_track_map_.end())
    681     return NULL;
    682 
    683   return &it->second;
    684 }
    685 
    686 }  // namespace media
    687