diff options
Diffstat (limited to 'chromium/media/base/android/audio_decoder_job.cc')
-rw-r--r-- | chromium/media/base/android/audio_decoder_job.cc | 130 |
1 files changed, 101 insertions, 29 deletions
diff --git a/chromium/media/base/android/audio_decoder_job.cc b/chromium/media/base/android/audio_decoder_job.cc index d089796ccc6..cb882cee42e 100644 --- a/chromium/media/base/android/audio_decoder_job.cc +++ b/chromium/media/base/android/audio_decoder_job.cc @@ -8,6 +8,14 @@ #include "base/lazy_instance.h" #include "base/threading/thread.h" #include "media/base/android/media_codec_bridge.h" +#include "media/base/audio_timestamp_helper.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 { @@ -24,54 +32,118 @@ class AudioDecoderThread : public base::Thread { base::LazyInstance<AudioDecoderThread>::Leaky g_audio_decoder_thread = LAZY_INSTANCE_INITIALIZER; -AudioDecoderJob* AudioDecoderJob::Create( - const AudioCodec audio_codec, - int sample_rate, - int channel_count, - const uint8* extra_data, - size_t extra_data_size, - jobject media_crypto, - const base::Closure& request_data_cb) { - scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec)); - if (codec && codec->Start(audio_codec, sample_rate, channel_count, extra_data, - extra_data_size, true, media_crypto)) { - return new AudioDecoderJob(codec.Pass(), request_data_cb); - } - - LOG(ERROR) << "Failed to create AudioDecoderJob."; - return NULL; -} - AudioDecoderJob::AudioDecoderJob( - scoped_ptr<AudioCodecBridge> audio_codec_bridge, - const base::Closure& request_data_cb) + const base::Closure& request_data_cb, + const base::Closure& on_demuxer_config_changed_cb) : MediaDecoderJob(g_audio_decoder_thread.Pointer()->message_loop_proxy(), - audio_codec_bridge.get(), request_data_cb), - audio_codec_bridge_(audio_codec_bridge.Pass()) { + request_data_cb, + on_demuxer_config_changed_cb), + audio_codec_(kUnknownAudioCodec), + num_channels_(0), + sampling_rate_(0), + volume_(-1.0), + bytes_per_frame_(0) { } -AudioDecoderJob::~AudioDecoderJob() { +AudioDecoderJob::~AudioDecoderJob() {} + +bool AudioDecoderJob::HasStream() const { + return audio_codec_ != kUnknownAudioCodec; } void AudioDecoderJob::SetVolume(double volume) { - audio_codec_bridge_->SetVolume(volume); + volume_ = volume; + SetVolumeInternal(); +} + +void AudioDecoderJob::SetBaseTimestamp(base::TimeDelta base_timestamp) { + DCHECK(!is_decoding()); + base_timestamp_ = base_timestamp; + if (audio_timestamp_helper_) + audio_timestamp_helper_->SetBaseTimestamp(base_timestamp_); } void AudioDecoderJob::ReleaseOutputBuffer( int output_buffer_index, size_t size, bool render_output, + base::TimeDelta current_presentation_timestamp, const ReleaseOutputCompletionCallback& callback) { - size_t size_to_render = render_output ? size : 0u; - if (size_to_render) - audio_codec_bridge_->PlayOutputBuffer(output_buffer_index, size_to_render); - audio_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, false); + render_output = render_output && (size != 0u); + if (render_output) { + int64 head_position = (static_cast<AudioCodecBridge*>( + media_codec_bridge_.get()))->PlayOutputBuffer( + output_buffer_index, size); + audio_timestamp_helper_->AddFrames(size / bytes_per_frame_); + int64 frames_to_play = + audio_timestamp_helper_->frame_count() - head_position; + DCHECK_GE(frames_to_play, 0); + current_presentation_timestamp = + audio_timestamp_helper_->GetTimestamp() - + audio_timestamp_helper_->GetFrameDuration(frames_to_play); + } else { + current_presentation_timestamp = kNoTimestamp(); + } + media_codec_bridge_->ReleaseOutputBuffer(output_buffer_index, false); - callback.Run(size_to_render); + callback.Run(current_presentation_timestamp, + audio_timestamp_helper_->GetTimestamp()); } bool AudioDecoderJob::ComputeTimeToRender() const { return false; } +void AudioDecoderJob::UpdateDemuxerConfigs(const DemuxerConfigs& configs) { + // TODO(qinmin): split DemuxerConfig for audio and video separately so we + // can simply store the stucture here. + audio_codec_ = configs.audio_codec; + num_channels_ = configs.audio_channels; + sampling_rate_ = configs.audio_sampling_rate; + set_is_content_encrypted(configs.is_audio_encrypted); + audio_extra_data_ = configs.audio_extra_data; + bytes_per_frame_ = kBytesPerAudioOutputSample * num_channels_; +} + +bool AudioDecoderJob::AreDemuxerConfigsChanged( + const DemuxerConfigs& configs) const { + return audio_codec_ != configs.audio_codec || + num_channels_ != configs.audio_channels || + sampling_rate_ != configs.audio_sampling_rate || + is_content_encrypted() != configs.is_audio_encrypted || + audio_extra_data_.size() != configs.audio_extra_data.size() || + !std::equal(audio_extra_data_.begin(), + audio_extra_data_.end(), + configs.audio_extra_data.begin()); +} + +bool AudioDecoderJob::CreateMediaCodecBridgeInternal() { + media_codec_bridge_.reset(AudioCodecBridge::Create(audio_codec_)); + if (!media_codec_bridge_) + return false; + + if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))->Start( + audio_codec_, sampling_rate_, num_channels_, &audio_extra_data_[0], + audio_extra_data_.size(), true, GetMediaCrypto().obj())) { + media_codec_bridge_.reset(); + return false; + } + + SetVolumeInternal(); + + // Need to pass the base timestamp to the new decoder. + if (audio_timestamp_helper_) + base_timestamp_ = audio_timestamp_helper_->GetTimestamp(); + audio_timestamp_helper_.reset(new AudioTimestampHelper(sampling_rate_)); + audio_timestamp_helper_->SetBaseTimestamp(base_timestamp_); + return true; +} + +void AudioDecoderJob::SetVolumeInternal() { + if (media_codec_bridge_) { + static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->SetVolume( + volume_); + } +} + } // namespace media |