| Index: media/filters/decrypting_audio_decoder.cc
|
| diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_audio_decoder.cc
|
| similarity index 66%
|
| copy from media/filters/decrypting_video_decoder.cc
|
| copy to media/filters/decrypting_audio_decoder.cc
|
| index 8ea96750b301cdd70b6c561d3fbff453393895b8..a6871b5335930fa5a2638ad96d4230d91de5edc6 100644
|
| --- a/media/filters/decrypting_video_decoder.cc
|
| +++ b/media/filters/decrypting_audio_decoder.cc
|
| @@ -2,57 +2,61 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "media/filters/decrypting_video_decoder.h"
|
| +#include "media/filters/decrypting_audio_decoder.h"
|
|
|
| #include "base/bind.h"
|
| #include "base/callback_helpers.h"
|
| #include "base/location.h"
|
| #include "base/message_loop_proxy.h"
|
| +#include "media/base/audio_decoder_config.h"
|
| #include "media/base/bind_to_loop.h"
|
| +#include "media/base/buffers.h"
|
| +#include "media/base/data_buffer.h"
|
| #include "media/base/decoder_buffer.h"
|
| #include "media/base/decryptor.h"
|
| #include "media/base/demuxer_stream.h"
|
| #include "media/base/pipeline.h"
|
| -#include "media/base/video_decoder_config.h"
|
| -#include "media/base/video_frame.h"
|
|
|
| namespace media {
|
|
|
| #define BIND_TO_LOOP(function) \
|
| media::BindToLoop(message_loop_, base::Bind(function, this))
|
|
|
| -DecryptingVideoDecoder::DecryptingVideoDecoder(
|
| +DecryptingAudioDecoder::DecryptingAudioDecoder(
|
| const MessageLoopFactoryCB& message_loop_factory_cb,
|
| const RequestDecryptorNotificationCB& request_decryptor_notification_cb)
|
| : message_loop_factory_cb_(message_loop_factory_cb),
|
| state_(kUninitialized),
|
| request_decryptor_notification_cb_(request_decryptor_notification_cb),
|
| decryptor_(NULL),
|
| - key_added_while_pending_decode_(false) {
|
| + key_added_while_pending_decode_(false),
|
| + bits_per_channel_(0),
|
| + channel_layout_(CHANNEL_LAYOUT_NONE),
|
| + samples_per_second_(0) {
|
| }
|
|
|
| -void DecryptingVideoDecoder::Initialize(
|
| +void DecryptingAudioDecoder::Initialize(
|
| const scoped_refptr<DemuxerStream>& stream,
|
| const PipelineStatusCB& status_cb,
|
| const StatisticsCB& statistics_cb) {
|
| DCHECK(!message_loop_);
|
| message_loop_ = base::ResetAndReturn(&message_loop_factory_cb_).Run();
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::DoInitialize, this,
|
| + &DecryptingAudioDecoder::DoInitialize, this,
|
| stream, status_cb, statistics_cb));
|
| }
|
|
|
| -void DecryptingVideoDecoder::Read(const ReadCB& read_cb) {
|
| +void DecryptingAudioDecoder::Read(const ReadCB& read_cb) {
|
| // Complete operation asynchronously on different stack of execution as per
|
| - // the API contract of VideoDecoder::Read()
|
| + // the API contract of AudioDecoder::Read()
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::DoRead, this, read_cb));
|
| + &DecryptingAudioDecoder::DoRead, this, read_cb));
|
| }
|
|
|
| -void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
|
| +void DecryptingAudioDecoder::Reset(const base::Closure& closure) {
|
| if (!message_loop_->BelongsToCurrentThread()) {
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::Reset, this, closure));
|
| + &DecryptingAudioDecoder::Reset, this, closure));
|
| return;
|
| }
|
|
|
| @@ -67,7 +71,7 @@ void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
|
|
|
| reset_cb_ = closure;
|
|
|
| - decryptor_->ResetDecoder(Decryptor::kVideo);
|
| + decryptor_->ResetDecoder(Decryptor::kAudio);
|
|
|
| // Reset() cannot complete if the read callback is still pending.
|
| // Defer the resetting process in this case. The |reset_cb_| will be fired
|
| @@ -88,41 +92,22 @@ void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
|
| DoReset();
|
| }
|
|
|
| -void DecryptingVideoDecoder::Stop(const base::Closure& closure) {
|
| - if (!message_loop_->BelongsToCurrentThread()) {
|
| - message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::Stop, this, closure));
|
| - return;
|
| - }
|
| +int DecryptingAudioDecoder::bits_per_channel() {
|
| + return bits_per_channel_;
|
| +}
|
|
|
| - DVLOG(2) << "Stop() - state: " << state_;
|
| -
|
| - // At this point the render thread is likely paused (in WebMediaPlayerImpl's
|
| - // Destroy()), so running |closure| can't wait for anything that requires the
|
| - // render thread to be processing messages to complete (such as PPAPI
|
| - // callbacks).
|
| - if (decryptor_)
|
| - decryptor_->DeinitializeDecoder(Decryptor::kVideo);
|
| - if (!request_decryptor_notification_cb_.is_null()) {
|
| - base::ResetAndReturn(&request_decryptor_notification_cb_).Run(
|
| - DecryptorNotificationCB());
|
| - }
|
| - pending_buffer_to_decode_ = NULL;
|
| - if (!init_cb_.is_null())
|
| - base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
|
| - if (!read_cb_.is_null())
|
| - base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
|
| - if (!reset_cb_.is_null())
|
| - base::ResetAndReturn(&reset_cb_).Run();
|
| - state_ = kStopped;
|
| - closure.Run();
|
| +ChannelLayout DecryptingAudioDecoder::channel_layout() {
|
| + return channel_layout_;
|
| }
|
|
|
| -DecryptingVideoDecoder::~DecryptingVideoDecoder() {
|
| - DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
|
| +int DecryptingAudioDecoder::samples_per_second() {
|
| + return samples_per_second_;
|
| }
|
|
|
| -void DecryptingVideoDecoder::DoInitialize(
|
| +DecryptingAudioDecoder::~DecryptingAudioDecoder() {
|
| +}
|
| +
|
| +void DecryptingAudioDecoder::DoInitialize(
|
| const scoped_refptr<DemuxerStream>& stream,
|
| const PipelineStatusCB& status_cb,
|
| const StatisticsCB& statistics_cb) {
|
| @@ -131,15 +116,14 @@ void DecryptingVideoDecoder::DoInitialize(
|
| DCHECK_EQ(state_, kUninitialized) << state_;
|
| DCHECK(stream);
|
|
|
| - const VideoDecoderConfig& config = stream->video_decoder_config();
|
| + const AudioDecoderConfig& config = stream->audio_decoder_config();
|
| if (!config.IsValidConfig()) {
|
| - DLOG(ERROR) << "Invalid video stream config: "
|
| - << config.AsHumanReadableString();
|
| + DLOG(ERROR) << "Invalid audio stream config.";
|
| status_cb.Run(PIPELINE_ERROR_DECODE);
|
| return;
|
| }
|
|
|
| - // DecryptingVideoDecoder only accepts potentially encrypted stream.
|
| + // DecryptingAudioDecoder only accepts potentially encrypted stream.
|
| if (!config.is_encrypted()) {
|
| status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
|
| return;
|
| @@ -153,40 +137,32 @@ void DecryptingVideoDecoder::DoInitialize(
|
|
|
| state_ = kDecryptorRequested;
|
| request_decryptor_notification_cb_.Run(
|
| - BIND_TO_LOOP(&DecryptingVideoDecoder::SetDecryptor));
|
| + BIND_TO_LOOP(&DecryptingAudioDecoder::SetDecryptor));
|
| }
|
|
|
| -void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) {
|
| +void DecryptingAudioDecoder::SetDecryptor(Decryptor* decryptor) {
|
| DVLOG(2) << "SetDecryptor()";
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == kStopped)
|
| - return;
|
| -
|
| DCHECK_EQ(state_, kDecryptorRequested) << state_;
|
| DCHECK(!init_cb_.is_null());
|
| DCHECK(!request_decryptor_notification_cb_.is_null());
|
| - request_decryptor_notification_cb_.Reset();
|
|
|
| + request_decryptor_notification_cb_.Reset();
|
| decryptor_ = decryptor;
|
|
|
| - scoped_ptr<VideoDecoderConfig> scoped_config(new VideoDecoderConfig());
|
| - scoped_config->CopyFrom(demuxer_stream_->video_decoder_config());
|
| + scoped_ptr<AudioDecoderConfig> scoped_config(new AudioDecoderConfig());
|
| + scoped_config->CopyFrom(demuxer_stream_->audio_decoder_config());
|
|
|
| state_ = kPendingDecoderInit;
|
| - decryptor_->InitializeVideoDecoder(
|
| + decryptor_->InitializeAudioDecoder(
|
| scoped_config.Pass(),
|
| - BIND_TO_LOOP(&DecryptingVideoDecoder::FinishInitialization),
|
| - BIND_TO_LOOP(&DecryptingVideoDecoder::OnKeyAdded));
|
| + BIND_TO_LOOP(&DecryptingAudioDecoder::FinishInitialization),
|
| + BIND_TO_LOOP(&DecryptingAudioDecoder::OnKeyAdded));
|
| }
|
|
|
| -void DecryptingVideoDecoder::FinishInitialization(bool success) {
|
| +void DecryptingAudioDecoder::FinishInitialization(bool success) {
|
| DVLOG(2) << "FinishInitialization()";
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == kStopped)
|
| - return;
|
| -
|
| DCHECK_EQ(state_, kPendingDecoderInit) << state_;
|
| DCHECK(!init_cb_.is_null());
|
| DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished.
|
| @@ -194,25 +170,37 @@ void DecryptingVideoDecoder::FinishInitialization(bool success) {
|
|
|
| if (!success) {
|
| base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
|
| - state_ = kStopped;
|
| + state_ = kDecodeFinished;
|
| return;
|
| }
|
|
|
| // Success!
|
| + const AudioDecoderConfig& config = demuxer_stream_->audio_decoder_config();
|
| + bits_per_channel_ = config.bits_per_channel();
|
| + channel_layout_ = config.channel_layout();
|
| + samples_per_second_ = config.samples_per_second();
|
| state_ = kIdle;
|
| base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
|
| }
|
|
|
| -void DecryptingVideoDecoder::DoRead(const ReadCB& read_cb) {
|
| +void DecryptingAudioDecoder::DoRead(const ReadCB& read_cb) {
|
| DVLOG(3) << "DoRead()";
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| DCHECK(state_ == kIdle || state_ == kDecodeFinished) << state_;
|
| DCHECK(!read_cb.is_null());
|
| CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
|
|
|
| - // Return empty frames if decoding has finished.
|
| + // Return empty (end-of-stream) frames if decoding has finished.
|
| if (state_ == kDecodeFinished) {
|
| - read_cb.Run(kOk, VideoFrame::CreateEmptyFrame());
|
| + read_cb.Run(kOk, scoped_refptr<Buffer>(new DataBuffer(0)));
|
| + return;
|
| + }
|
| +
|
| + if (!queued_audio_frames_.empty()) {
|
| + if (queued_audio_frames_.front()->IsEndOfStream())
|
| + state_ = kDecodeFinished;
|
| + read_cb.Run(kOk, queued_audio_frames_.front());
|
| + queued_audio_frames_.pop_front();
|
| return;
|
| }
|
|
|
| @@ -221,16 +209,16 @@ void DecryptingVideoDecoder::DoRead(const ReadCB& read_cb) {
|
| ReadFromDemuxerStream();
|
| }
|
|
|
| -void DecryptingVideoDecoder::ReadFromDemuxerStream() {
|
| +void DecryptingAudioDecoder::ReadFromDemuxerStream() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| DCHECK_EQ(state_, kPendingDemuxerRead) << state_;
|
| DCHECK(!read_cb_.is_null());
|
|
|
| demuxer_stream_->Read(
|
| - base::Bind(&DecryptingVideoDecoder::DecryptAndDecodeBuffer, this));
|
| + base::Bind(&DecryptingAudioDecoder::DecryptAndDecodeBuffer, this));
|
| }
|
|
|
| -void DecryptingVideoDecoder::DecryptAndDecodeBuffer(
|
| +void DecryptingAudioDecoder::DecryptAndDecodeBuffer(
|
| DemuxerStream::Status status,
|
| const scoped_refptr<DecoderBuffer>& buffer) {
|
| // In theory, we don't need to force post the task here, because we do a
|
| @@ -239,26 +227,21 @@ void DecryptingVideoDecoder::DecryptAndDecodeBuffer(
|
| // stack we are still fine. But it looks like a force post task makes the
|
| // logic more understandable and manageable, so why not?
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::DoDecryptAndDecodeBuffer, this, status, buffer));
|
| + &DecryptingAudioDecoder::DoDecryptAndDecodeBuffer, this, status, buffer));
|
| }
|
|
|
| -void DecryptingVideoDecoder::DoDecryptAndDecodeBuffer(
|
| +void DecryptingAudioDecoder::DoDecryptAndDecodeBuffer(
|
| DemuxerStream::Status status,
|
| const scoped_refptr<DecoderBuffer>& buffer) {
|
| DVLOG(3) << "DoDecryptAndDecodeBuffer()";
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == kStopped)
|
| - return;
|
| -
|
| DCHECK_EQ(state_, kPendingDemuxerRead) << state_;
|
| DCHECK(!read_cb_.is_null());
|
| DCHECK_EQ(buffer != NULL, status == DemuxerStream::kOk) << status;
|
|
|
| if (!reset_cb_.is_null()) {
|
| base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
|
| - if (!reset_cb_.is_null())
|
| - DoReset();
|
| + DoReset();
|
| return;
|
| }
|
|
|
| @@ -285,41 +268,38 @@ void DecryptingVideoDecoder::DoDecryptAndDecodeBuffer(
|
| DecodePendingBuffer();
|
| }
|
|
|
| -void DecryptingVideoDecoder::DecodePendingBuffer() {
|
| +void DecryptingAudioDecoder::DecodePendingBuffer() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| DCHECK_EQ(state_, kPendingDecode) << state_;
|
| - decryptor_->DecryptAndDecodeVideo(
|
| + decryptor_->DecryptAndDecodeAudio(
|
| pending_buffer_to_decode_,
|
| - base::Bind(&DecryptingVideoDecoder::DeliverFrame, this,
|
| + base::Bind(&DecryptingAudioDecoder::DeliverFrame, this,
|
| pending_buffer_to_decode_->GetDataSize()));
|
| }
|
|
|
| -void DecryptingVideoDecoder::DeliverFrame(
|
| +void DecryptingAudioDecoder::DeliverFrame(
|
| int buffer_size,
|
| Decryptor::Status status,
|
| - const scoped_refptr<VideoFrame>& frame) {
|
| - // We need to force task post here because the VideoDecodeCB can be executed
|
| - // synchronously in Reset()/Stop(). Instead of using more complicated logic in
|
| + const Decryptor::AudioBuffers& frames) {
|
| + // We need to force task post here because the AudioDecodeCB can be executed
|
| + // synchronously in Reset(). Instead of using more complicated logic in
|
| // those function to fix it, why not force task post here to make everything
|
| // simple and clear?
|
| message_loop_->PostTask(FROM_HERE, base::Bind(
|
| - &DecryptingVideoDecoder::DoDeliverFrame, this,
|
| - buffer_size, status, frame));
|
| + &DecryptingAudioDecoder::DoDeliverFrame, this,
|
| + buffer_size, status, frames));
|
| }
|
|
|
| -void DecryptingVideoDecoder::DoDeliverFrame(
|
| +void DecryptingAudioDecoder::DoDeliverFrame(
|
| int buffer_size,
|
| Decryptor::Status status,
|
| - const scoped_refptr<VideoFrame>& frame) {
|
| + const Decryptor::AudioBuffers& frames) {
|
| DVLOG(3) << "DoDeliverFrame()";
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| -
|
| - if (state_ == kStopped)
|
| - return;
|
| -
|
| DCHECK_EQ(state_, kPendingDecode) << state_;
|
| DCHECK(!read_cb_.is_null());
|
| DCHECK(pending_buffer_to_decode_);
|
| + DCHECK(queued_audio_frames_.empty());
|
|
|
| bool need_to_try_again_if_nokey_is_returned = key_added_while_pending_decode_;
|
| key_added_while_pending_decode_ = false;
|
| @@ -327,20 +307,19 @@ void DecryptingVideoDecoder::DoDeliverFrame(
|
| if (!reset_cb_.is_null()) {
|
| pending_buffer_to_decode_ = NULL;
|
| base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
|
| - if (!reset_cb_.is_null())
|
| - DoReset();
|
| + DoReset();
|
| return;
|
| }
|
|
|
| if (status == Decryptor::kError) {
|
| - DCHECK(!frame);
|
| + DCHECK(frames.empty());
|
| state_ = kDecodeFinished;
|
| base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
|
| return;
|
| }
|
|
|
| if (status == Decryptor::kNoKey) {
|
| - DCHECK(!frame);
|
| + DCHECK(frames.empty());
|
| if (need_to_try_again_if_nokey_is_returned) {
|
| // The |state_| is still kPendingDecode.
|
| DecodePendingBuffer();
|
| @@ -354,24 +333,29 @@ void DecryptingVideoDecoder::DoDeliverFrame(
|
| // The buffer has been accepted by the decoder, let's report statistics.
|
| if (buffer_size) {
|
| PipelineStatistics statistics;
|
| - statistics.video_bytes_decoded = buffer_size;
|
| + statistics.audio_bytes_decoded = buffer_size;
|
| statistics_cb_.Run(statistics);
|
| }
|
|
|
| if (status == Decryptor::kNeedMoreData) {
|
| - DCHECK(!frame);
|
| + DCHECK(frames.empty());
|
| state_ = kPendingDemuxerRead;
|
| ReadFromDemuxerStream();
|
| return;
|
| }
|
|
|
| DCHECK_EQ(status, Decryptor::kSuccess);
|
| - state_ = frame->IsEndOfStream() ? kDecodeFinished : kIdle;
|
| - base::ResetAndReturn(&read_cb_).Run(kOk, frame);
|
| +
|
| + DCHECK(!frames.empty());
|
| + queued_audio_frames_ = frames;
|
| +
|
| + scoped_refptr<Buffer> first_frame = queued_audio_frames_.front();
|
| + queued_audio_frames_.pop_front();
|
| + state_ = first_frame->IsEndOfStream() ? kDecodeFinished : kIdle;
|
| + base::ResetAndReturn(&read_cb_).Run(kOk, first_frame);
|
| }
|
|
|
| -void DecryptingVideoDecoder::OnKeyAdded() {
|
| - DVLOG(2) << "OnKeyAdded()";
|
| +void DecryptingAudioDecoder::OnKeyAdded() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
|
|
| if (state_ == kPendingDecode) {
|
| @@ -385,7 +369,7 @@ void DecryptingVideoDecoder::OnKeyAdded() {
|
| }
|
| }
|
|
|
| -void DecryptingVideoDecoder::DoReset() {
|
| +void DecryptingAudioDecoder::DoReset() {
|
| DCHECK(init_cb_.is_null());
|
| DCHECK(read_cb_.is_null());
|
| state_ = kIdle;
|
|
|