| Index: media/base/audio_splicer.cc
|
| diff --git a/media/base/audio_splicer.cc b/media/base/audio_splicer.cc
|
| index 9424b0b39d602a601587182e6cff755a18dfa069..accff36cd30acec7a1db197ac264d52cf5ce664e 100644
|
| --- a/media/base/audio_splicer.cc
|
| +++ b/media/base/audio_splicer.cc
|
| @@ -12,27 +12,39 @@
|
| #include "media/base/audio_bus.h"
|
| #include "media/base/audio_decoder_config.h"
|
| #include "media/base/audio_timestamp_helper.h"
|
| +#include "media/base/media_log.h"
|
| #include "media/base/vector_math.h"
|
|
|
| namespace media {
|
|
|
| -// Minimum gap size needed before the splicer will take action to
|
| -// fill a gap. This avoids periodically inserting and then dropping samples
|
| -// when the buffer timestamps are slightly off because of timestamp rounding
|
| -// in the source content. Unit is frames.
|
| -static const int kMinGapSize = 2;
|
| +namespace {
|
| +
|
| +enum {
|
| + // Minimum gap size needed before the splicer will take action to
|
| + // fill a gap. This avoids periodically inserting and then dropping samples
|
| + // when the buffer timestamps are slightly off because of timestamp rounding
|
| + // in the source content. Unit is frames.
|
| + kMinGapSize = 2,
|
| +
|
| + // Limits the number of MEDIA_LOG() per sanitizer instance warning the user
|
| + // about splicer overlaps within |kMaxTimeDeltaInMilliseconds| or gaps larger
|
| + // than |kMinGapSize| and less than |kMaxTimeDeltaInMilliseconds|. These
|
| + // warnings may be frequent for some streams, and number of sanitizer
|
| + // instances may be high, so keep this limit low to help reduce log spam.
|
| + kMaxSanitizerWarningLogs = 5,
|
| +};
|
|
|
| // AudioBuffer::TrimStart() is not as accurate as the timestamp helper, so
|
| // manually adjust the duration and timestamp after trimming.
|
| -static void AccurateTrimStart(int frames_to_trim,
|
| - const scoped_refptr<AudioBuffer> buffer,
|
| - const AudioTimestampHelper& timestamp_helper) {
|
| +void AccurateTrimStart(int frames_to_trim,
|
| + const scoped_refptr<AudioBuffer> buffer,
|
| + const AudioTimestampHelper& timestamp_helper) {
|
| buffer->TrimStart(frames_to_trim);
|
| buffer->set_timestamp(timestamp_helper.GetTimestamp());
|
| }
|
|
|
| // Returns an AudioBus whose frame buffer is backed by the provided AudioBuffer.
|
| -static scoped_ptr<AudioBus> CreateAudioBufferWrapper(
|
| +scoped_ptr<AudioBus> CreateAudioBufferWrapper(
|
| const scoped_refptr<AudioBuffer>& buffer) {
|
| scoped_ptr<AudioBus> wrapper =
|
| AudioBus::CreateWrapper(buffer->channel_count());
|
| @@ -44,9 +56,12 @@ static scoped_ptr<AudioBus> CreateAudioBufferWrapper(
|
| return wrapper.Pass();
|
| }
|
|
|
| +} // namespace
|
| +
|
| class AudioStreamSanitizer {
|
| public:
|
| - explicit AudioStreamSanitizer(int samples_per_second);
|
| + AudioStreamSanitizer(int samples_per_second,
|
| + const scoped_refptr<MediaLog>& media_log);
|
| ~AudioStreamSanitizer();
|
|
|
| // Resets the sanitizer state by clearing the output buffers queue, and
|
| @@ -89,12 +104,23 @@ class AudioStreamSanitizer {
|
| typedef std::deque<scoped_refptr<AudioBuffer> > BufferQueue;
|
| BufferQueue output_buffers_;
|
|
|
| + scoped_refptr<MediaLog> media_log_;
|
| +
|
| + // To prevent log spam, counts the number of audio gap or overlaps warned in
|
| + // logs.
|
| + int num_warning_logs_;
|
| +
|
| DISALLOW_ASSIGN(AudioStreamSanitizer);
|
| };
|
|
|
| -AudioStreamSanitizer::AudioStreamSanitizer(int samples_per_second)
|
| +AudioStreamSanitizer::AudioStreamSanitizer(
|
| + int samples_per_second,
|
| + const scoped_refptr<MediaLog>& media_log)
|
| : output_timestamp_helper_(samples_per_second),
|
| - received_end_of_stream_(false) {}
|
| + received_end_of_stream_(false),
|
| + media_log_(media_log),
|
| + num_warning_logs_(0) {
|
| +}
|
|
|
| AudioStreamSanitizer::~AudioStreamSanitizer() {}
|
|
|
| @@ -128,7 +154,12 @@ bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) {
|
| output_timestamp_helper_.SetBaseTimestamp(input->timestamp());
|
|
|
| if (output_timestamp_helper_.base_timestamp() > input->timestamp()) {
|
| - DVLOG(1) << "Input timestamp is before the base timestamp.";
|
| + MEDIA_LOG(ERROR, media_log_)
|
| + << "Audio splicing failed: unexpected timestamp sequence. base "
|
| + "timestamp="
|
| + << output_timestamp_helper_.base_timestamp().InMicroseconds()
|
| + << "us, input timestamp=" << input->timestamp().InMicroseconds()
|
| + << "us";
|
| return false;
|
| }
|
|
|
| @@ -139,7 +170,13 @@ bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) {
|
|
|
| if (std::abs(delta.InMilliseconds()) >
|
| AudioSplicer::kMaxTimeDeltaInMilliseconds) {
|
| - DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us";
|
| + MEDIA_LOG(ERROR, media_log_)
|
| + << "Audio splicing failed: coded frame timestamp differs from "
|
| + "expected timestamp " << expected_timestamp.InMicroseconds()
|
| + << "us by " << delta.InMicroseconds()
|
| + << "us, more than threshold of +/-"
|
| + << AudioSplicer::kMaxTimeDeltaInMilliseconds
|
| + << "ms. Expected timestamp is based on decoded frames and frame rate.";
|
| return false;
|
| }
|
|
|
| @@ -153,6 +190,11 @@ bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) {
|
| }
|
|
|
| if (frames_to_fill > 0) {
|
| + LIMITED_MEDIA_LOG(DEBUG, media_log_, num_warning_logs_,
|
| + kMaxSanitizerWarningLogs)
|
| + << "Audio splicer inserting silence for small gap of "
|
| + << delta.InMicroseconds() << "us at time "
|
| + << expected_timestamp.InMicroseconds() << "us.";
|
| DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds()
|
| << " us: " << delta.InMicroseconds() << " us";
|
|
|
| @@ -177,6 +219,11 @@ bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) {
|
| //
|
| // A crossfade can't be done here because only the current buffer is available
|
| // at this point, not previous buffers.
|
| + LIMITED_MEDIA_LOG(DEBUG, media_log_, num_warning_logs_,
|
| + kMaxSanitizerWarningLogs)
|
| + << "Audio splicer skipping frames for small overlap of "
|
| + << -delta.InMicroseconds() << "us at time "
|
| + << expected_timestamp.InMicroseconds() << "us.";
|
| DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds()
|
| << " us: " << -delta.InMicroseconds() << " us";
|
|
|
| @@ -227,15 +274,20 @@ bool AudioStreamSanitizer::DrainInto(AudioStreamSanitizer* output) {
|
| return true;
|
| }
|
|
|
| -AudioSplicer::AudioSplicer(int samples_per_second)
|
| +AudioSplicer::AudioSplicer(int samples_per_second,
|
| + const scoped_refptr<MediaLog>& media_log)
|
| : max_crossfade_duration_(
|
| base::TimeDelta::FromMilliseconds(kCrossfadeDurationInMilliseconds)),
|
| splice_timestamp_(kNoTimestamp()),
|
| max_splice_end_timestamp_(kNoTimestamp()),
|
| - output_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
|
| - pre_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
|
| - post_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
|
| - have_all_pre_splice_buffers_(false) {}
|
| + output_sanitizer_(
|
| + new AudioStreamSanitizer(samples_per_second, media_log)),
|
| + pre_splice_sanitizer_(
|
| + new AudioStreamSanitizer(samples_per_second, media_log)),
|
| + post_splice_sanitizer_(
|
| + new AudioStreamSanitizer(samples_per_second, media_log)),
|
| + have_all_pre_splice_buffers_(false) {
|
| +}
|
|
|
| AudioSplicer::~AudioSplicer() {}
|
|
|
|
|