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