1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/source_buffer_stream.h"
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/trace_event/trace_event.h"
16 #include "media/base/demuxer_memory_limit.h"
17 #include "media/base/media_switches.h"
18 #include "media/base/stream_parser_buffer.h"
19 #include "media/base/timestamp_constants.h"
25 // The minimum interbuffer decode timestamp delta (or buffer duration) for use
26 // in fudge room for range membership, adjacency and coalescing.
27 const int kMinimumInterbufferDistanceInMs = 1;
29 // Limit the number of MEDIA_LOG() logs for track buffer time gaps.
30 const int kMaxTrackBufferGapWarningLogs = 20;
32 // Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings.
33 const int kMaxGarbageCollectAlgorithmWarningLogs = 20;
35 // Limit the number of MEDIA_LOG() logs for splice overlap trimming.
36 const int kMaxAudioSpliceLogs = 20;
38 // Helper method that returns true if |ranges| is sorted in increasing order,
40 bool IsRangeListSorted(const SourceBufferStream::RangeList& ranges) {
41 base::TimeDelta prev = kNoTimestamp;
42 for (const auto& range_ptr : ranges) {
43 if (prev != kNoTimestamp && prev >= range_ptr->GetStartTimestamp())
45 prev = range_ptr->GetBufferedEndTimestamp();
50 // Returns an estimate of how far from the beginning or end of a range a buffer
51 // can be to still be considered in the range, given the |approximate_duration|
52 // of a buffer in the stream.
53 // TODO(wolenetz): Once all stream parsers emit accurate frame durations, use
54 // logic like FrameProcessor (2*last_frame_duration + last_decode_timestamp)
55 // instead of an overall maximum interbuffer delta for range discontinuity
57 // See http://crbug.com/351489 and http://crbug.com/351166.
58 base::TimeDelta ComputeFudgeRoom(base::TimeDelta approximate_duration) {
59 // Because we do not know exactly when is the next timestamp, any buffer
60 // that starts within 2x the approximate duration of a buffer is considered
62 return 2 * approximate_duration;
65 // The amount of time the beginning of the buffered data can differ from the
66 // start time in order to still be considered the start of stream.
67 base::TimeDelta kSeekToStartFudgeRoom() {
68 return base::Milliseconds(1000);
71 // Helper method for logging.
72 std::string StatusToString(const SourceBufferStreamStatus& status) {
74 case SourceBufferStreamStatus::kSuccess:
76 case SourceBufferStreamStatus::kNeedBuffer:
78 case SourceBufferStreamStatus::kConfigChange:
79 return "kConfigChange";
80 case SourceBufferStreamStatus::kEndOfStream:
81 return "kEndOfStream";
87 // Helper method for logging, converts a range into a readable string.
88 std::string RangeToString(const SourceBufferRange& range) {
89 if (range.size_in_bytes() == 0) {
93 ss << "[" << range.GetStartTimestamp().InMicroseconds() << "us;"
94 << range.GetEndTimestamp().InMicroseconds() << "us("
95 << range.GetBufferedEndTimestamp().InMicroseconds() << "us)]";
99 // Helper method for logging, converts a set of ranges into a readable string.
100 std::string RangesToString(const SourceBufferStream::RangeList& ranges) {
104 std::stringstream ss;
105 for (const auto& range_ptr : ranges) {
106 if (range_ptr != ranges.front())
108 ss << RangeToString(*range_ptr);
113 std::string BufferQueueBuffersToLogString(
114 const SourceBufferStream::BufferQueue& buffers) {
115 std::stringstream result;
117 result << "Buffers:\n";
118 for (const auto& buf : buffers) {
119 result << "\tdts=" << buf->GetDecodeTimestamp().InMicroseconds() << " "
120 << buf->AsHumanReadableString()
121 << ", is_duration_estimated=" << buf->is_duration_estimated()
128 std::string BufferQueueMetadataToLogString(
129 const SourceBufferStream::BufferQueue& buffers) {
130 std::stringstream result;
131 base::TimeDelta pts_interval_start;
132 base::TimeDelta pts_interval_end;
133 SourceBufferStream::GetTimestampInterval(buffers, &pts_interval_start,
136 result << "dts=[" << buffers.front()->GetDecodeTimestamp().InMicroseconds()
137 << "us;" << buffers.back()->GetDecodeTimestamp().InMicroseconds()
138 << "us(last frame dur=" << buffers.back()->duration().InMicroseconds()
139 << "us)], pts interval=[" << pts_interval_start.InMicroseconds()
140 << "us," << pts_interval_end.InMicroseconds() << "us)";
144 SourceBufferRange::GapPolicy TypeToGapPolicy(SourceBufferStreamType type) {
146 case SourceBufferStreamType::kAudio:
147 case SourceBufferStreamType::kVideo:
148 return SourceBufferRange::NO_GAPS_ALLOWED;
149 case SourceBufferStreamType::kText:
150 return SourceBufferRange::ALLOW_GAPS;
154 return SourceBufferRange::NO_GAPS_ALLOWED;
159 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
161 : media_log_(media_log),
162 seek_buffer_timestamp_(kNoTimestamp),
163 coded_frame_group_start_pts_(kNoTimestamp),
164 range_for_next_append_(ranges_.end()),
165 highest_output_buffer_timestamp_(kNoTimestamp),
166 max_interbuffer_distance_(
167 base::Milliseconds(kMinimumInterbufferDistanceInMs)),
168 memory_limit_(GetDemuxerStreamAudioMemoryLimit(&audio_config)) {
169 DCHECK(audio_config.IsValidConfig());
170 audio_configs_.push_back(audio_config);
171 DVLOG(2) << __func__ << ": audio_buffer_size= " << memory_limit_;
174 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
176 : media_log_(media_log),
177 seek_buffer_timestamp_(kNoTimestamp),
178 coded_frame_group_start_pts_(kNoTimestamp),
179 range_for_next_append_(ranges_.end()),
180 highest_output_buffer_timestamp_(kNoTimestamp),
181 max_interbuffer_distance_(
182 base::Milliseconds(kMinimumInterbufferDistanceInMs)),
184 GetDemuxerStreamVideoMemoryLimit(Demuxer::DemuxerTypes::kChunkDemuxer,
186 DCHECK(video_config.IsValidConfig());
187 video_configs_.push_back(video_config);
188 DVLOG(2) << __func__ << ": video_buffer_size= " << memory_limit_;
191 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
193 : media_log_(media_log),
194 text_track_config_(text_config),
195 seek_buffer_timestamp_(kNoTimestamp),
196 coded_frame_group_start_pts_(kNoTimestamp),
197 range_for_next_append_(ranges_.end()),
198 highest_output_buffer_timestamp_(kNoTimestamp),
199 max_interbuffer_distance_(
200 base::Milliseconds(kMinimumInterbufferDistanceInMs)),
202 GetDemuxerStreamAudioMemoryLimit(nullptr /*audio_config*/)) {}
204 SourceBufferStream::~SourceBufferStream() = default;
206 void SourceBufferStream::OnStartOfCodedFrameGroup(
207 base::TimeDelta coded_frame_group_start_pts) {
208 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " (pts "
209 << coded_frame_group_start_pts.InMicroseconds() << "us)";
210 DCHECK(!end_of_stream_);
211 coded_frame_group_start_pts_ = coded_frame_group_start_pts;
212 new_coded_frame_group_ = true;
214 auto last_range = range_for_next_append_;
215 range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_pts_);
217 // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
218 // is not adjacent to the previous coded frame group appended to the stream.
219 if (range_for_next_append_ == ranges_.end() ||
220 !IsNextGopAdjacentToEndOfCurrentAppendSequence(
221 coded_frame_group_start_pts_)) {
222 ResetLastAppendedState();
223 DVLOG(3) << __func__ << " next appended buffers will "
224 << (range_for_next_append_ == ranges_.end()
225 ? "be in a new range"
226 : "overlap an existing range");
228 if (range_for_next_append_ != ranges_.end()) {
229 // If this new coded frame group overlaps an existing range, preserve
230 // continuity from that range to the new group by moving the start time
231 // earlier (but not at or beyond the most recent buffered frame's time
232 // before |coded_frame_group_start_pts_| in the range, and not beyond the
233 // range's start time. This update helps prevent discontinuity from being
234 // introduced by the ::RemoveInternal processing during the next ::Append
236 base::TimeDelta adjusted_start_time =
237 (*range_for_next_append_)
238 ->FindHighestBufferedTimestampAtOrBefore(
239 coded_frame_group_start_pts_);
240 if (adjusted_start_time < coded_frame_group_start_pts_) {
241 // Exclude removal of that earlier frame during later Append
242 // processing by adjusting the removal range slightly forward.
243 coded_frame_group_start_pts_ =
244 adjusted_start_time + base::Microseconds(1);
247 } else if (last_range != ranges_.end()) {
248 DCHECK(last_range == range_for_next_append_);
249 DVLOG(3) << __func__ << " next appended buffers will continue range unless "
250 << "intervening remove makes discontinuity";
254 void SourceBufferStream::Append(const BufferQueue& buffers) {
255 TRACE_EVENT2("media", "SourceBufferStream::Append",
256 "stream type", GetStreamTypeName(),
257 "buffers to append", buffers.size());
259 DCHECK(!buffers.empty());
260 DCHECK(coded_frame_group_start_pts_ != kNoTimestamp);
261 DCHECK(!end_of_stream_);
263 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": buffers "
264 << BufferQueueMetadataToLogString(buffers);
265 DVLOG(4) << BufferQueueBuffersToLogString(buffers);
267 DCHECK(!buffers.front()->is_key_frame() ||
268 coded_frame_group_start_pts_ <= buffers.front()->timestamp());
269 DVLOG_IF(2, coded_frame_group_start_pts_ > buffers.front()->timestamp())
271 << " Suspected SAP-Type-2 occurrence: coded_frame_group_start_pts_="
272 << coded_frame_group_start_pts_.InMicroseconds()
273 << "us, first new buffer has timestamp="
274 << buffers.front()->timestamp().InMicroseconds() << "us";
276 // New coded frame groups emitted by the coded frame processor must begin with
277 // a keyframe. Avoid propagating with escalating impact if this assumption is
279 CHECK(!new_coded_frame_group_ || buffers.front()->is_key_frame());
281 // Buffers within each GOP in a coded frame group must be monotonically
282 // increasing in DTS order.
283 DCHECK(IsDtsMonotonicallyIncreasing(buffers));
285 // Both of these checks enforce what should be guaranteed by how
286 // FrameProcessor signals OnStartOfCodedFrameGroup and the buffers it tells us
288 DCHECK(coded_frame_group_start_pts_ >= base::TimeDelta());
289 DCHECK(buffers.front()->timestamp() >= base::TimeDelta());
291 if (UpdateMaxInterbufferDtsDistance(buffers)) {
292 // Coalesce |ranges_| using the new fudge room. This helps keep |ranges_|
293 // sorted in complex scenarios. See https://crbug.com/793247.
294 MergeAllAdjacentRanges();
297 SetConfigIds(buffers);
299 // Save a snapshot of stream state before range modifications are made.
300 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
301 BufferQueue deleted_buffers;
303 PrepareRangesForNextAppend(buffers, &deleted_buffers);
305 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
306 // create a new range with |buffers|.
307 if (range_for_next_append_ != ranges_.end()) {
308 if (new_coded_frame_group_) {
309 // If the first append to this stream in a new coded frame group continues
310 // a previous range, use the new group's start time instead of the first
311 // new buffer's timestamp as the proof of adjacency to the existing range.
312 // A large gap (larger than our normal buffer adjacency test) can occur in
313 // a muxed set of streams (which share a common coded frame group start
314 // time) with a significantly jagged start across the streams.
315 (*range_for_next_append_)
316 ->AppendBuffersToEnd(buffers, coded_frame_group_start_pts_);
318 // Otherwise, use the first new buffer as proof of adjacency.
319 (*range_for_next_append_)->AppendBuffersToEnd(buffers, kNoTimestamp);
322 last_appended_buffer_timestamp_ = buffers.back()->timestamp();
323 last_appended_buffer_duration_ = buffers.back()->duration();
324 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
325 last_appended_buffer_decode_timestamp_ =
326 buffers.back()->GetDecodeTimestamp();
327 highest_timestamp_in_append_sequence_ =
328 (*range_for_next_append_)->GetEndTimestamp();
329 highest_buffered_end_time_in_append_sequence_ =
330 (*range_for_next_append_)->GetBufferedEndTimestamp();
332 base::TimeDelta new_range_start_time =
333 std::min(coded_frame_group_start_pts_, buffers.front()->timestamp());
335 const BufferQueue* buffers_for_new_range = &buffers;
336 BufferQueue trimmed_buffers;
338 // If the new range is not being created because of a new coded frame group,
339 // then we must make sure that we start with a key frame. This can happen
340 // if the GOP in the previous append gets destroyed by a Remove() call.
341 if (!new_coded_frame_group_) {
342 BufferQueue::const_iterator itr = buffers.begin();
344 // Scan past all the non-key-frames.
345 while (itr != buffers.end() && !(*itr)->is_key_frame()) {
349 // If we didn't find a key frame, then update the last appended
350 // buffer state and return.
351 if (itr == buffers.end()) {
352 last_appended_buffer_timestamp_ = buffers.back()->timestamp();
353 last_appended_buffer_duration_ = buffers.back()->duration();
354 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
355 last_appended_buffer_decode_timestamp_ =
356 buffers.back()->GetDecodeTimestamp();
357 // Since we didn't buffer anything, don't update
358 // |highest_timestamp_in_append_sequence_|.
359 DVLOG(1) << __func__ << " " << GetStreamTypeName()
360 << ": new buffers in the middle of coded frame group depend on"
361 " keyframe that has been removed, and contain no keyframes."
362 " Skipping further processing.";
363 DVLOG(1) << __func__ << " " << GetStreamTypeName()
364 << ": done. ranges_=" << RangesToString(ranges_);
366 } else if (itr != buffers.begin()) {
367 // Copy the first key frame and everything after it into
368 // |trimmed_buffers|.
369 trimmed_buffers.assign(itr, buffers.end());
370 buffers_for_new_range = &trimmed_buffers;
373 new_range_start_time = buffers_for_new_range->front()->timestamp();
376 range_for_next_append_ = AddToRanges(std::make_unique<SourceBufferRange>(
377 TypeToGapPolicy(GetType()), *buffers_for_new_range,
378 new_range_start_time,
379 base::BindRepeating(&SourceBufferStream::GetMaxInterbufferDistance,
380 base::Unretained(this))));
382 last_appended_buffer_timestamp_ =
383 buffers_for_new_range->back()->timestamp();
384 last_appended_buffer_duration_ = buffers_for_new_range->back()->duration();
385 last_appended_buffer_is_keyframe_ =
386 buffers_for_new_range->back()->is_key_frame();
387 last_appended_buffer_decode_timestamp_ =
388 buffers_for_new_range->back()->GetDecodeTimestamp();
389 highest_timestamp_in_append_sequence_ =
390 (*range_for_next_append_)->GetEndTimestamp();
391 highest_buffered_end_time_in_append_sequence_ =
392 (*range_for_next_append_)->GetBufferedEndTimestamp();
395 new_coded_frame_group_ = false;
397 MergeWithNextRangeIfNecessary(range_for_next_append_);
399 // Some SAP-Type-2 append sequences require that we coalesce
400 // |range_for_next_append_| with the range that is *before* it.
401 if (range_for_next_append_ != ranges_.begin()) {
402 auto prior_range = range_for_next_append_;
404 MergeWithNextRangeIfNecessary(prior_range);
407 // Seek to try to fulfill a previous call to Seek().
409 DCHECK(!selected_range_);
410 DCHECK(deleted_buffers.empty());
411 Seek(seek_buffer_timestamp_);
414 if (!deleted_buffers.empty()) {
415 track_buffer_.insert(track_buffer_.end(), deleted_buffers.begin(),
416 deleted_buffers.end());
417 DVLOG(3) << __func__ << " " << GetStreamTypeName() << " Added "
418 << deleted_buffers.size()
419 << " buffers to track buffer. TB size is now "
420 << track_buffer_.size();
422 DVLOG(3) << __func__ << " " << GetStreamTypeName()
423 << " No deleted buffers for track buffer";
426 // Prune any extra buffers in |track_buffer_| if new keyframes
427 // are appended to the range covered by |track_buffer_|.
428 if (!track_buffer_.empty()) {
429 base::TimeDelta keyframe_timestamp =
430 FindKeyframeAfterTimestamp(track_buffer_.front()->timestamp());
431 if (keyframe_timestamp != kNoTimestamp)
432 PruneTrackBuffer(keyframe_timestamp);
435 SetSelectedRangeIfNeeded(next_buffer_timestamp);
437 DVLOG(1) << __func__ << " " << GetStreamTypeName()
438 << ": done. ranges_=" << RangesToString(ranges_);
439 DCHECK(IsRangeListSorted(ranges_));
440 DCHECK(OnlySelectedRangeIsSeeked());
443 void SourceBufferStream::Remove(base::TimeDelta start,
445 base::TimeDelta duration) {
446 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
447 << start.InMicroseconds() << "us, " << end.InMicroseconds() << "us, "
448 << duration.InMicroseconds() << "us)";
449 DCHECK(start >= base::TimeDelta()) << start.InMicroseconds() << "us";
450 DCHECK(start < end) << "start " << start.InMicroseconds() << "us, end "
451 << end.InMicroseconds() << "us";
452 DCHECK(duration != kNoTimestamp);
454 base::TimeDelta remove_end_timestamp = duration;
455 base::TimeDelta keyframe_timestamp = FindKeyframeAfterTimestamp(end);
456 if (keyframe_timestamp != kNoTimestamp) {
457 remove_end_timestamp = keyframe_timestamp;
458 } else if (end < remove_end_timestamp) {
459 remove_end_timestamp = end;
462 BufferQueue deleted_buffers;
463 RemoveInternal(start, remove_end_timestamp, false, &deleted_buffers);
465 if (!deleted_buffers.empty()) {
466 // Buffers for the current position have been removed.
467 SetSelectedRangeIfNeeded(deleted_buffers.front()->timestamp());
468 if (highest_output_buffer_timestamp_ == kNoTimestamp) {
469 // We just removed buffers for the current playback position for this
470 // stream, yet we also had output no buffer since the last Seek.
471 // Re-seek to prevent stall.
472 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": re-seeking to "
473 << seek_buffer_timestamp_
474 << " to prevent stall if this time becomes buffered again";
475 Seek(seek_buffer_timestamp_);
479 DCHECK(OnlySelectedRangeIsSeeked());
480 DCHECK(IsRangeListSorted(ranges_));
483 base::TimeDelta SourceBufferStream::PotentialNextAppendTimestamp() const {
484 // The next potential append will either be in a GOP adjacent to
485 // |highest_timestamp_in_append_sequence_| (if known), or if unknown and we
486 // are still at the beginning of a new coded frame group, then will be into
487 // the range (if any) to which |coded_frame_group_start_pts_| belongs.
488 if (highest_timestamp_in_append_sequence_ != kNoTimestamp)
489 return highest_timestamp_in_append_sequence_;
491 if (new_coded_frame_group_)
492 return coded_frame_group_start_pts_;
494 // If we still don't know a potential next append timestamp, then we have
495 // removed the range to which it previously belonged and have not completed a
496 // subsequent append or received a subsequent OnStartOfCodedFrameGroup()
501 void SourceBufferStream::UpdateLastAppendStateForRemove(
502 base::TimeDelta remove_start,
503 base::TimeDelta remove_end,
504 bool exclude_start) {
505 // TODO(chcunningham): change exclude_start to include_start in this class and
506 // SourceBufferRange. Negatives are hard to reason about.
507 bool include_start = !exclude_start;
509 // No need to check previous append's GOP if starting a new CFG. New CFG is
510 // already required to begin with a key frame.
511 if (new_coded_frame_group_)
514 if (range_for_next_append_ != ranges_.end()) {
515 if (last_appended_buffer_timestamp_ != kNoTimestamp) {
516 // Note start and end of last appended GOP.
517 base::TimeDelta gop_end = highest_timestamp_in_append_sequence_;
518 base::TimeDelta gop_start =
519 (*range_for_next_append_)->KeyframeBeforeTimestamp(gop_end);
521 // If last append is about to be disrupted, reset associated state so we
522 // know to create a new range for future appends and require an initial
524 if (((include_start && remove_start == gop_end) ||
525 remove_start < gop_end) &&
526 remove_end > gop_start) {
527 DVLOG(2) << __func__ << " " << GetStreamTypeName()
528 << " Resetting next append state for remove ("
529 << remove_start.InMicroseconds() << "us, "
530 << remove_end.InMicroseconds() << "us, " << exclude_start
532 range_for_next_append_ = ranges_.end();
533 ResetLastAppendedState();
536 NOTREACHED() << __func__ << " " << GetStreamTypeName()
537 << " range_for_next_append_ set, but not tracking last"
538 << " append nor new coded frame group.";
543 void SourceBufferStream::RemoveInternal(base::TimeDelta start,
546 BufferQueue* deleted_buffers) {
547 DVLOG(2) << __func__ << " " << GetStreamTypeName() << " ("
548 << start.InMicroseconds() << "us, " << end.InMicroseconds() << "us, "
549 << exclude_start << ")";
550 DVLOG(3) << __func__ << " " << GetStreamTypeName()
551 << ": before remove ranges_=" << RangesToString(ranges_);
553 DCHECK(start >= base::TimeDelta());
554 DCHECK(start < end) << "start " << start.InMicroseconds() << "us, end "
555 << end.InMicroseconds() << "us";
556 DCHECK(deleted_buffers);
558 // Doing this up-front simplifies decisions about |range_for_next_append_|
560 UpdateLastAppendStateForRemove(start, end, exclude_start);
562 auto itr = ranges_.begin();
563 while (itr != ranges_.end()) {
564 SourceBufferRange* range = itr->get();
565 if (range->GetStartTimestamp() >= end)
568 // Split off any remaining GOPs starting at or after |end| and add it to
570 std::unique_ptr<SourceBufferRange> new_range = range->SplitRange(end);
572 itr = ranges_.insert(++itr, std::move(new_range));
574 // Update |range_for_next_append_| if it was previously |range| and should
575 // be the new range (that |itr| is at) now.
576 if (range_for_next_append_ != ranges_.end() &&
577 range_for_next_append_->get() == range) {
578 base::TimeDelta potential_next_append_timestamp =
579 PotentialNextAppendTimestamp();
580 if (potential_next_append_timestamp != kNoTimestamp &&
581 (*itr)->BelongsToRange(potential_next_append_timestamp)) {
582 range_for_next_append_ = itr;
586 // Update the selected range if the next buffer position was transferred
587 // to the newly inserted range (that |itr| is at now).
588 if ((*itr)->HasNextBufferPosition())
589 SetSelectedRange(itr->get());
594 // Truncate the current range so that it only contains data before
595 // the removal range.
596 BufferQueue saved_buffers;
597 bool delete_range = range->TruncateAt(start, &saved_buffers, exclude_start);
599 // Check to see if the current playback position was removed and update the
600 // selected range appropriately.
601 if (!saved_buffers.empty()) {
602 DCHECK(!range->HasNextBufferPosition());
603 DCHECK(deleted_buffers->empty());
605 *deleted_buffers = saved_buffers;
608 if (range == selected_range_ && !range->HasNextBufferPosition())
609 SetSelectedRange(NULL);
611 // If the current range now is completely covered by the removal
612 // range then delete it and move on.
614 DeleteAndRemoveRange(&itr);
618 // Clear |range_for_next_append_| if we determine that the removal
619 // operation makes it impossible for the next append to be added
620 // to the current range.
621 if (range_for_next_append_ != ranges_.end() &&
622 range_for_next_append_->get() == range) {
623 base::TimeDelta potential_next_append_timestamp =
624 PotentialNextAppendTimestamp();
626 if (!range->BelongsToRange(potential_next_append_timestamp)) {
627 DVLOG(1) << "Resetting range_for_next_append_ since the next append"
628 << " can't add to the current range.";
629 range_for_next_append_ =
630 FindExistingRangeFor(potential_next_append_timestamp);
634 // Move on to the next range.
638 DVLOG(3) << __func__ << " " << GetStreamTypeName()
639 << ": after remove ranges_=" << RangesToString(ranges_);
641 DCHECK(OnlySelectedRangeIsSeeked());
644 void SourceBufferStream::ResetSeekState() {
645 SetSelectedRange(NULL);
646 track_buffer_.clear();
647 config_change_pending_ = false;
648 highest_output_buffer_timestamp_ = kNoTimestamp;
649 just_exhausted_track_buffer_ = false;
650 pending_buffer_.reset();
651 pending_buffers_complete_ = false;
654 void SourceBufferStream::ResetLastAppendedState() {
655 last_appended_buffer_timestamp_ = kNoTimestamp;
656 last_appended_buffer_duration_ = kNoTimestamp;
657 last_appended_buffer_is_keyframe_ = false;
658 last_appended_buffer_decode_timestamp_ = kNoDecodeTimestamp;
659 highest_timestamp_in_append_sequence_ = kNoTimestamp;
660 highest_buffered_end_time_in_append_sequence_ = kNoTimestamp;
663 bool SourceBufferStream::ShouldSeekToStartOfBuffered(
664 base::TimeDelta seek_timestamp) const {
667 base::TimeDelta beginning_of_buffered = ranges_.front()->GetStartTimestamp();
668 return (seek_timestamp <= beginning_of_buffered &&
669 beginning_of_buffered < kSeekToStartFudgeRoom());
672 bool SourceBufferStream::IsDtsMonotonicallyIncreasing(
673 const BufferQueue& buffers) {
674 DCHECK(!buffers.empty());
675 DecodeTimestamp prev_dts = last_appended_buffer_decode_timestamp_;
676 for (BufferQueue::const_iterator itr = buffers.begin();
677 itr != buffers.end(); ++itr) {
678 DecodeTimestamp current_dts = (*itr)->GetDecodeTimestamp();
679 bool current_is_keyframe = (*itr)->is_key_frame();
680 DCHECK(current_dts != kNoDecodeTimestamp);
681 DCHECK((*itr)->duration() >= base::TimeDelta())
682 << "Packet with invalid duration."
683 << " pts " << (*itr)->timestamp().InMicroseconds() << "us dts "
684 << (*itr)->GetDecodeTimestamp().InMicroseconds() << "us dur "
685 << (*itr)->duration().InMicroseconds() << "us";
687 // Only verify DTS monotonicity within the current GOP (since the last
688 // keyframe). FrameProcessor should have enforced that all audio frames are
689 // keyframes already, or are nonkeyframes with monotonically increasing PTS
690 // since the last keyframe for those types of audio for which nonkeyframes
691 // may be involved, e.g. xHE-AAC. Video nonkeyframes are not restricted to
692 // being in-order by PTS, but both audio and video nonkeyframes must be in
693 // decode sequence since the last keyframe.
694 if (current_is_keyframe) {
695 // Reset prev_dts tracking since a new GOP is starting.
696 prev_dts = kNoDecodeTimestamp;
699 if (prev_dts != kNoDecodeTimestamp) {
700 if (current_dts < prev_dts) {
701 MEDIA_LOG(ERROR, media_log_)
702 << "Buffers did not monotonically increase.";
707 prev_dts = current_dts;
712 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
713 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
714 if ((*itr)->HasNextBufferPosition() && itr->get() != selected_range_)
717 return !selected_range_ || selected_range_->HasNextBufferPosition();
720 bool SourceBufferStream::UpdateMaxInterbufferDtsDistance(
721 const BufferQueue& buffers) {
722 DCHECK(!buffers.empty());
723 base::TimeDelta old_distance = max_interbuffer_distance_;
724 DecodeTimestamp prev_dts = last_appended_buffer_decode_timestamp_;
725 for (BufferQueue::const_iterator itr = buffers.begin();
726 itr != buffers.end(); ++itr) {
727 DecodeTimestamp current_dts = (*itr)->GetDecodeTimestamp();
728 DCHECK(current_dts != kNoDecodeTimestamp);
730 base::TimeDelta interbuffer_distance = (*itr)->duration();
731 DCHECK(interbuffer_distance >= base::TimeDelta());
733 if (prev_dts != kNoDecodeTimestamp) {
734 interbuffer_distance =
735 std::max(current_dts - prev_dts, interbuffer_distance);
738 DCHECK(max_interbuffer_distance_ >=
739 base::Milliseconds(kMinimumInterbufferDistanceInMs));
740 max_interbuffer_distance_ =
741 std::max(max_interbuffer_distance_, interbuffer_distance);
742 prev_dts = current_dts;
744 bool changed_max = max_interbuffer_distance_ != old_distance;
745 DVLOG_IF(2, changed_max) << __func__ << " " << GetStreamTypeName()
746 << " Changed max interbuffer DTS distance from "
747 << old_distance.InMicroseconds() << "us to "
748 << max_interbuffer_distance_.InMicroseconds()
753 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) {
754 for (BufferQueue::const_iterator itr = buffers.begin();
755 itr != buffers.end(); ++itr) {
756 (*itr)->SetConfigId(append_config_index_);
760 void SourceBufferStream::OnMemoryPressure(
761 base::TimeDelta media_time,
762 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
763 bool force_instant_gc) {
764 DVLOG(4) << __func__ << " level=" << memory_pressure_level;
765 // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
767 if (memory_pressure_level ==
768 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
772 memory_pressure_level_ = memory_pressure_level;
774 if (force_instant_gc)
775 GarbageCollectIfNeeded(media_time, 0);
778 bool SourceBufferStream::GarbageCollectIfNeeded(base::TimeDelta media_time,
779 size_t newDataSize) {
780 DCHECK(media_time != kNoTimestamp);
781 // Garbage collection should only happen before/during appending new data,
782 // which should not happen in end-of-stream state. Unless we also allow GC to
783 // happen on memory pressure notifications, which might happen even in EOS
785 if (!base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC))
786 DCHECK(!end_of_stream_);
787 // Compute size of |ranges_|.
788 size_t ranges_size = GetBufferedSize();
790 // Sanity and overflow checks
791 if ((newDataSize > memory_limit_) ||
792 (ranges_size + newDataSize < ranges_size)) {
793 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_,
794 kMaxGarbageCollectAlgorithmWarningLogs)
795 << GetStreamTypeName() << " stream: "
796 << "new append of newDataSize=" << newDataSize
797 << " bytes exceeds memory_limit_=" << memory_limit_
798 << ", currently buffered ranges_size=" << ranges_size;
802 size_t effective_memory_limit = memory_limit_;
803 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
804 switch (memory_pressure_level_) {
805 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
806 effective_memory_limit = memory_limit_ / 2;
808 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
809 effective_memory_limit = 0;
811 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
816 // Return if we're under or at the memory limit.
817 if (ranges_size + newDataSize <= effective_memory_limit)
820 size_t bytes_over_hard_memory_limit = 0;
821 if (ranges_size + newDataSize > memory_limit_)
822 bytes_over_hard_memory_limit = ranges_size + newDataSize - memory_limit_;
824 size_t bytes_to_free = ranges_size + newDataSize - effective_memory_limit;
826 DVLOG(2) << __func__ << " " << GetStreamTypeName()
827 << ": Before GC media_time=" << media_time.InMicroseconds()
828 << "us ranges_=" << RangesToString(ranges_)
829 << " seek_pending_=" << seek_pending_
830 << " ranges_size=" << ranges_size << " newDataSize=" << newDataSize
831 << " memory_limit_=" << memory_limit_
832 << " effective_memory_limit=" << effective_memory_limit
833 << " last_appended_buffer_timestamp_="
834 << last_appended_buffer_timestamp_.InMicroseconds()
835 << "us highest_timestamp_in_append_sequence_="
836 << highest_timestamp_in_append_sequence_.InMicroseconds()
837 << "us highest_buffered_end_time_in_append_sequence_="
838 << highest_buffered_end_time_in_append_sequence_.InMicroseconds()
841 if (selected_range_ && !seek_pending_ &&
842 media_time > selected_range_->GetBufferedEndTimestamp()) {
843 // Strictly speaking |media_time| (taken from HTMLMediaElement::currentTime)
844 // should always be in the buffered ranges, but media::Pipeline uses audio
845 // stream as the main time source, when audio is present.
846 // In cases when audio and video streams have different buffered ranges, the
847 // |media_time| value might be slightly outside of the video stream buffered
848 // range. In those cases we need to clamp |media_time| value to the current
849 // stream buffered ranges, to ensure the MSE garbage collection algorithm
850 // works correctly (see crbug.com/563292 for details).
851 base::TimeDelta selected_buffered_end =
852 selected_range_->GetBufferedEndTimestamp();
854 DVLOG(2) << __func__ << " media_time " << media_time.InMicroseconds()
855 << "us is outside of selected_range_=["
856 << selected_range_->GetStartTimestamp().InMicroseconds() << "us;"
857 << selected_buffered_end.InMicroseconds()
858 << "us] clamping media_time to be "
859 << selected_buffered_end.InMicroseconds() << "us";
860 media_time = selected_buffered_end;
863 size_t bytes_freed = 0;
865 // If last appended buffer position was earlier than the current playback time
866 // then try deleting data between last append and current media_time.
867 if (last_appended_buffer_timestamp_ != kNoTimestamp &&
868 last_appended_buffer_duration_ != kNoTimestamp &&
869 highest_buffered_end_time_in_append_sequence_ != kNoTimestamp &&
870 media_time > highest_buffered_end_time_in_append_sequence_) {
871 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
872 DVLOG(3) << __func__ << " FreeBuffersAfterLastAppended "
873 << " released " << between << " bytes"
874 << " ranges_=" << RangesToString(ranges_);
875 bytes_freed += between;
877 // Some players start appending data at the new seek target position before
878 // actually initiating the seek operation (i.e. they try to improve seek
879 // performance by prebuffering some data at the seek target position and
880 // initiating seek once enough data is pre-buffered. In those cases we'll
881 // see that data is being appended at some new position, but there is no
882 // pending seek reported yet. In this situation we need to try preserving
883 // the most recently appended data, i.e. data belonging to the same buffered
884 // range as the most recent append.
885 if (range_for_next_append_ != ranges_.end()) {
886 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
887 media_time = (*range_for_next_append_)->GetStartTimestamp();
888 DVLOG(3) << __func__ << " media_time adjusted to "
889 << media_time.InMicroseconds() << "us";
893 // If there is an unsatisfied pending seek, we can safely remove all data that
894 // is earlier than seek target, then remove from the back until we reach the
895 // most recently appended GOP and then remove from the front if we still don't
896 // have enough space for the upcoming append.
897 if (bytes_freed < bytes_to_free && seek_pending_) {
898 DCHECK(!ranges_.empty());
899 // All data earlier than the seek target |media_time| can be removed safely
900 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
901 DVLOG(3) << __func__ << " Removed " << front
902 << " bytes from the front. ranges_=" << RangesToString(ranges_);
903 bytes_freed += front;
905 // If removing data earlier than |media_time| didn't free up enough space,
906 // then try deleting from the back until we reach most recently appended GOP
907 if (bytes_freed < bytes_to_free) {
908 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
909 DVLOG(3) << __func__ << " Removed " << back
910 << " bytes from the back. ranges_=" << RangesToString(ranges_);
914 // If even that wasn't enough, then try greedily deleting from the front,
915 // that should allow us to remove as much data as necessary to succeed.
916 if (bytes_freed < bytes_to_free) {
917 size_t front2 = FreeBuffers(bytes_to_free - bytes_freed,
918 ranges_.back()->GetEndTimestamp(), false);
919 DVLOG(3) << __func__ << " Removed " << front2
920 << " bytes from the front. ranges_=" << RangesToString(ranges_);
921 bytes_freed += front2;
923 DCHECK(bytes_freed >= bytes_to_free);
926 // Try removing data from the front of the SourceBuffer up to |media_time|
928 if (bytes_freed < bytes_to_free) {
929 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
930 DVLOG(3) << __func__ << " Removed " << front
931 << " bytes from the front. ranges_=" << RangesToString(ranges_);
932 bytes_freed += front;
935 // Try removing data from the back of the SourceBuffer, until we reach the
936 // most recent append position.
937 if (bytes_freed < bytes_to_free) {
938 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
939 DVLOG(3) << __func__ << " Removed " << back
940 << " bytes from the back. ranges_=" << RangesToString(ranges_);
944 DVLOG(2) << __func__ << " " << GetStreamTypeName()
945 << ": After GC bytes_to_free=" << bytes_to_free
946 << " bytes_freed=" << bytes_freed
947 << " bytes_over_hard_memory_limit=" << bytes_over_hard_memory_limit
948 << " ranges_=" << RangesToString(ranges_);
950 return bytes_freed >= bytes_over_hard_memory_limit;
953 size_t SourceBufferStream::FreeBuffersAfterLastAppended(
954 size_t total_bytes_to_free,
955 base::TimeDelta media_time) {
956 DVLOG(4) << __func__ << " highest_buffered_end_time_in_append_sequence_="
957 << highest_buffered_end_time_in_append_sequence_.InMicroseconds()
958 << "us media_time=" << media_time.InMicroseconds() << "us";
960 base::TimeDelta remove_range_start =
961 highest_buffered_end_time_in_append_sequence_;
962 if (last_appended_buffer_is_keyframe_)
963 remove_range_start += GetMaxInterbufferDistance();
965 base::TimeDelta remove_range_start_keyframe =
966 FindKeyframeAfterTimestamp(remove_range_start);
967 if (remove_range_start_keyframe != kNoTimestamp)
968 remove_range_start = remove_range_start_keyframe;
969 if (remove_range_start >= media_time)
972 base::TimeDelta remove_range_end;
973 size_t bytes_freed = GetRemovalRange(remove_range_start,
977 if (bytes_freed > 0) {
978 DVLOG(4) << __func__ << " removing [" << remove_range_start.InMicroseconds()
979 << "us;" << remove_range_end.InMicroseconds() << "us]";
980 Remove(remove_range_start, remove_range_end, media_time);
986 size_t SourceBufferStream::GetRemovalRange(
987 base::TimeDelta start_timestamp,
988 base::TimeDelta end_timestamp,
989 size_t total_bytes_to_free,
990 base::TimeDelta* removal_end_timestamp) {
991 DCHECK(start_timestamp >= base::TimeDelta())
992 << start_timestamp.InMicroseconds() << "us";
993 DCHECK(start_timestamp < end_timestamp)
994 << "start " << start_timestamp.InMicroseconds() << "us, end "
995 << end_timestamp.InMicroseconds() << "us";
997 size_t bytes_freed = 0;
999 for (auto itr = ranges_.begin();
1000 itr != ranges_.end() && bytes_freed < total_bytes_to_free; ++itr) {
1001 SourceBufferRange* range = itr->get();
1002 if (range->GetStartTimestamp() >= end_timestamp)
1004 if (range->GetEndTimestamp() < start_timestamp)
1007 size_t bytes_to_free = total_bytes_to_free - bytes_freed;
1008 size_t bytes_removed = range->GetRemovalGOP(
1009 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp);
1010 bytes_freed += bytes_removed;
1015 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free,
1016 base::TimeDelta media_time,
1017 bool reverse_direction) {
1018 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers",
1019 "total bytes to free", total_bytes_to_free,
1020 "reverse direction", reverse_direction);
1022 DCHECK_GT(total_bytes_to_free, 0u);
1023 size_t bytes_freed = 0;
1025 // This range will save the last GOP appended to |range_for_next_append_|
1026 // if the buffers surrounding it get deleted during garbage collection.
1027 std::unique_ptr<SourceBufferRange> new_range_for_append;
1029 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) {
1030 SourceBufferRange* current_range = NULL;
1031 BufferQueue buffers;
1032 size_t bytes_deleted = 0;
1034 if (reverse_direction) {
1035 current_range = ranges_.back().get();
1036 DVLOG(5) << "current_range=" << RangeToString(*current_range);
1037 if (current_range->LastGOPContainsNextBufferPosition()) {
1038 DCHECK_EQ(current_range, selected_range_);
1039 DVLOG(5) << "current_range contains next read position, stopping GC";
1042 DVLOG(5) << "Deleting GOP from back: " << RangeToString(*current_range);
1043 bytes_deleted = current_range->DeleteGOPFromBack(&buffers);
1045 current_range = ranges_.front().get();
1046 DVLOG(5) << "current_range=" << RangeToString(*current_range);
1048 // FirstGOPEarlierThanMediaTime() is useful here especially if
1049 // |seek_pending_| (such that no range contains next buffer
1051 // FirstGOPContainsNextBufferPosition() is useful here especially if
1052 // |!seek_pending_| to protect against DeleteGOPFromFront() if
1053 // FirstGOPEarlierThanMediaTime() was insufficient alone.
1054 if (!current_range->FirstGOPEarlierThanMediaTime(media_time) ||
1055 current_range->FirstGOPContainsNextBufferPosition()) {
1056 // We have removed all data up to the GOP that contains current playback
1057 // position, we can't delete any further.
1058 DVLOG(5) << "current_range contains playback position, stopping GC";
1061 DVLOG(4) << "Deleting GOP from front: " << RangeToString(*current_range)
1062 << ", media_time: " << media_time.InMicroseconds()
1063 << ", current_range->HasNextBufferPosition(): "
1064 << current_range->HasNextBufferPosition();
1065 bytes_deleted = current_range->DeleteGOPFromFront(&buffers);
1068 // Check to see if we've just deleted the GOP that was last appended.
1069 base::TimeDelta end_timestamp = buffers.back()->timestamp();
1070 if (end_timestamp == last_appended_buffer_timestamp_) {
1071 DCHECK(last_appended_buffer_timestamp_ != kNoTimestamp);
1072 DCHECK(!new_range_for_append);
1074 // Create a new range containing these buffers.
1075 new_range_for_append = std::make_unique<SourceBufferRange>(
1076 TypeToGapPolicy(GetType()), buffers, kNoTimestamp,
1077 base::BindRepeating(&SourceBufferStream::GetMaxInterbufferDistance,
1078 base::Unretained(this)));
1080 range_for_next_append_ = ranges_.end();
1082 bytes_freed += bytes_deleted;
1085 if (current_range->size_in_bytes() == 0) {
1086 DCHECK_NE(current_range, selected_range_);
1087 DCHECK(range_for_next_append_ == ranges_.end() ||
1088 range_for_next_append_->get() != current_range);
1090 // Delete |current_range| by popping it out of |ranges_|.
1091 reverse_direction ? ranges_.pop_back() : ranges_.pop_front();
1094 if (reverse_direction && new_range_for_append) {
1095 // We don't want to delete any further, or we'll be creating gaps
1100 // Insert |new_range_for_append| into |ranges_|, if applicable.
1101 if (new_range_for_append) {
1102 range_for_next_append_ = AddToRanges(std::move(new_range_for_append));
1103 DCHECK(range_for_next_append_ != ranges_.end());
1105 // Check to see if we need to merge the just added range that was in
1106 // |new_range_for_append| with the range before or after it. That added
1107 // range is created whenever the last GOP appended is encountered,
1108 // regardless of whether any buffers after it are ultimately deleted.
1109 // Merging is necessary if there were no buffers (or very few buffers)
1110 // deleted after creating that added range.
1111 if (range_for_next_append_ != ranges_.begin()) {
1112 auto range_before_next = range_for_next_append_;
1113 --range_before_next;
1114 MergeWithNextRangeIfNecessary(range_before_next);
1116 MergeWithNextRangeIfNecessary(range_for_next_append_);
1121 void SourceBufferStream::TrimSpliceOverlap(const BufferQueue& new_buffers) {
1122 DCHECK(!new_buffers.empty());
1123 DCHECK_EQ(SourceBufferStreamType::kAudio, GetType());
1125 const base::TimeDelta splice_timestamp = new_buffers.front()->timestamp();
1127 // Since some audio formats may have nonkeyframes (in PTS order since last
1128 // keyframe), if the front of the new buffers is one of those, it cannot be
1129 // used to begin a decode following an overlap. Here, we bail in this case,
1130 // since such a splice could not be coherently decoded.
1131 if (!new_buffers.front()->is_key_frame()) {
1132 DVLOG(3) << __func__
1133 << " No splice trimming. Front of |new_buffers| is not a "
1134 "keyframe, at time "
1135 << splice_timestamp.InMicroseconds();
1139 // Find the overlapped range (if any).
1140 auto range_itr = FindExistingRangeFor(splice_timestamp);
1141 if (range_itr == ranges_.end()) {
1142 DVLOG(3) << __func__ << " No splice trimming. No range overlap at time "
1143 << splice_timestamp.InMicroseconds();
1147 // Search for overlapped buffer needs exclusive end value. Choosing smallest
1149 const base::TimeDelta end_pts = splice_timestamp + base::Microseconds(1);
1151 // Find if new buffer's start would overlap an existing buffer. Note that
1152 // overlapped audio buffers might be nonkeyframes, but if so, FrameProcessor
1153 // ensures they are in PTS order since the previous keyframe.
1154 BufferQueue overlapped_buffers;
1156 ->GetBuffersInRange(splice_timestamp, end_pts,
1157 &overlapped_buffers)) {
1158 // Bail if no overlapped buffers found.
1159 DVLOG(3) << __func__ << " No splice trimming. No buffer overlap at time "
1160 << splice_timestamp.InMicroseconds();
1164 // At most one buffer should exist containing the time of the newly appended
1165 // buffer's start. It may happen that bad content appends buffers with
1166 // durations that cause nonsensical overlap. Trimming should not be performed
1167 // in these cases, as the content is already in a bad state.
1168 if (overlapped_buffers.size() != 1U) {
1169 DVLOG(3) << __func__
1170 << " No splice trimming. Found more than one overlapped buffer"
1171 " (bad content) at time "
1172 << splice_timestamp.InMicroseconds();
1174 MEDIA_LOG(WARNING, media_log_)
1175 << "Media is badly muxed. Detected " << overlapped_buffers.size()
1176 << " overlapping audio buffers at time "
1177 << splice_timestamp.InMicroseconds();
1180 StreamParserBuffer* overlapped_buffer = overlapped_buffers.front().get();
1182 if (overlapped_buffer->timestamp() == splice_timestamp) {
1183 // Ignore buffers with the same start time. They will be completely removed
1184 // in PrepareRangesForNextAppend().
1185 DVLOG(3) << __func__ << " No splice trimming at time "
1186 << splice_timestamp.InMicroseconds()
1187 << ". Overlapped buffer will be completely removed.";
1191 // Trimming a buffer with estimated duration is too risky. Estimates are rough
1192 // and what appears to be overlap may really just be a bad estimate. Imprecise
1193 // trimming may lead to loss of AV sync.
1194 if (overlapped_buffer->is_duration_estimated()) {
1195 DVLOG(3) << __func__ << " Skipping audio splice trimming at PTS="
1196 << splice_timestamp.InMicroseconds() << ". Overlapped buffer has "
1197 << "estimated duration.";
1201 // Determine the duration of overlap.
1202 base::TimeDelta overlapped_end_time =
1203 overlapped_buffer->timestamp() + overlapped_buffer->duration();
1204 base::TimeDelta overlap_duration = overlapped_end_time - splice_timestamp;
1206 // At this point overlap should be non-empty (ruled out same-timestamp above).
1207 DCHECK_GT(overlap_duration, base::TimeDelta());
1209 // Don't trim for overlaps of less than one millisecond (which is frequently
1210 // the extent of timestamp resolution for poorly encoded media).
1211 if (overlap_duration < base::Milliseconds(1)) {
1212 std::stringstream log_string;
1213 log_string << "Skipping audio splice trimming at PTS="
1214 << splice_timestamp.InMicroseconds() << "us. Found only "
1215 << overlap_duration.InMicroseconds()
1216 << "us of overlap, need at least 1000us. Multiple occurrences "
1217 << "may result in loss of A/V sync.";
1218 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_logs_, kMaxAudioSpliceLogs)
1219 << log_string.str();
1220 DVLOG(1) << __func__ << log_string.str();
1224 // Trim overlap from the existing buffer.
1225 DecoderBuffer::DiscardPadding discard_padding =
1226 overlapped_buffer->discard_padding();
1227 discard_padding.second += overlap_duration;
1228 overlapped_buffer->set_discard_padding(discard_padding);
1229 overlapped_buffer->set_duration(overlapped_buffer->duration() -
1232 // Note that the range's end time tracking shouldn't need explicit updating
1233 // here due to the overlapped buffer's truncation because the range tracks
1234 // that end time using a pointer to the buffer (which should be
1235 // |overlapped_buffer| if the overlap occurred at the end of the range).
1236 // Every audio frame is either a keyframe, or if a nonkeyframe is in PTS order
1237 // since the last keyframe, so there is no out-of-order PTS vs DTS sequencing
1238 // to overcome. If the overlap occurs in the middle of the range, the caller
1239 // invokes methods on the range which internally update the end time(s) of the
1240 // resulting range(s) involved in the append.
1242 std::stringstream log_string;
1243 log_string << "Audio buffer splice at PTS="
1244 << splice_timestamp.InMicroseconds()
1245 << "us. Trimmed tail of overlapped buffer (PTS="
1246 << overlapped_buffer->timestamp().InMicroseconds() << "us) by "
1247 << overlap_duration.InMicroseconds() << "us.";
1248 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_logs_, kMaxAudioSpliceLogs)
1249 << log_string.str();
1250 DVLOG(1) << __func__ << log_string.str();
1253 void SourceBufferStream::PrepareRangesForNextAppend(
1254 const BufferQueue& new_buffers,
1255 BufferQueue* deleted_buffers) {
1256 DCHECK(deleted_buffers);
1258 if (GetType() == SourceBufferStreamType::kAudio)
1259 TrimSpliceOverlap(new_buffers);
1261 base::TimeDelta buffers_start_timestamp = kNoTimestamp;
1262 base::TimeDelta buffers_end_timestamp = kNoTimestamp;
1263 GetTimestampInterval(new_buffers, &buffers_start_timestamp,
1264 &buffers_end_timestamp);
1265 DCHECK(buffers_start_timestamp != kNoTimestamp);
1266 DCHECK(buffers_end_timestamp != kNoTimestamp);
1268 // 1. Clean up the old buffers between the last appended buffers and the
1269 // beginning of |new_buffers|.
1270 if (highest_timestamp_in_append_sequence_ != kNoTimestamp &&
1271 highest_timestamp_in_append_sequence_ < buffers_start_timestamp) {
1272 RemoveInternal(highest_timestamp_in_append_sequence_,
1273 buffers_start_timestamp, true, deleted_buffers);
1276 // 2. Delete the buffers that |new_buffers| overlaps.
1277 // There may be buffers in |new_buffers| with timestamp before
1278 // |highest_timestamp_in_append_sequence_| that shouldn't trigger removal of
1279 // stuff before |highest_timestamp_in_append_sequence_|.
1280 if (highest_timestamp_in_append_sequence_ != kNoTimestamp &&
1281 buffers_start_timestamp < highest_timestamp_in_append_sequence_) {
1282 DCHECK(highest_timestamp_in_append_sequence_ <=
1283 highest_buffered_end_time_in_append_sequence_);
1284 buffers_start_timestamp = highest_buffered_end_time_in_append_sequence_;
1287 if (new_coded_frame_group_) {
1288 // Extend the deletion range earlier to the coded frame group start time if
1289 // this is the first append in a new coded frame group.
1290 DCHECK(coded_frame_group_start_pts_ != kNoTimestamp);
1291 buffers_start_timestamp =
1292 std::min(coded_frame_group_start_pts_, buffers_start_timestamp);
1295 // Return early if no further overlap removal is needed. First check if
1296 // |buffers_start_timestamp| is in the middle of the range; we could be
1297 // overlap-appending the middle of a previous coded frame sequence's range
1298 // with non-keyframes prior to |highest_timestamp_in_append_sequence_|, so we
1299 // need to split that range appropriately here and then return early. If we
1300 // don't return early here, overlap removal (including any necessary range
1301 // splitting) will occur.
1302 if (buffers_start_timestamp >= buffers_end_timestamp) {
1303 DCHECK(highest_timestamp_in_append_sequence_ != kNoTimestamp);
1304 DCHECK(range_for_next_append_ != ranges_.end());
1305 DCHECK((*range_for_next_append_)->BelongsToRange(buffers_start_timestamp));
1307 // Split the range at |buffers_start_timestamp|, if necessary, then return
1309 std::unique_ptr<SourceBufferRange> new_range =
1310 (*range_for_next_append_)->SplitRange(buffers_start_timestamp);
1314 range_for_next_append_ =
1315 ranges_.insert(++range_for_next_append_, std::move(new_range));
1317 // Update the selected range if the next buffer position was transferred
1318 // to the newly inserted range.
1319 if ((*range_for_next_append_)->HasNextBufferPosition())
1320 SetSelectedRange(range_for_next_append_->get());
1322 --range_for_next_append_;
1326 // Exclude the start from removal to avoid deleting the highest appended
1327 // buffer in cases where the first buffer in |new_buffers| has same timestamp
1328 // as the highest appended buffer (even in out-of-order DTS vs PTS sequence).
1329 // Only do this when :
1330 // A. Type is video. This may occur in cases of VP9 alt-ref frames or frames
1331 // with incorrect timestamps. Removing a frame may break decode
1332 // dependencies and there are no downsides to just keeping it (other than
1333 // some throw-away decoder work).
1334 // B. Type is text. TODO(chcunningham): Implement text splicing. See
1335 // http://crbug.com/661408
1336 // C. Type is audio and overlapped duration is 0. We've encountered Vorbis
1337 // streams containing zero-duration buffers (i.e. no real overlap). For
1338 // non-zero duration removing overlapped frames is important to preserve
1339 // A/V sync (see AudioClock).
1340 const bool exclude_start =
1341 highest_timestamp_in_append_sequence_ ==
1342 new_buffers.front()->timestamp() &&
1343 (GetType() == SourceBufferStreamType::kVideo ||
1344 GetType() == SourceBufferStreamType::kText ||
1345 last_appended_buffer_duration_ == base::TimeDelta());
1347 // Finally do the deletion of overlap.
1348 RemoveInternal(buffers_start_timestamp, buffers_end_timestamp, exclude_start,
1353 void SourceBufferStream::GetTimestampInterval(const BufferQueue& buffers,
1354 base::TimeDelta* start,
1355 base::TimeDelta* end) {
1356 base::TimeDelta start_pts = buffers.front()->timestamp();
1357 base::TimeDelta end_pts = start_pts;
1359 for (const auto& buffer : buffers) {
1360 base::TimeDelta timestamp = buffer->timestamp();
1361 start_pts = std::min(timestamp, start_pts);
1362 base::TimeDelta duration = buffer->duration();
1364 // FrameProcessor should protect against unknown buffer durations.
1365 DCHECK_NE(duration, kNoTimestamp);
1367 if (duration.is_positive() && !buffer->is_duration_estimated()) {
1368 timestamp += duration;
1370 // TODO(chcunningham): Emit warning when 0ms durations are not expected.
1371 // http://crbug.com/312836
1372 timestamp += base::Microseconds(1);
1374 end_pts = std::max(timestamp, end_pts);
1380 bool SourceBufferStream::IsNextGopAdjacentToEndOfCurrentAppendSequence(
1381 base::TimeDelta next_gop_timestamp) const {
1382 base::TimeDelta upper_bound = highest_timestamp_in_append_sequence_ +
1383 ComputeFudgeRoom(GetMaxInterbufferDistance());
1384 DVLOG(4) << __func__ << " " << GetStreamTypeName()
1385 << " next_gop_timestamp=" << next_gop_timestamp.InMicroseconds()
1386 << "us, highest_timestamp_in_append_sequence_="
1387 << highest_timestamp_in_append_sequence_.InMicroseconds()
1388 << "us, upper_bound=" << upper_bound.InMicroseconds() << "us";
1389 return highest_timestamp_in_append_sequence_ < next_gop_timestamp &&
1390 next_gop_timestamp <= upper_bound;
1393 void SourceBufferStream::PruneTrackBuffer(const base::TimeDelta timestamp) {
1394 DCHECK(timestamp != kNoTimestamp);
1396 // Scan forward until we find a buffer with timestamp at or beyond the limit.
1397 // Then remove all those at and beyond that point.
1398 size_t goal_size = 0; // The number of buffers we will keep in the result.
1399 for (const auto& buf : track_buffer_) {
1400 if (buf->timestamp() >= timestamp)
1405 while (track_buffer_.size() > goal_size) {
1406 track_buffer_.pop_back();
1409 DVLOG(3) << __func__ << " " << GetStreamTypeName()
1410 << " Removed all buffers in track buffer sequence starting with the "
1411 "first at timestamp >= "
1412 << timestamp.InMicroseconds()
1413 << "us. New track buffer size:" << track_buffer_.size();
1416 void SourceBufferStream::MergeWithNextRangeIfNecessary(
1417 const RangeList::iterator& range_with_new_buffers_itr) {
1418 DCHECK(range_with_new_buffers_itr != ranges_.end());
1420 SourceBufferRange* range_with_new_buffers = range_with_new_buffers_itr->get();
1421 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
1424 if (next_range_itr == ranges_.end() ||
1425 !range_with_new_buffers->CanAppendRangeToEnd(**next_range_itr)) {
1429 bool transfer_current_position = selected_range_ == next_range_itr->get();
1430 DVLOG(3) << __func__ << " " << GetStreamTypeName() << " merging "
1431 << RangeToString(*range_with_new_buffers) << " into "
1432 << RangeToString(**next_range_itr);
1433 range_with_new_buffers->AppendRangeToEnd(**next_range_itr,
1434 transfer_current_position);
1435 // Update |selected_range_| pointer if |range| has become selected after
1437 if (transfer_current_position)
1438 SetSelectedRange(range_with_new_buffers);
1440 if (next_range_itr == range_for_next_append_)
1441 range_for_next_append_ = range_with_new_buffers_itr;
1443 DeleteAndRemoveRange(&next_range_itr);
1446 void SourceBufferStream::MergeAllAdjacentRanges() {
1447 DVLOG(1) << __func__ << " " << GetStreamTypeName()
1448 << ": Before: ranges_=" << RangesToString(ranges_);
1450 auto range_itr = ranges_.begin();
1452 while (range_itr != ranges_.end()) {
1453 const size_t old_ranges_size = ranges_.size();
1454 MergeWithNextRangeIfNecessary(range_itr);
1456 // Only proceed to the next range if the current range didn't merge with it.
1457 if (old_ranges_size == ranges_.size())
1461 DVLOG(1) << __func__ << " " << GetStreamTypeName()
1462 << ": After: ranges_=" << RangesToString(ranges_);
1465 void SourceBufferStream::Seek(base::TimeDelta timestamp) {
1466 DCHECK(timestamp >= base::TimeDelta());
1467 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
1468 << timestamp.InMicroseconds() << "us)";
1471 seek_buffer_timestamp_ = timestamp;
1472 seek_pending_ = true;
1474 if (ShouldSeekToStartOfBuffered(timestamp)) {
1475 ranges_.front()->SeekToStart();
1476 SetSelectedRange(ranges_.front().get());
1477 seek_pending_ = false;
1481 auto itr = ranges_.end();
1482 for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1483 if ((*itr)->CanSeekTo(timestamp))
1487 if (itr == ranges_.end())
1490 if (!audio_configs_.empty()) {
1491 // Adjust |timestamp| for an Opus stream backward up to the config's seek
1492 // preroll, but not further than the range start time, and not at all if
1493 // there is a config change in the middle of that preroll interval. If
1494 // |timestamp| is already before the range start time, as can happen due to
1495 // fudge room, do not adjust it.
1496 const auto& config = audio_configs_[(*itr)->GetConfigIdAtTime(timestamp)];
1497 if (config.codec() == AudioCodec::kOpus &&
1498 timestamp > (*itr)->GetStartTimestamp()) {
1499 base::TimeDelta preroll_timestamp = std::max(
1500 timestamp - config.seek_preroll(), (*itr)->GetStartTimestamp());
1501 if ((*itr)->CanSeekTo(preroll_timestamp) &&
1502 (*itr)->SameConfigThruRange(preroll_timestamp, timestamp)) {
1503 timestamp = preroll_timestamp;
1508 SeekAndSetSelectedRange(itr->get(), timestamp);
1509 seek_pending_ = false;
1512 bool SourceBufferStream::IsSeekPending() const {
1513 return seek_pending_ && !IsEndOfStreamReached();
1516 // TODO(wolenetz): Disallow duration changes that truncate buffered media. See
1517 // https://crbug.com/623729.
1518 void SourceBufferStream::OnSetDuration(base::TimeDelta duration) {
1519 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
1520 << duration.InMicroseconds() << "us)";
1521 DCHECK(!end_of_stream_);
1523 if (ranges_.empty())
1526 base::TimeDelta start = duration;
1527 base::TimeDelta end = ranges_.back()->GetBufferedEndTimestamp();
1529 // Trim the end if it exceeds the new duration.
1531 BufferQueue deleted_buffers;
1532 RemoveInternal(start, end, false, &deleted_buffers);
1534 if (!deleted_buffers.empty()) {
1535 // Truncation removed current position. Clear selected range.
1536 SetSelectedRange(NULL);
1541 SourceBufferStreamStatus SourceBufferStream::GetNextBuffer(
1542 scoped_refptr<StreamParserBuffer>* out_buffer) {
1543 DVLOG(2) << __func__ << " " << GetStreamTypeName();
1544 if (!pending_buffer_.get()) {
1545 const SourceBufferStreamStatus status = GetNextBufferInternal(out_buffer);
1546 if (status != SourceBufferStreamStatus::kSuccess ||
1547 !SetPendingBuffer(out_buffer)) {
1548 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1549 << ": no pending buffer, returning status "
1550 << StatusToString(status);
1555 DCHECK(pending_buffer_->preroll_buffer().get());
1557 const SourceBufferStreamStatus status =
1558 HandleNextBufferWithPreroll(out_buffer);
1559 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1560 << ": handled next buffer with preroll, returning status "
1561 << StatusToString(status);
1565 SourceBufferStreamStatus SourceBufferStream::HandleNextBufferWithPreroll(
1566 scoped_refptr<StreamParserBuffer>* out_buffer) {
1567 // Any config change should have already been handled.
1568 DCHECK_EQ(current_config_index_, pending_buffer_->GetConfigId());
1570 // Check if the preroll buffer has already been handed out.
1571 if (!pending_buffers_complete_) {
1572 pending_buffers_complete_ = true;
1573 *out_buffer = pending_buffer_->preroll_buffer();
1574 return SourceBufferStreamStatus::kSuccess;
1577 // Preroll complete, hand out the final buffer.
1578 *out_buffer = std::move(pending_buffer_);
1579 return SourceBufferStreamStatus::kSuccess;
1582 SourceBufferStreamStatus SourceBufferStream::GetNextBufferInternal(
1583 scoped_refptr<StreamParserBuffer>* out_buffer) {
1584 CHECK(!config_change_pending_);
1586 if (!track_buffer_.empty()) {
1587 DCHECK(!selected_range_);
1589 if (track_buffer_.front()->GetConfigId() != current_config_index_) {
1590 config_change_pending_ = true;
1591 DVLOG(1) << "Config change (track buffer config ID does not match).";
1592 return SourceBufferStreamStatus::kConfigChange;
1595 DVLOG(3) << __func__ << " Next buffer coming from track_buffer_";
1596 *out_buffer = std::move(track_buffer_.front());
1597 track_buffer_.pop_front();
1598 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer);
1599 highest_output_buffer_timestamp_ =
1600 std::max(highest_output_buffer_timestamp_, (*out_buffer)->timestamp());
1602 // If the track buffer becomes empty, then try to set the selected range
1603 // based on the timestamp of this buffer being returned.
1604 if (track_buffer_.empty()) {
1605 just_exhausted_track_buffer_ = true;
1606 SetSelectedRangeIfNeeded(highest_output_buffer_timestamp_);
1609 return SourceBufferStreamStatus::kSuccess;
1612 DCHECK(track_buffer_.empty());
1613 if (!selected_range_ || !selected_range_->HasNextBuffer()) {
1614 if (IsEndOfStreamReached()) {
1615 return SourceBufferStreamStatus::kEndOfStream;
1617 DVLOG(3) << __func__ << " " << GetStreamTypeName()
1618 << ": returning kNeedBuffer "
1619 << (selected_range_ ? "(selected range has no next buffer)"
1620 : "(no selected range)");
1621 return SourceBufferStreamStatus::kNeedBuffer;
1624 if (selected_range_->GetNextConfigId() != current_config_index_) {
1625 config_change_pending_ = true;
1626 DVLOG(1) << "Config change (selected range config ID does not match).";
1627 return SourceBufferStreamStatus::kConfigChange;
1630 CHECK(selected_range_->GetNextBuffer(out_buffer));
1631 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer);
1632 highest_output_buffer_timestamp_ =
1633 std::max(highest_output_buffer_timestamp_, (*out_buffer)->timestamp());
1634 return SourceBufferStreamStatus::kSuccess;
1637 void SourceBufferStream::WarnIfTrackBufferExhaustionSkipsForward(
1638 scoped_refptr<StreamParserBuffer> next_buffer) {
1639 if (!just_exhausted_track_buffer_)
1642 just_exhausted_track_buffer_ = false;
1643 DCHECK(next_buffer->is_key_frame());
1644 base::TimeDelta next_output_buffer_timestamp = next_buffer->timestamp();
1645 base::TimeDelta delta =
1646 next_output_buffer_timestamp - highest_output_buffer_timestamp_;
1647 if (delta > GetMaxInterbufferDistance()) {
1648 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_track_buffer_gap_warning_logs_,
1649 kMaxTrackBufferGapWarningLogs)
1650 << "Media append that overlapped current playback position may cause "
1651 "time gap in playing "
1652 << GetStreamTypeName() << " stream because the next keyframe is "
1653 << delta.InMilliseconds()
1654 << "ms beyond last overlapped frame. Media may appear temporarily "
1659 bool SourceBufferStream::IsNextBufferConfigChanged() {
1660 if (!track_buffer_.empty())
1661 return track_buffer_.front()->GetConfigId() != current_config_index_;
1663 if (!selected_range_ || !selected_range_->HasNextBuffer())
1666 return selected_range_->GetNextConfigId() != current_config_index_;
1669 base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() {
1670 if (!track_buffer_.empty())
1671 return track_buffer_.front()->timestamp();
1673 if (!selected_range_)
1674 return kNoTimestamp;
1676 DCHECK(selected_range_->HasNextBufferPosition());
1677 return selected_range_->GetNextTimestamp();
1680 SourceBufferStream::RangeList::iterator
1681 SourceBufferStream::FindExistingRangeFor(base::TimeDelta start_timestamp) {
1682 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1683 if ((*itr)->BelongsToRange(start_timestamp))
1686 return ranges_.end();
1689 SourceBufferStream::RangeList::iterator SourceBufferStream::AddToRanges(
1690 std::unique_ptr<SourceBufferRange> new_range) {
1691 base::TimeDelta start_timestamp = new_range->GetStartTimestamp();
1692 auto itr = ranges_.end();
1693 for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1694 if ((*itr)->GetStartTimestamp() > start_timestamp)
1697 return ranges_.insert(itr, std::move(new_range));
1700 void SourceBufferStream::SeekAndSetSelectedRange(
1701 SourceBufferRange* range,
1702 base::TimeDelta seek_timestamp) {
1704 range->Seek(seek_timestamp);
1705 SetSelectedRange(range);
1708 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) {
1709 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": " << selected_range_
1710 << " " << (selected_range_ ? RangeToString(*selected_range_) : "")
1711 << " -> " << range << " " << (range ? RangeToString(*range) : "");
1712 if (selected_range_)
1713 selected_range_->ResetNextBufferPosition();
1714 DCHECK(!range || range->HasNextBufferPosition());
1715 selected_range_ = range;
1718 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const {
1719 Ranges<base::TimeDelta> ranges;
1720 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1721 ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetBufferedEndTimestamp());
1726 base::TimeDelta SourceBufferStream::GetHighestPresentationTimestamp() const {
1727 if (ranges_.empty())
1728 return base::TimeDelta();
1730 return ranges_.back()->GetEndTimestamp();
1733 base::TimeDelta SourceBufferStream::GetBufferedDuration() const {
1734 if (ranges_.empty())
1735 return base::TimeDelta();
1737 return ranges_.back()->GetBufferedEndTimestamp();
1740 size_t SourceBufferStream::GetBufferedSize() const {
1741 size_t ranges_size = 0;
1742 for (const auto& range_ptr : ranges_)
1743 ranges_size += range_ptr->size_in_bytes();
1747 void SourceBufferStream::MarkEndOfStream() {
1748 DCHECK(!end_of_stream_);
1749 end_of_stream_ = true;
1752 void SourceBufferStream::UnmarkEndOfStream() {
1753 DCHECK(end_of_stream_);
1754 end_of_stream_ = false;
1757 bool SourceBufferStream::IsEndOfStreamReached() const {
1758 if (!end_of_stream_ || !track_buffer_.empty())
1761 if (ranges_.empty())
1764 if (seek_pending_) {
1765 base::TimeDelta last_range_end_time =
1766 ranges_.back()->GetBufferedEndTimestamp();
1767 return seek_buffer_timestamp_ >= last_range_end_time;
1770 if (!selected_range_)
1773 return selected_range_ == ranges_.back().get();
1776 const AudioDecoderConfig& SourceBufferStream::GetCurrentAudioDecoderConfig() {
1777 if (config_change_pending_)
1778 CompleteConfigChange();
1779 // Trying to track down crash. http://crbug.com/715761
1780 CHECK(current_config_index_ >= 0 &&
1781 static_cast<size_t>(current_config_index_) < audio_configs_.size());
1782 return audio_configs_[current_config_index_];
1785 const VideoDecoderConfig& SourceBufferStream::GetCurrentVideoDecoderConfig() {
1786 if (config_change_pending_)
1787 CompleteConfigChange();
1788 // Trying to track down crash. http://crbug.com/715761
1789 CHECK(current_config_index_ >= 0 &&
1790 static_cast<size_t>(current_config_index_) < video_configs_.size());
1791 return video_configs_[current_config_index_];
1794 const TextTrackConfig& SourceBufferStream::GetCurrentTextTrackConfig() {
1795 return text_track_config_;
1798 base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const {
1799 return max_interbuffer_distance_;
1802 bool SourceBufferStream::UpdateAudioConfig(const AudioDecoderConfig& config,
1803 bool allow_codec_change) {
1804 DCHECK(!audio_configs_.empty());
1805 DCHECK(video_configs_.empty());
1806 DVLOG(3) << "UpdateAudioConfig.";
1808 if (!allow_codec_change &&
1809 audio_configs_[append_config_index_].codec() != config.codec()) {
1810 // TODO(wolenetz): When we relax addSourceBuffer() and changeType() codec
1811 // strictness, codec changes should be allowed even without changing the
1813 // TODO(wolenetz): Remove "experimental" from this error message when
1814 // changeType() ships without needing experimental blink flag.
1815 MEDIA_LOG(ERROR, media_log_) << "Audio codec changes not allowed unless "
1816 "using experimental changeType().";
1820 // Check to see if the new config matches an existing one.
1821 for (size_t i = 0; i < audio_configs_.size(); ++i) {
1822 if (config.Matches(audio_configs_[i])) {
1823 append_config_index_ = i;
1828 // No matches found so let's add this one to the list.
1829 append_config_index_ = audio_configs_.size();
1830 DVLOG(2) << "New audio config - index: " << append_config_index_;
1831 audio_configs_.resize(audio_configs_.size() + 1);
1832 audio_configs_[append_config_index_] = config;
1836 bool SourceBufferStream::UpdateVideoConfig(const VideoDecoderConfig& config,
1837 bool allow_codec_change) {
1838 DCHECK(!video_configs_.empty());
1839 DCHECK(audio_configs_.empty());
1840 DVLOG(3) << "UpdateVideoConfig.";
1842 if (!allow_codec_change &&
1843 video_configs_[append_config_index_].codec() != config.codec()) {
1844 // TODO(wolenetz): When we relax addSourceBuffer() and changeType() codec
1845 // strictness, codec changes should be allowed even without changing the
1847 // TODO(wolenetz): Remove "experimental" from this error message when
1848 // changeType() ships without needing experimental blink flag.
1849 MEDIA_LOG(ERROR, media_log_) << "Video codec changes not allowed unless "
1850 "using experimental changeType()";
1854 // Check to see if the new config matches an existing one.
1855 for (size_t i = 0; i < video_configs_.size(); ++i) {
1856 if (config.Matches(video_configs_[i])) {
1857 append_config_index_ = i;
1862 // No matches found so let's add this one to the list.
1863 append_config_index_ = video_configs_.size();
1864 DVLOG(2) << "New video config - index: " << append_config_index_;
1865 video_configs_.resize(video_configs_.size() + 1);
1866 video_configs_[append_config_index_] = config;
1870 void SourceBufferStream::CompleteConfigChange() {
1871 config_change_pending_ = false;
1873 if (!track_buffer_.empty()) {
1874 current_config_index_ = track_buffer_.front()->GetConfigId();
1878 if (selected_range_ && selected_range_->HasNextBuffer())
1879 current_config_index_ = selected_range_->GetNextConfigId();
1882 void SourceBufferStream::SetSelectedRangeIfNeeded(
1883 const base::TimeDelta timestamp) {
1884 DVLOG(2) << __func__ << " " << GetStreamTypeName() << "("
1885 << timestamp.InMicroseconds() << "us)";
1887 if (selected_range_) {
1888 DCHECK(track_buffer_.empty());
1892 if (!track_buffer_.empty()) {
1893 DCHECK(!selected_range_);
1897 base::TimeDelta start_timestamp = timestamp;
1899 // If the next buffer timestamp is not known then use a timestamp just after
1900 // the timestamp on the last buffer returned by GetNextBuffer().
1901 if (start_timestamp == kNoTimestamp) {
1902 if (highest_output_buffer_timestamp_ == kNoTimestamp) {
1903 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1904 << " no previous output timestamp";
1908 start_timestamp = highest_output_buffer_timestamp_ + base::Microseconds(1);
1911 base::TimeDelta seek_timestamp =
1912 FindNewSelectedRangeSeekTimestamp(start_timestamp);
1914 // If we don't have buffered data to seek to, then return.
1915 if (seek_timestamp == kNoTimestamp) {
1916 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1917 << " couldn't find new selected range seek timestamp";
1921 DCHECK(track_buffer_.empty());
1922 SeekAndSetSelectedRange(FindExistingRangeFor(seek_timestamp)->get(),
1926 base::TimeDelta SourceBufferStream::FindNewSelectedRangeSeekTimestamp(
1927 const base::TimeDelta start_timestamp) {
1928 DCHECK(start_timestamp != kNoTimestamp);
1929 DCHECK(start_timestamp >= base::TimeDelta());
1931 auto itr = ranges_.begin();
1933 // When checking a range to see if it has or begins soon enough after
1934 // |start_timestamp|, use the fudge room to determine "soon enough".
1935 base::TimeDelta start_timestamp_plus_fudge =
1936 start_timestamp + ComputeFudgeRoom(GetMaxInterbufferDistance());
1938 // Multiple ranges could be within the fudge room, because the fudge room is
1939 // dynamic based on max inter-buffer distance seen so far. Optimistically
1940 // check the earliest ones first.
1941 for (; itr != ranges_.end(); ++itr) {
1942 base::TimeDelta range_start = (*itr)->GetStartTimestamp();
1943 if (range_start >= start_timestamp_plus_fudge)
1945 if ((*itr)->GetEndTimestamp() < start_timestamp)
1947 base::TimeDelta search_timestamp = start_timestamp;
1948 if (start_timestamp < range_start &&
1949 start_timestamp_plus_fudge >= range_start) {
1950 search_timestamp = range_start;
1952 base::TimeDelta keyframe_timestamp =
1953 (*itr)->NextKeyframeTimestamp(search_timestamp);
1954 if (keyframe_timestamp != kNoTimestamp)
1955 return keyframe_timestamp;
1958 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1959 << " no buffered data for pts=" << start_timestamp.InMicroseconds()
1961 return kNoTimestamp;
1964 base::TimeDelta SourceBufferStream::FindKeyframeAfterTimestamp(
1965 const base::TimeDelta timestamp) {
1966 DCHECK(timestamp != kNoTimestamp);
1968 auto itr = FindExistingRangeFor(timestamp);
1970 if (itr == ranges_.end())
1971 return kNoTimestamp;
1973 // First check for a keyframe timestamp >= |timestamp|
1974 // in the current range.
1975 return (*itr)->NextKeyframeTimestamp(timestamp);
1978 std::string SourceBufferStream::GetStreamTypeName() const {
1979 switch (GetType()) {
1980 case SourceBufferStreamType::kAudio:
1982 case SourceBufferStreamType::kVideo:
1984 case SourceBufferStreamType::kText:
1991 SourceBufferStreamType SourceBufferStream::GetType() const {
1992 if (!audio_configs_.empty())
1993 return SourceBufferStreamType::kAudio;
1994 if (!video_configs_.empty())
1995 return SourceBufferStreamType::kVideo;
1996 DCHECK_NE(text_track_config_.kind(), kTextNone);
1997 return SourceBufferStreamType::kText;
2000 void SourceBufferStream::DeleteAndRemoveRange(RangeList::iterator* itr) {
2001 DVLOG(1) << __func__;
2003 DCHECK(*itr != ranges_.end());
2004 if ((*itr)->get() == selected_range_) {
2005 DVLOG(1) << __func__ << " deleting selected range.";
2006 SetSelectedRange(NULL);
2009 if (*itr == range_for_next_append_) {
2010 DVLOG(1) << __func__ << " deleting range_for_next_append_.";
2011 range_for_next_append_ = ranges_.end();
2012 ResetLastAppendedState();
2015 *itr = ranges_.erase(*itr);
2018 bool SourceBufferStream::SetPendingBuffer(
2019 scoped_refptr<StreamParserBuffer>* out_buffer) {
2020 DCHECK(out_buffer->get());
2021 DCHECK(!pending_buffer_.get());
2023 const bool have_preroll_buffer = !!(*out_buffer)->preroll_buffer().get();
2025 if (!have_preroll_buffer)
2028 pending_buffer_.swap(*out_buffer);
2029 pending_buffers_complete_ = false;
2033 } // namespace media