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 |
| index d868382ef42c6a639e832484bc4830ac0b4f6254..e28568549a025f823d0514c8ceb2f35893d130ca 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); |
|
acolwell GONE FROM CHROMIUM
2014/05/01 01:08:34
Why do you need the whole buffer? It looks like yo
DaleCurtis
2014/05/01 01:26:32
Good point, I'll only store that in the next patch
DaleCurtis
2014/05/01 19:21:27
Done.
|
| 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); |
|
acolwell GONE FROM CHROMIUM
2014/05/01 01:08:34
Why isn't discard padding in frames? You appear to
DaleCurtis
2014/05/01 01:26:32
It's in TimeDelta since the MSE case will be based
acolwell GONE FROM CHROMIUM
2014/05/01 17:44:26
Ok. I see. I don't have a good alternte proposal r
|
| + |
| + // Regardless of the timestamp on the encoded buffer, the corresponding |
| + // decoded output will appear |codec_delay_| frames later. |
| + size_t discard_start = codec_delay_; |
|
acolwell GONE FROM CHROMIUM
2014/05/01 01:08:34
Isn't this baking in an assumption that discard_pa
DaleCurtis
2014/05/01 01:26:32
No, this code should work for start discard paddin
|
| + if (codec_delay_ > 0) { |
|
acolwell GONE FROM CHROMIUM
2014/05/01 17:44:26
I think this should be renamed too because this na
DaleCurtis
2014/05/01 19:21:27
Done.
|
| + // 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); |
|
acolwell GONE FROM CHROMIUM
2014/05/01 01:08:34
Does this hold for Opus? I was under the impressio
DaleCurtis
2014/05/01 01:26:32
We may need to discuss this part more, since I'm a
|
| + |
| + 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_); |
|
acolwell GONE FROM CHROMIUM
2014/05/01 01:08:34
Please add a TODO and file a bug for this since I
DaleCurtis
2014/05/01 01:26:32
As far as I can tell this all works fine. See my c
|
| + |
| 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 to the buffer. |