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

Unified Diff: media/filters/source_buffer_stream.cc

Issue 1670033002: Reland: MSE: Relax the 'media segment must begin with keyframe' requirement (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Undid patch set 9's test change, since FrameProcessor *can* produce that output Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/source_buffer_stream.cc
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index d2b4fae6e5fc56a902d344cf03e69ac027355fc9..e03a8c38ab8e92d920fc73ac501b2ca38d67af38 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -37,6 +37,15 @@ const int kMaxTrackBufferGapWarningLogs = 20;
// Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings.
const int kMaxGarbageCollectAlgorithmWarningLogs = 20;
+// Limit the number of MEDIA_LOG() logs for same DTS for non-keyframe followed
+// by keyframe. Prior to relaxing the "media segments must begin with a
+// keyframe" requirement, we issued decode error for this situation. That was
+// likely too strict, and now that the keyframe requirement is relaxed, we have
+// no knowledge of media segment boundaries here. Now, we log but don't trigger
+// decode error, since we allow these sequences which may cause extra decoder
+// work or other side-effects.
+const int kMaxStrangeSameTimestampsLogs = 20;
+
// Helper method that returns true if |ranges| is sorted in increasing order,
// false otherwise.
bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) {
@@ -137,7 +146,7 @@ SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
bool splice_frames_enabled)
: media_log_(media_log),
seek_buffer_timestamp_(kNoTimestamp()),
- media_segment_start_time_(kNoDecodeTimestamp()),
+ coded_frame_group_start_time_(kNoDecodeTimestamp()),
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp()),
@@ -152,7 +161,7 @@ SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
bool splice_frames_enabled)
: media_log_(media_log),
seek_buffer_timestamp_(kNoTimestamp()),
- media_segment_start_time_(kNoDecodeTimestamp()),
+ coded_frame_group_start_time_(kNoDecodeTimestamp()),
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp()),
@@ -168,7 +177,7 @@ SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
: media_log_(media_log),
text_track_config_(text_config),
seek_buffer_timestamp_(kNoTimestamp()),
- media_segment_start_time_(kNoDecodeTimestamp()),
+ coded_frame_group_start_time_(kNoDecodeTimestamp()),
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp()),
@@ -182,26 +191,29 @@ SourceBufferStream::~SourceBufferStream() {
}
}
-void SourceBufferStream::OnNewMediaSegment(
- DecodeTimestamp media_segment_start_time) {
- DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
- << " (" << media_segment_start_time.InSecondsF() << ")";
+void SourceBufferStream::OnStartOfCodedFrameGroup(
+ DecodeTimestamp coded_frame_group_start_time) {
+ DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << " ("
+ << coded_frame_group_start_time.InSecondsF() << ")";
DCHECK(!end_of_stream_);
- media_segment_start_time_ = media_segment_start_time;
- new_media_segment_ = true;
+ coded_frame_group_start_time_ = coded_frame_group_start_time;
+ new_coded_frame_group_ = true;
RangeList::iterator last_range = range_for_next_append_;
- range_for_next_append_ = FindExistingRangeFor(media_segment_start_time);
+ range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_time);
- // Only reset |last_appended_buffer_timestamp_| if this new media segment is
- // not adjacent to the previous media segment appended to the stream.
+ // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
+ // is not adjacent to the previous coded frame group appended to the stream.
if (range_for_next_append_ == ranges_.end() ||
!AreAdjacentInSequence(last_appended_buffer_timestamp_,
- media_segment_start_time)) {
+ coded_frame_group_start_time)) {
last_appended_buffer_timestamp_ = kNoDecodeTimestamp();
last_appended_buffer_duration_ = kNoTimestamp();
last_appended_buffer_is_keyframe_ = false;
- DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range";
+ DVLOG(3) << __FUNCTION__ << " next appended buffers will "
+ << (range_for_next_append_ == ranges_.end()
+ ? "be in a new range"
+ : "overlap an existing range");
} else if (last_range != ranges_.end()) {
DCHECK(last_range == range_for_next_append_);
DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range "
@@ -215,41 +227,29 @@ bool SourceBufferStream::Append(const BufferQueue& buffers) {
"buffers to append", buffers.size());
DCHECK(!buffers.empty());
- DCHECK(media_segment_start_time_ != kNoDecodeTimestamp());
- DCHECK(media_segment_start_time_ <= buffers.front()->GetDecodeTimestamp());
+ DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
+ DCHECK(coded_frame_group_start_time_ <=
+ buffers.front()->GetDecodeTimestamp());
DCHECK(!end_of_stream_);
DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
<< ": buffers " << BufferQueueToLogString(buffers);
- // New media segments must begin with a keyframe.
- // TODO(wolenetz): Relax this requirement. See http://crbug.com/229412.
- if (new_media_segment_ && !buffers.front()->is_key_frame()) {
- MEDIA_LOG(ERROR, media_log_) << "Media segment did not begin with key "
- "frame. Support for such segments will be "
- "available in a future version. Please see "
- "https://crbug.com/229412.";
- return false;
- }
-
- // Buffers within a media segment should be monotonically increasing.
- if (!IsMonotonicallyIncreasing(buffers))
- return false;
+ // New coded frame groups emitted by the coded frame processor must begin with
+ // a keyframe. TODO(wolenetz): Change this to [DCHECK + MEDIA_LOG(ERROR...) +
+ // return false] once the CHECK has baked in a stable release. See
+ // https://crbug.com/580621.
+ CHECK(!new_coded_frame_group_ || buffers.front()->is_key_frame());
- if (media_segment_start_time_ < DecodeTimestamp() ||
- buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) {
- MEDIA_LOG(ERROR, media_log_)
- << "Cannot append a media segment with negative timestamps.";
+ // Buffers within a coded frame group should be monotonically increasing.
+ if (!IsMonotonicallyIncreasing(buffers)) {
return false;
}
- if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(),
- buffers.front()->is_key_frame())) {
- const DecodeTimestamp& dts = buffers.front()->GetDecodeTimestamp();
+ if (coded_frame_group_start_time_ < DecodeTimestamp() ||
+ buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) {
MEDIA_LOG(ERROR, media_log_)
- << "Invalid same timestamp construct detected at"
- << " time " << dts.InSecondsF();
-
+ << "Cannot append a coded frame group with negative timestamps.";
return false;
}
@@ -265,21 +265,40 @@ bool SourceBufferStream::Append(const BufferQueue& buffers) {
// If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
// create a new range with |buffers|.
if (range_for_next_append_ != ranges_.end()) {
- (*range_for_next_append_)->AppendBuffersToEnd(buffers);
+ if (new_coded_frame_group_ && (!splice_frames_enabled_ ||
+ buffers.front()->splice_buffers().empty())) {
+ // If the first append to this stream in a new coded frame group continues
+ // a previous range, use the new group's start time instead of the first
+ // new buffer's timestamp as the proof of adjacency to the existing range.
+ // A large gap (larger than our normal buffer adjacency test) can occur in
+ // a muxed set of streams (which share a common coded frame group start
+ // time) with a significantly jagged start across the streams.
+ // Don't do this logic if there was a splice frame generated for the first
+ // new buffer, since splices are guaranteed to be in the same range and
+ // adjacent, and since the splice frame's timestamp can be less than
+ // |coded_frame_group_start_time_| due to the splicing.
+ (*range_for_next_append_)
+ ->AppendBuffersToEnd(buffers, coded_frame_group_start_time_);
+ } else {
+ // Otherwise, use the first new buffer's timestamp as the proof of
+ // adjacency.
+ (*range_for_next_append_)
+ ->AppendBuffersToEnd(buffers, kNoDecodeTimestamp());
+ }
+
last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
last_appended_buffer_duration_ = buffers.back()->duration();
last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
} else {
DecodeTimestamp new_range_start_time = std::min(
- media_segment_start_time_, buffers.front()->GetDecodeTimestamp());
+ coded_frame_group_start_time_, buffers.front()->GetDecodeTimestamp());
const BufferQueue* buffers_for_new_range = &buffers;
BufferQueue trimmed_buffers;
- // If the new range is not being created because of a new media
- // segment, then we must make sure that we start with a key frame.
- // This can happen if the GOP in the previous append gets destroyed
- // by a Remove() call.
- if (!new_media_segment_) {
+ // If the new range is not being created because of a new coded frame group,
+ // then we must make sure that we start with a key frame. This can happen
+ // if the GOP in the previous append gets destroyed by a Remove() call.
+ if (!new_coded_frame_group_) {
BufferQueue::const_iterator itr = buffers.begin();
// Scan past all the non-key-frames.
@@ -294,7 +313,7 @@ bool SourceBufferStream::Append(const BufferQueue& buffers) {
last_appended_buffer_duration_ = buffers.back()->duration();
last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
- << ": new buffers in the middle of media segment depend on"
+ << ": new buffers in the middle of coded frame group depend on"
"keyframe that has been removed, and contain no keyframes."
"Skipping further processing.";
DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
@@ -324,7 +343,7 @@ bool SourceBufferStream::Append(const BufferQueue& buffers) {
buffers_for_new_range->back()->is_key_frame();
}
- new_media_segment_ = false;
+ new_coded_frame_group_ = false;
MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
@@ -413,6 +432,28 @@ void SourceBufferStream::Remove(base::TimeDelta start, base::TimeDelta end,
}
}
+DecodeTimestamp SourceBufferStream::PotentialNextAppendTimestamp() const {
+ // The next potential append will either be just at or after
+ // |last_appended_buffer_timestamp_| (if known), or if unknown and we are
+ // still at the beginning of a new coded frame group, then will be into the
+ // range (if any) to which |coded_frame_group_start_time_| belongs.
+ if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp()) {
+ // TODO(wolenetz): Determine if this +1us is still necessary. See
+ // https://crbug.com/589295.
+ return last_appended_buffer_timestamp_ +
+ base::TimeDelta::FromInternalValue(1);
+ }
+
+ if (new_coded_frame_group_)
+ return coded_frame_group_start_time_;
+
+ // If we still don't know a potential next append timestamp, then we have
+ // removed the ranged to which it previously belonged and have not completed a
+ // subsequent append or received a subsequent OnStartOfCodedFrameGroup()
+ // signal.
+ return kNoDecodeTimestamp();
+}
+
void SourceBufferStream::RemoveInternal(DecodeTimestamp start,
DecodeTimestamp end,
bool exclude_start,
@@ -440,6 +481,19 @@ void SourceBufferStream::RemoveInternal(DecodeTimestamp start,
SourceBufferRange* new_range = range->SplitRange(end);
if (new_range) {
itr = ranges_.insert(++itr, new_range);
+
+ // Update |range_for_next_append_| if it was previously |range| and should
+ // be |new_range| now.
+ if (range_for_next_append_ != ranges_.end() &&
+ *range_for_next_append_ == range) {
+ DecodeTimestamp potential_next_append_timestamp =
+ PotentialNextAppendTimestamp();
+ if (potential_next_append_timestamp != kNoDecodeTimestamp() &&
+ new_range->BelongsToRange(potential_next_append_timestamp)) {
+ range_for_next_append_ = itr;
+ }
+ }
+
--itr;
// Update the selected range if the next buffer position was transferred
@@ -476,11 +530,9 @@ void SourceBufferStream::RemoveInternal(DecodeTimestamp start,
// operation makes it impossible for the next append to be added
// to the current range.
if (range_for_next_append_ != ranges_.end() &&
- *range_for_next_append_ == range &&
- last_appended_buffer_timestamp_ != kNoDecodeTimestamp()) {
+ *range_for_next_append_ == range) {
DecodeTimestamp potential_next_append_timestamp =
- last_appended_buffer_timestamp_ +
- base::TimeDelta::FromInternalValue(1);
+ PotentialNextAppendTimestamp();
if (!range->BelongsToRange(potential_next_append_timestamp)) {
DVLOG(1) << "Resetting range_for_next_append_ since the next append"
@@ -522,8 +574,7 @@ bool SourceBufferStream::ShouldSeekToStartOfBuffered(
beginning_of_buffered < kSeekToStartFudgeRoom());
}
-bool SourceBufferStream::IsMonotonicallyIncreasing(
- const BufferQueue& buffers) const {
+bool SourceBufferStream::IsMonotonicallyIncreasing(const BufferQueue& buffers) {
DCHECK(!buffers.empty());
DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_;
bool prev_is_keyframe = last_appended_buffer_is_keyframe_;
@@ -546,12 +597,13 @@ bool SourceBufferStream::IsMonotonicallyIncreasing(
}
if (current_timestamp == prev_timestamp &&
- !SourceBufferRange::AllowSameTimestamp(prev_is_keyframe,
- current_is_keyframe)) {
- MEDIA_LOG(ERROR, media_log_) << "Unexpected combination of buffers with"
- << " the same timestamp detected at "
- << current_timestamp.InSecondsF();
- return false;
+ SourceBufferRange::IsUncommonSameTimestampSequence(
+ prev_is_keyframe, current_is_keyframe)) {
+ LIMITED_MEDIA_LOG(DEBUG, media_log_, num_strange_same_timestamps_logs_,
+ kMaxStrangeSameTimestampsLogs)
+ << "Detected an append sequence with keyframe following a "
+ "non-keyframe, both with the same decode timestamp of "
+ << current_timestamp.InSecondsF();
}
}
@@ -561,15 +613,6 @@ bool SourceBufferStream::IsMonotonicallyIncreasing(
return true;
}
-bool SourceBufferStream::IsNextTimestampValid(
- DecodeTimestamp next_timestamp, bool next_is_keyframe) const {
- return (last_appended_buffer_timestamp_ != next_timestamp) ||
- new_media_segment_ ||
- SourceBufferRange::AllowSameTimestamp(last_appended_buffer_is_keyframe_,
- next_is_keyframe);
-}
-
-
bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
for (RangeList::const_iterator itr = ranges_.begin();
itr != ranges_.end(); ++itr) {
@@ -938,9 +981,7 @@ void SourceBufferStream::PrepareRangesForNextAppend(
GenerateSpliceFrame(new_buffers);
DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_;
- bool prev_is_keyframe = last_appended_buffer_is_keyframe_;
DecodeTimestamp next_timestamp = new_buffers.front()->GetDecodeTimestamp();
- bool next_is_keyframe = new_buffers.front()->is_key_frame();
if (prev_timestamp != kNoDecodeTimestamp() &&
prev_timestamp != next_timestamp) {
@@ -949,22 +990,25 @@ void SourceBufferStream::PrepareRangesForNextAppend(
RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers);
}
- // Make the delete range exclusive if we are dealing with an allowed same
- // timestamp situation. This prevents the first buffer in the current append
- // from deleting the last buffer in the previous append if both buffers
- // have the same timestamp.
- //
- // The delete range should never be exclusive if a splice frame was generated
- // because we don't generate splice frames for same timestamp situations.
+ // Always make the start of the delete range exclusive for same timestamp
+ // across the last buffer in the previous append and the first buffer in the
+ // current append. Never be exclusive if a splice frame was generated because
+ // we don't generate splice frames for same timestamp situations.
DCHECK(new_buffers.front()->splice_timestamp() !=
new_buffers.front()->timestamp());
- const bool exclude_start =
- new_buffers.front()->splice_buffers().empty() &&
- prev_timestamp == next_timestamp &&
- SourceBufferRange::AllowSameTimestamp(prev_is_keyframe, next_is_keyframe);
+ const bool exclude_start = new_buffers.front()->splice_buffers().empty() &&
+ prev_timestamp == next_timestamp;
// Delete the buffers that |new_buffers| overlaps.
DecodeTimestamp start = new_buffers.front()->GetDecodeTimestamp();
+ if (new_coded_frame_group_) {
+ // Extend the deletion range earlier to the coded frame group start time if
+ // this is the first append in a new coded frame group. Note that |start|
+ // could already be less than |coded_frame_group_start_time_| if a splice
+ // was generated.
+ DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
+ start = std::min(coded_frame_group_start_time_, start);
+ }
DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp();
base::TimeDelta duration = new_buffers.back()->duration();
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698