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