Chromium Code Reviews| 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 65% |
| copy from media/filters/decrypting_video_decoder.cc |
| copy to media/filters/decrypting_audio_decoder.cc |
| index b8200300b89d7ea3b555f4c48e7156525fd93edf..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_; |
| +} |
| + |
| +int DecryptingAudioDecoder::samples_per_second() { |
| + return samples_per_second_; |
| } |
| -DecryptingVideoDecoder::~DecryptingVideoDecoder() { |
| - DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; |
| +DecryptingAudioDecoder::~DecryptingAudioDecoder() { |
|
scherkus (not reviewing)
2012/10/18 21:13:12
can't we still DCHECK for uninitialized?
xhwang
2012/10/18 22:49:08
ISTM dtor can happen in a lot of states now, e.g.
|
| } |
| -void DecryptingVideoDecoder::DoInitialize( |
| +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,38 +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(); |
| 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. |
| @@ -192,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; |
| } |
| @@ -219,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 |
| @@ -237,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; |
| } |
| @@ -283,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; |
| @@ -325,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(); |
| @@ -352,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) { |
| @@ -383,7 +369,7 @@ void DecryptingVideoDecoder::OnKeyAdded() { |
| } |
| } |
| -void DecryptingVideoDecoder::DoReset() { |
| +void DecryptingAudioDecoder::DoReset() { |
| DCHECK(init_cb_.is_null()); |
| DCHECK(read_cb_.is_null()); |
| state_ = kIdle; |