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; |