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 <gui/Surface.h>
31#include <gui/SurfaceTextureClient.h>
32
33#include <media/ICrypto.h>
34#include <media/stagefright/MediaCodec.h>
35#include <media/stagefright/foundation/ABuffer.h>
36#include <media/stagefright/foundation/ADebug.h>
37#include <media/stagefright/foundation/ALooper.h>
38#include <media/stagefright/foundation/AMessage.h>
39#include <media/stagefright/foundation/AString.h>
40#include <media/stagefright/MediaErrors.h>
41
42#include <system/window.h>
43
44namespace android {
45
46// Keep these in sync with their equivalents in MediaCodec.java !!!
47enum {
48    DEQUEUE_INFO_TRY_AGAIN_LATER            = -1,
49    DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED      = -2,
50    DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
51};
52
53struct fields_t {
54    jfieldID context;
55
56    jfieldID cryptoInfoNumSubSamplesID;
57    jfieldID cryptoInfoNumBytesOfClearDataID;
58    jfieldID cryptoInfoNumBytesOfEncryptedDataID;
59    jfieldID cryptoInfoKeyID;
60    jfieldID cryptoInfoIVID;
61    jfieldID cryptoInfoModeID;
62};
63
64static fields_t gFields;
65
66////////////////////////////////////////////////////////////////////////////////
67
68JMediaCodec::JMediaCodec(
69        JNIEnv *env, jobject thiz,
70        const char *name, bool nameIsType, bool encoder)
71    : mClass(NULL),
72      mObject(NULL) {
73    jclass clazz = env->GetObjectClass(thiz);
74    CHECK(clazz != NULL);
75
76    mClass = (jclass)env->NewGlobalRef(clazz);
77    mObject = env->NewWeakGlobalRef(thiz);
78
79    mLooper = new ALooper;
80    mLooper->setName("MediaCodec_looper");
81
82    mLooper->start(
83            false,      // runOnCallingThread
84            false,       // canCallJava
85            PRIORITY_DEFAULT);
86
87    if (nameIsType) {
88        mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
89    } else {
90        mCodec = MediaCodec::CreateByComponentName(mLooper, name);
91    }
92}
93
94status_t JMediaCodec::initCheck() const {
95    return mCodec != NULL ? OK : NO_INIT;
96}
97
98JMediaCodec::~JMediaCodec() {
99    mCodec->release();
100
101    JNIEnv *env = AndroidRuntime::getJNIEnv();
102
103    env->DeleteWeakGlobalRef(mObject);
104    mObject = NULL;
105    env->DeleteGlobalRef(mClass);
106    mClass = NULL;
107}
108
109status_t JMediaCodec::configure(
110        const sp<AMessage> &format,
111        const sp<ISurfaceTexture> &surfaceTexture,
112        const sp<ICrypto> &crypto,
113        int flags) {
114    sp<SurfaceTextureClient> client;
115    if (surfaceTexture != NULL) {
116        mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
117    } else {
118        mSurfaceTextureClient.clear();
119    }
120
121    return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
122}
123
124status_t JMediaCodec::start() {
125    return mCodec->start();
126}
127
128status_t JMediaCodec::stop() {
129    mSurfaceTextureClient.clear();
130
131    return mCodec->stop();
132}
133
134status_t JMediaCodec::flush() {
135    return mCodec->flush();
136}
137
138status_t JMediaCodec::queueInputBuffer(
139        size_t index,
140        size_t offset, size_t size, int64_t timeUs, uint32_t flags,
141        AString *errorDetailMsg) {
142    return mCodec->queueInputBuffer(
143            index, offset, size, timeUs, flags, errorDetailMsg);
144}
145
146status_t JMediaCodec::queueSecureInputBuffer(
147        size_t index,
148        size_t offset,
149        const CryptoPlugin::SubSample *subSamples,
150        size_t numSubSamples,
151        const uint8_t key[16],
152        const uint8_t iv[16],
153        CryptoPlugin::Mode mode,
154        int64_t presentationTimeUs,
155        uint32_t flags,
156        AString *errorDetailMsg) {
157    return mCodec->queueSecureInputBuffer(
158            index, offset, subSamples, numSubSamples, key, iv, mode,
159            presentationTimeUs, flags, errorDetailMsg);
160}
161
162status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
163    return mCodec->dequeueInputBuffer(index, timeoutUs);
164}
165
166status_t JMediaCodec::dequeueOutputBuffer(
167        JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
168    size_t size, offset;
169    int64_t timeUs;
170    uint32_t flags;
171    status_t err;
172    if ((err = mCodec->dequeueOutputBuffer(
173                    index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) {
174        return err;
175    }
176
177    jclass clazz = env->FindClass("android/media/MediaCodec$BufferInfo");
178
179    jmethodID method = env->GetMethodID(clazz, "set", "(IIJI)V");
180    env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags);
181
182    return OK;
183}
184
185status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
186    return render
187        ? mCodec->renderOutputBufferAndRelease(index)
188        : mCodec->releaseOutputBuffer(index);
189}
190
191status_t JMediaCodec::getOutputFormat(JNIEnv *env, jobject *format) const {
192    sp<AMessage> msg;
193    status_t err;
194    if ((err = mCodec->getOutputFormat(&msg)) != OK) {
195        return err;
196    }
197
198    return ConvertMessageToMap(env, msg, format);
199}
200
201status_t JMediaCodec::getBuffers(
202        JNIEnv *env, bool input, jobjectArray *bufArray) const {
203    Vector<sp<ABuffer> > buffers;
204
205    status_t err =
206        input
207            ? mCodec->getInputBuffers(&buffers)
208            : mCodec->getOutputBuffers(&buffers);
209
210    if (err != OK) {
211        return err;
212    }
213
214    jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer");
215    CHECK(byteBufferClass != NULL);
216
217    jmethodID orderID = env->GetMethodID(
218            byteBufferClass,
219            "order",
220            "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
221
222    CHECK(orderID != NULL);
223
224    jclass byteOrderClass = env->FindClass("java/nio/ByteOrder");
225    CHECK(byteOrderClass != NULL);
226
227    jmethodID nativeOrderID = env->GetStaticMethodID(
228            byteOrderClass, "nativeOrder", "()Ljava/nio/ByteOrder;");
229    CHECK(nativeOrderID != NULL);
230
231    jobject nativeByteOrderObj =
232        env->CallStaticObjectMethod(byteOrderClass, nativeOrderID);
233    CHECK(nativeByteOrderObj != NULL);
234
235    *bufArray = (jobjectArray)env->NewObjectArray(
236            buffers.size(), byteBufferClass, NULL);
237
238    for (size_t i = 0; i < buffers.size(); ++i) {
239        const sp<ABuffer> &buffer = buffers.itemAt(i);
240
241        jobject byteBuffer =
242            env->NewDirectByteBuffer(
243                buffer->base(),
244                buffer->capacity());
245
246        jobject me = env->CallObjectMethod(
247                byteBuffer, orderID, nativeByteOrderObj);
248        env->DeleteLocalRef(me);
249        me = NULL;
250
251        env->SetObjectArrayElement(
252                *bufArray, i, byteBuffer);
253
254        env->DeleteLocalRef(byteBuffer);
255        byteBuffer = NULL;
256    }
257
258    env->DeleteLocalRef(nativeByteOrderObj);
259    nativeByteOrderObj = NULL;
260
261    return OK;
262}
263
264void JMediaCodec::setVideoScalingMode(int mode) {
265    if (mSurfaceTextureClient != NULL) {
266        native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
267    }
268}
269
270}  // namespace android
271
272////////////////////////////////////////////////////////////////////////////////
273
274using namespace android;
275
276static sp<JMediaCodec> setMediaCodec(
277        JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
278    sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context);
279    if (codec != NULL) {
280        codec->incStrong(thiz);
281    }
282    if (old != NULL) {
283        old->decStrong(thiz);
284    }
285    env->SetIntField(thiz, gFields.context, (int)codec.get());
286
287    return old;
288}
289
290static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
291    return (JMediaCodec *)env->GetIntField(thiz, gFields.context);
292}
293
294static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
295    setMediaCodec(env, thiz, NULL);
296}
297
298static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
299    jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
300    CHECK(clazz != NULL);
301
302    jmethodID constructID =
303        env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
304    CHECK(constructID != NULL);
305
306    jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
307
308    jthrowable exception =
309        (jthrowable)env->NewObject(clazz, constructID, err, msgObj);
310
311    env->Throw(exception);
312}
313
314static jint throwExceptionAsNecessary(
315        JNIEnv *env, status_t err, const char *msg = NULL) {
316    if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
317        // We'll throw our custom MediaCodec.CryptoException
318
319        throwCryptoException(env, err, msg);
320        return 0;
321    }
322
323    switch (err) {
324        case OK:
325            return 0;
326
327        case -EAGAIN:
328            return DEQUEUE_INFO_TRY_AGAIN_LATER;
329
330        case INFO_FORMAT_CHANGED:
331            return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
332
333        case INFO_OUTPUT_BUFFERS_CHANGED:
334            return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
335
336        default:
337        {
338            jniThrowException(env, "java/lang/IllegalStateException", NULL);
339            break;
340        }
341    }
342
343    return 0;
344}
345
346static void android_media_MediaCodec_native_configure(
347        JNIEnv *env,
348        jobject thiz,
349        jobjectArray keys, jobjectArray values,
350        jobject jsurface,
351        jobject jcrypto,
352        jint flags) {
353    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
354
355    if (codec == NULL) {
356        jniThrowException(env, "java/lang/IllegalStateException", NULL);
357        return;
358    }
359
360    sp<AMessage> format;
361    status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
362
363    if (err != OK) {
364        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
365        return;
366    }
367
368    sp<ISurfaceTexture> surfaceTexture;
369    if (jsurface != NULL) {
370        sp<Surface> surface(Surface_getSurface(env, jsurface));
371        if (surface != NULL) {
372            surfaceTexture = surface->getSurfaceTexture();
373        } else {
374            jniThrowException(
375                    env,
376                    "java/lang/IllegalArgumentException",
377                    "The surface has been released");
378            return;
379        }
380    }
381
382    sp<ICrypto> crypto;
383    if (jcrypto != NULL) {
384        crypto = JCrypto::GetCrypto(env, jcrypto);
385    }
386
387    err = codec->configure(format, surfaceTexture, crypto, flags);
388
389    throwExceptionAsNecessary(env, err);
390}
391
392static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
393    ALOGV("android_media_MediaCodec_start");
394
395    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
396
397    if (codec == NULL) {
398        jniThrowException(env, "java/lang/IllegalStateException", NULL);
399        return;
400    }
401
402    status_t err = codec->start();
403
404    throwExceptionAsNecessary(env, err);
405}
406
407static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
408    ALOGV("android_media_MediaCodec_stop");
409
410    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
411
412    if (codec == NULL) {
413        jniThrowException(env, "java/lang/IllegalStateException", NULL);
414        return;
415    }
416
417    status_t err = codec->stop();
418
419    throwExceptionAsNecessary(env, err);
420}
421
422static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
423    ALOGV("android_media_MediaCodec_flush");
424
425    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
426
427    if (codec == NULL) {
428        jniThrowException(env, "java/lang/IllegalStateException", NULL);
429        return;
430    }
431
432    status_t err = codec->flush();
433
434    throwExceptionAsNecessary(env, err);
435}
436
437static void android_media_MediaCodec_queueInputBuffer(
438        JNIEnv *env,
439        jobject thiz,
440        jint index,
441        jint offset,
442        jint size,
443        jlong timestampUs,
444        jint flags) {
445    ALOGV("android_media_MediaCodec_queueInputBuffer");
446
447    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
448
449    if (codec == NULL) {
450        jniThrowException(env, "java/lang/IllegalStateException", NULL);
451        return;
452    }
453
454    AString errorDetailMsg;
455
456    status_t err = codec->queueInputBuffer(
457            index, offset, size, timestampUs, flags, &errorDetailMsg);
458
459    throwExceptionAsNecessary(
460            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
461}
462
463static void android_media_MediaCodec_queueSecureInputBuffer(
464        JNIEnv *env,
465        jobject thiz,
466        jint index,
467        jint offset,
468        jobject cryptoInfoObj,
469        jlong timestampUs,
470        jint flags) {
471    ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
472
473    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
474
475    if (codec == NULL) {
476        jniThrowException(env, "java/lang/IllegalStateException", NULL);
477        return;
478    }
479
480    jint numSubSamples =
481        env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
482
483    jintArray numBytesOfClearDataObj =
484        (jintArray)env->GetObjectField(
485                cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
486
487    jintArray numBytesOfEncryptedDataObj =
488        (jintArray)env->GetObjectField(
489                cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
490
491    jbyteArray keyObj =
492        (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
493
494    jbyteArray ivObj =
495        (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
496
497    jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
498
499    status_t err = OK;
500
501    CryptoPlugin::SubSample *subSamples = NULL;
502    jbyte *key = NULL;
503    jbyte *iv = NULL;
504
505    if (numSubSamples <= 0) {
506        err = -EINVAL;
507    } else if (numBytesOfClearDataObj == NULL
508            && numBytesOfEncryptedDataObj == NULL) {
509        err = -EINVAL;
510    } else if (numBytesOfEncryptedDataObj != NULL
511            && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
512        err = -ERANGE;
513    } else if (numBytesOfClearDataObj != NULL
514            && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
515        err = -ERANGE;
516    } else {
517        jboolean isCopy;
518
519        jint *numBytesOfClearData =
520            (numBytesOfClearDataObj == NULL)
521                ? NULL
522                : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
523
524        jint *numBytesOfEncryptedData =
525            (numBytesOfEncryptedDataObj == NULL)
526                ? NULL
527                : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
528
529        subSamples = new CryptoPlugin::SubSample[numSubSamples];
530
531        for (jint i = 0; i < numSubSamples; ++i) {
532            subSamples[i].mNumBytesOfClearData =
533                (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
534
535            subSamples[i].mNumBytesOfEncryptedData =
536                (numBytesOfEncryptedData == NULL)
537                    ? 0 : numBytesOfEncryptedData[i];
538        }
539
540        if (numBytesOfEncryptedData != NULL) {
541            env->ReleaseIntArrayElements(
542                    numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
543            numBytesOfEncryptedData = NULL;
544        }
545
546        if (numBytesOfClearData != NULL) {
547            env->ReleaseIntArrayElements(
548                    numBytesOfClearDataObj, numBytesOfClearData, 0);
549            numBytesOfClearData = NULL;
550        }
551    }
552
553    if (err == OK && keyObj != NULL) {
554        if (env->GetArrayLength(keyObj) != 16) {
555            err = -EINVAL;
556        } else {
557            jboolean isCopy;
558            key = env->GetByteArrayElements(keyObj, &isCopy);
559        }
560    }
561
562    if (err == OK && ivObj != NULL) {
563        if (env->GetArrayLength(ivObj) != 16) {
564            err = -EINVAL;
565        } else {
566            jboolean isCopy;
567            iv = env->GetByteArrayElements(ivObj, &isCopy);
568        }
569    }
570
571    AString errorDetailMsg;
572
573    if (err == OK) {
574        err = codec->queueSecureInputBuffer(
575                index, offset,
576                subSamples, numSubSamples,
577                (const uint8_t *)key, (const uint8_t *)iv,
578                (CryptoPlugin::Mode)mode,
579                timestampUs,
580                flags,
581                &errorDetailMsg);
582    }
583
584    if (iv != NULL) {
585        env->ReleaseByteArrayElements(ivObj, iv, 0);
586        iv = NULL;
587    }
588
589    if (key != NULL) {
590        env->ReleaseByteArrayElements(keyObj, key, 0);
591        key = NULL;
592    }
593
594    delete[] subSamples;
595    subSamples = NULL;
596
597    throwExceptionAsNecessary(
598            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
599}
600
601static jint android_media_MediaCodec_dequeueInputBuffer(
602        JNIEnv *env, jobject thiz, jlong timeoutUs) {
603    ALOGV("android_media_MediaCodec_dequeueInputBuffer");
604
605    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
606
607    if (codec == NULL) {
608        jniThrowException(env, "java/lang/IllegalStateException", NULL);
609        return -1;
610    }
611
612    size_t index;
613    status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
614
615    if (err == OK) {
616        return index;
617    }
618
619    return throwExceptionAsNecessary(env, err);
620}
621
622static jint android_media_MediaCodec_dequeueOutputBuffer(
623        JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
624    ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
625
626    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
627
628    if (codec == NULL) {
629        jniThrowException(env, "java/lang/IllegalStateException", NULL);
630        return 0;
631    }
632
633    size_t index;
634    status_t err = codec->dequeueOutputBuffer(
635            env, bufferInfo, &index, timeoutUs);
636
637    if (err == OK) {
638        return index;
639    }
640
641    return throwExceptionAsNecessary(env, err);
642}
643
644static void android_media_MediaCodec_releaseOutputBuffer(
645        JNIEnv *env, jobject thiz, jint index, jboolean render) {
646    ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
647
648    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
649
650    if (codec == NULL) {
651        jniThrowException(env, "java/lang/IllegalStateException", NULL);
652        return;
653    }
654
655    status_t err = codec->releaseOutputBuffer(index, render);
656
657    throwExceptionAsNecessary(env, err);
658}
659
660static jobject android_media_MediaCodec_getOutputFormatNative(
661        JNIEnv *env, jobject thiz) {
662    ALOGV("android_media_MediaCodec_getOutputFormatNative");
663
664    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
665
666    if (codec == NULL) {
667        jniThrowException(env, "java/lang/IllegalStateException", NULL);
668        return NULL;
669    }
670
671    jobject format;
672    status_t err = codec->getOutputFormat(env, &format);
673
674    if (err == OK) {
675        return format;
676    }
677
678    throwExceptionAsNecessary(env, err);
679
680    return NULL;
681}
682
683static jobjectArray android_media_MediaCodec_getBuffers(
684        JNIEnv *env, jobject thiz, jboolean input) {
685    ALOGV("android_media_MediaCodec_getBuffers");
686
687    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
688
689    if (codec == NULL) {
690        jniThrowException(env, "java/lang/IllegalStateException", NULL);
691        return NULL;
692    }
693
694    jobjectArray buffers;
695    status_t err = codec->getBuffers(env, input, &buffers);
696
697    if (err == OK) {
698        return buffers;
699    }
700
701    throwExceptionAsNecessary(env, err);
702
703    return NULL;
704}
705
706static void android_media_MediaCodec_setVideoScalingMode(
707        JNIEnv *env, jobject thiz, jint mode) {
708    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
709
710    if (codec == NULL) {
711        jniThrowException(env, "java/lang/IllegalStateException", NULL);
712        return;
713    }
714
715    if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
716            && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
717        jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
718        return;
719    }
720
721    codec->setVideoScalingMode(mode);
722}
723
724static void android_media_MediaCodec_native_init(JNIEnv *env) {
725    jclass clazz = env->FindClass("android/media/MediaCodec");
726    CHECK(clazz != NULL);
727
728    gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
729    CHECK(gFields.context != NULL);
730
731    clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
732    CHECK(clazz != NULL);
733
734    gFields.cryptoInfoNumSubSamplesID =
735        env->GetFieldID(clazz, "numSubSamples", "I");
736    CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
737
738    gFields.cryptoInfoNumBytesOfClearDataID =
739        env->GetFieldID(clazz, "numBytesOfClearData", "[I");
740    CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
741
742    gFields.cryptoInfoNumBytesOfEncryptedDataID =
743        env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
744    CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
745
746    gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
747    CHECK(gFields.cryptoInfoKeyID != NULL);
748
749    gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
750    CHECK(gFields.cryptoInfoIVID != NULL);
751
752    gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
753    CHECK(gFields.cryptoInfoModeID != NULL);
754}
755
756static void android_media_MediaCodec_native_setup(
757        JNIEnv *env, jobject thiz,
758        jstring name, jboolean nameIsType, jboolean encoder) {
759    if (name == NULL) {
760        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
761        return;
762    }
763
764    const char *tmp = env->GetStringUTFChars(name, NULL);
765
766    if (tmp == NULL) {
767        return;
768    }
769
770    sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
771
772    status_t err = codec->initCheck();
773
774    env->ReleaseStringUTFChars(name, tmp);
775    tmp = NULL;
776
777    if (err != OK) {
778        jniThrowException(
779                env,
780                "java/io/IOException",
781                "Failed to allocate component instance");
782        return;
783    }
784
785    setMediaCodec(env,thiz, codec);
786}
787
788static void android_media_MediaCodec_native_finalize(
789        JNIEnv *env, jobject thiz) {
790    android_media_MediaCodec_release(env, thiz);
791}
792
793static JNINativeMethod gMethods[] = {
794    { "release", "()V", (void *)android_media_MediaCodec_release },
795
796    { "native_configure",
797      "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
798      "Landroid/media/MediaCrypto;I)V",
799      (void *)android_media_MediaCodec_native_configure },
800
801    { "start", "()V", (void *)android_media_MediaCodec_start },
802    { "stop", "()V", (void *)android_media_MediaCodec_stop },
803    { "flush", "()V", (void *)android_media_MediaCodec_flush },
804
805    { "queueInputBuffer", "(IIIJI)V",
806      (void *)android_media_MediaCodec_queueInputBuffer },
807
808    { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
809      (void *)android_media_MediaCodec_queueSecureInputBuffer },
810
811    { "dequeueInputBuffer", "(J)I",
812      (void *)android_media_MediaCodec_dequeueInputBuffer },
813
814    { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
815      (void *)android_media_MediaCodec_dequeueOutputBuffer },
816
817    { "releaseOutputBuffer", "(IZ)V",
818      (void *)android_media_MediaCodec_releaseOutputBuffer },
819
820    { "getOutputFormatNative", "()Ljava/util/Map;",
821      (void *)android_media_MediaCodec_getOutputFormatNative },
822
823    { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
824      (void *)android_media_MediaCodec_getBuffers },
825
826    { "setVideoScalingMode", "(I)V",
827      (void *)android_media_MediaCodec_setVideoScalingMode },
828
829    { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
830
831    { "native_setup", "(Ljava/lang/String;ZZ)V",
832      (void *)android_media_MediaCodec_native_setup },
833
834    { "native_finalize", "()V",
835      (void *)android_media_MediaCodec_native_finalize },
836};
837
838int register_android_media_MediaCodec(JNIEnv *env) {
839    return AndroidRuntime::registerNativeMethods(env,
840                "android/media/MediaCodec", gMethods, NELEM(gMethods));
841}
842