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 
     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 };
     60 
     61 static struct CryptoErrorCodes {
     62     jint cryptoErrorNoKey;
     63     jint cryptoErrorKeyExpired;
     64     jint cryptoErrorResourceBusy;
     65     jint cryptoErrorInsufficientOutputProtection;
     66 } gCryptoErrorCodes;
     67 
     68 static struct CodecActionCodes {
     69     jint codecActionTransient;
     70     jint codecActionRecoverable;
     71 } gCodecActionCodes;
     72 
     73 struct fields_t {
     74     jfieldID context;
     75     jmethodID postEventFromNativeID;
     76     jfieldID cryptoInfoNumSubSamplesID;
     77     jfieldID cryptoInfoNumBytesOfClearDataID;
     78     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
     79     jfieldID cryptoInfoKeyID;
     80     jfieldID cryptoInfoIVID;
     81     jfieldID cryptoInfoModeID;
     82 };
     83 
     84 static fields_t gFields;
     85 
     86 ////////////////////////////////////////////////////////////////////////////////
     87 
     88 JMediaCodec::JMediaCodec(
     89         JNIEnv *env, jobject thiz,
     90         const char *name, bool nameIsType, bool encoder)
     91     : mClass(NULL),
     92       mObject(NULL) {
     93     jclass clazz = env->GetObjectClass(thiz);
     94     CHECK(clazz != NULL);
     95 
     96     mClass = (jclass)env->NewGlobalRef(clazz);
     97     mObject = env->NewWeakGlobalRef(thiz);
     98 
     99     cacheJavaObjects(env);
    100 
    101     mLooper = new ALooper;
    102     mLooper->setName("MediaCodec_looper");
    103 
    104     mLooper->start(
    105             false,      // runOnCallingThread
    106             true,       // canCallJava
    107             PRIORITY_FOREGROUND);
    108 
    109     if (nameIsType) {
    110         mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
    111     } else {
    112         mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
    113     }
    114     CHECK((mCodec != NULL) != (mInitStatus != OK));
    115 }
    116 
    117 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
    118     jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
    119     mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
    120     CHECK(mByteBufferClass != NULL);
    121 
    122     ScopedLocalRef<jclass> byteOrderClass(
    123             env, env->FindClass("java/nio/ByteOrder"));
    124     CHECK(byteOrderClass.get() != NULL);
    125 
    126     jmethodID nativeOrderID = env->GetStaticMethodID(
    127             byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
    128     CHECK(nativeOrderID != NULL);
    129 
    130     jobject nativeByteOrderObj =
    131         env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
    132     mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
    133     CHECK(mNativeByteOrderObj != NULL);
    134     env->DeleteLocalRef(nativeByteOrderObj);
    135     nativeByteOrderObj = NULL;
    136 
    137     mByteBufferOrderMethodID = env->GetMethodID(
    138             mByteBufferClass,
    139             "order",
    140             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
    141     CHECK(mByteBufferOrderMethodID != NULL);
    142 
    143     mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
    144             mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
    145     CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
    146 
    147     mByteBufferPositionMethodID = env->GetMethodID(
    148             mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
    149     CHECK(mByteBufferPositionMethodID != NULL);
    150 
    151     mByteBufferLimitMethodID = env->GetMethodID(
    152             mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
    153     CHECK(mByteBufferLimitMethodID != NULL);
    154 }
    155 
    156 status_t JMediaCodec::initCheck() const {
    157     return mInitStatus;
    158 }
    159 
    160 void JMediaCodec::registerSelf() {
    161     mLooper->registerHandler(this);
    162 }
    163 
    164 void JMediaCodec::release() {
    165     if (mCodec != NULL) {
    166         mCodec->release();
    167         mCodec.clear();
    168         mInitStatus = NO_INIT;
    169     }
    170 
    171     if (mLooper != NULL) {
    172         mLooper->unregisterHandler(id());
    173         mLooper->stop();
    174         mLooper.clear();
    175     }
    176 }
    177 
    178 JMediaCodec::~JMediaCodec() {
    179     if (mCodec != NULL || mLooper != NULL) {
    180         /* MediaCodec and looper should have been released explicitly already
    181          * in setMediaCodec() (see comments in setMediaCodec()).
    182          *
    183          * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
    184          * message handler, doing release() there risks deadlock as MediaCodec::
    185          * release() post synchronous message to the same looper.
    186          *
    187          * Print a warning and try to proceed with releasing.
    188          */
    189         ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
    190         release();
    191         ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
    192     }
    193 
    194     JNIEnv *env = AndroidRuntime::getJNIEnv();
    195 
    196     env->DeleteWeakGlobalRef(mObject);
    197     mObject = NULL;
    198     env->DeleteGlobalRef(mClass);
    199     mClass = NULL;
    200     deleteJavaObjects(env);
    201 }
    202 
    203 void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
    204     env->DeleteGlobalRef(mByteBufferClass);
    205     mByteBufferClass = NULL;
    206     env->DeleteGlobalRef(mNativeByteOrderObj);
    207     mNativeByteOrderObj = NULL;
    208 
    209     mByteBufferOrderMethodID = NULL;
    210     mByteBufferAsReadOnlyBufferMethodID = NULL;
    211     mByteBufferPositionMethodID = NULL;
    212     mByteBufferLimitMethodID = NULL;
    213 }
    214 
    215 status_t JMediaCodec::setCallback(jobject cb) {
    216     if (cb != NULL) {
    217         if (mCallbackNotification == NULL) {
    218             mCallbackNotification = new AMessage(kWhatCallbackNotify, id());
    219         }
    220     } else {
    221         mCallbackNotification.clear();
    222     }
    223 
    224     return mCodec->setCallback(mCallbackNotification);
    225 }
    226 
    227 status_t JMediaCodec::configure(
    228         const sp<AMessage> &format,
    229         const sp<IGraphicBufferProducer> &bufferProducer,
    230         const sp<ICrypto> &crypto,
    231         int flags) {
    232     sp<Surface> client;
    233     if (bufferProducer != NULL) {
    234         mSurfaceTextureClient =
    235             new Surface(bufferProducer, true /* controlledByApp */);
    236     } else {
    237         mSurfaceTextureClient.clear();
    238     }
    239 
    240     return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
    241 }
    242 
    243 status_t JMediaCodec::createInputSurface(
    244         sp<IGraphicBufferProducer>* bufferProducer) {
    245     return mCodec->createInputSurface(bufferProducer);
    246 }
    247 
    248 status_t JMediaCodec::start() {
    249     return mCodec->start();
    250 }
    251 
    252 status_t JMediaCodec::stop() {
    253     mSurfaceTextureClient.clear();
    254 
    255     return mCodec->stop();
    256 }
    257 
    258 status_t JMediaCodec::flush() {
    259     return mCodec->flush();
    260 }
    261 
    262 status_t JMediaCodec::reset() {
    263     return mCodec->reset();
    264 }
    265 
    266 status_t JMediaCodec::queueInputBuffer(
    267         size_t index,
    268         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
    269         AString *errorDetailMsg) {
    270     return mCodec->queueInputBuffer(
    271             index, offset, size, timeUs, flags, errorDetailMsg);
    272 }
    273 
    274 status_t JMediaCodec::queueSecureInputBuffer(
    275         size_t index,
    276         size_t offset,
    277         const CryptoPlugin::SubSample *subSamples,
    278         size_t numSubSamples,
    279         const uint8_t key[16],
    280         const uint8_t iv[16],
    281         CryptoPlugin::Mode mode,
    282         int64_t presentationTimeUs,
    283         uint32_t flags,
    284         AString *errorDetailMsg) {
    285     return mCodec->queueSecureInputBuffer(
    286             index, offset, subSamples, numSubSamples, key, iv, mode,
    287             presentationTimeUs, flags, errorDetailMsg);
    288 }
    289 
    290 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
    291     return mCodec->dequeueInputBuffer(index, timeoutUs);
    292 }
    293 
    294 status_t JMediaCodec::dequeueOutputBuffer(
    295         JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
    296     size_t size, offset;
    297     int64_t timeUs;
    298     uint32_t flags;
    299     status_t err = mCodec->dequeueOutputBuffer(
    300             index, &offset, &size, &timeUs, &flags, timeoutUs);
    301 
    302     if (err != OK) {
    303         return err;
    304     }
    305 
    306     ScopedLocalRef<jclass> clazz(
    307             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
    308 
    309     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
    310     env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
    311 
    312     return OK;
    313 }
    314 
    315 status_t JMediaCodec::releaseOutputBuffer(
    316         size_t index, bool render, bool updatePTS, int64_t timestampNs) {
    317     if (updatePTS) {
    318         return mCodec->renderOutputBufferAndRelease(index, timestampNs);
    319     }
    320     return render
    321         ? mCodec->renderOutputBufferAndRelease(index)
    322         : mCodec->releaseOutputBuffer(index);
    323 }
    324 
    325 status_t JMediaCodec::signalEndOfInputStream() {
    326     return mCodec->signalEndOfInputStream();
    327 }
    328 
    329 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
    330     sp<AMessage> msg;
    331     status_t err;
    332     err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
    333     if (err != OK) {
    334         return err;
    335     }
    336 
    337     return ConvertMessageToMap(env, msg, format);
    338 }
    339 
    340 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
    341     sp<AMessage> msg;
    342     status_t err;
    343     if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
    344         return err;
    345     }
    346 
    347     return ConvertMessageToMap(env, msg, format);
    348 }
    349 
    350 status_t JMediaCodec::getBuffers(
    351         JNIEnv *env, bool input, jobjectArray *bufArray) const {
    352     Vector<sp<ABuffer> > buffers;
    353 
    354     status_t err =
    355         input
    356             ? mCodec->getInputBuffers(&buffers)
    357             : mCodec->getOutputBuffers(&buffers);
    358 
    359     if (err != OK) {
    360         return err;
    361     }
    362 
    363     *bufArray = (jobjectArray)env->NewObjectArray(
    364             buffers.size(), mByteBufferClass, NULL);
    365     if (*bufArray == NULL) {
    366         return NO_MEMORY;
    367     }
    368 
    369     for (size_t i = 0; i < buffers.size(); ++i) {
    370         const sp<ABuffer> &buffer = buffers.itemAt(i);
    371 
    372         jobject byteBuffer = NULL;
    373         err = createByteBufferFromABuffer(
    374                 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
    375         if (err != OK) {
    376             return err;
    377         }
    378         if (byteBuffer != NULL) {
    379             env->SetObjectArrayElement(
    380                     *bufArray, i, byteBuffer);
    381 
    382             env->DeleteLocalRef(byteBuffer);
    383             byteBuffer = NULL;
    384         }
    385     }
    386 
    387     return OK;
    388 }
    389 
    390 // static
    391 status_t JMediaCodec::createByteBufferFromABuffer(
    392         JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
    393         jobject *buf) const {
    394     // if this is an ABuffer that doesn't actually hold any accessible memory,
    395     // use a null ByteBuffer
    396     *buf = NULL;
    397     if (buffer->base() == NULL) {
    398         return OK;
    399     }
    400 
    401     jobject byteBuffer =
    402         env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
    403     if (readOnly && byteBuffer != NULL) {
    404         jobject readOnlyBuffer = env->CallObjectMethod(
    405                 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
    406         env->DeleteLocalRef(byteBuffer);
    407         byteBuffer = readOnlyBuffer;
    408     }
    409     if (byteBuffer == NULL) {
    410         return NO_MEMORY;
    411     }
    412     jobject me = env->CallObjectMethod(
    413             byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
    414     env->DeleteLocalRef(me);
    415     me = env->CallObjectMethod(
    416             byteBuffer, mByteBufferLimitMethodID,
    417             clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
    418     env->DeleteLocalRef(me);
    419     me = env->CallObjectMethod(
    420             byteBuffer, mByteBufferPositionMethodID,
    421             clearBuffer ? 0 : buffer->offset());
    422     env->DeleteLocalRef(me);
    423     me = NULL;
    424 
    425     *buf = byteBuffer;
    426     return OK;
    427 }
    428 
    429 status_t JMediaCodec::getBuffer(
    430         JNIEnv *env, bool input, size_t index, jobject *buf) const {
    431     sp<ABuffer> buffer;
    432 
    433     status_t err =
    434         input
    435             ? mCodec->getInputBuffer(index, &buffer)
    436             : mCodec->getOutputBuffer(index, &buffer);
    437 
    438     if (err != OK) {
    439         return err;
    440     }
    441 
    442     return createByteBufferFromABuffer(
    443             env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
    444 }
    445 
    446 status_t JMediaCodec::getImage(
    447         JNIEnv *env, bool input, size_t index, jobject *buf) const {
    448     sp<ABuffer> buffer;
    449 
    450     status_t err =
    451         input
    452             ? mCodec->getInputBuffer(index, &buffer)
    453             : mCodec->getOutputBuffer(index, &buffer);
    454 
    455     if (err != OK) {
    456         return err;
    457     }
    458 
    459     // if this is an ABuffer that doesn't actually hold any accessible memory,
    460     // use a null ByteBuffer
    461     *buf = NULL;
    462     if (buffer->base() == NULL) {
    463         return OK;
    464     }
    465 
    466     // check if buffer is an image
    467     sp<ABuffer> imageData;
    468     if (!buffer->meta()->findBuffer("image-data", &imageData)) {
    469         return OK;
    470     }
    471 
    472     int64_t timestamp = 0;
    473     if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
    474         timestamp *= 1000; // adjust to ns
    475     }
    476 
    477     jobject byteBuffer = NULL;
    478     err = createByteBufferFromABuffer(
    479             env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
    480     if (err != OK) {
    481         return OK;
    482     }
    483 
    484     jobject infoBuffer = NULL;
    485     err = createByteBufferFromABuffer(
    486             env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
    487     if (err != OK) {
    488         env->DeleteLocalRef(byteBuffer);
    489         byteBuffer = NULL;
    490         return OK;
    491     }
    492 
    493     jobject cropRect = NULL;
    494     int32_t left, top, right, bottom;
    495     if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
    496         ScopedLocalRef<jclass> rectClazz(
    497                 env, env->FindClass("android/graphics/Rect"));
    498         CHECK(rectClazz.get() != NULL);
    499 
    500         jmethodID rectConstructID = env->GetMethodID(
    501                 rectClazz.get(), "<init>", "(IIII)V");
    502 
    503         cropRect = env->NewObject(
    504                 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
    505     }
    506 
    507     ScopedLocalRef<jclass> imageClazz(
    508             env, env->FindClass("android/media/MediaCodec$MediaImage"));
    509     CHECK(imageClazz.get() != NULL);
    510 
    511     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
    512             "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
    513 
    514     *buf = env->NewObject(imageClazz.get(), imageConstructID,
    515             byteBuffer, infoBuffer,
    516             (jboolean)!input /* readOnly */,
    517             (jlong)timestamp,
    518             (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
    519 
    520     // if MediaImage creation fails, return null
    521     if (env->ExceptionCheck()) {
    522         env->ExceptionDescribe();
    523         env->ExceptionClear();
    524         *buf = NULL;
    525     }
    526 
    527     if (cropRect != NULL) {
    528         env->DeleteLocalRef(cropRect);
    529         cropRect = NULL;
    530     }
    531 
    532     env->DeleteLocalRef(byteBuffer);
    533     byteBuffer = NULL;
    534 
    535     env->DeleteLocalRef(infoBuffer);
    536     infoBuffer = NULL;
    537 
    538     return OK;
    539 }
    540 
    541 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
    542     AString name;
    543 
    544     status_t err = mCodec->getName(&name);
    545 
    546     if (err != OK) {
    547         return err;
    548     }
    549 
    550     *nameStr = env->NewStringUTF(name.c_str());
    551 
    552     return OK;
    553 }
    554 
    555 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
    556     return mCodec->setParameters(msg);
    557 }
    558 
    559 void JMediaCodec::setVideoScalingMode(int mode) {
    560     if (mSurfaceTextureClient != NULL) {
    561         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
    562     }
    563 }
    564 
    565 static jthrowable createCodecException(
    566         JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
    567     ScopedLocalRef<jclass> clazz(
    568             env, env->FindClass("android/media/MediaCodec$CodecException"));
    569     CHECK(clazz.get() != NULL);
    570 
    571     const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
    572     CHECK(ctor != NULL);
    573 
    574     ScopedLocalRef<jstring> msgObj(
    575             env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
    576 
    577     // translate action code to Java equivalent
    578     switch (actionCode) {
    579     case ACTION_CODE_TRANSIENT:
    580         actionCode = gCodecActionCodes.codecActionTransient;
    581         break;
    582     case ACTION_CODE_RECOVERABLE:
    583         actionCode = gCodecActionCodes.codecActionRecoverable;
    584         break;
    585     default:
    586         actionCode = 0;  // everything else is fatal
    587         break;
    588     }
    589 
    590     return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
    591 }
    592 
    593 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
    594     int32_t arg1, arg2 = 0;
    595     jobject obj = NULL;
    596     CHECK(msg->findInt32("callbackID", &arg1));
    597     JNIEnv *env = AndroidRuntime::getJNIEnv();
    598 
    599     switch (arg1) {
    600         case MediaCodec::CB_INPUT_AVAILABLE:
    601         {
    602             CHECK(msg->findInt32("index", &arg2));
    603             break;
    604         }
    605 
    606         case MediaCodec::CB_OUTPUT_AVAILABLE:
    607         {
    608             CHECK(msg->findInt32("index", &arg2));
    609 
    610             size_t size, offset;
    611             int64_t timeUs;
    612             uint32_t flags;
    613             CHECK(msg->findSize("size", &size));
    614             CHECK(msg->findSize("offset", &offset));
    615             CHECK(msg->findInt64("timeUs", &timeUs));
    616             CHECK(msg->findInt32("flags", (int32_t *)&flags));
    617 
    618             ScopedLocalRef<jclass> clazz(
    619                     env, env->FindClass("android/media/MediaCodec$BufferInfo"));
    620             jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
    621             jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
    622 
    623             obj = env->NewObject(clazz.get(), ctor);
    624 
    625             if (obj == NULL) {
    626                 if (env->ExceptionCheck()) {
    627                     ALOGE("Could not create MediaCodec.BufferInfo.");
    628                     env->ExceptionClear();
    629                 }
    630                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    631                 return;
    632             }
    633 
    634             env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
    635             break;
    636         }
    637 
    638         case MediaCodec::CB_ERROR:
    639         {
    640             int32_t err, actionCode;
    641             CHECK(msg->findInt32("err", &err));
    642             CHECK(msg->findInt32("actionCode", &actionCode));
    643 
    644             // note that DRM errors could conceivably alias into a CodecException
    645             obj = (jobject)createCodecException(env, err, actionCode);
    646 
    647             if (obj == NULL) {
    648                 if (env->ExceptionCheck()) {
    649                     ALOGE("Could not create CodecException object.");
    650                     env->ExceptionClear();
    651                 }
    652                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    653                 return;
    654             }
    655 
    656             break;
    657         }
    658 
    659         case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
    660         {
    661             sp<AMessage> format;
    662             CHECK(msg->findMessage("format", &format));
    663 
    664             if (OK != ConvertMessageToMap(env, format, &obj)) {
    665                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
    666                 return;
    667             }
    668 
    669             break;
    670         }
    671 
    672         default:
    673             TRESPASS();
    674     }
    675 
    676     env->CallVoidMethod(
    677             mObject,
    678             gFields.postEventFromNativeID,
    679             EVENT_CALLBACK,
    680             arg1,
    681             arg2,
    682             obj);
    683 
    684     env->DeleteLocalRef(obj);
    685 }
    686 
    687 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    688     switch (msg->what()) {
    689         case kWhatCallbackNotify:
    690         {
    691             handleCallback(msg);
    692             break;
    693         }
    694         default:
    695             TRESPASS();
    696     }
    697 }
    698 
    699 }  // namespace android
    700 
    701 ////////////////////////////////////////////////////////////////////////////////
    702 
    703 using namespace android;
    704 
    705 static sp<JMediaCodec> setMediaCodec(
    706         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
    707     sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
    708     if (codec != NULL) {
    709         codec->incStrong(thiz);
    710     }
    711     if (old != NULL) {
    712         /* release MediaCodec and stop the looper now before decStrong.
    713          * otherwise JMediaCodec::~JMediaCodec() could be called from within
    714          * its message handler, doing release() from there will deadlock
    715          * (as MediaCodec::release() post synchronous message to the same looper)
    716          */
    717         old->release();
    718         old->decStrong(thiz);
    719     }
    720     env->SetLongField(thiz, gFields.context, (jlong)codec.get());
    721 
    722     return old;
    723 }
    724 
    725 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
    726     return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
    727 }
    728 
    729 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
    730     setMediaCodec(env, thiz, NULL);
    731 }
    732 
    733 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
    734     jthrowable exception = createCodecException(env, err, actionCode, msg);
    735     env->Throw(exception);
    736 }
    737 
    738 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
    739     ScopedLocalRef<jclass> clazz(
    740             env, env->FindClass("android/media/MediaCodec$CryptoException"));
    741     CHECK(clazz.get() != NULL);
    742 
    743     jmethodID constructID =
    744         env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
    745     CHECK(constructID != NULL);
    746 
    747     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
    748 
    749     /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
    750     switch (err) {
    751         case ERROR_DRM_NO_LICENSE:
    752             err = gCryptoErrorCodes.cryptoErrorNoKey;
    753             break;
    754         case ERROR_DRM_LICENSE_EXPIRED:
    755             err = gCryptoErrorCodes.cryptoErrorKeyExpired;
    756             break;
    757         case ERROR_DRM_RESOURCE_BUSY:
    758             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
    759             break;
    760         case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
    761             err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
    762             break;
    763         default:  /* Other negative DRM error codes go out as is. */
    764             break;
    765     }
    766 
    767     jthrowable exception =
    768         (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
    769 
    770     env->Throw(exception);
    771 }
    772 
    773 static jint throwExceptionAsNecessary(
    774         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
    775         const char *msg = NULL) {
    776     switch (err) {
    777         case OK:
    778             return 0;
    779 
    780         case -EAGAIN:
    781             return DEQUEUE_INFO_TRY_AGAIN_LATER;
    782 
    783         case INFO_FORMAT_CHANGED:
    784             return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
    785 
    786         case INFO_OUTPUT_BUFFERS_CHANGED:
    787             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
    788 
    789         case INVALID_OPERATION:
    790             jniThrowException(env, "java/lang/IllegalStateException", msg);
    791             return 0;
    792 
    793         default:
    794             if (isCryptoError(err)) {
    795                 throwCryptoException(env, err, msg);
    796                 return 0;
    797             }
    798             throwCodecException(env, err, actionCode, msg);
    799             return 0;
    800     }
    801 }
    802 
    803 static void android_media_MediaCodec_native_setCallback(
    804         JNIEnv *env,
    805         jobject thiz,
    806         jobject cb) {
    807     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    808 
    809     if (codec == NULL) {
    810         throwExceptionAsNecessary(env, INVALID_OPERATION);
    811         return;
    812     }
    813 
    814     status_t err = codec->setCallback(cb);
    815 
    816     throwExceptionAsNecessary(env, err);
    817 }
    818 
    819 static void android_media_MediaCodec_native_configure(
    820         JNIEnv *env,
    821         jobject thiz,
    822         jobjectArray keys, jobjectArray values,
    823         jobject jsurface,
    824         jobject jcrypto,
    825         jint flags) {
    826     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    827 
    828     if (codec == NULL) {
    829         throwExceptionAsNecessary(env, INVALID_OPERATION);
    830         return;
    831     }
    832 
    833     sp<AMessage> format;
    834     status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
    835 
    836     if (err != OK) {
    837         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    838         return;
    839     }
    840 
    841     sp<IGraphicBufferProducer> bufferProducer;
    842     if (jsurface != NULL) {
    843         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
    844         if (surface != NULL) {
    845             bufferProducer = surface->getIGraphicBufferProducer();
    846         } else {
    847             jniThrowException(
    848                     env,
    849                     "java/lang/IllegalArgumentException",
    850                     "The surface has been released");
    851             return;
    852         }
    853     }
    854 
    855     sp<ICrypto> crypto;
    856     if (jcrypto != NULL) {
    857         crypto = JCrypto::GetCrypto(env, jcrypto);
    858     }
    859 
    860     err = codec->configure(format, bufferProducer, crypto, flags);
    861 
    862     throwExceptionAsNecessary(env, err);
    863 }
    864 
    865 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
    866         jobject thiz) {
    867     ALOGV("android_media_MediaCodec_createInputSurface");
    868 
    869     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    870     if (codec == NULL) {
    871         throwExceptionAsNecessary(env, INVALID_OPERATION);
    872         return NULL;
    873     }
    874 
    875     // Tell the MediaCodec that we want to use a Surface as input.
    876     sp<IGraphicBufferProducer> bufferProducer;
    877     status_t err = codec->createInputSurface(&bufferProducer);
    878     if (err != NO_ERROR) {
    879         throwExceptionAsNecessary(env, err);
    880         return NULL;
    881     }
    882 
    883     // Wrap the IGBP in a Java-language Surface.
    884     return android_view_Surface_createFromIGraphicBufferProducer(env,
    885             bufferProducer);
    886 }
    887 
    888 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
    889     ALOGV("android_media_MediaCodec_start");
    890 
    891     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    892 
    893     if (codec == NULL) {
    894         throwExceptionAsNecessary(env, INVALID_OPERATION);
    895         return;
    896     }
    897 
    898     status_t err = codec->start();
    899 
    900     throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
    901 }
    902 
    903 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
    904     ALOGV("android_media_MediaCodec_stop");
    905 
    906     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    907 
    908     if (codec == NULL) {
    909         throwExceptionAsNecessary(env, INVALID_OPERATION);
    910         return;
    911     }
    912 
    913     status_t err = codec->stop();
    914 
    915     throwExceptionAsNecessary(env, err);
    916 }
    917 
    918 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
    919     ALOGV("android_media_MediaCodec_reset");
    920 
    921     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    922 
    923     if (codec == NULL) {
    924         throwExceptionAsNecessary(env, INVALID_OPERATION);
    925         return;
    926     }
    927 
    928     status_t err = codec->reset();
    929     if (err != OK) {
    930         // treat all errors as fatal for now, though resource not available
    931         // errors could be treated as transient.
    932         // we also should avoid sending INVALID_OPERATION here due to
    933         // the transitory nature of reset(), it should not inadvertently
    934         // trigger an IllegalStateException.
    935         err = UNKNOWN_ERROR;
    936     }
    937     throwExceptionAsNecessary(env, err);
    938 }
    939 
    940 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
    941     ALOGV("android_media_MediaCodec_flush");
    942 
    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->flush();
    951 
    952     throwExceptionAsNecessary(env, err);
    953 }
    954 
    955 static void android_media_MediaCodec_queueInputBuffer(
    956         JNIEnv *env,
    957         jobject thiz,
    958         jint index,
    959         jint offset,
    960         jint size,
    961         jlong timestampUs,
    962         jint flags) {
    963     ALOGV("android_media_MediaCodec_queueInputBuffer");
    964 
    965     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    966 
    967     if (codec == NULL) {
    968         throwExceptionAsNecessary(env, INVALID_OPERATION);
    969         return;
    970     }
    971 
    972     AString errorDetailMsg;
    973 
    974     status_t err = codec->queueInputBuffer(
    975             index, offset, size, timestampUs, flags, &errorDetailMsg);
    976 
    977     throwExceptionAsNecessary(
    978             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
    979 }
    980 
    981 static void android_media_MediaCodec_queueSecureInputBuffer(
    982         JNIEnv *env,
    983         jobject thiz,
    984         jint index,
    985         jint offset,
    986         jobject cryptoInfoObj,
    987         jlong timestampUs,
    988         jint flags) {
    989     ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
    990 
    991     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
    992 
    993     if (codec == NULL) {
    994         throwExceptionAsNecessary(env, INVALID_OPERATION);
    995         return;
    996     }
    997 
    998     jint numSubSamples =
    999         env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
   1000 
   1001     jintArray numBytesOfClearDataObj =
   1002         (jintArray)env->GetObjectField(
   1003                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
   1004 
   1005     jintArray numBytesOfEncryptedDataObj =
   1006         (jintArray)env->GetObjectField(
   1007                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
   1008 
   1009     jbyteArray keyObj =
   1010         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
   1011 
   1012     jbyteArray ivObj =
   1013         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
   1014 
   1015     jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
   1016 
   1017     status_t err = OK;
   1018 
   1019     CryptoPlugin::SubSample *subSamples = NULL;
   1020     jbyte *key = NULL;
   1021     jbyte *iv = NULL;
   1022 
   1023     if (numSubSamples <= 0) {
   1024         err = -EINVAL;
   1025     } else if (numBytesOfClearDataObj == NULL
   1026             && numBytesOfEncryptedDataObj == NULL) {
   1027         err = -EINVAL;
   1028     } else if (numBytesOfEncryptedDataObj != NULL
   1029             && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
   1030         err = -ERANGE;
   1031     } else if (numBytesOfClearDataObj != NULL
   1032             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
   1033         err = -ERANGE;
   1034     // subSamples array may silently overflow if number of samples are too large.  Use
   1035     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
   1036     } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
   1037         err = -EINVAL;
   1038     } else {
   1039         jboolean isCopy;
   1040 
   1041         jint *numBytesOfClearData =
   1042             (numBytesOfClearDataObj == NULL)
   1043                 ? NULL
   1044                 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
   1045 
   1046         jint *numBytesOfEncryptedData =
   1047             (numBytesOfEncryptedDataObj == NULL)
   1048                 ? NULL
   1049                 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
   1050 
   1051         subSamples = new CryptoPlugin::SubSample[numSubSamples];
   1052 
   1053         for (jint i = 0; i < numSubSamples; ++i) {
   1054             subSamples[i].mNumBytesOfClearData =
   1055                 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
   1056 
   1057             subSamples[i].mNumBytesOfEncryptedData =
   1058                 (numBytesOfEncryptedData == NULL)
   1059                     ? 0 : numBytesOfEncryptedData[i];
   1060         }
   1061 
   1062         if (numBytesOfEncryptedData != NULL) {
   1063             env->ReleaseIntArrayElements(
   1064                     numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
   1065             numBytesOfEncryptedData = NULL;
   1066         }
   1067 
   1068         if (numBytesOfClearData != NULL) {
   1069             env->ReleaseIntArrayElements(
   1070                     numBytesOfClearDataObj, numBytesOfClearData, 0);
   1071             numBytesOfClearData = NULL;
   1072         }
   1073     }
   1074 
   1075     if (err == OK && keyObj != NULL) {
   1076         if (env->GetArrayLength(keyObj) != 16) {
   1077             err = -EINVAL;
   1078         } else {
   1079             jboolean isCopy;
   1080             key = env->GetByteArrayElements(keyObj, &isCopy);
   1081         }
   1082     }
   1083 
   1084     if (err == OK && ivObj != NULL) {
   1085         if (env->GetArrayLength(ivObj) != 16) {
   1086             err = -EINVAL;
   1087         } else {
   1088             jboolean isCopy;
   1089             iv = env->GetByteArrayElements(ivObj, &isCopy);
   1090         }
   1091     }
   1092 
   1093     AString errorDetailMsg;
   1094 
   1095     if (err == OK) {
   1096         err = codec->queueSecureInputBuffer(
   1097                 index, offset,
   1098                 subSamples, numSubSamples,
   1099                 (const uint8_t *)key, (const uint8_t *)iv,
   1100                 (CryptoPlugin::Mode)mode,
   1101                 timestampUs,
   1102                 flags,
   1103                 &errorDetailMsg);
   1104     }
   1105 
   1106     if (iv != NULL) {
   1107         env->ReleaseByteArrayElements(ivObj, iv, 0);
   1108         iv = NULL;
   1109     }
   1110 
   1111     if (key != NULL) {
   1112         env->ReleaseByteArrayElements(keyObj, key, 0);
   1113         key = NULL;
   1114     }
   1115 
   1116     delete[] subSamples;
   1117     subSamples = NULL;
   1118 
   1119     throwExceptionAsNecessary(
   1120             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
   1121 }
   1122 
   1123 static jint android_media_MediaCodec_dequeueInputBuffer(
   1124         JNIEnv *env, jobject thiz, jlong timeoutUs) {
   1125     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
   1126 
   1127     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1128 
   1129     if (codec == NULL) {
   1130         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1131         return -1;
   1132     }
   1133 
   1134     size_t index;
   1135     status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
   1136 
   1137     if (err == OK) {
   1138         return (jint) index;
   1139     }
   1140 
   1141     return throwExceptionAsNecessary(env, err);
   1142 }
   1143 
   1144 static jint android_media_MediaCodec_dequeueOutputBuffer(
   1145         JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
   1146     ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
   1147 
   1148     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1149 
   1150     if (codec == NULL) {
   1151         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1152         return 0;
   1153     }
   1154 
   1155     size_t index;
   1156     status_t err = codec->dequeueOutputBuffer(
   1157             env, bufferInfo, &index, timeoutUs);
   1158 
   1159     if (err == OK) {
   1160         return (jint) index;
   1161     }
   1162 
   1163     return throwExceptionAsNecessary(env, err);
   1164 }
   1165 
   1166 static void android_media_MediaCodec_releaseOutputBuffer(
   1167         JNIEnv *env, jobject thiz,
   1168         jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
   1169     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
   1170 
   1171     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1172 
   1173     if (codec == NULL) {
   1174         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1175         return;
   1176     }
   1177 
   1178     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
   1179 
   1180     throwExceptionAsNecessary(env, err);
   1181 }
   1182 
   1183 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
   1184         jobject thiz) {
   1185     ALOGV("android_media_MediaCodec_signalEndOfInputStream");
   1186 
   1187     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1188     if (codec == NULL) {
   1189         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1190         return;
   1191     }
   1192 
   1193     status_t err = codec->signalEndOfInputStream();
   1194 
   1195     throwExceptionAsNecessary(env, err);
   1196 }
   1197 
   1198 static jobject android_media_MediaCodec_getFormatNative(
   1199         JNIEnv *env, jobject thiz, jboolean input) {
   1200     ALOGV("android_media_MediaCodec_getFormatNative");
   1201 
   1202     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1203 
   1204     if (codec == NULL) {
   1205         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1206         return NULL;
   1207     }
   1208 
   1209     jobject format;
   1210     status_t err = codec->getFormat(env, input, &format);
   1211 
   1212     if (err == OK) {
   1213         return format;
   1214     }
   1215 
   1216     throwExceptionAsNecessary(env, err);
   1217 
   1218     return NULL;
   1219 }
   1220 
   1221 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
   1222         JNIEnv *env, jobject thiz, jint index) {
   1223     ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
   1224 
   1225     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1226 
   1227     if (codec == NULL) {
   1228         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1229         return NULL;
   1230     }
   1231 
   1232     jobject format;
   1233     status_t err = codec->getOutputFormat(env, index, &format);
   1234 
   1235     if (err == OK) {
   1236         return format;
   1237     }
   1238 
   1239     throwExceptionAsNecessary(env, err);
   1240 
   1241     return NULL;
   1242 }
   1243 
   1244 static jobjectArray android_media_MediaCodec_getBuffers(
   1245         JNIEnv *env, jobject thiz, jboolean input) {
   1246     ALOGV("android_media_MediaCodec_getBuffers");
   1247 
   1248     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1249 
   1250     if (codec == NULL) {
   1251         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1252         return NULL;
   1253     }
   1254 
   1255     jobjectArray buffers;
   1256     status_t err = codec->getBuffers(env, input, &buffers);
   1257 
   1258     if (err == OK) {
   1259         return buffers;
   1260     }
   1261 
   1262     // if we're out of memory, an exception was already thrown
   1263     if (err != NO_MEMORY) {
   1264         throwExceptionAsNecessary(env, err);
   1265     }
   1266 
   1267     return NULL;
   1268 }
   1269 
   1270 static jobject android_media_MediaCodec_getBuffer(
   1271         JNIEnv *env, jobject thiz, jboolean input, jint index) {
   1272     ALOGV("android_media_MediaCodec_getBuffer");
   1273 
   1274     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1275 
   1276     if (codec == NULL) {
   1277         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1278         return NULL;
   1279     }
   1280 
   1281     jobject buffer;
   1282     status_t err = codec->getBuffer(env, input, index, &buffer);
   1283 
   1284     if (err == OK) {
   1285         return buffer;
   1286     }
   1287 
   1288     // if we're out of memory, an exception was already thrown
   1289     if (err != NO_MEMORY) {
   1290         throwExceptionAsNecessary(env, err);
   1291     }
   1292 
   1293     return NULL;
   1294 }
   1295 
   1296 static jobject android_media_MediaCodec_getImage(
   1297         JNIEnv *env, jobject thiz, jboolean input, jint index) {
   1298     ALOGV("android_media_MediaCodec_getImage");
   1299 
   1300     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1301 
   1302     if (codec == NULL) {
   1303         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1304         return NULL;
   1305     }
   1306 
   1307     jobject image;
   1308     status_t err = codec->getImage(env, input, index, &image);
   1309 
   1310     if (err == OK) {
   1311         return image;
   1312     }
   1313 
   1314     // if we're out of memory, an exception was already thrown
   1315     if (err != NO_MEMORY) {
   1316         throwExceptionAsNecessary(env, err);
   1317     }
   1318 
   1319     return NULL;
   1320 }
   1321 
   1322 static jobject android_media_MediaCodec_getName(
   1323         JNIEnv *env, jobject thiz) {
   1324     ALOGV("android_media_MediaCodec_getName");
   1325 
   1326     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1327 
   1328     if (codec == NULL) {
   1329         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1330         return NULL;
   1331     }
   1332 
   1333     jstring name;
   1334     status_t err = codec->getName(env, &name);
   1335 
   1336     if (err == OK) {
   1337         return name;
   1338     }
   1339 
   1340     throwExceptionAsNecessary(env, err);
   1341 
   1342     return NULL;
   1343 }
   1344 
   1345 static void android_media_MediaCodec_setParameters(
   1346         JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
   1347     ALOGV("android_media_MediaCodec_setParameters");
   1348 
   1349     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1350 
   1351     if (codec == NULL) {
   1352         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1353         return;
   1354     }
   1355 
   1356     sp<AMessage> params;
   1357     status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
   1358 
   1359     if (err == OK) {
   1360         err = codec->setParameters(params);
   1361     }
   1362 
   1363     throwExceptionAsNecessary(env, err);
   1364 }
   1365 
   1366 static void android_media_MediaCodec_setVideoScalingMode(
   1367         JNIEnv *env, jobject thiz, jint mode) {
   1368     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
   1369 
   1370     if (codec == NULL) {
   1371         throwExceptionAsNecessary(env, INVALID_OPERATION);
   1372         return;
   1373     }
   1374 
   1375     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
   1376             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
   1377         jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
   1378         return;
   1379     }
   1380 
   1381     codec->setVideoScalingMode(mode);
   1382 }
   1383 
   1384 static void android_media_MediaCodec_native_init(JNIEnv *env) {
   1385     ScopedLocalRef<jclass> clazz(
   1386             env, env->FindClass("android/media/MediaCodec"));
   1387     CHECK(clazz.get() != NULL);
   1388 
   1389     gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
   1390     CHECK(gFields.context != NULL);
   1391 
   1392     gFields.postEventFromNativeID =
   1393         env->GetMethodID(
   1394                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
   1395 
   1396     CHECK(gFields.postEventFromNativeID != NULL);
   1397 
   1398     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
   1399     CHECK(clazz.get() != NULL);
   1400 
   1401     gFields.cryptoInfoNumSubSamplesID =
   1402         env->GetFieldID(clazz.get(), "numSubSamples", "I");
   1403     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
   1404 
   1405     gFields.cryptoInfoNumBytesOfClearDataID =
   1406         env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
   1407     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
   1408 
   1409     gFields.cryptoInfoNumBytesOfEncryptedDataID =
   1410         env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
   1411     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
   1412 
   1413     gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
   1414     CHECK(gFields.cryptoInfoKeyID != NULL);
   1415 
   1416     gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
   1417     CHECK(gFields.cryptoInfoIVID != NULL);
   1418 
   1419     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
   1420     CHECK(gFields.cryptoInfoModeID != NULL);
   1421 
   1422     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
   1423     CHECK(clazz.get() != NULL);
   1424 
   1425     jfieldID field;
   1426     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
   1427     CHECK(field != NULL);
   1428     gCryptoErrorCodes.cryptoErrorNoKey =
   1429         env->GetStaticIntField(clazz.get(), field);
   1430 
   1431     field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
   1432     CHECK(field != NULL);
   1433     gCryptoErrorCodes.cryptoErrorKeyExpired =
   1434         env->GetStaticIntField(clazz.get(), field);
   1435 
   1436     field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
   1437     CHECK(field != NULL);
   1438     gCryptoErrorCodes.cryptoErrorResourceBusy =
   1439         env->GetStaticIntField(clazz.get(), field);
   1440 
   1441     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
   1442     CHECK(field != NULL);
   1443     gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
   1444         env->GetStaticIntField(clazz.get(), field);
   1445 
   1446     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
   1447     CHECK(clazz.get() != NULL);
   1448     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
   1449     CHECK(field != NULL);
   1450     gCodecActionCodes.codecActionTransient =
   1451         env->GetStaticIntField(clazz.get(), field);
   1452 
   1453     field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
   1454     CHECK(field != NULL);
   1455     gCodecActionCodes.codecActionRecoverable =
   1456         env->GetStaticIntField(clazz.get(), field);
   1457 }
   1458 
   1459 static void android_media_MediaCodec_native_setup(
   1460         JNIEnv *env, jobject thiz,
   1461         jstring name, jboolean nameIsType, jboolean encoder) {
   1462     if (name == NULL) {
   1463         jniThrowException(env, "java/lang/NullPointerException", NULL);
   1464         return;
   1465     }
   1466 
   1467     const char *tmp = env->GetStringUTFChars(name, NULL);
   1468 
   1469     if (tmp == NULL) {
   1470         return;
   1471     }
   1472 
   1473     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
   1474 
   1475     const status_t err = codec->initCheck();
   1476     if (err == NAME_NOT_FOUND) {
   1477         // fail and do not try again.
   1478         jniThrowException(env, "java/lang/IllegalArgumentException",
   1479                 String8::format("Failed to initialize %s, error %#x", tmp, err));
   1480         env->ReleaseStringUTFChars(name, tmp);
   1481         return;
   1482     } else if (err != OK) {
   1483         // believed possible to try again
   1484         jniThrowException(env, "java/io/IOException",
   1485                 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
   1486         env->ReleaseStringUTFChars(name, tmp);
   1487         return;
   1488     }
   1489 
   1490     env->ReleaseStringUTFChars(name, tmp);
   1491 
   1492     codec->registerSelf();
   1493 
   1494     setMediaCodec(env,thiz, codec);
   1495 }
   1496 
   1497 static void android_media_MediaCodec_native_finalize(
   1498         JNIEnv *env, jobject thiz) {
   1499     android_media_MediaCodec_release(env, thiz);
   1500 }
   1501 
   1502 static JNINativeMethod gMethods[] = {
   1503     { "native_release", "()V", (void *)android_media_MediaCodec_release },
   1504 
   1505     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
   1506 
   1507     { "native_setCallback",
   1508       "(Landroid/media/MediaCodec$Callback;)V",
   1509       (void *)android_media_MediaCodec_native_setCallback },
   1510 
   1511     { "native_configure",
   1512       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
   1513       "Landroid/media/MediaCrypto;I)V",
   1514       (void *)android_media_MediaCodec_native_configure },
   1515 
   1516     { "createInputSurface", "()Landroid/view/Surface;",
   1517       (void *)android_media_MediaCodec_createInputSurface },
   1518 
   1519     { "native_start", "()V", (void *)android_media_MediaCodec_start },
   1520     { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
   1521     { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
   1522 
   1523     { "native_queueInputBuffer", "(IIIJI)V",
   1524       (void *)android_media_MediaCodec_queueInputBuffer },
   1525 
   1526     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
   1527       (void *)android_media_MediaCodec_queueSecureInputBuffer },
   1528 
   1529     { "native_dequeueInputBuffer", "(J)I",
   1530       (void *)android_media_MediaCodec_dequeueInputBuffer },
   1531 
   1532     { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
   1533       (void *)android_media_MediaCodec_dequeueOutputBuffer },
   1534 
   1535     { "releaseOutputBuffer", "(IZZJ)V",
   1536       (void *)android_media_MediaCodec_releaseOutputBuffer },
   1537 
   1538     { "signalEndOfInputStream", "()V",
   1539       (void *)android_media_MediaCodec_signalEndOfInputStream },
   1540 
   1541     { "getFormatNative", "(Z)Ljava/util/Map;",
   1542       (void *)android_media_MediaCodec_getFormatNative },
   1543 
   1544     { "getOutputFormatNative", "(I)Ljava/util/Map;",
   1545       (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
   1546 
   1547     { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
   1548       (void *)android_media_MediaCodec_getBuffers },
   1549 
   1550     { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
   1551       (void *)android_media_MediaCodec_getBuffer },
   1552 
   1553     { "getImage", "(ZI)Landroid/media/Image;",
   1554       (void *)android_media_MediaCodec_getImage },
   1555 
   1556     { "getName", "()Ljava/lang/String;",
   1557       (void *)android_media_MediaCodec_getName },
   1558 
   1559     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
   1560       (void *)android_media_MediaCodec_setParameters },
   1561 
   1562     { "setVideoScalingMode", "(I)V",
   1563       (void *)android_media_MediaCodec_setVideoScalingMode },
   1564 
   1565     { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
   1566 
   1567     { "native_setup", "(Ljava/lang/String;ZZ)V",
   1568       (void *)android_media_MediaCodec_native_setup },
   1569 
   1570     { "native_finalize", "()V",
   1571       (void *)android_media_MediaCodec_native_finalize },
   1572 };
   1573 
   1574 int register_android_media_MediaCodec(JNIEnv *env) {
   1575     return AndroidRuntime::registerNativeMethods(env,
   1576                 "android/media/MediaCodec", gMethods, NELEM(gMethods));
   1577 }
   1578