Chromium Code Reviews| 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..b907fe8e4858d3a4b92fcaa6de5a3eeb17fa65d7 |
| --- /dev/null |
| +++ b/media/base/audio_discard_helper.cc |
| @@ -0,0 +1,110 @@ |
| +// 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 <cmath> |
| + |
| +#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()) { |
|
wolenetz
2014/04/28 21:52:07
nit: is any sanity checking needed on sample_rate_
DaleCurtis
2014/04/28 23:09:03
As far as this code is concerned it just needs to
|
| +} |
| + |
| +AudioDiscardHelper::~AudioDiscardHelper() { |
| +} |
| + |
| +int AudioDiscardHelper::TimeDeltaToFrames(base::TimeDelta duration) const { |
| + DCHECK(duration >= base::TimeDelta()); |
| + return std::ceil(duration.InSecondsF() * sample_rate_); |
|
wolenetz
2014/04/28 21:52:07
With ceil(), might we hit off-by-one stuff here? (
DaleCurtis
2014/04/28 23:09:03
Since this floating point value is calculated from
|
| +} |
| + |
| +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()) |
| + timestamp_helper_.SetBaseTimestamp(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); |
|
wolenetz
2014/04/28 21:52:07
TrimStart() will modify decoded_buffer's duration_
DaleCurtis
2014/04/28 22:03:51
It's this codes expectation that it is the sole au
wolenetz
2014/04/28 22:37:56
Regarding assumption of ability to set duration/ti
DaleCurtis
2014/04/28 23:09:03
I think that comment can be removed now. I'll do
|
| + } |
| + |
| + // 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. |
|
wolenetz
2014/04/28 21:52:07
nit: reference bug?
DaleCurtis
2014/04/28 23:09:03
Done.
|
| + 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) { |
|
wolenetz
2014/04/28 21:52:07
Is end discard aware of start discard? (If not, co
DaleCurtis
2014/04/28 22:03:51
It's expected that users of discard_padding() will
|
| + DLOG(ERROR) << "Invalid file. Incorrect discard padding value."; |
|
wolenetz
2014/04/28 21:52:07
nit: If this helper will be used by MSE, not just
DaleCurtis
2014/04/28 23:09:03
Done.
|
| + 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 |