Chromium Code Reviews| Index: media/base/android/media_codec_audio_decoder.cc |
| diff --git a/media/base/android/media_codec_audio_decoder.cc b/media/base/android/media_codec_audio_decoder.cc |
| index c910ce62f272ef889354ea257d6adc9462b935f3..50d084a9bf6c43b26bd3cc3e687f04f61376913d 100644 |
| --- a/media/base/android/media_codec_audio_decoder.cc |
| +++ b/media/base/android/media_codec_audio_decoder.cc |
| @@ -15,6 +15,9 @@ namespace { |
| // Use 16bit PCM for audio output. Keep this value in sync with the output |
| // format we passed to AudioTrack in MediaCodecBridge. |
| const int kBytesPerAudioOutputSample = 2; |
| + |
| +// Fake buffer index that refers to pending buffer. |
| +const int kPendingBufferIndex = -1; |
| } |
| namespace media { |
| @@ -23,12 +26,14 @@ MediaCodecAudioDecoder::MediaCodecAudioDecoder( |
| const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| const base::Closure& request_data_cb, |
| const base::Closure& starvation_cb, |
| + const base::Closure& preroll_done_cb, |
| const base::Closure& stop_done_cb, |
| const base::Closure& error_cb, |
| const SetTimeCallback& update_current_time_cb) |
| : MediaCodecDecoder(media_task_runner, |
| request_data_cb, |
| starvation_cb, |
| + preroll_done_cb, |
| stop_done_cb, |
| error_cb, |
| "AudioDecoder"), |
| @@ -69,6 +74,16 @@ void MediaCodecAudioDecoder::Flush() { |
| MediaCodecDecoder::Flush(); |
| frame_count_ = 0; |
| + pending_buffer_.Invalidate(); |
| +} |
| + |
| +void MediaCodecAudioDecoder::ReleaseMediaCodec() { |
| + DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| + |
| + DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| + |
| + MediaCodecDecoder::ReleaseMediaCodec(); |
| + pending_buffer_.Invalidate(); |
| } |
| void MediaCodecAudioDecoder::SetVolume(double volume) { |
| @@ -158,37 +173,39 @@ void MediaCodecAudioDecoder::OnOutputFormatChanged() { |
| void MediaCodecAudioDecoder::Render(int buffer_index, |
| size_t size, |
| - bool render_output, |
| + RenderMode render_mode, |
| base::TimeDelta pts, |
| bool eos_encountered) { |
| DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| - DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts; |
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts << " " |
| + << AsString(render_mode); |
| - render_output = render_output && (size != 0u); |
| + bool do_render = false; |
| - if (render_output) { |
| - int64 head_position = |
| - (static_cast<AudioCodecBridge*>(media_codec_bridge_.get())) |
| - ->PlayOutputBuffer(buffer_index, size); |
| + switch (render_mode) { |
| + case kRenderSkip: |
| + break; |
| - size_t new_frames_count = size / bytes_per_frame_; |
| - frame_count_ += new_frames_count; |
| - audio_timestamp_helper_->AddFrames(new_frames_count); |
| - int64 frames_to_play = frame_count_ - head_position; |
| - DCHECK_GE(frames_to_play, 0); |
| + case kRenderAfterPreroll: |
| + // Do not bother to play a single last frame after preroll |
| + if (!eos_encountered && size != 0u) |
| + CreatePendingBuffer(buffer_index, size, pts); |
|
qinmin
2015/07/31 18:43:10
I prefer we just move the pending buffer to java s
|
| + break; |
| - base::TimeDelta last_buffered = audio_timestamp_helper_->GetTimestamp(); |
| - base::TimeDelta now_playing = |
| - last_buffered - |
| - audio_timestamp_helper_->GetFrameDuration(frames_to_play); |
| + case kRenderNow: |
| + do_render = (size != 0u); |
| + break; |
| + } |
| - DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| - << " will play: [" << now_playing << "," << last_buffered << "]"; |
| + if (do_render) { |
| + if (pending_buffer_.IsValid()) { |
| + PlayOutputBuffer(kPendingBufferIndex, pending_buffer_.data.size(), |
| + pending_buffer_.pts); |
| + pending_buffer_.Invalidate(); |
| + } |
| - media_task_runner_->PostTask( |
| - FROM_HERE, |
| - base::Bind(update_current_time_cb_, now_playing, last_buffered)); |
| + PlayOutputBuffer(buffer_index, size, pts); |
| } |
| media_codec_bridge_->ReleaseOutputBuffer(buffer_index, false); |
| @@ -196,6 +213,70 @@ void MediaCodecAudioDecoder::Render(int buffer_index, |
| CheckLastFrame(eos_encountered, false); // no delayed tasks |
| } |
| +void MediaCodecAudioDecoder::CreatePendingBuffer(int buffer_index, |
| + size_t size, |
| + base::TimeDelta pts) { |
| + DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| + DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| + << " size:" << size; |
| + |
| + pending_buffer_.pts = pts; |
| + pending_buffer_.data.resize(size); // capacity should only increase |
| + |
| + DCHECK(media_codec_bridge_); |
| + if (!media_codec_bridge_->CopyFromOutputBuffer( |
| + buffer_index, 0, &pending_buffer_.data[0], size)) { |
| + DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": cannot copy" |
| + << " from buffer index:" << buffer_index << " size:" << size; |
| + pending_buffer_.Invalidate(); |
| + } |
| +} |
| + |
| +void MediaCodecAudioDecoder::PlayOutputBuffer(int buffer_index, |
| + size_t size, |
| + base::TimeDelta pts) { |
| + DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| + |
| + AudioCodecBridge* audio_codec = |
| + static_cast<AudioCodecBridge*>(media_codec_bridge_.get()); |
| + |
| + DCHECK(audio_codec); |
| + |
| + int64 head_position = |
| + (buffer_index == kPendingBufferIndex) |
| + ? audio_codec->PlayOutputBuffer(&pending_buffer_.data[0], size) |
| + : audio_codec->PlayOutputBuffer(buffer_index, size); |
| + |
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| + << " head_position:" << head_position; |
| + |
| + size_t new_frames_count = size / bytes_per_frame_; |
| + frame_count_ += new_frames_count; |
| + audio_timestamp_helper_->AddFrames(new_frames_count); |
| + |
| + int64 frames_to_play = frame_count_ - head_position; |
| + |
| + // TODO(timav): remove this DVLOG after more testing. |
| + if (frames_to_play < 0) { |
| + DVLOG(0) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| + << " frame_count_ < head_position (" << frame_count_ << " < " |
| + << head_position << ")" |
| + << " new_frames_count:" << new_frames_count; |
| + } |
| + DCHECK_GE(frames_to_play, 0); |
| + |
| + base::TimeDelta last_buffered = audio_timestamp_helper_->GetTimestamp(); |
| + base::TimeDelta now_playing = |
| + last_buffered - audio_timestamp_helper_->GetFrameDuration(frames_to_play); |
| + |
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| + << " will play: [" << now_playing << "," << last_buffered << "]"; |
| + |
| + media_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind(update_current_time_cb_, now_playing, last_buffered)); |
| +} |
| + |
| void MediaCodecAudioDecoder::SetVolumeInternal() { |
| DCHECK(media_task_runner_->BelongsToCurrentThread()); |