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

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: Added overflow check to sanity checks and use CHECK instead of DCHECK 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 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 // are appended to the range covered by |track_buffer_|. 355 // are appended to the range covered by |track_buffer_|.
356 if (!track_buffer_.empty()) { 356 if (!track_buffer_.empty()) {
357 DecodeTimestamp keyframe_timestamp = 357 DecodeTimestamp keyframe_timestamp =
358 FindKeyframeAfterTimestamp(track_buffer_.front()->GetDecodeTimestamp()); 358 FindKeyframeAfterTimestamp(track_buffer_.front()->GetDecodeTimestamp());
359 if (keyframe_timestamp != kNoDecodeTimestamp()) 359 if (keyframe_timestamp != kNoDecodeTimestamp())
360 PruneTrackBuffer(keyframe_timestamp); 360 PruneTrackBuffer(keyframe_timestamp);
361 } 361 }
362 362
363 SetSelectedRangeIfNeeded(next_buffer_timestamp); 363 SetSelectedRangeIfNeeded(next_buffer_timestamp);
364 364
365 GarbageCollectIfNeeded();
366
367 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 365 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
368 << ": done. ranges_=" << RangesToString(ranges_); 366 << ": done. ranges_=" << RangesToString(ranges_);
369 DCHECK(IsRangeListSorted(ranges_)); 367 DCHECK(IsRangeListSorted(ranges_));
370 DCHECK(OnlySelectedRangeIsSeeked()); 368 DCHECK(OnlySelectedRangeIsSeeked());
371 return true; 369 return true;
372 } 370 }
373 371
374 void SourceBufferStream::Remove(base::TimeDelta start, base::TimeDelta end, 372 void SourceBufferStream::Remove(base::TimeDelta start, base::TimeDelta end,
375 base::TimeDelta duration) { 373 base::TimeDelta duration) {
376 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 374 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 } 603 }
606 } 604 }
607 605
608 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { 606 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) {
609 for (BufferQueue::const_iterator itr = buffers.begin(); 607 for (BufferQueue::const_iterator itr = buffers.begin();
610 itr != buffers.end(); ++itr) { 608 itr != buffers.end(); ++itr) {
611 (*itr)->SetConfigId(append_config_index_); 609 (*itr)->SetConfigId(append_config_index_);
612 } 610 }
613 } 611 }
614 612
615 void SourceBufferStream::GarbageCollectIfNeeded() { 613 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time,
614 size_t newDataSize) {
615 DCHECK(media_time != kNoDecodeTimestamp());
616 // Compute size of |ranges_|. 616 // Compute size of |ranges_|.
617 size_t ranges_size = 0; 617 size_t ranges_size = GetBufferedSize();
618 for (RangeList::iterator itr = ranges_.begin(); itr != ranges_.end(); ++itr) 618
619 ranges_size += (*itr)->size_in_bytes(); 619 // Sanity and overflow checks
620 if ((newDataSize > memory_limit_) ||
621 (ranges_size + newDataSize < ranges_size))
622 return false;
620 623
621 // Return if we're under or at the memory limit. 624 // Return if we're under or at the memory limit.
622 if (ranges_size <= memory_limit_) 625 if (ranges_size + newDataSize <= memory_limit_)
623 return; 626 return true;
624 627
625 size_t bytes_to_free = ranges_size - memory_limit_; 628 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_;
626 629
627 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" 630 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC"
631 << " media_time=" << media_time.InSecondsF()
632 << " ranges_=" << RangesToString(ranges_)
628 << " ranges_size=" << ranges_size 633 << " ranges_size=" << ranges_size
629 << " ranges_=" << RangesToString(ranges_) 634 << " newDataSize=" << newDataSize
630 << " memory_limit_=" << memory_limit_; 635 << " memory_limit_=" << memory_limit_
636 << " last_appended_buffer_timestamp_="
637 << last_appended_buffer_timestamp_.InSecondsF();
631 638
632 // Begin deleting after the last appended buffer. 639 size_t bytes_freed = 0;
633 size_t bytes_freed = FreeBuffersAfterLastAppended(bytes_to_free);
634 640
635 // Begin deleting from the front. 641 // If last appended buffer position was earlier than the current playback time
636 if (bytes_freed < bytes_to_free) 642 // then try deleting data between last append and current media_time.
637 bytes_freed += FreeBuffers(bytes_to_free - bytes_freed, false); 643 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() &&
644 last_appended_buffer_timestamp_ < media_time) {
645 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
646 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended "
647 << " released " << between << " bytes"
648 << " ranges_=" << RangesToString(ranges_);
649 bytes_freed += between;
638 650
639 // Begin deleting from the back. 651 // If the last append happened before the current playback position
640 if (bytes_freed < bytes_to_free) 652 // |media_time|, then JS player is probably preparing to seek back and we
641 bytes_freed += FreeBuffers(bytes_to_free - bytes_freed, true); 653 // should try to preserve all most recently appended data (which is in
654 // range_for_next_append_) from being removed by GC (see crbug.com/440173)
655 if (range_for_next_append_ != ranges_.end()) {
656 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
657 media_time = (*range_for_next_append_)->GetStartTimestamp();
658 }
659 }
660
661 // Try removing data from the front of the SourceBuffer up to |media_time|
662 // position.
663 if (bytes_freed < bytes_to_free) {
664 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
665 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the front"
666 << " ranges_=" << RangesToString(ranges_);
667 bytes_freed += front;
668 }
669
670 // Try removing data from the back of the SourceBuffer, until we reach the
671 // most recent append position.
672 if (bytes_freed < bytes_to_free) {
673 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
674 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back"
675 << " ranges_=" << RangesToString(ranges_);
676 bytes_freed += back;
677 }
642 678
643 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC" 679 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC"
680 << " bytes_to_free=" << bytes_to_free
644 << " bytes_freed=" << bytes_freed 681 << " bytes_freed=" << bytes_freed
645 << " ranges_=" << RangesToString(ranges_); 682 << " ranges_=" << RangesToString(ranges_);
683
684 return bytes_freed >= bytes_to_free;
646 } 685 }
647 686
648 size_t SourceBufferStream::FreeBuffersAfterLastAppended( 687 size_t SourceBufferStream::FreeBuffersAfterLastAppended(
649 size_t total_bytes_to_free) { 688 size_t total_bytes_to_free, DecodeTimestamp media_time) {
650 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); 689 DVLOG(4) << __FUNCTION__ << " last_appended_buffer_timestamp_="
651 if (last_appended_buffer_timestamp_ == kNoDecodeTimestamp() || 690 << last_appended_buffer_timestamp_.InSecondsF()
652 next_buffer_timestamp == kNoDecodeTimestamp() || 691 << " media_time=" << media_time.InSecondsF();
653 last_appended_buffer_timestamp_ >= next_buffer_timestamp) {
654 return 0;
655 }
656 692
657 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_; 693 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_;
658 if (last_appended_buffer_is_keyframe_) 694 if (last_appended_buffer_is_keyframe_)
659 remove_range_start += GetMaxInterbufferDistance(); 695 remove_range_start += GetMaxInterbufferDistance();
660 696
661 DecodeTimestamp remove_range_start_keyframe = FindKeyframeAfterTimestamp( 697 DecodeTimestamp remove_range_start_keyframe = FindKeyframeAfterTimestamp(
662 remove_range_start); 698 remove_range_start);
663 if (remove_range_start_keyframe != kNoDecodeTimestamp()) 699 if (remove_range_start_keyframe != kNoDecodeTimestamp())
664 remove_range_start = remove_range_start_keyframe; 700 remove_range_start = remove_range_start_keyframe;
665 if (remove_range_start >= next_buffer_timestamp) 701 if (remove_range_start >= media_time)
666 return 0; 702 return 0;
667 703
668 DecodeTimestamp remove_range_end; 704 DecodeTimestamp remove_range_end;
669 size_t bytes_freed = GetRemovalRange(remove_range_start, 705 size_t bytes_freed = GetRemovalRange(remove_range_start,
670 next_buffer_timestamp, 706 media_time,
671 total_bytes_to_free, 707 total_bytes_to_free,
672 &remove_range_end); 708 &remove_range_end);
673 if (bytes_freed > 0) { 709 if (bytes_freed > 0) {
710 DVLOG(4) << __FUNCTION__ << " removing ["
711 << remove_range_start.ToPresentationTime().InSecondsF() << ";"
712 << remove_range_end.ToPresentationTime().InSecondsF() << "]";
674 Remove(remove_range_start.ToPresentationTime(), 713 Remove(remove_range_start.ToPresentationTime(),
675 remove_range_end.ToPresentationTime(), 714 remove_range_end.ToPresentationTime(),
676 next_buffer_timestamp.ToPresentationTime()); 715 media_time.ToPresentationTime());
677 } 716 }
678 717
679 return bytes_freed; 718 return bytes_freed;
680 } 719 }
681 720
682 size_t SourceBufferStream::GetRemovalRange( 721 size_t SourceBufferStream::GetRemovalRange(
683 DecodeTimestamp start_timestamp, DecodeTimestamp end_timestamp, 722 DecodeTimestamp start_timestamp, DecodeTimestamp end_timestamp,
684 size_t total_bytes_to_free, DecodeTimestamp* removal_end_timestamp) { 723 size_t total_bytes_to_free, DecodeTimestamp* removal_end_timestamp) {
685 DCHECK(start_timestamp >= DecodeTimestamp()) << start_timestamp.InSecondsF(); 724 DCHECK(start_timestamp >= DecodeTimestamp()) << start_timestamp.InSecondsF();
686 DCHECK(start_timestamp < end_timestamp) 725 DCHECK(start_timestamp < end_timestamp)
(...skipping 12 matching lines...) Expand all
699 738
700 size_t bytes_to_free = total_bytes_to_free - bytes_freed; 739 size_t bytes_to_free = total_bytes_to_free - bytes_freed;
701 size_t bytes_removed = range->GetRemovalGOP( 740 size_t bytes_removed = range->GetRemovalGOP(
702 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp); 741 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp);
703 bytes_freed += bytes_removed; 742 bytes_freed += bytes_removed;
704 } 743 }
705 return bytes_freed; 744 return bytes_freed;
706 } 745 }
707 746
708 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free, 747 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free,
748 DecodeTimestamp media_time,
709 bool reverse_direction) { 749 bool reverse_direction) {
710 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers", 750 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers",
711 "total bytes to free", total_bytes_to_free, 751 "total bytes to free", total_bytes_to_free,
712 "reverse direction", reverse_direction); 752 "reverse direction", reverse_direction);
713 753
714 DCHECK_GT(total_bytes_to_free, 0u); 754 DCHECK_GT(total_bytes_to_free, 0u);
715 size_t bytes_freed = 0; 755 size_t bytes_freed = 0;
716 756
717 // This range will save the last GOP appended to |range_for_next_append_| 757 // This range will save the last GOP appended to |range_for_next_append_|
718 // if the buffers surrounding it get deleted during garbage collection. 758 // if the buffers surrounding it get deleted during garbage collection.
719 SourceBufferRange* new_range_for_append = NULL; 759 SourceBufferRange* new_range_for_append = NULL;
720 760
721 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) { 761 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) {
722 SourceBufferRange* current_range = NULL; 762 SourceBufferRange* current_range = NULL;
723 BufferQueue buffers; 763 BufferQueue buffers;
724 size_t bytes_deleted = 0; 764 size_t bytes_deleted = 0;
725 765
726 if (reverse_direction) { 766 if (reverse_direction) {
727 current_range = ranges_.back(); 767 current_range = ranges_.back();
768 DVLOG(5) << "current_range=" << RangeToString(*current_range);
728 if (current_range->LastGOPContainsNextBufferPosition()) { 769 if (current_range->LastGOPContainsNextBufferPosition()) {
729 DCHECK_EQ(current_range, selected_range_); 770 DCHECK_EQ(current_range, selected_range_);
771 DVLOG(5) << "current_range contains next read position, stopping GC";
730 break; 772 break;
731 } 773 }
774 DVLOG(5) << "Deleting GOP from back: " << RangeToString(*current_range);
732 bytes_deleted = current_range->DeleteGOPFromBack(&buffers); 775 bytes_deleted = current_range->DeleteGOPFromBack(&buffers);
733 } else { 776 } else {
734 current_range = ranges_.front(); 777 current_range = ranges_.front();
735 if (current_range->FirstGOPContainsNextBufferPosition()) { 778 DVLOG(5) << "current_range=" << RangeToString(*current_range);
736 DCHECK_EQ(current_range, selected_range_); 779 if (!current_range->FirstGOPEarlierThanMediaTime(media_time)) {
780 // We have removed all data up to the GOP that contains current playback
781 // position, we can't delete any further.
782 DVLOG(5) << "current_range contains playback position, stopping GC";
737 break; 783 break;
738 } 784 }
785 DVLOG(4) << "Deleting GOP from front: " << RangeToString(*current_range);
739 bytes_deleted = current_range->DeleteGOPFromFront(&buffers); 786 bytes_deleted = current_range->DeleteGOPFromFront(&buffers);
740 } 787 }
741 788
742 // Check to see if we've just deleted the GOP that was last appended. 789 // Check to see if we've just deleted the GOP that was last appended.
743 DecodeTimestamp end_timestamp = buffers.back()->GetDecodeTimestamp(); 790 DecodeTimestamp end_timestamp = buffers.back()->GetDecodeTimestamp();
744 if (end_timestamp == last_appended_buffer_timestamp_) { 791 if (end_timestamp == last_appended_buffer_timestamp_) {
745 DCHECK(last_appended_buffer_timestamp_ != kNoDecodeTimestamp()); 792 DCHECK(last_appended_buffer_timestamp_ != kNoDecodeTimestamp());
746 DCHECK(!new_range_for_append); 793 DCHECK(!new_range_for_append);
794
747 // Create a new range containing these buffers. 795 // Create a new range containing these buffers.
748 new_range_for_append = new SourceBufferRange( 796 new_range_for_append = new SourceBufferRange(
749 TypeToGapPolicy(GetType()), 797 TypeToGapPolicy(GetType()),
750 buffers, kNoDecodeTimestamp(), 798 buffers, kNoDecodeTimestamp(),
751 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, 799 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
752 base::Unretained(this))); 800 base::Unretained(this)));
753 range_for_next_append_ = ranges_.end(); 801 range_for_next_append_ = ranges_.end();
754 } else { 802 } else {
755 bytes_freed += bytes_deleted; 803 bytes_freed += bytes_deleted;
756 } 804 }
757 805
758 if (current_range->size_in_bytes() == 0) { 806 if (current_range->size_in_bytes() == 0) {
759 DCHECK_NE(current_range, selected_range_); 807 DCHECK_NE(current_range, selected_range_);
760 DCHECK(range_for_next_append_ == ranges_.end() || 808 DCHECK(range_for_next_append_ == ranges_.end() ||
761 *range_for_next_append_ != current_range); 809 *range_for_next_append_ != current_range);
762 delete current_range; 810 delete current_range;
763 reverse_direction ? ranges_.pop_back() : ranges_.pop_front(); 811 reverse_direction ? ranges_.pop_back() : ranges_.pop_front();
764 } 812 }
813
814 if (reverse_direction && new_range_for_append) {
815 // We don't want to delete any further, or we'll be creating gaps
816 break;
817 }
765 } 818 }
766 819
767 // Insert |new_range_for_append| into |ranges_|, if applicable. 820 // Insert |new_range_for_append| into |ranges_|, if applicable.
768 if (new_range_for_append) { 821 if (new_range_for_append) {
769 range_for_next_append_ = AddToRanges(new_range_for_append); 822 range_for_next_append_ = AddToRanges(new_range_for_append);
770 DCHECK(range_for_next_append_ != ranges_.end()); 823 DCHECK(range_for_next_append_ != ranges_.end());
771 824
772 // Check to see if we need to merge |new_range_for_append| with the range 825 // Check to see if we need to merge |new_range_for_append| with the range
773 // before or after it. |new_range_for_append| is created whenever the last 826 // before or after it. |new_range_for_append| is created whenever the last
774 // GOP appended is encountered, regardless of whether any buffers after it 827 // GOP appended is encountered, regardless of whether any buffers after it
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
1214 } 1267 }
1215 1268
1216 void SourceBufferStream::SeekAndSetSelectedRange( 1269 void SourceBufferStream::SeekAndSetSelectedRange(
1217 SourceBufferRange* range, DecodeTimestamp seek_timestamp) { 1270 SourceBufferRange* range, DecodeTimestamp seek_timestamp) {
1218 if (range) 1271 if (range)
1219 range->Seek(seek_timestamp); 1272 range->Seek(seek_timestamp);
1220 SetSelectedRange(range); 1273 SetSelectedRange(range);
1221 } 1274 }
1222 1275
1223 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) { 1276 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) {
1224 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 1277 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << ": "
1225 << ": " << selected_range_ << " -> " << range; 1278 << selected_range_ << " "
1279 << (selected_range_ ? RangeToString(*selected_range_) : "")
1280 << " -> " << range << " " << (range ? RangeToString(*range) : "");
1226 if (selected_range_) 1281 if (selected_range_)
1227 selected_range_->ResetNextBufferPosition(); 1282 selected_range_->ResetNextBufferPosition();
1228 DCHECK(!range || range->HasNextBufferPosition()); 1283 DCHECK(!range || range->HasNextBufferPosition());
1229 selected_range_ = range; 1284 selected_range_ = range;
1230 } 1285 }
1231 1286
1232 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const { 1287 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const {
1233 Ranges<base::TimeDelta> ranges; 1288 Ranges<base::TimeDelta> ranges;
1234 for (RangeList::const_iterator itr = ranges_.begin(); 1289 for (RangeList::const_iterator itr = ranges_.begin();
1235 itr != ranges_.end(); ++itr) { 1290 itr != ranges_.end(); ++itr) {
1236 ranges.Add((*itr)->GetStartTimestamp().ToPresentationTime(), 1291 ranges.Add((*itr)->GetStartTimestamp().ToPresentationTime(),
1237 (*itr)->GetBufferedEndTimestamp().ToPresentationTime()); 1292 (*itr)->GetBufferedEndTimestamp().ToPresentationTime());
1238 } 1293 }
1239 return ranges; 1294 return ranges;
1240 } 1295 }
1241 1296
1242 base::TimeDelta SourceBufferStream::GetBufferedDuration() const { 1297 base::TimeDelta SourceBufferStream::GetBufferedDuration() const {
1243 if (ranges_.empty()) 1298 if (ranges_.empty())
1244 return base::TimeDelta(); 1299 return base::TimeDelta();
1245 1300
1246 return ranges_.back()->GetBufferedEndTimestamp().ToPresentationTime(); 1301 return ranges_.back()->GetBufferedEndTimestamp().ToPresentationTime();
1247 } 1302 }
1248 1303
1304 size_t SourceBufferStream::GetBufferedSize() const {
1305 size_t ranges_size = 0;
1306 for (const auto& range : ranges_)
1307 ranges_size += range->size_in_bytes();
1308 return ranges_size;
1309 }
1310
1249 void SourceBufferStream::MarkEndOfStream() { 1311 void SourceBufferStream::MarkEndOfStream() {
1250 DCHECK(!end_of_stream_); 1312 DCHECK(!end_of_stream_);
1251 end_of_stream_ = true; 1313 end_of_stream_ = true;
1252 } 1314 }
1253 1315
1254 void SourceBufferStream::UnmarkEndOfStream() { 1316 void SourceBufferStream::UnmarkEndOfStream() {
1255 DCHECK(end_of_stream_); 1317 DCHECK(end_of_stream_);
1256 end_of_stream_ = false; 1318 end_of_stream_ = false;
1257 } 1319 }
1258 1320
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
1668 return false; 1730 return false;
1669 1731
1670 DCHECK_NE(have_splice_buffers, have_preroll_buffer); 1732 DCHECK_NE(have_splice_buffers, have_preroll_buffer);
1671 splice_buffers_index_ = 0; 1733 splice_buffers_index_ = 0;
1672 pending_buffer_.swap(*out_buffer); 1734 pending_buffer_.swap(*out_buffer);
1673 pending_buffers_complete_ = false; 1735 pending_buffers_complete_ = false;
1674 return true; 1736 return true;
1675 } 1737 }
1676 1738
1677 } // namespace media 1739 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698