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

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

Issue 1491513002: [MSE] Fix GC with media_time past the last appended buffer timestamp (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Implement media_time clamping to buffered ranges Created 5 years 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
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 132
133 } // namespace 133 } // namespace
134 134
135 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, 135 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
136 const scoped_refptr<MediaLog>& media_log, 136 const scoped_refptr<MediaLog>& media_log,
137 bool splice_frames_enabled) 137 bool splice_frames_enabled)
138 : media_log_(media_log), 138 : media_log_(media_log),
139 seek_buffer_timestamp_(kNoTimestamp()), 139 seek_buffer_timestamp_(kNoTimestamp()),
140 media_segment_start_time_(kNoDecodeTimestamp()), 140 media_segment_start_time_(kNoDecodeTimestamp()),
141 range_for_next_append_(ranges_.end()), 141 range_for_next_append_(ranges_.end()),
142 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
143 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 142 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
144 max_interbuffer_distance_(kNoTimestamp()), 143 max_interbuffer_distance_(kNoTimestamp()),
145 memory_limit_(kSourceBufferAudioMemoryLimit), 144 memory_limit_(kSourceBufferAudioMemoryLimit),
146 splice_frames_enabled_(splice_frames_enabled) { 145 splice_frames_enabled_(splice_frames_enabled) {
147 DCHECK(audio_config.IsValidConfig()); 146 DCHECK(audio_config.IsValidConfig());
148 audio_configs_.push_back(audio_config); 147 audio_configs_.push_back(audio_config);
149 } 148 }
150 149
151 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, 150 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
152 const scoped_refptr<MediaLog>& media_log, 151 const scoped_refptr<MediaLog>& media_log,
153 bool splice_frames_enabled) 152 bool splice_frames_enabled)
154 : media_log_(media_log), 153 : media_log_(media_log),
155 seek_buffer_timestamp_(kNoTimestamp()), 154 seek_buffer_timestamp_(kNoTimestamp()),
156 media_segment_start_time_(kNoDecodeTimestamp()), 155 media_segment_start_time_(kNoDecodeTimestamp()),
157 range_for_next_append_(ranges_.end()), 156 range_for_next_append_(ranges_.end()),
158 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
159 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 157 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
160 max_interbuffer_distance_(kNoTimestamp()), 158 max_interbuffer_distance_(kNoTimestamp()),
161 memory_limit_(kSourceBufferVideoMemoryLimit), 159 memory_limit_(kSourceBufferVideoMemoryLimit),
162 splice_frames_enabled_(splice_frames_enabled) { 160 splice_frames_enabled_(splice_frames_enabled) {
163 DCHECK(video_config.IsValidConfig()); 161 DCHECK(video_config.IsValidConfig());
164 video_configs_.push_back(video_config); 162 video_configs_.push_back(video_config);
165 } 163 }
166 164
167 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, 165 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
168 const scoped_refptr<MediaLog>& media_log, 166 const scoped_refptr<MediaLog>& media_log,
169 bool splice_frames_enabled) 167 bool splice_frames_enabled)
170 : media_log_(media_log), 168 : media_log_(media_log),
171 text_track_config_(text_config), 169 text_track_config_(text_config),
172 seek_buffer_timestamp_(kNoTimestamp()), 170 seek_buffer_timestamp_(kNoTimestamp()),
173 media_segment_start_time_(kNoDecodeTimestamp()), 171 media_segment_start_time_(kNoDecodeTimestamp()),
174 range_for_next_append_(ranges_.end()), 172 range_for_next_append_(ranges_.end()),
175 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
176 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 173 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
177 max_interbuffer_distance_(kNoTimestamp()), 174 max_interbuffer_distance_(kNoTimestamp()),
178 memory_limit_(kSourceBufferAudioMemoryLimit), 175 memory_limit_(kSourceBufferAudioMemoryLimit),
179 splice_frames_enabled_(splice_frames_enabled) {} 176 splice_frames_enabled_(splice_frames_enabled) {}
180 177
181 SourceBufferStream::~SourceBufferStream() { 178 SourceBufferStream::~SourceBufferStream() {
182 while (!ranges_.empty()) { 179 while (!ranges_.empty()) {
183 delete ranges_.front(); 180 delete ranges_.front();
184 ranges_.pop_front(); 181 ranges_.pop_front();
185 } 182 }
186 } 183 }
187 184
188 void SourceBufferStream::OnNewMediaSegment( 185 void SourceBufferStream::OnNewMediaSegment(
189 DecodeTimestamp media_segment_start_time) { 186 DecodeTimestamp media_segment_start_time) {
190 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 187 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
191 << " (" << media_segment_start_time.InSecondsF() << ")"; 188 << " (" << media_segment_start_time.InSecondsF() << ")";
192 DCHECK(!end_of_stream_); 189 DCHECK(!end_of_stream_);
193 media_segment_start_time_ = media_segment_start_time; 190 media_segment_start_time_ = media_segment_start_time;
194 new_media_segment_ = true; 191 new_media_segment_ = true;
195 192
196 RangeList::iterator last_range = range_for_next_append_; 193 RangeList::iterator last_range = range_for_next_append_;
197 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time); 194 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time);
198 195
199 // Only reset |last_appended_buffer_timestamp_| if this new media segment is 196 // Only reset |last_appended_buffer_timestamp_| if this new media segment is
200 // not adjacent to the previous media segment appended to the stream. 197 // not adjacent to the previous media segment appended to the stream.
201 if (range_for_next_append_ == ranges_.end() || 198 if (range_for_next_append_ == ranges_.end() ||
202 !AreAdjacentInSequence(last_appended_buffer_timestamp_, 199 !AreAdjacentInSequence(last_appended_buffer_timestamp_,
203 media_segment_start_time)) { 200 media_segment_start_time)) {
204 last_appended_buffer_timestamp_ = kNoDecodeTimestamp(); 201 last_appended_buffer_timestamp_ = kNoDecodeTimestamp();
202 last_appended_buffer_duration_ = kNoTimestamp();
205 last_appended_buffer_is_keyframe_ = false; 203 last_appended_buffer_is_keyframe_ = false;
206 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range"; 204 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range";
207 } else if (last_range != ranges_.end()) { 205 } else if (last_range != ranges_.end()) {
208 DCHECK(last_range == range_for_next_append_); 206 DCHECK(last_range == range_for_next_append_);
209 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range " 207 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range "
210 << "unless intervening remove makes discontinuity"; 208 << "unless intervening remove makes discontinuity";
211 } 209 }
212 } 210 }
213 211
214 bool SourceBufferStream::Append(const BufferQueue& buffers) { 212 bool SourceBufferStream::Append(const BufferQueue& buffers) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); 260 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp();
263 BufferQueue deleted_buffers; 261 BufferQueue deleted_buffers;
264 262
265 PrepareRangesForNextAppend(buffers, &deleted_buffers); 263 PrepareRangesForNextAppend(buffers, &deleted_buffers);
266 264
267 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, 265 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
268 // create a new range with |buffers|. 266 // create a new range with |buffers|.
269 if (range_for_next_append_ != ranges_.end()) { 267 if (range_for_next_append_ != ranges_.end()) {
270 (*range_for_next_append_)->AppendBuffersToEnd(buffers); 268 (*range_for_next_append_)->AppendBuffersToEnd(buffers);
271 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); 269 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
270 last_appended_buffer_duration_ = buffers.back()->duration();
272 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); 271 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
273 } else { 272 } else {
274 DecodeTimestamp new_range_start_time = std::min( 273 DecodeTimestamp new_range_start_time = std::min(
275 media_segment_start_time_, buffers.front()->GetDecodeTimestamp()); 274 media_segment_start_time_, buffers.front()->GetDecodeTimestamp());
276 const BufferQueue* buffers_for_new_range = &buffers; 275 const BufferQueue* buffers_for_new_range = &buffers;
277 BufferQueue trimmed_buffers; 276 BufferQueue trimmed_buffers;
278 277
279 // If the new range is not being created because of a new media 278 // If the new range is not being created because of a new media
280 // segment, then we must make sure that we start with a key frame. 279 // segment, then we must make sure that we start with a key frame.
281 // This can happen if the GOP in the previous append gets destroyed 280 // This can happen if the GOP in the previous append gets destroyed
282 // by a Remove() call. 281 // by a Remove() call.
283 if (!new_media_segment_) { 282 if (!new_media_segment_) {
284 BufferQueue::const_iterator itr = buffers.begin(); 283 BufferQueue::const_iterator itr = buffers.begin();
285 284
286 // Scan past all the non-key-frames. 285 // Scan past all the non-key-frames.
287 while (itr != buffers.end() && !(*itr)->is_key_frame()) { 286 while (itr != buffers.end() && !(*itr)->is_key_frame()) {
288 ++itr; 287 ++itr;
289 } 288 }
290 289
291 // If we didn't find a key frame, then update the last appended 290 // If we didn't find a key frame, then update the last appended
292 // buffer state and return. 291 // buffer state and return.
293 if (itr == buffers.end()) { 292 if (itr == buffers.end()) {
294 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); 293 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
294 last_appended_buffer_duration_ = buffers.back()->duration();
295 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); 295 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
296 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 296 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
297 << ": new buffers in the middle of media segment depend on" 297 << ": new buffers in the middle of media segment depend on"
298 "keyframe that has been removed, and contain no keyframes." 298 "keyframe that has been removed, and contain no keyframes."
299 "Skipping further processing."; 299 "Skipping further processing.";
300 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 300 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
301 << ": done. ranges_=" << RangesToString(ranges_); 301 << ": done. ranges_=" << RangesToString(ranges_);
302 return true; 302 return true;
303 } else if (itr != buffers.begin()) { 303 } else if (itr != buffers.begin()) {
304 // Copy the first key frame and everything after it into 304 // Copy the first key frame and everything after it into
305 // |trimmed_buffers|. 305 // |trimmed_buffers|.
306 trimmed_buffers.assign(itr, buffers.end()); 306 trimmed_buffers.assign(itr, buffers.end());
307 buffers_for_new_range = &trimmed_buffers; 307 buffers_for_new_range = &trimmed_buffers;
308 } 308 }
309 309
310 new_range_start_time = 310 new_range_start_time =
311 buffers_for_new_range->front()->GetDecodeTimestamp(); 311 buffers_for_new_range->front()->GetDecodeTimestamp();
312 } 312 }
313 313
314 range_for_next_append_ = 314 range_for_next_append_ =
315 AddToRanges(new SourceBufferRange( 315 AddToRanges(new SourceBufferRange(
316 TypeToGapPolicy(GetType()), 316 TypeToGapPolicy(GetType()),
317 *buffers_for_new_range, new_range_start_time, 317 *buffers_for_new_range, new_range_start_time,
318 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, 318 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
319 base::Unretained(this)))); 319 base::Unretained(this))));
320 last_appended_buffer_timestamp_ = 320 last_appended_buffer_timestamp_ =
321 buffers_for_new_range->back()->GetDecodeTimestamp(); 321 buffers_for_new_range->back()->GetDecodeTimestamp();
322 last_appended_buffer_duration_ = buffers_for_new_range->back()->duration();
322 last_appended_buffer_is_keyframe_ = 323 last_appended_buffer_is_keyframe_ =
323 buffers_for_new_range->back()->is_key_frame(); 324 buffers_for_new_range->back()->is_key_frame();
324 } 325 }
325 326
326 new_media_segment_ = false; 327 new_media_segment_ = false;
327 328
328 MergeWithAdjacentRangeIfNecessary(range_for_next_append_); 329 MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
329 330
330 // Seek to try to fulfill a previous call to Seek(). 331 // Seek to try to fulfill a previous call to Seek().
331 if (seek_pending_) { 332 if (seek_pending_) {
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC" 645 DVLOG(2) << __FUNCTION__ << " " << GetStreamTypeName() << ": Before GC"
645 << " media_time=" << media_time.InSecondsF() 646 << " media_time=" << media_time.InSecondsF()
646 << " ranges_=" << RangesToString(ranges_) 647 << " ranges_=" << RangesToString(ranges_)
647 << " seek_pending_=" << seek_pending_ 648 << " seek_pending_=" << seek_pending_
648 << " ranges_size=" << ranges_size 649 << " ranges_size=" << ranges_size
649 << " newDataSize=" << newDataSize 650 << " newDataSize=" << newDataSize
650 << " memory_limit_=" << memory_limit_ 651 << " memory_limit_=" << memory_limit_
651 << " last_appended_buffer_timestamp_=" 652 << " last_appended_buffer_timestamp_="
652 << last_appended_buffer_timestamp_.InSecondsF(); 653 << last_appended_buffer_timestamp_.InSecondsF();
653 654
655 if (selected_range_ && !seek_pending_ &&
656 media_time > selected_range_->GetBufferedEndTimestamp()) {
657 // Strictly speaking |media_time| (taken from HTMLMediaElement::currentTime)
658 // should always be in the buffered ranges, but media::Pipeline uses audio
659 // stream as the main time source, when audio is present.
660 // In cases when audio and video streams have different buffered ranges, the
661 // |media_time| value might be slightly outside of the video stream buffered
662 // range. In those cases we need to clamp |media_time| value to the current
663 // stream buffered ranges, to ensure the MSE garbage collection algorithm
664 // works correctly (see crbug.com/563292 for details).
665 DecodeTimestamp selected_buffered_end =
666 selected_range_->GetBufferedEndTimestamp();
667
668 DVLOG(2) << __FUNCTION__ << " media_time " << media_time.InSecondsF()
669 << " is outside of selected_range_=["
670 << selected_range_->GetStartTimestamp().InSecondsF() << ";"
671 << selected_buffered_end.InSecondsF()
672 << "] clamping media_time to be "
673 << selected_buffered_end.InSecondsF();
674 media_time = selected_buffered_end;
675 }
676
654 size_t bytes_freed = 0; 677 size_t bytes_freed = 0;
655 678
656 // If last appended buffer position was earlier than the current playback time 679 // If last appended buffer position was earlier than the current playback time
657 // then try deleting data between last append and current media_time. 680 // then try deleting data between last append and current media_time.
658 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() && 681 if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp() &&
659 last_appended_buffer_timestamp_ < media_time) { 682 last_appended_buffer_duration_ != kNoTimestamp() &&
683 media_time >
684 last_appended_buffer_timestamp_ + last_appended_buffer_duration_) {
660 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time); 685 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
661 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended " 686 DVLOG(3) << __FUNCTION__ << " FreeBuffersAfterLastAppended "
662 << " released " << between << " bytes" 687 << " released " << between << " bytes"
663 << " ranges_=" << RangesToString(ranges_); 688 << " ranges_=" << RangesToString(ranges_);
664 bytes_freed += between; 689 bytes_freed += between;
665 690
666 // Some players start appending data at the new seek target position before 691 // Some players start appending data at the new seek target position before
667 // actually initiating the seek operation (i.e. they try to improve seek 692 // actually initiating the seek operation (i.e. they try to improve seek
668 // performance by prebuffering some data at the seek target position and 693 // performance by prebuffering some data at the seek target position and
669 // initiating seek once enough data is pre-buffered. In those cases we'll 694 // 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 695 // 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 696 // 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 697 // the most recently appended data, i.e. data belonging to the same buffered
673 // range as the most recent append. 698 // range as the most recent append.
674 if (range_for_next_append_ != ranges_.end()) { 699 if (range_for_next_append_ != ranges_.end()) {
675 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time); 700 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
676 media_time = (*range_for_next_append_)->GetStartTimestamp(); 701 media_time = (*range_for_next_append_)->GetStartTimestamp();
702 DVLOG(3) << __FUNCTION__ << " media_time adjusted to "
703 << media_time.InSecondsF();
677 } 704 }
678 } 705 }
679 706
680 // If there is an unsatisfied pending seek, we can safely remove all data that 707 // 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 708 // 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 709 // most recently appended GOP and then remove from the front if we still don't
683 // have enough space for the upcoming append. 710 // have enough space for the upcoming append.
684 if (bytes_freed < bytes_to_free && seek_pending_) { 711 if (bytes_freed < bytes_to_free && seek_pending_) {
685 DCHECK(!ranges_.empty()); 712 DCHECK(!ranges_.empty());
686 // All data earlier than the seek target |media_time| can be removed safely 713 // All data earlier than the seek target |media_time| can be removed safely
(...skipping 1068 matching lines...) Expand 10 before | Expand all | Expand 10 after
1755 return false; 1782 return false;
1756 1783
1757 DCHECK_NE(have_splice_buffers, have_preroll_buffer); 1784 DCHECK_NE(have_splice_buffers, have_preroll_buffer);
1758 splice_buffers_index_ = 0; 1785 splice_buffers_index_ = 0;
1759 pending_buffer_.swap(*out_buffer); 1786 pending_buffer_.swap(*out_buffer);
1760 pending_buffers_complete_ = false; 1787 pending_buffers_complete_ = false;
1761 return true; 1788 return true;
1762 } 1789 }
1763 1790
1764 } // namespace media 1791 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698