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