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

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

Issue 1347483003: Fix seeking back in the new MSE GC algorithm (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Latest patchset from 1349973002 which addressed feedback comments made there Created 5 years, 3 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 16 matching lines...) Expand all
27 // Limit the number of MEDIA_LOG() logs for splice buffer generation warnings 27 // Limit the number of MEDIA_LOG() logs for splice buffer generation warnings
28 // and successes. Though these values are high enough to possibly exhaust the 28 // and successes. Though these values are high enough to possibly exhaust the
29 // media internals event cache (along with other events), these logs are 29 // media internals event cache (along with other events), these logs are
30 // important for debugging splice generation. 30 // important for debugging splice generation.
31 const int kMaxSpliceGenerationWarningLogs = 50; 31 const int kMaxSpliceGenerationWarningLogs = 50;
32 const int kMaxSpliceGenerationSuccessLogs = 20; 32 const int kMaxSpliceGenerationSuccessLogs = 20;
33 33
34 // Limit the number of MEDIA_LOG() logs for track buffer time gaps. 34 // Limit the number of MEDIA_LOG() logs for track buffer time gaps.
35 const int kMaxTrackBufferGapWarningLogs = 20; 35 const int kMaxTrackBufferGapWarningLogs = 20;
36 36
37 // Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings.
38 const int kMaxGarbageCollectAlgorithWarningLogs = 50;
wolenetz 2015/09/21 20:14:39 nit: 50 is probably too high. In general, GC failu
servolk 2015/09/21 21:09:57 Done.
39
37 // Helper method that returns true if |ranges| is sorted in increasing order, 40 // Helper method that returns true if |ranges| is sorted in increasing order,
38 // false otherwise. 41 // false otherwise.
39 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) { 42 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) {
40 DecodeTimestamp prev = kNoDecodeTimestamp(); 43 DecodeTimestamp prev = kNoDecodeTimestamp();
41 for (std::list<SourceBufferRange*>::const_iterator itr = 44 for (std::list<SourceBufferRange*>::const_iterator itr =
42 ranges.begin(); itr != ranges.end(); ++itr) { 45 ranges.begin(); itr != ranges.end(); ++itr) {
43 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp()) 46 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp())
44 return false; 47 return false;
45 prev = (*itr)->GetEndTimestamp(); 48 prev = (*itr)->GetEndTimestamp();
46 } 49 }
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 } 615 }
613 616
614 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time, 617 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time,
615 size_t newDataSize) { 618 size_t newDataSize) {
616 DCHECK(media_time != kNoDecodeTimestamp()); 619 DCHECK(media_time != kNoDecodeTimestamp());
617 // Compute size of |ranges_|. 620 // Compute size of |ranges_|.
618 size_t ranges_size = GetBufferedSize(); 621 size_t ranges_size = GetBufferedSize();
619 622
620 // Sanity and overflow checks 623 // Sanity and overflow checks
621 if ((newDataSize > memory_limit_) || 624 if ((newDataSize > memory_limit_) ||
622 (ranges_size + newDataSize < ranges_size)) 625 (ranges_size + newDataSize < ranges_size)) {
626 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_,
627 kMaxGarbageCollectAlgorithWarningLogs)
628 << "GarbageCollectIfNeeded failed: memory_limit_=" << memory_limit_
wolenetz 2015/09/21 20:14:39 nit: since this is going to chrome://media-interna
servolk 2015/09/21 21:09:57 Done.
629 << " ranges_size=" << ranges_size << " newDataSize=" << newDataSize;
623 return false; 630 return false;
631 }
624 632
625 // Return if we're under or at the memory limit. 633 // Return if we're under or at the memory limit.
626 if (ranges_size + newDataSize <= memory_limit_) 634 if (ranges_size + newDataSize <= memory_limit_)
627 return true; 635 return true;
628 636
629 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_; 637 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_;
630 638
639 // If there is a pending seek, then we should allow GC to remove data more
640 // aggressively for the upcoming append to allow seeking to proceed.
641 bool seek_pending = IsSeekPending();
wolenetz 2015/09/21 20:14:39 IIUC, IsSeekPending() isn't really what we want: i
servolk 2015/09/21 21:09:57 Done.
642
631 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" 643 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC"
632 << " media_time=" << media_time.InSecondsF() 644 << " media_time=" << media_time.InSecondsF()
633 << " ranges_=" << RangesToString(ranges_) 645 << " ranges_=" << RangesToString(ranges_)
646 << " seek_pending=" << seek_pending
634 << " ranges_size=" << ranges_size 647 << " ranges_size=" << ranges_size
635 << " newDataSize=" << newDataSize 648 << " newDataSize=" << newDataSize
636 << " memory_limit_=" << memory_limit_ 649 << " memory_limit_=" << memory_limit_
637 << " last_appended_buffer_timestamp_=" 650 << " last_appended_buffer_timestamp_="
638 << last_appended_buffer_timestamp_.InSecondsF(); 651 << last_appended_buffer_timestamp_.InSecondsF();
639 652
640 size_t bytes_freed = 0; 653 size_t bytes_freed = 0;
641 654
642 // If last appended buffer position was earlier than the current playback time 655 // If last appended buffer position was earlier than the current playback time
643 // then try deleting data between last append and current media_time. 656 // then try deleting data between last append and current media_time.
644 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() && 657 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() &&
645 last_appended_buffer_timestamp_ < media_time) { 658 last_appended_buffer_timestamp_ < media_time) {
646 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time); 659 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
647 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended " 660 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended "
648 << " released " << between << " bytes" 661 << " released " << between << " bytes"
649 << " ranges_=" << RangesToString(ranges_); 662 << " ranges_=" << RangesToString(ranges_);
650 bytes_freed += between; 663 bytes_freed += between;
651 664
652 // If the last append happened before the current playback position 665 // Some players start appending data at the new seek target position before
653 // |media_time|, then JS player is probably preparing to seek back and we 666 // actually initiating the seek operation (i.e. they try to improve seek
654 // should try to preserve all most recently appended data (which is in 667 // performance by prebuffering some data at the seek target position and
655 // range_for_next_append_) from being removed by GC (see crbug.com/440173) 668 // initiating seek once enough data is pre-buffered. In those cases we'll
669 // see that data is being appended at some new position, but there is no
670 // pending seek reported yet. In this situation we need to try preserving
671 // the most recently appended data, i.e. data belonging to the same buffered
672 // range as the most recent append.
656 if (range_for_next_append_ != ranges_.end()) { 673 if (range_for_next_append_ != ranges_.end()) {
657 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time); 674 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
658 media_time = (*range_for_next_append_)->GetStartTimestamp(); 675 media_time = (*range_for_next_append_)->GetStartTimestamp();
659 } 676 }
660 } 677 }
661 678
679 // If there is an unsatisfied pending seek, we can safely remove all data that
680 // is earlier than seek target, then remove from the back until we reach the
681 // most recently appended GOP and then remove from the front if we still don't
682 // have enough space for the upcoming append.
683 if (bytes_freed < bytes_to_free && seek_pending) {
684 DCHECK(!ranges_.empty());
685 // All data earlier than the seek target |media_time| can be removed safely
686 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
687 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the"
688 << " front. ranges_=" << RangesToString(ranges_);
689 bytes_freed += front;
690
691 // If removing data earlier than |media_time| didn't free up enough space,
692 // then try deleting from the back until we reach most recently appended GOP
693 if (bytes_freed < bytes_to_free) {
694 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
695 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back"
696 << " ranges_=" << RangesToString(ranges_);
697 bytes_freed += back;
698 }
699
700 // If even that wasn't enough, then try greedily deleting from the front,
701 // that should allow us to remove as much data as necessary to succeed.
702 if (bytes_freed < bytes_to_free) {
703 size_t front2 = FreeBuffers(bytes_to_free - bytes_freed,
704 ranges_.back()->GetEndTimestamp(), false);
705 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the"
706 << " front. ranges_=" << RangesToString(ranges_);
707 bytes_freed += front2;
708 }
709 DCHECK(bytes_freed >= bytes_to_free);
710 }
711
662 // Try removing data from the front of the SourceBuffer up to |media_time| 712 // Try removing data from the front of the SourceBuffer up to |media_time|
663 // position. 713 // position.
664 if (bytes_freed < bytes_to_free) { 714 if (bytes_freed < bytes_to_free) {
665 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false); 715 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
666 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the front" 716 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the"
667 << " ranges_=" << RangesToString(ranges_); 717 << " front. ranges_=" << RangesToString(ranges_);
668 bytes_freed += front; 718 bytes_freed += front;
669 } 719 }
670 720
671 // Try removing data from the back of the SourceBuffer, until we reach the 721 // Try removing data from the back of the SourceBuffer, until we reach the
672 // most recent append position. 722 // most recent append position.
673 if (bytes_freed < bytes_to_free) { 723 if (bytes_freed < bytes_to_free) {
674 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); 724 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
675 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back" 725 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back."
676 << " ranges_=" << RangesToString(ranges_); 726 << " ranges_=" << RangesToString(ranges_);
677 bytes_freed += back; 727 bytes_freed += back;
678 } 728 }
679 729
680 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC" 730 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC"
681 << " bytes_to_free=" << bytes_to_free 731 << " bytes_to_free=" << bytes_to_free
682 << " bytes_freed=" << bytes_freed 732 << " bytes_freed=" << bytes_freed
683 << " ranges_=" << RangesToString(ranges_); 733 << " ranges_=" << RangesToString(ranges_);
684 734
685 return bytes_freed >= bytes_to_free; 735 return bytes_freed >= bytes_to_free;
wolenetz 2015/09/21 20:14:39 nit: I recommend adding another LIMITED_MEDIA_LOG(
servolk 2015/09/21 21:09:57 Actually I think in this case we should use (D)VLO
wolenetz 2015/09/21 21:38:28 Acknowledged. Except in the iteration of the strea
686 } 736 }
687 737
688 size_t SourceBufferStream::FreeBuffersAfterLastAppended( 738 size_t SourceBufferStream::FreeBuffersAfterLastAppended(
689 size_t total_bytes_to_free, DecodeTimestamp media_time) { 739 size_t total_bytes_to_free, DecodeTimestamp media_time) {
690 DVLOG(4) << __FUNCTION__ << " last_appended_buffer_timestamp_=" 740 DVLOG(4) << __FUNCTION__ << " last_appended_buffer_timestamp_="
691 << last_appended_buffer_timestamp_.InSecondsF() 741 << last_appended_buffer_timestamp_.InSecondsF()
692 << " media_time=" << media_time.InSecondsF(); 742 << " media_time=" << media_time.InSecondsF();
693 743
694 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_; 744 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_;
695 if (last_appended_buffer_is_keyframe_) 745 if (last_appended_buffer_is_keyframe_)
(...skipping 1035 matching lines...) Expand 10 before | Expand all | Expand 10 after
1731 return false; 1781 return false;
1732 1782
1733 DCHECK_NE(have_splice_buffers, have_preroll_buffer); 1783 DCHECK_NE(have_splice_buffers, have_preroll_buffer);
1734 splice_buffers_index_ = 0; 1784 splice_buffers_index_ = 0;
1735 pending_buffer_.swap(*out_buffer); 1785 pending_buffer_.swap(*out_buffer);
1736 pending_buffers_complete_ = false; 1786 pending_buffers_complete_ = false;
1737 return true; 1787 return true;
1738 } 1788 }
1739 1789
1740 } // namespace media 1790 } // namespace media
OLDNEW
« media/filters/chunk_demuxer_unittest.cc ('K') | « media/filters/source_buffer_stream.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698