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 <type_traits>
22 
23 #include "android_media_MediaCodec.h"
24 
25 #include "android_media_MediaCodecLinearBlock.h"
26 #include "android_media_MediaCrypto.h"
27 #include "android_media_MediaDescrambler.h"
28 #include "android_media_MediaMetricsJNI.h"
29 #include "android_media_Streams.h"
30 #include "android_runtime/AndroidRuntime.h"
31 #include "android_runtime/android_view_Surface.h"
32 #include "android_util_Binder.h"
33 #include "jni.h"
34 #include <nativehelper/JNIHelp.h>
35 #include <nativehelper/ScopedLocalRef.h>
36 
37 #include <C2AllocatorGralloc.h>
38 #include <C2BlockInternal.h>
39 #include <C2Buffer.h>
40 #include <C2PlatformSupport.h>
41 
42 #include <android/hardware/cas/native/1.0/IDescrambler.h>
43 
44 #include <android_runtime/android_hardware_HardwareBuffer.h>
45 
46 #include <binder/MemoryDealer.h>
47 
48 #include <cutils/compiler.h>
49 
50 #include <gui/Surface.h>
51 
52 #include <hidlmemory/FrameworkUtils.h>
53 
54 #include <media/MediaCodecBuffer.h>
55 #include <media/hardware/VideoAPI.h>
56 #include <media/stagefright/MediaCodec.h>
57 #include <media/stagefright/foundation/ABuffer.h>
58 #include <media/stagefright/foundation/ADebug.h>
59 #include <media/stagefright/foundation/ALooper.h>
60 #include <media/stagefright/foundation/AMessage.h>
61 #include <media/stagefright/foundation/AString.h>
62 #include <media/stagefright/MediaErrors.h>
63 #include <media/stagefright/PersistentSurface.h>
64 #include <mediadrm/ICrypto.h>
65 
66 #include <private/android/AHardwareBufferHelpers.h>
67 
68 #include <system/window.h>
69 
70 namespace android {
71 
72 // Keep these in sync with their equivalents in MediaCodec.java !!!
73 enum {
74     DEQUEUE_INFO_TRY_AGAIN_LATER            = -1,
75     DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED      = -2,
76     DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
77 };
78 
79 enum {
80     EVENT_CALLBACK = 1,
81     EVENT_SET_CALLBACK = 2,
82     EVENT_FRAME_RENDERED = 3,
83 };
84 
85 static struct CryptoErrorCodes {
86     jint cryptoErrorNoKey;
87     jint cryptoErrorKeyExpired;
88     jint cryptoErrorResourceBusy;
89     jint cryptoErrorInsufficientOutputProtection;
90     jint cryptoErrorSessionNotOpened;
91     jint cryptoErrorInsufficientSecurity;
92     jint cryptoErrorUnsupportedOperation;
93     jint cryptoErrorFrameTooLarge;
94     jint cryptoErrorLostState;
95 } gCryptoErrorCodes;
96 
97 static struct CodecActionCodes {
98     jint codecActionTransient;
99     jint codecActionRecoverable;
100 } gCodecActionCodes;
101 
102 static struct CodecErrorCodes {
103     jint errorInsufficientResource;
104     jint errorReclaimed;
105 } gCodecErrorCodes;
106 
107 static struct {
108     jclass clazz;
109     jfieldID mLock;
110     jfieldID mPersistentObject;
111     jmethodID ctor;
112     jmethodID setNativeObjectLocked;
113 } gPersistentSurfaceClassInfo;
114 
115 static struct {
116     jint Unencrypted;
117     jint AesCtr;
118     jint AesCbc;
119 } gCryptoModes;
120 
121 static struct {
122     jclass capsClazz;
123     jmethodID capsCtorId;
124     jclass profileLevelClazz;
125     jfieldID profileField;
126     jfieldID levelField;
127 } gCodecInfo;
128 
129 static struct {
130     jclass clazz;
131     jobject nativeByteOrder;
132     jmethodID orderId;
133     jmethodID asReadOnlyBufferId;
134     jmethodID positionId;
135     jmethodID limitId;
136     jmethodID getPositionId;
137     jmethodID getLimitId;
138 } gByteBufferInfo;
139 
140 static struct {
141     jmethodID sizeId;
142     jmethodID getId;
143     jmethodID addId;
144 } gArrayListInfo;
145 
146 static struct {
147     jclass clazz;
148     jmethodID ctorId;
149     jmethodID setInternalStateId;
150     jfieldID contextId;
151     jfieldID validId;
152     jfieldID lockId;
153 } gLinearBlockInfo;
154 
155 struct fields_t {
156     jmethodID postEventFromNativeID;
157     jmethodID lockAndGetContextID;
158     jmethodID setAndUnlockContextID;
159     jfieldID cryptoInfoNumSubSamplesID;
160     jfieldID cryptoInfoNumBytesOfClearDataID;
161     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
162     jfieldID cryptoInfoKeyID;
163     jfieldID cryptoInfoIVID;
164     jfieldID cryptoInfoModeID;
165     jfieldID cryptoInfoPatternID;
166     jfieldID patternEncryptBlocksID;
167     jfieldID patternSkipBlocksID;
168     jfieldID queueRequestIndexID;
169     jfieldID outputFrameLinearBlockID;
170     jfieldID outputFrameHardwareBufferID;
171     jfieldID outputFrameChangedKeysID;
172     jfieldID outputFrameFormatID;
173 };
174 
175 static fields_t gFields;
176 static const void *sRefBaseOwner;
177 
178 
179 ////////////////////////////////////////////////////////////////////////////////
180 
JMediaCodec(JNIEnv * env,jobject thiz,const char * name,bool nameIsType,bool encoder)181 JMediaCodec::JMediaCodec(
182         JNIEnv *env, jobject thiz,
183         const char *name, bool nameIsType, bool encoder)
184     : mClass(NULL),
185       mObject(NULL) {
186     jclass clazz = env->GetObjectClass(thiz);
187     CHECK(clazz != NULL);
188 
189     mClass = (jclass)env->NewGlobalRef(clazz);
190     mObject = env->NewWeakGlobalRef(thiz);
191 
192     mLooper = new ALooper;
193     mLooper->setName("MediaCodec_looper");
194 
195     mLooper->start(
196             false,      // runOnCallingThread
197             true,       // canCallJava
198             ANDROID_PRIORITY_VIDEO);
199 
200     if (nameIsType) {
201         mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
202         if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
203             mNameAtCreation = "(null)";
204         }
205     } else {
206         mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
207         mNameAtCreation = name;
208     }
209     CHECK((mCodec != NULL) != (mInitStatus != OK));
210 }
211 
initCheck() const212 status_t JMediaCodec::initCheck() const {
213     return mInitStatus;
214 }
215 
registerSelf()216 void JMediaCodec::registerSelf() {
217     mLooper->registerHandler(this);
218 }
219 
release()220 void JMediaCodec::release() {
221     std::call_once(mReleaseFlag, [this] {
222         if (mCodec != NULL) {
223             mCodec->release();
224             mInitStatus = NO_INIT;
225         }
226 
227         if (mLooper != NULL) {
228             mLooper->unregisterHandler(id());
229             mLooper->stop();
230             mLooper.clear();
231         }
232     });
233 }
234 
releaseAsync()235 void JMediaCodec::releaseAsync() {
236     std::call_once(mAsyncReleaseFlag, [this] {
237         if (mCodec != NULL) {
238             sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
239             // Hold strong reference to this until async release is complete
240             notify->setObject("this", this);
241             mCodec->releaseAsync(notify);
242         }
243         mInitStatus = NO_INIT;
244     });
245 }
246 
~JMediaCodec()247 JMediaCodec::~JMediaCodec() {
248     if (mLooper != NULL) {
249         /* MediaCodec and looper should have been released explicitly already
250          * in setMediaCodec() (see comments in setMediaCodec()).
251          *
252          * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
253          * message handler, doing release() there risks deadlock as MediaCodec::
254          * release() post synchronous message to the same looper.
255          *
256          * Print a warning and try to proceed with releasing.
257          */
258         ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
259         release();
260         ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
261     }
262 
263     JNIEnv *env = AndroidRuntime::getJNIEnv();
264 
265     env->DeleteWeakGlobalRef(mObject);
266     mObject = NULL;
267     env->DeleteGlobalRef(mClass);
268     mClass = NULL;
269 }
270 
enableOnFrameRenderedListener(jboolean enable)271 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
272     if (enable) {
273         if (mOnFrameRenderedNotification == NULL) {
274             mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
275         }
276     } else {
277         mOnFrameRenderedNotification.clear();
278     }
279 
280     return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
281 }
282 
setCallback(jobject cb)283 status_t JMediaCodec::setCallback(jobject cb) {
284     if (cb != NULL) {
285         if (mCallbackNotification == NULL) {
286             mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
287         }
288     } else {
289         mCallbackNotification.clear();
290     }
291 
292     return mCodec->setCallback(mCallbackNotification);
293 }
294 
configure(const sp<AMessage> & format,const sp<IGraphicBufferProducer> & bufferProducer,const sp<ICrypto> & crypto,const sp<IDescrambler> & descrambler,int flags)295 status_t JMediaCodec::configure(
296         const sp<AMessage> &format,
297         const sp<IGraphicBufferProducer> &bufferProducer,
298         const sp<ICrypto> &crypto,
299         const sp<IDescrambler> &descrambler,
300         int flags) {
301     sp<Surface> client;
302     if (bufferProducer != NULL) {
303         mSurfaceTextureClient =
304             new Surface(bufferProducer, true /* controlledByApp */);
305     } else {
306         mSurfaceTextureClient.clear();
307     }
308 
309     constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
310     AString mime;
311     CHECK(format->findString("mime", &mime));
312     mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
313             && !(flags & CONFIGURE_FLAG_ENCODE);
314     mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
315 
316     return mCodec->configure(
317             format, mSurfaceTextureClient, crypto, descrambler, flags);
318 }
319 
setSurface(const sp<IGraphicBufferProducer> & bufferProducer)320 status_t JMediaCodec::setSurface(
321         const sp<IGraphicBufferProducer> &bufferProducer) {
322     sp<Surface> client;
323     if (bufferProducer != NULL) {
324         client = new Surface(bufferProducer, true /* controlledByApp */);
325     }
326     status_t err = mCodec->setSurface(client);
327     if (err == OK) {
328         mSurfaceTextureClient = client;
329     }
330     return err;
331 }
332 
createInputSurface(sp<IGraphicBufferProducer> * bufferProducer)333 status_t JMediaCodec::createInputSurface(
334         sp<IGraphicBufferProducer>* bufferProducer) {
335     return mCodec->createInputSurface(bufferProducer);
336 }
337 
setInputSurface(const sp<PersistentSurface> & surface)338 status_t JMediaCodec::setInputSurface(
339         const sp<PersistentSurface> &surface) {
340     return mCodec->setInputSurface(surface);
341 }
342 
start()343 status_t JMediaCodec::start() {
344     return mCodec->start();
345 }
346 
stop()347 status_t JMediaCodec::stop() {
348     mSurfaceTextureClient.clear();
349 
350     return mCodec->stop();
351 }
352 
flush()353 status_t JMediaCodec::flush() {
354     return mCodec->flush();
355 }
356 
reset()357 status_t JMediaCodec::reset() {
358     return mCodec->reset();
359 }
360 
queueInputBuffer(size_t index,size_t offset,size_t size,int64_t timeUs,uint32_t flags,AString * errorDetailMsg)361 status_t JMediaCodec::queueInputBuffer(
362         size_t index,
363         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
364         AString *errorDetailMsg) {
365     return mCodec->queueInputBuffer(
366             index, offset, size, timeUs, flags, errorDetailMsg);
367 }
368 
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)369 status_t JMediaCodec::queueSecureInputBuffer(
370         size_t index,
371         size_t offset,
372         const CryptoPlugin::SubSample *subSamples,
373         size_t numSubSamples,
374         const uint8_t key[16],
375         const uint8_t iv[16],
376         CryptoPlugin::Mode mode,
377         const CryptoPlugin::Pattern &pattern,
378         int64_t presentationTimeUs,
379         uint32_t flags,
380         AString *errorDetailMsg) {
381     return mCodec->queueSecureInputBuffer(
382             index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
383             presentationTimeUs, flags, errorDetailMsg);
384 }
385 
queueBuffer(size_t index,const std::shared_ptr<C2Buffer> & buffer,int64_t timeUs,uint32_t flags,const sp<AMessage> & tunings,AString * errorDetailMsg)386 status_t JMediaCodec::queueBuffer(
387         size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
388         uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
389     return mCodec->queueBuffer(
390             index, buffer, timeUs, flags, tunings, errorDetailMsg);
391 }
392 
queueEncryptedLinearBlock(size_t index,const sp<hardware::HidlMemory> & buffer,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,const sp<AMessage> & tunings,AString * errorDetailMsg)393 status_t JMediaCodec::queueEncryptedLinearBlock(
394         size_t index,
395         const sp<hardware::HidlMemory> &buffer,
396         size_t offset,
397         const CryptoPlugin::SubSample *subSamples,
398         size_t numSubSamples,
399         const uint8_t key[16],
400         const uint8_t iv[16],
401         CryptoPlugin::Mode mode,
402         const CryptoPlugin::Pattern &pattern,
403         int64_t presentationTimeUs,
404         uint32_t flags,
405         const sp<AMessage> &tunings,
406         AString *errorDetailMsg) {
407     return mCodec->queueEncryptedBuffer(
408             index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
409             presentationTimeUs, flags, tunings, errorDetailMsg);
410 }
411 
dequeueInputBuffer(size_t * index,int64_t timeoutUs)412 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
413     return mCodec->dequeueInputBuffer(index, timeoutUs);
414 }
415 
dequeueOutputBuffer(JNIEnv * env,jobject bufferInfo,size_t * index,int64_t timeoutUs)416 status_t JMediaCodec::dequeueOutputBuffer(
417         JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
418     size_t size, offset;
419     int64_t timeUs;
420     uint32_t flags;
421     status_t err = mCodec->dequeueOutputBuffer(
422             index, &offset, &size, &timeUs, &flags, timeoutUs);
423 
424     if (err != OK) {
425         return err;
426     }
427 
428     ScopedLocalRef<jclass> clazz(
429             env, env->FindClass("android/media/MediaCodec$BufferInfo"));
430 
431     jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
432     env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
433 
434     return OK;
435 }
436 
releaseOutputBuffer(size_t index,bool render,bool updatePTS,int64_t timestampNs)437 status_t JMediaCodec::releaseOutputBuffer(
438         size_t index, bool render, bool updatePTS, int64_t timestampNs) {
439     if (updatePTS) {
440         return mCodec->renderOutputBufferAndRelease(index, timestampNs);
441     }
442     return render
443         ? mCodec->renderOutputBufferAndRelease(index)
444         : mCodec->releaseOutputBuffer(index);
445 }
446 
signalEndOfInputStream()447 status_t JMediaCodec::signalEndOfInputStream() {
448     return mCodec->signalEndOfInputStream();
449 }
450 
getFormat(JNIEnv * env,bool input,jobject * format) const451 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
452     sp<AMessage> msg;
453     status_t err;
454     err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
455     if (err != OK) {
456         return err;
457     }
458 
459     return ConvertMessageToMap(env, msg, format);
460 }
461 
getOutputFormat(JNIEnv * env,size_t index,jobject * format) const462 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
463     sp<AMessage> msg;
464     status_t err;
465     if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
466         return err;
467     }
468 
469     return ConvertMessageToMap(env, msg, format);
470 }
471 
getBuffers(JNIEnv * env,bool input,jobjectArray * bufArray) const472 status_t JMediaCodec::getBuffers(
473         JNIEnv *env, bool input, jobjectArray *bufArray) const {
474     Vector<sp<MediaCodecBuffer> > buffers;
475 
476     status_t err =
477         input
478             ? mCodec->getInputBuffers(&buffers)
479             : mCodec->getOutputBuffers(&buffers);
480 
481     if (err != OK) {
482         return err;
483     }
484 
485     *bufArray = (jobjectArray)env->NewObjectArray(
486             buffers.size(), gByteBufferInfo.clazz, NULL);
487     if (*bufArray == NULL) {
488         return NO_MEMORY;
489     }
490 
491     for (size_t i = 0; i < buffers.size(); ++i) {
492         const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
493 
494         jobject byteBuffer = NULL;
495         err = createByteBufferFromABuffer(
496                 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
497         if (err != OK) {
498             return err;
499         }
500         if (byteBuffer != NULL) {
501             env->SetObjectArrayElement(
502                     *bufArray, i, byteBuffer);
503 
504             env->DeleteLocalRef(byteBuffer);
505             byteBuffer = NULL;
506         }
507     }
508 
509     return OK;
510 }
511 
512 template <typename T>
CreateByteBuffer(JNIEnv * env,T * base,size_t capacity,size_t offset,size_t size,bool readOnly,bool clearBuffer)513 static jobject CreateByteBuffer(
514         JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
515         bool readOnly, bool clearBuffer) {
516     jobject byteBuffer =
517         env->NewDirectByteBuffer(
518                 const_cast<typename std::remove_const<T>::type *>(base),
519                 capacity);
520     if (readOnly && byteBuffer != NULL) {
521         jobject readOnlyBuffer = env->CallObjectMethod(
522                 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
523         env->DeleteLocalRef(byteBuffer);
524         byteBuffer = readOnlyBuffer;
525     }
526     if (byteBuffer == NULL) {
527         return nullptr;
528     }
529     jobject me = env->CallObjectMethod(
530             byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
531     env->DeleteLocalRef(me);
532     me = env->CallObjectMethod(
533             byteBuffer, gByteBufferInfo.limitId,
534             clearBuffer ? capacity : offset + size);
535     env->DeleteLocalRef(me);
536     me = env->CallObjectMethod(
537             byteBuffer, gByteBufferInfo.positionId,
538             clearBuffer ? 0 : offset);
539     env->DeleteLocalRef(me);
540     me = NULL;
541     return byteBuffer;
542 }
543 
544 
545 // static
546 template <typename T>
createByteBufferFromABuffer(JNIEnv * env,bool readOnly,bool clearBuffer,const sp<T> & buffer,jobject * buf) const547 status_t JMediaCodec::createByteBufferFromABuffer(
548         JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
549         jobject *buf) const {
550     // if this is an ABuffer that doesn't actually hold any accessible memory,
551     // use a null ByteBuffer
552     *buf = NULL;
553 
554     if (buffer == NULL) {
555         ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
556         return OK;
557     }
558 
559     if (buffer->base() == NULL) {
560         return OK;
561     }
562 
563     jobject byteBuffer = CreateByteBuffer(
564             env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
565             readOnly, clearBuffer);
566 
567     *buf = byteBuffer;
568     return OK;
569 }
570 
getBuffer(JNIEnv * env,bool input,size_t index,jobject * buf) const571 status_t JMediaCodec::getBuffer(
572         JNIEnv *env, bool input, size_t index, jobject *buf) const {
573     sp<MediaCodecBuffer> buffer;
574 
575     status_t err =
576         input
577             ? mCodec->getInputBuffer(index, &buffer)
578             : mCodec->getOutputBuffer(index, &buffer);
579 
580     if (err != OK) {
581         return err;
582     }
583 
584     return createByteBufferFromABuffer(
585             env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
586 }
587 
getImage(JNIEnv * env,bool input,size_t index,jobject * buf) const588 status_t JMediaCodec::getImage(
589         JNIEnv *env, bool input, size_t index, jobject *buf) const {
590     sp<MediaCodecBuffer> buffer;
591 
592     status_t err =
593         input
594             ? mCodec->getInputBuffer(index, &buffer)
595             : mCodec->getOutputBuffer(index, &buffer);
596 
597     if (err != OK) {
598         return err;
599     }
600 
601     // if this is an ABuffer that doesn't actually hold any accessible memory,
602     // use a null ByteBuffer
603     *buf = NULL;
604     if (buffer->base() == NULL) {
605         return OK;
606     }
607 
608     // check if buffer is an image
609     sp<ABuffer> imageData;
610     if (!buffer->meta()->findBuffer("image-data", &imageData)) {
611         return OK;
612     }
613 
614     int64_t timestamp = 0;
615     if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
616         timestamp *= 1000; // adjust to ns
617     }
618 
619     jobject byteBuffer = NULL;
620     err = createByteBufferFromABuffer(
621             env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
622     if (err != OK) {
623         return OK;
624     }
625 
626     jobject infoBuffer = NULL;
627     err = createByteBufferFromABuffer(
628             env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
629     if (err != OK) {
630         env->DeleteLocalRef(byteBuffer);
631         byteBuffer = NULL;
632         return OK;
633     }
634 
635     jobject cropRect = NULL;
636     int32_t left, top, right, bottom;
637     if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
638         ScopedLocalRef<jclass> rectClazz(
639                 env, env->FindClass("android/graphics/Rect"));
640         CHECK(rectClazz.get() != NULL);
641 
642         jmethodID rectConstructID = env->GetMethodID(
643                 rectClazz.get(), "<init>", "(IIII)V");
644 
645         cropRect = env->NewObject(
646                 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
647     }
648 
649     ScopedLocalRef<jclass> imageClazz(
650             env, env->FindClass("android/media/MediaCodec$MediaImage"));
651     CHECK(imageClazz.get() != NULL);
652 
653     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
654             "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
655 
656     *buf = env->NewObject(imageClazz.get(), imageConstructID,
657             byteBuffer, infoBuffer,
658             (jboolean)!input /* readOnly */,
659             (jlong)timestamp,
660             (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
661 
662     // if MediaImage creation fails, return null
663     if (env->ExceptionCheck()) {
664         env->ExceptionDescribe();
665         env->ExceptionClear();
666         *buf = NULL;
667     }
668 
669     if (cropRect != NULL) {
670         env->DeleteLocalRef(cropRect);
671         cropRect = NULL;
672     }
673 
674     env->DeleteLocalRef(byteBuffer);
675     byteBuffer = NULL;
676 
677     env->DeleteLocalRef(infoBuffer);
678     infoBuffer = NULL;
679 
680     return OK;
681 }
682 
getOutputFrame(JNIEnv * env,jobject frame,size_t index) const683 status_t JMediaCodec::getOutputFrame(
684         JNIEnv *env, jobject frame, size_t index) const {
685     sp<MediaCodecBuffer> buffer;
686 
687     status_t err = mCodec->getOutputBuffer(index, &buffer);
688     if (err != OK) {
689         return err;
690     }
691 
692     if (buffer->size() > 0) {
693         std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
694         if (c2Buffer) {
695             switch (c2Buffer->data().type()) {
696                 case C2BufferData::LINEAR: {
697                     std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
698                     context->mBuffer = c2Buffer;
699                     ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
700                             gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
701                     env->CallVoidMethod(
702                             linearBlock.get(),
703                             gLinearBlockInfo.setInternalStateId,
704                             (jlong)context.release(),
705                             true);
706                     env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
707                     break;
708                 }
709                 case C2BufferData::GRAPHIC: {
710                     const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
711                     uint32_t width, height, format, stride, igbp_slot, generation;
712                     uint64_t usage, igbp_id;
713                     _UnwrapNativeCodec2GrallocMetadata(
714                             c2Handle, &width, &height, &format, &usage, &stride, &generation,
715                             &igbp_id, &igbp_slot);
716                     native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
717                     GraphicBuffer* graphicBuffer = new GraphicBuffer(
718                             grallocHandle, GraphicBuffer::CLONE_HANDLE,
719                             width, height, format, 1, usage, stride);
720                     ScopedLocalRef<jobject> hardwareBuffer{
721                         env,
722                         android_hardware_HardwareBuffer_createFromAHardwareBuffer(
723                                 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
724                     env->SetObjectField(
725                             frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
726                     break;
727                 }
728                 case C2BufferData::LINEAR_CHUNKS:  [[fallthrough]];
729                 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
730                 case C2BufferData::INVALID:        [[fallthrough]];
731                 default:
732                     return INVALID_OPERATION;
733             }
734         } else {
735             if (!mGraphicOutput) {
736                 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
737                 context->mLegacyBuffer = buffer;
738                 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
739                         gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
740                 env->CallVoidMethod(
741                         linearBlock.get(),
742                         gLinearBlockInfo.setInternalStateId,
743                         (jlong)context.release(),
744                         true);
745                 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
746             } else {
747                 // No-op.
748             }
749         }
750     }
751 
752     jobject formatMap;
753     err = getOutputFormat(env, index, &formatMap);
754     if (err != OK) {
755         return err;
756     }
757     ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
758     ScopedLocalRef<jobject> format{env, env->NewObject(
759             mediaFormatClass.get(),
760             env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
761             formatMap)};
762     env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
763     env->DeleteLocalRef(formatMap);
764     formatMap = nullptr;
765 
766     sp<RefBase> obj;
767     if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
768         sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
769             (decltype(changedKeys.get()))obj.get()};
770         ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
771                 frame, gFields.outputFrameChangedKeysID)};
772         for (const std::string &key : changedKeys->value) {
773             ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
774             (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
775         }
776     }
777     return OK;
778 }
779 
780 
getName(JNIEnv * env,jstring * nameStr) const781 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
782     AString name;
783 
784     status_t err = mCodec->getName(&name);
785 
786     if (err != OK) {
787         return err;
788     }
789 
790     *nameStr = env->NewStringUTF(name.c_str());
791 
792     return OK;
793 }
794 
getCodecCapabilitiesObject(JNIEnv * env,const char * mime,bool isEncoder,const sp<MediaCodecInfo::Capabilities> & capabilities)795 static jobject getCodecCapabilitiesObject(
796         JNIEnv *env, const char *mime, bool isEncoder,
797         const sp<MediaCodecInfo::Capabilities> &capabilities) {
798     Vector<MediaCodecInfo::ProfileLevel> profileLevels;
799     Vector<uint32_t> colorFormats;
800 
801     sp<AMessage> defaultFormat = new AMessage();
802     defaultFormat->setString("mime", mime);
803 
804     capabilities->getSupportedColorFormats(&colorFormats);
805     capabilities->getSupportedProfileLevels(&profileLevels);
806     sp<AMessage> details = capabilities->getDetails();
807 
808     jobject defaultFormatObj = NULL;
809     if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
810         return NULL;
811     }
812     ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
813 
814     jobject detailsObj = NULL;
815     if (ConvertMessageToMap(env, details, &detailsObj)) {
816         return NULL;
817     }
818     ScopedLocalRef<jobject> detailsRef(env, detailsObj);
819 
820     ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
821             profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
822 
823     for (size_t i = 0; i < profileLevels.size(); ++i) {
824         const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
825 
826         ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
827                 gCodecInfo.profileLevelClazz));
828 
829         env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
830         env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
831 
832         env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
833     }
834 
835     ScopedLocalRef<jintArray> colorFormatsArray(
836             env, env->NewIntArray(colorFormats.size()));
837     for (size_t i = 0; i < colorFormats.size(); ++i) {
838         jint val = colorFormats.itemAt(i);
839         env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
840     }
841 
842     return env->NewObject(
843             gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
844             profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
845             defaultFormatRef.get(), detailsRef.get());
846 }
847 
getCodecInfo(JNIEnv * env,jobject * codecInfoObject) const848 status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
849     sp<MediaCodecInfo> codecInfo;
850 
851     status_t err = mCodec->getCodecInfo(&codecInfo);
852 
853     if (err != OK) {
854         return err;
855     }
856 
857     ScopedLocalRef<jstring> nameObject(env,
858             env->NewStringUTF(mNameAtCreation.c_str()));
859 
860     ScopedLocalRef<jstring> canonicalNameObject(env,
861             env->NewStringUTF(codecInfo->getCodecName()));
862 
863     MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
864     bool isEncoder = codecInfo->isEncoder();
865 
866     Vector<AString> mediaTypes;
867     codecInfo->getSupportedMediaTypes(&mediaTypes);
868 
869     ScopedLocalRef<jobjectArray> capsArrayObj(env,
870         env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
871 
872     for (size_t i = 0; i < mediaTypes.size(); i++) {
873         const sp<MediaCodecInfo::Capabilities> caps =
874                 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
875 
876         ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
877                 env, mediaTypes[i].c_str(), isEncoder, caps));
878 
879         env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
880     }
881 
882     ScopedLocalRef<jclass> codecInfoClazz(env,
883             env->FindClass("android/media/MediaCodecInfo"));
884     CHECK(codecInfoClazz.get() != NULL);
885 
886     jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
887             "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
888 
889     *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
890             nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
891 
892     return OK;
893 }
894 
getMetrics(JNIEnv *,mediametrics::Item * & reply) const895 status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
896     mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
897     status_t status = mCodec->getMetrics(reply2);
898     // getMetrics() updates reply2, pass the converted update along to our caller.
899     reply = mediametrics::Item::convert(reply2);
900     return status;
901 }
902 
setParameters(const sp<AMessage> & msg)903 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
904     return mCodec->setParameters(msg);
905 }
906 
setVideoScalingMode(int mode)907 void JMediaCodec::setVideoScalingMode(int mode) {
908     if (mSurfaceTextureClient != NULL) {
909         // this works for components that queue to surface
910         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
911         // also signal via param for components that queue to IGBP
912         sp<AMessage> msg = new AMessage;
913         msg->setInt32("android._video-scaling", mode);
914         (void)mCodec->setParameters(msg);
915     }
916 }
917 
selectAudioPresentation(const int32_t presentationId,const int32_t programId)918 void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
919     sp<AMessage> msg = new AMessage;
920     msg->setInt32("audio-presentation-presentation-id", presentationId);
921     msg->setInt32("audio-presentation-program-id", programId);
922     (void)mCodec->setParameters(msg);
923 }
924 
createCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg=NULL)925 static jthrowable createCodecException(
926         JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
927     ScopedLocalRef<jclass> clazz(
928             env, env->FindClass("android/media/MediaCodec$CodecException"));
929     CHECK(clazz.get() != NULL);
930 
931     const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
932     CHECK(ctor != NULL);
933 
934     ScopedLocalRef<jstring> msgObj(
935             env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
936 
937     // translate action code to Java equivalent
938     switch (actionCode) {
939     case ACTION_CODE_TRANSIENT:
940         actionCode = gCodecActionCodes.codecActionTransient;
941         break;
942     case ACTION_CODE_RECOVERABLE:
943         actionCode = gCodecActionCodes.codecActionRecoverable;
944         break;
945     default:
946         actionCode = 0;  // everything else is fatal
947         break;
948     }
949 
950     /* translate OS errors to Java API CodecException errorCodes */
951     switch (err) {
952         case NO_MEMORY:
953             err = gCodecErrorCodes.errorInsufficientResource;
954             break;
955         case DEAD_OBJECT:
956             err = gCodecErrorCodes.errorReclaimed;
957             break;
958         default:  /* Other error codes go out as is. */
959             break;
960     }
961 
962     return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
963 }
964 
handleCallback(const sp<AMessage> & msg)965 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
966     int32_t arg1, arg2 = 0;
967     jobject obj = NULL;
968     CHECK(msg->findInt32("callbackID", &arg1));
969     JNIEnv *env = AndroidRuntime::getJNIEnv();
970 
971     switch (arg1) {
972         case MediaCodec::CB_INPUT_AVAILABLE:
973         {
974             CHECK(msg->findInt32("index", &arg2));
975             break;
976         }
977 
978         case MediaCodec::CB_OUTPUT_AVAILABLE:
979         {
980             CHECK(msg->findInt32("index", &arg2));
981 
982             size_t size, offset;
983             int64_t timeUs;
984             uint32_t flags;
985             CHECK(msg->findSize("size", &size));
986             CHECK(msg->findSize("offset", &offset));
987             CHECK(msg->findInt64("timeUs", &timeUs));
988             CHECK(msg->findInt32("flags", (int32_t *)&flags));
989 
990             ScopedLocalRef<jclass> clazz(
991                     env, env->FindClass("android/media/MediaCodec$BufferInfo"));
992             jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
993             jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
994 
995             obj = env->NewObject(clazz.get(), ctor);
996 
997             if (obj == NULL) {
998                 if (env->ExceptionCheck()) {
999                     ALOGE("Could not create MediaCodec.BufferInfo.");
1000                     env->ExceptionClear();
1001                 }
1002                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1003                 return;
1004             }
1005 
1006             env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
1007             break;
1008         }
1009 
1010         case MediaCodec::CB_ERROR:
1011         {
1012             int32_t err, actionCode;
1013             CHECK(msg->findInt32("err", &err));
1014             CHECK(msg->findInt32("actionCode", &actionCode));
1015 
1016             // note that DRM errors could conceivably alias into a CodecException
1017             obj = (jobject)createCodecException(env, err, actionCode);
1018 
1019             if (obj == NULL) {
1020                 if (env->ExceptionCheck()) {
1021                     ALOGE("Could not create CodecException object.");
1022                     env->ExceptionClear();
1023                 }
1024                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1025                 return;
1026             }
1027 
1028             break;
1029         }
1030 
1031         case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
1032         {
1033             sp<AMessage> format;
1034             CHECK(msg->findMessage("format", &format));
1035 
1036             if (OK != ConvertMessageToMap(env, format, &obj)) {
1037                 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1038                 return;
1039             }
1040 
1041             break;
1042         }
1043 
1044         default:
1045             TRESPASS();
1046     }
1047 
1048     env->CallVoidMethod(
1049             mObject,
1050             gFields.postEventFromNativeID,
1051             EVENT_CALLBACK,
1052             arg1,
1053             arg2,
1054             obj);
1055 
1056     env->DeleteLocalRef(obj);
1057 }
1058 
handleFrameRenderedNotification(const sp<AMessage> & msg)1059 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1060     int32_t arg1 = 0, arg2 = 0;
1061     jobject obj = NULL;
1062     JNIEnv *env = AndroidRuntime::getJNIEnv();
1063 
1064     sp<AMessage> data;
1065     CHECK(msg->findMessage("data", &data));
1066 
1067     status_t err = ConvertMessageToMap(env, data, &obj);
1068     if (err != OK) {
1069         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1070         return;
1071     }
1072 
1073     env->CallVoidMethod(
1074             mObject, gFields.postEventFromNativeID,
1075             EVENT_FRAME_RENDERED, arg1, arg2, obj);
1076 
1077     env->DeleteLocalRef(obj);
1078 }
1079 
onMessageReceived(const sp<AMessage> & msg)1080 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1081     switch (msg->what()) {
1082         case kWhatCallbackNotify:
1083         {
1084             handleCallback(msg);
1085             break;
1086         }
1087         case kWhatFrameRendered:
1088         {
1089             handleFrameRenderedNotification(msg);
1090             break;
1091         }
1092         case kWhatAsyncReleaseComplete:
1093         {
1094             if (mLooper != NULL) {
1095                 mLooper->unregisterHandler(id());
1096                 mLooper->stop();
1097                 mLooper.clear();
1098             }
1099             break;
1100         }
1101         default:
1102             TRESPASS();
1103     }
1104 }
1105 
1106 }  // namespace android
1107 
1108 ////////////////////////////////////////////////////////////////////////////////
1109 
1110 using namespace android;
1111 
setMediaCodec(JNIEnv * env,jobject thiz,const sp<JMediaCodec> & codec,bool release=true)1112 static sp<JMediaCodec> setMediaCodec(
1113         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
1114     sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1115     if (codec != NULL) {
1116         codec->incStrong(thiz);
1117     }
1118     if (old != NULL) {
1119         /* release MediaCodec and stop the looper now before decStrong.
1120          * otherwise JMediaCodec::~JMediaCodec() could be called from within
1121          * its message handler, doing release() from there will deadlock
1122          * (as MediaCodec::release() post synchronous message to the same looper)
1123          */
1124         if (release) {
1125             old->release();
1126         }
1127         old->decStrong(thiz);
1128     }
1129     env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1130 
1131     return old;
1132 }
1133 
getMediaCodec(JNIEnv * env,jobject thiz)1134 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
1135     sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1136     env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1137     return codec;
1138 }
1139 
android_media_MediaCodec_release(JNIEnv * env,jobject thiz)1140 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
1141     // Clear Java native reference.
1142     sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
1143     if (codec != NULL) {
1144         codec->releaseAsync();
1145     }
1146 }
1147 
throwCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg)1148 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1149     jthrowable exception = createCodecException(env, err, actionCode, msg);
1150     env->Throw(exception);
1151 }
1152 
throwCryptoException(JNIEnv * env,status_t err,const char * msg)1153 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
1154     ScopedLocalRef<jclass> clazz(
1155             env, env->FindClass("android/media/MediaCodec$CryptoException"));
1156     CHECK(clazz.get() != NULL);
1157 
1158     jmethodID constructID =
1159         env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
1160     CHECK(constructID != NULL);
1161 
1162     const char *defaultMsg = "Unknown Error";
1163 
1164     /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
1165     switch (err) {
1166         case ERROR_DRM_NO_LICENSE:
1167             err = gCryptoErrorCodes.cryptoErrorNoKey;
1168             defaultMsg = "Crypto key not available";
1169             break;
1170         case ERROR_DRM_LICENSE_EXPIRED:
1171             err = gCryptoErrorCodes.cryptoErrorKeyExpired;
1172             defaultMsg = "License expired";
1173             break;
1174         case ERROR_DRM_RESOURCE_BUSY:
1175             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
1176             defaultMsg = "Resource busy or unavailable";
1177             break;
1178         case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1179             err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1180             defaultMsg = "Required output protections are not active";
1181             break;
1182         case ERROR_DRM_SESSION_NOT_OPENED:
1183             err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1184             defaultMsg = "Attempted to use a closed session";
1185             break;
1186         case ERROR_DRM_INSUFFICIENT_SECURITY:
1187             err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1188             defaultMsg = "Required security level is not met";
1189             break;
1190         case ERROR_DRM_CANNOT_HANDLE:
1191             err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1192             defaultMsg = "Operation not supported in this configuration";
1193             break;
1194         case ERROR_DRM_FRAME_TOO_LARGE:
1195             err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1196             defaultMsg = "Decrytped frame exceeds size of output buffer";
1197             break;
1198         case ERROR_DRM_SESSION_LOST_STATE:
1199             err = gCryptoErrorCodes.cryptoErrorLostState;
1200             defaultMsg = "Session state was lost, open a new session and retry";
1201             break;
1202         default:  /* Other negative DRM error codes go out as is. */
1203             break;
1204     }
1205 
1206     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
1207 
1208     jthrowable exception =
1209         (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
1210 
1211     env->Throw(exception);
1212 }
1213 
throwExceptionAsNecessary(JNIEnv * env,status_t err,int32_t actionCode=ACTION_CODE_FATAL,const char * msg=NULL)1214 static jint throwExceptionAsNecessary(
1215         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1216         const char *msg = NULL) {
1217     switch (err) {
1218         case OK:
1219             return 0;
1220 
1221         case -EAGAIN:
1222             return DEQUEUE_INFO_TRY_AGAIN_LATER;
1223 
1224         case INFO_FORMAT_CHANGED:
1225             return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1226 
1227         case INFO_OUTPUT_BUFFERS_CHANGED:
1228             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1229 
1230         case INVALID_OPERATION:
1231             jniThrowException(env, "java/lang/IllegalStateException", msg);
1232             return 0;
1233 
1234         case BAD_VALUE:
1235             jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1236             return 0;
1237 
1238         default:
1239             if (isCryptoError(err)) {
1240                 throwCryptoException(env, err, msg);
1241                 return 0;
1242             }
1243             throwCodecException(env, err, actionCode, msg);
1244             return 0;
1245     }
1246 }
1247 
android_media_MediaCodec_native_enableOnFrameRenderedListener(JNIEnv * env,jobject thiz,jboolean enabled)1248 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1249         JNIEnv *env,
1250         jobject thiz,
1251         jboolean enabled) {
1252     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1253 
1254     if (codec == NULL || codec->initCheck() != OK) {
1255         throwExceptionAsNecessary(env, INVALID_OPERATION);
1256         return;
1257     }
1258 
1259     status_t err = codec->enableOnFrameRenderedListener(enabled);
1260 
1261     throwExceptionAsNecessary(env, err);
1262 }
1263 
android_media_MediaCodec_native_setCallback(JNIEnv * env,jobject thiz,jobject cb)1264 static void android_media_MediaCodec_native_setCallback(
1265         JNIEnv *env,
1266         jobject thiz,
1267         jobject cb) {
1268     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1269 
1270     if (codec == NULL || codec->initCheck() != OK) {
1271         throwExceptionAsNecessary(env, INVALID_OPERATION);
1272         return;
1273     }
1274 
1275     status_t err = codec->setCallback(cb);
1276 
1277     throwExceptionAsNecessary(env, err);
1278 }
1279 
android_media_MediaCodec_native_configure(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray values,jobject jsurface,jobject jcrypto,jobject descramblerBinderObj,jint flags)1280 static void android_media_MediaCodec_native_configure(
1281         JNIEnv *env,
1282         jobject thiz,
1283         jobjectArray keys, jobjectArray values,
1284         jobject jsurface,
1285         jobject jcrypto,
1286         jobject descramblerBinderObj,
1287         jint flags) {
1288     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1289 
1290     if (codec == NULL || codec->initCheck() != OK) {
1291         throwExceptionAsNecessary(env, INVALID_OPERATION);
1292         return;
1293     }
1294 
1295     sp<AMessage> format;
1296     status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1297 
1298     if (err != OK) {
1299         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1300         return;
1301     }
1302 
1303     sp<IGraphicBufferProducer> bufferProducer;
1304     if (jsurface != NULL) {
1305         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1306         if (surface != NULL) {
1307             bufferProducer = surface->getIGraphicBufferProducer();
1308         } else {
1309             jniThrowException(
1310                     env,
1311                     "java/lang/IllegalArgumentException",
1312                     "The surface has been released");
1313             return;
1314         }
1315     }
1316 
1317     sp<ICrypto> crypto;
1318     if (jcrypto != NULL) {
1319         crypto = JCrypto::GetCrypto(env, jcrypto);
1320     }
1321 
1322     sp<IDescrambler> descrambler;
1323     if (descramblerBinderObj != NULL) {
1324         descrambler = GetDescrambler(env, descramblerBinderObj);
1325     }
1326 
1327     err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
1328 
1329     throwExceptionAsNecessary(env, err);
1330 }
1331 
android_media_MediaCodec_native_setSurface(JNIEnv * env,jobject thiz,jobject jsurface)1332 static void android_media_MediaCodec_native_setSurface(
1333         JNIEnv *env,
1334         jobject thiz,
1335         jobject jsurface) {
1336     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1337 
1338     if (codec == NULL || codec->initCheck() != OK) {
1339         throwExceptionAsNecessary(env, INVALID_OPERATION);
1340         return;
1341     }
1342 
1343     sp<IGraphicBufferProducer> bufferProducer;
1344     if (jsurface != NULL) {
1345         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1346         if (surface != NULL) {
1347             bufferProducer = surface->getIGraphicBufferProducer();
1348         } else {
1349             jniThrowException(
1350                     env,
1351                     "java/lang/IllegalArgumentException",
1352                     "The surface has been released");
1353             return;
1354         }
1355     }
1356 
1357     status_t err = codec->setSurface(bufferProducer);
1358     throwExceptionAsNecessary(env, err);
1359 }
1360 
android_media_MediaCodec_getPersistentInputSurface(JNIEnv * env,jobject object)1361 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1362         JNIEnv* env, jobject object) {
1363     sp<PersistentSurface> persistentSurface;
1364 
1365     jobject lock = env->GetObjectField(
1366             object, gPersistentSurfaceClassInfo.mLock);
1367     if (env->MonitorEnter(lock) == JNI_OK) {
1368         persistentSurface = reinterpret_cast<PersistentSurface *>(
1369                 env->GetLongField(object,
1370                         gPersistentSurfaceClassInfo.mPersistentObject));
1371         env->MonitorExit(lock);
1372     }
1373     env->DeleteLocalRef(lock);
1374 
1375     return persistentSurface;
1376 }
1377 
android_media_MediaCodec_createPersistentInputSurface(JNIEnv * env,jclass)1378 static jobject android_media_MediaCodec_createPersistentInputSurface(
1379         JNIEnv* env, jclass /* clazz */) {
1380     ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1381     sp<PersistentSurface> persistentSurface =
1382         MediaCodec::CreatePersistentInputSurface();
1383 
1384     if (persistentSurface == NULL) {
1385         return NULL;
1386     }
1387 
1388     sp<Surface> surface = new Surface(
1389             persistentSurface->getBufferProducer(), true);
1390     if (surface == NULL) {
1391         return NULL;
1392     }
1393 
1394     jobject object = env->NewObject(
1395             gPersistentSurfaceClassInfo.clazz,
1396             gPersistentSurfaceClassInfo.ctor);
1397 
1398     if (object == NULL) {
1399         if (env->ExceptionCheck()) {
1400             ALOGE("Could not create PersistentSurface.");
1401             env->ExceptionClear();
1402         }
1403         return NULL;
1404     }
1405 
1406     jobject lock = env->GetObjectField(
1407             object, gPersistentSurfaceClassInfo.mLock);
1408     if (env->MonitorEnter(lock) == JNI_OK) {
1409         env->CallVoidMethod(
1410                 object,
1411                 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1412                 (jlong)surface.get());
1413         env->SetLongField(
1414                 object,
1415                 gPersistentSurfaceClassInfo.mPersistentObject,
1416                 (jlong)persistentSurface.get());
1417         env->MonitorExit(lock);
1418     } else {
1419         env->DeleteLocalRef(object);
1420         object = NULL;
1421     }
1422     env->DeleteLocalRef(lock);
1423 
1424     if (object != NULL) {
1425         surface->incStrong(&sRefBaseOwner);
1426         persistentSurface->incStrong(&sRefBaseOwner);
1427     }
1428 
1429     return object;
1430 }
1431 
android_media_MediaCodec_releasePersistentInputSurface(JNIEnv * env,jclass,jobject object)1432 static void android_media_MediaCodec_releasePersistentInputSurface(
1433         JNIEnv* env, jclass /* clazz */, jobject object) {
1434     sp<PersistentSurface> persistentSurface;
1435 
1436     jobject lock = env->GetObjectField(
1437             object, gPersistentSurfaceClassInfo.mLock);
1438     if (env->MonitorEnter(lock) == JNI_OK) {
1439         persistentSurface = reinterpret_cast<PersistentSurface *>(
1440             env->GetLongField(
1441                     object, gPersistentSurfaceClassInfo.mPersistentObject));
1442         env->SetLongField(
1443                 object,
1444                 gPersistentSurfaceClassInfo.mPersistentObject,
1445                 (jlong)0);
1446         env->MonitorExit(lock);
1447     }
1448     env->DeleteLocalRef(lock);
1449 
1450     if (persistentSurface != NULL) {
1451         persistentSurface->decStrong(&sRefBaseOwner);
1452     }
1453     // no need to release surface as it will be released by Surface's jni
1454 }
1455 
android_media_MediaCodec_setInputSurface(JNIEnv * env,jobject thiz,jobject object)1456 static void android_media_MediaCodec_setInputSurface(
1457         JNIEnv* env, jobject thiz, jobject object) {
1458     ALOGV("android_media_MediaCodec_setInputSurface");
1459 
1460     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1461     if (codec == NULL || codec->initCheck() != OK) {
1462         throwExceptionAsNecessary(env, INVALID_OPERATION);
1463         return;
1464     }
1465 
1466     sp<PersistentSurface> persistentSurface =
1467         android_media_MediaCodec_getPersistentInputSurface(env, object);
1468 
1469     if (persistentSurface == NULL) {
1470         throwExceptionAsNecessary(
1471                 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1472         return;
1473     }
1474     status_t err = codec->setInputSurface(persistentSurface);
1475     if (err != NO_ERROR) {
1476         throwExceptionAsNecessary(env, err);
1477     }
1478 }
1479 
android_media_MediaCodec_createInputSurface(JNIEnv * env,jobject thiz)1480 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1481         jobject thiz) {
1482     ALOGV("android_media_MediaCodec_createInputSurface");
1483 
1484     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1485     if (codec == NULL || codec->initCheck() != OK) {
1486         throwExceptionAsNecessary(env, INVALID_OPERATION);
1487         return NULL;
1488     }
1489 
1490     // Tell the MediaCodec that we want to use a Surface as input.
1491     sp<IGraphicBufferProducer> bufferProducer;
1492     status_t err = codec->createInputSurface(&bufferProducer);
1493     if (err != NO_ERROR) {
1494         throwExceptionAsNecessary(env, err);
1495         return NULL;
1496     }
1497 
1498     // Wrap the IGBP in a Java-language Surface.
1499     return android_view_Surface_createFromIGraphicBufferProducer(env,
1500             bufferProducer);
1501 }
1502 
android_media_MediaCodec_start(JNIEnv * env,jobject thiz)1503 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1504     ALOGV("android_media_MediaCodec_start");
1505 
1506     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1507 
1508     if (codec == NULL || codec->initCheck() != OK) {
1509         throwExceptionAsNecessary(env, INVALID_OPERATION);
1510         return;
1511     }
1512 
1513     status_t err = codec->start();
1514 
1515     throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
1516 }
1517 
android_media_MediaCodec_stop(JNIEnv * env,jobject thiz)1518 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1519     ALOGV("android_media_MediaCodec_stop");
1520 
1521     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1522 
1523     if (codec == NULL || codec->initCheck() != OK) {
1524         throwExceptionAsNecessary(env, INVALID_OPERATION);
1525         return;
1526     }
1527 
1528     status_t err = codec->stop();
1529 
1530     throwExceptionAsNecessary(env, err);
1531 }
1532 
android_media_MediaCodec_reset(JNIEnv * env,jobject thiz)1533 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1534     ALOGV("android_media_MediaCodec_reset");
1535 
1536     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1537 
1538     if (codec == NULL || codec->initCheck() != OK) {
1539         throwExceptionAsNecessary(env, INVALID_OPERATION);
1540         return;
1541     }
1542 
1543     status_t err = codec->reset();
1544     if (err != OK) {
1545         // treat all errors as fatal for now, though resource not available
1546         // errors could be treated as transient.
1547         // we also should avoid sending INVALID_OPERATION here due to
1548         // the transitory nature of reset(), it should not inadvertently
1549         // trigger an IllegalStateException.
1550         err = UNKNOWN_ERROR;
1551     }
1552     throwExceptionAsNecessary(env, err);
1553 }
1554 
android_media_MediaCodec_flush(JNIEnv * env,jobject thiz)1555 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1556     ALOGV("android_media_MediaCodec_flush");
1557 
1558     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1559 
1560     if (codec == NULL || codec->initCheck() != OK) {
1561         throwExceptionAsNecessary(env, INVALID_OPERATION);
1562         return;
1563     }
1564 
1565     status_t err = codec->flush();
1566 
1567     throwExceptionAsNecessary(env, err);
1568 }
1569 
android_media_MediaCodec_queueInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jint size,jlong timestampUs,jint flags)1570 static void android_media_MediaCodec_queueInputBuffer(
1571         JNIEnv *env,
1572         jobject thiz,
1573         jint index,
1574         jint offset,
1575         jint size,
1576         jlong timestampUs,
1577         jint flags) {
1578     ALOGV("android_media_MediaCodec_queueInputBuffer");
1579 
1580     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1581 
1582     if (codec == NULL || codec->initCheck() != OK) {
1583         throwExceptionAsNecessary(env, INVALID_OPERATION);
1584         return;
1585     }
1586 
1587     AString errorDetailMsg;
1588 
1589     status_t err = codec->queueInputBuffer(
1590             index, offset, size, timestampUs, flags, &errorDetailMsg);
1591 
1592     throwExceptionAsNecessary(
1593             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1594 }
1595 
1596 struct NativeCryptoInfo {
NativeCryptoInfoNativeCryptoInfo1597     NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1598         : mEnv{env},
1599           mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1600           mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1601         mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1602 
1603         ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1604                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1605 
1606         ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1607                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1608 
1609         jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1610         if (jmode == gCryptoModes.Unencrypted) {
1611             mMode = CryptoPlugin::kMode_Unencrypted;
1612         } else if (jmode == gCryptoModes.AesCtr) {
1613             mMode = CryptoPlugin::kMode_AES_CTR;
1614         } else if (jmode == gCryptoModes.AesCbc) {
1615             mMode = CryptoPlugin::kMode_AES_CBC;
1616         }  else {
1617             throwExceptionAsNecessary(env, INVALID_OPERATION);
1618             return;
1619         }
1620 
1621         ScopedLocalRef<jobject> patternObj{
1622             env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1623 
1624         if (patternObj.get() == nullptr) {
1625             mPattern.mEncryptBlocks = 0;
1626             mPattern.mSkipBlocks = 0;
1627         } else {
1628             mPattern.mEncryptBlocks = env->GetIntField(
1629                     patternObj.get(), gFields.patternEncryptBlocksID);
1630             mPattern.mSkipBlocks = env->GetIntField(
1631                     patternObj.get(), gFields.patternSkipBlocksID);
1632         }
1633 
1634         mErr = OK;
1635         if (mNumSubSamples <= 0) {
1636             mErr = -EINVAL;
1637         } else if (numBytesOfClearDataObj == nullptr
1638                 && numBytesOfEncryptedDataObj == nullptr) {
1639             mErr = -EINVAL;
1640         } else if (numBytesOfEncryptedDataObj != nullptr
1641                 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1642             mErr = -ERANGE;
1643         } else if (numBytesOfClearDataObj != nullptr
1644                 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1645             mErr = -ERANGE;
1646         // subSamples array may silently overflow if number of samples are too large.  Use
1647         // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1648         } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1649             mErr = -EINVAL;
1650         } else {
1651             jint *numBytesOfClearData =
1652                 (numBytesOfClearDataObj == nullptr)
1653                     ? nullptr
1654                     : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1655 
1656             jint *numBytesOfEncryptedData =
1657                 (numBytesOfEncryptedDataObj == nullptr)
1658                     ? nullptr
1659                     : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1660 
1661             mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1662 
1663             for (jint i = 0; i < mNumSubSamples; ++i) {
1664                 mSubSamples[i].mNumBytesOfClearData =
1665                     (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1666 
1667                 mSubSamples[i].mNumBytesOfEncryptedData =
1668                     (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1669             }
1670 
1671             if (numBytesOfEncryptedData != nullptr) {
1672                 env->ReleaseIntArrayElements(
1673                         numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1674                 numBytesOfEncryptedData = nullptr;
1675             }
1676 
1677             if (numBytesOfClearData != nullptr) {
1678                 env->ReleaseIntArrayElements(
1679                         numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1680                 numBytesOfClearData = nullptr;
1681             }
1682         }
1683 
1684         if (mErr == OK && mKeyObj.get() != nullptr) {
1685             if (env->GetArrayLength(mKeyObj.get()) != 16) {
1686                 mErr = -EINVAL;
1687             } else {
1688                 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1689             }
1690         }
1691 
1692         if (mErr == OK && mIvObj.get() != nullptr) {
1693             if (env->GetArrayLength(mIvObj.get()) != 16) {
1694                 mErr = -EINVAL;
1695             } else {
1696                 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1697             }
1698         }
1699 
1700     }
1701 
NativeCryptoInfoNativeCryptoInfo1702     explicit NativeCryptoInfo(jint size)
1703         : mIvObj{nullptr, nullptr},
1704           mKeyObj{nullptr, nullptr},
1705           mMode{CryptoPlugin::kMode_Unencrypted},
1706           mPattern{0, 0} {
1707         mSubSamples = new CryptoPlugin::SubSample[1];
1708         mNumSubSamples = 1;
1709         mSubSamples[0].mNumBytesOfClearData = size;
1710         mSubSamples[0].mNumBytesOfEncryptedData = 0;
1711     }
1712 
~NativeCryptoInfoNativeCryptoInfo1713     ~NativeCryptoInfo() {
1714         if (mIv != nullptr) {
1715             mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1716         }
1717 
1718         if (mKey != nullptr) {
1719             mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1720         }
1721 
1722         if (mSubSamples != nullptr) {
1723             delete[] mSubSamples;
1724         }
1725     }
1726 
1727     JNIEnv *mEnv{nullptr};
1728     ScopedLocalRef<jbyteArray> mIvObj;
1729     ScopedLocalRef<jbyteArray> mKeyObj;
1730     status_t mErr{OK};
1731 
1732     CryptoPlugin::SubSample *mSubSamples{nullptr};
1733     int32_t mNumSubSamples{0};
1734     jbyte *mIv{nullptr};
1735     jbyte *mKey{nullptr};
1736     enum CryptoPlugin::Mode mMode;
1737     CryptoPlugin::Pattern mPattern;
1738 };
1739 
android_media_MediaCodec_queueSecureInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jobject cryptoInfoObj,jlong timestampUs,jint flags)1740 static void android_media_MediaCodec_queueSecureInputBuffer(
1741         JNIEnv *env,
1742         jobject thiz,
1743         jint index,
1744         jint offset,
1745         jobject cryptoInfoObj,
1746         jlong timestampUs,
1747         jint flags) {
1748     ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1749 
1750     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1751 
1752     if (codec == NULL || codec->initCheck() != OK) {
1753         throwExceptionAsNecessary(env, INVALID_OPERATION);
1754         return;
1755     }
1756 
1757     jint numSubSamples =
1758         env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1759 
1760     jintArray numBytesOfClearDataObj =
1761         (jintArray)env->GetObjectField(
1762                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1763 
1764     jintArray numBytesOfEncryptedDataObj =
1765         (jintArray)env->GetObjectField(
1766                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1767 
1768     jbyteArray keyObj =
1769         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1770 
1771     jbyteArray ivObj =
1772         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1773 
1774     jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1775     enum CryptoPlugin::Mode mode;
1776     if (jmode == gCryptoModes.Unencrypted) {
1777         mode = CryptoPlugin::kMode_Unencrypted;
1778     } else if (jmode == gCryptoModes.AesCtr) {
1779         mode = CryptoPlugin::kMode_AES_CTR;
1780     } else if (jmode == gCryptoModes.AesCbc) {
1781         mode = CryptoPlugin::kMode_AES_CBC;
1782     }  else {
1783         throwExceptionAsNecessary(env, INVALID_OPERATION);
1784         return;
1785     }
1786 
1787     jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1788 
1789     CryptoPlugin::Pattern pattern;
1790     if (patternObj == NULL) {
1791         pattern.mEncryptBlocks = 0;
1792         pattern.mSkipBlocks = 0;
1793     } else {
1794         pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1795         pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1796     }
1797 
1798     status_t err = OK;
1799 
1800     CryptoPlugin::SubSample *subSamples = NULL;
1801     jbyte *key = NULL;
1802     jbyte *iv = NULL;
1803 
1804     if (numSubSamples <= 0) {
1805         err = -EINVAL;
1806     } else if (numBytesOfClearDataObj == NULL
1807             && numBytesOfEncryptedDataObj == NULL) {
1808         err = -EINVAL;
1809     } else if (numBytesOfEncryptedDataObj != NULL
1810             && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1811         err = -ERANGE;
1812     } else if (numBytesOfClearDataObj != NULL
1813             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1814         err = -ERANGE;
1815     // subSamples array may silently overflow if number of samples are too large.  Use
1816     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1817     } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1818         err = -EINVAL;
1819     } else {
1820         jboolean isCopy;
1821 
1822         jint *numBytesOfClearData =
1823             (numBytesOfClearDataObj == NULL)
1824                 ? NULL
1825                 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1826 
1827         jint *numBytesOfEncryptedData =
1828             (numBytesOfEncryptedDataObj == NULL)
1829                 ? NULL
1830                 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1831 
1832         subSamples = new CryptoPlugin::SubSample[numSubSamples];
1833 
1834         for (jint i = 0; i < numSubSamples; ++i) {
1835             subSamples[i].mNumBytesOfClearData =
1836                 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1837 
1838             subSamples[i].mNumBytesOfEncryptedData =
1839                 (numBytesOfEncryptedData == NULL)
1840                     ? 0 : numBytesOfEncryptedData[i];
1841         }
1842 
1843         if (numBytesOfEncryptedData != NULL) {
1844             env->ReleaseIntArrayElements(
1845                     numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1846             numBytesOfEncryptedData = NULL;
1847         }
1848 
1849         if (numBytesOfClearData != NULL) {
1850             env->ReleaseIntArrayElements(
1851                     numBytesOfClearDataObj, numBytesOfClearData, 0);
1852             numBytesOfClearData = NULL;
1853         }
1854     }
1855 
1856     if (err == OK && keyObj != NULL) {
1857         if (env->GetArrayLength(keyObj) != 16) {
1858             err = -EINVAL;
1859         } else {
1860             jboolean isCopy;
1861             key = env->GetByteArrayElements(keyObj, &isCopy);
1862         }
1863     }
1864 
1865     if (err == OK && ivObj != NULL) {
1866         if (env->GetArrayLength(ivObj) != 16) {
1867             err = -EINVAL;
1868         } else {
1869             jboolean isCopy;
1870             iv = env->GetByteArrayElements(ivObj, &isCopy);
1871         }
1872     }
1873 
1874     AString errorDetailMsg;
1875 
1876     if (err == OK) {
1877         err = codec->queueSecureInputBuffer(
1878                 index, offset,
1879                 subSamples, numSubSamples,
1880                 (const uint8_t *)key, (const uint8_t *)iv,
1881                 mode,
1882                 pattern,
1883                 timestampUs,
1884                 flags,
1885                 &errorDetailMsg);
1886     }
1887 
1888     if (iv != NULL) {
1889         env->ReleaseByteArrayElements(ivObj, iv, 0);
1890         iv = NULL;
1891     }
1892 
1893     if (key != NULL) {
1894         env->ReleaseByteArrayElements(keyObj, key, 0);
1895         key = NULL;
1896     }
1897 
1898     delete[] subSamples;
1899     subSamples = NULL;
1900 
1901     throwExceptionAsNecessary(
1902             env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1903 }
1904 
android_media_MediaCodec_mapHardwareBuffer(JNIEnv * env,jclass,jobject bufferObj)1905 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
1906     ALOGV("android_media_MediaCodec_mapHardwareBuffer");
1907     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
1908             env, bufferObj);
1909     AHardwareBuffer_Desc desc;
1910     AHardwareBuffer_describe(hardwareBuffer, &desc);
1911     if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
1912         ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
1913         return nullptr;
1914     }
1915     if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
1916         ALOGI("mapHardwareBuffer: buffer not CPU readable");
1917         return nullptr;
1918     }
1919     bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
1920 
1921     uint64_t cpuUsage = 0;
1922     cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
1923     cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
1924 
1925     AHardwareBuffer_Planes planes;
1926     int err = AHardwareBuffer_lockPlanes(
1927             hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
1928     if (err != 0) {
1929         ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
1930         return nullptr;
1931     }
1932 
1933     if (planes.planeCount != 3) {
1934         ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
1935         return nullptr;
1936     }
1937 
1938     ScopedLocalRef<jobjectArray> buffersArray{
1939             env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
1940     ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
1941     ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
1942 
1943     jboolean isCopy = JNI_FALSE;
1944     jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1945     jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1946 
1947     // For Y plane
1948     int rowSampling = 1;
1949     int colSampling = 1;
1950     // plane indices are Y-U-V.
1951     for (uint32_t i = 0; i < 3; ++i) {
1952         const AHardwareBuffer_Plane &plane = planes.planes[i];
1953         int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
1954         int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
1955         int maxOffset = maxRowOffset + maxColOffset;
1956         ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
1957                 env,
1958                 plane.data,
1959                 maxOffset + 1,
1960                 0,
1961                 maxOffset + 1,
1962                 readOnly,
1963                 true)};
1964 
1965         env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
1966         rowStrides[i] = plane.rowStride;
1967         pixelStrides[i] = plane.pixelStride;
1968         // For U-V planes
1969         rowSampling = 2;
1970         colSampling = 2;
1971     }
1972 
1973     env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
1974     env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
1975     rowStrides = pixelStrides = nullptr;
1976 
1977     ScopedLocalRef<jclass> imageClazz(
1978             env, env->FindClass("android/media/MediaCodec$MediaImage"));
1979     CHECK(imageClazz.get() != NULL);
1980 
1981     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
1982             "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
1983 
1984     jobject img = env->NewObject(imageClazz.get(), imageConstructID,
1985             buffersArray.get(),
1986             rowStridesArray.get(),
1987             pixelStridesArray.get(),
1988             desc.width,
1989             desc.height,
1990             desc.format, // ???
1991             (jboolean)readOnly /* readOnly */,
1992             (jlong)0 /* timestamp */,
1993             (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
1994             (jlong)hardwareBuffer);
1995 
1996     // if MediaImage creation fails, return null
1997     if (env->ExceptionCheck()) {
1998         env->ExceptionDescribe();
1999         env->ExceptionClear();
2000         return nullptr;
2001     }
2002 
2003     AHardwareBuffer_acquire(hardwareBuffer);
2004 
2005     return img;
2006 }
2007 
android_media_MediaCodec_closeMediaImage(JNIEnv *,jclass,jlong context)2008 static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2009     ALOGV("android_media_MediaCodec_closeMediaImage");
2010     if (context == 0) {
2011         return;
2012     }
2013     AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2014 
2015     int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2016     if (err != 0) {
2017         ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2018         // Continue to release the hardwareBuffer
2019     }
2020 
2021     AHardwareBuffer_release(hardwareBuffer);
2022 }
2023 
ConvertKeyValueListsToAMessage(JNIEnv * env,jobject keys,jobject values,sp<AMessage> * msg)2024 static status_t ConvertKeyValueListsToAMessage(
2025         JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2026     static struct Fields {
2027         explicit Fields(JNIEnv *env) {
2028             ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2029             CHECK(clazz.get() != NULL);
2030             mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2031 
2032             clazz.reset(env->FindClass("java/lang/Integer"));
2033             CHECK(clazz.get() != NULL);
2034             mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2035 
2036             mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2037             CHECK(mIntegerValueId != NULL);
2038 
2039             clazz.reset(env->FindClass("java/lang/Long"));
2040             CHECK(clazz.get() != NULL);
2041             mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2042 
2043             mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2044             CHECK(mLongValueId != NULL);
2045 
2046             clazz.reset(env->FindClass("java/lang/Float"));
2047             CHECK(clazz.get() != NULL);
2048             mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2049 
2050             mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2051             CHECK(mFloatValueId != NULL);
2052 
2053             clazz.reset(env->FindClass("java/util/ArrayList"));
2054             CHECK(clazz.get() != NULL);
2055 
2056             mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2057             CHECK(mByteBufferArrayId != NULL);
2058         }
2059 
2060         jclass mStringClass;
2061         jclass mIntegerClass;
2062         jmethodID mIntegerValueId;
2063         jclass mLongClass;
2064         jmethodID mLongValueId;
2065         jclass mFloatClass;
2066         jmethodID mFloatValueId;
2067         jmethodID mByteBufferArrayId;
2068     } sFields{env};
2069 
2070     jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2071     if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2072         return BAD_VALUE;
2073     }
2074 
2075     sp<AMessage> result{new AMessage};
2076     for (jint i = 0; i < size; ++i) {
2077         ScopedLocalRef<jstring> jkey{
2078             env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2079         const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2080         AString key;
2081         if (tmp) {
2082             key.setTo(tmp);
2083         }
2084         env->ReleaseStringUTFChars(jkey.get(), tmp);
2085         if (key.empty()) {
2086             return NO_MEMORY;
2087         }
2088 
2089         ScopedLocalRef<jobject> jvalue{
2090             env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2091 
2092         if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2093             const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2094             AString value;
2095             if (!tmp) {
2096                 return NO_MEMORY;
2097             }
2098             value.setTo(tmp);
2099             env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
2100             result->setString(key.c_str(), value);
2101         } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2102             jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2103             result->setInt32(key.c_str(), value);
2104         } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2105             jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2106             result->setInt64(key.c_str(), value);
2107         } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2108             jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2109             result->setFloat(key.c_str(), value);
2110         } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
2111             jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2112             jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
2113             sp<ABuffer> buffer{new ABuffer(limit - position)};
2114             void *data = env->GetDirectBufferAddress(jvalue.get());
2115             if (data != nullptr) {
2116                 memcpy(buffer->data(),
2117                        static_cast<const uint8_t *>(data) + position,
2118                        buffer->size());
2119             } else {
2120                 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2121                         jvalue.get(), sFields.mByteBufferArrayId)};
2122                 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2123                                         reinterpret_cast<jbyte *>(buffer->data()));
2124             }
2125             result->setBuffer(key.c_str(), buffer);
2126         }
2127     }
2128 
2129     *msg = result;
2130     return OK;
2131 }
2132 
android_media_MediaCodec_native_queueLinearBlock(JNIEnv * env,jobject thiz,jint index,jobject bufferObj,jint offset,jint size,jobject cryptoInfoObj,jlong presentationTimeUs,jint flags,jobject keys,jobject values)2133 static void android_media_MediaCodec_native_queueLinearBlock(
2134         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2135         jint offset, jint size, jobject cryptoInfoObj,
2136         jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2137     ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2138 
2139     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2140 
2141     if (codec == nullptr || codec->initCheck() != OK) {
2142         throwExceptionAsNecessary(env, INVALID_OPERATION);
2143         return;
2144     }
2145 
2146     sp<AMessage> tunings;
2147     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2148     if (err != OK) {
2149         throwExceptionAsNecessary(env, err);
2150         return;
2151     }
2152 
2153     std::shared_ptr<C2Buffer> buffer;
2154     sp<hardware::HidlMemory> memory;
2155     ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2156     if (env->MonitorEnter(lock.get()) == JNI_OK) {
2157         if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2158             JMediaCodecLinearBlock *context =
2159                 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
2160             if (codec->hasCryptoOrDescrambler()) {
2161                 memory = context->toHidlMemory();
2162                 // TODO: copy if memory is null
2163                 offset += context->mHidlMemoryOffset;
2164             } else {
2165                 buffer = context->toC2Buffer(offset, size);
2166                 // TODO: copy if buffer is null
2167             }
2168         }
2169         env->MonitorExit(lock.get());
2170     } else {
2171         throwExceptionAsNecessary(env, INVALID_OPERATION);
2172         return;
2173     }
2174 
2175     AString errorDetailMsg;
2176     if (codec->hasCryptoOrDescrambler()) {
2177         if (!memory) {
2178             ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
2179             throwExceptionAsNecessary(env, BAD_VALUE);
2180             return;
2181         }
2182         NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
2183             if (cryptoInfoObj == nullptr) {
2184                 return NativeCryptoInfo{size};
2185             } else {
2186                 return NativeCryptoInfo{env, cryptoInfoObj};
2187             }
2188         }();
2189         err = codec->queueEncryptedLinearBlock(
2190                 index,
2191                 memory,
2192                 offset,
2193                 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2194                 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2195                 cryptoInfo.mMode,
2196                 cryptoInfo.mPattern,
2197                 presentationTimeUs,
2198                 flags,
2199                 tunings,
2200                 &errorDetailMsg);
2201     } else {
2202         if (!buffer) {
2203             ALOGI("queueLinearBlock: no C2Buffer found");
2204             throwExceptionAsNecessary(env, BAD_VALUE);
2205             return;
2206         }
2207         err = codec->queueBuffer(
2208                 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2209     }
2210     throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2211 }
2212 
android_media_MediaCodec_native_queueHardwareBuffer(JNIEnv * env,jobject thiz,jint index,jobject bufferObj,jlong presentationTimeUs,jint flags,jobject keys,jobject values)2213 static void android_media_MediaCodec_native_queueHardwareBuffer(
2214         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2215         jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2216     ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
2217 
2218     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2219 
2220     if (codec == NULL || codec->initCheck() != OK) {
2221         throwExceptionAsNecessary(env, INVALID_OPERATION);
2222         return;
2223     }
2224 
2225     sp<AMessage> tunings;
2226     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2227     if (err != OK) {
2228         throwExceptionAsNecessary(env, err);
2229         return;
2230     }
2231 
2232     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2233             env, bufferObj);
2234     sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2235     C2Handle *handle = WrapNativeCodec2GrallocHandle(
2236             graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2237             graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2238     static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2239         std::shared_ptr<C2Allocator> alloc;
2240         c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2241                 C2PlatformAllocatorStore::GRALLOC, &alloc);
2242         if (err == C2_OK) {
2243             return alloc;
2244         }
2245         return nullptr;
2246     }();
2247     std::shared_ptr<C2GraphicAllocation> alloc;
2248     c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2249     if (c2err != C2_OK) {
2250         ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
2251         throwExceptionAsNecessary(env, BAD_VALUE);
2252         return;
2253     }
2254     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
2255     std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2256             block->crop(), C2Fence{}));
2257     AString errorDetailMsg;
2258     err = codec->queueBuffer(
2259             index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2260     throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2261 }
2262 
android_media_MediaCodec_native_getOutputFrame(JNIEnv * env,jobject thiz,jobject frame,jint index)2263 static void android_media_MediaCodec_native_getOutputFrame(
2264         JNIEnv *env, jobject thiz, jobject frame, jint index) {
2265     ALOGV("android_media_MediaCodec_native_getOutputFrame");
2266 
2267     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2268 
2269     if (codec == NULL || codec->initCheck() != OK) {
2270         throwExceptionAsNecessary(env, INVALID_OPERATION);
2271         return;
2272     }
2273 
2274     status_t err = codec->getOutputFrame(env, frame, index);
2275     if (err != OK) {
2276         throwExceptionAsNecessary(env, err);
2277     }
2278 }
2279 
android_media_MediaCodec_dequeueInputBuffer(JNIEnv * env,jobject thiz,jlong timeoutUs)2280 static jint android_media_MediaCodec_dequeueInputBuffer(
2281         JNIEnv *env, jobject thiz, jlong timeoutUs) {
2282     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2283 
2284     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2285 
2286     if (codec == NULL || codec->initCheck() != OK) {
2287         throwExceptionAsNecessary(env, INVALID_OPERATION);
2288         return -1;
2289     }
2290 
2291     size_t index;
2292     status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2293 
2294     if (err == OK) {
2295         return (jint) index;
2296     }
2297 
2298     return throwExceptionAsNecessary(env, err);
2299 }
2300 
android_media_MediaCodec_dequeueOutputBuffer(JNIEnv * env,jobject thiz,jobject bufferInfo,jlong timeoutUs)2301 static jint android_media_MediaCodec_dequeueOutputBuffer(
2302         JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2303     ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2304 
2305     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2306 
2307     if (codec == NULL || codec->initCheck() != OK) {
2308         throwExceptionAsNecessary(env, INVALID_OPERATION);
2309         return 0;
2310     }
2311 
2312     size_t index;
2313     status_t err = codec->dequeueOutputBuffer(
2314             env, bufferInfo, &index, timeoutUs);
2315 
2316     if (err == OK) {
2317         return (jint) index;
2318     }
2319 
2320     return throwExceptionAsNecessary(env, err);
2321 }
2322 
android_media_MediaCodec_releaseOutputBuffer(JNIEnv * env,jobject thiz,jint index,jboolean render,jboolean updatePTS,jlong timestampNs)2323 static void android_media_MediaCodec_releaseOutputBuffer(
2324         JNIEnv *env, jobject thiz,
2325         jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
2326     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2327 
2328     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2329 
2330     if (codec == NULL || codec->initCheck() != OK) {
2331         throwExceptionAsNecessary(env, INVALID_OPERATION);
2332         return;
2333     }
2334 
2335     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
2336 
2337     throwExceptionAsNecessary(env, err);
2338 }
2339 
android_media_MediaCodec_signalEndOfInputStream(JNIEnv * env,jobject thiz)2340 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2341         jobject thiz) {
2342     ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2343 
2344     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2345     if (codec == NULL || codec->initCheck() != OK) {
2346         throwExceptionAsNecessary(env, INVALID_OPERATION);
2347         return;
2348     }
2349 
2350     status_t err = codec->signalEndOfInputStream();
2351 
2352     throwExceptionAsNecessary(env, err);
2353 }
2354 
android_media_MediaCodec_getFormatNative(JNIEnv * env,jobject thiz,jboolean input)2355 static jobject android_media_MediaCodec_getFormatNative(
2356         JNIEnv *env, jobject thiz, jboolean input) {
2357     ALOGV("android_media_MediaCodec_getFormatNative");
2358 
2359     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2360 
2361     if (codec == NULL || codec->initCheck() != OK) {
2362         throwExceptionAsNecessary(env, INVALID_OPERATION);
2363         return NULL;
2364     }
2365 
2366     jobject format;
2367     status_t err = codec->getFormat(env, input, &format);
2368 
2369     if (err == OK) {
2370         return format;
2371     }
2372 
2373     throwExceptionAsNecessary(env, err);
2374 
2375     return NULL;
2376 }
2377 
android_media_MediaCodec_getOutputFormatForIndexNative(JNIEnv * env,jobject thiz,jint index)2378 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2379         JNIEnv *env, jobject thiz, jint index) {
2380     ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2381 
2382     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2383 
2384     if (codec == NULL || codec->initCheck() != OK) {
2385         throwExceptionAsNecessary(env, INVALID_OPERATION);
2386         return NULL;
2387     }
2388 
2389     jobject format;
2390     status_t err = codec->getOutputFormat(env, index, &format);
2391 
2392     if (err == OK) {
2393         return format;
2394     }
2395 
2396     throwExceptionAsNecessary(env, err);
2397 
2398     return NULL;
2399 }
2400 
android_media_MediaCodec_getBuffers(JNIEnv * env,jobject thiz,jboolean input)2401 static jobjectArray android_media_MediaCodec_getBuffers(
2402         JNIEnv *env, jobject thiz, jboolean input) {
2403     ALOGV("android_media_MediaCodec_getBuffers");
2404 
2405     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2406 
2407     if (codec == NULL || codec->initCheck() != OK) {
2408         throwExceptionAsNecessary(env, INVALID_OPERATION);
2409         return NULL;
2410     }
2411 
2412     jobjectArray buffers;
2413     status_t err = codec->getBuffers(env, input, &buffers);
2414 
2415     if (err == OK) {
2416         return buffers;
2417     }
2418 
2419     // if we're out of memory, an exception was already thrown
2420     if (err != NO_MEMORY) {
2421         throwExceptionAsNecessary(env, err);
2422     }
2423 
2424     return NULL;
2425 }
2426 
android_media_MediaCodec_getBuffer(JNIEnv * env,jobject thiz,jboolean input,jint index)2427 static jobject android_media_MediaCodec_getBuffer(
2428         JNIEnv *env, jobject thiz, jboolean input, jint index) {
2429     ALOGV("android_media_MediaCodec_getBuffer");
2430 
2431     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2432 
2433     if (codec == NULL || codec->initCheck() != OK) {
2434         throwExceptionAsNecessary(env, INVALID_OPERATION);
2435         return NULL;
2436     }
2437 
2438     jobject buffer;
2439     status_t err = codec->getBuffer(env, input, index, &buffer);
2440 
2441     if (err == OK) {
2442         return buffer;
2443     }
2444 
2445     // if we're out of memory, an exception was already thrown
2446     if (err != NO_MEMORY) {
2447         throwExceptionAsNecessary(env, err);
2448     }
2449 
2450     return NULL;
2451 }
2452 
android_media_MediaCodec_getImage(JNIEnv * env,jobject thiz,jboolean input,jint index)2453 static jobject android_media_MediaCodec_getImage(
2454         JNIEnv *env, jobject thiz, jboolean input, jint index) {
2455     ALOGV("android_media_MediaCodec_getImage");
2456 
2457     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2458 
2459     if (codec == NULL || codec->initCheck() != OK) {
2460         throwExceptionAsNecessary(env, INVALID_OPERATION);
2461         return NULL;
2462     }
2463 
2464     jobject image;
2465     status_t err = codec->getImage(env, input, index, &image);
2466 
2467     if (err == OK) {
2468         return image;
2469     }
2470 
2471     // if we're out of memory, an exception was already thrown
2472     if (err != NO_MEMORY) {
2473         throwExceptionAsNecessary(env, err);
2474     }
2475 
2476     return NULL;
2477 }
2478 
android_media_MediaCodec_getName(JNIEnv * env,jobject thiz)2479 static jobject android_media_MediaCodec_getName(
2480         JNIEnv *env, jobject thiz) {
2481     ALOGV("android_media_MediaCodec_getName");
2482 
2483     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2484 
2485     if (codec == NULL || codec->initCheck() != OK) {
2486         throwExceptionAsNecessary(env, INVALID_OPERATION);
2487         return NULL;
2488     }
2489 
2490     jstring name;
2491     status_t err = codec->getName(env, &name);
2492 
2493     if (err == OK) {
2494         return name;
2495     }
2496 
2497     throwExceptionAsNecessary(env, err);
2498 
2499     return NULL;
2500 }
2501 
android_media_MediaCodec_getOwnCodecInfo(JNIEnv * env,jobject thiz)2502 static jobject android_media_MediaCodec_getOwnCodecInfo(
2503         JNIEnv *env, jobject thiz) {
2504     ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2505 
2506     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2507 
2508     if (codec == NULL || codec->initCheck() != OK) {
2509         throwExceptionAsNecessary(env, INVALID_OPERATION);
2510         return NULL;
2511     }
2512 
2513     jobject codecInfoObj;
2514     status_t err = codec->getCodecInfo(env, &codecInfoObj);
2515 
2516     if (err == OK) {
2517         return codecInfoObj;
2518     }
2519 
2520     throwExceptionAsNecessary(env, err);
2521 
2522     return NULL;
2523 }
2524 
2525 static jobject
android_media_MediaCodec_native_getMetrics(JNIEnv * env,jobject thiz)2526 android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
2527 {
2528     ALOGV("android_media_MediaCodec_native_getMetrics");
2529 
2530     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2531     if (codec == NULL || codec->initCheck() != OK) {
2532         jniThrowException(env, "java/lang/IllegalStateException", NULL);
2533         return 0;
2534     }
2535 
2536     // get what we have for the metrics from the codec
2537     mediametrics::Item *item = 0;
2538 
2539     status_t err = codec->getMetrics(env, item);
2540     if (err != OK) {
2541         ALOGE("getMetrics failed");
2542         return (jobject) NULL;
2543     }
2544 
2545     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2546 
2547     // housekeeping
2548     delete item;
2549     item = 0;
2550 
2551     return mybundle;
2552 }
2553 
android_media_MediaCodec_setParameters(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray vals)2554 static void android_media_MediaCodec_setParameters(
2555         JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2556     ALOGV("android_media_MediaCodec_setParameters");
2557 
2558     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2559 
2560     if (codec == NULL || codec->initCheck() != OK) {
2561         throwExceptionAsNecessary(env, INVALID_OPERATION);
2562         return;
2563     }
2564 
2565     sp<AMessage> params;
2566     status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2567 
2568     if (err == OK) {
2569         err = codec->setParameters(params);
2570     }
2571 
2572     throwExceptionAsNecessary(env, err);
2573 }
2574 
android_media_MediaCodec_setVideoScalingMode(JNIEnv * env,jobject thiz,jint mode)2575 static void android_media_MediaCodec_setVideoScalingMode(
2576         JNIEnv *env, jobject thiz, jint mode) {
2577     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2578 
2579     if (codec == NULL || codec->initCheck() != OK) {
2580         throwExceptionAsNecessary(env, INVALID_OPERATION);
2581         return;
2582     }
2583 
2584     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2585             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
2586         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
2587         return;
2588     }
2589 
2590     codec->setVideoScalingMode(mode);
2591 }
2592 
android_media_MediaCodec_setAudioPresentation(JNIEnv * env,jobject thiz,jint presentationId,jint programId)2593 static void android_media_MediaCodec_setAudioPresentation(
2594         JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2595     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2596 
2597     if (codec == NULL || codec->initCheck() != OK) {
2598         throwExceptionAsNecessary(env, INVALID_OPERATION);
2599         return;
2600     }
2601 
2602     codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2603 }
2604 
android_media_MediaCodec_native_init(JNIEnv * env,jclass)2605 static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
2606     ScopedLocalRef<jclass> clazz(
2607             env, env->FindClass("android/media/MediaCodec"));
2608     CHECK(clazz.get() != NULL);
2609 
2610     gFields.postEventFromNativeID =
2611         env->GetMethodID(
2612                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
2613     CHECK(gFields.postEventFromNativeID != NULL);
2614 
2615     gFields.lockAndGetContextID =
2616         env->GetMethodID(
2617                 clazz.get(), "lockAndGetContext", "()J");
2618     CHECK(gFields.lockAndGetContextID != NULL);
2619 
2620     gFields.setAndUnlockContextID =
2621         env->GetMethodID(
2622                 clazz.get(), "setAndUnlockContext", "(J)V");
2623     CHECK(gFields.setAndUnlockContextID != NULL);
2624 
2625     jfieldID field;
2626     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
2627     CHECK(field != NULL);
2628     gCryptoModes.Unencrypted =
2629         env->GetStaticIntField(clazz.get(), field);
2630 
2631     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
2632     CHECK(field != NULL);
2633     gCryptoModes.AesCtr =
2634         env->GetStaticIntField(clazz.get(), field);
2635 
2636     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
2637     CHECK(field != NULL);
2638     gCryptoModes.AesCbc =
2639         env->GetStaticIntField(clazz.get(), field);
2640 
2641     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
2642     CHECK(clazz.get() != NULL);
2643 
2644     gFields.cryptoInfoNumSubSamplesID =
2645         env->GetFieldID(clazz.get(), "numSubSamples", "I");
2646     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
2647 
2648     gFields.cryptoInfoNumBytesOfClearDataID =
2649         env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
2650     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
2651 
2652     gFields.cryptoInfoNumBytesOfEncryptedDataID =
2653         env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
2654     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
2655 
2656     gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
2657     CHECK(gFields.cryptoInfoKeyID != NULL);
2658 
2659     gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
2660     CHECK(gFields.cryptoInfoIVID != NULL);
2661 
2662     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
2663     CHECK(gFields.cryptoInfoModeID != NULL);
2664 
2665     gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
2666         "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
2667     CHECK(gFields.cryptoInfoPatternID != NULL);
2668 
2669     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
2670     CHECK(clazz.get() != NULL);
2671 
2672     gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
2673     CHECK(gFields.patternEncryptBlocksID != NULL);
2674 
2675     gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
2676     CHECK(gFields.patternSkipBlocksID != NULL);
2677 
2678     clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
2679     CHECK(clazz.get() != NULL);
2680 
2681     gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
2682     CHECK(gFields.queueRequestIndexID != NULL);
2683 
2684     clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
2685     CHECK(clazz.get() != NULL);
2686 
2687     gFields.outputFrameLinearBlockID =
2688         env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
2689     CHECK(gFields.outputFrameLinearBlockID != NULL);
2690 
2691     gFields.outputFrameHardwareBufferID =
2692         env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
2693     CHECK(gFields.outputFrameHardwareBufferID != NULL);
2694 
2695     gFields.outputFrameChangedKeysID =
2696         env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
2697     CHECK(gFields.outputFrameChangedKeysID != NULL);
2698 
2699     gFields.outputFrameFormatID =
2700         env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
2701     CHECK(gFields.outputFrameFormatID != NULL);
2702 
2703     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
2704     CHECK(clazz.get() != NULL);
2705 
2706     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
2707     CHECK(field != NULL);
2708     gCryptoErrorCodes.cryptoErrorNoKey =
2709         env->GetStaticIntField(clazz.get(), field);
2710 
2711     field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
2712     CHECK(field != NULL);
2713     gCryptoErrorCodes.cryptoErrorKeyExpired =
2714         env->GetStaticIntField(clazz.get(), field);
2715 
2716     field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
2717     CHECK(field != NULL);
2718     gCryptoErrorCodes.cryptoErrorResourceBusy =
2719         env->GetStaticIntField(clazz.get(), field);
2720 
2721     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
2722     CHECK(field != NULL);
2723     gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
2724         env->GetStaticIntField(clazz.get(), field);
2725 
2726     field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
2727     CHECK(field != NULL);
2728     gCryptoErrorCodes.cryptoErrorSessionNotOpened =
2729         env->GetStaticIntField(clazz.get(), field);
2730 
2731     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
2732     CHECK(field != NULL);
2733     gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
2734         env->GetStaticIntField(clazz.get(), field);
2735 
2736     field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
2737     CHECK(field != NULL);
2738     gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
2739         env->GetStaticIntField(clazz.get(), field);
2740 
2741     field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
2742     CHECK(field != NULL);
2743     gCryptoErrorCodes.cryptoErrorFrameTooLarge =
2744         env->GetStaticIntField(clazz.get(), field);
2745 
2746     field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
2747     CHECK(field != NULL);
2748     gCryptoErrorCodes.cryptoErrorLostState =
2749         env->GetStaticIntField(clazz.get(), field);
2750 
2751     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
2752     CHECK(clazz.get() != NULL);
2753     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
2754     CHECK(field != NULL);
2755     gCodecActionCodes.codecActionTransient =
2756         env->GetStaticIntField(clazz.get(), field);
2757 
2758     field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
2759     CHECK(field != NULL);
2760     gCodecActionCodes.codecActionRecoverable =
2761         env->GetStaticIntField(clazz.get(), field);
2762 
2763     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
2764     CHECK(field != NULL);
2765     gCodecErrorCodes.errorInsufficientResource =
2766         env->GetStaticIntField(clazz.get(), field);
2767 
2768     field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
2769     CHECK(field != NULL);
2770     gCodecErrorCodes.errorReclaimed =
2771         env->GetStaticIntField(clazz.get(), field);
2772 
2773     clazz.reset(env->FindClass("android/view/Surface"));
2774     CHECK(clazz.get() != NULL);
2775 
2776     field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2777     CHECK(field != NULL);
2778     gPersistentSurfaceClassInfo.mLock = field;
2779 
2780     jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
2781     CHECK(method != NULL);
2782     gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2783 
2784     clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2785     CHECK(clazz.get() != NULL);
2786     gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2787 
2788     method = env->GetMethodID(clazz.get(), "<init>", "()V");
2789     CHECK(method != NULL);
2790     gPersistentSurfaceClassInfo.ctor = method;
2791 
2792     field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2793     CHECK(field != NULL);
2794     gPersistentSurfaceClassInfo.mPersistentObject = field;
2795 
2796     clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2797     CHECK(clazz.get() != NULL);
2798     gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2799 
2800     method = env->GetMethodID(clazz.get(), "<init>",
2801             "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
2802             "Ljava/util/Map;Ljava/util/Map;)V");
2803     CHECK(method != NULL);
2804     gCodecInfo.capsCtorId = method;
2805 
2806     clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2807     CHECK(clazz.get() != NULL);
2808     gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2809 
2810     field = env->GetFieldID(clazz.get(), "profile", "I");
2811     CHECK(field != NULL);
2812     gCodecInfo.profileField = field;
2813 
2814     field = env->GetFieldID(clazz.get(), "level", "I");
2815     CHECK(field != NULL);
2816     gCodecInfo.levelField = field;
2817 
2818     clazz.reset(env->FindClass("java/nio/ByteBuffer"));
2819     CHECK(clazz.get() != NULL);
2820     gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2821 
2822     ScopedLocalRef<jclass> byteOrderClass(
2823             env, env->FindClass("java/nio/ByteOrder"));
2824     CHECK(byteOrderClass.get() != NULL);
2825 
2826     jmethodID nativeOrderID = env->GetStaticMethodID(
2827             byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
2828     CHECK(nativeOrderID != NULL);
2829 
2830     ScopedLocalRef<jobject> nativeByteOrderObj{
2831         env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
2832     gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
2833     CHECK(gByteBufferInfo.nativeByteOrder != NULL);
2834     nativeByteOrderObj.reset();
2835 
2836     gByteBufferInfo.orderId = env->GetMethodID(
2837             clazz.get(),
2838             "order",
2839             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
2840     CHECK(gByteBufferInfo.orderId != NULL);
2841 
2842     gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
2843             clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
2844     CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
2845 
2846     gByteBufferInfo.positionId = env->GetMethodID(
2847             clazz.get(), "position", "(I)Ljava/nio/Buffer;");
2848     CHECK(gByteBufferInfo.positionId != NULL);
2849 
2850     gByteBufferInfo.limitId = env->GetMethodID(
2851             clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
2852     CHECK(gByteBufferInfo.limitId != NULL);
2853 
2854     gByteBufferInfo.getPositionId = env->GetMethodID(
2855             clazz.get(), "position", "()I");
2856     CHECK(gByteBufferInfo.getPositionId != NULL);
2857 
2858     gByteBufferInfo.getLimitId = env->GetMethodID(
2859             clazz.get(), "limit", "()I");
2860     CHECK(gByteBufferInfo.getLimitId != NULL);
2861 
2862     clazz.reset(env->FindClass("java/util/ArrayList"));
2863     CHECK(clazz.get() != NULL);
2864 
2865     gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
2866     CHECK(gArrayListInfo.sizeId != NULL);
2867 
2868     gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
2869     CHECK(gArrayListInfo.getId != NULL);
2870 
2871     gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
2872     CHECK(gArrayListInfo.addId != NULL);
2873 
2874     clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
2875     CHECK(clazz.get() != NULL);
2876 
2877     gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2878 
2879     gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
2880     CHECK(gLinearBlockInfo.ctorId != NULL);
2881 
2882     gLinearBlockInfo.setInternalStateId = env->GetMethodID(
2883             clazz.get(), "setInternalStateLocked", "(JZ)V");
2884     CHECK(gLinearBlockInfo.setInternalStateId != NULL);
2885 
2886     gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
2887     CHECK(gLinearBlockInfo.contextId != NULL);
2888 
2889     gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
2890     CHECK(gLinearBlockInfo.validId != NULL);
2891 
2892     gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2893     CHECK(gLinearBlockInfo.lockId != NULL);
2894 }
2895 
android_media_MediaCodec_native_setup(JNIEnv * env,jobject thiz,jstring name,jboolean nameIsType,jboolean encoder)2896 static void android_media_MediaCodec_native_setup(
2897         JNIEnv *env, jobject thiz,
2898         jstring name, jboolean nameIsType, jboolean encoder) {
2899     if (name == NULL) {
2900         jniThrowException(env, "java/lang/NullPointerException", NULL);
2901         return;
2902     }
2903 
2904     const char *tmp = env->GetStringUTFChars(name, NULL);
2905 
2906     if (tmp == NULL) {
2907         return;
2908     }
2909 
2910     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2911 
2912     const status_t err = codec->initCheck();
2913     if (err == NAME_NOT_FOUND) {
2914         // fail and do not try again.
2915         jniThrowException(env, "java/lang/IllegalArgumentException",
2916                 String8::format("Failed to initialize %s, error %#x", tmp, err));
2917         env->ReleaseStringUTFChars(name, tmp);
2918         return;
2919     } if (err == NO_MEMORY) {
2920         throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2921                 String8::format("Failed to initialize %s, error %#x", tmp, err));
2922         env->ReleaseStringUTFChars(name, tmp);
2923         return;
2924     } else if (err != OK) {
2925         // believed possible to try again
2926         jniThrowException(env, "java/io/IOException",
2927                 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2928         env->ReleaseStringUTFChars(name, tmp);
2929         return;
2930     }
2931 
2932     env->ReleaseStringUTFChars(name, tmp);
2933 
2934     codec->registerSelf();
2935 
2936     setMediaCodec(env,thiz, codec);
2937 }
2938 
android_media_MediaCodec_native_finalize(JNIEnv * env,jobject thiz)2939 static void android_media_MediaCodec_native_finalize(
2940         JNIEnv *env, jobject thiz) {
2941     setMediaCodec(env, thiz, NULL);
2942 }
2943 
2944 // MediaCodec.LinearBlock
2945 
android_media_MediaCodec_LinearBlock_native_map(JNIEnv * env,jobject thiz)2946 static jobject android_media_MediaCodec_LinearBlock_native_map(
2947         JNIEnv *env, jobject thiz) {
2948     JMediaCodecLinearBlock *context =
2949         (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2950     if (context->mBuffer) {
2951         std::shared_ptr<C2Buffer> buffer = context->mBuffer;
2952         if (!context->mReadonlyMapping) {
2953             const C2BufferData data = buffer->data();
2954             if (data.type() != C2BufferData::LINEAR) {
2955                 throwExceptionAsNecessary(env, INVALID_OPERATION);
2956                 return nullptr;
2957             }
2958             if (data.linearBlocks().size() != 1u) {
2959                 throwExceptionAsNecessary(env, INVALID_OPERATION);
2960                 return nullptr;
2961             }
2962             C2ConstLinearBlock block = data.linearBlocks().front();
2963             context->mReadonlyMapping =
2964                 std::make_shared<C2ReadView>(block.map().get());
2965         }
2966         return CreateByteBuffer(
2967                 env,
2968                 context->mReadonlyMapping->data(),  // base
2969                 context->mReadonlyMapping->capacity(),  // capacity
2970                 0u,  // offset
2971                 context->mReadonlyMapping->capacity(),  // size
2972                 true,  // readOnly
2973                 true /* clearBuffer */);
2974     } else if (context->mBlock) {
2975         std::shared_ptr<C2LinearBlock> block = context->mBlock;
2976         if (!context->mReadWriteMapping) {
2977             context->mReadWriteMapping =
2978                 std::make_shared<C2WriteView>(block->map().get());
2979         }
2980         return CreateByteBuffer(
2981                 env,
2982                 context->mReadWriteMapping->base(),
2983                 context->mReadWriteMapping->capacity(),
2984                 context->mReadWriteMapping->offset(),
2985                 context->mReadWriteMapping->size(),
2986                 false,  // readOnly
2987                 true /* clearBuffer */);
2988     } else if (context->mLegacyBuffer) {
2989         return CreateByteBuffer(
2990                 env,
2991                 context->mLegacyBuffer->base(),
2992                 context->mLegacyBuffer->capacity(),
2993                 context->mLegacyBuffer->offset(),
2994                 context->mLegacyBuffer->size(),
2995                 true,  // readOnly
2996                 true /* clearBuffer */);
2997     } else if (context->mMemory) {
2998         return CreateByteBuffer(
2999                 env,
3000                 context->mMemory->unsecurePointer(),
3001                 context->mMemory->size(),
3002                 0,
3003                 context->mMemory->size(),
3004                 false,  // readOnly
3005                 true /* clearBuffer */);
3006     }
3007     throwExceptionAsNecessary(env, INVALID_OPERATION);
3008     return nullptr;
3009 }
3010 
android_media_MediaCodec_LinearBlock_native_recycle(JNIEnv * env,jobject thiz)3011 static void android_media_MediaCodec_LinearBlock_native_recycle(
3012         JNIEnv *env, jobject thiz) {
3013     JMediaCodecLinearBlock *context =
3014         (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3015     env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
3016     delete context;
3017 }
3018 
PopulateNamesVector(JNIEnv * env,jobjectArray codecNames,std::vector<std::string> * names)3019 static void PopulateNamesVector(
3020         JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3021     jsize length = env->GetArrayLength(codecNames);
3022     for (jsize i = 0; i < length; ++i) {
3023         jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3024         if (jstr == nullptr) {
3025             // null entries are ignored
3026             continue;
3027         }
3028         const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3029         if (cstr == nullptr) {
3030             throwExceptionAsNecessary(env, BAD_VALUE);
3031             return;
3032         }
3033         names->emplace_back(cstr);
3034         env->ReleaseStringUTFChars(jstr, cstr);
3035     }
3036 }
3037 
android_media_MediaCodec_LinearBlock_native_obtain(JNIEnv * env,jobject thiz,jint capacity,jobjectArray codecNames)3038 static void android_media_MediaCodec_LinearBlock_native_obtain(
3039         JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3040     std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3041     std::vector<std::string> names;
3042     PopulateNamesVector(env, codecNames, &names);
3043     bool hasSecure = false;
3044     bool hasNonSecure = false;
3045     for (const std::string &name : names) {
3046         if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3047             hasSecure = true;
3048         } else {
3049             hasNonSecure = true;
3050         }
3051     }
3052     if (hasSecure && !hasNonSecure) {
3053         constexpr size_t kInitialDealerCapacity = 1048576;  // 1MB
3054         thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
3055                 kInitialDealerCapacity, "JNI(1MB)");
3056         context->mMemory = sDealer->allocate(capacity);
3057         if (context->mMemory == nullptr) {
3058             size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
3059             while (capacity * 2 > newDealerCapacity) {
3060                 newDealerCapacity *= 2;
3061             }
3062             ALOGI("LinearBlock.native_obtain: "
3063                   "Dealer capacity increasing from %zuMB to %zuMB",
3064                   sDealer->getMemoryHeap()->getSize() / 1048576,
3065                   newDealerCapacity / 1048576);
3066             sDealer = new MemoryDealer(
3067                     newDealerCapacity,
3068                     AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
3069             context->mMemory = sDealer->allocate(capacity);
3070         }
3071         context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
3072                     &context->mHidlMemoryOffset, &context->mHidlMemorySize));
3073     } else {
3074         context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
3075         if (!context->mBlock) {
3076             jniThrowException(env, "java/io/IOException", nullptr);
3077             return;
3078         }
3079     }
3080     env->CallVoidMethod(
3081             thiz,
3082             gLinearBlockInfo.setInternalStateId,
3083             (jlong)context.release(),
3084             true /* isMappable */);
3085 }
3086 
android_media_MediaCodec_LinearBlock_checkCompatible(JNIEnv * env,jclass,jobjectArray codecNames)3087 static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
3088         JNIEnv *env, jclass, jobjectArray codecNames) {
3089     std::vector<std::string> names;
3090     PopulateNamesVector(env, codecNames, &names);
3091     bool isCompatible = false;
3092     bool hasSecure = false;
3093     bool hasNonSecure = false;
3094     for (const std::string &name : names) {
3095         if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3096             hasSecure = true;
3097         } else {
3098             hasNonSecure = true;
3099         }
3100     }
3101     if (hasSecure && hasNonSecure) {
3102         return false;
3103     }
3104     status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3105     if (err != OK) {
3106         throwExceptionAsNecessary(env, err);
3107     }
3108     return isCompatible;
3109 }
3110 
3111 static const JNINativeMethod gMethods[] = {
3112     { "native_release", "()V", (void *)android_media_MediaCodec_release },
3113 
3114     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3115 
3116     { "native_releasePersistentInputSurface",
3117       "(Landroid/view/Surface;)V",
3118        (void *)android_media_MediaCodec_releasePersistentInputSurface},
3119 
3120     { "native_createPersistentInputSurface",
3121       "()Landroid/media/MediaCodec$PersistentSurface;",
3122       (void *)android_media_MediaCodec_createPersistentInputSurface },
3123 
3124     { "native_setInputSurface", "(Landroid/view/Surface;)V",
3125       (void *)android_media_MediaCodec_setInputSurface },
3126 
3127     { "native_enableOnFrameRenderedListener", "(Z)V",
3128       (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3129 
3130     { "native_setCallback",
3131       "(Landroid/media/MediaCodec$Callback;)V",
3132       (void *)android_media_MediaCodec_native_setCallback },
3133 
3134     { "native_configure",
3135       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
3136       "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
3137       (void *)android_media_MediaCodec_native_configure },
3138 
3139     { "native_setSurface",
3140       "(Landroid/view/Surface;)V",
3141       (void *)android_media_MediaCodec_native_setSurface },
3142 
3143     { "createInputSurface", "()Landroid/view/Surface;",
3144       (void *)android_media_MediaCodec_createInputSurface },
3145 
3146     { "native_start", "()V", (void *)android_media_MediaCodec_start },
3147     { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
3148     { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
3149 
3150     { "native_queueInputBuffer", "(IIIJI)V",
3151       (void *)android_media_MediaCodec_queueInputBuffer },
3152 
3153     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
3154       (void *)android_media_MediaCodec_queueSecureInputBuffer },
3155 
3156     { "native_mapHardwareBuffer",
3157       "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3158       (void *)android_media_MediaCodec_mapHardwareBuffer },
3159 
3160     { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3161 
3162     { "native_queueLinearBlock",
3163       "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3164       "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3165       (void *)android_media_MediaCodec_native_queueLinearBlock },
3166 
3167     { "native_queueHardwareBuffer",
3168       "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3169       (void *)android_media_MediaCodec_native_queueHardwareBuffer },
3170 
3171     { "native_getOutputFrame",
3172       "(Landroid/media/MediaCodec$OutputFrame;I)V",
3173       (void *)android_media_MediaCodec_native_getOutputFrame },
3174 
3175     { "native_dequeueInputBuffer", "(J)I",
3176       (void *)android_media_MediaCodec_dequeueInputBuffer },
3177 
3178     { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
3179       (void *)android_media_MediaCodec_dequeueOutputBuffer },
3180 
3181     { "releaseOutputBuffer", "(IZZJ)V",
3182       (void *)android_media_MediaCodec_releaseOutputBuffer },
3183 
3184     { "signalEndOfInputStream", "()V",
3185       (void *)android_media_MediaCodec_signalEndOfInputStream },
3186 
3187     { "getFormatNative", "(Z)Ljava/util/Map;",
3188       (void *)android_media_MediaCodec_getFormatNative },
3189 
3190     { "getOutputFormatNative", "(I)Ljava/util/Map;",
3191       (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
3192 
3193     { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3194       (void *)android_media_MediaCodec_getBuffers },
3195 
3196     { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3197       (void *)android_media_MediaCodec_getBuffer },
3198 
3199     { "getImage", "(ZI)Landroid/media/Image;",
3200       (void *)android_media_MediaCodec_getImage },
3201 
3202     { "getCanonicalName", "()Ljava/lang/String;",
3203       (void *)android_media_MediaCodec_getName },
3204 
3205     { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3206         (void *)android_media_MediaCodec_getOwnCodecInfo },
3207 
3208     { "native_getMetrics", "()Landroid/os/PersistableBundle;",
3209       (void *)android_media_MediaCodec_native_getMetrics},
3210 
3211     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3212       (void *)android_media_MediaCodec_setParameters },
3213 
3214     { "setVideoScalingMode", "(I)V",
3215       (void *)android_media_MediaCodec_setVideoScalingMode },
3216 
3217     { "native_setAudioPresentation", "(II)V",
3218       (void *)android_media_MediaCodec_setAudioPresentation },
3219 
3220     { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3221 
3222     { "native_setup", "(Ljava/lang/String;ZZ)V",
3223       (void *)android_media_MediaCodec_native_setup },
3224 
3225     { "native_finalize", "()V",
3226       (void *)android_media_MediaCodec_native_finalize },
3227 };
3228 
3229 static const JNINativeMethod gLinearBlockMethods[] = {
3230     { "native_map", "()Ljava/nio/ByteBuffer;",
3231       (void *)android_media_MediaCodec_LinearBlock_native_map },
3232 
3233     { "native_recycle", "()V",
3234       (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3235 
3236     { "native_obtain", "(I[Ljava/lang/String;)V",
3237       (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3238 
3239     { "native_checkCompatible", "([Ljava/lang/String;)Z",
3240       (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3241 };
3242 
register_android_media_MediaCodec(JNIEnv * env)3243 int register_android_media_MediaCodec(JNIEnv *env) {
3244     int result = AndroidRuntime::registerNativeMethods(env,
3245                 "android/media/MediaCodec", gMethods, NELEM(gMethods));
3246     if (result != JNI_OK) {
3247         return result;
3248     }
3249     result = AndroidRuntime::registerNativeMethods(env,
3250                 "android/media/MediaCodec$LinearBlock",
3251                 gLinearBlockMethods,
3252                 NELEM(gLinearBlockMethods));
3253     return result;
3254 }
3255