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

Side by Side Diff: media/filters/source_buffer_stream.cc

Issue 12701008: Fix SourceBufferStream alt-ref frame handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/filters/source_buffer_stream.h" 5 #include "media/filters/source_buffer_stream.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 // Returns the timestamp of the next buffer that will be returned from 116 // Returns the timestamp of the next buffer that will be returned from
117 // GetNextBuffer(), or kNoTimestamp() if the timestamp is unknown. 117 // GetNextBuffer(), or kNoTimestamp() if the timestamp is unknown.
118 base::TimeDelta GetNextTimestamp() const; 118 base::TimeDelta GetNextTimestamp() const;
119 119
120 // Returns the start timestamp of the range. 120 // Returns the start timestamp of the range.
121 base::TimeDelta GetStartTimestamp() const; 121 base::TimeDelta GetStartTimestamp() const;
122 122
123 // Returns the timestamp of the last buffer in the range. 123 // Returns the timestamp of the last buffer in the range.
124 base::TimeDelta GetEndTimestamp() const; 124 base::TimeDelta GetEndTimestamp() const;
125 125
126 // Returns true if the last buffer in the range is a keyframe.
127 bool IsEndKeyframe() const;
scherkus (not reviewing) 2013/03/11 21:23:40 EndsWithKeyframe?
acolwell GONE FROM CHROMIUM 2013/03/11 22:31:38 Removed. Method no longer needed.
128
126 // Returns the timestamp for the end of the buffered region in this range. 129 // Returns the timestamp for the end of the buffered region in this range.
127 // This is an approximation if the duration for the last buffer in the range 130 // This is an approximation if the duration for the last buffer in the range
128 // is unset. 131 // is unset.
129 base::TimeDelta GetBufferedEndTimestamp() const; 132 base::TimeDelta GetBufferedEndTimestamp() const;
130 133
131 // Gets the timestamp for the keyframe that is after |timestamp|. If 134 // Gets the timestamp for the keyframe that is after |timestamp|. If
132 // there isn't a keyframe in the range after |timestamp| then kNoTimestamp() 135 // there isn't a keyframe in the range after |timestamp| then kNoTimestamp()
133 // is returned. 136 // is returned.
134 base::TimeDelta NextKeyframeTimestamp(base::TimeDelta timestamp); 137 base::TimeDelta NextKeyframeTimestamp(base::TimeDelta timestamp);
135 138
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 DCHECK(!buffers.empty()); 371 DCHECK(!buffers.empty());
369 DCHECK(media_segment_start_time_ != kNoTimestamp()); 372 DCHECK(media_segment_start_time_ != kNoTimestamp());
370 373
371 // New media segments must begin with a keyframe. 374 // New media segments must begin with a keyframe.
372 if (new_media_segment_ && !buffers.front()->IsKeyframe()) { 375 if (new_media_segment_ && !buffers.front()->IsKeyframe()) {
373 MEDIA_LOG(log_cb_) << "Media segment did not begin with keyframe."; 376 MEDIA_LOG(log_cb_) << "Media segment did not begin with keyframe.";
374 return false; 377 return false;
375 } 378 }
376 379
377 // Buffers within a media segment should be monotonically increasing. 380 // Buffers within a media segment should be monotonically increasing.
378 if (!IsMonotonicallyIncreasing(buffers)) { 381 if (!IsMonotonicallyIncreasing(buffers))
379 MEDIA_LOG(log_cb_) << "Buffers were not monotonically increasing.";
380 return false; 382 return false;
381 }
382 383
383 if (media_segment_start_time_ < base::TimeDelta() || 384 if (media_segment_start_time_ < base::TimeDelta() ||
384 buffers.front()->GetDecodeTimestamp() < base::TimeDelta()) { 385 buffers.front()->GetDecodeTimestamp() < base::TimeDelta()) {
385 MEDIA_LOG(log_cb_) 386 MEDIA_LOG(log_cb_)
386 << "Cannot append a media segment with negative timestamps."; 387 << "Cannot append a media segment with negative timestamps.";
387 return false; 388 return false;
388 } 389 }
389 390
390 UpdateMaxInterbufferDistance(buffers); 391 UpdateMaxInterbufferDistance(buffers);
391 SetConfigIds(buffers); 392 SetConfigIds(buffers);
392 393
393 // Save a snapshot of stream state before range modifications are made. 394 // Save a snapshot of stream state before range modifications are made.
394 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp(); 395 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
395 BufferQueue deleted_buffers; 396 BufferQueue deleted_buffers;
396 397
397 RangeList::iterator range_for_new_buffers = range_for_next_append_; 398 RangeList::iterator range_for_new_buffers = range_for_next_append_;
398 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, 399 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
399 // create a new range with |buffers|. 400 // create a new range with |buffers|.
400 if (range_for_new_buffers != ranges_.end()) { 401 if (range_for_new_buffers != ranges_.end()) {
401 InsertIntoExistingRange(range_for_new_buffers, buffers, &deleted_buffers); 402 if (!InsertIntoExistingRange(range_for_new_buffers, buffers,
403 &deleted_buffers)) {
404 return false;
405 }
402 } else { 406 } else {
403 DCHECK(new_media_segment_); 407 DCHECK(new_media_segment_);
404 range_for_new_buffers = 408 range_for_new_buffers =
405 AddToRanges(new SourceBufferRange( 409 AddToRanges(new SourceBufferRange(
406 buffers, media_segment_start_time_, 410 buffers, media_segment_start_time_,
407 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, 411 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
408 base::Unretained(this)))); 412 base::Unretained(this))));
409 } 413 }
410 414
411 range_for_next_append_ = range_for_new_buffers; 415 range_for_next_append_ = range_for_new_buffers;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 base::TimeDelta beginning_of_buffered = 474 base::TimeDelta beginning_of_buffered =
471 ranges_.front()->GetStartTimestamp(); 475 ranges_.front()->GetStartTimestamp();
472 return (seek_timestamp <= beginning_of_buffered && 476 return (seek_timestamp <= beginning_of_buffered &&
473 beginning_of_buffered < kSeekToStartFudgeRoom()); 477 beginning_of_buffered < kSeekToStartFudgeRoom());
474 } 478 }
475 479
476 bool SourceBufferStream::IsMonotonicallyIncreasing( 480 bool SourceBufferStream::IsMonotonicallyIncreasing(
477 const BufferQueue& buffers) const { 481 const BufferQueue& buffers) const {
478 DCHECK(!buffers.empty()); 482 DCHECK(!buffers.empty());
479 base::TimeDelta prev_timestamp = last_appended_buffer_timestamp_; 483 base::TimeDelta prev_timestamp = last_appended_buffer_timestamp_;
484 bool prev_is_keyframe = false;
480 for (BufferQueue::const_iterator itr = buffers.begin(); 485 for (BufferQueue::const_iterator itr = buffers.begin();
481 itr != buffers.end(); ++itr) { 486 itr != buffers.end(); ++itr) {
482 base::TimeDelta current_timestamp = (*itr)->GetDecodeTimestamp(); 487 base::TimeDelta current_timestamp = (*itr)->GetDecodeTimestamp();
488 bool current_is_keyframe = (*itr)->IsKeyframe();
483 DCHECK(current_timestamp != kNoTimestamp()); 489 DCHECK(current_timestamp != kNoTimestamp());
484 490
485 if (prev_timestamp != kNoTimestamp() && current_timestamp < prev_timestamp) 491 if (prev_timestamp != kNoTimestamp()) {
486 return false; 492 if (current_timestamp < prev_timestamp) {
493 MEDIA_LOG(log_cb_) << "Buffers were not monotonically increasing.";
494 return false;
495 }
496
497 if (current_timestamp == prev_timestamp &&
498 (current_is_keyframe || prev_is_keyframe)) {
499 MEDIA_LOG(log_cb_) << "Invalid alt-ref frame construct detected at "
500 << current_timestamp.InSecondsF();
501 return false;
502 }
503 }
487 504
488 prev_timestamp = current_timestamp; 505 prev_timestamp = current_timestamp;
506 prev_is_keyframe = current_is_keyframe;
489 } 507 }
490 return true; 508 return true;
491 } 509 }
492 510
493 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const { 511 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
494 for (RangeList::const_iterator itr = ranges_.begin(); 512 for (RangeList::const_iterator itr = ranges_.begin();
495 itr != ranges_.end(); ++itr) { 513 itr != ranges_.end(); ++itr) {
496 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_) 514 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_)
497 return false; 515 return false;
498 } 516 }
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 if (range_for_next_append_ != ranges_.begin()) { 639 if (range_for_next_append_ != ranges_.begin()) {
622 RangeList::iterator range_before_next = range_for_next_append_; 640 RangeList::iterator range_before_next = range_for_next_append_;
623 --range_before_next; 641 --range_before_next;
624 MergeWithAdjacentRangeIfNecessary(range_before_next); 642 MergeWithAdjacentRangeIfNecessary(range_before_next);
625 } 643 }
626 MergeWithAdjacentRangeIfNecessary(range_for_next_append_); 644 MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
627 } 645 }
628 return bytes_freed; 646 return bytes_freed;
629 } 647 }
630 648
631 void SourceBufferStream::InsertIntoExistingRange( 649 bool SourceBufferStream::InsertIntoExistingRange(
632 const RangeList::iterator& range_for_new_buffers_itr, 650 const RangeList::iterator& range_for_new_buffers_itr,
633 const BufferQueue& new_buffers, BufferQueue* deleted_buffers) { 651 const BufferQueue& new_buffers, BufferQueue* deleted_buffers) {
634 DCHECK(deleted_buffers); 652 DCHECK(deleted_buffers);
635 653
636 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr; 654 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr;
637 655
638 bool temporarily_select_range = false; 656 bool temporarily_select_range = false;
639 if (!track_buffer_.empty()) { 657 if (!track_buffer_.empty()) {
640 base::TimeDelta tb_timestamp = track_buffer_.back()->GetDecodeTimestamp(); 658 base::TimeDelta tb_timestamp = track_buffer_.back()->GetDecodeTimestamp();
641 base::TimeDelta seek_timestamp = FindKeyframeAfterTimestamp(tb_timestamp); 659 base::TimeDelta seek_timestamp = FindKeyframeAfterTimestamp(tb_timestamp);
(...skipping 17 matching lines...) Expand all
659 677
660 if (last_appended_buffer_timestamp_ != kNoTimestamp()) { 678 if (last_appended_buffer_timestamp_ != kNoTimestamp()) {
661 // Clean up the old buffers between the last appended buffer and the 679 // Clean up the old buffers between the last appended buffer and the
662 // beginning of |new_buffers|. 680 // beginning of |new_buffers|.
663 DeleteBetween( 681 DeleteBetween(
664 range_for_new_buffers_itr, last_appended_buffer_timestamp_, 682 range_for_new_buffers_itr, last_appended_buffer_timestamp_,
665 new_buffers.front()->GetDecodeTimestamp(), true, 683 new_buffers.front()->GetDecodeTimestamp(), true,
666 deleted_buffers); 684 deleted_buffers);
667 } 685 }
668 686
669 // If we cannot append the |new_buffers| to the end of the existing range, 687 base::TimeDelta prev_timestamp = range_for_new_buffers->GetEndTimestamp();
670 // this is either a start overlap or an middle overlap. Delete the buffers 688 bool prev_is_keyframe = range_for_new_buffers->IsEndKeyframe();
671 // that |new_buffers| overlaps. 689 base::TimeDelta next_timestamp = new_buffers.front()->GetDecodeTimestamp();
672 if (!range_for_new_buffers->CanAppendBuffersToEnd(new_buffers)) { 690 bool next_is_keyframe = new_buffers.front()->IsKeyframe();
691 bool is_valid_alt_ref = prev_timestamp == next_timestamp &&
scherkus (not reviewing) 2013/03/11 21:23:40 how does this compare with the if block below that
acolwell GONE FROM CHROMIUM 2013/03/11 22:31:38 This identifies a valid alt-ref construct that we
692 !prev_is_keyframe && !next_is_keyframe;
693
694 // Check for invalid alt-ref frame constructs.
695 // A keyframe followed by a non-keyframe or
696 // a non-keyframe followed by a keyframe that is not
697 // the first frame of a media segment are errors.
698 if (prev_timestamp == next_timestamp &&
699 ((prev_is_keyframe && !next_is_keyframe) ||
700 (!new_media_segment_ && next_is_keyframe))) {
701 MEDIA_LOG(log_cb_) << "Invalid alt-ref frame construct detected at time "
702 << prev_timestamp.InSecondsF();
703 return false;
704 }
705
706 // If a valid alt-ref frame sequence was not detected and we cannot append the
707 // |new_buffers| to the end of the existing range, this is either a start
708 // overlap or an middle overlap. Delete the buffers that |new_buffers|
709 // overlaps.
710 if (!is_valid_alt_ref &&
711 !range_for_new_buffers->CanAppendBuffersToEnd(new_buffers)) {
673 DeleteBetween( 712 DeleteBetween(
674 range_for_new_buffers_itr, new_buffers.front()->GetDecodeTimestamp(), 713 range_for_new_buffers_itr, new_buffers.front()->GetDecodeTimestamp(),
675 new_buffers.back()->GetDecodeTimestamp(), false, 714 new_buffers.back()->GetDecodeTimestamp(), false,
676 deleted_buffers); 715 deleted_buffers);
677 } 716 }
678 717
679 // Restore the range seek state if necessary. 718 // Restore the range seek state if necessary.
680 if (temporarily_select_range) 719 if (temporarily_select_range)
681 SetSelectedRange(NULL); 720 SetSelectedRange(NULL);
682 721
683 range_for_new_buffers->AppendBuffersToEnd(new_buffers); 722 range_for_new_buffers->AppendBuffersToEnd(new_buffers);
723 return true;
684 } 724 }
685 725
686 void SourceBufferStream::DeleteBetween( 726 void SourceBufferStream::DeleteBetween(
687 const RangeList::iterator& range_itr, base::TimeDelta start_timestamp, 727 const RangeList::iterator& range_itr, base::TimeDelta start_timestamp,
688 base::TimeDelta end_timestamp, bool is_range_exclusive, 728 base::TimeDelta end_timestamp, bool is_range_exclusive,
689 BufferQueue* deleted_buffers) { 729 BufferQueue* deleted_buffers) {
690 SourceBufferRange* new_next_range = 730 SourceBufferRange* new_next_range =
691 (*range_itr)->SplitRange(end_timestamp, is_range_exclusive); 731 (*range_itr)->SplitRange(end_timestamp, is_range_exclusive);
692 732
693 // Insert the |new_next_range| into |ranges_| after |range|. 733 // Insert the |new_next_range| into |ranges_| after |range|.
(...skipping 942 matching lines...) Expand 10 before | Expand all | Expand 10 after
1636 if (start_timestamp == kNoTimestamp()) 1676 if (start_timestamp == kNoTimestamp())
1637 start_timestamp = buffers_.front()->GetDecodeTimestamp(); 1677 start_timestamp = buffers_.front()->GetDecodeTimestamp();
1638 return start_timestamp; 1678 return start_timestamp;
1639 } 1679 }
1640 1680
1641 base::TimeDelta SourceBufferRange::GetEndTimestamp() const { 1681 base::TimeDelta SourceBufferRange::GetEndTimestamp() const {
1642 DCHECK(!buffers_.empty()); 1682 DCHECK(!buffers_.empty());
1643 return buffers_.back()->GetDecodeTimestamp(); 1683 return buffers_.back()->GetDecodeTimestamp();
1644 } 1684 }
1645 1685
1686 bool SourceBufferRange::IsEndKeyframe() const {
1687 DCHECK(!buffers_.empty());
1688 return buffers_.back()->IsKeyframe();
1689 }
1690
1646 base::TimeDelta SourceBufferRange::GetBufferedEndTimestamp() const { 1691 base::TimeDelta SourceBufferRange::GetBufferedEndTimestamp() const {
1647 DCHECK(!buffers_.empty()); 1692 DCHECK(!buffers_.empty());
1648 base::TimeDelta duration = buffers_.back()->GetDuration(); 1693 base::TimeDelta duration = buffers_.back()->GetDuration();
1649 if (duration == kNoTimestamp() || duration == base::TimeDelta()) 1694 if (duration == kNoTimestamp() || duration == base::TimeDelta())
1650 duration = GetApproximateDuration(); 1695 duration = GetApproximateDuration();
1651 return GetEndTimestamp() + duration; 1696 return GetEndTimestamp() + duration;
1652 } 1697 }
1653 1698
1654 base::TimeDelta SourceBufferRange::NextKeyframeTimestamp( 1699 base::TimeDelta SourceBufferRange::NextKeyframeTimestamp(
1655 base::TimeDelta timestamp) { 1700 base::TimeDelta timestamp) {
(...skipping 29 matching lines...) Expand all
1685 return ComputeFudgeRoom(GetApproximateDuration()); 1730 return ComputeFudgeRoom(GetApproximateDuration());
1686 } 1731 }
1687 1732
1688 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { 1733 base::TimeDelta SourceBufferRange::GetApproximateDuration() const {
1689 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); 1734 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run();
1690 DCHECK(max_interbuffer_distance != kNoTimestamp()); 1735 DCHECK(max_interbuffer_distance != kNoTimestamp());
1691 return max_interbuffer_distance; 1736 return max_interbuffer_distance;
1692 } 1737 }
1693 1738
1694 } // namespace media 1739 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698