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