summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-03 04:55:52 +0000
committerqinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-03 04:55:52 +0000
commit1d92fe59c433a757b7b0bae28a11b8f773b831d8 (patch)
tree041089d06f96a9a2e3989c2590500ee78a5dc77d
parentdf87559411fe06079453d3e3f038f5044dcb2e0d (diff)
downloadchromium_src-1d92fe59c433a757b7b0bae28a11b8f773b831d8.zip
chromium_src-1d92fe59c433a757b7b0bae28a11b8f773b831d8.tar.gz
chromium_src-1d92fe59c433a757b7b0bae28a11b8f773b831d8.tar.bz2
Adding a call to push crypto info into MediaCodecBridge
BUG=163552 Review URL: https://chromiumcodereview.appspot.com/18436002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209896 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/base/android/java/src/org/chromium/media/MediaCodecBridge.java20
-rw-r--r--media/base/android/media_codec_bridge.cc74
-rw-r--r--media/base/android/media_codec_bridge.h13
-rw-r--r--media/base/android/media_source_player.cc17
4 files changed, 109 insertions, 15 deletions
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 18bc529..731f868 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -142,7 +142,25 @@ class MediaCodecBridge {
@CalledByNative
private void queueInputBuffer(
int index, int offset, int size, long presentationTimeUs, int flags) {
- mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
+ try {
+ mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags);
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Failed to queue input buffer " + e.toString());
+ }
+ }
+
+ @CalledByNative
+ private void queueSecureInputBuffer(
+ int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData,
+ int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) {
+ try {
+ MediaCodec.CryptoInfo cryptoInfo = new MediaCodec.CryptoInfo();
+ cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData,
+ keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR);
+ mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0);
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Failed to queue secure input buffer " + e.toString());
+ }
}
@CalledByNative
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index 97e9c48..d539f700 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -17,6 +17,7 @@
#include "base/strings/stringprintf.h"
#include "jni/MediaCodecBridge_jni.h"
#include "media/base/bit_reader.h"
+#include "media/base/decrypt_config.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
@@ -50,6 +51,15 @@ static const char* VideoCodecToMimeType(const VideoCodec codec) {
}
}
+static ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+ JNIEnv* env, scoped_ptr<jint[]> native_array, int size) {
+ ScopedJavaLocalRef<jintArray> j_array;
+ j_array.Reset(env, env->NewIntArray(size));
+ env->SetIntArrayRegion(j_array.obj(), 0, size,
+ native_array.get());
+ return j_array;
+}
+
// static
const base::TimeDelta MediaCodecBridge::kTimeOutInfinity =
base::TimeDelta::FromMicroseconds(-1);
@@ -106,25 +116,44 @@ void MediaCodecBridge::GetOutputFormat(int* width, int* height) {
size_t MediaCodecBridge::QueueInputBuffer(
int index, const uint8* data, int size,
const base::TimeDelta& presentation_time) {
+ size_t size_to_copy = FillInputBuffer(index, data, size);
JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jobject> j_buffer(
- Java_MediaCodecBridge_getInputBuffer(env, j_media_codec_.obj(), index));
-
- uint8* direct_buffer =
- static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
- int64 buffer_capacity = env->GetDirectBufferCapacity(j_buffer.obj());
-
- size_t size_to_copy = (buffer_capacity < size) ? buffer_capacity : size;
-
- if (size_to_copy > 0)
- memcpy(direct_buffer, data, size_to_copy);
Java_MediaCodecBridge_queueInputBuffer(
env, j_media_codec_.obj(),
index, 0, size_to_copy, presentation_time.InMicroseconds(), 0);
return size_to_copy;
}
+size_t 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);
+
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jbyteArray> j_key_id =
+ base::android::ToJavaByteArray(env, key_id, key_id_size);
+ ScopedJavaLocalRef<jbyteArray> j_iv =
+ base::android::ToJavaByteArray(env, iv, iv_size);
+ scoped_ptr<jint[]> native_clear_array(new jint[subsamples_size]);
+ scoped_ptr<jint[]> native_cypher_array(new jint[subsamples_size]);
+ for (int i = 0; i < subsamples_size; ++i) {
+ native_clear_array[i] = subsamples[i].clear_bytes;
+ native_cypher_array[i] = subsamples[i].cypher_bytes;
+ }
+ ScopedJavaLocalRef<jintArray> clear_array = ToJavaIntArray(
+ env, native_clear_array.Pass(), subsamples_size);
+ 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;
+}
+
void MediaCodecBridge::QueueEOS(int input_buffer_index) {
JNIEnv* env = AttachCurrentThread();
Java_MediaCodecBridge_queueInputBuffer(
@@ -177,6 +206,27 @@ void MediaCodecBridge::GetOutputBuffers() {
Java_MediaCodecBridge_getOutputBuffers(env, j_media_codec_.obj());
}
+size_t MediaCodecBridge::FillInputBuffer(
+ int index, const uint8* data, int size) {
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jobject> j_buffer(
+ Java_MediaCodecBridge_getInputBuffer(env, j_media_codec_.obj(), index));
+
+ uint8* direct_buffer =
+ static_cast<uint8*>(env->GetDirectBufferAddress(j_buffer.obj()));
+ int64 buffer_capacity = env->GetDirectBufferCapacity(j_buffer.obj());
+
+ int size_to_copy = (buffer_capacity < size) ? buffer_capacity : size;
+ // TODO(qinmin): Handling the case that not all the data can be copied.
+ DCHECK(size_to_copy == size) <<
+ "Failed to fill all the data into the input buffer. Size to fill: "
+ << size << ". Size filled: " << size_to_copy;
+ if (size_to_copy > 0)
+ memcpy(direct_buffer, data, size_to_copy);
+ return size_to_copy;
+}
+
AudioCodecBridge::AudioCodecBridge(const char* mime)
: MediaCodecBridge(mime) {
}
diff --git a/media/base/android/media_codec_bridge.h b/media/base/android/media_codec_bridge.h
index c13634d..14694d6 100644
--- a/media/base/android/media_codec_bridge.h
+++ b/media/base/android/media_codec_bridge.h
@@ -16,6 +16,8 @@
namespace media {
+struct SubsampleEntry;
+
// This class serves as a bridge for native code to call java functions inside
// Android MediaCodec class. For more information on Android MediaCodec, check
// http://developer.android.com/reference/android/media/MediaCodec.html
@@ -62,6 +64,14 @@ class MEDIA_EXPORT MediaCodecBridge {
size_t 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,
+ 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);
+
// Submits an empty buffer with a EOS (END OF STREAM) flag.
void QueueEOS(int input_buffer_index);
@@ -98,6 +108,9 @@ class MEDIA_EXPORT MediaCodecBridge {
jobject media_codec() { return j_media_codec_.obj(); }
private:
+ // Fills a particular input buffer and returns the size of copied data.
+ size_t FillInputBuffer(int index, const uint8* data, int data_size);
+
// Java MediaCodec instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_codec_;
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index f76b4da..1929f49 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -132,11 +132,24 @@ void MediaDecoderJob::DecodeInternal(
}
// TODO(qinmin): skip frames if video is falling far behind.
if (input_buf_index >= 0) {
- if (unit.end_of_stream) {
+ if (unit.end_of_stream || unit.data.empty()) {
media_codec_bridge_->QueueEOS(input_buf_index);
- } else {
+ } else if (unit.key_id.empty()){
media_codec_bridge_->QueueInputBuffer(
input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
+ } else {
+ if (unit.iv.empty() || unit.subsamples.empty()) {
+ LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
+ << "has key IDs!";
+ ui_loop_->PostTask(FROM_HERE, base::Bind(
+ callback, DECODE_FAILED, start_presentation_timestamp, 0, false));
+ return;
+ }
+ 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);
}
}