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

Side by Side Diff: media/filters/chunk_demuxer.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: Rebase on top of dummy WebSourceBufferImpl::evictCodedFrames CL 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/chunk_demuxer.h" 5 #include "media/filters/chunk_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <list> 9 #include <list>
10 10
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 124
125 // Aborts the current append sequence and resets the parser. 125 // Aborts the current append sequence and resets the parser.
126 void Abort(TimeDelta append_window_start, 126 void Abort(TimeDelta append_window_start,
127 TimeDelta append_window_end, 127 TimeDelta append_window_end,
128 TimeDelta* timestamp_offset); 128 TimeDelta* timestamp_offset);
129 129
130 // Calls Remove(|start|, |end|, |duration|) on all 130 // Calls Remove(|start|, |end|, |duration|) on all
131 // ChunkDemuxerStreams managed by this object. 131 // ChunkDemuxerStreams managed by this object.
132 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); 132 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
133 133
134 // If the buffer is full, attempts to try to free up space, as specified in
135 // the "Coded Frame Eviction Algorithm" in the Media Source Extensions Spec.
136 // Returns false iff buffer is still full after running eviction.
137 // https://w3c.github.io/media-source/#sourcebuffer-coded-frame-eviction
138 bool EvictCodedFrames(DecodeTimestamp media_time, size_t newDataSize);
139
134 // Returns true if currently parsing a media segment, or false otherwise. 140 // Returns true if currently parsing a media segment, or false otherwise.
135 bool parsing_media_segment() const { return parsing_media_segment_; } 141 bool parsing_media_segment() const { return parsing_media_segment_; }
136 142
137 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. 143 // Sets |frame_processor_|'s sequence mode to |sequence_mode|.
138 void SetSequenceMode(bool sequence_mode); 144 void SetSequenceMode(bool sequence_mode);
139 145
140 // Signals the coded frame processor to update its group start timestamp to be 146 // Signals the coded frame processor to update its group start timestamp to be
141 // |timestamp_offset| if it is in sequence append mode. 147 // |timestamp_offset| if it is in sequence append mode.
142 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset); 148 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset);
143 149
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 // appending the processed frames to associated demuxer streams for each 194 // appending the processed frames to associated demuxer streams for each
189 // frame's track. 195 // frame's track.
190 // Returns true on a successful call. Returns false if an error occurred while 196 // Returns true on a successful call. Returns false if an error occurred while
191 // processing the buffers. 197 // processing the buffers.
192 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 198 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
193 const StreamParser::BufferQueue& video_buffers, 199 const StreamParser::BufferQueue& video_buffers,
194 const StreamParser::TextBufferQueueMap& text_map); 200 const StreamParser::TextBufferQueueMap& text_map);
195 201
196 void OnSourceInitDone(const StreamParser::InitParameters& params); 202 void OnSourceInitDone(const StreamParser::InitParameters& params);
197 203
204 // EstimateVideoDataSize uses some heuristics to estimate the size of the
205 // video size in the chunk of muxed audio/video data without parsing it.
206 // This is used by EvictCodedFrames algorithm, which happens before Append
207 // (and therefore before parsing is performed) to prepare space for new data.
208 size_t EstimateVideoDataSize(size_t muxed_data_chunk_size) const;
209
198 CreateDemuxerStreamCB create_demuxer_stream_cb_; 210 CreateDemuxerStreamCB create_demuxer_stream_cb_;
199 NewTextTrackCB new_text_track_cb_; 211 NewTextTrackCB new_text_track_cb_;
200 212
201 // During Append(), if OnNewBuffers() coded frame processing updates the 213 // During Append(), if OnNewBuffers() coded frame processing updates the
202 // timestamp offset then |*timestamp_offset_during_append_| is also updated 214 // timestamp offset then |*timestamp_offset_during_append_| is also updated
203 // so Append()'s caller can know the new offset. This pointer is only non-NULL 215 // so Append()'s caller can know the new offset. This pointer is only non-NULL
204 // during the lifetime of an Append() call. 216 // during the lifetime of an Append() call.
205 TimeDelta* timestamp_offset_during_append_; 217 TimeDelta* timestamp_offset_during_append_;
206 218
207 // During Append(), coded frame processing triggered by OnNewBuffers() 219 // During Append(), coded frame processing triggered by OnNewBuffers()
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 374
363 if (video_) 375 if (video_)
364 video_->Remove(start, end, duration); 376 video_->Remove(start, end, duration);
365 377
366 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 378 for (TextStreamMap::iterator itr = text_stream_map_.begin();
367 itr != text_stream_map_.end(); ++itr) { 379 itr != text_stream_map_.end(); ++itr) {
368 itr->second->Remove(start, end, duration); 380 itr->second->Remove(start, end, duration);
369 } 381 }
370 } 382 }
371 383
384 size_t SourceState::EstimateVideoDataSize(size_t muxed_data_chunk_size) const {
385 DCHECK(audio_);
386 DCHECK(video_);
387
388 size_t bufferedVideoSize = video_->GetBufferedSize();
389 size_t bufferedAudioSize = audio_->GetBufferedSize();
390 if (bufferedVideoSize == 0 || bufferedAudioSize == 0) {
391 // At this point either audio or video buffer is empty, which means buffer
392 // levels are probably low anyway and we should have enough space in the
393 // buffers for appending new data, so just take a very rough guess.
394 return muxed_data_chunk_size / 2;
395 }
396
397 // We need to estimate how much audio and video data is going to be in the
398 // newly appended data chunk to make space for the new data. And we need to do
399 // that without parsing the data (which will happen later, in the Append
400 // phase). So for now we can only rely on some heuristic here. Let's assume
401 // that the proportion of the audio/video in the new data chunk is the same as
402 // the current ratio of buffered audio/video.
403 // Longer term this should go away once we further change the MSE GC algorithm
404 // to work across all streams of a SourceBuffer (see crbug.com/520704).
405 DCHECK(bufferedVideoSize + bufferedAudioSize > 0);
wolenetz 2015/08/21 18:15:57 Hmm. size_t can't be negative. So this is only che
servolk 2015/08/21 18:19:14 Right
servolk 2015/08/21 19:06:45 (this is just a sanity check, since we are going t
wolenetz 2015/08/21 19:39:37 Acknowledged. Let's please strengthen sanity here
servolk 2015/08/21 20:16:54 Done.
406 size_t estimatedVideoData = muxed_data_chunk_size * bufferedVideoSize /
wolenetz 2015/08/21 18:15:56 not lgtm: Working with integers, this may not do w
servolk 2015/08/21 18:19:14 I believe it would be calculated as (10 * 51) / 10
servolk 2015/08/21 19:06:45 Since I had to upload a new patchset with the upda
wolenetz 2015/08/21 19:39:37 Acknowledged.
407 (bufferedVideoSize + bufferedAudioSize);
408 return estimatedVideoData;
409 }
410
411 bool SourceState::EvictCodedFrames(DecodeTimestamp media_time,
412 size_t newDataSize) {
413 bool success = true;
414
415 DVLOG(3) << __FUNCTION__ << " media_time=" << media_time.InSecondsF()
416 << " newDataSize=" << newDataSize
417 << " bufferedVideoSize=" << (video_ ? video_->GetBufferedSize() : 0)
418 << " bufferedAudioSize=" << (audio_ ? audio_->GetBufferedSize() : 0);
419
420 size_t newAudioSize = 0;
421 size_t newVideoSize = 0;
422 if (audio_ && video_) {
423 newVideoSize = EstimateVideoDataSize(newDataSize);
424 newAudioSize = newDataSize - newVideoSize;
425 } else if (video_) {
426 newVideoSize = newDataSize;
427 } else if (audio_) {
428 newAudioSize = newDataSize;
429 }
430
431 DVLOG(3) << __FUNCTION__ << " estimated audio/video sizes: "
432 << " newVideoSize=" << newVideoSize
433 << " newAudioSize=" << newAudioSize;
434
435 if (audio_)
436 success = audio_->EvictCodedFrames(media_time, newAudioSize) && success;
437
438 if (video_)
439 success = video_->EvictCodedFrames(media_time, newVideoSize) && success;
440
441 for (TextStreamMap::iterator itr = text_stream_map_.begin();
442 itr != text_stream_map_.end(); ++itr) {
443 success = itr->second->EvictCodedFrames(media_time, 0) && success;
444 }
445
446 DVLOG(3) << __FUNCTION__ << " result=" << success
447 << " bufferedVideoSize=" << (video_ ? video_->GetBufferedSize() : 0)
448 << " bufferedAudioSize=" << (audio_ ? audio_->GetBufferedSize() : 0);
449
450 return success;
451 }
452
372 Ranges<TimeDelta> SourceState::GetBufferedRanges(TimeDelta duration, 453 Ranges<TimeDelta> SourceState::GetBufferedRanges(TimeDelta duration,
373 bool ended) const { 454 bool ended) const {
374 // TODO(acolwell): When we start allowing disabled tracks we'll need to update 455 // TODO(acolwell): When we start allowing disabled tracks we'll need to update
375 // this code to only add ranges from active tracks. 456 // this code to only add ranges from active tracks.
376 RangesList ranges_list; 457 RangesList ranges_list;
377 if (audio_) 458 if (audio_)
378 ranges_list.push_back(audio_->GetBufferedRanges(duration)); 459 ranges_list.push_back(audio_->GetBufferedRanges(duration));
379 460
380 if (video_) 461 if (video_)
381 ranges_list.push_back(video_->GetBufferedRanges(duration)); 462 ranges_list.push_back(video_->GetBufferedRanges(duration));
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
872 953
873 return true; 954 return true;
874 } 955 }
875 956
876 void ChunkDemuxerStream::Remove(TimeDelta start, TimeDelta end, 957 void ChunkDemuxerStream::Remove(TimeDelta start, TimeDelta end,
877 TimeDelta duration) { 958 TimeDelta duration) {
878 base::AutoLock auto_lock(lock_); 959 base::AutoLock auto_lock(lock_);
879 stream_->Remove(start, end, duration); 960 stream_->Remove(start, end, duration);
880 } 961 }
881 962
963 bool ChunkDemuxerStream::EvictCodedFrames(DecodeTimestamp media_time,
964 size_t newDataSize) {
965 base::AutoLock auto_lock(lock_);
966 return stream_->GarbageCollectIfNeeded(media_time, newDataSize);
967 }
968
882 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) { 969 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) {
883 base::AutoLock auto_lock(lock_); 970 base::AutoLock auto_lock(lock_);
884 stream_->OnSetDuration(duration); 971 stream_->OnSetDuration(duration);
885 } 972 }
886 973
887 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( 974 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
888 TimeDelta duration) const { 975 TimeDelta duration) const {
889 base::AutoLock auto_lock(lock_); 976 base::AutoLock auto_lock(lock_);
890 977
891 if (type_ == TEXT) { 978 if (type_ == TEXT) {
(...skipping 16 matching lines...) Expand all
908 // range. 995 // range.
909 Ranges<TimeDelta> valid_time_range; 996 Ranges<TimeDelta> valid_time_range;
910 valid_time_range.Add(range.start(0), duration); 997 valid_time_range.Add(range.start(0), duration);
911 return range.IntersectionWith(valid_time_range); 998 return range.IntersectionWith(valid_time_range);
912 } 999 }
913 1000
914 TimeDelta ChunkDemuxerStream::GetBufferedDuration() const { 1001 TimeDelta ChunkDemuxerStream::GetBufferedDuration() const {
915 return stream_->GetBufferedDuration(); 1002 return stream_->GetBufferedDuration();
916 } 1003 }
917 1004
1005 size_t ChunkDemuxerStream::GetBufferedSize() const {
1006 return stream_->GetBufferedSize();
1007 }
1008
918 void ChunkDemuxerStream::OnNewMediaSegment(DecodeTimestamp start_timestamp) { 1009 void ChunkDemuxerStream::OnNewMediaSegment(DecodeTimestamp start_timestamp) {
919 DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment(" 1010 DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment("
920 << start_timestamp.InSecondsF() << ")"; 1011 << start_timestamp.InSecondsF() << ")";
921 base::AutoLock auto_lock(lock_); 1012 base::AutoLock auto_lock(lock_);
922 stream_->OnNewMediaSegment(start_timestamp); 1013 stream_->OnNewMediaSegment(start_timestamp);
923 } 1014 }
924 1015
925 bool ChunkDemuxerStream::UpdateAudioConfig( 1016 bool ChunkDemuxerStream::UpdateAudioConfig(
926 const AudioDecoderConfig& config, 1017 const AudioDecoderConfig& config,
927 const scoped_refptr<MediaLog>& media_log) { 1018 const scoped_refptr<MediaLog>& media_log) {
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 1405 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
1315 base::AutoLock auto_lock(lock_); 1406 base::AutoLock auto_lock(lock_);
1316 DCHECK(!id.empty()); 1407 DCHECK(!id.empty());
1317 1408
1318 SourceStateMap::const_iterator itr = source_state_map_.find(id); 1409 SourceStateMap::const_iterator itr = source_state_map_.find(id);
1319 1410
1320 DCHECK(itr != source_state_map_.end()); 1411 DCHECK(itr != source_state_map_.end());
1321 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); 1412 return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
1322 } 1413 }
1323 1414
1415 bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
1416 base::TimeDelta currentMediaTime,
1417 size_t newDataSize) {
1418 DVLOG(1) << __FUNCTION__ << "(" << id << ")"
1419 << " media_time=" << currentMediaTime.InSecondsF()
1420 << " newDataSize=" << newDataSize;
1421 base::AutoLock auto_lock(lock_);
1422
1423 // Note: The direct conversion from PTS to DTS is safe here, since we don't
1424 // need to know currentTime precisely for GC. GC only needs to know which GOP
1425 // currentTime points to.
1426 DecodeTimestamp media_time_dts =
1427 DecodeTimestamp::FromPresentationTime(currentMediaTime);
1428
1429 DCHECK(!id.empty());
1430 SourceStateMap::const_iterator itr = source_state_map_.find(id);
1431 if (itr == source_state_map_.end()) {
1432 LOG(WARNING) << __FUNCTION__ << " stream " << id << " not found";
1433 return false;
1434 }
1435 return itr->second->EvictCodedFrames(media_time_dts, newDataSize);
1436 }
1437
1324 void ChunkDemuxer::AppendData( 1438 void ChunkDemuxer::AppendData(
1325 const std::string& id, 1439 const std::string& id,
1326 const uint8* data, 1440 const uint8* data,
1327 size_t length, 1441 size_t length,
1328 TimeDelta append_window_start, 1442 TimeDelta append_window_start,
1329 TimeDelta append_window_end, 1443 TimeDelta append_window_end,
1330 TimeDelta* timestamp_offset, 1444 TimeDelta* timestamp_offset,
1331 const InitSegmentReceivedCB& init_segment_received_cb) { 1445 const InitSegmentReceivedCB& init_segment_received_cb) {
1332 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 1446 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
1333 1447
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after
1834 } 1948 }
1835 1949
1836 void ChunkDemuxer::ShutdownAllStreams() { 1950 void ChunkDemuxer::ShutdownAllStreams() {
1837 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1951 for (SourceStateMap::iterator itr = source_state_map_.begin();
1838 itr != source_state_map_.end(); ++itr) { 1952 itr != source_state_map_.end(); ++itr) {
1839 itr->second->Shutdown(); 1953 itr->second->Shutdown();
1840 } 1954 }
1841 } 1955 }
1842 1956
1843 } // namespace media 1957 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698