Index: media/base/audio_discard_helper.cc |
diff --git a/media/base/audio_discard_helper.cc b/media/base/audio_discard_helper.cc |
index 3088130b00c48ca9f3c7966a4c45eac53e4ca87c..57ff5f24490020d21c5c6bceb22bc498886bf25e 100644 |
--- a/media/base/audio_discard_helper.cc |
+++ b/media/base/audio_discard_helper.cc |
@@ -24,8 +24,9 @@ static void WarnOnNonMonotonicTimestamps(base::TimeDelta last_timestamp, |
<< " diff " << diff.InMicroseconds() << " us"; |
} |
-AudioDiscardHelper::AudioDiscardHelper(int sample_rate) |
+AudioDiscardHelper::AudioDiscardHelper(int sample_rate, size_t codec_delay) |
: sample_rate_(sample_rate), |
+ codec_delay_(codec_delay), |
timestamp_helper_(sample_rate_), |
discard_frames_(0), |
last_input_timestamp_(kNoTimestamp()) { |
@@ -44,6 +45,7 @@ void AudioDiscardHelper::Reset(size_t initial_discard) { |
discard_frames_ = initial_discard; |
last_input_timestamp_ = kNoTimestamp(); |
timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); |
+ delayed_discard_ = NULL; |
} |
bool AudioDiscardHelper::ProcessBuffers( |
@@ -59,15 +61,29 @@ bool AudioDiscardHelper::ProcessBuffers( |
last_input_timestamp_ = encoded_buffer->timestamp(); |
// If this is the first buffer seen, setup the timestamp helper. |
- if (!initialized()) { |
+ const bool first_buffer = !initialized(); |
+ if (first_buffer) { |
// 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()) |
+ if (!decoded_buffer) { |
+ // If there's a one buffer delay for decoding, we need to save it so it can |
+ // be processed with the next decoder buffer. |
+ if (first_buffer) |
+ delayed_discard_ = encoded_buffer; |
return false; |
+ } |
+ |
+ const size_t original_frame_count = decoded_buffer->frame_count(); |
+ |
+ // If there's a one buffer delay for decoding, pick up the last encoded buffer |
+ // for processing with the current decoded buffer. |
+ scoped_refptr<DecoderBuffer> current_encoded_buffer = encoded_buffer; |
+ if (delayed_discard_) |
+ delayed_discard_.swap(current_encoded_buffer); |
if (discard_frames_ > 0) { |
const size_t decoded_frames = decoded_buffer->frame_count(); |
@@ -75,20 +91,74 @@ bool AudioDiscardHelper::ProcessBuffers( |
discard_frames_ -= frames_to_discard; |
// If everything would be discarded, indicate a new buffer is required. |
- if (frames_to_discard == decoded_frames) |
+ if (frames_to_discard == decoded_frames) { |
+ // For simplicity disallow cases where a buffer with discard padding is |
+ // present. Doing so allows us to avoid complexity around tracking |
+ // discards across buffers. |
+ DCHECK(current_encoded_buffer->discard_padding().first == |
+ base::TimeDelta()); |
+ DCHECK(current_encoded_buffer->discard_padding().second == |
+ base::TimeDelta()); |
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()) { |
+ // Handle front discard padding. |
+ if (current_encoded_buffer->discard_padding().first > base::TimeDelta()) { |
+ const size_t decoded_frames = decoded_buffer->frame_count(); |
+ const size_t start_frames_to_discard = |
+ TimeDeltaToFrames(current_encoded_buffer->discard_padding().first); |
+ |
+ // Regardless of the timestamp on the encoded buffer, the corresponding |
+ // decoded output will appear |codec_delay_| frames later. |
+ size_t discard_start = codec_delay_; |
+ if (codec_delay_ > 0) { |
+ // If we have a |codec_delay_| and have already discarded frames from this |
+ // buffer, the |discard_start| must be adjusted by the number of frames |
+ // already discarded. |
+ const size_t frames_discarded_so_far = |
+ original_frame_count - decoded_buffer->frame_count(); |
+ CHECK_LE(frames_discarded_so_far, codec_delay_); |
+ discard_start -= frames_discarded_so_far; |
+ } |
+ |
+ // For simplicity require the start of the discard to be within the current |
+ // buffer. Doing so allows us avoid complexity around tracking discards |
+ // across buffers. |
+ CHECK_LT(discard_start, decoded_frames); |
+ |
+ const size_t frames_to_discard = |
+ std::min(start_frames_to_discard, decoded_frames - discard_start); |
+ |
+ // Carry over any frames which need to be discarded from the front of the |
+ // next buffer. |
+ DCHECK(!discard_frames_); |
+ discard_frames_ = start_frames_to_discard - frames_to_discard; |
+ |
+ // If everything would be discarded, indicate a new buffer is required. |
+ if (frames_to_discard == decoded_frames) { |
+ // The buffer should not have been marked with end discard if the front |
+ // discard removes everything. |
+ DCHECK(current_encoded_buffer->discard_padding().second == |
+ base::TimeDelta()); |
+ return false; |
+ } |
+ |
+ decoded_buffer->TrimRange(discard_start, discard_start + frames_to_discard); |
+ } |
+ |
+ // Handle end discard padding. |
+ if (current_encoded_buffer->discard_padding().second > base::TimeDelta()) { |
+ // Limit end discarding to when there is no |codec_delay_|, otherwise it's |
+ // non-trivial determining where to start discarding end frames. |
+ CHECK(!codec_delay_); |
+ |
const size_t decoded_frames = decoded_buffer->frame_count(); |
const size_t end_frames_to_discard = |
- TimeDeltaToFrames(encoded_buffer->discard_padding()); |
+ TimeDeltaToFrames(current_encoded_buffer->discard_padding().second); |
+ |
if (end_frames_to_discard > decoded_frames) { |
DLOG(ERROR) << "Encountered invalid discard padding value."; |
return false; |
@@ -100,7 +170,8 @@ bool AudioDiscardHelper::ProcessBuffers( |
decoded_buffer->TrimEnd(end_frames_to_discard); |
} else { |
- DCHECK(encoded_buffer->discard_padding() == base::TimeDelta()); |
+ DCHECK(current_encoded_buffer->discard_padding().second == |
+ base::TimeDelta()); |
} |
// Assign timestamp and duration to the buffer. |