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