OSDN Git Service

Merge "Fall-through for ActionModes with ToolbarActionBar" into lmp-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
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 };
60
61 struct CryptoErrorCodes {
62     jint cryptoErrorNoKey;
63     jint cryptoErrorKeyExpired;
64     jint cryptoErrorResourceBusy;
65 } gCryptoErrorCodes;
66
67 struct fields_t {
68     jfieldID context;
69     jmethodID postEventFromNativeID;
70     jfieldID cryptoInfoNumSubSamplesID;
71     jfieldID cryptoInfoNumBytesOfClearDataID;
72     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
73     jfieldID cryptoInfoKeyID;
74     jfieldID cryptoInfoIVID;
75     jfieldID cryptoInfoModeID;
76 };
77
78 static fields_t gFields;
79
80 ////////////////////////////////////////////////////////////////////////////////
81
82 JMediaCodec::JMediaCodec(
83         JNIEnv *env, jobject thiz,
84         const char *name, bool nameIsType, bool encoder)
85     : mClass(NULL),
86       mObject(NULL) {
87     jclass clazz = env->GetObjectClass(thiz);
88     CHECK(clazz != NULL);
89
90     mClass = (jclass)env->NewGlobalRef(clazz);
91     mObject = env->NewWeakGlobalRef(thiz);
92
93     cacheJavaObjects(env);
94
95     mLooper = new ALooper;
96     mLooper->setName("MediaCodec_looper");
97
98     mLooper->start(
99             false,      // runOnCallingThread
100             true,       // canCallJava
101             PRIORITY_FOREGROUND);
102
103     if (nameIsType) {
104         mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
105     } else {
106         mCodec = MediaCodec::CreateByComponentName(mLooper, name);
107     }
108 }
109
110 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
111     jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
112     mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
113     CHECK(mByteBufferClass != NULL);
114
115     ScopedLocalRef<jclass> byteOrderClass(
116             env, env->FindClass("java/nio/ByteOrder"));
117     CHECK(byteOrderClass.get() != NULL);
118
119     jmethodID nativeOrderID = env->GetStaticMethodID(
120             byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
121     CHECK(nativeOrderID != NULL);
122
123     jobject nativeByteOrderObj =
124         env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
125     mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
126     CHECK(mNativeByteOrderObj != NULL);
127     env->DeleteLocalRef(nativeByteOrderObj);
128     nativeByteOrderObj = NULL;
129
130     mByteBufferOrderMethodID = env->GetMethodID(
131             mByteBufferClass,
132             "order",
133             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
134     CHECK(mByteBufferOrderMethodID != NULL);
135
136     mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
137             mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
138     CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
139
140     mByteBufferPositionMethodID = env->GetMethodID(
141             mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
142     CHECK(mByteBufferPositionMethodID != NULL);
143
144     mByteBufferLimitMethodID = env->GetMethodID(
145             mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
146     CHECK(mByteBufferLimitMethodID != NULL);
147 }
148
149 status_t JMediaCodec::initCheck() const {
150     return mCodec != NULL ? OK : NO_INIT;
151 }
152
153 void JMediaCodec::registerSelf() {
154     mLooper->registerHandler(this);
155 }
156
157 void JMediaCodec::release() {
158     if (mCodec != NULL) {
159         mCodec->release();
160         mCodec.clear();
161     }
162
163     if (mLooper != NULL) {
164         mLooper->unregisterHandler(id());
165         mLooper->stop();
166         mLooper.clear();
167     }
168 }
169
170 JMediaCodec::~JMediaCodec() {
171     if (mCodec != NULL || mLooper != NULL) {
172         /* MediaCodec and looper should have been released explicitly already
173          * in setMediaCodec() (see comments in setMediaCodec()).
174          *
175          * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
176          * message handler, doing release() there risks deadlock as MediaCodec::
177          * release() post synchronous message to the same looper.
178          *
179          * Print a warning and try to proceed with releasing.
180          */
181         ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
182         release();
183         ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
184     }
185
186     JNIEnv *env = AndroidRuntime::getJNIEnv();
187
188     env->DeleteWeakGlobalRef(mObject);
189     mObject = NULL;
190     env->DeleteGlobalRef(mClass);
191     mClass = NULL;
192     deleteJavaObjects(env);
193 }
194
195 void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
196     env->DeleteGlobalRef(mByteBufferClass);
197     mByteBufferClass = NULL;
198     env->DeleteGlobalRef(mNativeByteOrderObj);
199     mNativeByteOrderObj = NULL;
200
201     mByteBufferOrderMethodID = NULL;
202     mByteBufferAsReadOnlyBufferMethodID = NULL;
203     mByteBufferPositionMethodID = NULL;
204     mByteBufferLimitMethodID = NULL;
205 }
206
207 status_t JMediaCodec::setCallback(jobject cb) {
208     if (cb != NULL) {
209         if (mCallbackNotification == NULL) {
210             mCallbackNotification = new AMessage(kWhatCallbackNotify, id());
211         }
212     } else {
213         mCallbackNotification.clear();
214     }
215
216     return mCodec->setCallback(mCallbackNotification);
217 }
218
219 status_t JMediaCodec::configure(
220         const sp<AMessage> &format,
221         const sp<IGraphicBufferProducer> &bufferProducer,
222         const sp<ICrypto> &crypto,
223         int flags) {
224     sp<Surface> client;
225     if (bufferProducer != NULL) {
226         mSurfaceTextureClient =
227             new Surface(bufferProducer, true /* controlledByApp */);
228     } else {
229         mSurfaceTextureClient.clear();
230     }
231
232     return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
233 }
234
235 status_t JMediaCodec::createInputSurface(
236         sp<IGraphicBufferProducer>* bufferProducer) {
237     return mCodec->createInputSurface(bufferProducer);
238 }
239
240 status_t JMediaCodec::start() {
241     return mCodec->start();
242 }
243
244 status_t JMediaCodec::stop() {
245     mSurfaceTextureClient.clear();
246
247     return mCodec->stop();
248 }
249
250 status_t JMediaCodec::flush() {
251     return mCodec->flush();
252 }
253
254 status_t JMediaCodec::reset() {
255     return mCodec->reset();
256 }
257
258 status_t JMediaCodec::queueInputBuffer(
259         size_t index,
260         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
261         AString *errorDetailMsg) {
262     return mCodec->queueInputBuffer(
263             index, offset, size, timeUs, flags, errorDetailMsg);
264 }
265
266 status_t JMediaCodec::queueSecureInputBuffer(
267         size_t index,
268         size_t offset,
269         const CryptoPlugin::SubSample *subSamples,
270         size_t numSubSamples,
271         const uint8_t key[16],
272         const uint8_t iv[16],
273         CryptoPlugin::Mode mode,
274         int64_t presentationTimeUs,
275         uint32_t flags,
276         AString *errorDetailMsg) {
277     return mCodec->queueSecureInputBuffer(
278             index, offset, subSamples, numSubSamples, key, iv, mode,
279             presentationTimeUs, flags, errorDetailMsg);
280 }
281
282 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
283     return mCodec->dequeueInputBuffer(index, timeoutUs);
284 }
285
286 status_t JMediaCodec::dequeueOutputBuffer(
287         JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
288     size_t size, offset;
289     int64_t timeUs;
290     uint32_t flags;
291     status_t err = mCodec->dequeueOutputBuffer(
292             index, &offset, &size, &timeUs, &flags, timeoutUs);
293
294     if (err != OK) {
295         return err;
296     }
297
298     ScopedLocalRef<jclass> clazz(
299             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
300
301     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
302     env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
303
304     return OK;
305 }
306
307 status_t JMediaCodec::releaseOutputBuffer(
308         size_t index, bool render, bool updatePTS, int64_t timestampNs) {
309     if (updatePTS) {
310         return mCodec->renderOutputBufferAndRelease(index, timestampNs);
311     }
312     return render
313         ? mCodec->renderOutputBufferAndRelease(index)
314         : mCodec->releaseOutputBuffer(index);
315 }
316
317 status_t JMediaCodec::signalEndOfInputStream() {
318     return mCodec->signalEndOfInputStream();
319 }
320
321 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
322     sp<AMessage> msg;
323     status_t err;
324     err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
325     if (err != OK) {
326         return err;
327     }
328
329     return ConvertMessageToMap(env, msg, format);
330 }
331
332 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
333     sp<AMessage> msg;
334     status_t err;
335     if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
336         return err;
337     }
338
339     return ConvertMessageToMap(env, msg, format);
340 }
341
342 status_t JMediaCodec::getBuffers(
343         JNIEnv *env, bool input, jobjectArray *bufArray) const {
344     Vector<sp<ABuffer> > buffers;
345
346     status_t err =
347         input
348             ? mCodec->getInputBuffers(&buffers)
349             : mCodec->getOutputBuffers(&buffers);
350
351     if (err != OK) {
352         return err;
353     }
354
355     *bufArray = (jobjectArray)env->NewObjectArray(
356             buffers.size(), mByteBufferClass, NULL);
357     if (*bufArray == NULL) {
358         return NO_MEMORY;
359     }
360
361     for (size_t i = 0; i < buffers.size(); ++i) {
362         const sp<ABuffer> &buffer = buffers.itemAt(i);
363
364         jobject byteBuffer = NULL;
365         err = createByteBufferFromABuffer(
366                 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
367         if (err != OK) {
368             return err;
369         }
370         if (byteBuffer != NULL) {
371             env->SetObjectArrayElement(
372                     *bufArray, i, byteBuffer);
373
374             env->DeleteLocalRef(byteBuffer);
375             byteBuffer = NULL;
376         }
377     }
378
379     return OK;
380 }
381
382 // static
383 status_t JMediaCodec::createByteBufferFromABuffer(
384         JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
385         jobject *buf) const {
386     // if this is an ABuffer that doesn't actually hold any accessible memory,
387     // use a null ByteBuffer
388     *buf = NULL;
389     if (buffer->base() == NULL) {
390         return OK;
391     }
392
393     jobject byteBuffer =
394         env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
395     if (readOnly && byteBuffer != NULL) {
396         jobject readOnlyBuffer = env->CallObjectMethod(
397                 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
398         env->DeleteLocalRef(byteBuffer);
399         byteBuffer = readOnlyBuffer;
400     }
401     if (byteBuffer == NULL) {
402         return NO_MEMORY;
403     }
404     jobject me = env->CallObjectMethod(
405             byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
406     env->DeleteLocalRef(me);
407     me = env->CallObjectMethod(
408             byteBuffer, mByteBufferLimitMethodID,
409             clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
410     env->DeleteLocalRef(me);
411     me = env->CallObjectMethod(
412             byteBuffer, mByteBufferPositionMethodID,
413             clearBuffer ? 0 : buffer->offset());
414     env->DeleteLocalRef(me);
415     me = NULL;
416
417     *buf = byteBuffer;
418     return OK;
419 }
420
421 status_t JMediaCodec::getBuffer(
422         JNIEnv *env, bool input, size_t index, jobject *buf) const {
423     sp<ABuffer> buffer;
424
425     status_t err =
426         input
427             ? mCodec->getInputBuffer(index, &buffer)
428             : mCodec->getOutputBuffer(index, &buffer);
429
430     if (err != OK) {
431         return err;
432     }
433
434     return createByteBufferFromABuffer(
435             env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
436 }
437
438 status_t JMediaCodec::getImage(
439         JNIEnv *env, bool input, size_t index, jobject *buf) const {
440     sp<ABuffer> buffer;
441
442     status_t err =
443         input
444             ? mCodec->getInputBuffer(index, &buffer)
445             : mCodec->getOutputBuffer(index, &buffer);
446
447     if (err != OK) {
448         return err;
449     }
450
451     // if this is an ABuffer that doesn't actually hold any accessible memory,
452     // use a null ByteBuffer
453     *buf = NULL;
454     if (buffer->base() == NULL) {
455         return OK;
456     }
457
458     // check if buffer is an image
459     sp<ABuffer> imageData;
460     if (!buffer->meta()->findBuffer("image-data", &imageData)) {
461         return OK;
462     }
463
464     int64_t timestamp = 0;
465     if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
466         timestamp *= 1000; // adjust to ns
467     }
468
469     jobject byteBuffer = NULL;
470     err = createByteBufferFromABuffer(
471             env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
472     if (err != OK) {
473         return OK;
474     }
475
476     jobject infoBuffer = NULL;
477     err = createByteBufferFromABuffer(
478             env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
479     if (err != OK) {
480         env->DeleteLocalRef(byteBuffer);
481         byteBuffer = NULL;
482         return OK;
483     }
484
485     jobject cropRect = NULL;
486     int32_t left, top, right, bottom;
487     if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
488         ScopedLocalRef<jclass> rectClazz(
489                 env, env->FindClass("android/graphics/Rect"));
490         CHECK(rectClazz.get() != NULL);
491
492         jmethodID rectConstructID = env->GetMethodID(
493                 rectClazz.get(), "<init>", "(IIII)V");
494
495         cropRect = env->NewObject(
496                 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
497     }
498
499     ScopedLocalRef<jclass> imageClazz(
500             env, env->FindClass("android/media/MediaCodec$MediaImage"));
501     CHECK(imageClazz.get() != NULL);
502
503     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
504             "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
505
506     *buf = env->NewObject(imageClazz.get(), imageConstructID,
507             byteBuffer, infoBuffer,
508             (jboolean)!input /* readOnly */,
509             (jlong)timestamp,
510             (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
511
512     // if MediaImage creation fails, return null
513     if (env->ExceptionCheck()) {
514         env->ExceptionDescribe();
515         env->ExceptionClear();
516         *buf = NULL;
517     }
518
519     if (cropRect != NULL) {
520         env->DeleteLocalRef(cropRect);
521         cropRect = NULL;
522     }
523
524     env->DeleteLocalRef(byteBuffer);
525     byteBuffer = NULL;
526
527     env->DeleteLocalRef(infoBuffer);
528     infoBuffer = NULL;
529
530     return OK;
531 }
532
533 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
534     AString name;
535
536     status_t err = mCodec->getName(&name);
537
538     if (err != OK) {
539         return err;
540     }
541
542     *nameStr = env->NewStringUTF(name.c_str());
543
544     return OK;
545 }
546
547 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
548     return mCodec->setParameters(msg);
549 }
550
551 void JMediaCodec::setVideoScalingMode(int mode) {
552     if (mSurfaceTextureClient != NULL) {
553         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
554     }
555 }
556
557 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
558     int32_t arg1, arg2 = 0;
559     jobject obj = NULL;
560     CHECK(msg->findInt32("callbackID", &arg1));
561     JNIEnv *env = AndroidRuntime::getJNIEnv();
562
563     switch (arg1) {
564         case MediaCodec::CB_INPUT_AVAILABLE:
565         {
566             CHECK(msg->findInt32("index", &arg2));
567             break;
568         }
569
570         case MediaCodec::CB_OUTPUT_AVAILABLE:
571         {
572             CHECK(msg->findInt32("index", &arg2));
573
574             size_t size, offset;
575             int64_t timeUs;
576             uint32_t flags;
577             CHECK(msg->findSize("size", &size));
578             CHECK(msg->findSize("offset", &offset));
579             CHECK(msg->findInt64("timeUs", &timeUs));
580             CHECK(msg->findInt32("flags", (int32_t *)&flags));
581
582             ScopedLocalRef<jclass> clazz(
583                     env, env->FindClass("android/media/MediaCodec$BufferInfo"));
584             jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
585             jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
586
587             obj = env->NewObject(clazz.get(), ctor);
588
589             if (obj == NULL) {
590                 if (env->ExceptionCheck()) {
591                     ALOGE("Could not create MediaCodec.BufferInfo.");
592                     env->ExceptionClear();
593                 }
594                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
595                 return;
596             }
597
598             env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
599             break;
600         }
601
602         case MediaCodec::CB_ERROR:
603         {
604             int32_t err, actionCode;
605             CHECK(msg->findInt32("err", &err));
606             CHECK(msg->findInt32("actionCode", &actionCode));
607
608             // use Integer object to pass the action code
609             ScopedLocalRef<jclass> clazz(
610                     env, env->FindClass("android/media/MediaCodec$CodecException"));
611             jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
612
613             AString str;
614             const char *detail = "Unknown error";
615             if (msg->findString("detail", &str)) {
616                 detail = str.c_str();
617             }
618             jstring msgObj = env->NewStringUTF(detail);
619
620             obj = env->NewObject(clazz.get(), ctor, err, actionCode, msgObj);
621
622             if (obj == NULL) {
623                 if (env->ExceptionCheck()) {
624                     ALOGE("Could not create CodecException object.");
625                     env->ExceptionClear();
626                 }
627                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
628                 return;
629             }
630
631             break;
632         }
633
634         case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
635         {
636             sp<AMessage> format;
637             CHECK(msg->findMessage("format", &format));
638
639             if (OK != ConvertMessageToMap(env, format, &obj)) {
640                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
641                 return;
642             }
643
644             break;
645         }
646
647         default:
648             TRESPASS();
649     }
650
651     env->CallVoidMethod(
652             mObject,
653             gFields.postEventFromNativeID,
654             EVENT_CALLBACK,
655             arg1,
656             arg2,
657             obj);
658
659     env->DeleteLocalRef(obj);
660 }
661
662 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
663     switch (msg->what()) {
664         case kWhatCallbackNotify:
665         {
666             handleCallback(msg);
667             break;
668         }
669         default:
670             TRESPASS();
671     }
672 }
673
674 }  // namespace android
675
676 ////////////////////////////////////////////////////////////////////////////////
677
678 using namespace android;
679
680 static sp<JMediaCodec> setMediaCodec(
681         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
682     sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
683     if (codec != NULL) {
684         codec->incStrong(thiz);
685     }
686     if (old != NULL) {
687         /* release MediaCodec and stop the looper now before decStrong.
688          * otherwise JMediaCodec::~JMediaCodec() could be called from within
689          * its message handler, doing release() from there will deadlock
690          * (as MediaCodec::release() post synchronous message to the same looper)
691          */
692         old->release();
693         old->decStrong(thiz);
694     }
695     env->SetLongField(thiz, gFields.context, (jlong)codec.get());
696
697     return old;
698 }
699
700 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
701     return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
702 }
703
704 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
705     setMediaCodec(env, thiz, NULL);
706 }
707
708 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
709     ScopedLocalRef<jclass> clazz(
710             env, env->FindClass("android/media/MediaCodec$CryptoException"));
711     CHECK(clazz.get() != NULL);
712
713     jmethodID constructID =
714         env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
715     CHECK(constructID != NULL);
716
717     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
718
719     /* translate OS errors to Java API CryptoException errorCodes */
720     switch (err) {
721         case ERROR_DRM_NO_LICENSE:
722             err = gCryptoErrorCodes.cryptoErrorNoKey;
723             break;
724         case ERROR_DRM_LICENSE_EXPIRED:
725             err = gCryptoErrorCodes.cryptoErrorKeyExpired;
726             break;
727         case ERROR_DRM_RESOURCE_BUSY:
728             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
729             break;
730         default:
731             break;
732     }
733
734     jthrowable exception =
735         (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
736
737     env->Throw(exception);
738 }
739
740 static jint throwExceptionAsNecessary(
741         JNIEnv *env, status_t err, const char *msg = NULL) {
742     if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
743         // We'll throw our custom MediaCodec.CryptoException
744         throwCryptoException(env, err, msg);
745         return 0;
746     }
747
748     switch (err) {
749         case OK:
750             return 0;
751
752         case -EAGAIN:
753             return DEQUEUE_INFO_TRY_AGAIN_LATER;
754
755         case INFO_FORMAT_CHANGED:
756             return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
757
758         case INFO_OUTPUT_BUFFERS_CHANGED:
759             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
760
761         case ERROR_DRM_NO_LICENSE:
762         case ERROR_DRM_LICENSE_EXPIRED:
763         case ERROR_DRM_RESOURCE_BUSY:
764             throwCryptoException(env, err, msg);
765             break;
766
767         default:
768         {
769             jniThrowException(env, "java/lang/IllegalStateException", msg);
770             break;
771         }
772     }
773
774     return 0;
775 }
776
777 static void android_media_MediaCodec_native_setCallback(
778         JNIEnv *env,
779         jobject thiz,
780         jobject cb) {
781     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
782
783     if (codec == NULL) {
784         jniThrowException(env, "java/lang/IllegalStateException", NULL);
785         return;
786     }
787
788     status_t err = codec->setCallback(cb);
789
790     throwExceptionAsNecessary(env, err);
791 }
792
793 static void android_media_MediaCodec_native_configure(
794         JNIEnv *env,
795         jobject thiz,
796         jobjectArray keys, jobjectArray values,
797         jobject jsurface,
798         jobject jcrypto,
799         jint flags) {
800     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
801
802     if (codec == NULL) {
803         jniThrowException(env, "java/lang/IllegalStateException", NULL);
804         return;
805     }
806
807     sp<AMessage> format;
808     status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
809
810     if (err != OK) {
811         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
812         return;
813     }
814
815     sp<IGraphicBufferProducer> bufferProducer;
816     if (jsurface != NULL) {
817         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
818         if (surface != NULL) {
819             bufferProducer = surface->getIGraphicBufferProducer();
820         } else {
821             jniThrowException(
822                     env,
823                     "java/lang/IllegalArgumentException",
824                     "The surface has been released");
825             return;
826         }
827     }
828
829     sp<ICrypto> crypto;
830     if (jcrypto != NULL) {
831         crypto = JCrypto::GetCrypto(env, jcrypto);
832     }
833
834     err = codec->configure(format, bufferProducer, crypto, flags);
835
836     throwExceptionAsNecessary(env, err);
837 }
838
839 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
840         jobject thiz) {
841     ALOGV("android_media_MediaCodec_createInputSurface");
842
843     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
844     if (codec == NULL) {
845         jniThrowException(env, "java/lang/IllegalStateException", NULL);
846         return NULL;
847     }
848
849     // Tell the MediaCodec that we want to use a Surface as input.
850     sp<IGraphicBufferProducer> bufferProducer;
851     status_t err = codec->createInputSurface(&bufferProducer);
852     if (err != NO_ERROR) {
853         throwExceptionAsNecessary(env, err);
854         return NULL;
855     }
856
857     // Wrap the IGBP in a Java-language Surface.
858     return android_view_Surface_createFromIGraphicBufferProducer(env,
859             bufferProducer);
860 }
861
862 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
863     ALOGV("android_media_MediaCodec_start");
864
865     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
866
867     if (codec == NULL) {
868         jniThrowException(env, "java/lang/IllegalStateException", "no codec found");
869         return;
870     }
871
872     status_t err = codec->start();
873
874     throwExceptionAsNecessary(env, err, "start failed");
875 }
876
877 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
878     ALOGV("android_media_MediaCodec_stop");
879
880     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
881
882     if (codec == NULL) {
883         jniThrowException(env, "java/lang/IllegalStateException", NULL);
884         return;
885     }
886
887     status_t err = codec->stop();
888
889     throwExceptionAsNecessary(env, err);
890 }
891
892 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
893     ALOGV("android_media_MediaCodec_reset");
894
895     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
896
897     if (codec == NULL) {
898         // should never be here
899         jniThrowException(env, "java/lang/IllegalStateException", NULL);
900         return;
901     }
902
903     status_t err = codec->reset();
904     if (err != OK) {
905         // treat all errors as fatal for now, though resource not available
906         // errors could be treated as transient.
907         err = 0x80000000;
908     }
909     throwExceptionAsNecessary(env, err);
910 }
911
912 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
913     ALOGV("android_media_MediaCodec_flush");
914
915     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
916
917     if (codec == NULL) {
918         jniThrowException(env, "java/lang/IllegalStateException", NULL);
919         return;
920     }
921
922     status_t err = codec->flush();
923
924     throwExceptionAsNecessary(env, err);
925 }
926
927 static void android_media_MediaCodec_queueInputBuffer(
928         JNIEnv *env,
929         jobject thiz,
930         jint index,
931         jint offset,
932         jint size,
933         jlong timestampUs,
934         jint flags) {
935     ALOGV("android_media_MediaCodec_queueInputBuffer");
936
937     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
938
939     if (codec == NULL) {
940         jniThrowException(env, "java/lang/IllegalStateException", NULL);
941         return;
942     }
943
944     AString errorDetailMsg;
945
946     status_t err = codec->queueInputBuffer(
947             index, offset, size, timestampUs, flags, &errorDetailMsg);
948
949     throwExceptionAsNecessary(
950             env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
951 }
952
953 static void android_media_MediaCodec_queueSecureInputBuffer(
954         JNIEnv *env,
955         jobject thiz,
956         jint index,
957         jint offset,
958         jobject cryptoInfoObj,
959         jlong timestampUs,
960         jint flags) {
961     ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
962
963     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
964
965     if (codec == NULL) {
966         jniThrowException(env, "java/lang/IllegalStateException", NULL);
967         return;
968     }
969
970     jint numSubSamples =
971         env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
972
973     jintArray numBytesOfClearDataObj =
974         (jintArray)env->GetObjectField(
975                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
976
977     jintArray numBytesOfEncryptedDataObj =
978         (jintArray)env->GetObjectField(
979                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
980
981     jbyteArray keyObj =
982         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
983
984     jbyteArray ivObj =
985         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
986
987     jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
988
989     status_t err = OK;
990
991     CryptoPlugin::SubSample *subSamples = NULL;
992     jbyte *key = NULL;
993     jbyte *iv = NULL;
994
995     if (numSubSamples <= 0) {
996         err = -EINVAL;
997     } else if (numBytesOfClearDataObj == NULL
998             && numBytesOfEncryptedDataObj == NULL) {
999         err = -EINVAL;
1000     } else if (numBytesOfEncryptedDataObj != NULL
1001             && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1002         err = -ERANGE;
1003     } else if (numBytesOfClearDataObj != NULL
1004             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1005         err = -ERANGE;
1006     // subSamples array may silently overflow if number of samples are too large.  Use
1007     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1008     } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) {
1009         err = -EINVAL;
1010     } else {
1011         jboolean isCopy;
1012
1013         jint *numBytesOfClearData =
1014             (numBytesOfClearDataObj == NULL)
1015                 ? NULL
1016                 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1017
1018         jint *numBytesOfEncryptedData =
1019             (numBytesOfEncryptedDataObj == NULL)
1020                 ? NULL
1021                 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1022
1023         subSamples = new CryptoPlugin::SubSample[numSubSamples];
1024
1025         for (jint i = 0; i < numSubSamples; ++i) {
1026             subSamples[i].mNumBytesOfClearData =
1027                 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1028
1029             subSamples[i].mNumBytesOfEncryptedData =
1030                 (numBytesOfEncryptedData == NULL)
1031                     ? 0 : numBytesOfEncryptedData[i];
1032         }
1033
1034         if (numBytesOfEncryptedData != NULL) {
1035             env->ReleaseIntArrayElements(
1036                     numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1037             numBytesOfEncryptedData = NULL;
1038         }
1039
1040         if (numBytesOfClearData != NULL) {
1041             env->ReleaseIntArrayElements(
1042                     numBytesOfClearDataObj, numBytesOfClearData, 0);
1043             numBytesOfClearData = NULL;
1044         }
1045     }
1046
1047     if (err == OK && keyObj != NULL) {
1048         if (env->GetArrayLength(keyObj) != 16) {
1049             err = -EINVAL;
1050         } else {
1051             jboolean isCopy;
1052             key = env->GetByteArrayElements(keyObj, &isCopy);
1053         }
1054     }
1055
1056     if (err == OK && ivObj != NULL) {
1057         if (env->GetArrayLength(ivObj) != 16) {
1058             err = -EINVAL;
1059         } else {
1060             jboolean isCopy;
1061             iv = env->GetByteArrayElements(ivObj, &isCopy);
1062         }
1063     }
1064
1065     AString errorDetailMsg;
1066
1067     if (err == OK) {
1068         err = codec->queueSecureInputBuffer(
1069                 index, offset,
1070                 subSamples, numSubSamples,
1071                 (const uint8_t *)key, (const uint8_t *)iv,
1072                 (CryptoPlugin::Mode)mode,
1073                 timestampUs,
1074                 flags,
1075                 &errorDetailMsg);
1076     }
1077
1078     if (iv != NULL) {
1079         env->ReleaseByteArrayElements(ivObj, iv, 0);
1080         iv = NULL;
1081     }
1082
1083     if (key != NULL) {
1084         env->ReleaseByteArrayElements(keyObj, key, 0);
1085         key = NULL;
1086     }
1087
1088     delete[] subSamples;
1089     subSamples = NULL;
1090
1091     throwExceptionAsNecessary(
1092             env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1093 }
1094
1095 static jint android_media_MediaCodec_dequeueInputBuffer(
1096         JNIEnv *env, jobject thiz, jlong timeoutUs) {
1097     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1098
1099     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1100
1101     if (codec == NULL) {
1102         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1103         return -1;
1104     }
1105
1106     size_t index;
1107     status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1108
1109     if (err == OK) {
1110         return (jint) index;
1111     }
1112
1113     return throwExceptionAsNecessary(env, err);
1114 }
1115
1116 static jint android_media_MediaCodec_dequeueOutputBuffer(
1117         JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1118     ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1119
1120     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1121
1122     if (codec == NULL) {
1123         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1124         return 0;
1125     }
1126
1127     size_t index;
1128     status_t err = codec->dequeueOutputBuffer(
1129             env, bufferInfo, &index, timeoutUs);
1130
1131     if (err == OK) {
1132         return (jint) index;
1133     }
1134
1135     return throwExceptionAsNecessary(env, err);
1136 }
1137
1138 static void android_media_MediaCodec_releaseOutputBuffer(
1139         JNIEnv *env, jobject thiz,
1140         jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
1141     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1142
1143     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1144
1145     if (codec == NULL) {
1146         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1147         return;
1148     }
1149
1150     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
1151
1152     throwExceptionAsNecessary(env, err);
1153 }
1154
1155 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1156         jobject thiz) {
1157     ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1158
1159     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1160     if (codec == NULL) {
1161         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1162         return;
1163     }
1164
1165     status_t err = codec->signalEndOfInputStream();
1166
1167     throwExceptionAsNecessary(env, err);
1168 }
1169
1170 static jobject android_media_MediaCodec_getFormatNative(
1171         JNIEnv *env, jobject thiz, jboolean input) {
1172     ALOGV("android_media_MediaCodec_getFormatNative");
1173
1174     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1175
1176     if (codec == NULL) {
1177         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1178         return NULL;
1179     }
1180
1181     jobject format;
1182     status_t err = codec->getFormat(env, input, &format);
1183
1184     if (err == OK) {
1185         return format;
1186     }
1187
1188     throwExceptionAsNecessary(env, err);
1189
1190     return NULL;
1191 }
1192
1193 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1194         JNIEnv *env, jobject thiz, jint index) {
1195     ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1196
1197     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1198
1199     if (codec == NULL) {
1200         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1201         return NULL;
1202     }
1203
1204     jobject format;
1205     status_t err = codec->getOutputFormat(env, index, &format);
1206
1207     if (err == OK) {
1208         return format;
1209     }
1210
1211     throwExceptionAsNecessary(env, err);
1212
1213     return NULL;
1214 }
1215
1216 static jobjectArray android_media_MediaCodec_getBuffers(
1217         JNIEnv *env, jobject thiz, jboolean input) {
1218     ALOGV("android_media_MediaCodec_getBuffers");
1219
1220     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1221
1222     if (codec == NULL) {
1223         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1224         return NULL;
1225     }
1226
1227     jobjectArray buffers;
1228     status_t err = codec->getBuffers(env, input, &buffers);
1229
1230     if (err == OK) {
1231         return buffers;
1232     }
1233
1234     // if we're out of memory, an exception was already thrown
1235     if (err != NO_MEMORY) {
1236         throwExceptionAsNecessary(env, err);
1237     }
1238
1239     return NULL;
1240 }
1241
1242 static jobject android_media_MediaCodec_getBuffer(
1243         JNIEnv *env, jobject thiz, jboolean input, jint index) {
1244     ALOGV("android_media_MediaCodec_getBuffer");
1245
1246     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1247
1248     if (codec == NULL) {
1249         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1250         return NULL;
1251     }
1252
1253     jobject buffer;
1254     status_t err = codec->getBuffer(env, input, index, &buffer);
1255
1256     if (err == OK) {
1257         return buffer;
1258     }
1259
1260     // if we're out of memory, an exception was already thrown
1261     if (err != NO_MEMORY) {
1262         throwExceptionAsNecessary(env, err);
1263     }
1264
1265     return NULL;
1266 }
1267
1268 static jobject android_media_MediaCodec_getImage(
1269         JNIEnv *env, jobject thiz, jboolean input, jint index) {
1270     ALOGV("android_media_MediaCodec_getImage");
1271
1272     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1273
1274     if (codec == NULL) {
1275         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1276         return NULL;
1277     }
1278
1279     jobject image;
1280     status_t err = codec->getImage(env, input, index, &image);
1281
1282     if (err == OK) {
1283         return image;
1284     }
1285
1286     // if we're out of memory, an exception was already thrown
1287     if (err != NO_MEMORY) {
1288         throwExceptionAsNecessary(env, err);
1289     }
1290
1291     return NULL;
1292 }
1293
1294 static jobject android_media_MediaCodec_getName(
1295         JNIEnv *env, jobject thiz) {
1296     ALOGV("android_media_MediaCodec_getName");
1297
1298     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1299
1300     if (codec == NULL) {
1301         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1302         return NULL;
1303     }
1304
1305     jstring name;
1306     status_t err = codec->getName(env, &name);
1307
1308     if (err == OK) {
1309         return name;
1310     }
1311
1312     throwExceptionAsNecessary(env, err);
1313
1314     return NULL;
1315 }
1316
1317 static void android_media_MediaCodec_setParameters(
1318         JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1319     ALOGV("android_media_MediaCodec_setParameters");
1320
1321     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1322
1323     if (codec == NULL) {
1324         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1325         return;
1326     }
1327
1328     sp<AMessage> params;
1329     status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
1330
1331     if (err == OK) {
1332         err = codec->setParameters(params);
1333     }
1334
1335     throwExceptionAsNecessary(env, err);
1336 }
1337
1338 static void android_media_MediaCodec_setVideoScalingMode(
1339         JNIEnv *env, jobject thiz, jint mode) {
1340     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1341
1342     if (codec == NULL) {
1343         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1344         return;
1345     }
1346
1347     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1348             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
1349         jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
1350         return;
1351     }
1352
1353     codec->setVideoScalingMode(mode);
1354 }
1355
1356 static void android_media_MediaCodec_native_init(JNIEnv *env) {
1357     ScopedLocalRef<jclass> clazz(
1358             env, env->FindClass("android/media/MediaCodec"));
1359     CHECK(clazz.get() != NULL);
1360
1361     gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
1362     CHECK(gFields.context != NULL);
1363
1364     gFields.postEventFromNativeID =
1365         env->GetMethodID(
1366                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1367
1368     CHECK(gFields.postEventFromNativeID != NULL);
1369
1370     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1371     CHECK(clazz.get() != NULL);
1372
1373     gFields.cryptoInfoNumSubSamplesID =
1374         env->GetFieldID(clazz.get(), "numSubSamples", "I");
1375     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1376
1377     gFields.cryptoInfoNumBytesOfClearDataID =
1378         env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
1379     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1380
1381     gFields.cryptoInfoNumBytesOfEncryptedDataID =
1382         env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
1383     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1384
1385     gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
1386     CHECK(gFields.cryptoInfoKeyID != NULL);
1387
1388     gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
1389     CHECK(gFields.cryptoInfoIVID != NULL);
1390
1391     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
1392     CHECK(gFields.cryptoInfoModeID != NULL);
1393
1394     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1395     CHECK(clazz.get() != NULL);
1396
1397     jfieldID field;
1398     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
1399     CHECK(field != NULL);
1400     gCryptoErrorCodes.cryptoErrorNoKey =
1401         env->GetStaticIntField(clazz.get(), field);
1402
1403     field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
1404     CHECK(field != NULL);
1405     gCryptoErrorCodes.cryptoErrorKeyExpired =
1406         env->GetStaticIntField(clazz.get(), field);
1407
1408     field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
1409     CHECK(field != NULL);
1410     gCryptoErrorCodes.cryptoErrorResourceBusy =
1411         env->GetStaticIntField(clazz.get(), field);
1412 }
1413
1414 static void android_media_MediaCodec_native_setup(
1415         JNIEnv *env, jobject thiz,
1416         jstring name, jboolean nameIsType, jboolean encoder) {
1417     if (name == NULL) {
1418         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1419         return;
1420     }
1421
1422     const char *tmp = env->GetStringUTFChars(name, NULL);
1423
1424     if (tmp == NULL) {
1425         return;
1426     }
1427
1428     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
1429
1430     status_t err = codec->initCheck();
1431
1432     env->ReleaseStringUTFChars(name, tmp);
1433     tmp = NULL;
1434
1435     if (err != OK) {
1436         jniThrowException(
1437                 env,
1438                 "java/io/IOException",
1439                 "Failed to allocate component instance");
1440         return;
1441     }
1442
1443     codec->registerSelf();
1444
1445     setMediaCodec(env,thiz, codec);
1446 }
1447
1448 static void android_media_MediaCodec_native_finalize(
1449         JNIEnv *env, jobject thiz) {
1450     android_media_MediaCodec_release(env, thiz);
1451 }
1452
1453 static JNINativeMethod gMethods[] = {
1454     { "native_release", "()V", (void *)android_media_MediaCodec_release },
1455
1456     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1457
1458     { "native_setCallback",
1459       "(Landroid/media/MediaCodec$Callback;)V",
1460       (void *)android_media_MediaCodec_native_setCallback },
1461
1462     { "native_configure",
1463       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
1464       "Landroid/media/MediaCrypto;I)V",
1465       (void *)android_media_MediaCodec_native_configure },
1466
1467     { "createInputSurface", "()Landroid/view/Surface;",
1468       (void *)android_media_MediaCodec_createInputSurface },
1469
1470     { "native_start", "()V", (void *)android_media_MediaCodec_start },
1471     { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
1472     { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
1473
1474     { "native_queueInputBuffer", "(IIIJI)V",
1475       (void *)android_media_MediaCodec_queueInputBuffer },
1476
1477     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
1478       (void *)android_media_MediaCodec_queueSecureInputBuffer },
1479
1480     { "native_dequeueInputBuffer", "(J)I",
1481       (void *)android_media_MediaCodec_dequeueInputBuffer },
1482
1483     { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
1484       (void *)android_media_MediaCodec_dequeueOutputBuffer },
1485
1486     { "releaseOutputBuffer", "(IZZJ)V",
1487       (void *)android_media_MediaCodec_releaseOutputBuffer },
1488
1489     { "signalEndOfInputStream", "()V",
1490       (void *)android_media_MediaCodec_signalEndOfInputStream },
1491
1492     { "getFormatNative", "(Z)Ljava/util/Map;",
1493       (void *)android_media_MediaCodec_getFormatNative },
1494
1495     { "getOutputFormatNative", "(I)Ljava/util/Map;",
1496       (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
1497
1498     { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1499       (void *)android_media_MediaCodec_getBuffers },
1500
1501     { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
1502       (void *)android_media_MediaCodec_getBuffer },
1503
1504     { "getImage", "(ZI)Landroid/media/Image;",
1505       (void *)android_media_MediaCodec_getImage },
1506
1507     { "getName", "()Ljava/lang/String;",
1508       (void *)android_media_MediaCodec_getName },
1509
1510     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
1511       (void *)android_media_MediaCodec_setParameters },
1512
1513     { "setVideoScalingMode", "(I)V",
1514       (void *)android_media_MediaCodec_setVideoScalingMode },
1515
1516     { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
1517
1518     { "native_setup", "(Ljava/lang/String;ZZ)V",
1519       (void *)android_media_MediaCodec_native_setup },
1520
1521     { "native_finalize", "()V",
1522       (void *)android_media_MediaCodec_native_finalize },
1523 };
1524
1525 int register_android_media_MediaCodec(JNIEnv *env) {
1526     return AndroidRuntime::registerNativeMethods(env,
1527                 "android/media/MediaCodec", gMethods, NELEM(gMethods));
1528 }