Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: media/formats/webm/webm_cluster_parser.cc

Issue 239343007: MSE: Make WebMClusterParser hold back buffers at or beyond buffer missing duration (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Always reconstruct text_buffers_map_ from a cleared one in every GetTextBuffers() call. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/formats/webm/webm_cluster_parser.h" 5 #include "media/formats/webm/webm_cluster_parser.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/sys_byteorder.h" 10 #include "base/sys_byteorder.h"
(...skipping 24 matching lines...) Expand all
35 parser_(kWebMIdCluster, this), 35 parser_(kWebMIdCluster, this),
36 last_block_timecode_(-1), 36 last_block_timecode_(-1),
37 block_data_size_(-1), 37 block_data_size_(-1),
38 block_duration_(-1), 38 block_duration_(-1),
39 block_add_id_(-1), 39 block_add_id_(-1),
40 block_additional_data_size_(-1), 40 block_additional_data_size_(-1),
41 discard_padding_(-1), 41 discard_padding_(-1),
42 cluster_timecode_(-1), 42 cluster_timecode_(-1),
43 cluster_start_time_(kNoTimestamp()), 43 cluster_start_time_(kNoTimestamp()),
44 cluster_ended_(false), 44 cluster_ended_(false),
45 audio_(audio_track_num, false, audio_default_duration), 45 audio_(audio_track_num, false, audio_default_duration, log_cb),
46 video_(video_track_num, true, video_default_duration), 46 video_(video_track_num, true, video_default_duration, log_cb),
47 ready_buffer_upper_bound_(kNoTimestamp()),
47 log_cb_(log_cb) { 48 log_cb_(log_cb) {
48 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); 49 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
49 it != text_tracks.end(); 50 it != text_tracks.end();
50 ++it) { 51 ++it) {
51 text_track_map_.insert(std::make_pair( 52 text_track_map_.insert(std::make_pair(
52 it->first, Track(it->first, false, kNoTimestamp()))); 53 it->first, Track(it->first, false, kNoTimestamp(), log_cb_)));
53 } 54 }
54 } 55 }
55 56
56 WebMClusterParser::~WebMClusterParser() {} 57 WebMClusterParser::~WebMClusterParser() {}
57 58
58 void WebMClusterParser::Reset() { 59 void WebMClusterParser::Reset() {
59 last_block_timecode_ = -1; 60 last_block_timecode_ = -1;
60 cluster_timecode_ = -1; 61 cluster_timecode_ = -1;
61 cluster_start_time_ = kNoTimestamp(); 62 cluster_start_time_ = kNoTimestamp();
62 cluster_ended_ = false; 63 cluster_ended_ = false;
63 parser_.Reset(); 64 parser_.Reset();
64 audio_.Reset(); 65 audio_.Reset();
65 video_.Reset(); 66 video_.Reset();
66 ResetTextTracks(); 67 ResetTextTracks();
68 ready_buffer_upper_bound_ = kNoTimestamp();
67 } 69 }
68 70
69 int WebMClusterParser::Parse(const uint8* buf, int size) { 71 int WebMClusterParser::Parse(const uint8* buf, int size) {
70 audio_.ClearBuffersButKeepLastIfMissingDuration(); 72 audio_.ClearReadyBuffers();
71 video_.ClearBuffersButKeepLastIfMissingDuration(); 73 video_.ClearReadyBuffers();
72 ResetTextTracks(); 74 ClearTextTrackReadyBuffers();
75 ready_buffer_upper_bound_ = kNoTimestamp();
73 76
74 int result = parser_.Parse(buf, size); 77 int result = parser_.Parse(buf, size);
75 78
76 if (result < 0) { 79 if (result < 0) {
77 cluster_ended_ = false; 80 cluster_ended_ = false;
78 return result; 81 return result;
79 } 82 }
80 83
81 cluster_ended_ = parser_.IsParsingComplete(); 84 cluster_ended_ = parser_.IsParsingComplete();
82 if (cluster_ended_) { 85 if (cluster_ended_) {
(...skipping 15 matching lines...) Expand all
98 parser_.Reset(); 101 parser_.Reset();
99 102
100 last_block_timecode_ = -1; 103 last_block_timecode_ = -1;
101 cluster_timecode_ = -1; 104 cluster_timecode_ = -1;
102 } 105 }
103 106
104 return result; 107 return result;
105 } 108 }
106 109
107 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() { 110 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() {
108 if (cluster_ended_) 111 if (ready_buffer_upper_bound_ == kNoTimestamp())
109 audio_.ApplyDurationEstimateIfNeeded(); 112 UpdateReadyBuffers();
110 return audio_.buffers(); 113
114 return audio_.ready_buffers();
111 } 115 }
112 116
113 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() { 117 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() {
114 if (cluster_ended_) 118 if (ready_buffer_upper_bound_ == kNoTimestamp())
115 video_.ApplyDurationEstimateIfNeeded(); 119 UpdateReadyBuffers();
116 return video_.buffers(); 120
121 return video_.ready_buffers();
117 } 122 }
118 123
119 const WebMClusterParser::TextBufferQueueMap& 124 const WebMClusterParser::TextBufferQueueMap&
120 WebMClusterParser::GetTextBuffers() { 125 WebMClusterParser::GetTextBuffers() {
126 if (ready_buffer_upper_bound_ == kNoTimestamp())
127 UpdateReadyBuffers();
128
121 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in 129 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in
122 // the output only for non-empty text buffer queues in |text_track_map_|. 130 // the output only for non-empty ready_buffer() queues in |text_track_map_|.
123 text_buffers_map_.clear(); 131 text_buffers_map_.clear();
124 for (TextTrackMap::const_iterator itr = text_track_map_.begin(); 132 for (TextTrackMap::const_iterator itr = text_track_map_.begin();
125 itr != text_track_map_.end(); 133 itr != text_track_map_.end();
126 ++itr) { 134 ++itr) {
127 // Per OnBlock(), all text buffers should already have valid durations, so 135 const BufferQueue& text_buffers = itr->second.ready_buffers();
128 // there is no need to call
129 // itr->second.ApplyDurationEstimateIfNeeded() here.
130 const BufferQueue& text_buffers = itr->second.buffers();
131 if (!text_buffers.empty()) 136 if (!text_buffers.empty())
132 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); 137 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers));
133 } 138 }
134 139
135 return text_buffers_map_; 140 return text_buffers_map_;
136 } 141 }
137 142
138 WebMParserClient* WebMClusterParser::OnListStart(int id) { 143 WebMParserClient* WebMClusterParser::OnListStart(int id) {
139 if (id == kWebMIdCluster) { 144 if (id == kWebMIdCluster) {
140 cluster_timecode_ = -1; 145 cluster_timecode_ = -1;
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 } 411 }
407 412
408 if (discard_padding != 0) { 413 if (discard_padding != 0) {
409 buffer->set_discard_padding(base::TimeDelta::FromMicroseconds( 414 buffer->set_discard_padding(base::TimeDelta::FromMicroseconds(
410 discard_padding / 1000)); 415 discard_padding / 1000));
411 } 416 }
412 417
413 return track->AddBuffer(buffer); 418 return track->AddBuffer(buffer);
414 } 419 }
415 420
416 WebMClusterParser::Track::Track(int track_num, bool is_video, 421 WebMClusterParser::Track::Track(int track_num,
417 base::TimeDelta default_duration) 422 bool is_video,
423 base::TimeDelta default_duration,
424 const LogCB& log_cb)
418 : track_num_(track_num), 425 : track_num_(track_num),
419 is_video_(is_video), 426 is_video_(is_video),
420 default_duration_(default_duration), 427 default_duration_(default_duration),
421 estimated_next_frame_duration_(kNoTimestamp()) { 428 estimated_next_frame_duration_(kNoTimestamp()),
429 log_cb_(log_cb) {
422 DCHECK(default_duration_ == kNoTimestamp() || 430 DCHECK(default_duration_ == kNoTimestamp() ||
423 default_duration_ > base::TimeDelta()); 431 default_duration_ > base::TimeDelta());
424 } 432 }
425 433
426 WebMClusterParser::Track::~Track() {} 434 WebMClusterParser::Track::~Track() {}
427 435
436 base::TimeDelta WebMClusterParser::Track::GetReadyUpperBound() {
437 DCHECK(ready_buffers_.empty());
438 if (last_added_buffer_missing_duration_)
439 return last_added_buffer_missing_duration_->GetDecodeTimestamp();
440
441 return kInfiniteDuration();
442 }
443
444 void WebMClusterParser::Track::ExtractReadyBuffers(
445 const base::TimeDelta before_timestamp) {
446 DCHECK(ready_buffers_.empty());
447 DCHECK(base::TimeDelta() <= before_timestamp);
448 DCHECK(kNoTimestamp() != before_timestamp);
449
450 if (buffers_.empty())
451 return;
452
453 if (buffers_.back()->GetDecodeTimestamp() < before_timestamp) {
454 // All of |buffers_| are ready.
455 ready_buffers_.swap(buffers_);
456 DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " All "
457 << ready_buffers_.size() << " are ready: before upper bound ts "
458 << before_timestamp.InSecondsF();
459 return;
460 }
461
462 // Not all of |buffers_| are ready yet. Move any that are ready to
463 // |ready_buffers_|.
464 while (true) {
465 const scoped_refptr<StreamParserBuffer>& buffer = buffers_.front();
466 if (buffer->GetDecodeTimestamp() >= before_timestamp)
467 break;
468 ready_buffers_.push_back(buffer);
469 buffers_.pop_front();
470 DCHECK(!buffers_.empty());
471 }
472
473 DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " Only "
474 << ready_buffers_.size() << " ready, " << buffers_.size()
475 << " at or after upper bound ts " << before_timestamp.InSecondsF();
476 }
477
428 bool WebMClusterParser::Track::AddBuffer( 478 bool WebMClusterParser::Track::AddBuffer(
429 const scoped_refptr<StreamParserBuffer>& buffer) { 479 const scoped_refptr<StreamParserBuffer>& buffer) {
430 DVLOG(2) << "AddBuffer() : " << track_num_ 480 DVLOG(2) << "AddBuffer() : " << track_num_
431 << " ts " << buffer->timestamp().InSecondsF() 481 << " ts " << buffer->timestamp().InSecondsF()
432 << " dur " << buffer->duration().InSecondsF() 482 << " dur " << buffer->duration().InSecondsF()
433 << " kf " << buffer->IsKeyframe() 483 << " kf " << buffer->IsKeyframe()
434 << " size " << buffer->data_size(); 484 << " size " << buffer->data_size();
435 485
436 if (last_added_buffer_missing_duration_) { 486 if (last_added_buffer_missing_duration_) {
437 base::TimeDelta derived_duration = 487 base::TimeDelta derived_duration =
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 << last_added_buffer_missing_duration_->duration().InSecondsF() 524 << last_added_buffer_missing_duration_->duration().InSecondsF()
475 << " kf " << last_added_buffer_missing_duration_->IsKeyframe() 525 << " kf " << last_added_buffer_missing_duration_->IsKeyframe()
476 << " size " << last_added_buffer_missing_duration_->data_size(); 526 << " size " << last_added_buffer_missing_duration_->data_size();
477 527
478 // Don't use the applied duration as a future estimation (don't use 528 // Don't use the applied duration as a future estimation (don't use
479 // QueueBuffer() here.) 529 // QueueBuffer() here.)
480 buffers_.push_back(last_added_buffer_missing_duration_); 530 buffers_.push_back(last_added_buffer_missing_duration_);
481 last_added_buffer_missing_duration_ = NULL; 531 last_added_buffer_missing_duration_ = NULL;
482 } 532 }
483 533
484 void WebMClusterParser::Track::ClearBuffersButKeepLastIfMissingDuration() { 534 void WebMClusterParser::Track::ClearReadyBuffers() {
485 // Note that |estimated_next_frame_duration_| is not reset, so it can be 535 // Note that |buffers_| are kept and |estimated_next_frame_duration_| is not
486 // reused on subsequent buffers added to this instance. 536 // reset here.
487 buffers_.clear(); 537 ready_buffers_.clear();
488 } 538 }
489 539
490 void WebMClusterParser::Track::Reset() { 540 void WebMClusterParser::Track::Reset() {
491 ClearBuffersButKeepLastIfMissingDuration(); 541 ClearReadyBuffers();
542 buffers_.clear();
492 last_added_buffer_missing_duration_ = NULL; 543 last_added_buffer_missing_duration_ = NULL;
493 } 544 }
494 545
495 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const { 546 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const {
496 // For now, assume that all blocks are keyframes for datatypes other than 547 // For now, assume that all blocks are keyframes for datatypes other than
497 // video. This is a valid assumption for Vorbis, WebVTT, & Opus. 548 // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
498 if (!is_video_) 549 if (!is_video_)
499 return true; 550 return true;
500 551
501 // Make sure the block is big enough for the minimal keyframe header size. 552 // Make sure the block is big enough for the minimal keyframe header size.
502 if (size < 7) 553 if (size < 7)
503 return false; 554 return false;
504 555
505 // The LSb of the first byte must be a 0 for a keyframe. 556 // The LSb of the first byte must be a 0 for a keyframe.
506 // http://tools.ietf.org/html/rfc6386 Section 19.1 557 // http://tools.ietf.org/html/rfc6386 Section 19.1
507 if ((data[0] & 0x01) != 0) 558 if ((data[0] & 0x01) != 0)
508 return false; 559 return false;
509 560
510 // Verify VP8 keyframe startcode. 561 // Verify VP8 keyframe startcode.
511 // http://tools.ietf.org/html/rfc6386 Section 19.1 562 // http://tools.ietf.org/html/rfc6386 Section 19.1
512 if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) 563 if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a)
513 return false; 564 return false;
514 565
515 return true; 566 return true;
516 } 567 }
517 568
518 bool WebMClusterParser::Track::QueueBuffer( 569 bool WebMClusterParser::Track::QueueBuffer(
519 const scoped_refptr<StreamParserBuffer>& buffer) { 570 const scoped_refptr<StreamParserBuffer>& buffer) {
520 DCHECK(!last_added_buffer_missing_duration_); 571 DCHECK(!last_added_buffer_missing_duration_);
572
573 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing
574 // block timecode detection within a cluster. Therefore, we should not see
575 // those here.
576 base::TimeDelta previous_buffers_timestamp = buffers_.empty() ?
577 base::TimeDelta() : buffers_.back()->GetDecodeTimestamp();
578 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp());
579
521 base::TimeDelta duration = buffer->duration(); 580 base::TimeDelta duration = buffer->duration();
522 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { 581 if (duration < base::TimeDelta() || duration == kNoTimestamp()) {
523 DVLOG(2) << "QueueBuffer() : Invalid buffer duration: " 582 MEDIA_LOG(log_cb_) << "Invalid buffer duration: " << duration.InSecondsF();
524 << duration.InSecondsF();
525 return false; 583 return false;
526 } 584 }
527 585
528 // The estimated frame duration is the minimum non-zero duration since the 586 // The estimated frame duration is the minimum non-zero duration since the
529 // last initialization segment. The minimum is used to ensure frame durations 587 // last initialization segment. The minimum is used to ensure frame durations
530 // aren't overestimated. 588 // aren't overestimated.
531 if (duration > base::TimeDelta()) { 589 if (duration > base::TimeDelta()) {
532 if (estimated_next_frame_duration_ == kNoTimestamp()) { 590 if (estimated_next_frame_duration_ == kNoTimestamp()) {
533 estimated_next_frame_duration_ = duration; 591 estimated_next_frame_duration_ = duration;
534 } else { 592 } else {
(...skipping 19 matching lines...) Expand all
554 duration = base::TimeDelta::FromMilliseconds( 612 duration = base::TimeDelta::FromMilliseconds(
555 kDefaultAudioBufferDurationInMs); 613 kDefaultAudioBufferDurationInMs);
556 } 614 }
557 } 615 }
558 616
559 DCHECK(duration > base::TimeDelta()); 617 DCHECK(duration > base::TimeDelta());
560 DCHECK(duration != kNoTimestamp()); 618 DCHECK(duration != kNoTimestamp());
561 return duration; 619 return duration;
562 } 620 }
563 621
622 void WebMClusterParser::ClearTextTrackReadyBuffers() {
623 text_buffers_map_.clear();
624 for (TextTrackMap::iterator it = text_track_map_.begin();
625 it != text_track_map_.end();
626 ++it) {
627 it->second.ClearReadyBuffers();
628 }
629 }
630
564 void WebMClusterParser::ResetTextTracks() { 631 void WebMClusterParser::ResetTextTracks() {
565 text_buffers_map_.clear(); 632 ClearTextTrackReadyBuffers();
566 for (TextTrackMap::iterator it = text_track_map_.begin(); 633 for (TextTrackMap::iterator it = text_track_map_.begin();
567 it != text_track_map_.end(); 634 it != text_track_map_.end();
568 ++it) { 635 ++it) {
569 it->second.Reset(); 636 it->second.Reset();
570 } 637 }
571 } 638 }
572 639
640 void WebMClusterParser::UpdateReadyBuffers() {
641 DCHECK(ready_buffer_upper_bound_ == kNoTimestamp());
642 DCHECK(text_buffers_map_.empty());
643
644 if (cluster_ended_) {
645 audio_.ApplyDurationEstimateIfNeeded();
646 video_.ApplyDurationEstimateIfNeeded();
647 // Per OnBlock(), all text buffers should already have valid durations, so
648 // there is no need to call ApplyDurationEstimateIfNeeded() on text tracks
649 // here.
650 ready_buffer_upper_bound_ = kInfiniteDuration();
651 DCHECK(ready_buffer_upper_bound_ == audio_.GetReadyUpperBound());
652 DCHECK(ready_buffer_upper_bound_ == video_.GetReadyUpperBound());
653 } else {
654 ready_buffer_upper_bound_ = std::min(audio_.GetReadyUpperBound(),
655 video_.GetReadyUpperBound());
656 DCHECK(base::TimeDelta() <= ready_buffer_upper_bound_);
657 DCHECK(kNoTimestamp() != ready_buffer_upper_bound_);
658 }
659
660 // Prepare each track's ready buffers for retrieval.
661 audio_.ExtractReadyBuffers(ready_buffer_upper_bound_);
662 video_.ExtractReadyBuffers(ready_buffer_upper_bound_);
663 for (TextTrackMap::iterator itr = text_track_map_.begin();
664 itr != text_track_map_.end();
665 ++itr) {
666 itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_);
667 }
668 }
669
573 WebMClusterParser::Track* 670 WebMClusterParser::Track*
574 WebMClusterParser::FindTextTrack(int track_num) { 671 WebMClusterParser::FindTextTrack(int track_num) {
575 const TextTrackMap::iterator it = text_track_map_.find(track_num); 672 const TextTrackMap::iterator it = text_track_map_.find(track_num);
576 673
577 if (it == text_track_map_.end()) 674 if (it == text_track_map_.end())
578 return NULL; 675 return NULL;
579 676
580 return &it->second; 677 return &it->second;
581 } 678 }
582 679
583 } // namespace media 680 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698