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