| Index: media/base/android/media_codec_decoder.cc
|
| diff --git a/media/base/android/media_codec_decoder.cc b/media/base/android/media_codec_decoder.cc
|
| index fd8d84ecc60787c1eced4114010f086dd985e1e3..808aa761a55b551c7260eee8118833e2c03515fb 100644
|
| --- a/media/base/android/media_codec_decoder.cc
|
| +++ b/media/base/android/media_codec_decoder.cc
|
| @@ -37,6 +37,7 @@ MediaCodecDecoder::MediaCodecDecoder(
|
| const base::Closure& starvation_cb,
|
| const base::Closure& decoder_drained_cb,
|
| const base::Closure& stop_done_cb,
|
| + const base::Closure& waiting_for_decryption_key_cb,
|
| const base::Closure& error_cb,
|
| const char* decoder_thread_name)
|
| : media_task_runner_(media_task_runner),
|
| @@ -48,10 +49,12 @@ MediaCodecDecoder::MediaCodecDecoder(
|
| starvation_cb_(starvation_cb),
|
| decoder_drained_cb_(decoder_drained_cb),
|
| stop_done_cb_(stop_done_cb),
|
| + waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
|
| error_cb_(error_cb),
|
| state_(kStopped),
|
| is_prepared_(false),
|
| eos_enqueued_(false),
|
| + missing_key_reported_(false),
|
| completed_(false),
|
| last_frame_posted_(false),
|
| is_data_request_in_progress_(false),
|
| @@ -91,6 +94,7 @@ void MediaCodecDecoder::Flush() {
|
| is_incoming_data_invalid_ = true;
|
|
|
| eos_enqueued_ = false;
|
| + missing_key_reported_ = false;
|
| completed_ = false;
|
| drain_decoder_ = false;
|
| au_queue_.Flush();
|
| @@ -179,14 +183,12 @@ void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) {
|
| preroll_timestamp_ = preroll_timestamp;
|
| }
|
|
|
| -base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
|
| - base::android::ScopedJavaLocalRef<jobject> media_crypto;
|
| +void MediaCodecDecoder::SetNeedsReconfigure() {
|
| + DCHECK(media_task_runner_->BelongsToCurrentThread());
|
| +
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__;
|
|
|
| - // TODO(timav): implement DRM.
|
| - // drm_bridge_ is not implemented
|
| - // if (drm_bridge_)
|
| - // media_crypto = drm_bridge_->GetMediaCrypto();
|
| - return media_crypto;
|
| + needs_reconfigure_ = true;
|
| }
|
|
|
| void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) {
|
| @@ -202,7 +204,8 @@ void MediaCodecDecoder::Prefetch(const base::Closure& prefetch_done_cb) {
|
| PrefetchNextChunk();
|
| }
|
|
|
| -MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
|
| +MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure(
|
| + jobject media_crypto) {
|
| DCHECK(media_task_runner_->BelongsToCurrentThread());
|
|
|
| DVLOG(1) << class_name() << "::" << __FUNCTION__;
|
| @@ -233,7 +236,7 @@ MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
|
| au_info = au_queue_.GetInfo();
|
| }
|
|
|
| - MediaCodecDecoder::ConfigStatus result = ConfigureInternal();
|
| + MediaCodecDecoder::ConfigStatus result = ConfigureInternal(media_crypto);
|
|
|
| #ifndef NDEBUG
|
| // We check and reset |verify_next_frame_is_key_| on Decoder thread.
|
| @@ -401,6 +404,8 @@ void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) {
|
| SetState(kStopped);
|
| completed_ = (eos_encountered && !drain_decoder_);
|
|
|
| + missing_key_reported_ = false;
|
| +
|
| // If the stream is completed during preroll we need to report it since
|
| // another stream might be running and the player waits for two callbacks.
|
| if (completed_ && !preroll_done_cb_.is_null()) {
|
| @@ -498,6 +503,8 @@ void MediaCodecDecoder::DoEmergencyStop() {
|
| decoder_thread_.Stop(); // synchronous
|
|
|
| SetState(kStopped);
|
| +
|
| + missing_key_reported_ = false;
|
| }
|
|
|
| void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
|
| @@ -614,7 +621,13 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
|
|
|
| if (eos_enqueued_) {
|
| DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| - << ": eos_enqueued, returning";
|
| + << ": EOS enqueued, returning";
|
| + return true; // Nothing to do
|
| + }
|
| +
|
| + if (missing_key_reported_) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << ": NO KEY reported, returning";
|
| return true; // Nothing to do
|
| }
|
|
|
| @@ -694,18 +707,56 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
|
| }
|
|
|
| DCHECK(unit);
|
| + DCHECK(!unit->data.empty());
|
|
|
| - DVLOG(2) << class_name() << "::" << __FUNCTION__
|
| - << ": QueueInputBuffer pts:" << unit->timestamp;
|
| + if (unit->key_id.empty() || unit->iv.empty()) {
|
| + DVLOG(2) << class_name() << "::" << __FUNCTION__
|
| + << ": QueueInputBuffer pts:" << unit->timestamp;
|
|
|
| - status = media_codec_bridge_->QueueInputBuffer(
|
| - index, &unit->data[0], unit->data.size(), unit->timestamp);
|
| + status = media_codec_bridge_->QueueInputBuffer(
|
| + index, &unit->data[0], unit->data.size(), unit->timestamp);
|
| + } else {
|
| + DVLOG(2) << class_name() << "::" << __FUNCTION__
|
| + << ": QueueSecureInputBuffer pts:" << unit->timestamp
|
| + << " key_id size:" << unit->key_id.size()
|
| + << " iv size:" << unit->iv.size()
|
| + << " subsamples size:" << unit->subsamples.size();
|
|
|
| - if (status == MEDIA_CODEC_ERROR) {
|
| - DVLOG(0) << class_name() << "::" << __FUNCTION__
|
| - << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed";
|
| - media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
|
| - return false;
|
| + status = media_codec_bridge_->QueueSecureInputBuffer(
|
| + index, &unit->data[0], unit->data.size(),
|
| + reinterpret_cast<const uint8_t*>(&unit->key_id[0]), unit->key_id.size(),
|
| + reinterpret_cast<const uint8_t*>(&unit->iv[0]), unit->iv.size(),
|
| + unit->subsamples.empty() ? nullptr : &unit->subsamples[0],
|
| + unit->subsamples.size(), unit->timestamp);
|
| + }
|
| +
|
| + switch (status) {
|
| + case MEDIA_CODEC_OK:
|
| + break;
|
| +
|
| + case MEDIA_CODEC_ERROR:
|
| + DVLOG(0) << class_name() << "::" << __FUNCTION__
|
| + << ": MEDIA_CODEC_ERROR: QueueInputBuffer failed";
|
| + media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
|
| + return false;
|
| +
|
| + case MEDIA_CODEC_NO_KEY:
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << ": MEDIA_CODEC_NO_KEY";
|
| + media_task_runner_->PostTask(FROM_HERE, waiting_for_decryption_key_cb_);
|
| +
|
| + // In response to the |waiting_for_decryption_key_cb_| the player will
|
| + // request to stop decoder. We need to keep running to properly perform
|
| + // the stop, but prevent enqueuing the same frame over and over again so
|
| + // we won't generate more |waiting_for_decryption_key_cb_|.
|
| + missing_key_reported_ = true;
|
| + return true;
|
| +
|
| + default:
|
| + NOTREACHED() << class_name() << "::" << __FUNCTION__
|
| + << ": unexpected error code " << status;
|
| + media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
|
| + return false;
|
| }
|
|
|
| // Have successfully queued input buffer, go to next access unit.
|
|
|