This source file includes following definitions.
- IsOutOfSync
- weak_factory_
- Initialize
- GetDecodeOutput
- Reset
- Stop
- SetDecryptor
- InitializeDecoder
- FinishInitialization
- DecodePendingBuffer
- DeliverFrame
- OnKeyAdded
- DoReset
- EnqueueFrames
#include "media/filters/decrypting_audio_decoder.h"
#include <cstdlib>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "media/base/audio_buffer.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/buffers.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/pipeline.h"
namespace media {
const int DecryptingAudioDecoder::kSupportedBitsPerChannel = 16;
static inline bool IsOutOfSync(const base::TimeDelta& timestamp_1,
const base::TimeDelta& timestamp_2) {
const int64 kOutOfSyncThresholdInMilliseconds = 100;
return std::abs(timestamp_1.InMilliseconds() - timestamp_2.InMilliseconds()) >
kOutOfSyncThresholdInMilliseconds;
}
DecryptingAudioDecoder::DecryptingAudioDecoder(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const SetDecryptorReadyCB& set_decryptor_ready_cb)
: task_runner_(task_runner),
state_(kUninitialized),
set_decryptor_ready_cb_(set_decryptor_ready_cb),
decryptor_(NULL),
key_added_while_decode_pending_(false),
weak_factory_(this) {}
void DecryptingAudioDecoder::Initialize(const AudioDecoderConfig& config,
const PipelineStatusCB& status_cb) {
DVLOG(2) << "Initialize()";
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(decode_cb_.is_null());
DCHECK(reset_cb_.is_null());
weak_this_ = weak_factory_.GetWeakPtr();
init_cb_ = BindToCurrentLoop(status_cb);
if (!config.IsValidConfig()) {
DLOG(ERROR) << "Invalid audio stream config.";
base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_DECODE);
return;
}
if (!config.is_encrypted()) {
base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
return;
}
config_ = config;
if (state_ == kUninitialized) {
state_ = kDecryptorRequested;
set_decryptor_ready_cb_.Run(BindToCurrentLoop(
base::Bind(&DecryptingAudioDecoder::SetDecryptor, weak_this_)));
return;
}
decryptor_->DeinitializeDecoder(Decryptor::kAudio);
InitializeDecoder();
}
void DecryptingAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
const DecodeCB& decode_cb) {
DVLOG(3) << "Decode()";
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(state_ == kIdle || state_ == kDecodeFinished) << state_;
DCHECK(!decode_cb.is_null());
CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
decode_cb_ = BindToCurrentLoop(decode_cb);
if (state_ == kDecodeFinished) {
base::ResetAndReturn(&decode_cb_).Run(kOk, AudioBuffer::CreateEOSBuffer());
return;
}
if (!queued_audio_frames_.empty()) {
DCHECK(!buffer);
base::ResetAndReturn(&decode_cb_).Run(kOk, queued_audio_frames_.front());
queued_audio_frames_.pop_front();
return;
}
if (timestamp_helper_->base_timestamp() == kNoTimestamp() &&
!buffer->end_of_stream()) {
timestamp_helper_->SetBaseTimestamp(buffer->timestamp());
}
pending_buffer_to_decode_ = buffer;
state_ = kPendingDecode;
DecodePendingBuffer();
}
scoped_refptr<AudioBuffer> DecryptingAudioDecoder::GetDecodeOutput() {
if (queued_audio_frames_.empty())
return NULL;
scoped_refptr<AudioBuffer> out = queued_audio_frames_.front();
queued_audio_frames_.pop_front();
return out;
}
void DecryptingAudioDecoder::Reset(const base::Closure& closure) {
DVLOG(2) << "Reset() - state: " << state_;
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(state_ == kIdle ||
state_ == kPendingDecode ||
state_ == kWaitingForKey ||
state_ == kDecodeFinished) << state_;
DCHECK(init_cb_.is_null());
DCHECK(reset_cb_.is_null());
reset_cb_ = BindToCurrentLoop(closure);
decryptor_->ResetDecoder(Decryptor::kAudio);
if (state_ == kPendingDecode) {
DCHECK(!decode_cb_.is_null());
return;
}
if (state_ == kWaitingForKey) {
DCHECK(!decode_cb_.is_null());
pending_buffer_to_decode_ = NULL;
base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
}
DCHECK(decode_cb_.is_null());
DoReset();
}
void DecryptingAudioDecoder::Stop() {
DVLOG(2) << "Stop() - state: " << state_;
DCHECK(task_runner_->BelongsToCurrentThread());
weak_factory_.InvalidateWeakPtrs();
if (decryptor_) {
decryptor_->DeinitializeDecoder(Decryptor::kAudio);
decryptor_ = NULL;
}
if (!set_decryptor_ready_cb_.is_null())
base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
pending_buffer_to_decode_ = NULL;
if (!init_cb_.is_null())
base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
if (!decode_cb_.is_null())
base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
if (!reset_cb_.is_null())
base::ResetAndReturn(&reset_cb_).Run();
state_ = kStopped;
}
DecryptingAudioDecoder::~DecryptingAudioDecoder() {
DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
}
void DecryptingAudioDecoder::SetDecryptor(Decryptor* decryptor) {
DVLOG(2) << "SetDecryptor()";
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_EQ(state_, kDecryptorRequested) << state_;
DCHECK(!init_cb_.is_null());
DCHECK(!set_decryptor_ready_cb_.is_null());
set_decryptor_ready_cb_.Reset();
if (!decryptor) {
base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
state_ = kStopped;
return;
}
decryptor_ = decryptor;
InitializeDecoder();
}
void DecryptingAudioDecoder::InitializeDecoder() {
state_ = kPendingDecoderInit;
decryptor_->InitializeAudioDecoder(
config_,
BindToCurrentLoop(base::Bind(
&DecryptingAudioDecoder::FinishInitialization, weak_this_)));
}
void DecryptingAudioDecoder::FinishInitialization(bool success) {
DVLOG(2) << "FinishInitialization()";
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(state_ == kPendingDecoderInit) << state_;
DCHECK(!init_cb_.is_null());
DCHECK(reset_cb_.is_null());
DCHECK(decode_cb_.is_null());
if (!success) {
base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
state_ = kStopped;
return;
}
timestamp_helper_.reset(
new AudioTimestampHelper(config_.samples_per_second()));
decryptor_->RegisterNewKeyCB(
Decryptor::kAudio,
BindToCurrentLoop(
base::Bind(&DecryptingAudioDecoder::OnKeyAdded, weak_this_)));
state_ = kIdle;
base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
}
void DecryptingAudioDecoder::DecodePendingBuffer() {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_EQ(state_, kPendingDecode) << state_;
int buffer_size = 0;
if (!pending_buffer_to_decode_->end_of_stream()) {
buffer_size = pending_buffer_to_decode_->data_size();
}
decryptor_->DecryptAndDecodeAudio(
pending_buffer_to_decode_,
BindToCurrentLoop(base::Bind(
&DecryptingAudioDecoder::DeliverFrame, weak_this_, buffer_size)));
}
void DecryptingAudioDecoder::DeliverFrame(
int buffer_size,
Decryptor::Status status,
const Decryptor::AudioBuffers& frames) {
DVLOG(3) << "DeliverFrame() - status: " << status;
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_EQ(state_, kPendingDecode) << state_;
DCHECK(!decode_cb_.is_null());
DCHECK(pending_buffer_to_decode_.get());
DCHECK(queued_audio_frames_.empty());
bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
key_added_while_decode_pending_ = false;
scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
pending_buffer_to_decode_;
pending_buffer_to_decode_ = NULL;
if (!reset_cb_.is_null()) {
base::ResetAndReturn(&decode_cb_).Run(kAborted, NULL);
DoReset();
return;
}
DCHECK_EQ(status == Decryptor::kSuccess, !frames.empty());
if (status == Decryptor::kError) {
DVLOG(2) << "DeliverFrame() - kError";
state_ = kDecodeFinished;
base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
return;
}
if (status == Decryptor::kNoKey) {
DVLOG(2) << "DeliverFrame() - kNoKey";
pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
if (need_to_try_again_if_nokey_is_returned) {
DecodePendingBuffer();
return;
}
state_ = kWaitingForKey;
return;
}
if (status == Decryptor::kNeedMoreData) {
DVLOG(2) << "DeliverFrame() - kNeedMoreData";
if (scoped_pending_buffer_to_decode->end_of_stream()) {
state_ = kDecodeFinished;
base::ResetAndReturn(&decode_cb_)
.Run(kOk, AudioBuffer::CreateEOSBuffer());
return;
}
state_ = kIdle;
base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL);
return;
}
DCHECK_EQ(status, Decryptor::kSuccess);
DCHECK(!frames.empty());
EnqueueFrames(frames);
state_ = kIdle;
base::ResetAndReturn(&decode_cb_).Run(kOk, queued_audio_frames_.front());
queued_audio_frames_.pop_front();
}
void DecryptingAudioDecoder::OnKeyAdded() {
DCHECK(task_runner_->BelongsToCurrentThread());
if (state_ == kPendingDecode) {
key_added_while_decode_pending_ = true;
return;
}
if (state_ == kWaitingForKey) {
state_ = kPendingDecode;
DecodePendingBuffer();
}
}
void DecryptingAudioDecoder::DoReset() {
DCHECK(init_cb_.is_null());
DCHECK(decode_cb_.is_null());
timestamp_helper_->SetBaseTimestamp(kNoTimestamp());
state_ = kIdle;
base::ResetAndReturn(&reset_cb_).Run();
}
void DecryptingAudioDecoder::EnqueueFrames(
const Decryptor::AudioBuffers& frames) {
queued_audio_frames_ = frames;
for (Decryptor::AudioBuffers::iterator iter = queued_audio_frames_.begin();
iter != queued_audio_frames_.end();
++iter) {
scoped_refptr<AudioBuffer>& frame = *iter;
DCHECK(!frame->end_of_stream()) << "EOS frame returned.";
DCHECK_GT(frame->frame_count(), 0) << "Empty frame returned.";
base::TimeDelta current_time = timestamp_helper_->GetTimestamp();
if (IsOutOfSync(current_time, frame->timestamp())) {
DVLOG(1) << "Timestamp returned by the decoder ("
<< frame->timestamp().InMilliseconds() << " ms)"
<< " does not match the input timestamp and number of samples"
<< " decoded (" << current_time.InMilliseconds() << " ms).";
}
frame->set_timestamp(current_time);
frame->set_duration(
timestamp_helper_->GetFrameDuration(frame->frame_count()));
timestamp_helper_->AddFrames(frame->frame_count());
}
}
}