2 * Copyright 2012, The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MediaCodec-JNI"
19 #include <utils/Log.h>
21 #include "android_media_MediaCodec.h"
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"
30 #include <cutils/compiler.h>
32 #include <gui/Surface.h>
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>
45 #include <system/window.h>
49 // Keep these in sync with their equivalents in MediaCodec.java !!!
51 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
52 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
53 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
58 EVENT_SET_CALLBACK = 2,
59 EVENT_FRAME_RENDERED = 3,
62 static struct CryptoErrorCodes {
63 jint cryptoErrorNoKey;
64 jint cryptoErrorKeyExpired;
65 jint cryptoErrorResourceBusy;
66 jint cryptoErrorInsufficientOutputProtection;
67 jint cryptoErrorSessionNotOpened;
70 static struct CodecActionCodes {
71 jint codecActionTransient;
72 jint codecActionRecoverable;
75 static struct CodecErrorCodes {
76 jint errorInsufficientResource;
83 jfieldID mPersistentObject;
85 jmethodID setNativeObjectLocked;
86 } gPersistentSurfaceClassInfo;
90 jmethodID postEventFromNativeID;
91 jfieldID cryptoInfoNumSubSamplesID;
92 jfieldID cryptoInfoNumBytesOfClearDataID;
93 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
94 jfieldID cryptoInfoKeyID;
95 jfieldID cryptoInfoIVID;
96 jfieldID cryptoInfoModeID;
99 static fields_t gFields;
100 static const void *sRefBaseOwner;
102 ////////////////////////////////////////////////////////////////////////////////
104 JMediaCodec::JMediaCodec(
105 JNIEnv *env, jobject thiz,
106 const char *name, bool nameIsType, bool encoder)
109 jclass clazz = env->GetObjectClass(thiz);
110 CHECK(clazz != NULL);
112 mClass = (jclass)env->NewGlobalRef(clazz);
113 mObject = env->NewWeakGlobalRef(thiz);
115 cacheJavaObjects(env);
117 mLooper = new ALooper;
118 mLooper->setName("MediaCodec_looper");
121 false, // runOnCallingThread
123 PRIORITY_FOREGROUND);
126 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
128 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
130 CHECK((mCodec != NULL) != (mInitStatus != OK));
133 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
134 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
135 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
136 CHECK(mByteBufferClass != NULL);
138 ScopedLocalRef<jclass> byteOrderClass(
139 env, env->FindClass("java/nio/ByteOrder"));
140 CHECK(byteOrderClass.get() != NULL);
142 jmethodID nativeOrderID = env->GetStaticMethodID(
143 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
144 CHECK(nativeOrderID != NULL);
146 jobject nativeByteOrderObj =
147 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
148 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
149 CHECK(mNativeByteOrderObj != NULL);
150 env->DeleteLocalRef(nativeByteOrderObj);
151 nativeByteOrderObj = NULL;
153 mByteBufferOrderMethodID = env->GetMethodID(
156 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
157 CHECK(mByteBufferOrderMethodID != NULL);
159 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
160 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
161 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
163 mByteBufferPositionMethodID = env->GetMethodID(
164 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
165 CHECK(mByteBufferPositionMethodID != NULL);
167 mByteBufferLimitMethodID = env->GetMethodID(
168 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
169 CHECK(mByteBufferLimitMethodID != NULL);
172 status_t JMediaCodec::initCheck() const {
176 void JMediaCodec::registerSelf() {
177 mLooper->registerHandler(this);
180 void JMediaCodec::release() {
181 if (mCodec != NULL) {
184 mInitStatus = NO_INIT;
187 if (mLooper != NULL) {
188 mLooper->unregisterHandler(id());
194 JMediaCodec::~JMediaCodec() {
195 if (mCodec != NULL || mLooper != NULL) {
196 /* MediaCodec and looper should have been released explicitly already
197 * in setMediaCodec() (see comments in setMediaCodec()).
199 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
200 * message handler, doing release() there risks deadlock as MediaCodec::
201 * release() post synchronous message to the same looper.
203 * Print a warning and try to proceed with releasing.
205 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
207 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
210 JNIEnv *env = AndroidRuntime::getJNIEnv();
212 env->DeleteWeakGlobalRef(mObject);
214 env->DeleteGlobalRef(mClass);
216 deleteJavaObjects(env);
219 void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
220 env->DeleteGlobalRef(mByteBufferClass);
221 mByteBufferClass = NULL;
222 env->DeleteGlobalRef(mNativeByteOrderObj);
223 mNativeByteOrderObj = NULL;
225 mByteBufferOrderMethodID = NULL;
226 mByteBufferAsReadOnlyBufferMethodID = NULL;
227 mByteBufferPositionMethodID = NULL;
228 mByteBufferLimitMethodID = NULL;
231 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
233 if (mOnFrameRenderedNotification == NULL) {
234 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
237 mOnFrameRenderedNotification.clear();
240 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
243 status_t JMediaCodec::setCallback(jobject cb) {
245 if (mCallbackNotification == NULL) {
246 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
249 mCallbackNotification.clear();
252 return mCodec->setCallback(mCallbackNotification);
255 status_t JMediaCodec::configure(
256 const sp<AMessage> &format,
257 const sp<IGraphicBufferProducer> &bufferProducer,
258 const sp<ICrypto> &crypto,
261 if (bufferProducer != NULL) {
262 mSurfaceTextureClient =
263 new Surface(bufferProducer, true /* controlledByApp */);
265 mSurfaceTextureClient.clear();
268 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
271 status_t JMediaCodec::setSurface(
272 const sp<IGraphicBufferProducer> &bufferProducer) {
274 if (bufferProducer != NULL) {
275 client = new Surface(bufferProducer, true /* controlledByApp */);
277 status_t err = mCodec->setSurface(client);
279 mSurfaceTextureClient = client;
284 status_t JMediaCodec::createInputSurface(
285 sp<IGraphicBufferProducer>* bufferProducer) {
286 return mCodec->createInputSurface(bufferProducer);
289 status_t JMediaCodec::setInputSurface(
290 const sp<PersistentSurface> &surface) {
291 return mCodec->setInputSurface(surface);
294 status_t JMediaCodec::start() {
295 return mCodec->start();
298 status_t JMediaCodec::stop() {
299 mSurfaceTextureClient.clear();
301 return mCodec->stop();
304 status_t JMediaCodec::flush() {
305 return mCodec->flush();
308 status_t JMediaCodec::reset() {
309 return mCodec->reset();
312 status_t JMediaCodec::queueInputBuffer(
314 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
315 AString *errorDetailMsg) {
316 return mCodec->queueInputBuffer(
317 index, offset, size, timeUs, flags, errorDetailMsg);
320 status_t JMediaCodec::queueSecureInputBuffer(
323 const CryptoPlugin::SubSample *subSamples,
324 size_t numSubSamples,
325 const uint8_t key[16],
326 const uint8_t iv[16],
327 CryptoPlugin::Mode mode,
328 int64_t presentationTimeUs,
330 AString *errorDetailMsg) {
331 return mCodec->queueSecureInputBuffer(
332 index, offset, subSamples, numSubSamples, key, iv, mode,
333 presentationTimeUs, flags, errorDetailMsg);
336 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
337 return mCodec->dequeueInputBuffer(index, timeoutUs);
340 status_t JMediaCodec::dequeueOutputBuffer(
341 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
345 status_t err = mCodec->dequeueOutputBuffer(
346 index, &offset, &size, &timeUs, &flags, timeoutUs);
352 ScopedLocalRef<jclass> clazz(
353 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
355 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
356 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
361 status_t JMediaCodec::releaseOutputBuffer(
362 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
364 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
367 ? mCodec->renderOutputBufferAndRelease(index)
368 : mCodec->releaseOutputBuffer(index);
371 status_t JMediaCodec::signalEndOfInputStream() {
372 return mCodec->signalEndOfInputStream();
375 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
378 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
383 return ConvertMessageToMap(env, msg, format);
386 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
389 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
393 return ConvertMessageToMap(env, msg, format);
396 status_t JMediaCodec::getBuffers(
397 JNIEnv *env, bool input, jobjectArray *bufArray) const {
398 Vector<sp<ABuffer> > buffers;
402 ? mCodec->getInputBuffers(&buffers)
403 : mCodec->getOutputBuffers(&buffers);
409 *bufArray = (jobjectArray)env->NewObjectArray(
410 buffers.size(), mByteBufferClass, NULL);
411 if (*bufArray == NULL) {
415 for (size_t i = 0; i < buffers.size(); ++i) {
416 const sp<ABuffer> &buffer = buffers.itemAt(i);
418 jobject byteBuffer = NULL;
419 err = createByteBufferFromABuffer(
420 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
424 if (byteBuffer != NULL) {
425 env->SetObjectArrayElement(
426 *bufArray, i, byteBuffer);
428 env->DeleteLocalRef(byteBuffer);
437 status_t JMediaCodec::createByteBufferFromABuffer(
438 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
439 jobject *buf) const {
440 // if this is an ABuffer that doesn't actually hold any accessible memory,
441 // use a null ByteBuffer
443 if (buffer->base() == NULL) {
448 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
449 if (readOnly && byteBuffer != NULL) {
450 jobject readOnlyBuffer = env->CallObjectMethod(
451 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
452 env->DeleteLocalRef(byteBuffer);
453 byteBuffer = readOnlyBuffer;
455 if (byteBuffer == NULL) {
458 jobject me = env->CallObjectMethod(
459 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
460 env->DeleteLocalRef(me);
461 me = env->CallObjectMethod(
462 byteBuffer, mByteBufferLimitMethodID,
463 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
464 env->DeleteLocalRef(me);
465 me = env->CallObjectMethod(
466 byteBuffer, mByteBufferPositionMethodID,
467 clearBuffer ? 0 : buffer->offset());
468 env->DeleteLocalRef(me);
475 status_t JMediaCodec::getBuffer(
476 JNIEnv *env, bool input, size_t index, jobject *buf) const {
481 ? mCodec->getInputBuffer(index, &buffer)
482 : mCodec->getOutputBuffer(index, &buffer);
488 return createByteBufferFromABuffer(
489 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
492 status_t JMediaCodec::getImage(
493 JNIEnv *env, bool input, size_t index, jobject *buf) const {
498 ? mCodec->getInputBuffer(index, &buffer)
499 : mCodec->getOutputBuffer(index, &buffer);
505 // if this is an ABuffer that doesn't actually hold any accessible memory,
506 // use a null ByteBuffer
508 if (buffer->base() == NULL) {
512 // check if buffer is an image
513 sp<ABuffer> imageData;
514 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
518 int64_t timestamp = 0;
519 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) {
520 timestamp *= 1000; // adjust to ns
523 jobject byteBuffer = NULL;
524 err = createByteBufferFromABuffer(
525 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
530 jobject infoBuffer = NULL;
531 err = createByteBufferFromABuffer(
532 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
534 env->DeleteLocalRef(byteBuffer);
539 jobject cropRect = NULL;
540 int32_t left, top, right, bottom;
541 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
542 ScopedLocalRef<jclass> rectClazz(
543 env, env->FindClass("android/graphics/Rect"));
544 CHECK(rectClazz.get() != NULL);
546 jmethodID rectConstructID = env->GetMethodID(
547 rectClazz.get(), "<init>", "(IIII)V");
549 cropRect = env->NewObject(
550 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
553 ScopedLocalRef<jclass> imageClazz(
554 env, env->FindClass("android/media/MediaCodec$MediaImage"));
555 CHECK(imageClazz.get() != NULL);
557 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
558 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
560 *buf = env->NewObject(imageClazz.get(), imageConstructID,
561 byteBuffer, infoBuffer,
562 (jboolean)!input /* readOnly */,
564 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
566 // if MediaImage creation fails, return null
567 if (env->ExceptionCheck()) {
568 env->ExceptionDescribe();
569 env->ExceptionClear();
573 if (cropRect != NULL) {
574 env->DeleteLocalRef(cropRect);
578 env->DeleteLocalRef(byteBuffer);
581 env->DeleteLocalRef(infoBuffer);
587 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
590 status_t err = mCodec->getName(&name);
596 *nameStr = env->NewStringUTF(name.c_str());
601 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
602 return mCodec->setParameters(msg);
605 void JMediaCodec::setVideoScalingMode(int mode) {
606 if (mSurfaceTextureClient != NULL) {
607 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
611 static jthrowable createCodecException(
612 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
613 ScopedLocalRef<jclass> clazz(
614 env, env->FindClass("android/media/MediaCodec$CodecException"));
615 CHECK(clazz.get() != NULL);
617 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
620 ScopedLocalRef<jstring> msgObj(
621 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
623 // translate action code to Java equivalent
624 switch (actionCode) {
625 case ACTION_CODE_TRANSIENT:
626 actionCode = gCodecActionCodes.codecActionTransient;
628 case ACTION_CODE_RECOVERABLE:
629 actionCode = gCodecActionCodes.codecActionRecoverable;
632 actionCode = 0; // everything else is fatal
636 /* translate OS errors to Java API CodecException errorCodes */
639 err = gCodecErrorCodes.errorInsufficientResource;
642 err = gCodecErrorCodes.errorReclaimed;
644 default: /* Other error codes go out as is. */
648 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
651 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
652 int32_t arg1, arg2 = 0;
654 CHECK(msg->findInt32("callbackID", &arg1));
655 JNIEnv *env = AndroidRuntime::getJNIEnv();
658 case MediaCodec::CB_INPUT_AVAILABLE:
660 CHECK(msg->findInt32("index", &arg2));
664 case MediaCodec::CB_OUTPUT_AVAILABLE:
666 CHECK(msg->findInt32("index", &arg2));
671 CHECK(msg->findSize("size", &size));
672 CHECK(msg->findSize("offset", &offset));
673 CHECK(msg->findInt64("timeUs", &timeUs));
674 CHECK(msg->findInt32("flags", (int32_t *)&flags));
676 ScopedLocalRef<jclass> clazz(
677 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
678 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
679 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
681 obj = env->NewObject(clazz.get(), ctor);
684 if (env->ExceptionCheck()) {
685 ALOGE("Could not create MediaCodec.BufferInfo.");
686 env->ExceptionClear();
688 jniThrowException(env, "java/lang/IllegalStateException", NULL);
692 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
696 case MediaCodec::CB_ERROR:
698 int32_t err, actionCode;
699 CHECK(msg->findInt32("err", &err));
700 CHECK(msg->findInt32("actionCode", &actionCode));
702 // note that DRM errors could conceivably alias into a CodecException
703 obj = (jobject)createCodecException(env, err, actionCode);
706 if (env->ExceptionCheck()) {
707 ALOGE("Could not create CodecException object.");
708 env->ExceptionClear();
710 jniThrowException(env, "java/lang/IllegalStateException", NULL);
717 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
720 CHECK(msg->findMessage("format", &format));
722 if (OK != ConvertMessageToMap(env, format, &obj)) {
723 jniThrowException(env, "java/lang/IllegalStateException", NULL);
736 gFields.postEventFromNativeID,
742 env->DeleteLocalRef(obj);
745 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
746 int32_t arg1 = 0, arg2 = 0;
748 JNIEnv *env = AndroidRuntime::getJNIEnv();
751 CHECK(msg->findMessage("data", &data));
753 status_t err = ConvertMessageToMap(env, data, &obj);
755 jniThrowException(env, "java/lang/IllegalStateException", NULL);
760 mObject, gFields.postEventFromNativeID,
761 EVENT_FRAME_RENDERED, arg1, arg2, obj);
763 env->DeleteLocalRef(obj);
766 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
767 switch (msg->what()) {
768 case kWhatCallbackNotify:
773 case kWhatFrameRendered:
775 handleFrameRenderedNotification(msg);
783 } // namespace android
785 ////////////////////////////////////////////////////////////////////////////////
787 using namespace android;
789 static sp<JMediaCodec> setMediaCodec(
790 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
791 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
793 codec->incStrong(thiz);
796 /* release MediaCodec and stop the looper now before decStrong.
797 * otherwise JMediaCodec::~JMediaCodec() could be called from within
798 * its message handler, doing release() from there will deadlock
799 * (as MediaCodec::release() post synchronous message to the same looper)
802 old->decStrong(thiz);
804 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
809 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
810 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
813 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
814 setMediaCodec(env, thiz, NULL);
817 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
818 jthrowable exception = createCodecException(env, err, actionCode, msg);
819 env->Throw(exception);
822 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
823 ScopedLocalRef<jclass> clazz(
824 env, env->FindClass("android/media/MediaCodec$CryptoException"));
825 CHECK(clazz.get() != NULL);
827 jmethodID constructID =
828 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
829 CHECK(constructID != NULL);
831 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
833 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
835 case ERROR_DRM_NO_LICENSE:
836 err = gCryptoErrorCodes.cryptoErrorNoKey;
838 case ERROR_DRM_LICENSE_EXPIRED:
839 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
841 case ERROR_DRM_RESOURCE_BUSY:
842 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
844 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
845 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
847 case ERROR_DRM_SESSION_NOT_OPENED:
848 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
850 default: /* Other negative DRM error codes go out as is. */
854 jthrowable exception =
855 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
857 env->Throw(exception);
860 static jint throwExceptionAsNecessary(
861 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
862 const char *msg = NULL) {
868 return DEQUEUE_INFO_TRY_AGAIN_LATER;
870 case INFO_FORMAT_CHANGED:
871 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
873 case INFO_OUTPUT_BUFFERS_CHANGED:
874 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
876 case INVALID_OPERATION:
877 jniThrowException(env, "java/lang/IllegalStateException", msg);
881 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
885 if (isCryptoError(err)) {
886 throwCryptoException(env, err, msg);
889 throwCodecException(env, err, actionCode, msg);
894 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
898 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
901 throwExceptionAsNecessary(env, INVALID_OPERATION);
905 status_t err = codec->enableOnFrameRenderedListener(enabled);
907 throwExceptionAsNecessary(env, err);
910 static void android_media_MediaCodec_native_setCallback(
914 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
917 throwExceptionAsNecessary(env, INVALID_OPERATION);
921 status_t err = codec->setCallback(cb);
923 throwExceptionAsNecessary(env, err);
926 static void android_media_MediaCodec_native_configure(
929 jobjectArray keys, jobjectArray values,
933 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
936 throwExceptionAsNecessary(env, INVALID_OPERATION);
941 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
944 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
948 sp<IGraphicBufferProducer> bufferProducer;
949 if (jsurface != NULL) {
950 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
951 if (surface != NULL) {
952 bufferProducer = surface->getIGraphicBufferProducer();
956 "java/lang/IllegalArgumentException",
957 "The surface has been released");
963 if (jcrypto != NULL) {
964 crypto = JCrypto::GetCrypto(env, jcrypto);
967 err = codec->configure(format, bufferProducer, crypto, flags);
969 throwExceptionAsNecessary(env, err);
972 static void android_media_MediaCodec_native_setSurface(
976 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
979 throwExceptionAsNecessary(env, INVALID_OPERATION);
983 sp<IGraphicBufferProducer> bufferProducer;
984 if (jsurface != NULL) {
985 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
986 if (surface != NULL) {
987 bufferProducer = surface->getIGraphicBufferProducer();
991 "java/lang/IllegalArgumentException",
992 "The surface has been released");
997 status_t err = codec->setSurface(bufferProducer);
998 throwExceptionAsNecessary(env, err);
1001 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1002 JNIEnv* env, jobject object) {
1003 sp<PersistentSurface> persistentSurface;
1005 jobject lock = env->GetObjectField(
1006 object, gPersistentSurfaceClassInfo.mLock);
1007 if (env->MonitorEnter(lock) == JNI_OK) {
1008 persistentSurface = reinterpret_cast<PersistentSurface *>(
1009 env->GetLongField(object,
1010 gPersistentSurfaceClassInfo.mPersistentObject));
1011 env->MonitorExit(lock);
1013 env->DeleteLocalRef(lock);
1015 return persistentSurface;
1018 static jobject android_media_MediaCodec_createPersistentInputSurface(
1019 JNIEnv* env, jclass /* clazz */) {
1020 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1021 sp<PersistentSurface> persistentSurface =
1022 MediaCodec::CreatePersistentInputSurface();
1024 if (persistentSurface == NULL) {
1028 sp<Surface> surface = new Surface(
1029 persistentSurface->getBufferProducer(), true);
1030 if (surface == NULL) {
1034 jobject object = env->NewObject(
1035 gPersistentSurfaceClassInfo.clazz,
1036 gPersistentSurfaceClassInfo.ctor);
1038 if (object == NULL) {
1039 if (env->ExceptionCheck()) {
1040 ALOGE("Could not create PersistentSurface.");
1041 env->ExceptionClear();
1046 jobject lock = env->GetObjectField(
1047 object, gPersistentSurfaceClassInfo.mLock);
1048 if (env->MonitorEnter(lock) == JNI_OK) {
1049 env->CallVoidMethod(
1051 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1052 (jlong)surface.get());
1055 gPersistentSurfaceClassInfo.mPersistentObject,
1056 (jlong)persistentSurface.get());
1057 env->MonitorExit(lock);
1059 env->DeleteLocalRef(object);
1062 env->DeleteLocalRef(lock);
1064 if (object != NULL) {
1065 surface->incStrong(&sRefBaseOwner);
1066 persistentSurface->incStrong(&sRefBaseOwner);
1072 static void android_media_MediaCodec_releasePersistentInputSurface(
1073 JNIEnv* env, jclass /* clazz */, jobject object) {
1074 sp<PersistentSurface> persistentSurface;
1076 jobject lock = env->GetObjectField(
1077 object, gPersistentSurfaceClassInfo.mLock);
1078 if (env->MonitorEnter(lock) == JNI_OK) {
1079 persistentSurface = reinterpret_cast<PersistentSurface *>(
1081 object, gPersistentSurfaceClassInfo.mPersistentObject));
1084 gPersistentSurfaceClassInfo.mPersistentObject,
1086 env->MonitorExit(lock);
1088 env->DeleteLocalRef(lock);
1090 if (persistentSurface != NULL) {
1091 persistentSurface->decStrong(&sRefBaseOwner);
1093 // no need to release surface as it will be released by Surface's jni
1096 static void android_media_MediaCodec_setInputSurface(
1097 JNIEnv* env, jobject thiz, jobject object) {
1098 ALOGV("android_media_MediaCodec_setInputSurface");
1100 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1101 if (codec == NULL) {
1102 throwExceptionAsNecessary(env, INVALID_OPERATION);
1106 sp<PersistentSurface> persistentSurface =
1107 android_media_MediaCodec_getPersistentInputSurface(env, object);
1109 status_t err = codec->setInputSurface(persistentSurface);
1110 if (err != NO_ERROR) {
1111 throwExceptionAsNecessary(env, err);
1115 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1117 ALOGV("android_media_MediaCodec_createInputSurface");
1119 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1120 if (codec == NULL) {
1121 throwExceptionAsNecessary(env, INVALID_OPERATION);
1125 // Tell the MediaCodec that we want to use a Surface as input.
1126 sp<IGraphicBufferProducer> bufferProducer;
1127 status_t err = codec->createInputSurface(&bufferProducer);
1128 if (err != NO_ERROR) {
1129 throwExceptionAsNecessary(env, err);
1133 // Wrap the IGBP in a Java-language Surface.
1134 return android_view_Surface_createFromIGraphicBufferProducer(env,
1138 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1139 ALOGV("android_media_MediaCodec_start");
1141 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1143 if (codec == NULL) {
1144 throwExceptionAsNecessary(env, INVALID_OPERATION);
1148 status_t err = codec->start();
1150 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
1153 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1154 ALOGV("android_media_MediaCodec_stop");
1156 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1158 if (codec == NULL) {
1159 throwExceptionAsNecessary(env, INVALID_OPERATION);
1163 status_t err = codec->stop();
1165 throwExceptionAsNecessary(env, err);
1168 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1169 ALOGV("android_media_MediaCodec_reset");
1171 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1173 if (codec == NULL) {
1174 throwExceptionAsNecessary(env, INVALID_OPERATION);
1178 status_t err = codec->reset();
1180 // treat all errors as fatal for now, though resource not available
1181 // errors could be treated as transient.
1182 // we also should avoid sending INVALID_OPERATION here due to
1183 // the transitory nature of reset(), it should not inadvertently
1184 // trigger an IllegalStateException.
1185 err = UNKNOWN_ERROR;
1187 throwExceptionAsNecessary(env, err);
1190 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1191 ALOGV("android_media_MediaCodec_flush");
1193 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1195 if (codec == NULL) {
1196 throwExceptionAsNecessary(env, INVALID_OPERATION);
1200 status_t err = codec->flush();
1202 throwExceptionAsNecessary(env, err);
1205 static void android_media_MediaCodec_queueInputBuffer(
1213 ALOGV("android_media_MediaCodec_queueInputBuffer");
1215 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1217 if (codec == NULL) {
1218 throwExceptionAsNecessary(env, INVALID_OPERATION);
1222 AString errorDetailMsg;
1224 status_t err = codec->queueInputBuffer(
1225 index, offset, size, timestampUs, flags, &errorDetailMsg);
1227 throwExceptionAsNecessary(
1228 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1231 static void android_media_MediaCodec_queueSecureInputBuffer(
1236 jobject cryptoInfoObj,
1239 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1241 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1243 if (codec == NULL) {
1244 throwExceptionAsNecessary(env, INVALID_OPERATION);
1248 jint numSubSamples =
1249 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1251 jintArray numBytesOfClearDataObj =
1252 (jintArray)env->GetObjectField(
1253 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1255 jintArray numBytesOfEncryptedDataObj =
1256 (jintArray)env->GetObjectField(
1257 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1260 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1263 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1265 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1269 CryptoPlugin::SubSample *subSamples = NULL;
1273 if (numSubSamples <= 0) {
1275 } else if (numBytesOfClearDataObj == NULL
1276 && numBytesOfEncryptedDataObj == NULL) {
1278 } else if (numBytesOfEncryptedDataObj != NULL
1279 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1281 } else if (numBytesOfClearDataObj != NULL
1282 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1284 // subSamples array may silently overflow if number of samples are too large. Use
1285 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1286 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1291 jint *numBytesOfClearData =
1292 (numBytesOfClearDataObj == NULL)
1294 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1296 jint *numBytesOfEncryptedData =
1297 (numBytesOfEncryptedDataObj == NULL)
1299 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1301 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1303 for (jint i = 0; i < numSubSamples; ++i) {
1304 subSamples[i].mNumBytesOfClearData =
1305 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1307 subSamples[i].mNumBytesOfEncryptedData =
1308 (numBytesOfEncryptedData == NULL)
1309 ? 0 : numBytesOfEncryptedData[i];
1312 if (numBytesOfEncryptedData != NULL) {
1313 env->ReleaseIntArrayElements(
1314 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1315 numBytesOfEncryptedData = NULL;
1318 if (numBytesOfClearData != NULL) {
1319 env->ReleaseIntArrayElements(
1320 numBytesOfClearDataObj, numBytesOfClearData, 0);
1321 numBytesOfClearData = NULL;
1325 if (err == OK && keyObj != NULL) {
1326 if (env->GetArrayLength(keyObj) != 16) {
1330 key = env->GetByteArrayElements(keyObj, &isCopy);
1334 if (err == OK && ivObj != NULL) {
1335 if (env->GetArrayLength(ivObj) != 16) {
1339 iv = env->GetByteArrayElements(ivObj, &isCopy);
1343 AString errorDetailMsg;
1346 err = codec->queueSecureInputBuffer(
1348 subSamples, numSubSamples,
1349 (const uint8_t *)key, (const uint8_t *)iv,
1350 (CryptoPlugin::Mode)mode,
1357 env->ReleaseByteArrayElements(ivObj, iv, 0);
1362 env->ReleaseByteArrayElements(keyObj, key, 0);
1366 delete[] subSamples;
1369 throwExceptionAsNecessary(
1370 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1373 static jint android_media_MediaCodec_dequeueInputBuffer(
1374 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1375 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1377 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1379 if (codec == NULL) {
1380 throwExceptionAsNecessary(env, INVALID_OPERATION);
1385 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1388 return (jint) index;
1391 return throwExceptionAsNecessary(env, err);
1394 static jint android_media_MediaCodec_dequeueOutputBuffer(
1395 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1396 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1398 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1400 if (codec == NULL) {
1401 throwExceptionAsNecessary(env, INVALID_OPERATION);
1406 status_t err = codec->dequeueOutputBuffer(
1407 env, bufferInfo, &index, timeoutUs);
1410 return (jint) index;
1413 return throwExceptionAsNecessary(env, err);
1416 static void android_media_MediaCodec_releaseOutputBuffer(
1417 JNIEnv *env, jobject thiz,
1418 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
1419 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1421 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1423 if (codec == NULL) {
1424 throwExceptionAsNecessary(env, INVALID_OPERATION);
1428 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
1430 throwExceptionAsNecessary(env, err);
1433 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1435 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1437 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1438 if (codec == NULL) {
1439 throwExceptionAsNecessary(env, INVALID_OPERATION);
1443 status_t err = codec->signalEndOfInputStream();
1445 throwExceptionAsNecessary(env, err);
1448 static jobject android_media_MediaCodec_getFormatNative(
1449 JNIEnv *env, jobject thiz, jboolean input) {
1450 ALOGV("android_media_MediaCodec_getFormatNative");
1452 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1454 if (codec == NULL) {
1455 throwExceptionAsNecessary(env, INVALID_OPERATION);
1460 status_t err = codec->getFormat(env, input, &format);
1466 throwExceptionAsNecessary(env, err);
1471 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1472 JNIEnv *env, jobject thiz, jint index) {
1473 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1475 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1477 if (codec == NULL) {
1478 throwExceptionAsNecessary(env, INVALID_OPERATION);
1483 status_t err = codec->getOutputFormat(env, index, &format);
1489 throwExceptionAsNecessary(env, err);
1494 static jobjectArray android_media_MediaCodec_getBuffers(
1495 JNIEnv *env, jobject thiz, jboolean input) {
1496 ALOGV("android_media_MediaCodec_getBuffers");
1498 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1500 if (codec == NULL) {
1501 throwExceptionAsNecessary(env, INVALID_OPERATION);
1505 jobjectArray buffers;
1506 status_t err = codec->getBuffers(env, input, &buffers);
1512 // if we're out of memory, an exception was already thrown
1513 if (err != NO_MEMORY) {
1514 throwExceptionAsNecessary(env, err);
1520 static jobject android_media_MediaCodec_getBuffer(
1521 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1522 ALOGV("android_media_MediaCodec_getBuffer");
1524 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1526 if (codec == NULL) {
1527 throwExceptionAsNecessary(env, INVALID_OPERATION);
1532 status_t err = codec->getBuffer(env, input, index, &buffer);
1538 // if we're out of memory, an exception was already thrown
1539 if (err != NO_MEMORY) {
1540 throwExceptionAsNecessary(env, err);
1546 static jobject android_media_MediaCodec_getImage(
1547 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1548 ALOGV("android_media_MediaCodec_getImage");
1550 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1552 if (codec == NULL) {
1553 throwExceptionAsNecessary(env, INVALID_OPERATION);
1558 status_t err = codec->getImage(env, input, index, &image);
1564 // if we're out of memory, an exception was already thrown
1565 if (err != NO_MEMORY) {
1566 throwExceptionAsNecessary(env, err);
1572 static jobject android_media_MediaCodec_getName(
1573 JNIEnv *env, jobject thiz) {
1574 ALOGV("android_media_MediaCodec_getName");
1576 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1578 if (codec == NULL) {
1579 throwExceptionAsNecessary(env, INVALID_OPERATION);
1584 status_t err = codec->getName(env, &name);
1590 throwExceptionAsNecessary(env, err);
1595 static void android_media_MediaCodec_setParameters(
1596 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1597 ALOGV("android_media_MediaCodec_setParameters");
1599 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1601 if (codec == NULL) {
1602 throwExceptionAsNecessary(env, INVALID_OPERATION);
1606 sp<AMessage> params;
1607 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms);
1610 err = codec->setParameters(params);
1613 throwExceptionAsNecessary(env, err);
1616 static void android_media_MediaCodec_setVideoScalingMode(
1617 JNIEnv *env, jobject thiz, jint mode) {
1618 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1620 if (codec == NULL) {
1621 throwExceptionAsNecessary(env, INVALID_OPERATION);
1625 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1626 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
1627 jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
1631 codec->setVideoScalingMode(mode);
1634 static void android_media_MediaCodec_native_init(JNIEnv *env) {
1635 ScopedLocalRef<jclass> clazz(
1636 env, env->FindClass("android/media/MediaCodec"));
1637 CHECK(clazz.get() != NULL);
1639 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
1640 CHECK(gFields.context != NULL);
1642 gFields.postEventFromNativeID =
1644 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1646 CHECK(gFields.postEventFromNativeID != NULL);
1648 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1649 CHECK(clazz.get() != NULL);
1651 gFields.cryptoInfoNumSubSamplesID =
1652 env->GetFieldID(clazz.get(), "numSubSamples", "I");
1653 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1655 gFields.cryptoInfoNumBytesOfClearDataID =
1656 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
1657 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1659 gFields.cryptoInfoNumBytesOfEncryptedDataID =
1660 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
1661 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1663 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
1664 CHECK(gFields.cryptoInfoKeyID != NULL);
1666 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
1667 CHECK(gFields.cryptoInfoIVID != NULL);
1669 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
1670 CHECK(gFields.cryptoInfoModeID != NULL);
1672 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1673 CHECK(clazz.get() != NULL);
1676 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
1677 CHECK(field != NULL);
1678 gCryptoErrorCodes.cryptoErrorNoKey =
1679 env->GetStaticIntField(clazz.get(), field);
1681 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
1682 CHECK(field != NULL);
1683 gCryptoErrorCodes.cryptoErrorKeyExpired =
1684 env->GetStaticIntField(clazz.get(), field);
1686 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
1687 CHECK(field != NULL);
1688 gCryptoErrorCodes.cryptoErrorResourceBusy =
1689 env->GetStaticIntField(clazz.get(), field);
1691 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1692 CHECK(field != NULL);
1693 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1694 env->GetStaticIntField(clazz.get(), field);
1696 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1697 CHECK(field != NULL);
1698 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1699 env->GetStaticIntField(clazz.get(), field);
1701 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
1702 CHECK(clazz.get() != NULL);
1703 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
1704 CHECK(field != NULL);
1705 gCodecActionCodes.codecActionTransient =
1706 env->GetStaticIntField(clazz.get(), field);
1708 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
1709 CHECK(field != NULL);
1710 gCodecActionCodes.codecActionRecoverable =
1711 env->GetStaticIntField(clazz.get(), field);
1713 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
1714 CHECK(field != NULL);
1715 gCodecErrorCodes.errorInsufficientResource =
1716 env->GetStaticIntField(clazz.get(), field);
1718 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
1719 CHECK(field != NULL);
1720 gCodecErrorCodes.errorReclaimed =
1721 env->GetStaticIntField(clazz.get(), field);
1723 clazz.reset(env->FindClass("android/view/Surface"));
1724 CHECK(clazz.get() != NULL);
1726 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
1727 CHECK(field != NULL);
1728 gPersistentSurfaceClassInfo.mLock = field;
1730 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
1731 CHECK(method != NULL);
1732 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
1734 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
1735 CHECK(clazz.get() != NULL);
1736 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
1738 method = env->GetMethodID(clazz.get(), "<init>", "()V");
1739 CHECK(method != NULL);
1740 gPersistentSurfaceClassInfo.ctor = method;
1742 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
1743 CHECK(field != NULL);
1744 gPersistentSurfaceClassInfo.mPersistentObject = field;
1747 static void android_media_MediaCodec_native_setup(
1748 JNIEnv *env, jobject thiz,
1749 jstring name, jboolean nameIsType, jboolean encoder) {
1751 jniThrowException(env, "java/lang/NullPointerException", NULL);
1755 const char *tmp = env->GetStringUTFChars(name, NULL);
1761 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
1763 const status_t err = codec->initCheck();
1764 if (err == NAME_NOT_FOUND) {
1765 // fail and do not try again.
1766 jniThrowException(env, "java/lang/IllegalArgumentException",
1767 String8::format("Failed to initialize %s, error %#x", tmp, err));
1768 env->ReleaseStringUTFChars(name, tmp);
1770 } if (err == NO_MEMORY) {
1771 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
1772 String8::format("Failed to initialize %s, error %#x", tmp, err));
1773 env->ReleaseStringUTFChars(name, tmp);
1775 } else if (err != OK) {
1776 // believed possible to try again
1777 jniThrowException(env, "java/io/IOException",
1778 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
1779 env->ReleaseStringUTFChars(name, tmp);
1783 env->ReleaseStringUTFChars(name, tmp);
1785 codec->registerSelf();
1787 setMediaCodec(env,thiz, codec);
1790 static void android_media_MediaCodec_native_finalize(
1791 JNIEnv *env, jobject thiz) {
1792 android_media_MediaCodec_release(env, thiz);
1795 static JNINativeMethod gMethods[] = {
1796 { "native_release", "()V", (void *)android_media_MediaCodec_release },
1798 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1800 { "native_releasePersistentInputSurface",
1801 "(Landroid/view/Surface;)V",
1802 (void *)android_media_MediaCodec_releasePersistentInputSurface},
1804 { "native_createPersistentInputSurface",
1805 "()Landroid/media/MediaCodec$PersistentSurface;",
1806 (void *)android_media_MediaCodec_createPersistentInputSurface },
1808 { "native_setInputSurface", "(Landroid/view/Surface;)V",
1809 (void *)android_media_MediaCodec_setInputSurface },
1811 { "native_enableOnFrameRenderedListener", "(Z)V",
1812 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
1814 { "native_setCallback",
1815 "(Landroid/media/MediaCodec$Callback;)V",
1816 (void *)android_media_MediaCodec_native_setCallback },
1818 { "native_configure",
1819 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
1820 "Landroid/media/MediaCrypto;I)V",
1821 (void *)android_media_MediaCodec_native_configure },
1823 { "native_setSurface",
1824 "(Landroid/view/Surface;)V",
1825 (void *)android_media_MediaCodec_native_setSurface },
1827 { "createInputSurface", "()Landroid/view/Surface;",
1828 (void *)android_media_MediaCodec_createInputSurface },
1830 { "native_start", "()V", (void *)android_media_MediaCodec_start },
1831 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
1832 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
1834 { "native_queueInputBuffer", "(IIIJI)V",
1835 (void *)android_media_MediaCodec_queueInputBuffer },
1837 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
1838 (void *)android_media_MediaCodec_queueSecureInputBuffer },
1840 { "native_dequeueInputBuffer", "(J)I",
1841 (void *)android_media_MediaCodec_dequeueInputBuffer },
1843 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
1844 (void *)android_media_MediaCodec_dequeueOutputBuffer },
1846 { "releaseOutputBuffer", "(IZZJ)V",
1847 (void *)android_media_MediaCodec_releaseOutputBuffer },
1849 { "signalEndOfInputStream", "()V",
1850 (void *)android_media_MediaCodec_signalEndOfInputStream },
1852 { "getFormatNative", "(Z)Ljava/util/Map;",
1853 (void *)android_media_MediaCodec_getFormatNative },
1855 { "getOutputFormatNative", "(I)Ljava/util/Map;",
1856 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
1858 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1859 (void *)android_media_MediaCodec_getBuffers },
1861 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
1862 (void *)android_media_MediaCodec_getBuffer },
1864 { "getImage", "(ZI)Landroid/media/Image;",
1865 (void *)android_media_MediaCodec_getImage },
1867 { "getName", "()Ljava/lang/String;",
1868 (void *)android_media_MediaCodec_getName },
1870 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
1871 (void *)android_media_MediaCodec_setParameters },
1873 { "setVideoScalingMode", "(I)V",
1874 (void *)android_media_MediaCodec_setVideoScalingMode },
1876 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
1878 { "native_setup", "(Ljava/lang/String;ZZ)V",
1879 (void *)android_media_MediaCodec_native_setup },
1881 { "native_finalize", "()V",
1882 (void *)android_media_MediaCodec_native_finalize },
1885 int register_android_media_MediaCodec(JNIEnv *env) {
1886 return AndroidRuntime::registerNativeMethods(env,
1887 "android/media/MediaCodec", gMethods, NELEM(gMethods));