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/functional/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";
83 NOTREACHED_NORETURN();
86 // Helper method for logging, converts a range into a readable string.
87 std::string RangeToString(const SourceBufferRange& range) {
88 if (range.size_in_bytes() == 0) {
92 ss << "[" << range.GetStartTimestamp().InMicroseconds() << "us;"
93 << range.GetEndTimestamp().InMicroseconds() << "us("
94 << range.GetBufferedEndTimestamp().InMicroseconds() << "us)]";
98 // Helper method for logging, converts a set of ranges into a readable string.
99 std::string RangesToString(const SourceBufferStream::RangeList& ranges) {
103 std::stringstream ss;
104 for (const auto& range_ptr : ranges) {
105 if (range_ptr != ranges.front())
107 ss << RangeToString(*range_ptr);
112 std::string BufferQueueBuffersToLogString(
113 const SourceBufferStream::BufferQueue& buffers) {
114 std::stringstream result;
116 result << "Buffers:\n";
117 for (const auto& buf : buffers) {
118 result << "\tdts=" << buf->GetDecodeTimestamp().InMicroseconds() << " "
119 << buf->AsHumanReadableString()
120 << ", is_duration_estimated=" << buf->is_duration_estimated()
127 std::string BufferQueueMetadataToLogString(
128 const SourceBufferStream::BufferQueue& buffers) {
129 std::stringstream result;
130 base::TimeDelta pts_interval_start;
131 base::TimeDelta pts_interval_end;
132 SourceBufferStream::GetTimestampInterval(buffers, &pts_interval_start,
135 result << "dts=[" << buffers.front()->GetDecodeTimestamp().InMicroseconds()
136 << "us;" << buffers.back()->GetDecodeTimestamp().InMicroseconds()
137 << "us(last frame dur=" << buffers.back()->duration().InMicroseconds()
138 << "us)], pts interval=[" << pts_interval_start.InMicroseconds()
139 << "us," << pts_interval_end.InMicroseconds() << "us)";
145 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
147 : media_log_(media_log),
148 seek_buffer_timestamp_(kNoTimestamp),
149 coded_frame_group_start_pts_(kNoTimestamp),
150 range_for_next_append_(ranges_.end()),
151 highest_output_buffer_timestamp_(kNoTimestamp),
152 max_interbuffer_distance_(
153 base::Milliseconds(kMinimumInterbufferDistanceInMs)),
154 memory_limit_(GetDemuxerStreamAudioMemoryLimit(&audio_config)) {
155 DCHECK(audio_config.IsValidConfig());
156 audio_configs_.push_back(audio_config);
157 DVLOG(2) << __func__ << ": audio_buffer_size= " << memory_limit_;
160 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
162 : media_log_(media_log),
163 seek_buffer_timestamp_(kNoTimestamp),
164 coded_frame_group_start_pts_(kNoTimestamp),
165 range_for_next_append_(ranges_.end()),
166 highest_output_buffer_timestamp_(kNoTimestamp),
167 max_interbuffer_distance_(
168 base::Milliseconds(kMinimumInterbufferDistanceInMs)),
170 GetDemuxerStreamVideoMemoryLimit(Demuxer::DemuxerTypes::kChunkDemuxer,
172 DCHECK(video_config.IsValidConfig());
173 video_configs_.push_back(video_config);
174 DVLOG(2) << __func__ << ": video_buffer_size= " << memory_limit_;
177 SourceBufferStream::~SourceBufferStream() = default;
179 void SourceBufferStream::OnStartOfCodedFrameGroup(
180 base::TimeDelta coded_frame_group_start_pts) {
181 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " (pts "
182 << coded_frame_group_start_pts.InMicroseconds() << "us)";
183 DCHECK(!end_of_stream_);
184 coded_frame_group_start_pts_ = coded_frame_group_start_pts;
185 new_coded_frame_group_ = true;
187 auto last_range = range_for_next_append_;
188 range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_pts_);
190 // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
191 // is not adjacent to the previous coded frame group appended to the stream.
192 if (range_for_next_append_ == ranges_.end() ||
193 !IsNextGopAdjacentToEndOfCurrentAppendSequence(
194 coded_frame_group_start_pts_)) {
195 ResetLastAppendedState();
196 DVLOG(3) << __func__ << " next appended buffers will "
197 << (range_for_next_append_ == ranges_.end()
198 ? "be in a new range"
199 : "overlap an existing range");
201 if (range_for_next_append_ != ranges_.end()) {
202 // If this new coded frame group overlaps an existing range, preserve
203 // continuity from that range to the new group by moving the start time
204 // earlier (but not at or beyond the most recent buffered frame's time
205 // before |coded_frame_group_start_pts_| in the range, and not beyond the
206 // range's start time. This update helps prevent discontinuity from being
207 // introduced by the ::RemoveInternal processing during the next ::Append
209 base::TimeDelta adjusted_start_time =
210 (*range_for_next_append_)
211 ->FindHighestBufferedTimestampAtOrBefore(
212 coded_frame_group_start_pts_);
213 if (adjusted_start_time < coded_frame_group_start_pts_) {
214 // Exclude removal of that earlier frame during later Append
215 // processing by adjusting the removal range slightly forward.
216 coded_frame_group_start_pts_ =
217 adjusted_start_time + base::Microseconds(1);
220 } else if (last_range != ranges_.end()) {
221 DCHECK(last_range == range_for_next_append_);
222 DVLOG(3) << __func__ << " next appended buffers will continue range unless "
223 << "intervening remove makes discontinuity";
227 void SourceBufferStream::Append(const BufferQueue& buffers) {
228 TRACE_EVENT2("media", "SourceBufferStream::Append",
229 "stream type", GetStreamTypeName(),
230 "buffers to append", buffers.size());
232 DCHECK(!buffers.empty());
233 DCHECK(coded_frame_group_start_pts_ != kNoTimestamp);
234 DCHECK(!end_of_stream_);
236 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": buffers "
237 << BufferQueueMetadataToLogString(buffers);
238 DVLOG(4) << BufferQueueBuffersToLogString(buffers);
240 DCHECK(!buffers.front()->is_key_frame() ||
241 coded_frame_group_start_pts_ <= buffers.front()->timestamp());
242 DVLOG_IF(2, coded_frame_group_start_pts_ > buffers.front()->timestamp())
244 << " Suspected SAP-Type-2 occurrence: coded_frame_group_start_pts_="
245 << coded_frame_group_start_pts_.InMicroseconds()
246 << "us, first new buffer has timestamp="
247 << buffers.front()->timestamp().InMicroseconds() << "us";
249 // New coded frame groups emitted by the coded frame processor must begin with
250 // a keyframe. Avoid propagating with escalating impact if this assumption is
252 CHECK(!new_coded_frame_group_ || buffers.front()->is_key_frame());
254 // Buffers within each GOP in a coded frame group must be monotonically
255 // increasing in DTS order.
256 DCHECK(IsDtsMonotonicallyIncreasing(buffers));
258 // Both of these checks enforce what should be guaranteed by how
259 // FrameProcessor signals OnStartOfCodedFrameGroup and the buffers it tells us
261 DCHECK(coded_frame_group_start_pts_ >= base::TimeDelta());
262 DCHECK(buffers.front()->timestamp() >= base::TimeDelta());
264 if (UpdateMaxInterbufferDtsDistance(buffers)) {
265 // Coalesce |ranges_| using the new fudge room. This helps keep |ranges_|
266 // sorted in complex scenarios. See https://crbug.com/793247.
267 MergeAllAdjacentRanges();
270 SetConfigIds(buffers);
272 // Save a snapshot of stream state before range modifications are made.
273 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
274 BufferQueue deleted_buffers;
276 PrepareRangesForNextAppend(buffers, &deleted_buffers);
278 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
279 // create a new range with |buffers|.
280 if (range_for_next_append_ != ranges_.end()) {
281 if (new_coded_frame_group_) {
282 // If the first append to this stream in a new coded frame group continues
283 // a previous range, use the new group's start time instead of the first
284 // new buffer's timestamp as the proof of adjacency to the existing range.
285 // A large gap (larger than our normal buffer adjacency test) can occur in
286 // a muxed set of streams (which share a common coded frame group start
287 // time) with a significantly jagged start across the streams.
288 (*range_for_next_append_)
289 ->AppendBuffersToEnd(buffers, coded_frame_group_start_pts_);
291 // Otherwise, use the first new buffer as proof of adjacency.
292 (*range_for_next_append_)->AppendBuffersToEnd(buffers, kNoTimestamp);
295 last_appended_buffer_timestamp_ = buffers.back()->timestamp();
296 last_appended_buffer_duration_ = buffers.back()->duration();
297 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
298 last_appended_buffer_decode_timestamp_ =
299 buffers.back()->GetDecodeTimestamp();
300 highest_timestamp_in_append_sequence_ =
301 (*range_for_next_append_)->GetEndTimestamp();
302 highest_buffered_end_time_in_append_sequence_ =
303 (*range_for_next_append_)->GetBufferedEndTimestamp();
305 base::TimeDelta new_range_start_time =
306 std::min(coded_frame_group_start_pts_, buffers.front()->timestamp());
308 const BufferQueue* buffers_for_new_range = &buffers;
309 BufferQueue trimmed_buffers;
311 // If the new range is not being created because of a new coded frame group,
312 // then we must make sure that we start with a key frame. This can happen
313 // if the GOP in the previous append gets destroyed by a Remove() call.
314 if (!new_coded_frame_group_) {
315 BufferQueue::const_iterator itr = buffers.begin();
317 // Scan past all the non-key-frames.
318 while (itr != buffers.end() && !(*itr)->is_key_frame()) {
322 // If we didn't find a key frame, then update the last appended
323 // buffer state and return.
324 if (itr == buffers.end()) {
325 last_appended_buffer_timestamp_ = buffers.back()->timestamp();
326 last_appended_buffer_duration_ = buffers.back()->duration();
327 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
328 last_appended_buffer_decode_timestamp_ =
329 buffers.back()->GetDecodeTimestamp();
330 // Since we didn't buffer anything, don't update
331 // |highest_timestamp_in_append_sequence_|.
332 DVLOG(1) << __func__ << " " << GetStreamTypeName()
333 << ": new buffers in the middle of coded frame group depend on"
334 " keyframe that has been removed, and contain no keyframes."
335 " Skipping further processing.";
336 DVLOG(1) << __func__ << " " << GetStreamTypeName()
337 << ": done. ranges_=" << RangesToString(ranges_);
339 } else if (itr != buffers.begin()) {
340 // Copy the first key frame and everything after it into
341 // |trimmed_buffers|.
342 trimmed_buffers.assign(itr, buffers.end());
343 buffers_for_new_range = &trimmed_buffers;
346 new_range_start_time = buffers_for_new_range->front()->timestamp();
349 range_for_next_append_ = AddToRanges(std::make_unique<SourceBufferRange>(
350 SourceBufferRange::NO_GAPS_ALLOWED, *buffers_for_new_range,
351 new_range_start_time,
352 base::BindRepeating(&SourceBufferStream::GetMaxInterbufferDistance,
353 base::Unretained(this))));
355 last_appended_buffer_timestamp_ =
356 buffers_for_new_range->back()->timestamp();
357 last_appended_buffer_duration_ = buffers_for_new_range->back()->duration();
358 last_appended_buffer_is_keyframe_ =
359 buffers_for_new_range->back()->is_key_frame();
360 last_appended_buffer_decode_timestamp_ =
361 buffers_for_new_range->back()->GetDecodeTimestamp();
362 highest_timestamp_in_append_sequence_ =
363 (*range_for_next_append_)->GetEndTimestamp();
364 highest_buffered_end_time_in_append_sequence_ =
365 (*range_for_next_append_)->GetBufferedEndTimestamp();
368 new_coded_frame_group_ = false;
370 MergeWithNextRangeIfNecessary(range_for_next_append_);
372 // Some SAP-Type-2 append sequences require that we coalesce
373 // |range_for_next_append_| with the range that is *before* it.
374 if (range_for_next_append_ != ranges_.begin()) {
375 auto prior_range = range_for_next_append_;
377 MergeWithNextRangeIfNecessary(prior_range);
380 // Seek to try to fulfill a previous call to Seek().
382 DCHECK(!selected_range_);
383 DCHECK(deleted_buffers.empty());
384 Seek(seek_buffer_timestamp_);
387 if (!deleted_buffers.empty()) {
388 track_buffer_.insert(track_buffer_.end(), deleted_buffers.begin(),
389 deleted_buffers.end());
390 DVLOG(3) << __func__ << " " << GetStreamTypeName() << " Added "
391 << deleted_buffers.size()
392 << " buffers to track buffer. TB size is now "
393 << track_buffer_.size();
395 DVLOG(3) << __func__ << " " << GetStreamTypeName()
396 << " No deleted buffers for track buffer";
399 // Prune any extra buffers in |track_buffer_| if new keyframes
400 // are appended to the range covered by |track_buffer_|.
401 if (!track_buffer_.empty()) {
402 base::TimeDelta keyframe_timestamp =
403 FindKeyframeAfterTimestamp(track_buffer_.front()->timestamp());
404 if (keyframe_timestamp != kNoTimestamp)
405 PruneTrackBuffer(keyframe_timestamp);
408 SetSelectedRangeIfNeeded(next_buffer_timestamp);
410 DVLOG(1) << __func__ << " " << GetStreamTypeName()
411 << ": done. ranges_=" << RangesToString(ranges_);
412 DCHECK(IsRangeListSorted(ranges_));
413 DCHECK(OnlySelectedRangeIsSeeked());
416 void SourceBufferStream::Remove(base::TimeDelta start,
418 base::TimeDelta duration) {
419 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
420 << start.InMicroseconds() << "us, " << end.InMicroseconds() << "us, "
421 << duration.InMicroseconds() << "us)";
422 DCHECK(start >= base::TimeDelta()) << start.InMicroseconds() << "us";
423 DCHECK(start < end) << "start " << start.InMicroseconds() << "us, end "
424 << end.InMicroseconds() << "us";
425 DCHECK(duration != kNoTimestamp);
427 base::TimeDelta remove_end_timestamp = duration;
428 base::TimeDelta keyframe_timestamp = FindKeyframeAfterTimestamp(end);
429 if (keyframe_timestamp != kNoTimestamp) {
430 remove_end_timestamp = keyframe_timestamp;
431 } else if (end < remove_end_timestamp) {
432 remove_end_timestamp = end;
435 BufferQueue deleted_buffers;
436 RemoveInternal(start, remove_end_timestamp, false, &deleted_buffers);
438 if (!deleted_buffers.empty()) {
439 // Buffers for the current position have been removed.
440 SetSelectedRangeIfNeeded(deleted_buffers.front()->timestamp());
441 if (highest_output_buffer_timestamp_ == kNoTimestamp) {
442 // We just removed buffers for the current playback position for this
443 // stream, yet we also had output no buffer since the last Seek.
444 // Re-seek to prevent stall.
445 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": re-seeking to "
446 << seek_buffer_timestamp_
447 << " to prevent stall if this time becomes buffered again";
448 Seek(seek_buffer_timestamp_);
452 DCHECK(OnlySelectedRangeIsSeeked());
453 DCHECK(IsRangeListSorted(ranges_));
456 base::TimeDelta SourceBufferStream::PotentialNextAppendTimestamp() const {
457 // The next potential append will either be in a GOP adjacent to
458 // |highest_timestamp_in_append_sequence_| (if known), or if unknown and we
459 // are still at the beginning of a new coded frame group, then will be into
460 // the range (if any) to which |coded_frame_group_start_pts_| belongs.
461 if (highest_timestamp_in_append_sequence_ != kNoTimestamp)
462 return highest_timestamp_in_append_sequence_;
464 if (new_coded_frame_group_)
465 return coded_frame_group_start_pts_;
467 // If we still don't know a potential next append timestamp, then we have
468 // removed the range to which it previously belonged and have not completed a
469 // subsequent append or received a subsequent OnStartOfCodedFrameGroup()
474 void SourceBufferStream::UpdateLastAppendStateForRemove(
475 base::TimeDelta remove_start,
476 base::TimeDelta remove_end,
477 bool exclude_start) {
478 // TODO(chcunningham): change exclude_start to include_start in this class and
479 // SourceBufferRange. Negatives are hard to reason about.
480 bool include_start = !exclude_start;
482 // No need to check previous append's GOP if starting a new CFG. New CFG is
483 // already required to begin with a key frame.
484 if (new_coded_frame_group_)
487 if (range_for_next_append_ != ranges_.end()) {
488 if (last_appended_buffer_timestamp_ != kNoTimestamp) {
489 // Note start and end of last appended GOP.
490 base::TimeDelta gop_end = highest_timestamp_in_append_sequence_;
491 base::TimeDelta gop_start =
492 (*range_for_next_append_)->KeyframeBeforeTimestamp(gop_end);
494 // If last append is about to be disrupted, reset associated state so we
495 // know to create a new range for future appends and require an initial
497 if (((include_start && remove_start == gop_end) ||
498 remove_start < gop_end) &&
499 remove_end > gop_start) {
500 DVLOG(2) << __func__ << " " << GetStreamTypeName()
501 << " Resetting next append state for remove ("
502 << remove_start.InMicroseconds() << "us, "
503 << remove_end.InMicroseconds() << "us, " << exclude_start
505 range_for_next_append_ = ranges_.end();
506 ResetLastAppendedState();
509 NOTREACHED() << __func__ << " " << GetStreamTypeName()
510 << " range_for_next_append_ set, but not tracking last"
511 << " append nor new coded frame group.";
516 void SourceBufferStream::RemoveInternal(base::TimeDelta start,
519 BufferQueue* deleted_buffers) {
520 DVLOG(2) << __func__ << " " << GetStreamTypeName() << " ("
521 << start.InMicroseconds() << "us, " << end.InMicroseconds() << "us, "
522 << exclude_start << ")";
523 DVLOG(3) << __func__ << " " << GetStreamTypeName()
524 << ": before remove ranges_=" << RangesToString(ranges_);
526 DCHECK(start >= base::TimeDelta());
527 DCHECK(start < end) << "start " << start.InMicroseconds() << "us, end "
528 << end.InMicroseconds() << "us";
529 DCHECK(deleted_buffers);
531 // Doing this up-front simplifies decisions about |range_for_next_append_|
533 UpdateLastAppendStateForRemove(start, end, exclude_start);
535 auto itr = ranges_.begin();
536 while (itr != ranges_.end()) {
537 SourceBufferRange* range = itr->get();
538 if (range->GetStartTimestamp() >= end)
541 // Split off any remaining GOPs starting at or after |end| and add it to
543 std::unique_ptr<SourceBufferRange> new_range = range->SplitRange(end);
545 itr = ranges_.insert(++itr, std::move(new_range));
547 // Update |range_for_next_append_| if it was previously |range| and should
548 // be the new range (that |itr| is at) now.
549 if (range_for_next_append_ != ranges_.end() &&
550 range_for_next_append_->get() == range) {
551 base::TimeDelta potential_next_append_timestamp =
552 PotentialNextAppendTimestamp();
553 if (potential_next_append_timestamp != kNoTimestamp &&
554 (*itr)->BelongsToRange(potential_next_append_timestamp)) {
555 range_for_next_append_ = itr;
559 // Update the selected range if the next buffer position was transferred
560 // to the newly inserted range (that |itr| is at now).
561 if ((*itr)->HasNextBufferPosition())
562 SetSelectedRange(itr->get());
567 // Truncate the current range so that it only contains data before
568 // the removal range.
569 BufferQueue saved_buffers;
570 bool delete_range = range->TruncateAt(start, &saved_buffers, exclude_start);
572 // Check to see if the current playback position was removed and update the
573 // selected range appropriately.
574 if (!saved_buffers.empty()) {
575 DCHECK(!range->HasNextBufferPosition());
576 DCHECK(deleted_buffers->empty());
578 *deleted_buffers = saved_buffers;
581 if (range == selected_range_ && !range->HasNextBufferPosition())
582 SetSelectedRange(NULL);
584 // If the current range now is completely covered by the removal
585 // range then delete it and move on.
587 DeleteAndRemoveRange(&itr);
591 // Clear |range_for_next_append_| if we determine that the removal
592 // operation makes it impossible for the next append to be added
593 // to the current range.
594 if (range_for_next_append_ != ranges_.end() &&
595 range_for_next_append_->get() == range) {
596 base::TimeDelta potential_next_append_timestamp =
597 PotentialNextAppendTimestamp();
599 if (!range->BelongsToRange(potential_next_append_timestamp)) {
600 DVLOG(1) << "Resetting range_for_next_append_ since the next append"
601 << " can't add to the current range.";
602 range_for_next_append_ =
603 FindExistingRangeFor(potential_next_append_timestamp);
607 // Move on to the next range.
611 DVLOG(3) << __func__ << " " << GetStreamTypeName()
612 << ": after remove ranges_=" << RangesToString(ranges_);
614 DCHECK(OnlySelectedRangeIsSeeked());
617 void SourceBufferStream::ResetSeekState() {
618 SetSelectedRange(NULL);
619 track_buffer_.clear();
620 config_change_pending_ = false;
621 highest_output_buffer_timestamp_ = kNoTimestamp;
622 just_exhausted_track_buffer_ = false;
623 pending_buffer_.reset();
624 pending_buffers_complete_ = false;
627 void SourceBufferStream::ResetLastAppendedState() {
628 last_appended_buffer_timestamp_ = kNoTimestamp;
629 last_appended_buffer_duration_ = kNoTimestamp;
630 last_appended_buffer_is_keyframe_ = false;
631 last_appended_buffer_decode_timestamp_ = kNoDecodeTimestamp;
632 highest_timestamp_in_append_sequence_ = kNoTimestamp;
633 highest_buffered_end_time_in_append_sequence_ = kNoTimestamp;
636 bool SourceBufferStream::ShouldSeekToStartOfBuffered(
637 base::TimeDelta seek_timestamp) const {
640 base::TimeDelta beginning_of_buffered = ranges_.front()->GetStartTimestamp();
641 return (seek_timestamp <= beginning_of_buffered &&
642 beginning_of_buffered < kSeekToStartFudgeRoom());
645 bool SourceBufferStream::IsDtsMonotonicallyIncreasing(
646 const BufferQueue& buffers) {
647 DCHECK(!buffers.empty());
648 DecodeTimestamp prev_dts = last_appended_buffer_decode_timestamp_;
649 for (BufferQueue::const_iterator itr = buffers.begin();
650 itr != buffers.end(); ++itr) {
651 DecodeTimestamp current_dts = (*itr)->GetDecodeTimestamp();
652 bool current_is_keyframe = (*itr)->is_key_frame();
653 DCHECK(current_dts != kNoDecodeTimestamp);
654 DCHECK((*itr)->duration() >= base::TimeDelta())
655 << "Packet with invalid duration."
656 << " pts " << (*itr)->timestamp().InMicroseconds() << "us dts "
657 << (*itr)->GetDecodeTimestamp().InMicroseconds() << "us dur "
658 << (*itr)->duration().InMicroseconds() << "us";
660 // Only verify DTS monotonicity within the current GOP (since the last
661 // keyframe). FrameProcessor should have enforced that all audio frames are
662 // keyframes already, or are nonkeyframes with monotonically increasing PTS
663 // since the last keyframe for those types of audio for which nonkeyframes
664 // may be involved, e.g. xHE-AAC. Video nonkeyframes are not restricted to
665 // being in-order by PTS, but both audio and video nonkeyframes must be in
666 // decode sequence since the last keyframe.
667 if (current_is_keyframe) {
668 // Reset prev_dts tracking since a new GOP is starting.
669 prev_dts = kNoDecodeTimestamp;
672 if (prev_dts != kNoDecodeTimestamp) {
673 if (current_dts < prev_dts) {
674 MEDIA_LOG(ERROR, media_log_)
675 << "Buffers did not monotonically increase.";
680 prev_dts = current_dts;
685 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
686 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
687 if ((*itr)->HasNextBufferPosition() && itr->get() != selected_range_)
690 return !selected_range_ || selected_range_->HasNextBufferPosition();
693 bool SourceBufferStream::UpdateMaxInterbufferDtsDistance(
694 const BufferQueue& buffers) {
695 DCHECK(!buffers.empty());
696 base::TimeDelta old_distance = max_interbuffer_distance_;
697 DecodeTimestamp prev_dts = last_appended_buffer_decode_timestamp_;
698 for (BufferQueue::const_iterator itr = buffers.begin();
699 itr != buffers.end(); ++itr) {
700 DecodeTimestamp current_dts = (*itr)->GetDecodeTimestamp();
701 DCHECK(current_dts != kNoDecodeTimestamp);
703 base::TimeDelta interbuffer_distance = (*itr)->duration();
704 DCHECK(interbuffer_distance >= base::TimeDelta());
706 if (prev_dts != kNoDecodeTimestamp) {
707 interbuffer_distance =
708 std::max(current_dts - prev_dts, interbuffer_distance);
711 DCHECK(max_interbuffer_distance_ >=
712 base::Milliseconds(kMinimumInterbufferDistanceInMs));
713 max_interbuffer_distance_ =
714 std::max(max_interbuffer_distance_, interbuffer_distance);
715 prev_dts = current_dts;
717 bool changed_max = max_interbuffer_distance_ != old_distance;
718 DVLOG_IF(2, changed_max) << __func__ << " " << GetStreamTypeName()
719 << " Changed max interbuffer DTS distance from "
720 << old_distance.InMicroseconds() << "us to "
721 << max_interbuffer_distance_.InMicroseconds()
726 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) {
727 for (BufferQueue::const_iterator itr = buffers.begin();
728 itr != buffers.end(); ++itr) {
729 (*itr)->SetConfigId(append_config_index_);
733 void SourceBufferStream::OnMemoryPressure(
734 base::TimeDelta media_time,
735 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
736 bool force_instant_gc) {
737 DVLOG(4) << __func__ << " level=" << memory_pressure_level;
738 // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
740 if (memory_pressure_level ==
741 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
745 memory_pressure_level_ = memory_pressure_level;
747 if (force_instant_gc)
748 GarbageCollectIfNeeded(media_time, 0);
751 bool SourceBufferStream::GarbageCollectIfNeeded(base::TimeDelta media_time,
752 size_t newDataSize) {
753 DCHECK(media_time != kNoTimestamp);
754 // Garbage collection should only happen before/during appending new data,
755 // which should not happen in end-of-stream state. Unless we also allow GC to
756 // happen on memory pressure notifications, which might happen even in EOS
758 if (!base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC))
759 DCHECK(!end_of_stream_);
760 // Compute size of |ranges_|.
761 size_t ranges_size = GetBufferedSize();
763 // Sanity and overflow checks
764 if ((newDataSize > memory_limit_) ||
765 (ranges_size + newDataSize < ranges_size)) {
766 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_garbage_collect_algorithm_logs_,
767 kMaxGarbageCollectAlgorithmWarningLogs)
768 << GetStreamTypeName() << " stream: "
769 << "new append of newDataSize=" << newDataSize
770 << " bytes exceeds memory_limit_=" << memory_limit_
771 << ", currently buffered ranges_size=" << ranges_size;
775 size_t effective_memory_limit = memory_limit_;
776 if (base::FeatureList::IsEnabled(kMemoryPressureBasedSourceBufferGC)) {
777 switch (memory_pressure_level_) {
778 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
779 effective_memory_limit = memory_limit_ / 2;
781 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
782 effective_memory_limit = 0;
784 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
789 // Return if we're under or at the memory limit.
790 if (ranges_size + newDataSize <= effective_memory_limit)
793 size_t bytes_over_hard_memory_limit = 0;
794 if (ranges_size + newDataSize > memory_limit_)
795 bytes_over_hard_memory_limit = ranges_size + newDataSize - memory_limit_;
797 size_t bytes_to_free = ranges_size + newDataSize - effective_memory_limit;
799 DVLOG(2) << __func__ << " " << GetStreamTypeName()
800 << ": Before GC media_time=" << media_time.InMicroseconds()
801 << "us ranges_=" << RangesToString(ranges_)
802 << " seek_pending_=" << seek_pending_
803 << " ranges_size=" << ranges_size << " newDataSize=" << newDataSize
804 << " memory_limit_=" << memory_limit_
805 << " effective_memory_limit=" << effective_memory_limit
806 << " last_appended_buffer_timestamp_="
807 << last_appended_buffer_timestamp_.InMicroseconds()
808 << "us highest_timestamp_in_append_sequence_="
809 << highest_timestamp_in_append_sequence_.InMicroseconds()
810 << "us highest_buffered_end_time_in_append_sequence_="
811 << highest_buffered_end_time_in_append_sequence_.InMicroseconds()
814 if (selected_range_ && !seek_pending_ &&
815 media_time > selected_range_->GetBufferedEndTimestamp()) {
816 // Strictly speaking |media_time| (taken from HTMLMediaElement::currentTime)
817 // should always be in the buffered ranges, but media::Pipeline uses audio
818 // stream as the main time source, when audio is present.
819 // In cases when audio and video streams have different buffered ranges, the
820 // |media_time| value might be slightly outside of the video stream buffered
821 // range. In those cases we need to clamp |media_time| value to the current
822 // stream buffered ranges, to ensure the MSE garbage collection algorithm
823 // works correctly (see crbug.com/563292 for details).
824 base::TimeDelta selected_buffered_end =
825 selected_range_->GetBufferedEndTimestamp();
827 DVLOG(2) << __func__ << " media_time " << media_time.InMicroseconds()
828 << "us is outside of selected_range_=["
829 << selected_range_->GetStartTimestamp().InMicroseconds() << "us;"
830 << selected_buffered_end.InMicroseconds()
831 << "us] clamping media_time to be "
832 << selected_buffered_end.InMicroseconds() << "us";
833 media_time = selected_buffered_end;
836 size_t bytes_freed = 0;
838 // If last appended buffer position was earlier than the current playback time
839 // then try deleting data between last append and current media_time.
840 if (last_appended_buffer_timestamp_ != kNoTimestamp &&
841 last_appended_buffer_duration_ != kNoTimestamp &&
842 highest_buffered_end_time_in_append_sequence_ != kNoTimestamp &&
843 media_time > highest_buffered_end_time_in_append_sequence_) {
844 size_t between = FreeBuffersAfterLastAppended(bytes_to_free, media_time);
845 DVLOG(3) << __func__ << " FreeBuffersAfterLastAppended "
846 << " released " << between << " bytes"
847 << " ranges_=" << RangesToString(ranges_);
848 bytes_freed += between;
850 // Some players start appending data at the new seek target position before
851 // actually initiating the seek operation (i.e. they try to improve seek
852 // performance by prebuffering some data at the seek target position and
853 // initiating seek once enough data is pre-buffered. In those cases we'll
854 // see that data is being appended at some new position, but there is no
855 // pending seek reported yet. In this situation we need to try preserving
856 // the most recently appended data, i.e. data belonging to the same buffered
857 // range as the most recent append.
858 if (range_for_next_append_ != ranges_.end()) {
859 DCHECK((*range_for_next_append_)->GetStartTimestamp() <= media_time);
860 media_time = (*range_for_next_append_)->GetStartTimestamp();
861 DVLOG(3) << __func__ << " media_time adjusted to "
862 << media_time.InMicroseconds() << "us";
866 // If there is an unsatisfied pending seek, we can safely remove all data that
867 // is earlier than seek target, then remove from the back until we reach the
868 // most recently appended GOP and then remove from the front if we still don't
869 // have enough space for the upcoming append.
870 if (bytes_freed < bytes_to_free && seek_pending_) {
871 DCHECK(!ranges_.empty());
872 // All data earlier than the seek target |media_time| can be removed safely
873 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
874 DVLOG(3) << __func__ << " Removed " << front
875 << " bytes from the front. ranges_=" << RangesToString(ranges_);
876 bytes_freed += front;
878 // If removing data earlier than |media_time| didn't free up enough space,
879 // then try deleting from the back until we reach most recently appended GOP
880 if (bytes_freed < bytes_to_free) {
881 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
882 DVLOG(3) << __func__ << " Removed " << back
883 << " bytes from the back. ranges_=" << RangesToString(ranges_);
887 // If even that wasn't enough, then try greedily deleting from the front,
888 // that should allow us to remove as much data as necessary to succeed.
889 if (bytes_freed < bytes_to_free) {
890 size_t front2 = FreeBuffers(bytes_to_free - bytes_freed,
891 ranges_.back()->GetEndTimestamp(), false);
892 DVLOG(3) << __func__ << " Removed " << front2
893 << " bytes from the front. ranges_=" << RangesToString(ranges_);
894 bytes_freed += front2;
896 DCHECK(bytes_freed >= bytes_to_free);
899 // Try removing data from the front of the SourceBuffer up to |media_time|
901 if (bytes_freed < bytes_to_free) {
902 size_t front = FreeBuffers(bytes_to_free - bytes_freed, media_time, false);
903 DVLOG(3) << __func__ << " Removed " << front
904 << " bytes from the front. ranges_=" << RangesToString(ranges_);
905 bytes_freed += front;
908 // Try removing data from the back of the SourceBuffer, until we reach the
909 // most recent append position.
910 if (bytes_freed < bytes_to_free) {
911 size_t back = FreeBuffers(bytes_to_free - bytes_freed, media_time, true);
912 DVLOG(3) << __func__ << " Removed " << back
913 << " bytes from the back. ranges_=" << RangesToString(ranges_);
917 DVLOG(2) << __func__ << " " << GetStreamTypeName()
918 << ": After GC bytes_to_free=" << bytes_to_free
919 << " bytes_freed=" << bytes_freed
920 << " bytes_over_hard_memory_limit=" << bytes_over_hard_memory_limit
921 << " ranges_=" << RangesToString(ranges_);
923 return bytes_freed >= bytes_over_hard_memory_limit;
926 size_t SourceBufferStream::FreeBuffersAfterLastAppended(
927 size_t total_bytes_to_free,
928 base::TimeDelta media_time) {
929 DVLOG(4) << __func__ << " highest_buffered_end_time_in_append_sequence_="
930 << highest_buffered_end_time_in_append_sequence_.InMicroseconds()
931 << "us media_time=" << media_time.InMicroseconds() << "us";
933 base::TimeDelta remove_range_start =
934 highest_buffered_end_time_in_append_sequence_;
935 if (last_appended_buffer_is_keyframe_)
936 remove_range_start += GetMaxInterbufferDistance();
938 base::TimeDelta remove_range_start_keyframe =
939 FindKeyframeAfterTimestamp(remove_range_start);
940 if (remove_range_start_keyframe != kNoTimestamp)
941 remove_range_start = remove_range_start_keyframe;
942 if (remove_range_start >= media_time)
945 base::TimeDelta remove_range_end;
946 size_t bytes_freed = GetRemovalRange(remove_range_start,
950 if (bytes_freed > 0) {
951 DVLOG(4) << __func__ << " removing [" << remove_range_start.InMicroseconds()
952 << "us;" << remove_range_end.InMicroseconds() << "us]";
953 Remove(remove_range_start, remove_range_end, media_time);
959 size_t SourceBufferStream::GetRemovalRange(
960 base::TimeDelta start_timestamp,
961 base::TimeDelta end_timestamp,
962 size_t total_bytes_to_free,
963 base::TimeDelta* removal_end_timestamp) {
964 DCHECK(start_timestamp >= base::TimeDelta())
965 << start_timestamp.InMicroseconds() << "us";
966 DCHECK(start_timestamp < end_timestamp)
967 << "start " << start_timestamp.InMicroseconds() << "us, end "
968 << end_timestamp.InMicroseconds() << "us";
970 size_t bytes_freed = 0;
972 for (auto itr = ranges_.begin();
973 itr != ranges_.end() && bytes_freed < total_bytes_to_free; ++itr) {
974 SourceBufferRange* range = itr->get();
975 if (range->GetStartTimestamp() >= end_timestamp)
977 if (range->GetEndTimestamp() < start_timestamp)
980 size_t bytes_to_free = total_bytes_to_free - bytes_freed;
981 size_t bytes_removed = range->GetRemovalGOP(
982 start_timestamp, end_timestamp, bytes_to_free, removal_end_timestamp);
983 bytes_freed += bytes_removed;
988 size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free,
989 base::TimeDelta media_time,
990 bool reverse_direction) {
991 TRACE_EVENT2("media", "SourceBufferStream::FreeBuffers",
992 "total bytes to free", total_bytes_to_free,
993 "reverse direction", reverse_direction);
995 DCHECK_GT(total_bytes_to_free, 0u);
996 size_t bytes_freed = 0;
998 // This range will save the last GOP appended to |range_for_next_append_|
999 // if the buffers surrounding it get deleted during garbage collection.
1000 std::unique_ptr<SourceBufferRange> new_range_for_append;
1002 while (!ranges_.empty() && bytes_freed < total_bytes_to_free) {
1003 SourceBufferRange* current_range = NULL;
1004 BufferQueue buffers;
1005 size_t bytes_deleted = 0;
1007 if (reverse_direction) {
1008 current_range = ranges_.back().get();
1009 DVLOG(5) << "current_range=" << RangeToString(*current_range);
1010 if (current_range->LastGOPContainsNextBufferPosition()) {
1011 DCHECK_EQ(current_range, selected_range_);
1012 DVLOG(5) << "current_range contains next read position, stopping GC";
1015 DVLOG(5) << "Deleting GOP from back: " << RangeToString(*current_range);
1016 bytes_deleted = current_range->DeleteGOPFromBack(&buffers);
1018 current_range = ranges_.front().get();
1019 DVLOG(5) << "current_range=" << RangeToString(*current_range);
1021 // FirstGOPEarlierThanMediaTime() is useful here especially if
1022 // |seek_pending_| (such that no range contains next buffer
1024 // FirstGOPContainsNextBufferPosition() is useful here especially if
1025 // |!seek_pending_| to protect against DeleteGOPFromFront() if
1026 // FirstGOPEarlierThanMediaTime() was insufficient alone.
1027 if (!current_range->FirstGOPEarlierThanMediaTime(media_time) ||
1028 current_range->FirstGOPContainsNextBufferPosition()) {
1029 // We have removed all data up to the GOP that contains current playback
1030 // position, we can't delete any further.
1031 DVLOG(5) << "current_range contains playback position, stopping GC";
1034 DVLOG(4) << "Deleting GOP from front: " << RangeToString(*current_range)
1035 << ", media_time: " << media_time.InMicroseconds()
1036 << ", current_range->HasNextBufferPosition(): "
1037 << current_range->HasNextBufferPosition();
1038 bytes_deleted = current_range->DeleteGOPFromFront(&buffers);
1041 // Check to see if we've just deleted the GOP that was last appended.
1042 base::TimeDelta end_timestamp = buffers.back()->timestamp();
1043 if (end_timestamp == last_appended_buffer_timestamp_) {
1044 DCHECK(last_appended_buffer_timestamp_ != kNoTimestamp);
1045 DCHECK(!new_range_for_append);
1047 // Create a new range containing these buffers.
1048 new_range_for_append = std::make_unique<SourceBufferRange>(
1049 SourceBufferRange::NO_GAPS_ALLOWED, buffers, kNoTimestamp,
1050 base::BindRepeating(&SourceBufferStream::GetMaxInterbufferDistance,
1051 base::Unretained(this)));
1053 range_for_next_append_ = ranges_.end();
1055 bytes_freed += bytes_deleted;
1058 if (current_range->size_in_bytes() == 0) {
1059 DCHECK_NE(current_range, selected_range_);
1060 DCHECK(range_for_next_append_ == ranges_.end() ||
1061 range_for_next_append_->get() != current_range);
1063 // Delete |current_range| by popping it out of |ranges_|.
1064 reverse_direction ? ranges_.pop_back() : ranges_.pop_front();
1067 if (reverse_direction && new_range_for_append) {
1068 // We don't want to delete any further, or we'll be creating gaps
1073 // Insert |new_range_for_append| into |ranges_|, if applicable.
1074 if (new_range_for_append) {
1075 range_for_next_append_ = AddToRanges(std::move(new_range_for_append));
1076 DCHECK(range_for_next_append_ != ranges_.end());
1078 // Check to see if we need to merge the just added range that was in
1079 // |new_range_for_append| with the range before or after it. That added
1080 // range is created whenever the last GOP appended is encountered,
1081 // regardless of whether any buffers after it are ultimately deleted.
1082 // Merging is necessary if there were no buffers (or very few buffers)
1083 // deleted after creating that added range.
1084 if (range_for_next_append_ != ranges_.begin()) {
1085 auto range_before_next = range_for_next_append_;
1086 --range_before_next;
1087 MergeWithNextRangeIfNecessary(range_before_next);
1089 MergeWithNextRangeIfNecessary(range_for_next_append_);
1094 void SourceBufferStream::TrimSpliceOverlap(const BufferQueue& new_buffers) {
1095 DCHECK(!new_buffers.empty());
1096 DCHECK_EQ(SourceBufferStreamType::kAudio, GetType());
1098 const base::TimeDelta splice_timestamp = new_buffers.front()->timestamp();
1100 // Since some audio formats may have nonkeyframes (in PTS order since last
1101 // keyframe), if the front of the new buffers is one of those, it cannot be
1102 // used to begin a decode following an overlap. Here, we bail in this case,
1103 // since such a splice could not be coherently decoded.
1104 if (!new_buffers.front()->is_key_frame()) {
1105 DVLOG(3) << __func__
1106 << " No splice trimming. Front of |new_buffers| is not a "
1107 "keyframe, at time "
1108 << splice_timestamp.InMicroseconds();
1112 // Find the overlapped range (if any).
1113 auto range_itr = FindExistingRangeFor(splice_timestamp);
1114 if (range_itr == ranges_.end()) {
1115 DVLOG(3) << __func__ << " No splice trimming. No range overlap at time "
1116 << splice_timestamp.InMicroseconds();
1120 // Search for overlapped buffer needs exclusive end value. Choosing smallest
1122 const base::TimeDelta end_pts = splice_timestamp + base::Microseconds(1);
1124 // Find if new buffer's start would overlap an existing buffer. Note that
1125 // overlapped audio buffers might be nonkeyframes, but if so, FrameProcessor
1126 // ensures they are in PTS order since the previous keyframe.
1127 BufferQueue overlapped_buffers;
1129 ->GetBuffersInRange(splice_timestamp, end_pts,
1130 &overlapped_buffers)) {
1131 // Bail if no overlapped buffers found.
1132 DVLOG(3) << __func__ << " No splice trimming. No buffer overlap at time "
1133 << splice_timestamp.InMicroseconds();
1137 // At most one buffer should exist containing the time of the newly appended
1138 // buffer's start. It may happen that bad content appends buffers with
1139 // durations that cause nonsensical overlap. Trimming should not be performed
1140 // in these cases, as the content is already in a bad state.
1141 if (overlapped_buffers.size() != 1U) {
1142 DVLOG(3) << __func__
1143 << " No splice trimming. Found more than one overlapped buffer"
1144 " (bad content) at time "
1145 << splice_timestamp.InMicroseconds();
1147 MEDIA_LOG(WARNING, media_log_)
1148 << "Media is badly muxed. Detected " << overlapped_buffers.size()
1149 << " overlapping audio buffers at time "
1150 << splice_timestamp.InMicroseconds();
1153 StreamParserBuffer* overlapped_buffer = overlapped_buffers.front().get();
1155 if (overlapped_buffer->timestamp() == splice_timestamp) {
1156 // Ignore buffers with the same start time. They will be completely removed
1157 // in PrepareRangesForNextAppend().
1158 DVLOG(3) << __func__ << " No splice trimming at time "
1159 << splice_timestamp.InMicroseconds()
1160 << ". Overlapped buffer will be completely removed.";
1164 // Trimming a buffer with estimated duration is too risky. Estimates are rough
1165 // and what appears to be overlap may really just be a bad estimate. Imprecise
1166 // trimming may lead to loss of AV sync.
1167 if (overlapped_buffer->is_duration_estimated()) {
1168 DVLOG(3) << __func__ << " Skipping audio splice trimming at PTS="
1169 << splice_timestamp.InMicroseconds() << ". Overlapped buffer has "
1170 << "estimated duration.";
1174 // Determine the duration of overlap.
1175 base::TimeDelta overlapped_end_time =
1176 overlapped_buffer->timestamp() + overlapped_buffer->duration();
1177 base::TimeDelta overlap_duration = overlapped_end_time - splice_timestamp;
1179 // At this point overlap should be non-empty (ruled out same-timestamp above).
1180 DCHECK_GT(overlap_duration, base::TimeDelta());
1182 // Don't trim for overlaps of less than one millisecond (which is frequently
1183 // the extent of timestamp resolution for poorly encoded media).
1184 if (overlap_duration < base::Milliseconds(1)) {
1185 std::stringstream log_string;
1186 log_string << "Skipping audio splice trimming at PTS="
1187 << splice_timestamp.InMicroseconds() << "us. Found only "
1188 << overlap_duration.InMicroseconds()
1189 << "us of overlap, need at least 1000us. Multiple occurrences "
1190 << "may result in loss of A/V sync.";
1191 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_logs_, kMaxAudioSpliceLogs)
1192 << log_string.str();
1193 DVLOG(1) << __func__ << log_string.str();
1197 // Trim overlap from the existing buffer.
1198 DecoderBuffer::DiscardPadding discard_padding =
1199 overlapped_buffer->discard_padding();
1200 discard_padding.second += overlap_duration;
1201 overlapped_buffer->set_discard_padding(discard_padding);
1202 overlapped_buffer->set_duration(overlapped_buffer->duration() -
1205 // Note that the range's end time tracking shouldn't need explicit updating
1206 // here due to the overlapped buffer's truncation because the range tracks
1207 // that end time using a pointer to the buffer (which should be
1208 // |overlapped_buffer| if the overlap occurred at the end of the range).
1209 // Every audio frame is either a keyframe, or if a nonkeyframe is in PTS order
1210 // since the last keyframe, so there is no out-of-order PTS vs DTS sequencing
1211 // to overcome. If the overlap occurs in the middle of the range, the caller
1212 // invokes methods on the range which internally update the end time(s) of the
1213 // resulting range(s) involved in the append.
1215 std::stringstream log_string;
1216 log_string << "Audio buffer splice at PTS="
1217 << splice_timestamp.InMicroseconds()
1218 << "us. Trimmed tail of overlapped buffer (PTS="
1219 << overlapped_buffer->timestamp().InMicroseconds() << "us) by "
1220 << overlap_duration.InMicroseconds() << "us.";
1221 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_logs_, kMaxAudioSpliceLogs)
1222 << log_string.str();
1223 DVLOG(1) << __func__ << log_string.str();
1226 void SourceBufferStream::PrepareRangesForNextAppend(
1227 const BufferQueue& new_buffers,
1228 BufferQueue* deleted_buffers) {
1229 DCHECK(deleted_buffers);
1231 if (GetType() == SourceBufferStreamType::kAudio)
1232 TrimSpliceOverlap(new_buffers);
1234 base::TimeDelta buffers_start_timestamp = kNoTimestamp;
1235 base::TimeDelta buffers_end_timestamp = kNoTimestamp;
1236 GetTimestampInterval(new_buffers, &buffers_start_timestamp,
1237 &buffers_end_timestamp);
1238 DCHECK(buffers_start_timestamp != kNoTimestamp);
1239 DCHECK(buffers_end_timestamp != kNoTimestamp);
1241 // 1. Clean up the old buffers between the last appended buffers and the
1242 // beginning of |new_buffers|.
1243 if (highest_timestamp_in_append_sequence_ != kNoTimestamp &&
1244 highest_timestamp_in_append_sequence_ < buffers_start_timestamp) {
1245 RemoveInternal(highest_timestamp_in_append_sequence_,
1246 buffers_start_timestamp, true, deleted_buffers);
1249 // 2. Delete the buffers that |new_buffers| overlaps.
1250 // There may be buffers in |new_buffers| with timestamp before
1251 // |highest_timestamp_in_append_sequence_| that shouldn't trigger removal of
1252 // stuff before |highest_timestamp_in_append_sequence_|.
1253 if (highest_timestamp_in_append_sequence_ != kNoTimestamp &&
1254 buffers_start_timestamp < highest_timestamp_in_append_sequence_) {
1255 DCHECK(highest_timestamp_in_append_sequence_ <=
1256 highest_buffered_end_time_in_append_sequence_);
1257 buffers_start_timestamp = highest_buffered_end_time_in_append_sequence_;
1260 if (new_coded_frame_group_) {
1261 // Extend the deletion range earlier to the coded frame group start time if
1262 // this is the first append in a new coded frame group.
1263 DCHECK(coded_frame_group_start_pts_ != kNoTimestamp);
1264 buffers_start_timestamp =
1265 std::min(coded_frame_group_start_pts_, buffers_start_timestamp);
1268 // Return early if no further overlap removal is needed. First check if
1269 // |buffers_start_timestamp| is in the middle of the range; we could be
1270 // overlap-appending the middle of a previous coded frame sequence's range
1271 // with non-keyframes prior to |highest_timestamp_in_append_sequence_|, so we
1272 // need to split that range appropriately here and then return early. If we
1273 // don't return early here, overlap removal (including any necessary range
1274 // splitting) will occur.
1275 if (buffers_start_timestamp >= buffers_end_timestamp) {
1276 DCHECK(highest_timestamp_in_append_sequence_ != kNoTimestamp);
1277 DCHECK(range_for_next_append_ != ranges_.end());
1278 DCHECK((*range_for_next_append_)->BelongsToRange(buffers_start_timestamp));
1280 // Split the range at |buffers_start_timestamp|, if necessary, then return
1282 std::unique_ptr<SourceBufferRange> new_range =
1283 (*range_for_next_append_)->SplitRange(buffers_start_timestamp);
1287 range_for_next_append_ =
1288 ranges_.insert(++range_for_next_append_, std::move(new_range));
1290 // Update the selected range if the next buffer position was transferred
1291 // to the newly inserted range.
1292 if ((*range_for_next_append_)->HasNextBufferPosition())
1293 SetSelectedRange(range_for_next_append_->get());
1295 --range_for_next_append_;
1299 // Exclude the start from removal to avoid deleting the highest appended
1300 // buffer in cases where the first buffer in |new_buffers| has same timestamp
1301 // as the highest appended buffer (even in out-of-order DTS vs PTS sequence).
1302 // Only do this when :
1303 // A. Type is video. This may occur in cases of VP9 alt-ref frames or frames
1304 // with incorrect timestamps. Removing a frame may break decode
1305 // dependencies and there are no downsides to just keeping it (other than
1306 // some throw-away decoder work).
1307 // B. Type is audio and overlapped duration is 0. We've encountered Vorbis
1308 // streams containing zero-duration buffers (i.e. no real overlap). For
1309 // non-zero duration removing overlapped frames is important to preserve
1310 // A/V sync (see AudioClock).
1311 const bool exclude_start =
1312 highest_timestamp_in_append_sequence_ ==
1313 new_buffers.front()->timestamp() &&
1314 (GetType() == SourceBufferStreamType::kVideo ||
1315 last_appended_buffer_duration_ == base::TimeDelta());
1317 // Finally do the deletion of overlap.
1318 RemoveInternal(buffers_start_timestamp, buffers_end_timestamp, exclude_start,
1323 void SourceBufferStream::GetTimestampInterval(const BufferQueue& buffers,
1324 base::TimeDelta* start,
1325 base::TimeDelta* end) {
1326 base::TimeDelta start_pts = buffers.front()->timestamp();
1327 base::TimeDelta end_pts = start_pts;
1329 for (const auto& buffer : buffers) {
1330 base::TimeDelta timestamp = buffer->timestamp();
1331 start_pts = std::min(timestamp, start_pts);
1332 base::TimeDelta duration = buffer->duration();
1334 // FrameProcessor should protect against unknown buffer durations.
1335 DCHECK_NE(duration, kNoTimestamp);
1337 if (duration.is_positive() && !buffer->is_duration_estimated()) {
1338 timestamp += duration;
1340 // TODO(chcunningham): Emit warning when 0ms durations are not expected.
1341 // http://crbug.com/312836
1342 timestamp += base::Microseconds(1);
1344 end_pts = std::max(timestamp, end_pts);
1350 bool SourceBufferStream::IsNextGopAdjacentToEndOfCurrentAppendSequence(
1351 base::TimeDelta next_gop_timestamp) const {
1352 base::TimeDelta upper_bound = highest_timestamp_in_append_sequence_ +
1353 ComputeFudgeRoom(GetMaxInterbufferDistance());
1354 DVLOG(4) << __func__ << " " << GetStreamTypeName()
1355 << " next_gop_timestamp=" << next_gop_timestamp.InMicroseconds()
1356 << "us, highest_timestamp_in_append_sequence_="
1357 << highest_timestamp_in_append_sequence_.InMicroseconds()
1358 << "us, upper_bound=" << upper_bound.InMicroseconds() << "us";
1359 return highest_timestamp_in_append_sequence_ < next_gop_timestamp &&
1360 next_gop_timestamp <= upper_bound;
1363 void SourceBufferStream::PruneTrackBuffer(const base::TimeDelta timestamp) {
1364 DCHECK(timestamp != kNoTimestamp);
1366 // Scan forward until we find a buffer with timestamp at or beyond the limit.
1367 // Then remove all those at and beyond that point.
1368 size_t goal_size = 0; // The number of buffers we will keep in the result.
1369 for (const auto& buf : track_buffer_) {
1370 if (buf->timestamp() >= timestamp)
1375 while (track_buffer_.size() > goal_size) {
1376 track_buffer_.pop_back();
1379 DVLOG(3) << __func__ << " " << GetStreamTypeName()
1380 << " Removed all buffers in track buffer sequence starting with the "
1381 "first at timestamp >= "
1382 << timestamp.InMicroseconds()
1383 << "us. New track buffer size:" << track_buffer_.size();
1386 void SourceBufferStream::MergeWithNextRangeIfNecessary(
1387 const RangeList::iterator& range_with_new_buffers_itr) {
1388 DCHECK(range_with_new_buffers_itr != ranges_.end());
1390 SourceBufferRange* range_with_new_buffers = range_with_new_buffers_itr->get();
1391 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
1394 if (next_range_itr == ranges_.end() ||
1395 !range_with_new_buffers->CanAppendRangeToEnd(**next_range_itr)) {
1399 bool transfer_current_position = selected_range_ == next_range_itr->get();
1400 DVLOG(3) << __func__ << " " << GetStreamTypeName() << " merging "
1401 << RangeToString(*range_with_new_buffers) << " into "
1402 << RangeToString(**next_range_itr);
1403 range_with_new_buffers->AppendRangeToEnd(**next_range_itr,
1404 transfer_current_position);
1405 // Update |selected_range_| pointer if |range| has become selected after
1407 if (transfer_current_position)
1408 SetSelectedRange(range_with_new_buffers);
1410 if (next_range_itr == range_for_next_append_)
1411 range_for_next_append_ = range_with_new_buffers_itr;
1413 DeleteAndRemoveRange(&next_range_itr);
1416 void SourceBufferStream::MergeAllAdjacentRanges() {
1417 DVLOG(1) << __func__ << " " << GetStreamTypeName()
1418 << ": Before: ranges_=" << RangesToString(ranges_);
1420 auto range_itr = ranges_.begin();
1422 while (range_itr != ranges_.end()) {
1423 const size_t old_ranges_size = ranges_.size();
1424 MergeWithNextRangeIfNecessary(range_itr);
1426 // Only proceed to the next range if the current range didn't merge with it.
1427 if (old_ranges_size == ranges_.size())
1431 DVLOG(1) << __func__ << " " << GetStreamTypeName()
1432 << ": After: ranges_=" << RangesToString(ranges_);
1435 void SourceBufferStream::Seek(base::TimeDelta timestamp) {
1436 DCHECK(timestamp >= base::TimeDelta());
1437 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
1438 << timestamp.InMicroseconds() << "us)";
1441 seek_buffer_timestamp_ = timestamp;
1442 seek_pending_ = true;
1444 if (ShouldSeekToStartOfBuffered(timestamp)) {
1445 ranges_.front()->SeekToStart();
1446 SetSelectedRange(ranges_.front().get());
1447 seek_pending_ = false;
1451 auto itr = ranges_.end();
1452 for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1453 if ((*itr)->CanSeekTo(timestamp))
1457 if (itr == ranges_.end())
1460 if (!audio_configs_.empty()) {
1461 // Adjust |timestamp| for an Opus stream backward up to the config's seek
1462 // preroll, but not further than the range start time, and not at all if
1463 // there is a config change in the middle of that preroll interval. If
1464 // |timestamp| is already before the range start time, as can happen due to
1465 // fudge room, do not adjust it.
1466 const auto& config = audio_configs_[(*itr)->GetConfigIdAtTime(timestamp)];
1467 if (config.codec() == AudioCodec::kOpus &&
1468 timestamp > (*itr)->GetStartTimestamp()) {
1469 base::TimeDelta preroll_timestamp = std::max(
1470 timestamp - config.seek_preroll(), (*itr)->GetStartTimestamp());
1471 if ((*itr)->CanSeekTo(preroll_timestamp) &&
1472 (*itr)->SameConfigThruRange(preroll_timestamp, timestamp)) {
1473 timestamp = preroll_timestamp;
1478 SeekAndSetSelectedRange(itr->get(), timestamp);
1479 #if BUILDFLAG(IS_TIZEN_TV)
1480 // After seeking on audio stream coded with mpeg-h codec, there is a need to
1481 // one more time inject starting sequence to first frame.
1482 if (!audio_configs_.empty()) {
1483 const auto& config = audio_configs_[(*itr)->GetConfigIdAtTime(timestamp)];
1484 if (config.codec() == AudioCodec::kMpegHAudio) {
1485 (*itr)->ModifyFirstFrameForMpeghCodec();
1489 seek_pending_ = false;
1492 bool SourceBufferStream::IsSeekPending() const {
1493 return seek_pending_ && !IsEndOfStreamReached();
1496 // TODO(wolenetz): Disallow duration changes that truncate buffered media. See
1497 // https://crbug.com/623729.
1498 void SourceBufferStream::OnSetDuration(base::TimeDelta duration) {
1499 DVLOG(1) << __func__ << " " << GetStreamTypeName() << " ("
1500 << duration.InMicroseconds() << "us)";
1501 DCHECK(!end_of_stream_);
1503 if (ranges_.empty())
1506 base::TimeDelta start = duration;
1507 base::TimeDelta end = ranges_.back()->GetBufferedEndTimestamp();
1509 // Trim the end if it exceeds the new duration.
1511 BufferQueue deleted_buffers;
1512 RemoveInternal(start, end, false, &deleted_buffers);
1514 if (!deleted_buffers.empty()) {
1515 // Truncation removed current position. Clear selected range.
1516 SetSelectedRange(NULL);
1521 SourceBufferStreamStatus SourceBufferStream::GetNextBuffer(
1522 scoped_refptr<StreamParserBuffer>* out_buffer) {
1523 DVLOG(2) << __func__ << " " << GetStreamTypeName();
1524 if (!pending_buffer_.get()) {
1525 const SourceBufferStreamStatus status = GetNextBufferInternal(out_buffer);
1526 if (status != SourceBufferStreamStatus::kSuccess ||
1527 !SetPendingBuffer(out_buffer)) {
1528 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1529 << ": no pending buffer, returning status "
1530 << StatusToString(status);
1535 DCHECK(pending_buffer_->preroll_buffer().get());
1537 const SourceBufferStreamStatus status =
1538 HandleNextBufferWithPreroll(out_buffer);
1539 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1540 << ": handled next buffer with preroll, returning status "
1541 << StatusToString(status);
1545 SourceBufferStreamStatus SourceBufferStream::HandleNextBufferWithPreroll(
1546 scoped_refptr<StreamParserBuffer>* out_buffer) {
1547 // Any config change should have already been handled.
1548 DCHECK_EQ(current_config_index_, pending_buffer_->GetConfigId());
1550 // Check if the preroll buffer has already been handed out.
1551 if (!pending_buffers_complete_) {
1552 pending_buffers_complete_ = true;
1553 *out_buffer = pending_buffer_->preroll_buffer();
1554 return SourceBufferStreamStatus::kSuccess;
1557 // Preroll complete, hand out the final buffer.
1558 *out_buffer = std::move(pending_buffer_);
1559 return SourceBufferStreamStatus::kSuccess;
1562 SourceBufferStreamStatus SourceBufferStream::GetNextBufferInternal(
1563 scoped_refptr<StreamParserBuffer>* out_buffer) {
1564 CHECK(!config_change_pending_);
1566 if (!track_buffer_.empty()) {
1567 DCHECK(!selected_range_);
1569 if (track_buffer_.front()->GetConfigId() != current_config_index_) {
1570 config_change_pending_ = true;
1571 DVLOG(1) << "Config change (track buffer config ID does not match).";
1572 return SourceBufferStreamStatus::kConfigChange;
1575 DVLOG(3) << __func__ << " Next buffer coming from track_buffer_";
1576 *out_buffer = std::move(track_buffer_.front());
1577 track_buffer_.pop_front();
1578 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer);
1579 highest_output_buffer_timestamp_ =
1580 std::max(highest_output_buffer_timestamp_, (*out_buffer)->timestamp());
1582 // If the track buffer becomes empty, then try to set the selected range
1583 // based on the timestamp of this buffer being returned.
1584 if (track_buffer_.empty()) {
1585 just_exhausted_track_buffer_ = true;
1586 SetSelectedRangeIfNeeded(highest_output_buffer_timestamp_);
1589 return SourceBufferStreamStatus::kSuccess;
1592 DCHECK(track_buffer_.empty());
1593 if (!selected_range_ || !selected_range_->HasNextBuffer()) {
1594 if (IsEndOfStreamReached()) {
1595 return SourceBufferStreamStatus::kEndOfStream;
1597 DVLOG(3) << __func__ << " " << GetStreamTypeName()
1598 << ": returning kNeedBuffer "
1599 << (selected_range_ ? "(selected range has no next buffer)"
1600 : "(no selected range)");
1601 return SourceBufferStreamStatus::kNeedBuffer;
1604 if (selected_range_->GetNextConfigId() != current_config_index_) {
1605 config_change_pending_ = true;
1606 DVLOG(1) << "Config change (selected range config ID does not match).";
1607 return SourceBufferStreamStatus::kConfigChange;
1610 CHECK(selected_range_->GetNextBuffer(out_buffer));
1611 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer);
1612 highest_output_buffer_timestamp_ =
1613 std::max(highest_output_buffer_timestamp_, (*out_buffer)->timestamp());
1614 return SourceBufferStreamStatus::kSuccess;
1617 void SourceBufferStream::WarnIfTrackBufferExhaustionSkipsForward(
1618 scoped_refptr<StreamParserBuffer> next_buffer) {
1619 if (!just_exhausted_track_buffer_)
1622 just_exhausted_track_buffer_ = false;
1623 DCHECK(next_buffer->is_key_frame());
1624 base::TimeDelta next_output_buffer_timestamp = next_buffer->timestamp();
1625 base::TimeDelta delta =
1626 next_output_buffer_timestamp - highest_output_buffer_timestamp_;
1627 if (delta > GetMaxInterbufferDistance()) {
1628 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_track_buffer_gap_warning_logs_,
1629 kMaxTrackBufferGapWarningLogs)
1630 << "Media append that overlapped current playback position may cause "
1631 "time gap in playing "
1632 << GetStreamTypeName() << " stream because the next keyframe is "
1633 << delta.InMilliseconds()
1634 << "ms beyond last overlapped frame. Media may appear temporarily "
1639 bool SourceBufferStream::IsNextBufferConfigChanged() {
1640 if (!track_buffer_.empty())
1641 return track_buffer_.front()->GetConfigId() != current_config_index_;
1643 if (!selected_range_ || !selected_range_->HasNextBuffer())
1646 return selected_range_->GetNextConfigId() != current_config_index_;
1649 base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() {
1650 if (!track_buffer_.empty())
1651 return track_buffer_.front()->timestamp();
1653 if (!selected_range_)
1654 return kNoTimestamp;
1656 DCHECK(selected_range_->HasNextBufferPosition());
1657 return selected_range_->GetNextTimestamp();
1660 SourceBufferStream::RangeList::iterator
1661 SourceBufferStream::FindExistingRangeFor(base::TimeDelta start_timestamp) {
1662 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1663 if ((*itr)->BelongsToRange(start_timestamp))
1666 return ranges_.end();
1669 SourceBufferStream::RangeList::iterator SourceBufferStream::AddToRanges(
1670 std::unique_ptr<SourceBufferRange> new_range) {
1671 base::TimeDelta start_timestamp = new_range->GetStartTimestamp();
1672 auto itr = ranges_.end();
1673 for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1674 if ((*itr)->GetStartTimestamp() > start_timestamp)
1677 return ranges_.insert(itr, std::move(new_range));
1680 void SourceBufferStream::SeekAndSetSelectedRange(
1681 SourceBufferRange* range,
1682 base::TimeDelta seek_timestamp) {
1684 range->Seek(seek_timestamp);
1685 SetSelectedRange(range);
1688 void SourceBufferStream::SetSelectedRange(SourceBufferRange* range) {
1689 DVLOG(1) << __func__ << " " << GetStreamTypeName() << ": " << selected_range_
1690 << " " << (selected_range_ ? RangeToString(*selected_range_) : "")
1691 << " -> " << range << " " << (range ? RangeToString(*range) : "");
1692 if (selected_range_)
1693 selected_range_->ResetNextBufferPosition();
1694 DCHECK(!range || range->HasNextBufferPosition());
1695 selected_range_ = range;
1698 Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const {
1699 Ranges<base::TimeDelta> ranges;
1700 for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
1701 ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetBufferedEndTimestamp());
1706 base::TimeDelta SourceBufferStream::GetLowestPresentationTimestamp() const {
1707 if (ranges_.empty()) {
1708 return base::TimeDelta();
1711 return ranges_.front()->GetStartTimestamp();
1714 base::TimeDelta SourceBufferStream::GetHighestPresentationTimestamp() const {
1715 if (ranges_.empty())
1716 return base::TimeDelta();
1718 return ranges_.back()->GetEndTimestamp();
1721 base::TimeDelta SourceBufferStream::GetBufferedDuration() const {
1722 if (ranges_.empty())
1723 return base::TimeDelta();
1725 return ranges_.back()->GetBufferedEndTimestamp();
1728 size_t SourceBufferStream::GetBufferedSize() const {
1729 size_t ranges_size = 0;
1730 for (const auto& range_ptr : ranges_)
1731 ranges_size += range_ptr->size_in_bytes();
1735 void SourceBufferStream::MarkEndOfStream() {
1736 DCHECK(!end_of_stream_);
1737 end_of_stream_ = true;
1740 void SourceBufferStream::UnmarkEndOfStream() {
1741 DCHECK(end_of_stream_);
1742 end_of_stream_ = false;
1745 bool SourceBufferStream::IsEndOfStreamReached() const {
1746 if (!end_of_stream_ || !track_buffer_.empty())
1749 if (ranges_.empty())
1752 if (seek_pending_) {
1753 base::TimeDelta last_range_end_time =
1754 ranges_.back()->GetBufferedEndTimestamp();
1755 return seek_buffer_timestamp_ >= last_range_end_time;
1758 if (!selected_range_)
1761 return selected_range_ == ranges_.back().get();
1764 const AudioDecoderConfig& SourceBufferStream::GetCurrentAudioDecoderConfig() {
1765 if (config_change_pending_)
1766 CompleteConfigChange();
1767 // Trying to track down crash. http://crbug.com/715761
1768 CHECK(current_config_index_ >= 0 &&
1769 static_cast<size_t>(current_config_index_) < audio_configs_.size());
1770 return audio_configs_[current_config_index_];
1773 const VideoDecoderConfig& SourceBufferStream::GetCurrentVideoDecoderConfig() {
1774 if (config_change_pending_)
1775 CompleteConfigChange();
1776 // Trying to track down crash. http://crbug.com/715761
1777 CHECK(current_config_index_ >= 0 &&
1778 static_cast<size_t>(current_config_index_) < video_configs_.size());
1779 return video_configs_[current_config_index_];
1782 base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const {
1783 return max_interbuffer_distance_;
1786 #if BUILDFLAG(IS_TIZEN_TV)
1787 void SourceBufferStream::updateFramerate(
1788 const StreamFramerate::Framerate& framerate) {
1789 CHECK(current_config_index_ >= 0 &&
1790 static_cast<size_t>(current_config_index_) < video_configs_.size());
1792 video_configs_[current_config_index_].set_framerate_num(framerate.num);
1793 video_configs_[current_config_index_].set_framerate_den(framerate.den);
1797 bool SourceBufferStream::UpdateAudioConfig(const AudioDecoderConfig& config,
1798 bool allow_codec_change) {
1799 DCHECK(!audio_configs_.empty());
1800 DCHECK(video_configs_.empty());
1801 DVLOG(3) << "UpdateAudioConfig.";
1803 if (!allow_codec_change &&
1804 audio_configs_[append_config_index_].codec() != config.codec()) {
1805 // TODO(wolenetz): When we relax addSourceBuffer() and changeType() codec
1806 // strictness, codec changes should be allowed even without changing the
1808 // TODO(wolenetz): Remove "experimental" from this error message when
1809 // changeType() ships without needing experimental blink flag.
1810 MEDIA_LOG(ERROR, media_log_) << "Audio codec changes not allowed unless "
1811 "using experimental changeType().";
1815 // Check to see if the new config matches an existing one.
1816 for (size_t i = 0; i < audio_configs_.size(); ++i) {
1817 if (config.Matches(audio_configs_[i])) {
1818 append_config_index_ = i;
1823 // No matches found so let's add this one to the list.
1824 append_config_index_ = audio_configs_.size();
1825 DVLOG(2) << "New audio config - index: " << append_config_index_;
1826 audio_configs_.resize(audio_configs_.size() + 1);
1827 audio_configs_[append_config_index_] = config;
1831 bool SourceBufferStream::UpdateVideoConfig(const VideoDecoderConfig& config,
1832 bool allow_codec_change) {
1833 DCHECK(!video_configs_.empty());
1834 DCHECK(audio_configs_.empty());
1835 DVLOG(3) << "UpdateVideoConfig.";
1837 if (!allow_codec_change &&
1838 video_configs_[append_config_index_].codec() != config.codec()) {
1839 // TODO(wolenetz): When we relax addSourceBuffer() and changeType() codec
1840 // strictness, codec changes should be allowed even without changing the
1842 // TODO(wolenetz): Remove "experimental" from this error message when
1843 // changeType() ships without needing experimental blink flag.
1844 MEDIA_LOG(ERROR, media_log_) << "Video codec changes not allowed unless "
1845 "using experimental changeType()";
1849 // Check to see if the new config matches an existing one.
1850 for (size_t i = 0; i < video_configs_.size(); ++i) {
1851 if (config.Matches(video_configs_[i])) {
1852 append_config_index_ = i;
1857 // No matches found so let's add this one to the list.
1858 append_config_index_ = video_configs_.size();
1859 DVLOG(2) << "New video config - index: " << append_config_index_;
1860 video_configs_.resize(video_configs_.size() + 1);
1861 video_configs_[append_config_index_] = config;
1862 #if BUILDFLAG(IS_TIZEN_TV)
1863 size_t updated_memory_limit = UpdateDemuxerStreamVideoMemoryLimit(&config);
1864 memory_limit_ = std::max(memory_limit_, updated_memory_limit);
1869 void SourceBufferStream::CompleteConfigChange() {
1870 config_change_pending_ = false;
1872 if (!track_buffer_.empty()) {
1873 current_config_index_ = track_buffer_.front()->GetConfigId();
1877 if (selected_range_ && selected_range_->HasNextBuffer())
1878 current_config_index_ = selected_range_->GetNextConfigId();
1881 void SourceBufferStream::SetSelectedRangeIfNeeded(
1882 const base::TimeDelta timestamp) {
1883 DVLOG(2) << __func__ << " " << GetStreamTypeName() << "("
1884 << timestamp.InMicroseconds() << "us)";
1886 if (selected_range_) {
1887 DCHECK(track_buffer_.empty());
1891 if (!track_buffer_.empty()) {
1892 DCHECK(!selected_range_);
1896 base::TimeDelta start_timestamp = timestamp;
1898 // If the next buffer timestamp is not known then use a timestamp just after
1899 // the timestamp on the last buffer returned by GetNextBuffer().
1900 if (start_timestamp == kNoTimestamp) {
1901 if (highest_output_buffer_timestamp_ == kNoTimestamp) {
1902 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1903 << " no previous output timestamp";
1907 start_timestamp = highest_output_buffer_timestamp_ + base::Microseconds(1);
1910 base::TimeDelta seek_timestamp =
1911 FindNewSelectedRangeSeekTimestamp(start_timestamp);
1913 // If we don't have buffered data to seek to, then return.
1914 if (seek_timestamp == kNoTimestamp) {
1915 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1916 << " couldn't find new selected range seek timestamp";
1920 DCHECK(track_buffer_.empty());
1921 SeekAndSetSelectedRange(FindExistingRangeFor(seek_timestamp)->get(),
1925 base::TimeDelta SourceBufferStream::FindNewSelectedRangeSeekTimestamp(
1926 const base::TimeDelta start_timestamp) {
1927 DCHECK(start_timestamp != kNoTimestamp);
1928 DCHECK(start_timestamp >= base::TimeDelta());
1930 auto itr = ranges_.begin();
1932 // When checking a range to see if it has or begins soon enough after
1933 // |start_timestamp|, use the fudge room to determine "soon enough".
1934 base::TimeDelta start_timestamp_plus_fudge =
1935 start_timestamp + ComputeFudgeRoom(GetMaxInterbufferDistance());
1937 // Multiple ranges could be within the fudge room, because the fudge room is
1938 // dynamic based on max inter-buffer distance seen so far. Optimistically
1939 // check the earliest ones first.
1940 for (; itr != ranges_.end(); ++itr) {
1941 base::TimeDelta range_start = (*itr)->GetStartTimestamp();
1942 if (range_start >= start_timestamp_plus_fudge)
1944 if ((*itr)->GetEndTimestamp() < start_timestamp)
1946 base::TimeDelta search_timestamp = start_timestamp;
1947 if (start_timestamp < range_start &&
1948 start_timestamp_plus_fudge >= range_start) {
1949 search_timestamp = range_start;
1951 base::TimeDelta keyframe_timestamp =
1952 (*itr)->NextKeyframeTimestamp(search_timestamp);
1953 if (keyframe_timestamp != kNoTimestamp)
1954 return keyframe_timestamp;
1957 DVLOG(2) << __func__ << " " << GetStreamTypeName()
1958 << " no buffered data for pts=" << start_timestamp.InMicroseconds()
1960 return kNoTimestamp;
1963 base::TimeDelta SourceBufferStream::FindKeyframeAfterTimestamp(
1964 const base::TimeDelta timestamp) {
1965 DCHECK(timestamp != kNoTimestamp);
1967 auto itr = FindExistingRangeFor(timestamp);
1969 if (itr == ranges_.end())
1970 return kNoTimestamp;
1972 // First check for a keyframe timestamp >= |timestamp|
1973 // in the current range.
1974 return (*itr)->NextKeyframeTimestamp(timestamp);
1977 std::string SourceBufferStream::GetStreamTypeName() const {
1978 switch (GetType()) {
1979 case SourceBufferStreamType::kAudio:
1981 case SourceBufferStreamType::kVideo:
1984 NOTREACHED_NORETURN();
1987 SourceBufferStreamType SourceBufferStream::GetType() const {
1988 if (!audio_configs_.empty())
1989 return SourceBufferStreamType::kAudio;
1990 DCHECK(!video_configs_.empty());
1991 return SourceBufferStreamType::kVideo;
1994 void SourceBufferStream::DeleteAndRemoveRange(RangeList::iterator* itr) {
1995 DVLOG(1) << __func__;
1997 DCHECK(*itr != ranges_.end());
1998 if ((*itr)->get() == selected_range_) {
1999 DVLOG(1) << __func__ << " deleting selected range.";
2000 SetSelectedRange(NULL);
2003 if (*itr == range_for_next_append_) {
2004 DVLOG(1) << __func__ << " deleting range_for_next_append_.";
2005 range_for_next_append_ = ranges_.end();
2006 ResetLastAppendedState();
2009 *itr = ranges_.erase(*itr);
2012 bool SourceBufferStream::SetPendingBuffer(
2013 scoped_refptr<StreamParserBuffer>* out_buffer) {
2014 DCHECK(out_buffer->get());
2015 DCHECK(!pending_buffer_.get());
2017 const bool have_preroll_buffer = !!(*out_buffer)->preroll_buffer().get();
2019 if (!have_preroll_buffer)
2022 pending_buffer_.swap(*out_buffer);
2023 pending_buffers_complete_ = false;
2027 } // namespace media