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

Unified Diff: media/filters/source_buffer_stream.cc

Issue 2343543002: MSE: Replace crossfade splicing overlap trimming. (Closed)
Patch Set: Created 4 years, 3 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
Index: media/filters/source_buffer_stream.cc
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index a57c11278e7af5d306531802f211c4fc9f63ec4c..62930c15f4ccc718d6d80c96de18ea62bc18f96d 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <map>
#include <sstream>
+#include <string>
#include "base/bind.h"
#include "base/logging.h"
@@ -24,19 +25,15 @@ namespace {
// set and there's not enough information to get a better estimate.
const int kDefaultBufferDurationInMs = 125;
-// Limit the number of MEDIA_LOG() logs for splice buffer generation warnings
-// and successes. Though these values are high enough to possibly exhaust the
-// media internals event cache (along with other events), these logs are
-// important for debugging splice generation.
-const int kMaxSpliceGenerationWarningLogs = 50;
-const int kMaxSpliceGenerationSuccessLogs = 20;
-
// Limit the number of MEDIA_LOG() logs for track buffer time gaps.
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 generated splice silence.
+const int kMaxSpliceGenerationLogs = 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
@@ -142,38 +139,33 @@ SourceBufferRange::GapPolicy TypeToGapPolicy(SourceBufferStream::Type type) {
} // namespace
SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
- const scoped_refptr<MediaLog>& media_log,
- bool splice_frames_enabled)
+ const scoped_refptr<MediaLog>& media_log)
: media_log_(media_log),
seek_buffer_timestamp_(kNoTimestamp),
coded_frame_group_start_time_(kNoDecodeTimestamp()),
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp),
- memory_limit_(kSourceBufferAudioMemoryLimit),
- splice_frames_enabled_(splice_frames_enabled) {
+ memory_limit_(kSourceBufferAudioMemoryLimit) {
DCHECK(audio_config.IsValidConfig());
audio_configs_.push_back(audio_config);
}
SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
- const scoped_refptr<MediaLog>& media_log,
- bool splice_frames_enabled)
+ const scoped_refptr<MediaLog>& media_log)
: media_log_(media_log),
seek_buffer_timestamp_(kNoTimestamp),
coded_frame_group_start_time_(kNoDecodeTimestamp()),
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp),
- memory_limit_(kSourceBufferVideoMemoryLimit),
- splice_frames_enabled_(splice_frames_enabled) {
+ memory_limit_(kSourceBufferVideoMemoryLimit) {
DCHECK(video_config.IsValidConfig());
video_configs_.push_back(video_config);
}
SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
- const scoped_refptr<MediaLog>& media_log,
- bool splice_frames_enabled)
+ const scoped_refptr<MediaLog>& media_log)
: media_log_(media_log),
text_track_config_(text_config),
seek_buffer_timestamp_(kNoTimestamp),
@@ -181,8 +173,7 @@ SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
range_for_next_append_(ranges_.end()),
last_output_buffer_timestamp_(kNoDecodeTimestamp()),
max_interbuffer_distance_(kNoTimestamp),
- memory_limit_(kSourceBufferAudioMemoryLimit),
- splice_frames_enabled_(splice_frames_enabled) {}
+ memory_limit_(kSourceBufferAudioMemoryLimit) {}
SourceBufferStream::~SourceBufferStream() {
while (!ranges_.empty()) {
@@ -265,15 +256,15 @@ 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()) {
- if (new_coded_frame_group_ && (!splice_frames_enabled_ ||
- buffers.front()->splice_buffers().empty())) {
+ if (new_coded_frame_group_ &&
+ buffers.front()->leading_silence() == base::TimeDelta()) {
// 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
+ // Don't do this logic if splice silence was 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.
@@ -969,51 +960,117 @@ size_t SourceBufferStream::FreeBuffers(size_t total_bytes_to_free,
return bytes_freed;
}
+void SourceBufferStream::GenerateSpliceSilence(const BufferQueue& new_buffers) {
+ DCHECK(!new_buffers.empty());
+
+ // Find the overlapped range (if any).
+ const base::TimeDelta splice_timestamp = new_buffers.front()->timestamp();
+ const DecodeTimestamp splice_dts =
+ DecodeTimestamp::FromPresentationTime(splice_timestamp);
+ RangeList::iterator range_itr = FindExistingRangeFor(splice_dts);
+ if (range_itr == ranges_.end()) {
+ DVLOG(3) << __func__ << " Not generating splice. No range overlap at time "
+ << splice_timestamp.InMicroseconds();
+ return;
+ }
+
+ // Search for overlapped buffer needs exclusive end value. Choosing smallest
+ // possible value.
+ const DecodeTimestamp end_dts =
+ splice_dts + base::TimeDelta::FromInternalValue(1);
+
+ // Find if new buffer's start would overlap an existing buffer.
+ BufferQueue pre_splice_buffers;
+ if (!(*range_itr)
+ ->GetBuffersInRange(splice_dts, end_dts, &pre_splice_buffers)) {
+ // Bail if no overlapped buffers found.
+ DVLOG(3) << __func__ << " Not generating splice. No buffer overlap at time "
+ << splice_timestamp.InMicroseconds();
+ return;
+ }
+
+ // At most one buffer should exist containing the time of the newly appended
+ // buffer's start. GetBuffersInRange does not currently return buffers with
+ // zero duration.
+ DCHECK_EQ(pre_splice_buffers.size(), 1U)
+ << __func__ << " Found more than one overlapped buffer";
+
+ base::TimeDelta leading_silence = new_buffers.front()->timestamp() -
+ pre_splice_buffers.front()->timestamp();
+ DCHECK_GE(leading_silence, base::TimeDelta());
+
+ if (leading_silence == base::TimeDelta()) {
+ DVLOG(3) << __func__ << " Not generating splice for exact overlap at time "
+ << splice_timestamp.InMicroseconds();
+ return;
+ }
+
+ // Pad front of new buffers with leading silence and update front timestamp
+ // and duration. The overlapped buffer will be deleted in
+ // PrepareRangesForNewAppend.
+ new_buffers.front()->set_leading_silence(leading_silence);
+ new_buffers.front()->SetDecodeTimestamp(
+ new_buffers.front()->GetDecodeTimestamp() - leading_silence);
+ new_buffers.front()->set_timestamp(new_buffers.front()->timestamp() -
+ leading_silence);
+ new_buffers.front()->set_duration(new_buffers.front()->duration() +
+ leading_silence);
+
+ std::stringstream log_string;
+ log_string << "Generated splice for overlapping audio buffer at time:"
+ << splice_timestamp.InMicroseconds()
+ << "mu. Adding silence of length:"
+ << leading_silence.InMicroseconds()
+ << "mu to replace overlapped buffer at time:"
+ << pre_splice_buffers.front()->timestamp().InMicroseconds()
+ << "mu.";
+ LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_logs_,
+ kMaxSpliceGenerationLogs)
+ << log_string.str();
+ LOG(ERROR) << __func__ << log_string.str();
+}
+
void SourceBufferStream::PrepareRangesForNextAppend(
const BufferQueue& new_buffers, BufferQueue* deleted_buffers) {
DCHECK(deleted_buffers);
- // Handle splices between the existing buffers and the new buffers. If a
- // splice is generated the timestamp and duration of the first buffer in
- // |new_buffers| will be modified.
- if (splice_frames_enabled_)
- GenerateSpliceFrame(new_buffers);
+ if (GetType() == kAudio)
+ GenerateSpliceSilence(new_buffers);
+ base::TimeDelta prev_duration = last_appended_buffer_duration_;
DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_;
DecodeTimestamp next_timestamp = new_buffers.front()->GetDecodeTimestamp();
+ // 1. Clean up the old buffers between the last appended buffer and the
+ // beginning of |new_buffers|.
if (prev_timestamp != kNoDecodeTimestamp() &&
prev_timestamp != next_timestamp) {
- // Clean up the old buffers between the last appended buffer and the
- // beginning of |new_buffers|.
RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers);
}
- // 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;
-
- // Delete the buffers that |new_buffers| overlaps.
- DecodeTimestamp start = new_buffers.front()->GetDecodeTimestamp();
+ // 2. Delete the buffers that |new_buffers| overlaps.
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.
+ // this is the first append in a new coded frame group. Note that
+ // |next_timestamp| could already be less than
+ // |coded_frame_group_start_time_| if splice silence was generated.
DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
- start = std::min(coded_frame_group_start_time_, start);
+ next_timestamp = std::min(coded_frame_group_start_time_, next_timestamp);
}
- DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp();
- base::TimeDelta duration = new_buffers.back()->duration();
+
+ // Exclude the start timestamp from removal if the previous append is a zero
+ // duration frame with the same timestamp as the current append. This avoids
+ // deleting zero-duration VP9 alt-ref frames while still deleting frames
+ // with non-zero duration that are now overlapped (potentially due to
+ // generated splice silence).
+ const bool exclude_start =
+ prev_timestamp == next_timestamp && prev_duration == base::TimeDelta();
// Set end time for remove to include the duration of last buffer. If the
// duration is estimated, use 1 microsecond instead to ensure frames are not
// accidentally removed due to over-estimation.
+ DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp();
+ base::TimeDelta duration = new_buffers.back()->duration();
if (duration != kNoTimestamp && duration > base::TimeDelta() &&
!new_buffers.back()->is_duration_estimated()) {
end += duration;
@@ -1023,7 +1080,8 @@ void SourceBufferStream::PrepareRangesForNextAppend(
end += base::TimeDelta::FromInternalValue(1);
}
- RemoveInternal(start, end, exclude_start, deleted_buffers);
+ // Finally do the deletion of overlap.
+ RemoveInternal(next_timestamp, end, exclude_start, deleted_buffers);
}
bool SourceBufferStream::AreAdjacentInSequence(
@@ -1692,112 +1750,6 @@ void SourceBufferStream::DeleteAndRemoveRange(RangeList::iterator* itr) {
*itr = ranges_.erase(*itr);
}
-void SourceBufferStream::GenerateSpliceFrame(const BufferQueue& new_buffers) {
- DCHECK(!new_buffers.empty());
-
- // Splice frames are only supported for audio.
- if (GetType() != kAudio)
- return;
-
- // Find the overlapped range (if any).
- const base::TimeDelta splice_timestamp = new_buffers.front()->timestamp();
- const DecodeTimestamp splice_dts =
- DecodeTimestamp::FromPresentationTime(splice_timestamp);
- RangeList::iterator range_itr = FindExistingRangeFor(splice_dts);
- if (range_itr == ranges_.end())
- return;
-
- const DecodeTimestamp max_splice_end_dts =
- splice_dts + base::TimeDelta::FromMilliseconds(
- AudioSplicer::kCrossfadeDurationInMilliseconds);
-
- // Find all buffers involved before the splice point.
- BufferQueue pre_splice_buffers;
- if (!(*range_itr)->GetBuffersInRange(
- splice_dts, max_splice_end_dts, &pre_splice_buffers)) {
- return;
- }
-
- // If there are gaps in the timeline, it's possible that we only find buffers
- // after the splice point but within the splice range. For simplicity, we do
- // not generate splice frames in this case.
- //
- // We also do not want to generate splices if the first new buffer replaces an
- // existing buffer exactly.
- if (pre_splice_buffers.front()->timestamp() >= splice_timestamp) {
- LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_warning_logs_,
- kMaxSpliceGenerationWarningLogs)
- << "Skipping splice frame generation: first new buffer at "
- << splice_timestamp.InMicroseconds()
- << "us begins at or before existing buffer at "
- << pre_splice_buffers.front()->timestamp().InMicroseconds() << "us.";
- DVLOG(1) << "Skipping splice: overlapped buffers begin at or after the "
- "first new buffer.";
- return;
- }
-
- // If any |pre_splice_buffers| are already splices or preroll, do not generate
- // a splice.
- for (size_t i = 0; i < pre_splice_buffers.size(); ++i) {
- const BufferQueue& original_splice_buffers =
- pre_splice_buffers[i]->splice_buffers();
- if (!original_splice_buffers.empty()) {
- LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_warning_logs_,
- kMaxSpliceGenerationWarningLogs)
- << "Skipping splice frame generation: overlapped buffers at "
- << pre_splice_buffers[i]->timestamp().InMicroseconds()
- << "us are in a previously buffered splice.";
- DVLOG(1) << "Can't generate splice: overlapped buffers contain a "
- "pre-existing splice.";
- return;
- }
-
- if (pre_splice_buffers[i]->preroll_buffer().get()) {
- LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_warning_logs_,
- kMaxSpliceGenerationWarningLogs)
- << "Skipping splice frame generation: overlapped buffers at "
- << pre_splice_buffers[i]->timestamp().InMicroseconds()
- << "us contain preroll.";
- DVLOG(1) << "Can't generate splice: overlapped buffers contain preroll.";
- return;
- }
- }
-
- // Don't generate splice frames which represent less than a millisecond (which
- // is frequently the extent of timestamp resolution for poorly encoded media)
- // or less than two samples (need at least two to crossfade).
- const base::TimeDelta splice_duration =
- pre_splice_buffers.back()->timestamp() +
- pre_splice_buffers.back()->duration() - splice_timestamp;
- const base::TimeDelta minimum_splice_duration = std::max(
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromSecondsD(
- 2.0 / audio_configs_[append_config_index_].samples_per_second()));
- if (splice_duration < minimum_splice_duration) {
- LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_warning_logs_,
- kMaxSpliceGenerationWarningLogs)
- << "Skipping splice frame generation: not enough samples for splicing "
- "new buffer at "
- << splice_timestamp.InMicroseconds() << "us. Have "
- << splice_duration.InMicroseconds() << "us, but need "
- << minimum_splice_duration.InMicroseconds() << "us.";
- DVLOG(1) << "Can't generate splice: not enough samples for crossfade; have "
- << splice_duration.InMicroseconds() << "us, but need "
- << minimum_splice_duration.InMicroseconds() << "us.";
- return;
- }
-
- DVLOG(1) << "Generating splice frame @ " << new_buffers.front()->timestamp()
- << ", splice duration: " << splice_duration.InMicroseconds()
- << " us";
- LIMITED_MEDIA_LOG(DEBUG, media_log_, num_splice_generation_success_logs_,
- kMaxSpliceGenerationSuccessLogs)
- << "Generated splice of overlap duration "
- << splice_duration.InMicroseconds() << "us into new buffer at "
- << splice_timestamp.InMicroseconds() << "us.";
- new_buffers.front()->ConvertToSpliceBuffer(pre_splice_buffers);
-}
-
bool SourceBufferStream::SetPendingBuffer(
scoped_refptr<StreamParserBuffer>* out_buffer) {
DCHECK(out_buffer->get());

Powered by Google App Engine
This is Rietveld 408576698