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