diff options
author | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-03 04:55:52 +0000 |
---|---|---|
committer | qinmin@chromium.org <qinmin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-03 04:55:52 +0000 |
commit | 1d92fe59c433a757b7b0bae28a11b8f773b831d8 (patch) | |
tree | 041089d06f96a9a2e3989c2590500ee78a5dc77d | |
parent | df87559411fe06079453d3e3f038f5044dcb2e0d (diff) | |
download | chromium_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.java | 20 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.cc | 74 | ||||
-rw-r--r-- | media/base/android/media_codec_bridge.h | 13 | ||||
-rw-r--r-- | media/base/android/media_source_player.cc | 17 |
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); } } |