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

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

Issue 1008463002: Fix MSE GC, make it less aggressive, more spec-compliant (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: A bit more informative logging + fixed unit test Created 5 years, 4 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
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 #include <sstream> 9 #include <sstream>
10 10
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 // are appended to the range covered by |track_buffer_|. 385 // are appended to the range covered by |track_buffer_|.
386 if (!track_buffer_.empty()) { 386 if (!track_buffer_.empty()) {
387 DecodeTimestamp keyframe_timestamp = 387 DecodeTimestamp keyframe_timestamp =
388 FindKeyframeAfterTimestamp(track_buffer_.front()->GetDecodeTimestamp()); 388 FindKeyframeAfterTimestamp(track_buffer_.front()->GetDecodeTimestamp());
389 if (keyframe_timestamp != kNoDecodeTimestamp()) 389 if (keyframe_timestamp != kNoDecodeTimestamp())
390 PruneTrackBuffer(keyframe_timestamp); 390 PruneTrackBuffer(keyframe_timestamp);
391 } 391 }
392 392
393 SetSelectedRangeIfNeeded(next_buffer_timestamp); 393 SetSelectedRangeIfNeeded(next_buffer_timestamp);
394 394
395 GarbageCollectIfNeeded();
396
397 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 395 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
398 << ": done. ranges_=" << RangesToString(ranges_); 396 << ": done. ranges_=" << RangesToString(ranges_);
399 DCHECK(IsRangeListSorted(ranges_)); 397 DCHECK(IsRangeListSorted(ranges_));
400 DCHECK(OnlySelectedRangeIsSeeked()); 398 DCHECK(OnlySelectedRangeIsSeeked());
401 return true; 399 return true;
402 } 400 }
403 401
404 void SourceBufferStream::Remove(base::TimeDelta start, base::TimeDelta end, 402 void SourceBufferStream::Remove(base::TimeDelta start, base::TimeDelta end,
405 base::TimeDelta duration) { 403 base::TimeDelta duration) {
406 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 404 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 } 632 }
635 } 633 }
636 634
637 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { 635 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) {
638 for (BufferQueue::const_iterator itr = buffers.begin(); 636 for (BufferQueue::const_iterator itr = buffers.begin();
639 itr != buffers.end(); ++itr) { 637 itr != buffers.end(); ++itr) {
640 (*itr)->SetConfigId(append_config_index_); 638 (*itr)->SetConfigId(append_config_index_);
641 } 639 }
642 } 640 }
643 641
644 void SourceBufferStream::GarbageCollectIfNeeded() { 642 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time) {
643 DCHECK(media_time != kNoDecodeTimestamp());
645 // Compute size of |ranges_|. 644 // Compute size of |ranges_|.
646 size_t ranges_size = 0; 645 size_t ranges_size = 0;
647 for (RangeList::iterator itr = ranges_.begin(); itr != ranges_.end(); ++itr) 646 for (RangeList::iterator itr = ranges_.begin(); itr != ranges_.end(); ++itr)
648 ranges_size += (*itr)->size_in_bytes(); 647 ranges_size += (*itr)->size_in_bytes();
649 648
650 // Return if we're under or at the memory limit. 649 // Return if we're under or at the memory limit.
651 if (ranges_size <= memory_limit_) 650 if (ranges_size <= memory_limit_)
652 return; 651 return true;
653 652
654 size_t bytes_to_free = ranges_size - memory_limit_; 653 size_t bytes_to_free = ranges_size - memory_limit_;
655 654
656 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" 655 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC"
656 << " media_time=" << media_time.InSecondsF()
657 << " ranges_=" << RangesToString(ranges_)
657 << " ranges_size=" << ranges_size 658 << " ranges_size=" << ranges_size
658 << " ranges_=" << RangesToString(ranges_) 659 << " memory_limit_=" << memory_limit_
659 << " memory_limit_=" << memory_limit_; 660 << " last_appended_buffer_timestamp_="
661 << last_appended_buffer_timestamp_.InSecondsF();
660 662
661 // Begin deleting after the last appended buffer. 663 size_t bytes_freed = 0;
662 size_t bytes_freed = FreeBuffersAfterLastAppended(bytes_to_free);
663 664
664 // Begin deleting from the front. 665 // If last appended buffer position was earlier than the current playback time
665 if (bytes_freed < bytes_to_free) 666 // then try deleting data between last append and current media_time.
666 bytes_freed += FreeBuffers(bytes_to_free - bytes_freed, false); 667 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() &&
668 last_appended_buffer_timestamp_ < media_time) {
669 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
670 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended "
671 << " released " << between << " bytes"
672 << " ranges_=" << RangesToString(ranges_);
673 bytes_freed += between;
667 674
668 // Begin deleting from the back. 675 // If the last append happened before the current playback position
669 if (bytes_freed < bytes_to_free) 676 // |media_time|, then JS player is probably preparing to seek back and we
670 bytes_freed += FreeBuffers(bytes_to_free - bytes_freed, true); 677 // should try to preserve all most recently appended data (which is in
678 // range_for_next_append_) from being removed by GC (see crbug.com/440173)
679 if (range_for_next_append_ != ranges_.end()) {
680 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
681 media_time = (*range_for_next_append_)->GetStartTimestamp();
wolenetz 2015/08/12 21:09:57 This may be too lax, though web apps can follow-up
servolk 2015/08/13 00:31:42 Wait, we will only adjust media time here if range
682 }
683 }
684
685 // Try removing data from the front of the SourceBuffer up to |media_time|
686 // position.
687 if (bytes_freed < bytes_to_free) {
688 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
689 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the front"
690 << " ranges_=" << RangesToString(ranges_);
691 bytes_freed += front;
692 }
693
694 // Try removing data from the back of the SourceBuffer, until we reach the
695 // most recent append position.
696 if (bytes_freed < bytes_to_free) {
697 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
698 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back"
699 << " ranges_=" << RangesToString(ranges_);
700 bytes_freed += back;
701 }
671 702
672 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC" 703 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC"
704 << " bytes_to_free=" << bytes_to_free
673 << " bytes_freed=" << bytes_freed 705 << " bytes_freed=" << bytes_freed
674 << " ranges_=" << RangesToString(ranges_); 706 << " ranges_=" << RangesToString(ranges_);
707
708 return bytes_freed >= bytes_to_free;
675 } 709 }
676 710
677 size_t SourceBufferStream::FreeBuffersAfterLastAppended( 711 size_t SourceBufferStream::FreeBuffersAfterLastAppended(
678 size_t total_bytes_to_free) { 712 size_t total_bytes_to_free, DecodeTimestamp media_time) {
679 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); 713 DVLOG(4) << __FUNCTION__ << " last_appended_buffer_timestamp_="
680 if (last_appended_buffer_timestamp_ == kNoDecodeTimestamp() || 714 << last_appended_buffer_timestamp_.InSecondsF()
681 next_buffer_timestamp == kNoDecodeTimestamp() || 715 << " media_time=" << media_time.InSecondsF();
682 last_appended_buffer_timestamp_ >= next_buffer_timestamp) {
683 return 0;
684 }
685 716
686 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_; 717 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_;
687 if (last_appended_buffer_is_keyframe_) 718 if (last_appended_buffer_is_keyframe_)
688 remove_range_start += GetMaxInterbufferDistance(); 719 remove_range_start += GetMaxInterbufferDistance();
689 720
690 DecodeTimestamp remove_range_start_keyframe = FindKeyframeAfterTimestamp( 721 DecodeTimestamp remove_range_start_keyframe = FindKeyframeAfterTimestamp(
691 remove_range_start); 722 remove_range_start);
692 if (remove_range_start_keyframe != kNoDecodeTimestamp()) 723 if (remove_range_start_keyframe != kNoDecodeTimestamp())
693 remove_range_start = remove_range_start_keyframe; 724 remove_range_start = remove_range_start_keyframe;
694 if (remove_range_start >= next_buffer_timestamp) 725 if (remove_range_start >= media_time)
695 return 0; 726 return 0;
696 727
697 DecodeTimestamp remove_range_end; 728 DecodeTimestamp remove_range_end;
698 size_t bytes_freed = GetRemovalRange(remove_range_start, 729 size_t bytes_freed = GetRemovalRange(remove_range_start,
699 next_buffer_timestamp, 730 media_time,
700 total_bytes_to_free, 731 total_bytes_to_free,
701 &remove_range_end); 732 &remove_range_end);
702 if (bytes_freed > 0) { 733 if (bytes_freed > 0) {
734 DVLOG(4) << __FUNCTION__ << " removing ["
735 << remove_range_start.ToPresentationTime().InSecondsF() << ";"
736 << remove_range_end.ToPresentationTime().InSecondsF() << "]";
703 Remove(remove_range_start.ToPresentationTime(), 737 Remove(remove_range_start.ToPresentationTime(),
704 remove_range_end.ToPresentationTime(), 738 remove_range_end.ToPresentationTime(),
705 next_buffer_timestamp.ToPresentationTime()); 739 media_time.ToPresentationTime());
706 } 740 }
707 741
708 return bytes_freed; 742 return bytes_freed;
709 } 743 }
710 744
711 size_t SourceBufferStream::GetRemovalRange( 745 size_t SourceBufferStream::GetRemovalRange(
712 DecodeTimestamp start_timestamp, DecodeTimestamp end_timestamp, 746 DecodeTimestamp start_timestamp, DecodeTimestamp end_timestamp,
713 size_t total_bytes_to_free, DecodeTimestamp* removal_end_timestamp) { 747 size_t total_bytes_to_free, DecodeTimestamp* removal_end_timestamp) {
714 DCHECK(start_timestamp >= DecodeTimestamp()) << start_timestamp.InSecondsF(); 748 DCHECK(start_timestamp >= DecodeTimestamp()) << start_timestamp.InSecondsF();
715 DCHECK(start_timestamp < end_timestamp) 749 DCHECK(start_timestamp < end_timestamp)
(...skipping 12 matching lines...) Expand all
728 762
729 size_t bytes_to_free = total_bytes_to_free - bytes_freed; 763 size_t bytes_to_free = total_bytes_to_free - bytes_freed;
730 size_t bytes_removed = range->GetRemovalGOP( 764 size_t bytes_removed = range->GetRemovalGOP(
731 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp); 765 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp);
732 bytes_freed += bytes_removed; 766 bytes_freed += bytes_removed;
733 } 767 }
734 return bytes_freed; 768 return bytes_freed;
735 } 769 }
736 770
737 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free, 771 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free,
772 DecodeTimestamp media_time,
738 bool reverse_direction) { 773 bool reverse_direction) {
739 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers", 774 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers",
740 "total bytes to free", total_bytes_to_free, 775 "total bytes to free", total_bytes_to_free,
741 "reverse direction", reverse_direction); 776 "reverse direction", reverse_direction);
742 777
743 DCHECK_GT(total_bytes_to_free, 0u); 778 DCHECK_GT(total_bytes_to_free, 0u);
744 size_t bytes_freed = 0; 779 size_t bytes_freed = 0;
745 780
746 // This range will save the last GOP appended to |range_for_next_append_| 781 // This range will save the last GOP appended to |range_for_next_append_|
747 // if the buffers surrounding it get deleted during garbage collection. 782 // if the buffers surrounding it get deleted during garbage collection.
748 SourceBufferRange* new_range_for_append = NULL; 783 SourceBufferRange* new_range_for_append = NULL;
749 784
750 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) { 785 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) {
751 SourceBufferRange* current_range = NULL; 786 SourceBufferRange* current_range = NULL;
752 BufferQueue buffers; 787 BufferQueue buffers;
753 size_t bytes_deleted = 0; 788 size_t bytes_deleted = 0;
754 789
755 if (reverse_direction) { 790 if (reverse_direction) {
756 current_range = ranges_.back(); 791 current_range = ranges_.back();
792 DVLOG(5) << "current_range=" << RangeToString(*current_range);
757 if (current_range->LastGOPContainsNextBufferPosition()) { 793 if (current_range->LastGOPContainsNextBufferPosition()) {
758 DCHECK_EQ(current_range, selected_range_); 794 DCHECK_EQ(current_range, selected_range_);
795 DVLOG(5) << "current_range contains next read position, stopping GC";
759 break; 796 break;
760 } 797 }
798 DVLOG(5) << "Deleting GOP from back: " << RangeToString(*current_range);
761 bytes_deleted = current_range->DeleteGOPFromBack(&buffers); 799 bytes_deleted = current_range->DeleteGOPFromBack(&buffers);
762 } else { 800 } else {
763 current_range = ranges_.front(); 801 current_range = ranges_.front();
764 if (current_range->FirstGOPContainsNextBufferPosition()) { 802 DVLOG(5) << "current_range=" << RangeToString(*current_range);
765 DCHECK_EQ(current_range, selected_range_); 803 if (!current_range->FirstGOPEarlierThanMediaTime(media_time)) {
804 // We have removed all data up to the GOP that contains current playback
805 // position, we can't delete any further.
806 DVLOG(5) << "current_range contains playback position, stopping GC";
766 break; 807 break;
767 } 808 }
809 DVLOG(4) << "Deleting GOP from front: " << RangeToString(*current_range);
768 bytes_deleted = current_range->DeleteGOPFromFront(&buffers); 810 bytes_deleted = current_range->DeleteGOPFromFront(&buffers);
769 } 811 }
770 812
771 // Check to see if we've just deleted the GOP that was last appended. 813 // Check to see if we've just deleted the GOP that was last appended.
772 DecodeTimestamp end_timestamp = buffers.back()->GetDecodeTimestamp(); 814 DecodeTimestamp end_timestamp = buffers.back()->GetDecodeTimestamp();
773 if (end_timestamp == last_appended_buffer_timestamp_) { 815 if (end_timestamp == last_appended_buffer_timestamp_) {
774 DCHECK(last_appended_buffer_timestamp_ != kNoDecodeTimestamp()); 816 DCHECK(last_appended_buffer_timestamp_ != kNoDecodeTimestamp());
775 DCHECK(!new_range_for_append); 817 DCHECK(!new_range_for_append);
818
776 // Create a new range containing these buffers. 819 // Create a new range containing these buffers.
777 new_range_for_append = new SourceBufferRange( 820 new_range_for_append = new SourceBufferRange(
778 TypeToGapPolicy(GetType()), 821 TypeToGapPolicy(GetType()),
779 buffers, kNoDecodeTimestamp(), 822 buffers, kNoDecodeTimestamp(),
780 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, 823 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
781 base::Unretained(this))); 824 base::Unretained(this)));
782 range_for_next_append_ = ranges_.end(); 825 range_for_next_append_ = ranges_.end();
783 } else { 826 } else {
784 bytes_freed += bytes_deleted; 827 bytes_freed += bytes_deleted;
785 } 828 }
786 829
787 if (current_range->size_in_bytes() == 0) { 830 if (current_range->size_in_bytes() == 0) {
788 DCHECK_NE(current_range, selected_range_); 831 DCHECK_NE(current_range, selected_range_);
789 DCHECK(range_for_next_append_ == ranges_.end() || 832 DCHECK(range_for_next_append_ == ranges_.end() ||
790 *range_for_next_append_ != current_range); 833 *range_for_next_append_ != current_range);
791 delete current_range; 834 delete current_range;
792 reverse_direction ? ranges_.pop_back() : ranges_.pop_front(); 835 reverse_direction ? ranges_.pop_back() : ranges_.pop_front();
793 } 836 }
837
838 if (reverse_direction && new_range_for_append) {
839 // We don't want to delete any further, or we'll be creating gaps
840 break;
841 }
794 } 842 }
795 843
796 // Insert |new_range_for_append| into |ranges_|, if applicable. 844 // Insert |new_range_for_append| into |ranges_|, if applicable.
797 if (new_range_for_append) { 845 if (new_range_for_append) {
798 range_for_next_append_ = AddToRanges(new_range_for_append); 846 range_for_next_append_ = AddToRanges(new_range_for_append);
799 DCHECK(range_for_next_append_ != ranges_.end()); 847 DCHECK(range_for_next_append_ != ranges_.end());
800 848
801 // Check to see if we need to merge |new_range_for_append| with the range 849 // Check to see if we need to merge |new_range_for_append| with the range
802 // before or after it. |new_range_for_append| is created whenever the last 850 // before or after it. |new_range_for_append| is created whenever the last
803 // GOP appended is encountered, regardless of whether any buffers after it 851 // GOP appended is encountered, regardless of whether any buffers after it
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 } 1261 }
1214 1262
1215 void SourceBufferStream::SeekAndSetSelectedRange( 1263 void SourceBufferStream::SeekAndSetSelectedRange(
1216 SourceBufferRange* range, DecodeTimestamp seek_timestamp) { 1264 SourceBufferRange* range, DecodeTimestamp seek_timestamp) {
1217 if (range) 1265 if (range)
1218 range->Seek(seek_timestamp); 1266 range->Seek(seek_timestamp);
1219 SetSelectedRange(range); 1267 SetSelectedRange(range);
1220 } 1268 }
1221 1269
1222 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) { 1270 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) {
1223 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 1271 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << ": "
1224 << ": " << selected_range_ << " -> " << range; 1272 << selected_range_ << " "
1273 << (selected_range_ ? RangeToString(*selected_range_) : "")
1274 << " -> " << range << " " << (range ? RangeToString(*range) : "");
1225 if (selected_range_) 1275 if (selected_range_)
1226 selected_range_->ResetNextBufferPosition(); 1276 selected_range_->ResetNextBufferPosition();
1227 DCHECK(!range || range->HasNextBufferPosition()); 1277 DCHECK(!range || range->HasNextBufferPosition());
1228 selected_range_ = range; 1278 selected_range_ = range;
1229 } 1279 }
1230 1280
1231 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const { 1281 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const {
1232 Ranges<base::TimeDelta> ranges; 1282 Ranges<base::TimeDelta> ranges;
1233 for (RangeList::const_iterator itr = ranges_.begin(); 1283 for (RangeList::const_iterator itr = ranges_.begin();
1234 itr != ranges_.end(); ++itr) { 1284 itr != ranges_.end(); ++itr) {
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 return false; 1717 return false;
1668 1718
1669 DCHECK_NE(have_splice_buffers, have_preroll_buffer); 1719 DCHECK_NE(have_splice_buffers, have_preroll_buffer);
1670 splice_buffers_index_ = 0; 1720 splice_buffers_index_ = 0;
1671 pending_buffer_.swap(*out_buffer); 1721 pending_buffer_.swap(*out_buffer);
1672 pending_buffers_complete_ = false; 1722 pending_buffers_complete_ = false;
1673 return true; 1723 return true;
1674 } 1724 }
1675 1725
1676 } // namespace media 1726 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698