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