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 #include <string> | 10 #include <string> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "media/base/media_switches.h" | |
| 15 #include "media/base/timestamp_constants.h" | 16 #include "media/base/timestamp_constants.h" |
| 16 #include "media/filters/source_buffer_platform.h" | 17 #include "media/filters/source_buffer_platform.h" |
| 17 #include "media/filters/source_buffer_range.h" | 18 #include "media/filters/source_buffer_range.h" |
| 18 | 19 |
| 19 namespace media { | 20 namespace media { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // An arbitrarily-chosen number to estimate the duration of a buffer if none is | 24 // An arbitrarily-chosen number to estimate the duration of a buffer if none is |
| 24 // set and there's not enough information to get a better estimate. | 25 // set and there's not enough information to get a better estimate. |
| (...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 685 } | 686 } |
| 686 } | 687 } |
| 687 | 688 |
| 688 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { | 689 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { |
| 689 for (BufferQueue::const_iterator itr = buffers.begin(); | 690 for (BufferQueue::const_iterator itr = buffers.begin(); |
| 690 itr != buffers.end(); ++itr) { | 691 itr != buffers.end(); ++itr) { |
| 691 (*itr)->SetConfigId(append_config_index_); | 692 (*itr)->SetConfigId(append_config_index_); |
| 692 } | 693 } |
| 693 } | 694 } |
| 694 | 695 |
| 696 void SourceBufferStream::OnMemoryPressure( | |
| 697 DecodeTimestamp media_time, | |
| 698 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { | |
| 699 DVLOG(4) << __func__ << " level=" << memory_pressure_level; | |
| 700 memory_pressure_level_ = memory_pressure_level; | |
| 701 | |
| 702 // The new value of |memory_pressure_level_| updated set above will take | |
| 703 // effect on the next SourceBuffer append operation. But if we are notified | |
| 704 // that memory pressure is critical, we might want to perform a GC right away, | |
| 705 // to release some memory immediately. Strictly speaking MSE apps expect | |
| 706 // buffered ranges only at well-defined points, like SourceBuffer append | |
| 707 // operation, and may not expect this. But it might still be better than being | |
| 708 // killed due to OOM, so might be worth the risk. | |
| 709 if (base::FeatureList::IsEnabled(kMSEInstantGCOnMemoryPressure) && | |
| 710 memory_pressure_level == | |
| 711 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { | |
| 712 GarbageCollectIfNeeded(media_time, 0); | |
| 713 } | |
| 714 } | |
| 715 | |
| 695 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time, | 716 bool SourceBufferStream::GarbageCollectIfNeeded(DecodeTimestamp media_time, |
| 696 size_t newDataSize) { | 717 size_t newDataSize) { |
| 697 DCHECK(media_time != kNoDecodeTimestamp()); | 718 DCHECK(media_time != kNoDecodeTimestamp()); |
| 698 // Garbage collection should only happen before/during appending new data, | 719 // Garbage collection should only happen before/during appending new data, |
| 699 // which should not happen in end-of-stream state. | 720 // which should not happen in end-of-stream state. Unless we also allow GC to |
| 700 DCHECK(!end_of_stream_); | 721 // happen on memory pressure notifications, which might happen even in EOS |
| 722 // state. | |
| 723 if (!base::FeatureList::IsEnabled(kMSEInstantGCOnMemoryPressure)) { | |
| 724 DCHECK(!end_of_stream_); | |
| 725 } | |
| 701 // Compute size of |ranges_|. | 726 // Compute size of |ranges_|. |
| 702 size_t ranges_size = GetBufferedSize(); | 727 size_t ranges_size = GetBufferedSize(); |
| 703 | 728 |
| 704 // Sanity and overflow checks | 729 // Sanity and overflow checks |
| 705 if ((newDataSize > memory_limit_) || | 730 if ((newDataSize > memory_limit_) || |
| 706 (ranges_size + newDataSize < ranges_size)) { | 731 (ranges_size + newDataSize < ranges_size)) { |
| 707 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_, | 732 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_, |
| 708 kMaxGarbageCollectAlgorithmWarningLogs) | 733 kMaxGarbageCollectAlgorithmWarningLogs) |
| 709 << GetStreamTypeName() << " stream: " | 734 << GetStreamTypeName() << " stream: " |
| 710 << "new append of newDataSize=" << newDataSize | 735 << "new append of newDataSize=" << newDataSize |
| 711 << " bytes exceeds memory_limit_=" << memory_limit_ | 736 << " bytes exceeds memory_limit_=" << memory_limit_ |
| 712 << ", currently buffered ranges_size=" << ranges_size; | 737 << ", currently buffered ranges_size=" << ranges_size; |
| 713 return false; | 738 return false; |
| 714 } | 739 } |
| 715 | 740 |
| 741 size_t effective_memory_limit = memory_limit_; | |
| 742 if (base::FeatureList::IsEnabled(kReduceMSEBuffersOnMemoryPressure)) { | |
| 743 switch (memory_pressure_level_) { | |
| 744 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: | |
| 745 effective_memory_limit = memory_limit_ / 2; | |
| 746 break; | |
| 747 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: | |
| 748 effective_memory_limit = 0; | |
| 749 break; | |
| 750 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: | |
|
chcunningham
2017/01/25 03:47:15
Maybe no-op is fine, but what made you decide not
servolk
2017/01/25 18:06:47
Tbh I'm not sure what you mean by 'restore the mem
chcunningham
2017/01/25 22:21:57
My bad. I overlooked the local variable. Seems it
servolk
2017/01/26 18:10:14
Acknowledged.
| |
| 751 break; | |
| 752 } | |
| 753 } | |
| 754 | |
| 716 // Return if we're under or at the memory limit. | 755 // Return if we're under or at the memory limit. |
| 717 if (ranges_size + newDataSize <= memory_limit_) | 756 if (ranges_size + newDataSize <= effective_memory_limit) |
| 718 return true; | 757 return true; |
| 719 | 758 |
| 720 size_t bytes_to_free = ranges_size + newDataSize - memory_limit_; | 759 size_t bytes_over_hard_memory_limit = 0; |
| 760 if (ranges_size + newDataSize > memory_limit_) | |
| 761 bytes_over_hard_memory_limit = ranges_size + newDataSize - memory_limit_; | |
| 762 | |
| 763 size_t bytes_to_free = ranges_size + newDataSize - effective_memory_limit; | |
| 721 | 764 |
| 722 DVLOG(2) << __func__ << " " << GetStreamTypeName() | 765 DVLOG(2) << __func__ << " " << GetStreamTypeName() |
| 723 << ": Before GC media_time=" << media_time.InSecondsF() | 766 << ": Before GC media_time=" << media_time.InSecondsF() |
| 724 << " ranges_=" << RangesToString(ranges_) | 767 << " ranges_=" << RangesToString(ranges_) |
| 725 << " seek_pending_=" << seek_pending_ | 768 << " seek_pending_=" << seek_pending_ |
| 726 << " ranges_size=" << ranges_size << " newDataSize=" << newDataSize | 769 << " ranges_size=" << ranges_size << " newDataSize=" << newDataSize |
| 727 << " memory_limit_=" << memory_limit_ | 770 << " memory_limit_=" << memory_limit_ |
| 771 << " effective_memory_limit=" << effective_memory_limit | |
| 728 << " last_appended_buffer_timestamp_=" | 772 << " last_appended_buffer_timestamp_=" |
| 729 << last_appended_buffer_timestamp_.InSecondsF(); | 773 << last_appended_buffer_timestamp_.InSecondsF(); |
| 730 | 774 |
| 731 if (selected_range_ && !seek_pending_ && | 775 if (selected_range_ && !seek_pending_ && |
| 732 media_time > selected_range_->GetBufferedEndTimestamp()) { | 776 media_time > selected_range_->GetBufferedEndTimestamp()) { |
| 733 // Strictly speaking |media_time| (taken from HTMLMediaElement::currentTime) | 777 // Strictly speaking |media_time| (taken from HTMLMediaElement::currentTime) |
| 734 // should always be in the buffered ranges, but media::Pipeline uses audio | 778 // should always be in the buffered ranges, but media::Pipeline uses audio |
| 735 // stream as the main time source, when audio is present. | 779 // stream as the main time source, when audio is present. |
| 736 // In cases when audio and video streams have different buffered ranges, the | 780 // In cases when audio and video streams have different buffered ranges, the |
| 737 // |media_time| value might be slightly outside of the video stream buffered | 781 // |media_time| value might be slightly outside of the video stream buffered |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 827 if (bytes_freed < bytes_to_free) { | 871 if (bytes_freed < bytes_to_free) { |
| 828 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); | 872 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true); |
| 829 DVLOG(3) << __func__ << " Removed " << back | 873 DVLOG(3) << __func__ << " Removed " << back |
| 830 << " bytes from the back. ranges_=" << RangesToString(ranges_); | 874 << " bytes from the back. ranges_=" << RangesToString(ranges_); |
| 831 bytes_freed += back; | 875 bytes_freed += back; |
| 832 } | 876 } |
| 833 | 877 |
| 834 DVLOG(2) << __func__ << " " << GetStreamTypeName() | 878 DVLOG(2) << __func__ << " " << GetStreamTypeName() |
| 835 << ": After GC bytes_to_free=" << bytes_to_free | 879 << ": After GC bytes_to_free=" << bytes_to_free |
| 836 << " bytes_freed=" << bytes_freed | 880 << " bytes_freed=" << bytes_freed |
| 881 << " bytes_over_hard_memory_limit=" << bytes_over_hard_memory_limit | |
| 837 << " ranges_=" << RangesToString(ranges_); | 882 << " ranges_=" << RangesToString(ranges_); |
| 838 | 883 |
| 839 return bytes_freed >= bytes_to_free; | 884 return bytes_freed >= bytes_over_hard_memory_limit; |
| 840 } | 885 } |
| 841 | 886 |
| 842 size_t SourceBufferStream::FreeBuffersAfterLastAppended( | 887 size_t SourceBufferStream::FreeBuffersAfterLastAppended( |
| 843 size_t total_bytes_to_free, DecodeTimestamp media_time) { | 888 size_t total_bytes_to_free, DecodeTimestamp media_time) { |
| 844 DVLOG(4) << __func__ << " last_appended_buffer_timestamp_=" | 889 DVLOG(4) << __func__ << " last_appended_buffer_timestamp_=" |
| 845 << last_appended_buffer_timestamp_.InSecondsF() | 890 << last_appended_buffer_timestamp_.InSecondsF() |
| 846 << " media_time=" << media_time.InSecondsF(); | 891 << " media_time=" << media_time.InSecondsF(); |
| 847 | 892 |
| 848 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_; | 893 DecodeTimestamp remove_range_start = last_appended_buffer_timestamp_; |
| 849 if (last_appended_buffer_is_keyframe_) | 894 if (last_appended_buffer_is_keyframe_) |
| (...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1757 | 1802 |
| 1758 if (!have_preroll_buffer) | 1803 if (!have_preroll_buffer) |
| 1759 return false; | 1804 return false; |
| 1760 | 1805 |
| 1761 pending_buffer_.swap(*out_buffer); | 1806 pending_buffer_.swap(*out_buffer); |
| 1762 pending_buffers_complete_ = false; | 1807 pending_buffers_complete_ = false; |
| 1763 return true; | 1808 return true; |
| 1764 } | 1809 } |
| 1765 | 1810 |
| 1766 } // namespace media | 1811 } // namespace media |
| OLD | NEW |