OSDN Git Service

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