Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / formats / webm / webm_cluster_parser.cc
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_(kNoDecodeTimestamp()),
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_ = kNoDecodeTimestamp();
69 }
70
71 int WebMClusterParser::Parse(const uint8* buf, int size) {
72   audio_.ClearReadyBuffers();
73   video_.ClearReadyBuffers();
74   ClearTextTrackReadyBuffers();
75   ready_buffer_upper_bound_ = kNoDecodeTimestamp();
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_ == kNoDecodeTimestamp())
112     UpdateReadyBuffers();
113
114   return audio_.ready_buffers();
115 }
116
117 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() {
118   if (ready_buffer_upper_bound_ == kNoDecodeTimestamp())
119     UpdateReadyBuffers();
120
121   return video_.ready_buffers();
122 }
123
124 const WebMClusterParser::TextBufferQueueMap&
125 WebMClusterParser::GetTextBuffers() {
126   if (ready_buffer_upper_bound_ == kNoDecodeTimestamp())
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 DecodeTimestamp 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 DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max());
448 }
449
450 void WebMClusterParser::Track::ExtractReadyBuffers(
451     const DecodeTimestamp before_timestamp) {
452   DCHECK(ready_buffers_.empty());
453   DCHECK(DecodeTimestamp() <= before_timestamp);
454   DCHECK(kNoDecodeTimestamp() != 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   DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ?
583       DecodeTimestamp() : 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_ == kNoDecodeTimestamp());
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_ =
657         DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max());
658     DCHECK(ready_buffer_upper_bound_ == audio_.GetReadyUpperBound());
659     DCHECK(ready_buffer_upper_bound_ == video_.GetReadyUpperBound());
660   } else {
661     ready_buffer_upper_bound_ = std::min(audio_.GetReadyUpperBound(),
662                                          video_.GetReadyUpperBound());
663     DCHECK(DecodeTimestamp() <= ready_buffer_upper_bound_);
664     DCHECK(kNoDecodeTimestamp() != ready_buffer_upper_bound_);
665   }
666
667   // Prepare each track's ready buffers for retrieval.
668   audio_.ExtractReadyBuffers(ready_buffer_upper_bound_);
669   video_.ExtractReadyBuffers(ready_buffer_upper_bound_);
670   for (TextTrackMap::iterator itr = text_track_map_.begin();
671        itr != text_track_map_.end();
672        ++itr) {
673     itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_);
674   }
675 }
676
677 WebMClusterParser::Track*
678 WebMClusterParser::FindTextTrack(int track_num) {
679   const TextTrackMap::iterator it = text_track_map_.find(track_num);
680
681   if (it == text_track_map_.end())
682     return NULL;
683
684   return &it->second;
685 }
686
687 }  // namespace media