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