CryptoAsync: Creating MediaCodec.CryptoException
CryptoException is created with MediaCodec.CryptoInfo Added callback onCryptoError(MediaCodec.CryptoException) as another MediaCodec callback to signal decryption errors. Bug: 254050543 Change-Id: Ifb8bfb44b38178ec99e6dbb607825c642bd4e46f
This commit is contained in:
@@ -22143,6 +22143,7 @@ package android.media {
|
||||
field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
|
||||
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
|
||||
field public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2; // 0x2
|
||||
field public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4; // 0x4
|
||||
field public static final int CRYPTO_MODE_AES_CBC = 2; // 0x2
|
||||
field public static final int CRYPTO_MODE_AES_CTR = 1; // 0x1
|
||||
field public static final int CRYPTO_MODE_UNENCRYPTED = 0; // 0x0
|
||||
@@ -22172,6 +22173,7 @@ package android.media {
|
||||
|
||||
public abstract static class MediaCodec.Callback {
|
||||
ctor public MediaCodec.Callback();
|
||||
method public void onCryptoError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CryptoException);
|
||||
method public abstract void onError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CodecException);
|
||||
method public abstract void onInputBufferAvailable(@NonNull android.media.MediaCodec, int);
|
||||
method public abstract void onOutputBufferAvailable(@NonNull android.media.MediaCodec, int, @NonNull android.media.MediaCodec.BufferInfo);
|
||||
@@ -22189,6 +22191,7 @@ package android.media {
|
||||
|
||||
public static final class MediaCodec.CryptoException extends java.lang.RuntimeException implements android.media.MediaDrmThrowable {
|
||||
ctor public MediaCodec.CryptoException(int, @Nullable String);
|
||||
method @Nullable public android.media.MediaCodec.CryptoInfo getCryptoInfo();
|
||||
method public int getErrorCode();
|
||||
field @Deprecated public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8
|
||||
field @Deprecated public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
|
||||
|
||||
@@ -571,6 +571,10 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
void onError(…) {
|
||||
…
|
||||
}
|
||||
{@literal @Override}
|
||||
void onCryptoError(…) {
|
||||
…
|
||||
}
|
||||
});
|
||||
codec.configure(format, …);
|
||||
mOutputFormat = codec.getOutputFormat(); // option B
|
||||
@@ -1774,6 +1778,7 @@ final public class MediaCodec {
|
||||
private static final int CB_OUTPUT_FORMAT_CHANGE = 4;
|
||||
private static final String EOS_AND_DECODE_ONLY_ERROR_MESSAGE = "An input buffer cannot have "
|
||||
+ "both BUFFER_FLAG_END_OF_STREAM and BUFFER_FLAG_DECODE_ONLY flags";
|
||||
private static final int CB_CRYPTO_ERROR = 6;
|
||||
|
||||
private class EventHandler extends Handler {
|
||||
private MediaCodec mCodec;
|
||||
@@ -1901,6 +1906,12 @@ final public class MediaCodec {
|
||||
break;
|
||||
}
|
||||
|
||||
case CB_CRYPTO_ERROR:
|
||||
{
|
||||
mCallback.onCryptoError(mCodec, (MediaCodec.CryptoException) msg.obj);
|
||||
break;
|
||||
}
|
||||
|
||||
case CB_OUTPUT_FORMAT_CHANGE:
|
||||
{
|
||||
mCallback.onOutputFormatChanged(mCodec,
|
||||
@@ -2104,12 +2115,25 @@ final public class MediaCodec {
|
||||
*/
|
||||
public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2;
|
||||
|
||||
/**
|
||||
* This flag should be used on a secure decoder only. MediaCodec configured with this
|
||||
* flag does decryption in a separate thread. The flag requires MediaCodec to operate
|
||||
* asynchronously and will throw CryptoException if any, in the onCryptoError()
|
||||
* callback. Applications should override the default implementation of
|
||||
* onCryptoError() and access the associated CryptoException.
|
||||
*
|
||||
* CryptoException thrown will contain {@link MediaCodec.CryptoInfo}
|
||||
* This can be accessed using getCryptoInfo()
|
||||
*/
|
||||
public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
flag = true,
|
||||
value = {
|
||||
CONFIGURE_FLAG_ENCODE,
|
||||
CONFIGURE_FLAG_USE_BLOCK_MODEL,
|
||||
CONFIGURE_FLAG_USE_CRYPTO_ASYNC,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ConfigureFlag {}
|
||||
@@ -2523,19 +2547,20 @@ final public class MediaCodec {
|
||||
public final static class CryptoException extends RuntimeException
|
||||
implements MediaDrmThrowable {
|
||||
public CryptoException(int errorCode, @Nullable String detailMessage) {
|
||||
this(detailMessage, errorCode, 0, 0, 0);
|
||||
this(detailMessage, errorCode, 0, 0, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public CryptoException(String message, int errorCode, int vendorError, int oemError,
|
||||
int errorContext) {
|
||||
int errorContext, @Nullable CryptoInfo cryptoInfo) {
|
||||
super(message);
|
||||
mErrorCode = errorCode;
|
||||
mVendorError = vendorError;
|
||||
mOemError = oemError;
|
||||
mErrorContext = errorContext;
|
||||
mCryptoInfo = cryptoInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2654,6 +2679,16 @@ final public class MediaCodec {
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CryptoInfo associated with this {@link CryptoException}
|
||||
* if any
|
||||
*
|
||||
* @return CryptoInfo object if any. {@link MediaCodec.CryptoException}
|
||||
*/
|
||||
public @Nullable CryptoInfo getCryptoInfo() {
|
||||
return mCryptoInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVendorError() {
|
||||
return mVendorError;
|
||||
@@ -2670,6 +2705,7 @@ final public class MediaCodec {
|
||||
}
|
||||
|
||||
private final int mErrorCode, mVendorError, mOemError, mErrorContext;
|
||||
private CryptoInfo mCryptoInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5087,6 +5123,25 @@ final public class MediaCodec {
|
||||
*/
|
||||
public abstract void onError(@NonNull MediaCodec codec, @NonNull CodecException e);
|
||||
|
||||
/**
|
||||
* Called only when MediaCodec encountered a crypto(decryption) error when using
|
||||
* a decoder configured with CONFIGURE_FLAG_USE_CRYPTO_ASYNC flag along with crypto
|
||||
* or descrambler object.
|
||||
*
|
||||
* @param codec The MediaCodec object
|
||||
* @param e The {@link MediaCodec.CryptoException} object with error details.
|
||||
*/
|
||||
public void onCryptoError(@NonNull MediaCodec codec, @NonNull CryptoException e) {
|
||||
/*
|
||||
* A default implementation for backward compatibility.
|
||||
* Use of CONFIGURE_FLAG_USE_CRYPTO_ASYNC requires override of this callback
|
||||
* to receive CrytoInfo. Without an orverride an exception is thrown.
|
||||
*/
|
||||
throw new IllegalStateException(
|
||||
"Client must override onCryptoError when the codec is " +
|
||||
"configured with CONFIGURE_FLAG_USE_CRYPTO_ASYNC.", e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the output format has changed
|
||||
*
|
||||
|
||||
@@ -184,6 +184,8 @@ struct fields_t {
|
||||
jmethodID postEventFromNativeID;
|
||||
jmethodID lockAndGetContextID;
|
||||
jmethodID setAndUnlockContextID;
|
||||
jmethodID cryptoInfoSetID;
|
||||
jmethodID cryptoInfoSetPatternID;
|
||||
jfieldID cryptoInfoNumSubSamplesID;
|
||||
jfieldID cryptoInfoNumBytesOfClearDataID;
|
||||
jfieldID cryptoInfoNumBytesOfEncryptedDataID;
|
||||
@@ -203,6 +205,7 @@ struct fields_t {
|
||||
static fields_t gFields;
|
||||
static const void *sRefBaseOwner;
|
||||
|
||||
jint MediaErrorToJavaError(status_t err);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1068,6 +1071,180 @@ static jthrowable createCodecException(
|
||||
return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
|
||||
}
|
||||
|
||||
static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
|
||||
const sp<AMessage> & msg) {
|
||||
if(msg == nullptr || obj == nullptr) {
|
||||
ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
|
||||
return;
|
||||
}
|
||||
size_t numSubSamples = 0;
|
||||
sp<ABuffer> subSamplesBuffer;
|
||||
sp<ABuffer> keyBuffer;
|
||||
sp<ABuffer> ivBuffer;
|
||||
CryptoPlugin::Mode mode;
|
||||
CryptoPlugin::Pattern pattern;
|
||||
CHECK(msg->findInt32("mode", (int*)&mode));
|
||||
CHECK(msg->findSize("numSubSamples", &numSubSamples));
|
||||
CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
|
||||
CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
|
||||
CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
|
||||
CHECK(msg->findBuffer("iv", &ivBuffer));
|
||||
CHECK(msg->findBuffer("key", &keyBuffer));
|
||||
|
||||
// subsamples
|
||||
ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
|
||||
ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
|
||||
jboolean isCopy;
|
||||
jint *dstEncryptedSamples =
|
||||
env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
|
||||
jint * dstClearSamples =
|
||||
env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
|
||||
|
||||
CryptoPlugin::SubSample * samplesArray =
|
||||
(CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
|
||||
|
||||
for(int i = 0 ; i < numSubSamples ; i++) {
|
||||
dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
|
||||
dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
|
||||
}
|
||||
env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
|
||||
env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
|
||||
// key and iv
|
||||
jbyteArray keyArray = NULL;
|
||||
jbyteArray ivArray = NULL;
|
||||
if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
|
||||
keyArray = env->NewByteArray(keyBuffer->size());
|
||||
jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
|
||||
memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
|
||||
env->ReleaseByteArrayElements(keyArray,dstKey,0);
|
||||
}
|
||||
if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
|
||||
ivArray = env->NewByteArray(ivBuffer->size());
|
||||
jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
|
||||
memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
|
||||
env->ReleaseByteArrayElements(ivArray, dstIv,0);
|
||||
}
|
||||
// set samples, key and iv
|
||||
env->CallVoidMethod(
|
||||
obj,
|
||||
gFields.cryptoInfoSetID,
|
||||
(jint)numSubSamples,
|
||||
samplesOfClearDataArr.get(),
|
||||
samplesOfEncryptedDataArr.get(),
|
||||
keyArray,
|
||||
ivArray,
|
||||
mode);
|
||||
if (keyArray != NULL) {
|
||||
env->DeleteLocalRef(keyArray);
|
||||
}
|
||||
if (ivArray != NULL) {
|
||||
env->DeleteLocalRef(ivArray);
|
||||
}
|
||||
// set pattern
|
||||
env->CallVoidMethod(
|
||||
obj,
|
||||
gFields.cryptoInfoSetPatternID,
|
||||
pattern.mEncryptBlocks,
|
||||
pattern.mSkipBlocks);
|
||||
}
|
||||
|
||||
static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
|
||||
switch(err) {
|
||||
case ERROR_DRM_NO_LICENSE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorNoKey;
|
||||
defaultMsg = "Crypto key not available";
|
||||
break;
|
||||
case ERROR_DRM_LICENSE_EXPIRED:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
|
||||
defaultMsg = "License expired";
|
||||
break;
|
||||
case ERROR_DRM_RESOURCE_BUSY:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
|
||||
defaultMsg = "Resource busy or unavailable";
|
||||
break;
|
||||
case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
|
||||
defaultMsg = "Required output protections are not active";
|
||||
break;
|
||||
case ERROR_DRM_SESSION_NOT_OPENED:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
|
||||
defaultMsg = "Attempted to use a closed session";
|
||||
break;
|
||||
case ERROR_DRM_INSUFFICIENT_SECURITY:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
|
||||
defaultMsg = "Required security level is not met";
|
||||
break;
|
||||
case ERROR_DRM_CANNOT_HANDLE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
|
||||
defaultMsg = "Operation not supported in this configuration";
|
||||
break;
|
||||
case ERROR_DRM_FRAME_TOO_LARGE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
|
||||
defaultMsg = "Decrytped frame exceeds size of output buffer";
|
||||
break;
|
||||
case ERROR_DRM_SESSION_LOST_STATE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorLostState;
|
||||
defaultMsg = "Session state was lost, open a new session and retry";
|
||||
break;
|
||||
default: // Other negative DRM error codes go out best-effort.
|
||||
jerr = MediaErrorToJavaError(err);
|
||||
defaultMsg = StrCryptoError(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static jthrowable createCryptoException(JNIEnv *env, status_t err,
|
||||
const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
|
||||
const sp<AMessage> & cryptoInfo = NULL) {
|
||||
jthrowable exception = nullptr;
|
||||
jmethodID constructID = nullptr;
|
||||
ScopedLocalRef<jobject> cryptoInfoObject(env);
|
||||
std::string defaultMsg = "Unknown Error";
|
||||
jint jerr = 0;
|
||||
// Get a class ref for CryptoException
|
||||
ScopedLocalRef<jclass> clazz(
|
||||
env, env->FindClass("android/media/MediaCodec$CryptoException"));
|
||||
CHECK(clazz.get() != NULL);
|
||||
|
||||
// Get constructor ref for CryptoException
|
||||
constructID = env->GetMethodID(clazz.get(), "<init>",
|
||||
"(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
|
||||
CHECK(constructID != NULL);
|
||||
|
||||
// create detailed message for exception
|
||||
CryptoErrorToJavaError(err, jerr, defaultMsg);
|
||||
std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
|
||||
DrmStatus dStatus(err, originalMsg.c_str());
|
||||
std::string detailedMsg(
|
||||
DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
|
||||
jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
|
||||
|
||||
if (cryptoInfo != nullptr) {
|
||||
// Class ref for CryptoInfo
|
||||
ScopedLocalRef<jclass> clazzCryptoInfo(
|
||||
env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
|
||||
CHECK(clazzCryptoInfo.get() != NULL);
|
||||
|
||||
// Constructor reference for CryptoInfo
|
||||
jmethodID constructCryptoInfo =
|
||||
env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
|
||||
CHECK(constructCryptoInfo != NULL);
|
||||
|
||||
// Create CryptoInfo jobject
|
||||
cryptoInfoObject.reset(
|
||||
env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
|
||||
CHECK(cryptoInfoObject.get() != NULL);
|
||||
|
||||
// Translate AMesage to CryptoInfo
|
||||
AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
|
||||
}
|
||||
|
||||
exception = (jthrowable)env->NewObject(
|
||||
clazz.get(), constructID, msgObj, jerr,
|
||||
dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
|
||||
cryptoInfoObject.get());
|
||||
|
||||
return exception;
|
||||
}
|
||||
void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
|
||||
int32_t arg1, arg2 = 0;
|
||||
jobject obj = NULL;
|
||||
@@ -1107,6 +1284,17 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
|
||||
break;
|
||||
}
|
||||
|
||||
case MediaCodec::CB_CRYPTO_ERROR:
|
||||
{
|
||||
int32_t err, actionCode;
|
||||
AString errorDetail;
|
||||
CHECK(msg->findInt32("err", &err));
|
||||
CHECK(msg->findInt32("actionCode",&actionCode));
|
||||
CHECK(msg->findString("errorDetail", &errorDetail));
|
||||
obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
case MediaCodec::CB_ERROR:
|
||||
{
|
||||
int32_t err, actionCode;
|
||||
@@ -1144,7 +1332,6 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
|
||||
default:
|
||||
TRESPASS();
|
||||
}
|
||||
|
||||
env->CallVoidMethod(
|
||||
mObject,
|
||||
gFields.postEventFromNativeID,
|
||||
@@ -1229,7 +1416,6 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
|
||||
}
|
||||
}
|
||||
|
||||
jint MediaErrorToJavaError(status_t err);
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -1280,70 +1466,8 @@ static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, c
|
||||
|
||||
static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
|
||||
const sp<ICrypto> &crypto) {
|
||||
ScopedLocalRef<jclass> clazz(
|
||||
env, env->FindClass("android/media/MediaCodec$CryptoException"));
|
||||
CHECK(clazz.get() != NULL);
|
||||
|
||||
jmethodID constructID =
|
||||
env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;IIII)V");
|
||||
CHECK(constructID != NULL);
|
||||
|
||||
std::string defaultMsg = "Unknown Error";
|
||||
|
||||
/* translate OS errors to Java API CryptoException errorCodes (which are positive) */
|
||||
jint jerr = 0;
|
||||
switch (err) {
|
||||
case ERROR_DRM_NO_LICENSE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorNoKey;
|
||||
defaultMsg = "Crypto key not available";
|
||||
break;
|
||||
case ERROR_DRM_LICENSE_EXPIRED:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
|
||||
defaultMsg = "License expired";
|
||||
break;
|
||||
case ERROR_DRM_RESOURCE_BUSY:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
|
||||
defaultMsg = "Resource busy or unavailable";
|
||||
break;
|
||||
case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
|
||||
defaultMsg = "Required output protections are not active";
|
||||
break;
|
||||
case ERROR_DRM_SESSION_NOT_OPENED:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
|
||||
defaultMsg = "Attempted to use a closed session";
|
||||
break;
|
||||
case ERROR_DRM_INSUFFICIENT_SECURITY:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
|
||||
defaultMsg = "Required security level is not met";
|
||||
break;
|
||||
case ERROR_DRM_CANNOT_HANDLE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
|
||||
defaultMsg = "Operation not supported in this configuration";
|
||||
break;
|
||||
case ERROR_DRM_FRAME_TOO_LARGE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
|
||||
defaultMsg = "Decrytped frame exceeds size of output buffer";
|
||||
break;
|
||||
case ERROR_DRM_SESSION_LOST_STATE:
|
||||
jerr = gCryptoErrorCodes.cryptoErrorLostState;
|
||||
defaultMsg = "Session state was lost, open a new session and retry";
|
||||
break;
|
||||
default: /* Other negative DRM error codes go out best-effort. */
|
||||
jerr = MediaErrorToJavaError(err);
|
||||
defaultMsg = StrCryptoError(err);
|
||||
break;
|
||||
}
|
||||
|
||||
std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
|
||||
DrmStatus dStatus(err, originalMsg.c_str());
|
||||
std::string detailedMsg(DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
|
||||
jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
|
||||
|
||||
jthrowable exception =
|
||||
(jthrowable)env->NewObject(clazz.get(), constructID, msgObj, jerr,
|
||||
dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext());
|
||||
|
||||
jthrowable exception = createCryptoException(
|
||||
env, err, msg, crypto, /* cryptoInfo */ NULL);
|
||||
env->Throw(exception);
|
||||
}
|
||||
|
||||
@@ -2963,6 +3087,12 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
|
||||
clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
|
||||
CHECK(clazz.get() != NULL);
|
||||
|
||||
gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
|
||||
CHECK(gFields.cryptoInfoSetID != NULL);
|
||||
|
||||
gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
|
||||
CHECK(gFields.cryptoInfoSetPatternID != NULL);
|
||||
|
||||
gFields.cryptoInfoNumSubSamplesID =
|
||||
env->GetFieldID(clazz.get(), "numSubSamples", "I");
|
||||
CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
|
||||
|
||||
Reference in New Issue
Block a user