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