summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorTima Vaisburd <timav@chromium.org>2016-02-08 11:26:24 -0800
committerTima Vaisburd <timav@chromium.org>2016-02-08 19:29:45 +0000
commit82f21c30d7edbe8aab03738f2d572a74ac5798d6 (patch)
tree97093b52772037643a6c7851d90b2880b85353ca /media
parent069f7de6a55c925d47cddf9ab9998faa59df40be (diff)
downloadchromium_src-82f21c30d7edbe8aab03738f2d572a74ac5798d6.zip
chromium_src-82f21c30d7edbe8aab03738f2d572a74ac5798d6.tar.gz
chromium_src-82f21c30d7edbe8aab03738f2d572a74ac5798d6.tar.bz2
[Merged M49] Fix MediaCodec's MEDIA_CODEC_NO_KEY processing in MediaCodecPlayer
When MediaCodec.queueSecureInputBuffer() return MEDIA_CODEC_NO_KEY, the input buffer is still owned by the client (i.e. not by MediaCodec) and is filled with proper input data. The correct behavior is to keep trying to queue it using the same input buffer index and not dequeue new input buffers, otherwise the input buffers pool depletes and might end, in which case the MediaCodec would be blocked. For simplicity, this CL performs an extra data copy to such buffer. This CL also resets the flag |missing_key_reported_| at the beginning of the Preroll() and Play() commands, otherwise the playback would never be resumed after the first MEDIA_CODEC_NO_KEY. BUG=579767 TBR=timav > Review URL: https://codereview.chromium.org/1618433002 > Cr-Commit-Position: refs/heads/master@{#371049} Review URL: https://codereview.chromium.org/1676163003 . Cr-Commit-Position: refs/branch-heads/2623@{#298} Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
Diffstat (limited to 'media')
-rw-r--r--media/base/android/media_codec_decoder.cc77
-rw-r--r--media/base/android/media_codec_decoder.h4
2 files changed, 57 insertions, 24 deletions
diff --git a/media/base/android/media_codec_decoder.cc b/media/base/android/media_codec_decoder.cc
index 67d7188..bf3c8a3 100644
--- a/media/base/android/media_codec_decoder.cc
+++ b/media/base/android/media_codec_decoder.cc
@@ -54,6 +54,7 @@ MediaCodecDecoder::MediaCodecDecoder(
waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
error_cb_(error_cb),
state_(kStopped),
+ pending_input_buf_index_(-1),
is_prepared_(false),
eos_enqueued_(false),
missing_key_reported_(false),
@@ -105,6 +106,8 @@ void MediaCodecDecoder::Flush() {
DCHECK(!decoder_thread_.IsRunning());
is_prepared_ = false;
+ pending_input_buf_index_ = -1;
+
#ifndef NDEBUG
// We check and reset |verify_next_frame_is_key_| on Decoder thread.
// We have just DCHECKed that decoder thread is not running.
@@ -135,6 +138,8 @@ void MediaCodecDecoder::ReleaseMediaCodec() {
// |is_prepared_| is set on the decoder thread, it shouldn't be running now.
is_prepared_ = false;
+
+ pending_input_buf_index_ = -1;
}
bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
@@ -280,6 +285,7 @@ bool MediaCodecDecoder::Preroll(const base::Closure& preroll_done_cb) {
DissociatePTSFromTime(); // associaton will happen after preroll is done.
last_frame_posted_ = false;
+ missing_key_reported_ = false;
// Start the decoder thread
if (!decoder_thread_.Start()) {
@@ -325,6 +331,7 @@ bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) {
// Start the decoder thread
if (!decoder_thread_.IsRunning()) {
last_frame_posted_ = false;
+ missing_key_reported_ = false;
if (!decoder_thread_.Start()) {
DVLOG(1) << class_name() << "::" << __FUNCTION__
<< ": cannot start decoder thread";
@@ -683,39 +690,51 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
// Dequeue input buffer
- base::TimeDelta timeout =
- base::TimeDelta::FromMilliseconds(kInputBufferTimeout);
- int index = -1;
- MediaCodecStatus status =
- media_codec_bridge_->DequeueInputBuffer(timeout, &index);
+ int index = pending_input_buf_index_;
- DVLOG(2) << class_name() << ":: DequeueInputBuffer index:" << index;
+ // Do not dequeue a new input buffer if we failed with MEDIA_CODEC_NO_KEY.
+ // That status does not return this buffer back to the pool of
+ // available input buffers. We have to reuse it in QueueSecureInputBuffer().
+ if (index == -1) {
+ base::TimeDelta timeout =
+ base::TimeDelta::FromMilliseconds(kInputBufferTimeout);
+ MediaCodecStatus status =
+ media_codec_bridge_->DequeueInputBuffer(timeout, &index);
- switch (status) {
- case MEDIA_CODEC_ERROR:
- DVLOG(0) << class_name() << "::" << __FUNCTION__
- << ": MEDIA_CODEC_ERROR DequeueInputBuffer failed";
- media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
- return false;
+ switch (status) {
+ case MEDIA_CODEC_ERROR:
+ DVLOG(0) << class_name() << "::" << __FUNCTION__
+ << ": MEDIA_CODEC_ERROR DequeueInputBuffer failed";
+ media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
+ return false;
- case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
- DVLOG(2)
- << class_name() << "::" << __FUNCTION__
- << ": DequeueInputBuffer returned MediaCodec.INFO_TRY_AGAIN_LATER.";
- return true;
+ case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
+ DVLOG(2)
+ << class_name() << "::" << __FUNCTION__
+ << ": DequeueInputBuffer returned MediaCodec.INFO_TRY_AGAIN_LATER.";
+ return true;
- default:
- break;
+ default:
+ break;
+ }
+
+ DCHECK_EQ(status, MEDIA_CODEC_OK);
}
+ DVLOG(2) << class_name() << "::" << __FUNCTION__
+ << ": using input buffer index:" << index;
+
// We got the buffer
- DCHECK_EQ(status, MEDIA_CODEC_OK);
DCHECK_GE(index, 0);
const AccessUnit* unit = au_info.front_unit;
if (drain_decoder_ || unit->is_end_of_stream) {
DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": QueueEOS";
+
+ // Check that we are not using the pending input buffer to queue EOS
+ DCHECK(pending_input_buf_index_ == -1);
+
media_codec_bridge_->QueueEOS(index);
eos_enqueued_ = true;
return true;
@@ -724,12 +743,19 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
DCHECK(unit);
DCHECK(!unit->data.empty());
+ // Pending input buffer is already filled with data.
+ const uint8_t* memory =
+ (pending_input_buf_index_ == -1) ? &unit->data[0] : nullptr;
+
+ pending_input_buf_index_ = -1;
+ MediaCodecStatus status = MEDIA_CODEC_OK;
+
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);
+ index, memory, unit->data.size(), unit->timestamp);
} else {
DVLOG(2) << class_name() << "::" << __FUNCTION__
<< ": QueueSecureInputBuffer pts:" << unit->timestamp
@@ -738,7 +764,7 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
<< " subsamples size:" << unit->subsamples.size();
status = media_codec_bridge_->QueueSecureInputBuffer(
- index, &unit->data[0], unit->data.size(), unit->key_id, unit->iv,
+ index, memory, unit->data.size(), unit->key_id, unit->iv,
unit->subsamples.empty() ? nullptr : &unit->subsamples[0],
unit->subsamples.size(), unit->timestamp);
}
@@ -758,10 +784,13 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
<< ": MEDIA_CODEC_NO_KEY";
media_task_runner_->PostTask(FROM_HERE, waiting_for_decryption_key_cb_);
+ // We need to enqueue the same input buffer after we get the key.
+ // The buffer is owned by us (not the MediaCodec) and is filled with data.
+ pending_input_buf_index_ = index;
+
// 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_|.
+ // the stop, but prevent generating more |waiting_for_decryption_key_cb_|.
missing_key_reported_ = true;
return true;
diff --git a/media/base/android/media_codec_decoder.h b/media/base/android/media_codec_decoder.h
index 82b4d7b..4135d27 100644
--- a/media/base/android/media_codec_decoder.h
+++ b/media/base/android/media_codec_decoder.h
@@ -426,6 +426,10 @@ class MediaCodecDecoder {
// Preroll timestamp is set if we need preroll and cleared after we done it.
base::TimeDelta preroll_timestamp_;
+ // Index of the dequeued and filled buffer that we keep trying to enqueue.
+ // Such buffer appears in MEDIA_CODEC_NO_KEY processing.
+ int pending_input_buf_index_;
+
// Set to true when MediaCodec internal buffers are filled up.
bool is_prepared_;