summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/base/android/demuxer_stream_player_params.h5
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaCodecBridge.java101
-rw-r--r--media/base/android/media_codec_bridge.cc63
-rw-r--r--media/base/android/media_codec_bridge.h26
-rw-r--r--media/base/android/media_decoder_job.cc55
-rw-r--r--media/base/android/media_decoder_job.h4
-rw-r--r--media/base/android/media_drm_bridge.cc1
-rw-r--r--media/base/android/media_player_android.cc5
-rw-r--r--media/base/android/media_player_android.h4
-rw-r--r--media/base/android/media_source_player.cc29
-rw-r--r--media/base/android/media_source_player.h1
11 files changed, 197 insertions, 97 deletions
diff --git a/media/base/android/demuxer_stream_player_params.h b/media/base/android/demuxer_stream_player_params.h
index 92ef74f..4a3a04d 100644
--- a/media/base/android/demuxer_stream_player_params.h
+++ b/media/base/android/demuxer_stream_player_params.h
@@ -5,7 +5,9 @@
#ifndef MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
#define MEDIA_BASE_ANDROID_DEMUXER_STREAM_PLAYER_PARAMS_H_
+#if defined(GOOGLE_TV)
#include <string>
+#endif // defined(GOOGLE_TV)
#include <vector>
#include "media/base/audio_decoder_config.h"
@@ -33,7 +35,10 @@ struct MEDIA_EXPORT DemuxerConfigs {
std::vector<uint8> video_extra_data;
int duration_ms;
+
+#if defined(GOOGLE_TV)
std::string key_system;
+#endif // defined(GOOGLE_TV)
};
struct MEDIA_EXPORT AccessUnit {
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 42f1241..7025a1d 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -27,12 +27,20 @@ import org.chromium.base.JNINamespace;
*/
@JNINamespace("media")
class MediaCodecBridge {
-
private static final String TAG = "MediaCodecBridge";
// Error code for MediaCodecBridge. Keep this value in sync with
- // INFO_MEDIA_CODEC_ERROR in media_codec_bridge.h.
- private static final int MEDIA_CODEC_ERROR = -1000;
+ // MediaCodecStatus in media_codec_bridge.h.
+ private static final int MEDIA_CODEC_OK = 0;
+ private static final int MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER = 1;
+ private static final int MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER = 2;
+ private static final int MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED = 3;
+ private static final int MEDIA_CODEC_OUTPUT_FORMAT_CHANGED = 4;
+ private static final int MEDIA_CODEC_INPUT_END_OF_STREAM = 5;
+ private static final int MEDIA_CODEC_OUTPUT_END_OF_STREAM = 6;
+ private static final int MEDIA_CODEC_NO_KEY = 7;
+ private static final int MEDIA_CODEC_STOPPED = 8;
+ private static final int MEDIA_CODEC_ERROR = 9;
// After a flush(), dequeueOutputBuffer() can often produce empty presentation timestamps
// for several frames. As a result, the player may find that the time does not increase
@@ -50,15 +58,33 @@ class MediaCodecBridge {
private boolean mFlushed;
private long mLastPresentationTimeUs;
+ private static class DequeueInputResult {
+ private final int mStatus;
+ private final int mIndex;
+
+ private DequeueInputResult(int status, int index) {
+ mStatus = status;
+ mIndex = index;
+ }
+
+ @CalledByNative("DequeueInputResult")
+ private int status() { return mStatus; }
+
+ @CalledByNative("DequeueInputResult")
+ private int index() { return mIndex; }
+ }
+
private static class DequeueOutputResult {
+ private final int mStatus;
private final int mIndex;
private final int mFlags;
private final int mOffset;
private final long mPresentationTimeMicroseconds;
private final int mNumBytes;
- private DequeueOutputResult(int index, int flags, int offset,
+ private DequeueOutputResult(int status, int index, int flags, int offset,
long presentationTimeMicroseconds, int numBytes) {
+ mStatus = status;
mIndex = index;
mFlags = flags;
mOffset = offset;
@@ -67,6 +93,9 @@ class MediaCodecBridge {
}
@CalledByNative("DequeueOutputResult")
+ private int status() { return mStatus; }
+
+ @CalledByNative("DequeueOutputResult")
private int index() { return mIndex; }
@CalledByNative("DequeueOutputResult")
@@ -143,13 +172,24 @@ class MediaCodecBridge {
}
@CalledByNative
- private int dequeueInputBuffer(long timeoutUs) {
+ private DequeueInputResult dequeueInputBuffer(long timeoutUs) {
+ int status = MEDIA_CODEC_ERROR;
+ int index = -1;
try {
- return mMediaCodec.dequeueInputBuffer(timeoutUs);
+ int index_or_status = mMediaCodec.dequeueInputBuffer(timeoutUs);
+ if (index_or_status >= 0) { // index!
+ status = MEDIA_CODEC_OK;
+ index = index_or_status;
+ } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER");
+ status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER;
+ } else {
+ assert(false);
+ }
} catch(Exception e) {
- Log.e(TAG, "Cannot dequeue Input buffer " + e.toString());
+ Log.e(TAG, "Failed to dequeue input buffer: " + e.toString());
}
- return MEDIA_CODEC_ERROR;
+ return new DequeueInputResult(status, index);
}
@CalledByNative
@@ -190,18 +230,20 @@ class MediaCodecBridge {
}
@CalledByNative
- private void queueInputBuffer(
+ private int queueInputBuffer(
int index, int offset, int size, long presentationTimeUs, int flags) {
resetLastPresentationTimeIfNeeded(presentationTimeUs);
try {
mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
- } catch(IllegalStateException e) {
- Log.e(TAG, "Failed to queue input buffer " + e.toString());
+ } catch(Exception e) {
+ Log.e(TAG, "Failed to queue input buffer: " + e.toString());
+ return MEDIA_CODEC_ERROR;
}
+ return MEDIA_CODEC_OK;
}
@CalledByNative
- private void queueSecureInputBuffer(
+ private int queueSecureInputBuffer(
int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData,
int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) {
resetLastPresentationTimeIfNeeded(presentationTimeUs);
@@ -210,9 +252,19 @@ class MediaCodecBridge {
cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData,
keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR);
mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0);
+ } catch (MediaCodec.CryptoException e) {
+ Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
+ // TODO(xhwang): Replace hard coded value with constant/enum.
+ if (e.getErrorCode() == 1) {
+ Log.e(TAG, "No key available.");
+ return MEDIA_CODEC_NO_KEY;
+ }
+ return MEDIA_CODEC_ERROR;
} catch(IllegalStateException e) {
- Log.e(TAG, "Failed to queue secure input buffer " + e.toString());
+ Log.e(TAG, "Failed to queue secure input buffer: " + e.toString());
+ return MEDIA_CODEC_ERROR;
}
+ return MEDIA_CODEC_OK;
}
@CalledByNative
@@ -228,9 +280,10 @@ class MediaCodecBridge {
@CalledByNative
private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) {
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
- int index = MEDIA_CODEC_ERROR;
+ int status = MEDIA_CODEC_ERROR;
+ int index = -1;
try {
- index = mMediaCodec.dequeueOutputBuffer(info, timeoutUs);
+ int index_or_status = mMediaCodec.dequeueOutputBuffer(info, timeoutUs);
if (info.presentationTimeUs < mLastPresentationTimeUs) {
// TODO(qinmin): return a special code through DequeueOutputResult
// to notify the native code the the frame has a wrong presentation
@@ -238,11 +291,25 @@ class MediaCodecBridge {
info.presentationTimeUs = mLastPresentationTimeUs;
}
mLastPresentationTimeUs = info.presentationTimeUs;
+
+ if (index_or_status >= 0) { // index!
+ status = MEDIA_CODEC_OK;
+ index = index_or_status;
+ } else if (index_or_status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED;
+ } else if (index_or_status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
+ } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
+ } else {
+ assert(false);
+ }
} catch (IllegalStateException e) {
- Log.e(TAG, "Cannot dequeue output buffer " + e.toString());
+ Log.e(TAG, "Failed to dequeue output buffer: " + e.toString());
}
+
return new DequeueOutputResult(
- index, info.flags, info.offset, info.presentationTimeUs, info.size);
+ status, index, info.flags, info.offset, info.presentationTimeUs, info.size);
}
@CalledByNative
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index 8952433..f5c73a0 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -128,23 +128,24 @@ void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
*height = Java_MediaCodecBridge_getOutputHeight(env, j_media_codec_.obj());
}
-size_t MediaCodecBridge::QueueInputBuffer(
- int index, const uint8* data, int size,
+MediaCodecStatus MediaCodecBridge::QueueInputBuffer(
+ int index, const uint8* data, int data_size,
const base::TimeDelta& presentation_time) {
- size_t size_to_copy = FillInputBuffer(index, data, size);
+ int size_to_copy = FillInputBuffer(index, data, data_size);
+ DCHECK_EQ(size_to_copy, data_size);
JNIEnv* env = AttachCurrentThread();
- Java_MediaCodecBridge_queueInputBuffer(
+ return static_cast<MediaCodecStatus>(Java_MediaCodecBridge_queueInputBuffer(
env, j_media_codec_.obj(),
- index, 0, size_to_copy, presentation_time.InMicroseconds(), 0);
- return size_to_copy;
+ index, 0, size_to_copy, presentation_time.InMicroseconds(), 0));
}
-size_t MediaCodecBridge::QueueSecureInputBuffer(
+MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer(
int index, const uint8* data, int data_size, const uint8* key_id,
int key_id_size, const uint8* iv, int iv_size,
const SubsampleEntry* subsamples, int subsamples_size,
const base::TimeDelta& presentation_time) {
- size_t size_to_copy = FillInputBuffer(index, data, data_size);
+ int size_to_copy = FillInputBuffer(index, data, data_size);
+ DCHECK_EQ(size_to_copy, data_size);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> j_key_id =
@@ -162,12 +163,11 @@ size_t MediaCodecBridge::QueueSecureInputBuffer(
ScopedJavaLocalRef<jintArray> cypher_array = ToJavaIntArray(
env, native_cypher_array.Pass(), subsamples_size);
- Java_MediaCodecBridge_queueSecureInputBuffer(
- env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
- clear_array.obj(), cypher_array.obj(), subsamples_size,
- presentation_time.InMicroseconds());
-
- return size_to_copy;
+ return static_cast<MediaCodecStatus>(
+ Java_MediaCodecBridge_queueSecureInputBuffer(
+ env, j_media_codec_.obj(), index, 0, j_iv.obj(), j_key_id.obj(),
+ clear_array.obj(), cypher_array.obj(), subsamples_size,
+ presentation_time.InMicroseconds()));
}
void MediaCodecBridge::QueueEOS(int input_buffer_index) {
@@ -180,41 +180,21 @@ void MediaCodecBridge::QueueEOS(int input_buffer_index) {
MediaCodecStatus MediaCodecBridge::DequeueInputBuffer(
const base::TimeDelta& timeout, int* index) {
JNIEnv* env = AttachCurrentThread();
- int result = Java_MediaCodecBridge_dequeueInputBuffer(
+ ScopedJavaLocalRef<jobject> result = Java_MediaCodecBridge_dequeueInputBuffer(
env, j_media_codec_.obj(), timeout.InMicroseconds());
- if (result == INFO_MEDIA_CODEC_ERROR)
- return MEDIA_CODEC_ERROR;
- else if (result == INFO_TRY_AGAIN_LATER)
- return MEDIA_CODEC_ENQUEUE_INPUT_AGAIN_LATER;
-
- DCHECK_GE(result, 0);
- *index = result;
- return MEDIA_CODEC_OK;
+ *index = Java_DequeueInputResult_index(env, result.obj());
+ return static_cast<MediaCodecStatus>(
+ Java_DequeueInputResult_status(env, result.obj()));
}
MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer(
const base::TimeDelta& timeout, int* index, size_t* offset, size_t* size,
base::TimeDelta* presentation_time, bool* end_of_stream) {
JNIEnv* env = AttachCurrentThread();
-
ScopedJavaLocalRef<jobject> result =
Java_MediaCodecBridge_dequeueOutputBuffer(env, j_media_codec_.obj(),
timeout.InMicroseconds());
-
- int j_index = Java_DequeueOutputResult_index(env, result.obj());
- switch (j_index) {
- case INFO_OUTPUT_BUFFERS_CHANGED:
- return MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED;
- case INFO_OUTPUT_FORMAT_CHANGED:
- return MEDIA_CODEC_OUTPUT_FORMAT_CHANGED;
- case INFO_TRY_AGAIN_LATER:
- return MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER;
- case INFO_MEDIA_CODEC_ERROR:
- return MEDIA_CODEC_ERROR;
- }
-
- DCHECK_GE(j_index, 0);
- *index = j_index;
+ *index = Java_DequeueOutputResult_index(env, result.obj());;
*offset = base::checked_numeric_cast<size_t>(
Java_DequeueOutputResult_offset(env, result.obj()));
*size = base::checked_numeric_cast<size_t>(
@@ -223,7 +203,8 @@ MediaCodecStatus MediaCodecBridge::DequeueOutputBuffer(
Java_DequeueOutputResult_presentationTimeMicroseconds(env, result.obj()));
int flags = Java_DequeueOutputResult_flags(env, result.obj());
*end_of_stream = flags & kBufferFlagEndOfStream;
- return MEDIA_CODEC_OK;
+ return static_cast<MediaCodecStatus>(
+ Java_DequeueOutputResult_status(env, result.obj()));
}
void MediaCodecBridge::ReleaseOutputBuffer(int index, bool render) {
@@ -303,7 +284,7 @@ bool AudioCodecBridge::ConfigureMediaFormat(
return true;
JNIEnv* env = AttachCurrentThread();
- switch(codec) {
+ switch (codec) {
case kCodecVorbis:
{
if (extra_data[0] != 2) {
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index 47c3f89..9f855be 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -18,14 +18,17 @@ namespace media {
struct SubsampleEntry;
+// These must be in sync with MediaCodecBridge.MEDIA_CODEC_XXX constants in
+// MediaCodecBridge.java.
enum MediaCodecStatus {
MEDIA_CODEC_OK,
- MEDIA_CODEC_ENQUEUE_INPUT_AGAIN_LATER,
+ MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER,
MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER,
MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED,
MEDIA_CODEC_OUTPUT_FORMAT_CHANGED,
MEDIA_CODEC_INPUT_END_OF_STREAM,
MEDIA_CODEC_OUTPUT_END_OF_STREAM,
+ MEDIA_CODEC_NO_KEY,
MEDIA_CODEC_STOPPED,
MEDIA_CODEC_ERROR
};
@@ -38,13 +41,6 @@ enum MediaCodecStatus {
// object.
class MEDIA_EXPORT MediaCodecBridge {
public:
- enum DequeueBufferInfo {
- INFO_OUTPUT_BUFFERS_CHANGED = -3,
- INFO_OUTPUT_FORMAT_CHANGED = -2,
- INFO_TRY_AGAIN_LATER = -1,
- INFO_MEDIA_CODEC_ERROR = -1000,
- };
-
// Returns true if MediaCodec is available on the device.
static bool IsAvailable();
@@ -72,14 +68,16 @@ class MEDIA_EXPORT MediaCodecBridge {
void GetOutputFormat(int* width, int* height);
// Submits a byte array to the given input buffer. Call this after getting an
- // available buffer from DequeueInputBuffer(). Returns the number of bytes
- // put to the input buffer.
- size_t QueueInputBuffer(int index, const uint8* data, int size,
- const base::TimeDelta& presentation_time);
+ // available buffer from DequeueInputBuffer().
+ MediaCodecStatus QueueInputBuffer(int index,
+ const uint8* data,
+ int size,
+ const base::TimeDelta& presentation_time);
// Similar to the above call, but submits a buffer that is encrypted.
- size_t QueueSecureInputBuffer(
- int index, const uint8* data, int data_size,
+ MediaCodecStatus QueueSecureInputBuffer(
+ int index,
+ const uint8* data, int data_size,
const uint8* key_id, int key_id_size,
const uint8* iv, int iv_size,
const SubsampleEntry* subsamples, int subsamples_size,
diff --git a/media/base/android/media_decoder_job.cc b/media/base/android/media_decoder_job.cc
index 3230e236..33b48302 100644
--- a/media/base/android/media_decoder_job.cc
+++ b/media/base/android/media_decoder_job.cc
@@ -29,6 +29,7 @@ MediaDecoderJob::MediaDecoderJob(
weak_this_(this),
request_data_cb_(request_data_cb),
access_unit_index_(0),
+ input_buf_index_(-1),
stop_decode_pending_(false),
destroy_pending_(false) {
}
@@ -36,6 +37,7 @@ MediaDecoderJob::MediaDecoderJob(
MediaDecoderJob::~MediaDecoderJob() {}
void MediaDecoderJob::OnDataReceived(const DemuxerData& data) {
+ DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units";
DCHECK(ui_loop_->BelongsToCurrentThread());
DCHECK(!on_data_received_cb_.is_null());
@@ -132,44 +134,59 @@ void MediaDecoderJob::Release() {
delete this;
}
-MediaCodecStatus MediaDecoderJob::QueueInputBuffer(
- const AccessUnit& unit) {
- base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
- kMediaCodecTimeoutInMilliseconds);
- int input_buf_index = 0;
- MediaCodecStatus status =
- media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index);
- if (status != MEDIA_CODEC_OK)
- return status;
+MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(decoder_loop_->BelongsToCurrentThread());
+
+ int input_buf_index = input_buf_index_;
+ input_buf_index_ = -1;
+
+ // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge.
+ if (input_buf_index == -1) {
+ base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
+ kMediaCodecTimeoutInMilliseconds);
+ MediaCodecStatus status =
+ media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index);
+ if (status != MEDIA_CODEC_OK) {
+ DVLOG(1) << "DequeueInputBuffer fails: " << status;
+ return status;
+ }
+ }
// TODO(qinmin): skip frames if video is falling far behind.
DCHECK_GE(input_buf_index, 0);
if (unit.end_of_stream || unit.data.empty()) {
- media_codec_bridge_->QueueEOS(input_buf_index);
+ media_codec_bridge_->QueueEOS(input_buf_index_);
return MEDIA_CODEC_INPUT_END_OF_STREAM;
}
if (unit.key_id.empty()) {
- media_codec_bridge_->QueueInputBuffer(
+ return media_codec_bridge_->QueueInputBuffer(
input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
- return MEDIA_CODEC_OK;
}
if (unit.iv.empty() || unit.subsamples.empty()) {
- LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
+ DVLOG(1) << "The access unit doesn't have iv or subsamples while it "
<< "has key IDs!";
return MEDIA_CODEC_ERROR;
}
- media_codec_bridge_->QueueSecureInputBuffer(
+ MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer(
input_buf_index, &unit.data[0], unit.data.size(),
reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
&unit.subsamples[0], unit.subsamples.size(), unit.timestamp);
- return MEDIA_CODEC_OK;
+
+ // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|.
+ // Otherwise MediaDrm will report errors.
+ if (status == MEDIA_CODEC_NO_KEY)
+ input_buf_index_ = input_buf_index;
+
+ return status;
}
void MediaDecoderJob::RequestData(const base::Closure& done_cb) {
+ DVLOG(1) << __FUNCTION__;
DCHECK(ui_loop_->BelongsToCurrentThread());
DCHECK(on_data_received_cb_.is_null());
@@ -201,6 +218,9 @@ void MediaDecoderJob::DecodeInternal(
const base::TimeDelta& start_presentation_timestamp,
bool needs_flush,
const MediaDecoderJob::DecoderCallback& callback) {
+ DVLOG(1) << __FUNCTION__;
+ DCHECK(decoder_loop_->BelongsToCurrentThread());
+
if (needs_flush) {
DVLOG(1) << "DecodeInternal needs flush.";
input_eos_encountered_ = false;
@@ -259,7 +279,7 @@ void MediaDecoderJob::DecodeInternal(
// TODO(acolwell): Change to > since the else will never run for audio.
if (time_to_render >= base::TimeDelta()) {
- base::MessageLoop::current()->PostDelayedTask(
+ decoder_loop_->PostDelayedTask(
FROM_HERE,
base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
weak_this_.GetWeakPtr(), buffer_index, size,
@@ -289,8 +309,9 @@ void MediaDecoderJob::OnDecodeCompleted(
DCHECK(!decode_cb_.is_null());
if (status != MEDIA_CODEC_ERROR &&
- status != MEDIA_CODEC_ENQUEUE_INPUT_AGAIN_LATER &&
+ status != MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER &&
status != MEDIA_CODEC_INPUT_END_OF_STREAM &&
+ status != MEDIA_CODEC_NO_KEY &&
status != MEDIA_CODEC_STOPPED) {
access_unit_index_++;
}
diff --git a/media/base/android/media_decoder_job.h b/media/base/android/media_decoder_job.h
index 661f462..e54080e 100644
--- a/media/base/android/media_decoder_job.h
+++ b/media/base/android/media_decoder_job.h
@@ -151,6 +151,10 @@ class MediaDecoderJob {
// Data received over IPC from last RequestData() operation.
DemuxerData received_data_;
+ // The index of input buffer that can be used by QueueInputBuffer().
+ // If the index is uninitialized or invalid, it must be -1.
+ int input_buf_index_;
+
bool stop_decode_pending_;
// Indicates that this object should be destroyed once the current
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 7c6c25a..d529977 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -235,6 +235,7 @@ bool MediaDrmBridge::GenerateKeyRequest(const std::string& type,
void MediaDrmBridge::AddKey(const uint8* key, int key_length,
const uint8* init_data, int init_data_length,
const std::string& session_id) {
+ DVLOG(1) << __FUNCTION__;
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> j_key_data =
base::android::ToJavaByteArray(env, key, key_length);
diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc
index 6b1626a..ab249ac 100644
--- a/media/base/android/media_player_android.cc
+++ b/media/base/android/media_player_android.cc
@@ -92,4 +92,9 @@ void MediaPlayerAndroid::SetDrmBridge(MediaDrmBridge* drm_bridge) {
return;
}
+void MediaPlayerAndroid::OnKeyAdded() {
+ // Not all players care about the decryption key. Do nothing by default.
+ return;
+}
+
} // namespace media
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h
index 06cb573..a767e5f 100644
--- a/media/base/android/media_player_android.h
+++ b/media/base/android/media_player_android.h
@@ -102,6 +102,10 @@ class MEDIA_EXPORT MediaPlayerAndroid {
// Pass a drm bridge to a player.
virtual void SetDrmBridge(MediaDrmBridge* drm_bridge);
+ // Notifies the player that a decryption key has been added. The player
+ // may want to start/resume playback if it is waiting for a key.
+ virtual void OnKeyAdded();
+
int player_id() { return player_id_; }
protected:
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index af1f2b1..d657fca 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -4,6 +4,8 @@
#include "media/base/android/media_source_player.h"
+#include <limits>
+
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/barrier_closure.h"
@@ -185,6 +187,12 @@ void MediaSourcePlayer::SetVolume(double volume) {
SetVolumeInternal();
}
+void MediaSourcePlayer::OnKeyAdded() {
+ DVLOG(1) << __FUNCTION__;
+ if (playing_)
+ StartInternal();
+}
+
bool MediaSourcePlayer::CanPause() {
return Seekable();
}
@@ -211,7 +219,6 @@ void MediaSourcePlayer::StartInternal() {
ConfigureAudioDecoderJob();
ConfigureVideoDecoderJob();
-
// If one of the decoder job is not ready, do nothing.
if ((HasAudio() && !audio_decoder_job_) ||
(HasVideo() && !video_decoder_job_)) {
@@ -346,12 +353,15 @@ void MediaSourcePlayer::UpdateTimestamps(
}
void MediaSourcePlayer::ProcessPendingEvents() {
- DVLOG(1) << __FUNCTION__ << " : 0x"
- << std::hex << pending_event_;
+ DVLOG(1) << __FUNCTION__ << " : 0x" << std::hex << pending_event_;
// Wait for all the decoding jobs to finish before processing pending tasks.
- if ((audio_decoder_job_ && audio_decoder_job_->is_decoding()) ||
- (video_decoder_job_ && video_decoder_job_->is_decoding())) {
- DVLOG(1) << __FUNCTION__ << " : A job is still decoding.";
+ if (video_decoder_job_ && video_decoder_job_->is_decoding()) {
+ DVLOG(1) << __FUNCTION__ << " : A video job is still decoding.";
+ return;
+ }
+
+ if (audio_decoder_job_ && audio_decoder_job_->is_decoding()) {
+ DVLOG(1) << __FUNCTION__ << " : An audio job is still decoding.";
return;
}
@@ -412,7 +422,7 @@ void MediaSourcePlayer::ProcessPendingEvents() {
void MediaSourcePlayer::MediaDecoderCallback(
bool is_audio, MediaCodecStatus status,
const base::TimeDelta& presentation_timestamp, size_t audio_output_bytes) {
- DVLOG(1) << __FUNCTION__;
+ DVLOG(1) << __FUNCTION__ << ": " << is_audio << ", " << status;
if (is_audio)
decoder_starvation_callback_.Cancel();
@@ -442,6 +452,9 @@ void MediaSourcePlayer::MediaDecoderCallback(
return;
}
+ if (status == MEDIA_CODEC_NO_KEY)
+ return;
+
base::TimeDelta current_timestamp = GetCurrentTime();
if (is_audio) {
if (status == MEDIA_CODEC_OK) {
@@ -449,7 +462,7 @@ void MediaSourcePlayer::MediaDecoderCallback(
audio_timestamp_helper_->GetTimestamp() - current_timestamp;
StartStarvationCallback(timeout);
}
- DecodeMoreAudio();
+ DecodeMoreAudio();
return;
}
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index 7db76c3..fd262d7 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -67,6 +67,7 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid {
virtual void ReadFromDemuxerAck(const DemuxerData& data) OVERRIDE;
virtual void DurationChanged(const base::TimeDelta& duration) OVERRIDE;
virtual void SetDrmBridge(MediaDrmBridge* drm_bridge) OVERRIDE;
+ virtual void OnKeyAdded() OVERRIDE;
private:
// Update the current timestamp.