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