Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |