android_media_MediaCodec.cpp revision b12a5390694e8525ac61d7377e266e31d124c815
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
216    *bufArray = (jobjectArray)env->NewObjectArray(
217            buffers.size(), byteBufferClass, NULL);
218
219    for (size_t i = 0; i < buffers.size(); ++i) {
220        const sp<ABuffer> &buffer = buffers.itemAt(i);
221
222        jobject byteBuffer =
223            env->NewDirectByteBuffer(
224                buffer->base(),
225                buffer->capacity());
226
227        env->SetObjectArrayElement(
228                *bufArray, i, byteBuffer);
229
230        env->DeleteLocalRef(byteBuffer);
231        byteBuffer = NULL;
232    }
233
234    return OK;
235}
236
237void JMediaCodec::setVideoScalingMode(int mode) {
238    if (mSurfaceTextureClient != NULL) {
239        native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
240    }
241}
242
243}  // namespace android
244
245////////////////////////////////////////////////////////////////////////////////
246
247using namespace android;
248
249static sp<JMediaCodec> setMediaCodec(
250        JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
251    sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context);
252    if (codec != NULL) {
253        codec->incStrong(thiz);
254    }
255    if (old != NULL) {
256        old->decStrong(thiz);
257    }
258    env->SetIntField(thiz, gFields.context, (int)codec.get());
259
260    return old;
261}
262
263static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
264    return (JMediaCodec *)env->GetIntField(thiz, gFields.context);
265}
266
267static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
268    setMediaCodec(env, thiz, NULL);
269}
270
271static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
272    jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
273    CHECK(clazz != NULL);
274
275    jmethodID constructID =
276        env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
277    CHECK(constructID != NULL);
278
279    jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
280
281    jthrowable exception =
282        (jthrowable)env->NewObject(clazz, constructID, err, msgObj);
283
284    env->Throw(exception);
285}
286
287static jint throwExceptionAsNecessary(
288        JNIEnv *env, status_t err, const char *msg = NULL) {
289    if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
290        // We'll throw our custom MediaCodec.CryptoException
291
292        throwCryptoException(env, err, msg);
293        return 0;
294    }
295
296    switch (err) {
297        case OK:
298            return 0;
299
300        case -EAGAIN:
301            return DEQUEUE_INFO_TRY_AGAIN_LATER;
302
303        case INFO_FORMAT_CHANGED:
304            return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
305
306        case INFO_OUTPUT_BUFFERS_CHANGED:
307            return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
308
309        default:
310        {
311            jniThrowException(env, "java/lang/IllegalStateException", NULL);
312            break;
313        }
314    }
315
316    return 0;
317}
318
319static void android_media_MediaCodec_native_configure(
320        JNIEnv *env,
321        jobject thiz,
322        jobjectArray keys, jobjectArray values,
323        jobject jsurface,
324        jobject jcrypto,
325        jint flags) {
326    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
327
328    if (codec == NULL) {
329        jniThrowException(env, "java/lang/IllegalStateException", NULL);
330        return;
331    }
332
333    sp<AMessage> format;
334    status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
335
336    if (err != OK) {
337        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
338        return;
339    }
340
341    sp<ISurfaceTexture> surfaceTexture;
342    if (jsurface != NULL) {
343        sp<Surface> surface(Surface_getSurface(env, jsurface));
344        if (surface != NULL) {
345            surfaceTexture = surface->getSurfaceTexture();
346        } else {
347            jniThrowException(
348                    env,
349                    "java/lang/IllegalArgumentException",
350                    "The surface has been released");
351            return;
352        }
353    }
354
355    sp<ICrypto> crypto;
356    if (jcrypto != NULL) {
357        crypto = JCrypto::GetCrypto(env, jcrypto);
358    }
359
360    err = codec->configure(format, surfaceTexture, crypto, flags);
361
362    throwExceptionAsNecessary(env, err);
363}
364
365static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
366    ALOGV("android_media_MediaCodec_start");
367
368    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
369
370    if (codec == NULL) {
371        jniThrowException(env, "java/lang/IllegalStateException", NULL);
372        return;
373    }
374
375    status_t err = codec->start();
376
377    throwExceptionAsNecessary(env, err);
378}
379
380static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
381    ALOGV("android_media_MediaCodec_stop");
382
383    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
384
385    if (codec == NULL) {
386        jniThrowException(env, "java/lang/IllegalStateException", NULL);
387        return;
388    }
389
390    status_t err = codec->stop();
391
392    throwExceptionAsNecessary(env, err);
393}
394
395static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
396    ALOGV("android_media_MediaCodec_flush");
397
398    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
399
400    if (codec == NULL) {
401        jniThrowException(env, "java/lang/IllegalStateException", NULL);
402        return;
403    }
404
405    status_t err = codec->flush();
406
407    throwExceptionAsNecessary(env, err);
408}
409
410static void android_media_MediaCodec_queueInputBuffer(
411        JNIEnv *env,
412        jobject thiz,
413        jint index,
414        jint offset,
415        jint size,
416        jlong timestampUs,
417        jint flags) {
418    ALOGV("android_media_MediaCodec_queueInputBuffer");
419
420    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
421
422    if (codec == NULL) {
423        jniThrowException(env, "java/lang/IllegalStateException", NULL);
424        return;
425    }
426
427    AString errorDetailMsg;
428
429    status_t err = codec->queueInputBuffer(
430            index, offset, size, timestampUs, flags, &errorDetailMsg);
431
432    throwExceptionAsNecessary(
433            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
434}
435
436static void android_media_MediaCodec_queueSecureInputBuffer(
437        JNIEnv *env,
438        jobject thiz,
439        jint index,
440        jint offset,
441        jobject cryptoInfoObj,
442        jlong timestampUs,
443        jint flags) {
444    ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
445
446    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
447
448    if (codec == NULL) {
449        jniThrowException(env, "java/lang/IllegalStateException", NULL);
450        return;
451    }
452
453    jint numSubSamples =
454        env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
455
456    jintArray numBytesOfClearDataObj =
457        (jintArray)env->GetObjectField(
458                cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
459
460    jintArray numBytesOfEncryptedDataObj =
461        (jintArray)env->GetObjectField(
462                cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
463
464    jbyteArray keyObj =
465        (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
466
467    jbyteArray ivObj =
468        (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
469
470    jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
471
472    status_t err = OK;
473
474    CryptoPlugin::SubSample *subSamples = NULL;
475    jbyte *key = NULL;
476    jbyte *iv = NULL;
477
478    if (numSubSamples <= 0) {
479        err = -EINVAL;
480    } else if (numBytesOfClearDataObj == NULL
481            && numBytesOfEncryptedDataObj == NULL) {
482        err = -EINVAL;
483    } else if (numBytesOfEncryptedDataObj != NULL
484            && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
485        err = -ERANGE;
486    } else if (numBytesOfClearDataObj != NULL
487            && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
488        err = -ERANGE;
489    } else {
490        jboolean isCopy;
491
492        jint *numBytesOfClearData =
493            (numBytesOfClearDataObj == NULL)
494                ? NULL
495                : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
496
497        jint *numBytesOfEncryptedData =
498            (numBytesOfEncryptedDataObj == NULL)
499                ? NULL
500                : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
501
502        subSamples = new CryptoPlugin::SubSample[numSubSamples];
503
504        for (jint i = 0; i < numSubSamples; ++i) {
505            subSamples[i].mNumBytesOfClearData =
506                (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
507
508            subSamples[i].mNumBytesOfEncryptedData =
509                (numBytesOfEncryptedData == NULL)
510                    ? 0 : numBytesOfEncryptedData[i];
511        }
512
513        if (numBytesOfEncryptedData != NULL) {
514            env->ReleaseIntArrayElements(
515                    numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
516            numBytesOfEncryptedData = NULL;
517        }
518
519        if (numBytesOfClearData != NULL) {
520            env->ReleaseIntArrayElements(
521                    numBytesOfClearDataObj, numBytesOfClearData, 0);
522            numBytesOfClearData = NULL;
523        }
524    }
525
526    if (err == OK && keyObj != NULL) {
527        if (env->GetArrayLength(keyObj) != 16) {
528            err = -EINVAL;
529        } else {
530            jboolean isCopy;
531            key = env->GetByteArrayElements(keyObj, &isCopy);
532        }
533    }
534
535    if (err == OK && ivObj != NULL) {
536        if (env->GetArrayLength(ivObj) != 16) {
537            err = -EINVAL;
538        } else {
539            jboolean isCopy;
540            iv = env->GetByteArrayElements(ivObj, &isCopy);
541        }
542    }
543
544    AString errorDetailMsg;
545
546    if (err == OK) {
547        err = codec->queueSecureInputBuffer(
548                index, offset,
549                subSamples, numSubSamples,
550                (const uint8_t *)key, (const uint8_t *)iv,
551                (CryptoPlugin::Mode)mode,
552                timestampUs,
553                flags,
554                &errorDetailMsg);
555    }
556
557    if (iv != NULL) {
558        env->ReleaseByteArrayElements(ivObj, iv, 0);
559        iv = NULL;
560    }
561
562    if (key != NULL) {
563        env->ReleaseByteArrayElements(keyObj, key, 0);
564        key = NULL;
565    }
566
567    delete[] subSamples;
568    subSamples = NULL;
569
570    throwExceptionAsNecessary(
571            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
572}
573
574static jint android_media_MediaCodec_dequeueInputBuffer(
575        JNIEnv *env, jobject thiz, jlong timeoutUs) {
576    ALOGV("android_media_MediaCodec_dequeueInputBuffer");
577
578    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
579
580    if (codec == NULL) {
581        jniThrowException(env, "java/lang/IllegalStateException", NULL);
582        return -1;
583    }
584
585    size_t index;
586    status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
587
588    if (err == OK) {
589        return index;
590    }
591
592    return throwExceptionAsNecessary(env, err);
593}
594
595static jint android_media_MediaCodec_dequeueOutputBuffer(
596        JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
597    ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
598
599    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
600
601    if (codec == NULL) {
602        jniThrowException(env, "java/lang/IllegalStateException", NULL);
603        return 0;
604    }
605
606    size_t index;
607    status_t err = codec->dequeueOutputBuffer(
608            env, bufferInfo, &index, timeoutUs);
609
610    if (err == OK) {
611        return index;
612    }
613
614    return throwExceptionAsNecessary(env, err);
615}
616
617static void android_media_MediaCodec_releaseOutputBuffer(
618        JNIEnv *env, jobject thiz, jint index, jboolean render) {
619    ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
620
621    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
622
623    if (codec == NULL) {
624        jniThrowException(env, "java/lang/IllegalStateException", NULL);
625        return;
626    }
627
628    status_t err = codec->releaseOutputBuffer(index, render);
629
630    throwExceptionAsNecessary(env, err);
631}
632
633static jobject android_media_MediaCodec_getOutputFormat(
634        JNIEnv *env, jobject thiz) {
635    ALOGV("android_media_MediaCodec_getOutputFormat");
636
637    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
638
639    if (codec == NULL) {
640        jniThrowException(env, "java/lang/IllegalStateException", NULL);
641        return NULL;
642    }
643
644    jobject format;
645    status_t err = codec->getOutputFormat(env, &format);
646
647    if (err == OK) {
648        return format;
649    }
650
651    throwExceptionAsNecessary(env, err);
652
653    return NULL;
654}
655
656static jobjectArray android_media_MediaCodec_getBuffers(
657        JNIEnv *env, jobject thiz, jboolean input) {
658    ALOGV("android_media_MediaCodec_getBuffers");
659
660    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
661
662    if (codec == NULL) {
663        jniThrowException(env, "java/lang/IllegalStateException", NULL);
664        return NULL;
665    }
666
667    jobjectArray buffers;
668    status_t err = codec->getBuffers(env, input, &buffers);
669
670    if (err == OK) {
671        return buffers;
672    }
673
674    throwExceptionAsNecessary(env, err);
675
676    return NULL;
677}
678
679static void android_media_MediaCodec_setVideoScalingMode(
680        JNIEnv *env, jobject thiz, jint mode) {
681    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
682
683    if (codec == NULL) {
684        jniThrowException(env, "java/lang/IllegalStateException", NULL);
685        return;
686    }
687
688    if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
689            && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
690        jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
691        return;
692    }
693
694    codec->setVideoScalingMode(mode);
695}
696
697static void android_media_MediaCodec_native_init(JNIEnv *env) {
698    jclass clazz = env->FindClass("android/media/MediaCodec");
699    CHECK(clazz != NULL);
700
701    gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
702    CHECK(gFields.context != NULL);
703
704    clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
705    CHECK(clazz != NULL);
706
707    gFields.cryptoInfoNumSubSamplesID =
708        env->GetFieldID(clazz, "numSubSamples", "I");
709    CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
710
711    gFields.cryptoInfoNumBytesOfClearDataID =
712        env->GetFieldID(clazz, "numBytesOfClearData", "[I");
713    CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
714
715    gFields.cryptoInfoNumBytesOfEncryptedDataID =
716        env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
717    CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
718
719    gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
720    CHECK(gFields.cryptoInfoKeyID != NULL);
721
722    gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
723    CHECK(gFields.cryptoInfoIVID != NULL);
724
725    gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
726    CHECK(gFields.cryptoInfoModeID != NULL);
727}
728
729static void android_media_MediaCodec_native_setup(
730        JNIEnv *env, jobject thiz,
731        jstring name, jboolean nameIsType, jboolean encoder) {
732    if (name == NULL) {
733        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
734        return;
735    }
736
737    const char *tmp = env->GetStringUTFChars(name, NULL);
738
739    if (tmp == NULL) {
740        return;
741    }
742
743    sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
744
745    status_t err = codec->initCheck();
746
747    env->ReleaseStringUTFChars(name, tmp);
748    tmp = NULL;
749
750    if (err != OK) {
751        jniThrowException(
752                env,
753                "java/io/IOException",
754                "Failed to allocate component instance");
755        return;
756    }
757
758    setMediaCodec(env,thiz, codec);
759}
760
761static void android_media_MediaCodec_native_finalize(
762        JNIEnv *env, jobject thiz) {
763    android_media_MediaCodec_release(env, thiz);
764}
765
766static JNINativeMethod gMethods[] = {
767    { "release", "()V", (void *)android_media_MediaCodec_release },
768
769    { "native_configure",
770      "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
771      "Landroid/media/MediaCrypto;I)V",
772      (void *)android_media_MediaCodec_native_configure },
773
774    { "start", "()V", (void *)android_media_MediaCodec_start },
775    { "stop", "()V", (void *)android_media_MediaCodec_stop },
776    { "flush", "()V", (void *)android_media_MediaCodec_flush },
777
778    { "queueInputBuffer", "(IIIJI)V",
779      (void *)android_media_MediaCodec_queueInputBuffer },
780
781    { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
782      (void *)android_media_MediaCodec_queueSecureInputBuffer },
783
784    { "dequeueInputBuffer", "(J)I",
785      (void *)android_media_MediaCodec_dequeueInputBuffer },
786
787    { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
788      (void *)android_media_MediaCodec_dequeueOutputBuffer },
789
790    { "releaseOutputBuffer", "(IZ)V",
791      (void *)android_media_MediaCodec_releaseOutputBuffer },
792
793    { "getOutputFormat", "()Ljava/util/Map;",
794      (void *)android_media_MediaCodec_getOutputFormat },
795
796    { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
797      (void *)android_media_MediaCodec_getBuffers },
798
799    { "setVideoScalingMode", "(I)V",
800      (void *)android_media_MediaCodec_setVideoScalingMode },
801
802    { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
803
804    { "native_setup", "(Ljava/lang/String;ZZ)V",
805      (void *)android_media_MediaCodec_native_setup },
806
807    { "native_finalize", "()V",
808      (void *)android_media_MediaCodec_native_finalize },
809};
810
811int register_android_media_MediaCodec(JNIEnv *env) {
812    return AndroidRuntime::registerNativeMethods(env,
813                "android/media/MediaCodec", gMethods, NELEM(gMethods));
814}
815