| 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..d3893e518a1634adab8ff3cec6f40650b5a1a9c0 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& key_required_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),
|
| + key_required_cb_(key_required_cb),
|
| error_cb_(error_cb),
|
| state_(kStopped),
|
| is_prepared_(false),
|
| eos_enqueued_(false),
|
| + key_request_posted_(false),
|
| completed_(false),
|
| last_frame_posted_(false),
|
| is_data_request_in_progress_(false),
|
| @@ -179,14 +182,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 +203,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 +235,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 +403,8 @@ void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) {
|
| SetState(kStopped);
|
| completed_ = (eos_encountered && !drain_decoder_);
|
|
|
| + key_request_posted_ = 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 +502,8 @@ void MediaCodecDecoder::DoEmergencyStop() {
|
| decoder_thread_.Stop(); // synchronous
|
|
|
| SetState(kStopped);
|
| +
|
| + key_request_posted_ = false;
|
| }
|
|
|
| void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
|
| @@ -618,6 +624,12 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
|
| return true; // Nothing to do
|
| }
|
|
|
| + if (key_request_posted_) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << ": key_request_posted, returning";
|
| + return true; // Nothing to do
|
| + }
|
| +
|
| // Keep the number pending video frames low, ideally maintaining
|
| // the same audio and video duration after stop request
|
| if (NumDelayedRenderTasks() > 1) {
|
| @@ -695,17 +707,54 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
|
|
|
| DCHECK(unit);
|
|
|
| - 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, key_required_cb_);
|
| +
|
| + // In response to the |key_required_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 |key_required_cb_|.
|
| + key_request_posted_ = 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.
|
|
|