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 kMaxGarbageCollectAlgorithmWarningLogs = 20; |
| 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 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { | 610 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { |
608 for (BufferQueue::const_iterator itr = buffers.begin(); | 611 for (BufferQueue::const_iterator itr = buffers.begin(); |
609 itr != buffers.end(); ++itr) { | 612 itr != buffers.end(); ++itr) { |
610 (*itr)->SetConfigId(append_config_index_); | 613 (*itr)->SetConfigId(append_config_index_); |
611 } | 614 } |
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()); |
| 620 // Garbage collection should only happen before/during appending new data, |
| 621 // which should not happen in end-of-stream state. |
| 622 DCHECK(!end_of_stream_); |
617 // Compute size of |ranges_|. | 623 // Compute size of |ranges_|. |
618 size_t ranges_size = GetBufferedSize(); | 624 size_t ranges_size = GetBufferedSize(); |
619 | 625 |
620 // Sanity and overflow checks | 626 // Sanity and overflow checks |
621 if ((newDataSize > memory_limit_) || | 627 if ((newDataSize > memory_limit_) || |
622 (ranges_size + newDataSize < ranges_size)) | 628 (ranges_size + newDataSize < ranges_size)) { |
| 629 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_, |
| 630 kMaxGarbageCollectAlgorithmWarningLogs) |
| 631 << GetStreamTypeName() << " stream: " |
| 632 << "new append of newDataSize=" << newDataSize |
| 633 << " bytes exceeds memory_limit_=" << memory_limit_ |
| 634 << ", currently buffered ranges_size=" << ranges_size; |
623 return false; | 635 return false; |
| 636 } |
624 | 637 |
625 // Return if we're under or at the memory limit. | 638 // Return if we're under or at the memory limit. |
626 if (ranges_size + newDataSize <= memory_limit_) | 639 if (ranges_size + newDataSize <= memory_limit_) |
627 return true; | 640 return true; |
628 | 641 |
629 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_; | 642 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_; |
630 | 643 |
631 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" | 644 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" |
632 << " media_time=" << media_time.InSecondsF() | 645 << " media_time=" << media_time.InSecondsF() |
633 << " ranges_=" << RangesToString(ranges_) | 646 << " ranges_=" << RangesToString(ranges_) |
| 647 << " seek_pending_=" << seek_pending_ |
634 << " ranges_size=" << ranges_size | 648 << " ranges_size=" << ranges_size |
635 << " newDataSize=" << newDataSize | 649 << " newDataSize=" << newDataSize |
636 << " memory_limit_=" << memory_limit_ | 650 << " memory_limit_=" << memory_limit_ |
637 << " last_appended_buffer_timestamp_=" | 651 << " last_appended_buffer_timestamp_=" |
638 << last_appended_buffer_timestamp_.InSecondsF(); | 652 << last_appended_buffer_timestamp_.InSecondsF(); |
639 | 653 |
640 size_t bytes_freed = 0; | 654 size_t bytes_freed = 0; |
641 | 655 |
642 // If last appended buffer position was earlier than the current playback time | 656 // If last appended buffer position was earlier than the current playback time |
643 // then try deleting data between last append and current media_time. | 657 // then try deleting data between last append and current media_time. |
644 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() && | 658 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() && |
645 last_appended_buffer_timestamp_ < media_time) { | 659 last_appended_buffer_timestamp_ < media_time) { |
646 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time); | 660 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time); |
647 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended " | 661 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended " |
648 << " released " << between << " bytes" | 662 << " released " << between << " bytes" |
649 << " ranges_=" << RangesToString(ranges_); | 663 << " ranges_=" << RangesToString(ranges_); |
650 bytes_freed += between; | 664 bytes_freed += between; |
651 | 665 |
652 // If the last append happened before the current playback position | 666 // 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 | 667 // 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 | 668 // 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) | 669 // initiating seek once enough data is pre-buffered. In those cases we'll |
| 670 // see that data is being appended at some new position, but there is no |
| 671 // pending seek reported yet. In this situation we need to try preserving |
| 672 // the most recently appended data, i.e. data belonging to the same buffered |
| 673 // range as the most recent append. |
656 if (range_for_next_append_ != ranges_.end()) { | 674 if (range_for_next_append_ != ranges_.end()) { |
657 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time); | 675 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time); |
658 media_time = (*range_for_next_append_)->GetStartTimestamp(); | 676 media_time = (*range_for_next_append_)->GetStartTimestamp(); |
659 } | 677 } |
660 } | 678 } |
661 | 679 |
| 680 // If there is an unsatisfied pending seek, we can safely remove all data that |
| 681 // is earlier than seek target, then remove from the back until we reach the |
| 682 // most recently appended GOP and then remove from the front if we still don't |
| 683 // have enough space for the upcoming append. |
| 684 if (bytes_freed < bytes_to_free && seek_pending_) { |
| 685 DCHECK(!ranges_.empty()); |
| 686 // All data earlier than the seek target |media_time| can be removed safely |
| 687 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false); |
| 688 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the" |
| 689 << " front. ranges_=" << RangesToString(ranges_); |
| 690 bytes_freed += front; |
| 691 |
| 692 // If removing data earlier than |media_time| didn't free up enough space, |
| 693 // then try deleting from the back until we reach most recently appended GOP |
| 694 if (bytes_freed < bytes_to_free) { |
| 695 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); |
| 696 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back" |
| 697 << " ranges_=" << RangesToString(ranges_); |
| 698 bytes_freed += back; |
| 699 } |
| 700 |
| 701 // If even that wasn't enough, then try greedily deleting from the front, |
| 702 // that should allow us to remove as much data as necessary to succeed. |
| 703 if (bytes_freed < bytes_to_free) { |
| 704 size_t front2 = FreeBuffers(bytes_to_free - bytes_freed, |
| 705 ranges_.back()->GetEndTimestamp(), false); |
| 706 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the" |
| 707 << " front. ranges_=" << RangesToString(ranges_); |
| 708 bytes_freed += front2; |
| 709 } |
| 710 DCHECK(bytes_freed >= bytes_to_free); |
| 711 } |
| 712 |
662 // Try removing data from the front of the SourceBuffer up to |media_time| | 713 // Try removing data from the front of the SourceBuffer up to |media_time| |
663 // position. | 714 // position. |
664 if (bytes_freed < bytes_to_free) { | 715 if (bytes_freed < bytes_to_free) { |
665 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false); | 716 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false); |
666 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the front" | 717 DVLOG(3) << __FUNCTION__ << " Removed " << front << " bytes from the" |
667 << " ranges_=" << RangesToString(ranges_); | 718 << " front. ranges_=" << RangesToString(ranges_); |
668 bytes_freed += front; | 719 bytes_freed += front; |
669 } | 720 } |
670 | 721 |
671 // Try removing data from the back of the SourceBuffer, until we reach the | 722 // Try removing data from the back of the SourceBuffer, until we reach the |
672 // most recent append position. | 723 // most recent append position. |
673 if (bytes_freed < bytes_to_free) { | 724 if (bytes_freed < bytes_to_free) { |
674 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); | 725 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); |
675 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back" | 726 DVLOG(3) << __FUNCTION__ << " Removed " << back << " bytes from the back." |
676 << " ranges_=" << RangesToString(ranges_); | 727 << " ranges_=" << RangesToString(ranges_); |
677 bytes_freed += back; | 728 bytes_freed += back; |
678 } | 729 } |
679 | 730 |
680 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC" | 731 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": After GC" |
681 << " bytes_to_free=" << bytes_to_free | 732 << " bytes_to_free=" << bytes_to_free |
682 << " bytes_freed=" << bytes_freed | 733 << " bytes_freed=" << bytes_freed |
683 << " ranges_=" << RangesToString(ranges_); | 734 << " ranges_=" << RangesToString(ranges_); |
684 | 735 |
685 return bytes_freed >= bytes_to_free; | 736 return bytes_freed >= bytes_to_free; |
(...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1731 return false; | 1782 return false; |
1732 | 1783 |
1733 DCHECK_NE(have_splice_buffers, have_preroll_buffer); | 1784 DCHECK_NE(have_splice_buffers, have_preroll_buffer); |
1734 splice_buffers_index_ = 0; | 1785 splice_buffers_index_ = 0; |
1735 pending_buffer_.swap(*out_buffer); | 1786 pending_buffer_.swap(*out_buffer); |
1736 pending_buffers_complete_ = false; | 1787 pending_buffers_complete_ = false; |
1737 return true; | 1788 return true; |
1738 } | 1789 } |
1739 | 1790 |
1740 } // namespace media | 1791 } // namespace media |
OLD | NEW |