summaryrefslogtreecommitdiffstats
path: root/chromium/media/base/android/audio_decoder_job.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/base/android/audio_decoder_job.cc')
-rw-r--r--chromium/media/base/android/audio_decoder_job.cc130
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