Index: media/base/audio_discard_helper.cc |
diff --git a/media/base/audio_discard_helper.cc b/media/base/audio_discard_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3088130b00c48ca9f3c7966a4c45eac53e4ca87c |
--- /dev/null |
+++ b/media/base/audio_discard_helper.cc |
@@ -0,0 +1,114 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/base/audio_discard_helper.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/logging.h" |
+#include "media/base/audio_buffer.h" |
+#include "media/base/buffers.h" |
+#include "media/base/decoder_buffer.h" |
+ |
+namespace media { |
+ |
+static void WarnOnNonMonotonicTimestamps(base::TimeDelta last_timestamp, |
+ base::TimeDelta current_timestamp) { |
+ if (last_timestamp == kNoTimestamp() || last_timestamp < current_timestamp) |
+ return; |
+ |
+ const base::TimeDelta diff = current_timestamp - last_timestamp; |
+ DLOG(WARNING) << "Input timestamps are not monotonically increasing! " |
+ << " ts " << current_timestamp.InMicroseconds() << " us" |
+ << " diff " << diff.InMicroseconds() << " us"; |
+} |
+ |
+AudioDiscardHelper::AudioDiscardHelper(int sample_rate) |
+ : sample_rate_(sample_rate), |
+ timestamp_helper_(sample_rate_), |
+ discard_frames_(0), |
+ last_input_timestamp_(kNoTimestamp()) { |
+ DCHECK_GT(sample_rate_, 0); |
+} |
+ |
+AudioDiscardHelper::~AudioDiscardHelper() { |
+} |
+ |
+size_t AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { |
+ DCHECK(duration >= base::TimeDelta()); |
+ return duration.InSecondsF() * sample_rate_ + 0.5; |
+} |
+ |
+void AudioDiscardHelper::Reset(size_t initial_discard) { |
+ discard_frames_ = initial_discard; |
+ last_input_timestamp_ = kNoTimestamp(); |
+ timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); |
+} |
+ |
+bool AudioDiscardHelper::ProcessBuffers( |
+ const scoped_refptr<DecoderBuffer>& encoded_buffer, |
+ const scoped_refptr<AudioBuffer>& decoded_buffer) { |
+ DCHECK(!encoded_buffer->end_of_stream()); |
+ DCHECK(encoded_buffer->timestamp() != kNoTimestamp()); |
+ |
+ // Issue a debug warning when we see non-monotonic timestamps. Only a warning |
+ // to allow chained OGG playback. |
+ WarnOnNonMonotonicTimestamps(last_input_timestamp_, |
+ encoded_buffer->timestamp()); |
+ last_input_timestamp_ = encoded_buffer->timestamp(); |
+ |
+ // If this is the first buffer seen, setup the timestamp helper. |
+ if (!initialized()) { |
+ // Clamp the base timestamp to zero. |
+ timestamp_helper_.SetBaseTimestamp( |
+ std::max(base::TimeDelta(), encoded_buffer->timestamp())); |
+ } |
+ DCHECK(initialized()); |
+ |
+ if (!decoded_buffer || !decoded_buffer->frame_count()) |
+ return false; |
+ |
+ if (discard_frames_ > 0) { |
+ const size_t decoded_frames = decoded_buffer->frame_count(); |
+ const size_t frames_to_discard = std::min(discard_frames_, decoded_frames); |
+ discard_frames_ -= frames_to_discard; |
+ |
+ // If everything would be discarded, indicate a new buffer is required. |
+ if (frames_to_discard == decoded_frames) |
+ return false; |
+ |
+ decoded_buffer->TrimStart(frames_to_discard); |
+ } |
+ |
+ // TODO(dalecurtis): Applying the current buffer's discard padding doesn't |
+ // make sense in the Vorbis case because there is a delay of one buffer before |
+ // decoded buffers are returned. Fix and add support for more than just end |
+ // trimming. See http://crbug.com/360961. |
+ if (encoded_buffer->discard_padding() > base::TimeDelta()) { |
+ const size_t decoded_frames = decoded_buffer->frame_count(); |
+ const size_t end_frames_to_discard = |
+ TimeDeltaToFrames(encoded_buffer->discard_padding()); |
+ if (end_frames_to_discard > decoded_frames) { |
+ DLOG(ERROR) << "Encountered invalid discard padding value."; |
+ return false; |
+ } |
+ |
+ // If everything would be discarded, indicate a new buffer is required. |
+ if (end_frames_to_discard == decoded_frames) |
+ return false; |
+ |
+ decoded_buffer->TrimEnd(end_frames_to_discard); |
+ } else { |
+ DCHECK(encoded_buffer->discard_padding() == base::TimeDelta()); |
+ } |
+ |
+ // Assign timestamp and duration to the buffer. |
+ decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); |
+ decoded_buffer->set_duration( |
+ timestamp_helper_.GetFrameDuration(decoded_buffer->frame_count())); |
+ timestamp_helper_.AddFrames(decoded_buffer->frame_count()); |
+ return true; |
+} |
+ |
+} // namespace media |