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