| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..623b2deb5cd2a94fef8cc16b1b5eb8754b493ddf
|
| --- /dev/null
|
| +++ b/media/base/android/media_codec_audio_decoder.cc
|
| @@ -0,0 +1,184 @@
|
| +// Copyright 2015 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/android/media_codec_audio_decoder.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| +
|
| +#include "media/base/android/media_codec_bridge.h"
|
| +#include "media/base/audio_timestamp_helper.h"
|
| +#include "media/base/demuxer_stream.h"
|
| +
|
| +//#include "base/tvlog.h"
|
| +
|
| +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;
|
| +}
|
| +
|
| +namespace media {
|
| +
|
| +MediaCodecAudioDecoder::MediaCodecAudioDecoder(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
|
| + const base::Closure& request_data_cb,
|
| + const base::Closure& starvation_cb,
|
| + const base::Closure& stop_done_cb,
|
| + const base::Closure& error_cb,
|
| + const SetTimeCallback& update_current_time_cb)
|
| + : MediaCodecDecoder(media_task_runner, ui_task_runner,
|
| + request_data_cb, starvation_cb,
|
| + stop_done_cb, error_cb, update_current_time_cb,
|
| + "AudioDecoder"),
|
| + volume_(-1.0),
|
| + bytes_per_frame_(0),
|
| + frame_count_(0)
|
| +{}
|
| +
|
| +MediaCodecAudioDecoder::~MediaCodecAudioDecoder()
|
| +{
|
| + DVLOG(1) << "AudioDecoder::~AudioDecoder()";
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::SetVolume(double volume) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << volume;
|
| +
|
| + volume_ = volume;
|
| + SetVolumeInternal();
|
| +}
|
| +
|
| +bool MediaCodecAudioDecoder::HasStream() const {
|
| + return configs_.audio_codec != kUnknownAudioCodec;
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::Flush() {
|
| + MediaCodecDecoder::Flush();
|
| + frame_count_ = 0;
|
| +}
|
| +
|
| +bool MediaCodecAudioDecoder::IsCodecReconfigureNeeded(
|
| + const DemuxerConfigs& curr,
|
| + const DemuxerConfigs& next) const {
|
| + return curr.audio_codec != next.audio_codec ||
|
| + curr.audio_channels != next.audio_channels ||
|
| + curr.audio_sampling_rate != next.audio_sampling_rate ||
|
| + next.is_audio_encrypted != next.is_audio_encrypted ||
|
| + curr.audio_extra_data.size() != next.audio_extra_data.size() ||
|
| + !std::equal(curr.audio_extra_data.begin(),
|
| + curr.audio_extra_data.end(),
|
| + next.audio_extra_data.begin());
|
| +}
|
| +
|
| +MediaCodecDecoder::ConfigStatus
|
| +MediaCodecAudioDecoder::ConfigureInternal() {
|
| + // Media thread
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__;
|
| +
|
| + media_codec_bridge_.reset(AudioCodecBridge::Create(configs_.audio_codec));
|
| + if (!media_codec_bridge_)
|
| + return CONFIG_FAILURE;
|
| +
|
| + if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))->Start(
|
| + configs_.audio_codec,
|
| + configs_.audio_sampling_rate,
|
| + configs_.audio_channels,
|
| + &configs_.audio_extra_data[0],
|
| + configs_.audio_extra_data.size(),
|
| + configs_.audio_codec_delay_ns,
|
| + configs_.audio_seek_preroll_ns,
|
| + true,
|
| + GetMediaCrypto().obj())) {
|
| +
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__ << " failed";
|
| +
|
| + media_codec_bridge_.reset();
|
| + return CONFIG_FAILURE;
|
| + }
|
| +
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__ << " succeeded";
|
| +
|
| + SetVolumeInternal();
|
| +
|
| + bytes_per_frame_ = kBytesPerAudioOutputSample * configs_.audio_channels;
|
| + frame_count_ = 0;
|
| + ResetTimestampHelper();
|
| +
|
| + return CONFIG_OK;
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::SetBaseTimestamp(base::TimeDelta base_timestamp) {
|
| + // Media thread
|
| + DVLOG(1) << __FUNCTION__ << " " << base_timestamp;
|
| +
|
| + base_timestamp_ = base_timestamp;
|
| + if (audio_timestamp_helper_)
|
| + audio_timestamp_helper_->SetBaseTimestamp(base_timestamp_);
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::ResetTimestampHelper() {
|
| + // Media thread
|
| + if (audio_timestamp_helper_)
|
| + base_timestamp_ = audio_timestamp_helper_->GetTimestamp();
|
| +
|
| + audio_timestamp_helper_.reset(
|
| + new AudioTimestampHelper(configs_.audio_sampling_rate));
|
| +
|
| + audio_timestamp_helper_->SetBaseTimestamp(base_timestamp_);
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::SetVolumeInternal() {
|
| + // Media thread
|
| + if (media_codec_bridge_) {
|
| + static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->SetVolume(
|
| + volume_);
|
| + }
|
| +}
|
| +
|
| +void MediaCodecAudioDecoder::Render(int buffer_index,
|
| + size_t size,
|
| + bool render_output,
|
| + base::TimeDelta pts,
|
| + bool eos_encountered) {
|
| + // Decoder thread
|
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << " pts:" << pts;
|
| +
|
| + render_output = render_output && (size != 0u);
|
| +
|
| + if (render_output) {
|
| + int64 head_position = (static_cast<AudioCodecBridge*>(
|
| + media_codec_bridge_.get()))->PlayOutputBuffer(
|
| + buffer_index, size);
|
| +
|
| + 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);
|
| +
|
| + 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 << "]";
|
| +
|
| + update_current_time_cb_.Run(now_playing, last_buffered);
|
| + }
|
| +
|
| + media_codec_bridge_->ReleaseOutputBuffer(buffer_index, false);
|
| +
|
| + if (GetState() == STOPPING || eos_encountered) {
|
| + SetState(STOPPED);
|
| + media_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
|
| + weak_this_, eos_encountered));
|
| + }
|
| +}
|
| +
|
| +} // namespace media
|
|
|