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