| 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());
|
|
|