Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "MediaCodec-JNI"
     19 #include <utils/Log.h>
     20 
     21 #include "android_media_MediaCodec.h"
     22 
     23 #include "android_media_MediaCrypto.h"
     24 #include "android_media_Utils.h"
     25 #include "android_runtime/AndroidRuntime.h"
     26 #include "android_runtime/android_view_Surface.h"
     27 #include "jni.h"
     28 #include "JNIHelp.h"
     29 
     30 #include <cutils/compiler.h>
     31 
     32 #include <gui/Surface.h>
     33 
     34 #include <media/ICrypto.h>
     35 #include <media/stagefright/MediaCodec.h>
     36 #include <media/stagefright/foundation/ABuffer.h>
     37 #include <media/stagefright/foundation/ADebug.h>
     38 #include <media/stagefright/foundation/ALooper.h>
     39 #include <media/stagefright/foundation/AMessage.h>
     40 #include <media/stagefright/foundation/AString.h>
     41 #include <media/stagefright/MediaErrors.h>
     42 #include <media/stagefright/PersistentSurface.h>
     43 #include <nativehelper/ScopedLocalRef.h>
     44 
     45 #include <system/window.h>
     46 
     47 namespace android {
     48 
     49 // Keep these in sync with their equivalents in MediaCodec.java !!!
     50 enum {
     51     DEQUEUE_INFO_TRY_AGAIN_LATER            = -1,
     52     DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED      = -2,
     53     DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
     54 };
     55 
     56 enum {
     57     EVENT_CALLBACK = 1,
     58     EVENT_SET_CALLBACK = 2,
     59     EVENT_FRAME_RENDERED = 3,
     60 };
     61 
     62 static struct CryptoErrorCodes {
     63     jint cryptoErrorNoKey;
     64     jint cryptoErrorKeyExpired;
     65     jint cryptoErrorResourceBusy;
     66     jint cryptoErrorInsufficientOutputProtection;
     67     jint cryptoErrorSessionNotOpened;
     68     jint cryptoErrorUnsupportedOperation;
     69 } gCryptoErrorCodes;
     70 
     71 static struct CodecActionCodes {
     72     jint codecActionTransient;
     73     jint codecActionRecoverable;
     74 } gCodecActionCodes;
     75 
     76 static struct CodecErrorCodes {
     77     jint errorInsufficientResource;
     78     jint errorReclaimed;
     79 } gCodecErrorCodes;
     80 
     81 static struct {
     82     jclass clazz;
     83     jfieldID mLock;
     84     jfieldID mPersistentObject;
     85     jmethodID ctor;
     86     jmethodID setNativeObjectLocked;
     87 } gPersistentSurfaceClassInfo;
     88 
     89 static struct {
     90     jint Unencrypted;
     91     jint AesCtr;
     92     jint AesCbc;
     93 } gCryptoModes;
     94 
     95 
     96 struct fields_t {
     97     jfieldID context;
     98     jmethodID postEventFromNativeID;
     99     jfieldID cryptoInfoNumSubSamplesID;
    100     jfieldID cryptoInfoNumBytesOfClearDataID;
    101     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
    102     jfieldID cryptoInfoKeyID;
    103     jfieldID cryptoInfoIVID;
    104     jfieldID cryptoInfoModeID;
    105     jfieldID cryptoInfoPatternID;
    106     jfieldID patternEncryptBlocksID;
    107     jfieldID patternSkipBlocksID;
    108 };
    109 
    110 static fields_t gFields;
    111 static const void *sRefBaseOwner;
    112 
    113 ////////////////////////////////////////////////////////////////////////////////
    114 
    115 JMediaCodec::JMediaCodec(
    116         JNIEnv *env, jobject thiz,
    117         const char *name, bool nameIsType, bool encoder)
    118     : mClass(NULL),
    119       mObject(NULL) {
    120     jclass clazz = env->GetObjectClass(thiz);
    121     CHECK(clazz != NULL);
    122 
    123     mClass = (jclass)env->NewGlobalRef(clazz);
    124     mObject = env->NewWeakGlobalRef(thiz);
    125 
    126     cacheJavaObjects(env);
    127 
    128     mLooper = new ALooper;
    129     mLooper->setName("MediaCodec_looper");
    130 
    131     mLooper->start(
    132             false,      // runOnCallingThread
    133             true,       // canCallJava
    134             PRIORITY_FOREGROUND);
    135 
    136     if (nameIsType) {
    137         mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
    138     } else {
    139         mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
    140     }
    141     CHECK((mCodec != NULL) != (mInitStatus != OK));
    142 }
    143 
    144 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
    145     jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
    146     mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
    147     CHECK(mByteBufferClass != NULL);
    148 
    149     ScopedLocalRef<jclass> byteOrderClass(
    150             env, env->FindClass("java/nio/ByteOrder"));
    151     CHECK(byteOrderClass.get() != NULL);
    152 
    153     jmethodID nativeOrderID = env->GetStaticMethodID(
    154             byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
    155     CHECK(nativeOrderID != NULL);
    156 
    157     jobject nativeByteOrderObj =
    158         env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
    159     mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
    160     CHECK(mNativeByteOrderObj != NULL);
    161     env->DeleteLocalRef(nativeByteOrderObj);
    162     nativeByteOrderObj = NULL;
    163 
    164     mByteBufferOrderMethodID = env->GetMethodID(
    165             mByteBufferClass,
    166             "order",
    167             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
    168     CHECK(mByteBufferOrderMethodID != NULL);
    169 
    170     mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
    171             mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
    172     CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
    173 
    174     mByteBufferPositionMethodID = env->GetMethodID(
    175             mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
    176     CHECK(mByteBufferPositionMethodID != NULL);
    177 
    178     mByteBufferLimitMethodID = env->GetMethodID(
    179             mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
    180     CHECK(mByteBufferLimitMethodID != NULL);
    181 }
    182 
    183 status_t JMediaCodec::initCheck() const {
    184     return mInitStatus;
    185 }
    186 
    187 void JMediaCodec::registerSelf() {
    188     mLooper->registerHandler(this);
    189 }
    190 
    191 void JMediaCodec::release() {
    192     if (mCodec != NULL) {
    193         mCodec->release();
    194         mCodec.clear();
    195         mInitStatus = NO_INIT;
    196     }
    197 
    198     if (mLooper != NULL) {
    199         mLooper->unregisterHandler(id());
    200         mLooper->stop();
    201         mLooper.clear();
    202     }
    203 }
    204 
    205 JMediaCodec::~JMediaCodec() {
    206     if (mCodec != NULL || mLooper != NULL) {
    207         /* MediaCodec and looper should have been released explicitly already
    208          * in setMediaCodec() (see comments in setMediaCodec()).
    209          *
    210          * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
    211          * message handler, doing release() there risks deadlock as MediaCodec::
    212          * release() post synchronous message to the same looper.
    213          *
    214          * Print a warning and try to proceed with releasing.
    215          */
    216         ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
    217         release();
    218         ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
    219     }
    220 
    221     JNIEnv *env = AndroidRuntime::getJNIEnv();
    222 
    223     env->DeleteWeakGlobalRef(mObject);
    224     mObject = NULL;
    225     env->DeleteGlobalRef(mClass);
    226     mClass = NULL;
    227     deleteJavaObjects(env);
    228 }
    229 
    230 void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
    231     env->DeleteGlobalRef(mByteBufferClass);
    232     mByteBufferClass = NULL;
    233     env->DeleteGlobalRef(mNativeByteOrderObj);
    234     mNativeByteOrderObj = NULL;
    235 
    236     mByteBufferOrderMethodID = NULL;
    237     mByteBufferAsReadOnlyBufferMethodID = NULL;
    238     mByteBufferPositionMethodID = NULL;
    239     mByteBufferLimitMethodID = NULL;
    240 }
    241 
    242 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
    243     if (enable) {
    244         if (mOnFrameRenderedNotification == NULL) {
    245             mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
    246         }
    247     } else {
    248         mOnFrameRenderedNotification.clear();
    249     }
    250 
    251     return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
    252 }
    253 
    254 status_t JMediaCodec::setCallback(jobject cb) {
    255     if (cb != NULL) {
    256         if (mCallbackNotification == NULL) {
    257             mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
    258         }
    259     } else {
    260         mCallbackNotification.clear();
    261     }
    262 
    263     return mCodec->setCallback(mCallbackNotification);
    264 }
    265 
    266 status_t JMediaCodec::configure(
    267         const sp<AMessage> &format,
    268         const sp<IGraphicBufferProducer> &bufferProducer,
    269         const sp<ICrypto> &crypto,
    270         int flags) {
    271     sp<Surface> client;
    272     if (bufferProducer != NULL) {
    273         mSurfaceTextureClient =
    274             new Surface(bufferProducer, true /* controlledByApp */);
    275     } else {
    276         mSurfaceTextureClient.clear();
    277     }
    278 
    279     return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
    280 }
    281 
    282 status_t JMediaCodec::setSurface(
    283         const sp<IGraphicBufferProducer> &bufferProducer) {
    284     sp<Surface> client;
    285     if (bufferProducer != NULL) {
    286         client = new Surface(bufferProducer, true /* controlledByApp */);
    287     }
    288     status_t err = mCodec->setSurface(client);
    289     if (err == OK) {
    290         mSurfaceTextureClient = client;
    291     }
    292     return err;
    293 }
    294 
    295 status_t JMediaCodec::createInputSurface(
    296         sp<IGraphicBufferProducer>* bufferProducer) {
    297     return mCodec->createInputSurface(bufferProducer);
    298 }
    299 
    300 status_t JMediaCodec::setInputSurface(
    301         const sp<PersistentSurface> &surface) {
    302     return mCodec->setInputSurface(surface);
    303 }
    304 
    305 status_t JMediaCodec::start() {
    306     return mCodec->start();
    307 }
    308 
    309 status_t JMediaCodec::stop() {
    310     mSurfaceTextureClient.clear();
    311 
    312     return mCodec->stop();
    313 }
    314 
    315 status_t JMediaCodec::flush() {
    316     return mCodec->flush();
    317 }
    318 
    319 status_t JMediaCodec::reset() {
    320     return mCodec->reset();
    321 }
    322 
    323 status_t JMediaCodec::queueInputBuffer(
    324         size_t index,
    325         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
    326         AString *errorDetailMsg) {
    327     return mCodec->queueInputBuffer(
    328             index, offset, size, timeUs, flags, errorDetailMsg);
    329 }
    330 
    331 status_t JMediaCodec::queueSecureInputBuffer(
    332         size_t index,
    333         size_t offset,
    334         const CryptoPlugin::SubSample *subSamples,
    335         size_t numSubSamples,
    336         const uint8_t key[16],
    337         const uint8_t iv[16],
    338         CryptoPlugin::Mode mode,
    339         const CryptoPlugin::Pattern &pattern,
    340         int64_t presentationTimeUs,
    341         uint32_t flags,
    342         AString *errorDetailMsg) {
    343     return mCodec->queueSecureInputBuffer(
    344             index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
    345             presentationTimeUs, flags, errorDetailMsg);
    346 }
    347 
    348 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
    349     return mCodec->dequeueInputBuffer(index, timeoutUs);
    350 }
    351 
    352 status_t JMediaCodec::dequeueOutputBuffer(
    353         JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
    354     size_t size, offset;
    355     int64_t timeUs;
    356     uint32_t flags;
    357     status_t err = mCodec->dequeueOutputBuffer(
    358             index, &offset, &size, &timeUs, &flags, timeoutUs);
    359 
    360     if (err != OK) {
    361         return err;
    362     }
    363 
    364     ScopedLocalRef<jclass> clazz(
    365             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
    366 
    367     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
    368     env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
    369 
    370     return OK;
    371 }
    372 
    373 status_t JMediaCodec::releaseOutputBuffer(
    374         size_t index, bool render, bool updatePTS, int64_t timestampNs) {
    375     if (updatePTS) {
    376         return mCodec->renderOutputBufferAndRelease(index, timestampNs);
    377     }
    378     return render
    379         ? mCodec->renderOutputBufferAndRelease(index)
    380         : mCodec->releaseOutputBuffer(index);
    381 }
    382 
    383 status_t JMediaCodec::signalEndOfInputStream() {
    384     return mCodec->signalEndOfInputStream();
    385 }
    386 
    387 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
    388     sp<AMessage> msg;
    389     status_t err;
    390     err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
    391     if (err != OK) {
    392         return err;
    393     }
    394 
    395     return ConvertMessageToMap(env, msg, format);
    396 }
    397 
    398 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
    399     sp<AMessage> msg;
    400     status_t err;
    401     if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
    402         return err;
    403     }
    404 
    405     return ConvertMessageToMap(env, msg, format);
    406 }
    407 
    408 status_t JMediaCodec::getBuffers(
    409         JNIEnv *env, bool input, jobjectArray *bufArray) const {
    410     Vector<sp<ABuffer> > buffers;
    411 
    412     status_t err =
    413         input
    414             ? mCodec->getInputBuffers(&buffers)
    415             : mCodec->getOutputBuffers(&buffers);
    416 
    417     if (err != OK) {
    418         return err;
    419     }
    420 
    421     *bufArray = (jobjectArray)env->NewObjectArray(
    422             buffers.size(), mByteBufferClass, NULL);
    423     if (*bufArray == NULL) {
    424         return NO_MEMORY;
    425     }
    426 
    427     for (size_t i = 0; i < buffers.size(); ++i) {
    428         const sp<ABuffer> &buffer = buffers.itemAt(i);
    429 
    430         jobject byteBuffer = NULL;
    431         err = createByteBufferFromABuffer(
    432                 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
    433         if (err != OK) {
    434             return err;
    435         }
    436         if (byteBuffer != NULL) {
    437             env->SetObjectArrayElement(
    438                     *bufArray, i, byteBuffer);
    439 
    440             env->DeleteLocalRef(byteBuffer);
    441             byteBuffer = NULL;
    442         }
    443     }
    444 
    445     return OK;
    446 }
    447 
    448 // static
    449 status_t JMediaCodec::createByteBufferFromABuffer(
    450         JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
    451         jobject *buf) const {
    452     // if this is an ABuffer that doesn't actually hold any accessible memory,
    453     // use a null ByteBuffer
    454     *buf = NULL;
    455 
    456     if (buffer == NULL) {
    457         ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
    458         return OK;
    459     }
    460 
    461     if (buffer->base() == NULL) {
    462         return OK;
    463     }
    464 
    465     jobject byteBuffer =
    466         env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
    467     if (readOnly && byteBuffer != NULL) {
    468         jobject readOnlyBuffer = env->CallObjectMethod(
    469                 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
    470         env->DeleteLocalRef(byteBuffer);
    471         byteBuffer = readOnlyBuffer;
    472     }
    473     if (byteBuffer == NULL) {
    474         return NO_MEMORY;
    475     }
    476     jobject me = env->CallObjectMethod(
    477             byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
    478     env->DeleteLocalRef(me);
    479     me = env->CallObjectMethod(
    480             byteBuffer, mByteBufferLimitMethodID,
    481             clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
    482     env->DeleteLocalRef(me);
    483     me = env->CallObjectMethod(
    484             byteBuffer, mByteBufferPositionMethodID,
    485             clearBuffer ? 0 : buffer->offset());
    486     env->DeleteLocalRef(me);
    487     me = NULL;
    488 
    489     *buf = byteBuffer;
    490     return OK;
    491 }
    492 
    493 status_t JMediaCodec::getBuffer(
    494         JNIEnv *env, bool input, size_t index, jobject *buf) const {
    495     sp<ABuffer> buffer;
    496 
    497     status_t err =
    498         input
    499             ? mCodec->getInputBuffer(index, &buffer)
    500             : mCodec->getOutputBuffer(index, &buffer);
    501 
    502     if (err != OK) {
    503         return err;
    504     }
    505 
    506     return createByteBufferFromABuffer(
    507             env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
    508 }
    509 
    510 status_t JMediaCodec::getImage(
    511         JNIEnv *env, bool input, size_t index, jobject *buf) const {
    512     sp<ABuffer> buffer;
    513 
    514     status_t err =
    515         input
    516             ? mCodec->getInputBuffer(index, &buffer)
    517             : mCodec->getOutputBuffer(index, &buffer);
    518 
    519     if (err != OK) {
    520         return err;
    521     }
    522 
    523     // if this is an ABuffer that doesn't actually hold any accessible memory,
    524     // use a null ByteBuffer
    525     *buf = NULL;
    526     if (buffer->base() == NULL) {
    527         return OK;
    528     }
    529 
    530     // check if buffer is an image
    531     sp<ABuffer> imageData;
    532     if (!buffer->meta()->findBuffer("image-data", &imageData)) {
    533         return OK;
    534     }
    535 
    536     int64_t timestamp = 0;
    537     if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
    538         timestamp *= 1000; // adjust to ns
    539     }
    540 
    541     jobject byteBuffer = NULL;
    542     err = createByteBufferFromABuffer(
    543             env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
    544     if (err != OK) {
    545         return OK;
    546     }
    547 
    548     jobject infoBuffer = NULL;
    549     err = createByteBufferFromABuffer(
    550             env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
    551     if (err != OK) {
    552         env->DeleteLocalRef(byteBuffer);
    553         byteBuffer = NULL;
    554         return OK;
    555     }
    556 
    557     jobject cropRect = NULL;
    558     int32_t left, top, right, bottom;
    559     if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
    560         ScopedLocalRef<jclass> rectClazz(
    561                 env, env->FindClass("android/graphics/Rect"));
    562         CHECK(rectClazz.get() != NULL);
    563 
    564         jmethodID rectConstructID = env->GetMethodID(
    565                 rectClazz.get(), "<init>", "(IIII)V");
    566 
    567         cropRect = env->NewObject(
    568                 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
    569     }
    570 
    571     ScopedLocalRef<jclass> imageClazz(
    572             env, env->FindClass("android/media/MediaCodec$MediaImage"));
    573     CHECK(imageClazz.get() != NULL);
    574 
    575     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
    576             "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
    577 
    578     *buf = env->NewObject(imageClazz.get(), imageConstructID,
    579             byteBuffer, infoBuffer,
    580             (jboolean)!input /* readOnly */,
    581             (jlong)timestamp,
    582             (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
    583 
    584     // if MediaImage creation fails, return null
    585     if (env->ExceptionCheck()) {
    586         env->ExceptionDescribe();
    587         env->ExceptionClear();
    588         *buf = NULL;
    589     }
    590 
    591     if (cropRect != NULL) {
    592         env->DeleteLocalRef(cropRect);
    593         cropRect = NULL;
    594     }
    595 
    596     env->DeleteLocalRef(byteBuffer);
    597     byteBuffer = NULL;
    598 
    599     env->DeleteLocalRef(infoBuffer);
    600     infoBuffer = NULL;
    601 
    602     return OK;
    603 }
    604 
    605 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
    606     AString name;
    607 
    608     status_t err = mCodec->getName(&name);
    609 
    610     if (err != OK) {
    611         return err;
    612     }
    613 
    614     *nameStr = env->NewStringUTF(name.c_str());
    615 
    616     return OK;
    617 }
    618 
    619 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
    620     return mCodec->setParameters(msg);
    621 }
    622 
    623 void JMediaCodec::setVideoScalingMode(int mode) {
    624     if (mSurfaceTextureClient != NULL) {
    625         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
    626     }
    627 }
    628 
    629 static jthrowable createCodecException(
    630         JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
    631     ScopedLocalRef<jclass> clazz(
    632             env, env->FindClass("android/media/MediaCodec$CodecException"));
    633     CHECK(clazz.get() != NULL);
    634 
    635     const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
    636     CHECK(ctor != NULL);
    637 
    638     ScopedLocalRef<jstring> msgObj(
    639             env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
    640 
    641     // translate action code to Java equivalent
    642     switch (actionCode) {
    643     case ACTION_CODE_TRANSIENT:
    644         actionCode = gCodecActionCodes.codecActionTransient;
    645         break;
    646     case ACTION_CODE_RECOVERABLE:
    647         actionCode = gCodecActionCodes.codecActionRecoverable;
    648         break;
    649     default:
    650         actionCode = 0;  // everything else is fatal
    651         break;
    652     }
    653 
    654     /* translate OS errors to Java API CodecException errorCodes */
    655     switch (err) {
    656         case NO_MEMORY:
    657             err = gCodecErrorCodes.errorInsufficientResource;
    658             break;
    659         case DEAD_OBJECT:
    660             err = gCodecErrorCodes.errorReclaimed;
    661             break;
    662         default:  /* Other error codes go out as is. */
    663             break;
    664     }
    665 
    666     return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
    667 }
    668 
    669 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
    670     int32_t arg1, arg2 = 0;
    671     jobject obj = NULL;
    672     CHECK(msg->findInt32("callbackID", &arg1));
    673     JNIEnv *env = AndroidRuntime::getJNIEnv();
    674 
    675     switch (arg1) {
    676         case MediaCodec::CB_INPUT_AVAILABLE:
    677         {
    678             CHECK(msg->findInt32("index", &arg2));
    679             break;
    680         }
    681 
    682         case MediaCodec::CB_OUTPUT_AVAILABLE:
    683         {
    684             CHECK(msg->findInt32("index", &arg2));
    685 
    686             size_t size, offset;
    687             int64_t timeUs;
    688             uint32_t flags;
    689             CHECK(msg->findSize("size", &size));
    690             CHECK(msg->findSize("offset", &offset));
    691             CHECK(msg->findInt64("timeUs", &timeUs));
    692             CHECK(msg->findInt32("flags", (int32_t *)&flags));
    693 
    694             ScopedLocalRef<jclass> clazz(
    695                     env, env->FindClass("android/media/MediaCodec$BufferInfo"));
    696             jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
    697             jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
    698 
    699             obj = env->NewObject(clazz.get(), ctor);
    700 
    701             if (obj == NULL) {
    702                 if (env->ExceptionCheck()) {
    703                     ALOGE("Could not create MediaCodec.BufferInfo.");
    704                     env->ExceptionClear();
    705                 }
    706                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    707                 return;
    708             }
    709 
    710             env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
    711             break;
    712         }
    713 
    714         case MediaCodec::CB_ERROR:
    715         {
    716             int32_t err, actionCode;
    717             CHECK(msg->findInt32("err", &err));
    718             CHECK(msg->findInt32("actionCode", &actionCode));
    719 
    720             // note that DRM errors could conceivably alias into a CodecException
    721             obj = (jobject)createCodecException(env, err, actionCode);
    722 
    723             if (obj == NULL) {
    724                 if (env->ExceptionCheck()) {
    725                     ALOGE("Could not create CodecException object.");
    726                     env->ExceptionClear();
    727                 }
    728                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    729                 return;
    730             }
    731 
    732             break;
    733         }
    734 
    735         case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
    736         {
    737             sp<AMessage> format;
    738             CHECK(msg->findMessage("format", &format));
    739 
    740             if (OK != ConvertMessageToMap(env, format, &obj)) {
    741                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    742                 return;
    743             }
    744 
    745             break;
    746         }
    747 
    748         default:
    749             TRESPASS();
    750     }
    751 
    752     env->CallVoidMethod(
    753             mObject,
    754             gFields.postEventFromNativeID,
    755             EVENT_CALLBACK,
    756             arg1,
    757             arg2,
    758             obj);
    759 
    760     env->DeleteLocalRef(obj);
    761 }
    762 
    763 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
    764     int32_t arg1 = 0, arg2 = 0;
    765     jobject obj = NULL;
    766     JNIEnv *env = AndroidRuntime::getJNIEnv();
    767 
    768     sp<AMessage> data;
    769     CHECK(msg->findMessage("data", &data));
    770 
    771     status_t err = ConvertMessageToMap(env, data, &obj);
    772     if (err != OK) {
    773         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    774         return;
    775     }
    776 
    777     env->CallVoidMethod(
    778             mObject, gFields.postEventFromNativeID,
    779             EVENT_FRAME_RENDERED, arg1, arg2, obj);
    780 
    781     env->DeleteLocalRef(obj);
    782 }
    783 
    784 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    785     switch (msg->what()) {
    786         case kWhatCallbackNotify:
    787         {
    788             handleCallback(msg);
    789             break;
    790         }
    791         case kWhatFrameRendered:
    792         {
    793             handleFrameRenderedNotification(msg);
    794             break;
    795         }
    796         default:
    797             TRESPASS();
    798     }
    799 }
    800 
    801 }  // namespace android
    802 
    803 ////////////////////////////////////////////////////////////////////////////////
    804 
    805 using namespace android;
    806 
    807 static sp<JMediaCodec> setMediaCodec(
    808         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
    809     sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
    810     if (codec != NULL) {
    811         codec->incStrong(thiz);
    812     }
    813     if (old != NULL) {
    814         /* release MediaCodec and stop the looper now before decStrong.
    815          * otherwise JMediaCodec::~JMediaCodec() could be called from within
    816          * its message handler, doing release() from there will deadlock
    817          * (as MediaCodec::release() post synchronous message to the same looper)
    818          */
    819         old->release();
    820         old->decStrong(thiz);
    821     }
    822     env->SetLongField(thiz, gFields.context, (jlong)codec.get());
    823 
    824     return old;
    825 }
    826 
    827 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
    828     return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
    829 }
    830 
    831 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
    832     setMediaCodec(env, thiz, NULL);
    833 }
    834 
    835 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
    836     jthrowable exception = createCodecException(env, err, actionCode, msg);
    837     env->Throw(exception);
    838 }
    839 
    840 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
    841     ScopedLocalRef<jclass> clazz(
    842             env, env->FindClass("android/media/MediaCodec$CryptoException"));
    843     CHECK(clazz.get() != NULL);
    844 
    845     jmethodID constructID =
    846         env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
    847     CHECK(constructID != NULL);
    848 
    849     const char *defaultMsg = "Unknown Error";
    850 
    851     /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
    852     switch (err) {
    853         case ERROR_DRM_NO_LICENSE:
    854             err = gCryptoErrorCodes.cryptoErrorNoKey;
    855             defaultMsg = "Crypto key not available";
    856             break;
    857         case ERROR_DRM_LICENSE_EXPIRED:
    858             err = gCryptoErrorCodes.cryptoErrorKeyExpired;
    859             defaultMsg = "License expired";
    860             break;
    861         case ERROR_DRM_RESOURCE_BUSY:
    862             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
    863             defaultMsg = "Resource busy or unavailable";
    864             break;
    865         case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
    866             err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
    867             defaultMsg = "Required output protections are not active";
    868             break;
    869         case ERROR_DRM_SESSION_NOT_OPENED:
    870             err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
    871             defaultMsg = "Attempted to use a closed session";
    872             break;
    873         case ERROR_DRM_CANNOT_HANDLE:
    874             err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
    875             defaultMsg = "Operation not supported in this configuration";
    876             break;
    877         default:  /* Other negative DRM error codes go out as is. */
    878             break;
    879     }
    880 
    881     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
    882 
    883     jthrowable exception =
    884         (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
    885 
    886     env->Throw(exception);
    887 }
    888 
    889 static jint throwExceptionAsNecessary(
    890         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
    891         const char *msg = NULL) {
    892     switch (err) {
    893         case OK:
    894             return 0;
    895 
    896         case -EAGAIN:
    897             return DEQUEUE_INFO_TRY_AGAIN_LATER;
    898 
    899         case INFO_FORMAT_CHANGED:
    900             return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
    901 
    902         case INFO_OUTPUT_BUFFERS_CHANGED:
    903             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
    904 
    905         case INVALID_OPERATION:
    906             jniThrowException(env, "java/lang/IllegalStateException", msg);
    907             return 0;
    908 
    909         case BAD_VALUE:
    910             jniThrowException(env, "java/lang/IllegalArgumentException", msg);
    911             return 0;
    912 
    913         default:
    914             if (isCryptoError(err)) {
    915                 throwCryptoException(env, err, msg);
    916                 return 0;
    917             }
    918             throwCodecException(env, err, actionCode, msg);
    919             return 0;
    920     }
    921 }
    922 
    923 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
    924         JNIEnv *env,
    925         jobject thiz,
    926         jboolean enabled) {
    927     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    928 
    929     if (codec == NULL) {
    930         throwExceptionAsNecessary(env, INVALID_OPERATION);
    931         return;
    932     }
    933 
    934     status_t err = codec->enableOnFrameRenderedListener(enabled);
    935 
    936     throwExceptionAsNecessary(env, err);
    937 }
    938 
    939 static void android_media_MediaCodec_native_setCallback(
    940         JNIEnv *env,
    941         jobject thiz,
    942         jobject cb) {
    943     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    944 
    945     if (codec == NULL) {
    946         throwExceptionAsNecessary(env, INVALID_OPERATION);
    947         return;
    948     }
    949 
    950     status_t err = codec->setCallback(cb);
    951 
    952     throwExceptionAsNecessary(env, err);
    953 }
    954 
    955 static void android_media_MediaCodec_native_configure(
    956         JNIEnv *env,
    957         jobject thiz,
    958         jobjectArray keys, jobjectArray values,
    959         jobject jsurface,
    960         jobject jcrypto,
    961         jint flags) {
    962     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    963 
    964     if (codec == NULL) {
    965         throwExceptionAsNecessary(env, INVALID_OPERATION);
    966         return;
    967     }
    968 
    969     sp<AMessage> format;
    970     status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
    971 
    972     if (err != OK) {
    973         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    974         return;
    975     }
    976 
    977     sp<IGraphicBufferProducer> bufferProducer;
    978     if (jsurface != NULL) {
    979         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
    980         if (surface != NULL) {
    981             bufferProducer = surface->getIGraphicBufferProducer();
    982         } else {
    983             jniThrowException(
    984                     env,
    985                     "java/lang/IllegalArgumentException",
    986                     "The surface has been released");
    987             return;
    988         }
    989     }
    990 
    991     sp<ICrypto> crypto;
    992     if (jcrypto != NULL) {
    993         crypto = JCrypto::GetCrypto(env, jcrypto);
    994     }
    995 
    996     err = codec->configure(format, bufferProducer, crypto, flags);
    997 
    998     throwExceptionAsNecessary(env, err);
    999 }
   1000 
   1001 static void android_media_MediaCodec_native_setSurface(
   1002         JNIEnv *env,
   1003         jobject thiz,
   1004         jobject jsurface) {
   1005     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1006 
   1007     if (codec == NULL) {
   1008         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1009         return;
   1010     }
   1011 
   1012     sp<IGraphicBufferProducer> bufferProducer;
   1013     if (jsurface != NULL) {
   1014         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
   1015         if (surface != NULL) {
   1016             bufferProducer = surface->getIGraphicBufferProducer();
   1017         } else {
   1018             jniThrowException(
   1019                     env,
   1020                     "java/lang/IllegalArgumentException",
   1021                     "The surface has been released");
   1022             return;
   1023         }
   1024     }
   1025 
   1026     status_t err = codec->setSurface(bufferProducer);
   1027     throwExceptionAsNecessary(env, err);
   1028 }
   1029 
   1030 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
   1031         JNIEnv* env, jobject object) {
   1032     sp<PersistentSurface> persistentSurface;
   1033 
   1034     jobject lock = env->GetObjectField(
   1035             object, gPersistentSurfaceClassInfo.mLock);
   1036     if (env->MonitorEnter(lock) == JNI_OK) {
   1037         persistentSurface = reinterpret_cast<PersistentSurface *>(
   1038                 env->GetLongField(object,
   1039                         gPersistentSurfaceClassInfo.mPersistentObject));
   1040         env->MonitorExit(lock);
   1041     }
   1042     env->DeleteLocalRef(lock);
   1043 
   1044     return persistentSurface;
   1045 }
   1046 
   1047 static jobject android_media_MediaCodec_createPersistentInputSurface(
   1048         JNIEnv* env, jclass /* clazz */) {
   1049     ALOGV("android_media_MediaCodec_createPersistentInputSurface");
   1050     sp<PersistentSurface> persistentSurface =
   1051         MediaCodec::CreatePersistentInputSurface();
   1052 
   1053     if (persistentSurface == NULL) {
   1054         return NULL;
   1055     }
   1056 
   1057     sp<Surface> surface = new Surface(
   1058             persistentSurface->getBufferProducer(), true);
   1059     if (surface == NULL) {
   1060         return NULL;
   1061     }
   1062 
   1063     jobject object = env->NewObject(
   1064             gPersistentSurfaceClassInfo.clazz,
   1065             gPersistentSurfaceClassInfo.ctor);
   1066 
   1067     if (object == NULL) {
   1068         if (env->ExceptionCheck()) {
   1069             ALOGE("Could not create PersistentSurface.");
   1070             env->ExceptionClear();
   1071         }
   1072         return NULL;
   1073     }
   1074 
   1075     jobject lock = env->GetObjectField(
   1076             object, gPersistentSurfaceClassInfo.mLock);
   1077     if (env->MonitorEnter(lock) == JNI_OK) {
   1078         env->CallVoidMethod(
   1079                 object,
   1080                 gPersistentSurfaceClassInfo.setNativeObjectLocked,
   1081                 (jlong)surface.get());
   1082         env->SetLongField(
   1083                 object,
   1084                 gPersistentSurfaceClassInfo.mPersistentObject,
   1085                 (jlong)persistentSurface.get());
   1086         env->MonitorExit(lock);
   1087     } else {
   1088         env->DeleteLocalRef(object);
   1089         object = NULL;
   1090     }
   1091     env->DeleteLocalRef(lock);
   1092 
   1093     if (object != NULL) {
   1094         surface->incStrong(&sRefBaseOwner);
   1095         persistentSurface->incStrong(&sRefBaseOwner);
   1096     }
   1097 
   1098     return object;
   1099 }
   1100 
   1101 static void android_media_MediaCodec_releasePersistentInputSurface(
   1102         JNIEnv* env, jclass /* clazz */, jobject object) {
   1103     sp<PersistentSurface> persistentSurface;
   1104 
   1105     jobject lock = env->GetObjectField(
   1106             object, gPersistentSurfaceClassInfo.mLock);
   1107     if (env->MonitorEnter(lock) == JNI_OK) {
   1108         persistentSurface = reinterpret_cast<PersistentSurface *>(
   1109             env->GetLongField(
   1110                     object, gPersistentSurfaceClassInfo.mPersistentObject));
   1111         env->SetLongField(
   1112                 object,
   1113                 gPersistentSurfaceClassInfo.mPersistentObject,
   1114                 (jlong)0);
   1115         env->MonitorExit(lock);
   1116     }
   1117     env->DeleteLocalRef(lock);
   1118 
   1119     if (persistentSurface != NULL) {
   1120         persistentSurface->decStrong(&sRefBaseOwner);
   1121     }
   1122     // no need to release surface as it will be released by Surface's jni
   1123 }
   1124 
   1125 static void android_media_MediaCodec_setInputSurface(
   1126         JNIEnv* env, jobject thiz, jobject object) {
   1127     ALOGV("android_media_MediaCodec_setInputSurface");
   1128 
   1129     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1130     if (codec == NULL) {
   1131         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1132         return;
   1133     }
   1134 
   1135     sp<PersistentSurface> persistentSurface =
   1136         android_media_MediaCodec_getPersistentInputSurface(env, object);
   1137 
   1138     status_t err = codec->setInputSurface(persistentSurface);
   1139     if (err != NO_ERROR) {
   1140         throwExceptionAsNecessary(env, err);
   1141     }
   1142 }
   1143 
   1144 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
   1145         jobject thiz) {
   1146     ALOGV("android_media_MediaCodec_createInputSurface");
   1147 
   1148     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1149     if (codec == NULL) {
   1150         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1151         return NULL;
   1152     }
   1153 
   1154     // Tell the MediaCodec that we want to use a Surface as input.
   1155     sp<IGraphicBufferProducer> bufferProducer;
   1156     status_t err = codec->createInputSurface(&bufferProducer);
   1157     if (err != NO_ERROR) {
   1158         throwExceptionAsNecessary(env, err);
   1159         return NULL;
   1160     }
   1161 
   1162     // Wrap the IGBP in a Java-language Surface.
   1163     return android_view_Surface_createFromIGraphicBufferProducer(env,
   1164             bufferProducer);
   1165 }
   1166 
   1167 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
   1168     ALOGV("android_media_MediaCodec_start");
   1169 
   1170     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1171 
   1172     if (codec == NULL) {
   1173         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1174         return;
   1175     }
   1176 
   1177     status_t err = codec->start();
   1178 
   1179     throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
   1180 }
   1181 
   1182 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
   1183     ALOGV("android_media_MediaCodec_stop");
   1184 
   1185     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1186 
   1187     if (codec == NULL) {
   1188         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1189         return;
   1190     }
   1191 
   1192     status_t err = codec->stop();
   1193 
   1194     throwExceptionAsNecessary(env, err);
   1195 }
   1196 
   1197 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
   1198     ALOGV("android_media_MediaCodec_reset");
   1199 
   1200     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1201 
   1202     if (codec == NULL) {
   1203         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1204         return;
   1205     }
   1206 
   1207     status_t err = codec->reset();
   1208     if (err != OK) {
   1209         // treat all errors as fatal for now, though resource not available
   1210         // errors could be treated as transient.
   1211         // we also should avoid sending INVALID_OPERATION here due to
   1212         // the transitory nature of reset(), it should not inadvertently
   1213         // trigger an IllegalStateException.
   1214         err = UNKNOWN_ERROR;
   1215     }
   1216     throwExceptionAsNecessary(env, err);
   1217 }
   1218 
   1219 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
   1220     ALOGV("android_media_MediaCodec_flush");
   1221 
   1222     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1223 
   1224     if (codec == NULL) {
   1225         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1226         return;
   1227     }
   1228 
   1229     status_t err = codec->flush();
   1230 
   1231     throwExceptionAsNecessary(env, err);
   1232 }
   1233 
   1234 static void android_media_MediaCodec_queueInputBuffer(
   1235         JNIEnv *env,
   1236         jobject thiz,
   1237         jint index,
   1238         jint offset,
   1239         jint size,
   1240         jlong timestampUs,
   1241         jint flags) {
   1242     ALOGV("android_media_MediaCodec_queueInputBuffer");
   1243 
   1244     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1245 
   1246     if (codec == NULL) {
   1247         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1248         return;
   1249     }
   1250 
   1251     AString errorDetailMsg;
   1252 
   1253     status_t err = codec->queueInputBuffer(
   1254             index, offset, size, timestampUs, flags, &errorDetailMsg);
   1255 
   1256     throwExceptionAsNecessary(
   1257             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
   1258 }
   1259 
   1260 static void android_media_MediaCodec_queueSecureInputBuffer(
   1261         JNIEnv *env,
   1262         jobject thiz,
   1263         jint index,
   1264         jint offset,
   1265         jobject cryptoInfoObj,
   1266         jlong timestampUs,
   1267         jint flags) {
   1268     ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
   1269 
   1270     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1271 
   1272     if (codec == NULL) {
   1273         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1274         return;
   1275     }
   1276 
   1277     jint numSubSamples =
   1278         env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
   1279 
   1280     jintArray numBytesOfClearDataObj =
   1281         (jintArray)env->GetObjectField(
   1282                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
   1283 
   1284     jintArray numBytesOfEncryptedDataObj =
   1285         (jintArray)env->GetObjectField(
   1286                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
   1287 
   1288     jbyteArray keyObj =
   1289         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
   1290 
   1291     jbyteArray ivObj =
   1292         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
   1293 
   1294     jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
   1295     enum CryptoPlugin::Mode mode;
   1296     if (jmode == gCryptoModes.Unencrypted) {
   1297         mode = CryptoPlugin::kMode_Unencrypted;
   1298     } else if (jmode == gCryptoModes.AesCtr) {
   1299         mode = CryptoPlugin::kMode_AES_CTR;
   1300     } else if (jmode == gCryptoModes.AesCbc) {
   1301         mode = CryptoPlugin::kMode_AES_CBC;
   1302     }  else {
   1303         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1304         return;
   1305     }
   1306 
   1307     jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
   1308 
   1309     CryptoPlugin::Pattern pattern;
   1310     if (patternObj == NULL) {
   1311         pattern.mEncryptBlocks = 0;
   1312         pattern.mSkipBlocks = 0;
   1313     } else {
   1314         pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
   1315         pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
   1316     }
   1317 
   1318     status_t err = OK;
   1319 
   1320     CryptoPlugin::SubSample *subSamples = NULL;
   1321     jbyte *key = NULL;
   1322     jbyte *iv = NULL;
   1323 
   1324     if (numSubSamples <= 0) {
   1325         err = -EINVAL;
   1326     } else if (numBytesOfClearDataObj == NULL
   1327             && numBytesOfEncryptedDataObj == NULL) {
   1328         err = -EINVAL;
   1329     } else if (numBytesOfEncryptedDataObj != NULL
   1330             && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
   1331         err = -ERANGE;
   1332     } else if (numBytesOfClearDataObj != NULL
   1333             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
   1334         err = -ERANGE;
   1335     // subSamples array may silently overflow if number of samples are too large.  Use
   1336     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
   1337     } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
   1338         err = -EINVAL;
   1339     } else {
   1340         jboolean isCopy;
   1341 
   1342         jint *numBytesOfClearData =
   1343             (numBytesOfClearDataObj == NULL)
   1344                 ? NULL
   1345                 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
   1346 
   1347         jint *numBytesOfEncryptedData =
   1348             (numBytesOfEncryptedDataObj == NULL)
   1349                 ? NULL
   1350                 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
   1351 
   1352         subSamples = new CryptoPlugin::SubSample[numSubSamples];
   1353 
   1354         for (jint i = 0; i < numSubSamples; ++i) {
   1355             subSamples[i].mNumBytesOfClearData =
   1356                 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
   1357 
   1358             subSamples[i].mNumBytesOfEncryptedData =
   1359                 (numBytesOfEncryptedData == NULL)
   1360                     ? 0 : numBytesOfEncryptedData[i];
   1361         }
   1362 
   1363         if (numBytesOfEncryptedData != NULL) {
   1364             env->ReleaseIntArrayElements(
   1365                     numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
   1366             numBytesOfEncryptedData = NULL;
   1367         }
   1368 
   1369         if (numBytesOfClearData != NULL) {
   1370             env->ReleaseIntArrayElements(
   1371                     numBytesOfClearDataObj, numBytesOfClearData, 0);
   1372             numBytesOfClearData = NULL;
   1373         }
   1374     }
   1375 
   1376     if (err == OK && keyObj != NULL) {
   1377         if (env->GetArrayLength(keyObj) != 16) {
   1378             err = -EINVAL;
   1379         } else {
   1380             jboolean isCopy;
   1381             key = env->GetByteArrayElements(keyObj, &isCopy);
   1382         }
   1383     }
   1384 
   1385     if (err == OK && ivObj != NULL) {
   1386         if (env->GetArrayLength(ivObj) != 16) {
   1387             err = -EINVAL;
   1388         } else {
   1389             jboolean isCopy;
   1390             iv = env->GetByteArrayElements(ivObj, &isCopy);
   1391         }
   1392     }
   1393 
   1394     AString errorDetailMsg;
   1395 
   1396     if (err == OK) {
   1397         err = codec->queueSecureInputBuffer(
   1398                 index, offset,
   1399                 subSamples, numSubSamples,
   1400                 (const uint8_t *)key, (const uint8_t *)iv,
   1401                 mode,
   1402                 pattern,
   1403                 timestampUs,
   1404                 flags,
   1405                 &errorDetailMsg);
   1406     }
   1407 
   1408     if (iv != NULL) {
   1409         env->ReleaseByteArrayElements(ivObj, iv, 0);
   1410         iv = NULL;
   1411     }
   1412 
   1413     if (key != NULL) {
   1414         env->ReleaseByteArrayElements(keyObj, key, 0);
   1415         key = NULL;
   1416     }
   1417 
   1418     delete[] subSamples;
   1419     subSamples = NULL;
   1420 
   1421     throwExceptionAsNecessary(
   1422             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
   1423 }
   1424 
   1425 static jint android_media_MediaCodec_dequeueInputBuffer(
   1426         JNIEnv *env, jobject thiz, jlong timeoutUs) {
   1427     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
   1428 
   1429     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1430 
   1431     if (codec == NULL) {
   1432         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1433         return -1;
   1434     }
   1435 
   1436     size_t index;
   1437     status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
   1438 
   1439     if (err == OK) {
   1440         return (jint) index;
   1441     }
   1442 
   1443     return throwExceptionAsNecessary(env, err);
   1444 }
   1445 
   1446 static jint android_media_MediaCodec_dequeueOutputBuffer(
   1447         JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
   1448     ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
   1449 
   1450     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1451 
   1452     if (codec == NULL) {
   1453         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1454         return 0;
   1455     }
   1456 
   1457     size_t index;
   1458     status_t err = codec->dequeueOutputBuffer(
   1459             env, bufferInfo, &index, timeoutUs);
   1460 
   1461     if (err == OK) {
   1462         return (jint) index;
   1463     }
   1464 
   1465     return throwExceptionAsNecessary(env, err);
   1466 }
   1467 
   1468 static void android_media_MediaCodec_releaseOutputBuffer(
   1469         JNIEnv *env, jobject thiz,
   1470         jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
   1471     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
   1472 
   1473     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1474 
   1475     if (codec == NULL) {
   1476         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1477         return;
   1478     }
   1479 
   1480     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
   1481 
   1482     throwExceptionAsNecessary(env, err);
   1483 }
   1484 
   1485 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
   1486         jobject thiz) {
   1487     ALOGV("android_media_MediaCodec_signalEndOfInputStream");
   1488 
   1489     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1490     if (codec == NULL) {
   1491         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1492         return;
   1493     }
   1494 
   1495     status_t err = codec->signalEndOfInputStream();
   1496 
   1497     throwExceptionAsNecessary(env, err);
   1498 }
   1499 
   1500 static jobject android_media_MediaCodec_getFormatNative(
   1501         JNIEnv *env, jobject thiz, jboolean input) {
   1502     ALOGV("android_media_MediaCodec_getFormatNative");
   1503 
   1504     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1505 
   1506     if (codec == NULL) {
   1507         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1508         return NULL;
   1509     }
   1510 
   1511     jobject format;
   1512     status_t err = codec->getFormat(env, input, &format);
   1513 
   1514     if (err == OK) {
   1515         return format;
   1516     }
   1517 
   1518     throwExceptionAsNecessary(env, err);
   1519 
   1520     return NULL;
   1521 }
   1522 
   1523 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
   1524         JNIEnv *env, jobject thiz, jint index) {
   1525     ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
   1526 
   1527     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1528 
   1529     if (codec == NULL) {
   1530         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1531         return NULL;
   1532     }
   1533 
   1534     jobject format;
   1535     status_t err = codec->getOutputFormat(env, index, &format);
   1536 
   1537     if (err == OK) {
   1538         return format;
   1539     }
   1540 
   1541     throwExceptionAsNecessary(env, err);
   1542 
   1543     return NULL;
   1544 }
   1545 
   1546 static jobjectArray android_media_MediaCodec_getBuffers(
   1547         JNIEnv *env, jobject thiz, jboolean input) {
   1548     ALOGV("android_media_MediaCodec_getBuffers");
   1549 
   1550     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1551 
   1552     if (codec == NULL) {
   1553         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1554         return NULL;
   1555     }
   1556 
   1557     jobjectArray buffers;
   1558     status_t err = codec->getBuffers(env, input, &buffers);
   1559 
   1560     if (err == OK) {
   1561         return buffers;
   1562     }
   1563 
   1564     // if we're out of memory, an exception was already thrown
   1565     if (err != NO_MEMORY) {
   1566         throwExceptionAsNecessary(env, err);
   1567     }
   1568 
   1569     return NULL;
   1570 }
   1571 
   1572 static jobject android_media_MediaCodec_getBuffer(
   1573         JNIEnv *env, jobject thiz, jboolean input, jint index) {
   1574     ALOGV("android_media_MediaCodec_getBuffer");
   1575 
   1576     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1577 
   1578     if (codec == NULL) {
   1579         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1580         return NULL;
   1581     }
   1582 
   1583     jobject buffer;
   1584     status_t err = codec->getBuffer(env, input, index, &buffer);
   1585 
   1586     if (err == OK) {
   1587         return buffer;
   1588     }
   1589 
   1590     // if we're out of memory, an exception was already thrown
   1591     if (err != NO_MEMORY) {
   1592         throwExceptionAsNecessary(env, err);
   1593     }
   1594 
   1595     return NULL;
   1596 }
   1597 
   1598 static jobject android_media_MediaCodec_getImage(
   1599         JNIEnv *env, jobject thiz, jboolean input, jint index) {
   1600     ALOGV("android_media_MediaCodec_getImage");
   1601 
   1602     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1603 
   1604     if (codec == NULL) {
   1605         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1606         return NULL;
   1607     }
   1608 
   1609     jobject image;
   1610     status_t err = codec->getImage(env, input, index, &image);
   1611 
   1612     if (err == OK) {
   1613         return image;
   1614     }
   1615 
   1616     // if we're out of memory, an exception was already thrown
   1617     if (err != NO_MEMORY) {
   1618         throwExceptionAsNecessary(env, err);
   1619     }
   1620 
   1621     return NULL;
   1622 }
   1623 
   1624 static jobject android_media_MediaCodec_getName(
   1625         JNIEnv *env, jobject thiz) {
   1626     ALOGV("android_media_MediaCodec_getName");
   1627 
   1628     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1629 
   1630     if (codec == NULL) {
   1631         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1632         return NULL;
   1633     }
   1634 
   1635     jstring name;
   1636     status_t err = codec->getName(env, &name);
   1637 
   1638     if (err == OK) {
   1639         return name;
   1640     }
   1641 
   1642     throwExceptionAsNecessary(env, err);
   1643 
   1644     return NULL;
   1645 }
   1646 
   1647 static void android_media_MediaCodec_setParameters(
   1648         JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
   1649     ALOGV("android_media_MediaCodec_setParameters");
   1650 
   1651     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1652 
   1653     if (codec == NULL) {
   1654         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1655         return;
   1656     }
   1657 
   1658     sp<AMessage> params;
   1659     status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
   1660 
   1661     if (err == OK) {
   1662         err = codec->setParameters(params);
   1663     }
   1664 
   1665     throwExceptionAsNecessary(env, err);
   1666 }
   1667 
   1668 static void android_media_MediaCodec_setVideoScalingMode(
   1669         JNIEnv *env, jobject thiz, jint mode) {
   1670     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1671 
   1672     if (codec == NULL) {
   1673         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1674         return;
   1675     }
   1676 
   1677     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
   1678             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
   1679         jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
   1680         return;
   1681     }
   1682 
   1683     codec->setVideoScalingMode(mode);
   1684 }
   1685 
   1686 static void android_media_MediaCodec_native_init(JNIEnv *env) {
   1687     ScopedLocalRef<jclass> clazz(
   1688             env, env->FindClass("android/media/MediaCodec"));
   1689     CHECK(clazz.get() != NULL);
   1690 
   1691     gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
   1692     CHECK(gFields.context != NULL);
   1693 
   1694     gFields.postEventFromNativeID =
   1695         env->GetMethodID(
   1696                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
   1697 
   1698     CHECK(gFields.postEventFromNativeID != NULL);
   1699 
   1700     jfieldID field;
   1701     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
   1702     CHECK(field != NULL);
   1703     gCryptoModes.Unencrypted =
   1704         env->GetStaticIntField(clazz.get(), field);
   1705 
   1706     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
   1707     CHECK(field != NULL);
   1708     gCryptoModes.AesCtr =
   1709         env->GetStaticIntField(clazz.get(), field);
   1710 
   1711     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
   1712     CHECK(field != NULL);
   1713     gCryptoModes.AesCbc =
   1714         env->GetStaticIntField(clazz.get(), field);
   1715 
   1716     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
   1717     CHECK(clazz.get() != NULL);
   1718 
   1719     gFields.cryptoInfoNumSubSamplesID =
   1720         env->GetFieldID(clazz.get(), "numSubSamples", "I");
   1721     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
   1722 
   1723     gFields.cryptoInfoNumBytesOfClearDataID =
   1724         env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
   1725     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
   1726 
   1727     gFields.cryptoInfoNumBytesOfEncryptedDataID =
   1728         env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
   1729     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
   1730 
   1731     gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
   1732     CHECK(gFields.cryptoInfoKeyID != NULL);
   1733 
   1734     gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
   1735     CHECK(gFields.cryptoInfoIVID != NULL);
   1736 
   1737     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
   1738     CHECK(gFields.cryptoInfoModeID != NULL);
   1739 
   1740     gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
   1741         "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
   1742     CHECK(gFields.cryptoInfoPatternID != NULL);
   1743 
   1744     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
   1745     CHECK(clazz.get() != NULL);
   1746 
   1747     gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
   1748     CHECK(gFields.patternEncryptBlocksID != NULL);
   1749 
   1750     gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
   1751     CHECK(gFields.patternSkipBlocksID != NULL);
   1752 
   1753     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
   1754     CHECK(clazz.get() != NULL);
   1755 
   1756     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
   1757     CHECK(field != NULL);
   1758     gCryptoErrorCodes.cryptoErrorNoKey =
   1759         env->GetStaticIntField(clazz.get(), field);
   1760 
   1761     field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
   1762     CHECK(field != NULL);
   1763     gCryptoErrorCodes.cryptoErrorKeyExpired =
   1764         env->GetStaticIntField(clazz.get(), field);
   1765 
   1766     field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
   1767     CHECK(field != NULL);
   1768     gCryptoErrorCodes.cryptoErrorResourceBusy =
   1769         env->GetStaticIntField(clazz.get(), field);
   1770 
   1771     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
   1772     CHECK(field != NULL);
   1773     gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
   1774         env->GetStaticIntField(clazz.get(), field);
   1775 
   1776     field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
   1777     CHECK(field != NULL);
   1778     gCryptoErrorCodes.cryptoErrorSessionNotOpened =
   1779         env->GetStaticIntField(clazz.get(), field);
   1780 
   1781     field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
   1782     CHECK(field != NULL);
   1783     gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
   1784         env->GetStaticIntField(clazz.get(), field);
   1785 
   1786     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
   1787     CHECK(clazz.get() != NULL);
   1788     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
   1789     CHECK(field != NULL);
   1790     gCodecActionCodes.codecActionTransient =
   1791         env->GetStaticIntField(clazz.get(), field);
   1792 
   1793     field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
   1794     CHECK(field != NULL);
   1795     gCodecActionCodes.codecActionRecoverable =
   1796         env->GetStaticIntField(clazz.get(), field);
   1797 
   1798     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
   1799     CHECK(field != NULL);
   1800     gCodecErrorCodes.errorInsufficientResource =
   1801         env->GetStaticIntField(clazz.get(), field);
   1802 
   1803     field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
   1804     CHECK(field != NULL);
   1805     gCodecErrorCodes.errorReclaimed =
   1806         env->GetStaticIntField(clazz.get(), field);
   1807 
   1808     clazz.reset(env->FindClass("android/view/Surface"));
   1809     CHECK(clazz.get() != NULL);
   1810 
   1811     field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
   1812     CHECK(field != NULL);
   1813     gPersistentSurfaceClassInfo.mLock = field;
   1814 
   1815     jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
   1816     CHECK(method != NULL);
   1817     gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
   1818 
   1819     clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
   1820     CHECK(clazz.get() != NULL);
   1821     gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
   1822 
   1823     method = env->GetMethodID(clazz.get(), "<init>", "()V");
   1824     CHECK(method != NULL);
   1825     gPersistentSurfaceClassInfo.ctor = method;
   1826 
   1827     field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
   1828     CHECK(field != NULL);
   1829     gPersistentSurfaceClassInfo.mPersistentObject = field;
   1830 }
   1831 
   1832 static void android_media_MediaCodec_native_setup(
   1833         JNIEnv *env, jobject thiz,
   1834         jstring name, jboolean nameIsType, jboolean encoder) {
   1835     if (name == NULL) {
   1836         jniThrowException(env, "java/lang/NullPointerException", NULL);
   1837         return;
   1838     }
   1839 
   1840     const char *tmp = env->GetStringUTFChars(name, NULL);
   1841 
   1842     if (tmp == NULL) {
   1843         return;
   1844     }
   1845 
   1846     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
   1847 
   1848     const status_t err = codec->initCheck();
   1849     if (err == NAME_NOT_FOUND) {
   1850         // fail and do not try again.
   1851         jniThrowException(env, "java/lang/IllegalArgumentException",
   1852                 String8::format("Failed to initialize %s, error %#x", tmp, err));
   1853         env->ReleaseStringUTFChars(name, tmp);
   1854         return;
   1855     } if (err == NO_MEMORY) {
   1856         throwCodecException(env, err, ACTION_CODE_TRANSIENT,
   1857                 String8::format("Failed to initialize %s, error %#x", tmp, err));
   1858         env->ReleaseStringUTFChars(name, tmp);
   1859         return;
   1860     } else if (err != OK) {
   1861         // believed possible to try again
   1862         jniThrowException(env, "java/io/IOException",
   1863                 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
   1864         env->ReleaseStringUTFChars(name, tmp);
   1865         return;
   1866     }
   1867 
   1868     env->ReleaseStringUTFChars(name, tmp);
   1869 
   1870     codec->registerSelf();
   1871 
   1872     setMediaCodec(env,thiz, codec);
   1873 }
   1874 
   1875 static void android_media_MediaCodec_native_finalize(
   1876         JNIEnv *env, jobject thiz) {
   1877     android_media_MediaCodec_release(env, thiz);
   1878 }
   1879 
   1880 static const JNINativeMethod gMethods[] = {
   1881     { "native_release", "()V", (void *)android_media_MediaCodec_release },
   1882 
   1883     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
   1884 
   1885     { "native_releasePersistentInputSurface",
   1886       "(Landroid/view/Surface;)V",
   1887        (void *)android_media_MediaCodec_releasePersistentInputSurface},
   1888 
   1889     { "native_createPersistentInputSurface",
   1890       "()Landroid/media/MediaCodec$PersistentSurface;",
   1891       (void *)android_media_MediaCodec_createPersistentInputSurface },
   1892 
   1893     { "native_setInputSurface", "(Landroid/view/Surface;)V",
   1894       (void *)android_media_MediaCodec_setInputSurface },
   1895 
   1896     { "native_enableOnFrameRenderedListener", "(Z)V",
   1897       (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
   1898 
   1899     { "native_setCallback",
   1900       "(Landroid/media/MediaCodec$Callback;)V",
   1901       (void *)android_media_MediaCodec_native_setCallback },
   1902 
   1903     { "native_configure",
   1904       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
   1905       "Landroid/media/MediaCrypto;I)V",
   1906       (void *)android_media_MediaCodec_native_configure },
   1907 
   1908     { "native_setSurface",
   1909       "(Landroid/view/Surface;)V",
   1910       (void *)android_media_MediaCodec_native_setSurface },
   1911 
   1912     { "createInputSurface", "()Landroid/view/Surface;",
   1913       (void *)android_media_MediaCodec_createInputSurface },
   1914 
   1915     { "native_start", "()V", (void *)android_media_MediaCodec_start },
   1916     { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
   1917     { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
   1918 
   1919     { "native_queueInputBuffer", "(IIIJI)V",
   1920       (void *)android_media_MediaCodec_queueInputBuffer },
   1921 
   1922     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
   1923       (void *)android_media_MediaCodec_queueSecureInputBuffer },
   1924 
   1925     { "native_dequeueInputBuffer", "(J)I",
   1926       (void *)android_media_MediaCodec_dequeueInputBuffer },
   1927 
   1928     { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
   1929       (void *)android_media_MediaCodec_dequeueOutputBuffer },
   1930 
   1931     { "releaseOutputBuffer", "(IZZJ)V",
   1932       (void *)android_media_MediaCodec_releaseOutputBuffer },
   1933 
   1934     { "signalEndOfInputStream", "()V",
   1935       (void *)android_media_MediaCodec_signalEndOfInputStream },
   1936 
   1937     { "getFormatNative", "(Z)Ljava/util/Map;",
   1938       (void *)android_media_MediaCodec_getFormatNative },
   1939 
   1940     { "getOutputFormatNative", "(I)Ljava/util/Map;",
   1941       (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
   1942 
   1943     { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
   1944       (void *)android_media_MediaCodec_getBuffers },
   1945 
   1946     { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
   1947       (void *)android_media_MediaCodec_getBuffer },
   1948 
   1949     { "getImage", "(ZI)Landroid/media/Image;",
   1950       (void *)android_media_MediaCodec_getImage },
   1951 
   1952     { "getName", "()Ljava/lang/String;",
   1953       (void *)android_media_MediaCodec_getName },
   1954 
   1955     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
   1956       (void *)android_media_MediaCodec_setParameters },
   1957 
   1958     { "setVideoScalingMode", "(I)V",
   1959       (void *)android_media_MediaCodec_setVideoScalingMode },
   1960 
   1961     { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
   1962 
   1963     { "native_setup", "(Ljava/lang/String;ZZ)V",
   1964       (void *)android_media_MediaCodec_native_setup },
   1965 
   1966     { "native_finalize", "()V",
   1967       (void *)android_media_MediaCodec_native_finalize },
   1968 };
   1969 
   1970 int register_android_media_MediaCodec(JNIEnv *env) {
   1971     return AndroidRuntime::registerNativeMethods(env,
   1972                 "android/media/MediaCodec", gMethods, NELEM(gMethods));
   1973 }
   1974