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