Index: media/base/android/java/src/org/chromium/media/MediaCodecBridge.java |
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 4b3dce0885ed05d961e6b8d1362f57f774e5fccc..d33bfa435bfd1f2d909c12294b9bfbd515d6a03b 100644 |
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java |
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java |
@@ -7,6 +7,7 @@ package org.chromium.media; |
import android.annotation.TargetApi; |
import android.media.AudioFormat; |
import android.media.MediaCodec; |
+import android.media.MediaCodec.CryptoInfo; |
import android.media.MediaCrypto; |
import android.media.MediaFormat; |
import android.os.Build; |
@@ -54,6 +55,14 @@ class MediaCodecBridge { |
// We use only one output audio format (PCM16) that has 2 bytes per sample |
private static final int PCM16_BYTES_PER_SAMPLE = 2; |
+ // The following values should be kept in sync with the media::EncryptionScheme::CipherMode |
+ // enum in media/base/encryption_scheme.h |
+ private static final int MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_UNENCRYPTED = 0; |
+ private static final int MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_AES_CTR = 1; |
+ private static final int MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_AES_CBC = 2; |
+ |
+ private static final int MEDIA_CODEC_UNKNOWN_CIPHER_MODE = -1; |
+ |
// TODO(qinmin): Use MediaFormat constants when part of the public API. |
private static final String KEY_CROP_LEFT = "crop-left"; |
private static final String KEY_CROP_RIGHT = "crop-right"; |
@@ -401,15 +410,50 @@ class MediaCodecBridge { |
} |
} |
+ // Incoming |native| values are as defined in media/base/encryption_scheme.h. Translated values |
+ // are from MediaCodec. At present, these values are in sync. Returns |
+ // MEDIA_CODEC_UNKNOWN_CIPHER_MODE in the case of unknown incoming value. |
+ private int translateCipherModeValue(int nativeValue) { |
+ switch (nativeValue) { |
+ case MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_UNENCRYPTED: |
+ return MediaCodec.CRYPTO_MODE_UNENCRYPTED; |
+ case MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_AES_CTR: |
+ return MediaCodec.CRYPTO_MODE_AES_CTR; |
+ case MEDIA_ENCRYPTION_SCHEME_CIPHER_MODE_AES_CBC: |
+ return MediaCodec.CRYPTO_MODE_AES_CBC; |
+ default: |
+ Log.e(TAG, "Unsupported cipher mode: " + nativeValue); |
+ return MEDIA_CODEC_UNKNOWN_CIPHER_MODE; |
+ } |
+ } |
+ |
@CalledByNative |
- private int queueSecureInputBuffer( |
- int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClearData, |
- int[] numBytesOfEncryptedData, int numSubSamples, long presentationTimeUs) { |
+ private int queueSecureInputBuffer(int index, int offset, byte[] iv, byte[] keyId, |
+ int[] numBytesOfClearData, int[] numBytesOfEncryptedData, int numSubSamples, |
+ int cipherMode, int patternEncrypt, int patternSkip, long presentationTimeUs) { |
resetLastPresentationTimeIfNeeded(presentationTimeUs); |
try { |
- MediaCodec.CryptoInfo cryptoInfo = new MediaCodec.CryptoInfo(); |
- cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData, |
- keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR); |
+ cipherMode = translateCipherModeValue(cipherMode); |
+ if (cipherMode == MEDIA_CODEC_UNKNOWN_CIPHER_MODE) { |
+ return MEDIA_CODEC_ERROR; |
+ } |
+ boolean usesCbcs = cipherMode == MediaCodec.CRYPTO_MODE_AES_CBC; |
+ if (usesCbcs && !MediaCodecUtil.platformSupportsCbcsEncryption()) { |
+ Log.e(TAG, "Encryption scheme 'cbcs' not supported on this platform."); |
+ return MEDIA_CODEC_ERROR; |
+ } |
+ CryptoInfo cryptoInfo = new CryptoInfo(); |
+ cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncryptedData, keyId, iv, |
+ cipherMode); |
+ if (patternEncrypt != 0 && patternSkip != 0) { |
+ if (usesCbcs) { |
+ // Above platform check ensured that setting the pattern is indeed supported. |
+ MediaCodecUtil.setPatternIfSupported(cryptoInfo, patternEncrypt, patternSkip); |
+ } else { |
+ Log.e(TAG, "Pattern encryption only supported for 'cbcs' scheme (CBC mode)."); |
+ return MEDIA_CODEC_ERROR; |
+ } |
+ } |
mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, 0); |
} catch (MediaCodec.CryptoException e) { |
if (e.getErrorCode() == MediaCodec.CryptoException.ERROR_NO_KEY) { |