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 <android-base/stringprintf.h>
47 
48 #include <binder/MemoryDealer.h>
49 
50 #include <cutils/compiler.h>
51 
52 #include <gui/Surface.h>
53 
54 #include <hidlmemory/FrameworkUtils.h>
55 
56 #include <media/MediaCodecBuffer.h>
57 #include <media/hardware/VideoAPI.h>
58 #include <media/stagefright/CodecBase.h>
59 #include <media/stagefright/MediaCodec.h>
60 #include <media/stagefright/foundation/ABuffer.h>
61 #include <media/stagefright/foundation/ADebug.h>
62 #include <media/stagefright/foundation/ALooper.h>
63 #include <media/stagefright/foundation/AMessage.h>
64 #include <media/stagefright/foundation/AString.h>
65 #include <media/stagefright/MediaErrors.h>
66 #include <media/stagefright/PersistentSurface.h>
67 #include <mediadrm/DrmUtils.h>
68 #include <mediadrm/ICrypto.h>
69 
70 #include <private/android/AHardwareBufferHelpers.h>
71 
72 #include <system/window.h>
73 
74 namespace android {
75 
76 // Keep these in sync with their equivalents in MediaCodec.java !!!
77 enum {
78     DEQUEUE_INFO_TRY_AGAIN_LATER            = -1,
79     DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED      = -2,
80     DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
81 };
82 
83 enum {
84     EVENT_CALLBACK = 1,
85     EVENT_SET_CALLBACK = 2,
86     EVENT_FRAME_RENDERED = 3,
87     EVENT_FIRST_TUNNEL_FRAME_READY = 4,
88 };
89 
90 // From MediaFormat.java
91 enum {
92     TYPE_NULL           = 0,
93     TYPE_INTEGER        = 1,
94     TYPE_LONG           = 2,
95     TYPE_FLOAT          = 3,
96     TYPE_STRING         = 4,
97     TYPE_BYTE_BUFFER    = 5,
98 };
99 
100 static struct CryptoErrorCodes {
101     jint cryptoErrorNoKey;
102     jint cryptoErrorKeyExpired;
103     jint cryptoErrorResourceBusy;
104     jint cryptoErrorInsufficientOutputProtection;
105     jint cryptoErrorSessionNotOpened;
106     jint cryptoErrorInsufficientSecurity;
107     jint cryptoErrorUnsupportedOperation;
108     jint cryptoErrorFrameTooLarge;
109     jint cryptoErrorLostState;
110 } gCryptoErrorCodes;
111 
112 static struct CodecActionCodes {
113     jint codecActionTransient;
114     jint codecActionRecoverable;
115 } gCodecActionCodes;
116 
117 static struct CodecErrorCodes {
118     jint errorInsufficientResource;
119     jint errorReclaimed;
120 } gCodecErrorCodes;
121 
122 static struct {
123     jclass clazz;
124     jfieldID mLock;
125     jfieldID mPersistentObject;
126     jmethodID ctor;
127     jmethodID setNativeObjectLocked;
128 } gPersistentSurfaceClassInfo;
129 
130 static struct {
131     jint Unencrypted;
132     jint AesCtr;
133     jint AesCbc;
134 } gCryptoModes;
135 
136 static struct {
137     jclass capsClazz;
138     jmethodID capsCtorId;
139     jclass profileLevelClazz;
140     jfieldID profileField;
141     jfieldID levelField;
142 } gCodecInfo;
143 
144 static struct {
145     jclass clazz;
146     jobject nativeByteOrder;
147     jmethodID orderId;
148     jmethodID asReadOnlyBufferId;
149     jmethodID positionId;
150     jmethodID limitId;
151     jmethodID getPositionId;
152     jmethodID getLimitId;
153 } gByteBufferInfo;
154 
155 static struct {
156     jclass clazz;
157     jmethodID ctorId;
158     jmethodID sizeId;
159     jmethodID getId;
160     jmethodID addId;
161 } gArrayListInfo;
162 
163 static struct {
164     jclass clazz;
165     jmethodID ctorId;
166     jmethodID sizeId;
167     jmethodID addId;
168 } gArrayDequeInfo;
169 
170 static struct {
171     jclass clazz;
172     jmethodID ctorId;
173     jmethodID setInternalStateId;
174     jfieldID contextId;
175     jfieldID validId;
176     jfieldID lockId;
177 } gLinearBlockInfo;
178 
179 static struct {
180     jclass clazz;
181     jmethodID ctorId;
182     jfieldID nameId;
183     jfieldID typeId;
184 } gDescriptorInfo;
185 
186 static struct {
187     jclass clazz;
188     jmethodID ctorId;
189     jmethodID setId;
190 } gBufferInfo;
191 
192 struct fields_t {
193     jmethodID postEventFromNativeID;
194     jmethodID lockAndGetContextID;
195     jmethodID setAndUnlockContextID;
196     jmethodID cryptoInfoSetID;
197     jmethodID cryptoInfoSetPatternID;
198     jfieldID cryptoInfoNumSubSamplesID;
199     jfieldID cryptoInfoNumBytesOfClearDataID;
200     jfieldID cryptoInfoNumBytesOfEncryptedDataID;
201     jfieldID cryptoInfoKeyID;
202     jfieldID cryptoInfoIVID;
203     jfieldID cryptoInfoModeID;
204     jfieldID cryptoInfoPatternID;
205     jfieldID patternEncryptBlocksID;
206     jfieldID patternSkipBlocksID;
207     jfieldID queueRequestIndexID;
208     jfieldID outputFrameLinearBlockID;
209     jfieldID outputFrameHardwareBufferID;
210     jfieldID outputFramebufferInfosID;
211     jfieldID outputFrameChangedKeysID;
212     jfieldID outputFrameFormatID;
213     jfieldID bufferInfoFlags;
214     jfieldID bufferInfoOffset;
215     jfieldID bufferInfoSize;
216     jfieldID bufferInfoPresentationTimeUs;
217 
218 };
219 
220 static fields_t gFields;
221 static const void *sRefBaseOwner;
222 
223 jint MediaErrorToJavaError(status_t err);
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 
JMediaCodec(JNIEnv * env,jobject thiz,const char * name,bool nameIsType,bool encoder,int pid,int uid)227 JMediaCodec::JMediaCodec(
228         JNIEnv *env, jobject thiz,
229         const char *name, bool nameIsType, bool encoder, int pid, int uid)
230     : mClass(NULL),
231       mObject(NULL) {
232     jclass clazz = env->GetObjectClass(thiz);
233     CHECK(clazz != NULL);
234 
235     mClass = (jclass)env->NewGlobalRef(clazz);
236     mObject = env->NewWeakGlobalRef(thiz);
237 
238     mLooper = new ALooper;
239     mLooper->setName("MediaCodec_looper");
240 
241     mLooper->start(
242             false,      // runOnCallingThread
243             true,       // canCallJava
244             ANDROID_PRIORITY_VIDEO);
245 
246     if (nameIsType) {
247         mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
248         if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
249             mNameAtCreation = "(null)";
250         }
251     } else {
252         mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
253         mNameAtCreation = name;
254     }
255     CHECK((mCodec != NULL) != (mInitStatus != OK));
256 }
257 
initCheck() const258 status_t JMediaCodec::initCheck() const {
259     return mInitStatus;
260 }
261 
registerSelf()262 void JMediaCodec::registerSelf() {
263     mLooper->registerHandler(this);
264 }
265 
release()266 void JMediaCodec::release() {
267     std::call_once(mReleaseFlag, [this] {
268         if (mCodec != NULL) {
269             mCodec->release();
270             mInitStatus = NO_INIT;
271         }
272 
273         if (mLooper != NULL) {
274             mLooper->unregisterHandler(id());
275             mLooper->stop();
276             mLooper.clear();
277         }
278     });
279 }
280 
releaseAsync()281 void JMediaCodec::releaseAsync() {
282     std::call_once(mAsyncReleaseFlag, [this] {
283         if (mCodec != NULL) {
284             sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
285             // Hold strong reference to this until async release is complete
286             notify->setObject("this", this);
287             mCodec->releaseAsync(notify);
288         }
289         mInitStatus = NO_INIT;
290     });
291 }
292 
~JMediaCodec()293 JMediaCodec::~JMediaCodec() {
294     if (mLooper != NULL) {
295         /* MediaCodec and looper should have been released explicitly already
296          * in setMediaCodec() (see comments in setMediaCodec()).
297          *
298          * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
299          * message handler, doing release() there risks deadlock as MediaCodec::
300          * release() post synchronous message to the same looper.
301          *
302          * Print a warning and try to proceed with releasing.
303          */
304         ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
305         release();
306         ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
307     }
308 
309     JNIEnv *env = AndroidRuntime::getJNIEnv();
310 
311     env->DeleteWeakGlobalRef(mObject);
312     mObject = NULL;
313     env->DeleteGlobalRef(mClass);
314     mClass = NULL;
315 }
316 
enableOnFirstTunnelFrameReadyListener(jboolean enable)317 status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
318     if (enable) {
319         if (mOnFirstTunnelFrameReadyNotification == NULL) {
320             mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
321         }
322     } else {
323         mOnFirstTunnelFrameReadyNotification.clear();
324     }
325 
326     return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
327 }
328 
enableOnFrameRenderedListener(jboolean enable)329 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
330     if (enable) {
331         if (mOnFrameRenderedNotification == NULL) {
332             mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
333         }
334     } else {
335         mOnFrameRenderedNotification.clear();
336     }
337 
338     return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
339 }
340 
setCallback(jobject cb)341 status_t JMediaCodec::setCallback(jobject cb) {
342     if (cb != NULL) {
343         if (mCallbackNotification == NULL) {
344             mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
345         }
346     } else {
347         mCallbackNotification.clear();
348     }
349 
350     return mCodec->setCallback(mCallbackNotification);
351 }
352 
configure(const sp<AMessage> & format,const sp<IGraphicBufferProducer> & bufferProducer,const sp<ICrypto> & crypto,const sp<IDescrambler> & descrambler,int flags)353 status_t JMediaCodec::configure(
354         const sp<AMessage> &format,
355         const sp<IGraphicBufferProducer> &bufferProducer,
356         const sp<ICrypto> &crypto,
357         const sp<IDescrambler> &descrambler,
358         int flags) {
359     sp<Surface> client;
360     if (bufferProducer != NULL) {
361         mSurfaceTextureClient =
362             new Surface(bufferProducer, true /* controlledByApp */);
363     } else {
364         mSurfaceTextureClient.clear();
365     }
366 
367     constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
368     AString mime;
369     CHECK(format->findString("mime", &mime));
370     mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
371             && !(flags & CONFIGURE_FLAG_ENCODE);
372     mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
373     mCrypto = crypto;
374 
375     return mCodec->configure(
376             format, mSurfaceTextureClient, crypto, descrambler, flags);
377 }
378 
setSurface(const sp<IGraphicBufferProducer> & bufferProducer)379 status_t JMediaCodec::setSurface(
380         const sp<IGraphicBufferProducer> &bufferProducer) {
381     sp<Surface> client;
382     if (bufferProducer != NULL) {
383         client = new Surface(bufferProducer, true /* controlledByApp */);
384     }
385     status_t err = mCodec->setSurface(client);
386     if (err == OK) {
387         mSurfaceTextureClient = client;
388     }
389     return err;
390 }
391 
detachOutputSurface()392 status_t JMediaCodec::detachOutputSurface() {
393     status_t err = mCodec->detachOutputSurface();
394     if (err == OK) {
395         mSurfaceTextureClient.clear();
396     }
397     return err;
398 }
399 
createInputSurface(sp<IGraphicBufferProducer> * bufferProducer)400 status_t JMediaCodec::createInputSurface(
401         sp<IGraphicBufferProducer>* bufferProducer) {
402     return mCodec->createInputSurface(bufferProducer);
403 }
404 
setInputSurface(const sp<PersistentSurface> & surface)405 status_t JMediaCodec::setInputSurface(
406         const sp<PersistentSurface> &surface) {
407     return mCodec->setInputSurface(surface);
408 }
409 
start()410 status_t JMediaCodec::start() {
411     return mCodec->start();
412 }
413 
stop()414 status_t JMediaCodec::stop() {
415     mSurfaceTextureClient.clear();
416 
417     return mCodec->stop();
418 }
419 
flush()420 status_t JMediaCodec::flush() {
421     return mCodec->flush();
422 }
423 
reset()424 status_t JMediaCodec::reset() {
425     return mCodec->reset();
426 }
427 
queueInputBuffer(size_t index,size_t offset,size_t size,int64_t timeUs,uint32_t flags,AString * errorDetailMsg)428 status_t JMediaCodec::queueInputBuffer(
429         size_t index,
430         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
431         AString *errorDetailMsg) {
432     return mCodec->queueInputBuffer(
433             index, offset, size, timeUs, flags, errorDetailMsg);
434 }
435 
queueInputBuffers(size_t index,size_t offset,size_t size,const sp<RefBase> & infos,AString * errorDetailMsg)436 status_t JMediaCodec::queueInputBuffers(
437         size_t index,
438         size_t offset,
439         size_t size,
440         const sp<RefBase> &infos,
441         AString *errorDetailMsg) {
442 
443     sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
444     return mCodec->queueInputBuffers(
445             index,
446             offset,
447             size,
448             auInfo,
449             errorDetailMsg);
450 }
451 
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)452 status_t JMediaCodec::queueSecureInputBuffer(
453         size_t index,
454         size_t offset,
455         const CryptoPlugin::SubSample *subSamples,
456         size_t numSubSamples,
457         const uint8_t key[16],
458         const uint8_t iv[16],
459         CryptoPlugin::Mode mode,
460         const CryptoPlugin::Pattern &pattern,
461         int64_t presentationTimeUs,
462         uint32_t flags,
463         AString *errorDetailMsg) {
464     return mCodec->queueSecureInputBuffer(
465             index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
466             presentationTimeUs, flags, errorDetailMsg);
467 }
468 
queueSecureInputBuffers(size_t index,size_t offset,size_t size,const sp<RefBase> & auInfos_,const sp<RefBase> & cryptoInfos_,AString * errorDetailMsg)469 status_t JMediaCodec::queueSecureInputBuffers(
470         size_t index,
471         size_t offset,
472         size_t size,
473         const sp<RefBase> &auInfos_,
474         const sp<RefBase> &cryptoInfos_,
475         AString *errorDetailMsg) {
476     sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
477     sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
478     return mCodec->queueSecureInputBuffers(
479             index,
480             offset,
481             size,
482             auInfos,
483             cryptoInfos,
484             errorDetailMsg);
485 }
486 
queueBuffer(size_t index,const std::shared_ptr<C2Buffer> & buffer,const sp<RefBase> & infos,const sp<AMessage> & tunings,AString * errorDetailMsg)487 status_t JMediaCodec::queueBuffer(
488         size_t index, const std::shared_ptr<C2Buffer> &buffer,
489         const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
490     sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
491     return mCodec->queueBuffer(
492             index, buffer, auInfo, tunings, errorDetailMsg);
493 }
494 
queueEncryptedLinearBlock(size_t index,const sp<hardware::HidlMemory> & buffer,size_t offset,size_t size,const sp<RefBase> & infos,const sp<RefBase> & cryptoInfos_,const sp<AMessage> & tunings,AString * errorDetailMsg)495 status_t JMediaCodec::queueEncryptedLinearBlock(
496         size_t index,
497         const sp<hardware::HidlMemory> &buffer,
498         size_t offset,
499         size_t size,
500         const sp<RefBase> &infos,
501         const sp<RefBase> &cryptoInfos_,
502         const sp<AMessage> &tunings,
503         AString *errorDetailMsg) {
504     sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
505     sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
506     return mCodec->queueEncryptedBuffer(
507             index, buffer, offset, size, auInfo, cryptoInfos,
508             tunings, errorDetailMsg);
509 }
510 
dequeueInputBuffer(size_t * index,int64_t timeoutUs)511 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
512     return mCodec->dequeueInputBuffer(index, timeoutUs);
513 }
514 
dequeueOutputBuffer(JNIEnv * env,jobject bufferInfo,size_t * index,int64_t timeoutUs)515 status_t JMediaCodec::dequeueOutputBuffer(
516         JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
517     size_t size, offset;
518     int64_t timeUs;
519     uint32_t flags;
520     status_t err = mCodec->dequeueOutputBuffer(
521             index, &offset, &size, &timeUs, &flags, timeoutUs);
522 
523     if (err != OK) {
524         return err;
525     }
526 
527     env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
528 
529     return OK;
530 }
531 
releaseOutputBuffer(size_t index,bool render,bool updatePTS,int64_t timestampNs)532 status_t JMediaCodec::releaseOutputBuffer(
533         size_t index, bool render, bool updatePTS, int64_t timestampNs) {
534     if (updatePTS) {
535         return mCodec->renderOutputBufferAndRelease(index, timestampNs);
536     }
537     return render
538         ? mCodec->renderOutputBufferAndRelease(index)
539         : mCodec->releaseOutputBuffer(index);
540 }
541 
signalEndOfInputStream()542 status_t JMediaCodec::signalEndOfInputStream() {
543     return mCodec->signalEndOfInputStream();
544 }
545 
getFormat(JNIEnv * env,bool input,jobject * format) const546 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
547     sp<AMessage> msg;
548     status_t err;
549     err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
550     if (err != OK) {
551         return err;
552     }
553 
554     return ConvertMessageToMap(env, msg, format);
555 }
556 
getOutputFormat(JNIEnv * env,size_t index,jobject * format) const557 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
558     sp<AMessage> msg;
559     status_t err;
560     if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
561         return err;
562     }
563 
564     return ConvertMessageToMap(env, msg, format);
565 }
566 
getBuffers(JNIEnv * env,bool input,jobjectArray * bufArray) const567 status_t JMediaCodec::getBuffers(
568         JNIEnv *env, bool input, jobjectArray *bufArray) const {
569     Vector<sp<MediaCodecBuffer> > buffers;
570 
571     status_t err =
572         input
573             ? mCodec->getInputBuffers(&buffers)
574             : mCodec->getOutputBuffers(&buffers);
575 
576     if (err != OK) {
577         return err;
578     }
579 
580     *bufArray = (jobjectArray)env->NewObjectArray(
581             buffers.size(), gByteBufferInfo.clazz, NULL);
582     if (*bufArray == NULL) {
583         return NO_MEMORY;
584     }
585 
586     for (size_t i = 0; i < buffers.size(); ++i) {
587         const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
588 
589         jobject byteBuffer = NULL;
590         err = createByteBufferFromABuffer(
591                 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
592         if (err != OK) {
593             return err;
594         }
595         if (byteBuffer != NULL) {
596             env->SetObjectArrayElement(
597                     *bufArray, i, byteBuffer);
598 
599             env->DeleteLocalRef(byteBuffer);
600             byteBuffer = NULL;
601         }
602     }
603 
604     return OK;
605 }
606 
607 template <typename T>
CreateByteBuffer(JNIEnv * env,T * base,size_t capacity,size_t offset,size_t size,bool readOnly,bool clearBuffer)608 static jobject CreateByteBuffer(
609         JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
610         bool readOnly, bool clearBuffer) {
611     jobject byteBuffer =
612         env->NewDirectByteBuffer(
613                 const_cast<typename std::remove_const<T>::type *>(base),
614                 capacity);
615     if (readOnly && byteBuffer != NULL) {
616         jobject readOnlyBuffer = env->CallObjectMethod(
617                 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
618         env->DeleteLocalRef(byteBuffer);
619         byteBuffer = readOnlyBuffer;
620     }
621     if (byteBuffer == NULL) {
622         return nullptr;
623     }
624     jobject me = env->CallObjectMethod(
625             byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
626     env->DeleteLocalRef(me);
627     me = env->CallObjectMethod(
628             byteBuffer, gByteBufferInfo.limitId,
629             clearBuffer ? capacity : offset + size);
630     env->DeleteLocalRef(me);
631     me = env->CallObjectMethod(
632             byteBuffer, gByteBufferInfo.positionId,
633             clearBuffer ? 0 : offset);
634     env->DeleteLocalRef(me);
635     me = NULL;
636     return byteBuffer;
637 }
638 
639 
640 // static
641 template <typename T>
createByteBufferFromABuffer(JNIEnv * env,bool readOnly,bool clearBuffer,const sp<T> & buffer,jobject * buf) const642 status_t JMediaCodec::createByteBufferFromABuffer(
643         JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
644         jobject *buf) const {
645     // if this is an ABuffer that doesn't actually hold any accessible memory,
646     // use a null ByteBuffer
647     *buf = NULL;
648 
649     if (buffer == NULL) {
650         ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
651         return OK;
652     }
653 
654     if (buffer->base() == NULL) {
655         return OK;
656     }
657 
658     jobject byteBuffer = CreateByteBuffer(
659             env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
660             readOnly, clearBuffer);
661 
662     *buf = byteBuffer;
663     return OK;
664 }
665 
getBuffer(JNIEnv * env,bool input,size_t index,jobject * buf) const666 status_t JMediaCodec::getBuffer(
667         JNIEnv *env, bool input, size_t index, jobject *buf) const {
668     sp<MediaCodecBuffer> buffer;
669 
670     status_t err =
671         input
672             ? mCodec->getInputBuffer(index, &buffer)
673             : mCodec->getOutputBuffer(index, &buffer);
674 
675     if (err != OK) {
676         return err;
677     }
678 
679     return createByteBufferFromABuffer(
680             env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
681 }
682 
getImage(JNIEnv * env,bool input,size_t index,jobject * buf) const683 status_t JMediaCodec::getImage(
684         JNIEnv *env, bool input, size_t index, jobject *buf) const {
685     sp<MediaCodecBuffer> buffer;
686 
687     status_t err =
688         input
689             ? mCodec->getInputBuffer(index, &buffer)
690             : mCodec->getOutputBuffer(index, &buffer);
691 
692     if (err != OK) {
693         return err;
694     }
695 
696     // if this is an ABuffer that doesn't actually hold any accessible memory,
697     // use a null ByteBuffer
698     *buf = NULL;
699     if (buffer->base() == NULL) {
700         return OK;
701     }
702 
703     // check if buffer is an image
704     sp<ABuffer> imageData;
705     if (!buffer->meta()->findBuffer("image-data", &imageData)) {
706         return OK;
707     }
708 
709     int64_t timestamp = 0;
710     if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
711         timestamp *= 1000; // adjust to ns
712     }
713 
714     jobject byteBuffer = NULL;
715     err = createByteBufferFromABuffer(
716             env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
717     if (err != OK) {
718         return OK;
719     }
720 
721     jobject infoBuffer = NULL;
722     err = createByteBufferFromABuffer(
723             env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
724     if (err != OK) {
725         env->DeleteLocalRef(byteBuffer);
726         byteBuffer = NULL;
727         return OK;
728     }
729 
730     jobject cropRect = NULL;
731     int32_t left, top, right, bottom;
732     if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
733         ScopedLocalRef<jclass> rectClazz(
734                 env, env->FindClass("android/graphics/Rect"));
735         CHECK(rectClazz.get() != NULL);
736 
737         jmethodID rectConstructID = env->GetMethodID(
738                 rectClazz.get(), "<init>", "(IIII)V");
739 
740         cropRect = env->NewObject(
741                 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
742     }
743 
744     ScopedLocalRef<jclass> imageClazz(
745             env, env->FindClass("android/media/MediaCodec$MediaImage"));
746     CHECK(imageClazz.get() != NULL);
747 
748     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
749             "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
750 
751     *buf = env->NewObject(imageClazz.get(), imageConstructID,
752             byteBuffer, infoBuffer,
753             (jboolean)!input /* readOnly */,
754             (jlong)timestamp,
755             (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
756 
757     // if MediaImage creation fails, return null
758     if (env->ExceptionCheck()) {
759         env->ExceptionDescribe();
760         env->ExceptionClear();
761         *buf = NULL;
762     }
763 
764     if (cropRect != NULL) {
765         env->DeleteLocalRef(cropRect);
766         cropRect = NULL;
767     }
768 
769     env->DeleteLocalRef(byteBuffer);
770     byteBuffer = NULL;
771 
772     env->DeleteLocalRef(infoBuffer);
773     infoBuffer = NULL;
774 
775     return OK;
776 }
777 
maybeSetBufferInfos(JNIEnv * env,jobject & frame,const sp<BufferInfosWrapper> & bufInfos)778 void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
779     if (!bufInfos) {
780         return;
781     }
782     std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
783     if (infos.empty()) {
784         return;
785     }
786     ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
787             gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
788     jint offset = 0;
789     std::vector<jobject> jObjectInfos;
790     for (int i = 0 ; i < infos.size(); i++) {
791         jobject bufferInfo = env->NewObject(
792                 gBufferInfo.clazz, gBufferInfo.ctorId);
793         if (bufferInfo != NULL) {
794             env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
795                     offset,
796                     (jint)(infos)[i].mSize,
797                     (infos)[i].mTimestamp,
798                     (infos)[i].mFlags);
799             (void)env->CallBooleanMethod(
800                     dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
801             offset += (infos)[i].mSize;
802             jObjectInfos.push_back(bufferInfo);
803         }
804     }
805     env->SetObjectField(
806             frame,
807             gFields.outputFramebufferInfosID,
808             dequeObj.get());
809     for (int i = 0; i < jObjectInfos.size(); i++) {
810         env->DeleteLocalRef(jObjectInfos[i]);
811     }
812 }
813 
getOutputFrame(JNIEnv * env,jobject frame,size_t index) const814 status_t JMediaCodec::getOutputFrame(
815         JNIEnv *env, jobject frame, size_t index) const {
816     sp<MediaCodecBuffer> buffer;
817 
818     status_t err = mCodec->getOutputBuffer(index, &buffer);
819     if (err != OK) {
820         return err;
821     }
822 
823     if (buffer->size() > 0) {
824         sp<RefBase> obj;
825         sp<BufferInfosWrapper> bufInfos;
826         if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
827             bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
828         }
829         std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
830         if (c2Buffer) {
831             switch (c2Buffer->data().type()) {
832                 case C2BufferData::LINEAR: {
833                     std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
834                     context->mCodecNames.push_back(mNameAtCreation.c_str());
835                     context->mBuffer = c2Buffer;
836                     ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
837                             gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
838                     env->CallVoidMethod(
839                             linearBlock.get(),
840                             gLinearBlockInfo.setInternalStateId,
841                             (jlong)context.release(),
842                             true);
843                     env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
844                     maybeSetBufferInfos(env, frame, bufInfos);
845                     break;
846                 }
847                 case C2BufferData::GRAPHIC: {
848                     const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
849                     uint32_t width, height, format, stride, igbp_slot, generation;
850                     uint64_t usage, igbp_id;
851                     _UnwrapNativeCodec2GrallocMetadata(
852                             c2Handle, &width, &height, &format, &usage, &stride, &generation,
853                             &igbp_id, &igbp_slot);
854                     native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
855                     GraphicBuffer* graphicBuffer = new GraphicBuffer(
856                             grallocHandle, GraphicBuffer::CLONE_HANDLE,
857                             width, height, format, 1, usage, stride);
858                     ScopedLocalRef<jobject> hardwareBuffer{
859                         env,
860                         android_hardware_HardwareBuffer_createFromAHardwareBuffer(
861                                 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
862                     env->SetObjectField(
863                             frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
864                     break;
865                 }
866                 case C2BufferData::LINEAR_CHUNKS:  [[fallthrough]];
867                 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
868                 case C2BufferData::INVALID:        [[fallthrough]];
869                 default:
870                     return INVALID_OPERATION;
871             }
872         } else {
873             if (!mGraphicOutput) {
874                 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
875                 context->mCodecNames.push_back(mNameAtCreation.c_str());
876                 context->mLegacyBuffer = buffer;
877                 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
878                         gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
879                 env->CallVoidMethod(
880                         linearBlock.get(),
881                         gLinearBlockInfo.setInternalStateId,
882                         (jlong)context.release(),
883                         true);
884                 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
885                 maybeSetBufferInfos(env, frame, bufInfos);
886             } else {
887                 // No-op.
888             }
889         }
890     }
891 
892     jobject formatMap;
893     err = getOutputFormat(env, index, &formatMap);
894     if (err != OK) {
895         return err;
896     }
897     ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
898     ScopedLocalRef<jobject> format{env, env->NewObject(
899             mediaFormatClass.get(),
900             env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
901             formatMap)};
902     env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
903     env->DeleteLocalRef(formatMap);
904     formatMap = nullptr;
905 
906     sp<RefBase> obj;
907     if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
908         sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
909             (decltype(changedKeys.get()))obj.get()};
910         ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
911                 frame, gFields.outputFrameChangedKeysID)};
912         for (const std::string &key : changedKeys->value) {
913             ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
914             (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
915         }
916     }
917     return OK;
918 }
919 
getName(JNIEnv * env,jstring * nameStr) const920 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
921     AString name;
922 
923     status_t err = mCodec->getName(&name);
924 
925     if (err != OK) {
926         return err;
927     }
928 
929     *nameStr = env->NewStringUTF(name.c_str());
930 
931     return OK;
932 }
933 
getCodecCapabilitiesObject(JNIEnv * env,const char * mime,bool isEncoder,const sp<MediaCodecInfo::Capabilities> & capabilities)934 static jobject getCodecCapabilitiesObject(
935         JNIEnv *env, const char *mime, bool isEncoder,
936         const sp<MediaCodecInfo::Capabilities> &capabilities) {
937     Vector<MediaCodecInfo::ProfileLevel> profileLevels;
938     Vector<uint32_t> colorFormats;
939 
940     sp<AMessage> defaultFormat = new AMessage();
941     defaultFormat->setString("mime", mime);
942 
943     capabilities->getSupportedColorFormats(&colorFormats);
944     capabilities->getSupportedProfileLevels(&profileLevels);
945     sp<AMessage> details = capabilities->getDetails();
946 
947     jobject defaultFormatObj = NULL;
948     if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
949         return NULL;
950     }
951     ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
952 
953     jobject detailsObj = NULL;
954     if (ConvertMessageToMap(env, details, &detailsObj)) {
955         return NULL;
956     }
957     ScopedLocalRef<jobject> detailsRef(env, detailsObj);
958 
959     ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
960             profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
961 
962     for (size_t i = 0; i < profileLevels.size(); ++i) {
963         const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
964 
965         ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
966                 gCodecInfo.profileLevelClazz));
967 
968         env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
969         env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
970 
971         env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
972     }
973 
974     ScopedLocalRef<jintArray> colorFormatsArray(
975             env, env->NewIntArray(colorFormats.size()));
976     for (size_t i = 0; i < colorFormats.size(); ++i) {
977         jint val = colorFormats.itemAt(i);
978         env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
979     }
980 
981     return env->NewObject(
982             gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
983             profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
984             defaultFormatRef.get(), detailsRef.get());
985 }
986 
getCodecInfo(JNIEnv * env,jobject * codecInfoObject) const987 status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
988     sp<MediaCodecInfo> codecInfo;
989 
990     status_t err = mCodec->getCodecInfo(&codecInfo);
991 
992     if (err != OK) {
993         return err;
994     }
995 
996     ScopedLocalRef<jstring> nameObject(env,
997             env->NewStringUTF(mNameAtCreation.c_str()));
998 
999     ScopedLocalRef<jstring> canonicalNameObject(env,
1000             env->NewStringUTF(codecInfo->getCodecName()));
1001 
1002     MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
1003     bool isEncoder = codecInfo->isEncoder();
1004 
1005     Vector<AString> mediaTypes;
1006     codecInfo->getSupportedMediaTypes(&mediaTypes);
1007 
1008     ScopedLocalRef<jobjectArray> capsArrayObj(env,
1009         env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
1010 
1011     for (size_t i = 0; i < mediaTypes.size(); i++) {
1012         const sp<MediaCodecInfo::Capabilities> caps =
1013                 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
1014 
1015         ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
1016                 env, mediaTypes[i].c_str(), isEncoder, caps));
1017 
1018         env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
1019     }
1020 
1021     ScopedLocalRef<jclass> codecInfoClazz(env,
1022             env->FindClass("android/media/MediaCodecInfo"));
1023     CHECK(codecInfoClazz.get() != NULL);
1024 
1025     jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
1026             "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
1027 
1028     *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
1029             nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
1030 
1031     return OK;
1032 }
1033 
getMetrics(JNIEnv *,mediametrics::Item * & reply) const1034 status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
1035     mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
1036     status_t status = mCodec->getMetrics(reply2);
1037     // getMetrics() updates reply2, pass the converted update along to our caller.
1038     reply = mediametrics::Item::convert(reply2);
1039     return status;
1040 }
1041 
setParameters(const sp<AMessage> & msg)1042 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
1043     return mCodec->setParameters(msg);
1044 }
1045 
setVideoScalingMode(int mode)1046 void JMediaCodec::setVideoScalingMode(int mode) {
1047     if (mSurfaceTextureClient != NULL) {
1048         // this works for components that queue to surface
1049         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
1050         // also signal via param for components that queue to IGBP
1051         sp<AMessage> msg = new AMessage;
1052         msg->setInt32("android._video-scaling", mode);
1053         (void)mCodec->setParameters(msg);
1054     }
1055 }
1056 
selectAudioPresentation(const int32_t presentationId,const int32_t programId)1057 void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
1058     sp<AMessage> msg = new AMessage;
1059     msg->setInt32("audio-presentation-presentation-id", presentationId);
1060     msg->setInt32("audio-presentation-program-id", programId);
1061     (void)mCodec->setParameters(msg);
1062 }
1063 
querySupportedVendorParameters(JNIEnv * env,jobject * namesObj)1064 status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
1065     std::vector<std::string> names;
1066     status_t status = mCodec->querySupportedVendorParameters(&names);
1067     if (status != OK) {
1068         return status;
1069     }
1070     *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
1071     for (const std::string &name : names) {
1072         ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
1073         (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
1074     }
1075     return OK;
1076 }
1077 
describeParameter(JNIEnv * env,jstring name,jobject * descObj)1078 status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
1079     const char *tmp = env->GetStringUTFChars(name, nullptr);
1080     CodecParameterDescriptor desc;
1081     status_t status = mCodec->describeParameter(tmp, &desc);
1082     env->ReleaseStringUTFChars(name, tmp);
1083     if (status != OK) {
1084         return status;
1085     }
1086     jint type = TYPE_NULL;
1087     switch (desc.type) {
1088         case AMessage::kTypeInt32:  type = TYPE_INTEGER;     break;
1089         case AMessage::kTypeSize:
1090         case AMessage::kTypeInt64:  type = TYPE_LONG;        break;
1091         case AMessage::kTypeFloat:  type = TYPE_FLOAT;       break;
1092         case AMessage::kTypeString: type = TYPE_STRING;      break;
1093         case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
1094         default:                    type = TYPE_NULL;        break;
1095     }
1096     if (type == TYPE_NULL) {
1097         return BAD_VALUE;
1098     }
1099     *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1100     env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1101     env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1102     return OK;
1103 }
1104 
BuildVectorFromList(JNIEnv * env,jobject list,std::vector<std::string> * vec)1105 static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1106     ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1107     ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1108     jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1109     jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1110     jobject it = env->CallObjectMethod(
1111             list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1112     while (env->CallBooleanMethod(it, hasNextID)) {
1113         jstring name = (jstring)env->CallObjectMethod(it, nextID);
1114         const char *tmp = env->GetStringUTFChars(name, nullptr);
1115         vec->push_back(tmp);
1116         env->ReleaseStringUTFChars(name, tmp);
1117     }
1118 }
1119 
subscribeToVendorParameters(JNIEnv * env,jobject namesObj)1120 status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1121     std::vector<std::string> names;
1122     BuildVectorFromList(env, namesObj, &names);
1123     return mCodec->subscribeToVendorParameters(names);
1124 }
1125 
unsubscribeFromVendorParameters(JNIEnv * env,jobject namesObj)1126 status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1127     std::vector<std::string> names;
1128     BuildVectorFromList(env, namesObj, &names);
1129     return mCodec->unsubscribeFromVendorParameters(names);
1130 }
1131 
createCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg=NULL)1132 static jthrowable createCodecException(
1133         JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1134     ScopedLocalRef<jclass> clazz(
1135             env, env->FindClass("android/media/MediaCodec$CodecException"));
1136     CHECK(clazz.get() != NULL);
1137 
1138     const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
1139     CHECK(ctor != NULL);
1140 
1141     ScopedLocalRef<jstring> msgObj(
1142             env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
1143 
1144     // translate action code to Java equivalent
1145     switch (actionCode) {
1146     case ACTION_CODE_TRANSIENT:
1147         actionCode = gCodecActionCodes.codecActionTransient;
1148         break;
1149     case ACTION_CODE_RECOVERABLE:
1150         actionCode = gCodecActionCodes.codecActionRecoverable;
1151         break;
1152     default:
1153         actionCode = 0;  // everything else is fatal
1154         break;
1155     }
1156 
1157     /* translate OS errors to Java API CodecException errorCodes */
1158     switch (err) {
1159         case NO_MEMORY:
1160             err = gCodecErrorCodes.errorInsufficientResource;
1161             break;
1162         case DEAD_OBJECT:
1163             err = gCodecErrorCodes.errorReclaimed;
1164             break;
1165         default:  /* Other error codes go out as is. */
1166             break;
1167     }
1168 
1169     return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
1170 }
1171 
AMessageToCryptoInfo(JNIEnv * env,const jobject & obj,const sp<AMessage> & msg)1172 static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1173         const sp<AMessage> & msg) {
1174     if(msg == nullptr || obj == nullptr) {
1175         ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1176         return;
1177     }
1178     size_t numSubSamples = 0;
1179     sp<ABuffer> subSamplesBuffer;
1180     sp<ABuffer> keyBuffer;
1181     sp<ABuffer> ivBuffer;
1182     CryptoPlugin::Mode mode;
1183     CryptoPlugin::Pattern pattern;
1184     CHECK(msg->findInt32("mode", (int*)&mode));
1185     CHECK(msg->findSize("numSubSamples", &numSubSamples));
1186     CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1187     CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1188     CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1189     CHECK(msg->findBuffer("iv", &ivBuffer));
1190     CHECK(msg->findBuffer("key", &keyBuffer));
1191 
1192     // subsamples
1193     ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1194     ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1195     jboolean isCopy;
1196     jint *dstEncryptedSamples =
1197         env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1198     jint * dstClearSamples =
1199         env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1200 
1201     CryptoPlugin::SubSample * samplesArray =
1202         (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1203 
1204     for(int i = 0 ; i < numSubSamples ; i++) {
1205         dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1206         dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1207     }
1208     env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1209     env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1210     // key and iv
1211     jbyteArray keyArray = NULL;
1212     jbyteArray ivArray = NULL;
1213     if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1214         keyArray = env->NewByteArray(keyBuffer->size());
1215         jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1216         memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1217         env->ReleaseByteArrayElements(keyArray,dstKey,0);
1218     }
1219     if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1220         ivArray = env->NewByteArray(ivBuffer->size());
1221         jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1222         memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1223         env->ReleaseByteArrayElements(ivArray, dstIv,0);
1224     }
1225     // set samples, key and iv
1226     env->CallVoidMethod(
1227         obj,
1228         gFields.cryptoInfoSetID,
1229         (jint)numSubSamples,
1230         samplesOfClearDataArr.get(),
1231         samplesOfEncryptedDataArr.get(),
1232         keyArray,
1233         ivArray,
1234         mode);
1235     if (keyArray != NULL) {
1236         env->DeleteLocalRef(keyArray);
1237     }
1238     if (ivArray != NULL) {
1239         env->DeleteLocalRef(ivArray);
1240     }
1241     // set pattern
1242     env->CallVoidMethod(
1243         obj,
1244         gFields.cryptoInfoSetPatternID,
1245         pattern.mEncryptBlocks,
1246         pattern.mSkipBlocks);
1247 }
1248 
CryptoErrorToJavaError(status_t err,jint & jerr,std::string & defaultMsg)1249 static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1250     switch(err) {
1251         case ERROR_DRM_NO_LICENSE:
1252             jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1253             defaultMsg = "Crypto key not available";
1254             break;
1255         case ERROR_DRM_LICENSE_EXPIRED:
1256             jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1257             defaultMsg = "License expired";
1258             break;
1259         case ERROR_DRM_RESOURCE_BUSY:
1260             jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1261             defaultMsg = "Resource busy or unavailable";
1262             break;
1263         case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1264             jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1265             defaultMsg = "Required output protections are not active";
1266             break;
1267         case ERROR_DRM_SESSION_NOT_OPENED:
1268             jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1269             defaultMsg = "Attempted to use a closed session";
1270             break;
1271         case ERROR_DRM_INSUFFICIENT_SECURITY:
1272             jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1273             defaultMsg = "Required security level is not met";
1274             break;
1275         case ERROR_DRM_CANNOT_HANDLE:
1276             jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1277             defaultMsg = "Operation not supported in this configuration";
1278             break;
1279         case ERROR_DRM_FRAME_TOO_LARGE:
1280             jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1281             defaultMsg = "Decrytped frame exceeds size of output buffer";
1282             break;
1283         case ERROR_DRM_SESSION_LOST_STATE:
1284             jerr = gCryptoErrorCodes.cryptoErrorLostState;
1285             defaultMsg = "Session state was lost, open a new session and retry";
1286             break;
1287         default:  // Other negative DRM error codes go out best-effort.
1288             jerr = MediaErrorToJavaError(err);
1289             defaultMsg = StrCryptoError(err);
1290             break;
1291     }
1292 }
createCryptoException(JNIEnv * env,status_t err,const char * msg=NULL,const sp<ICrypto> & crypto=NULL,const sp<AMessage> & cryptoInfo=NULL)1293 static jthrowable createCryptoException(JNIEnv *env, status_t err,
1294         const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1295     const sp<AMessage> & cryptoInfo = NULL) {
1296     jthrowable exception = nullptr;
1297     jmethodID constructID = nullptr;
1298     ScopedLocalRef<jobject> cryptoInfoObject(env);
1299     std::string defaultMsg = "Unknown Error";
1300     jint jerr = 0;
1301     // Get a class ref for CryptoException
1302     ScopedLocalRef<jclass> clazz(
1303         env, env->FindClass("android/media/MediaCodec$CryptoException"));
1304     CHECK(clazz.get() != NULL);
1305 
1306     // Get constructor ref for CryptoException
1307     constructID = env->GetMethodID(clazz.get(), "<init>",
1308             "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1309     CHECK(constructID != NULL);
1310 
1311     // create detailed message for exception
1312     CryptoErrorToJavaError(err, jerr, defaultMsg);
1313     std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1314     DrmStatus dStatus(err, originalMsg.c_str());
1315     std::string detailedMsg(
1316             DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1317     jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1318 
1319     if (cryptoInfo != nullptr) {
1320         // Class ref for CryptoInfo
1321         ScopedLocalRef<jclass> clazzCryptoInfo(
1322                 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1323         CHECK(clazzCryptoInfo.get() != NULL);
1324 
1325         // Constructor reference for CryptoInfo
1326         jmethodID constructCryptoInfo =
1327                 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1328         CHECK(constructCryptoInfo != NULL);
1329 
1330         // Create CryptoInfo jobject
1331         cryptoInfoObject.reset(
1332                 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1333         CHECK(cryptoInfoObject.get() != NULL);
1334 
1335         // Translate AMesage to CryptoInfo
1336         AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1337     }
1338 
1339     exception = (jthrowable)env->NewObject(
1340             clazz.get(), constructID, msgObj, jerr,
1341             dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1342             cryptoInfoObject.get());
1343 
1344     return exception;
1345 }
handleCallback(const sp<AMessage> & msg)1346 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1347     int32_t arg1, arg2 = 0;
1348     jobject obj = NULL;
1349     std::vector<jobject> jObjectInfos;
1350     CHECK(msg->findInt32("callbackID", &arg1));
1351     JNIEnv *env = AndroidRuntime::getJNIEnv();
1352 
1353     switch (arg1) {
1354         case MediaCodec::CB_INPUT_AVAILABLE:
1355         {
1356             CHECK(msg->findInt32("index", &arg2));
1357             break;
1358         }
1359 
1360         case MediaCodec::CB_OUTPUT_AVAILABLE:
1361         {
1362             CHECK(msg->findInt32("index", &arg2));
1363 
1364             size_t size, offset;
1365             int64_t timeUs;
1366             uint32_t flags;
1367             CHECK(msg->findSize("size", &size));
1368             CHECK(msg->findSize("offset", &offset));
1369             CHECK(msg->findInt64("timeUs", &timeUs));
1370             CHECK(msg->findInt32("flags", (int32_t *)&flags));
1371 
1372             obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1373             if (obj == NULL) {
1374                 if (env->ExceptionCheck()) {
1375                     ALOGE("Could not create MediaCodec.BufferInfo.");
1376                     env->ExceptionClear();
1377                 }
1378                 jniThrowException(env, "java/lang/IllegalStateException",
1379                                   "Fatal error: could not create MediaCodec.BufferInfo object");
1380                 return;
1381             }
1382 
1383             env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
1384             break;
1385         }
1386 
1387         case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
1388         {
1389             sp<RefBase> spobj = nullptr;
1390             CHECK(msg->findInt32("index", &arg2));
1391             CHECK(msg->findObject("accessUnitInfo", &spobj));
1392             if (spobj != nullptr) {
1393                 sp<BufferInfosWrapper> bufferInfoParamsWrapper {
1394                         (BufferInfosWrapper *)spobj.get()};
1395                 std::vector<AccessUnitInfo> &bufferInfoParams =
1396                         bufferInfoParamsWrapper.get()->value;
1397                 obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
1398                 jint offset = 0;
1399                 for (int i = 0 ; i < bufferInfoParams.size(); i++) {
1400                     jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1401                     if (bufferInfo != NULL) {
1402                         env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
1403                                             offset,
1404                                             (jint)(bufferInfoParams)[i].mSize,
1405                                             (bufferInfoParams)[i].mTimestamp,
1406                                             (bufferInfoParams)[i].mFlags);
1407                         (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
1408                         offset += (bufferInfoParams)[i].mSize;
1409                         jObjectInfos.push_back(bufferInfo);
1410                     }
1411                 }
1412             }
1413             break;
1414         }
1415 
1416         case MediaCodec::CB_CRYPTO_ERROR:
1417         {
1418             int32_t err, actionCode;
1419             AString errorDetail;
1420             CHECK(msg->findInt32("err", &err));
1421             CHECK(msg->findInt32("actionCode",&actionCode));
1422             CHECK(msg->findString("errorDetail", &errorDetail));
1423             obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1424             break;
1425         }
1426 
1427         case MediaCodec::CB_ERROR:
1428         {
1429             int32_t err, actionCode;
1430             CHECK(msg->findInt32("err", &err));
1431             CHECK(msg->findInt32("actionCode", &actionCode));
1432 
1433             // note that DRM errors could conceivably alias into a CodecException
1434             obj = (jobject)createCodecException(env, err, actionCode);
1435 
1436             if (obj == NULL) {
1437                 if (env->ExceptionCheck()) {
1438                     ALOGE("Could not create CodecException object.");
1439                     env->ExceptionClear();
1440                 }
1441                 jniThrowException(env, "java/lang/IllegalStateException",
1442                                   "Fatal error: could not create CodecException object");
1443                 return;
1444             }
1445 
1446             break;
1447         }
1448 
1449         case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
1450         {
1451             sp<AMessage> format;
1452             CHECK(msg->findMessage("format", &format));
1453 
1454             if (OK != ConvertMessageToMap(env, format, &obj)) {
1455                 jniThrowException(env, "java/lang/IllegalStateException",
1456                                   "Fatal error: failed to convert format "
1457                                   "from native to Java object");
1458                 return;
1459             }
1460 
1461             break;
1462         }
1463 
1464         default:
1465             TRESPASS();
1466     }
1467     env->CallVoidMethod(
1468             mObject,
1469             gFields.postEventFromNativeID,
1470             EVENT_CALLBACK,
1471             arg1,
1472             arg2,
1473             obj);
1474 
1475     for (int i = 0; i < jObjectInfos.size(); i++) {
1476         env->DeleteLocalRef(jObjectInfos[i]);
1477     }
1478     env->DeleteLocalRef(obj);
1479 }
1480 
handleFirstTunnelFrameReadyNotification(const sp<AMessage> & msg)1481 void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1482     int32_t arg1 = 0, arg2 = 0;
1483     jobject obj = NULL;
1484     JNIEnv *env = AndroidRuntime::getJNIEnv();
1485 
1486     sp<AMessage> data;
1487     CHECK(msg->findMessage("data", &data));
1488 
1489     status_t err = ConvertMessageToMap(env, data, &obj);
1490     if (err != OK) {
1491         jniThrowException(env, "java/lang/IllegalStateException",
1492                           "Fatal error: failed to convert format from native to Java object");
1493         return;
1494     }
1495 
1496     env->CallVoidMethod(
1497             mObject, gFields.postEventFromNativeID,
1498             EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1499 
1500     env->DeleteLocalRef(obj);
1501 }
1502 
handleFrameRenderedNotification(const sp<AMessage> & msg)1503 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1504     int32_t arg1 = 0, arg2 = 0;
1505     jobject obj = NULL;
1506     JNIEnv *env = AndroidRuntime::getJNIEnv();
1507 
1508     sp<AMessage> data;
1509     CHECK(msg->findMessage("data", &data));
1510 
1511     status_t err = ConvertMessageToMap(env, data, &obj);
1512     if (err != OK) {
1513         jniThrowException(env, "java/lang/IllegalStateException",
1514                           "Fatal error: failed to convert format from native to Java object");
1515         return;
1516     }
1517 
1518     env->CallVoidMethod(
1519             mObject, gFields.postEventFromNativeID,
1520             EVENT_FRAME_RENDERED, arg1, arg2, obj);
1521 
1522     env->DeleteLocalRef(obj);
1523 }
1524 
getExceptionMessage(const char * msg=nullptr) const1525 std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1526     if (mCodec == nullptr) {
1527         return msg ?: "";
1528     }
1529     std::string prefix = "";
1530     if (msg && msg[0] != '\0') {
1531         prefix.append(msg);
1532         prefix.append("\n");
1533     }
1534     return prefix + mCodec->getErrorLog().extract();
1535 }
1536 
onMessageReceived(const sp<AMessage> & msg)1537 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1538     switch (msg->what()) {
1539         case kWhatCallbackNotify:
1540         {
1541             handleCallback(msg);
1542             break;
1543         }
1544         case kWhatFrameRendered:
1545         {
1546             handleFrameRenderedNotification(msg);
1547             break;
1548         }
1549         case kWhatAsyncReleaseComplete:
1550         {
1551             if (mLooper != NULL) {
1552                 mLooper->unregisterHandler(id());
1553                 mLooper->stop();
1554                 mLooper.clear();
1555             }
1556             break;
1557         }
1558         case kWhatFirstTunnelFrameReady:
1559         {
1560             handleFirstTunnelFrameReadyNotification(msg);
1561             break;
1562         }
1563         default:
1564             TRESPASS();
1565     }
1566 }
1567 
1568 
1569 }  // namespace android
1570 
1571 ////////////////////////////////////////////////////////////////////////////////
1572 
1573 using namespace android;
1574 
setMediaCodec(JNIEnv * env,jobject thiz,const sp<JMediaCodec> & codec,bool release=true)1575 static sp<JMediaCodec> setMediaCodec(
1576         JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
1577     sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1578     if (codec != NULL) {
1579         codec->incStrong(thiz);
1580     }
1581     if (old != NULL) {
1582         /* release MediaCodec and stop the looper now before decStrong.
1583          * otherwise JMediaCodec::~JMediaCodec() could be called from within
1584          * its message handler, doing release() from there will deadlock
1585          * (as MediaCodec::release() post synchronous message to the same looper)
1586          */
1587         if (release) {
1588             old->release();
1589         }
1590         old->decStrong(thiz);
1591     }
1592     env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1593 
1594     return old;
1595 }
1596 
getMediaCodec(JNIEnv * env,jobject thiz)1597 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
1598     sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1599     env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1600     return codec;
1601 }
1602 
android_media_MediaCodec_release(JNIEnv * env,jobject thiz)1603 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
1604     // Clear Java native reference.
1605     sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
1606     if (codec != NULL) {
1607         codec->releaseAsync();
1608     }
1609 }
1610 
throwCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg)1611 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1612     jthrowable exception = createCodecException(env, err, actionCode, msg);
1613     env->Throw(exception);
1614 }
1615 
throwCryptoException(JNIEnv * env,status_t err,const char * msg,const sp<ICrypto> & crypto)1616 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1617         const sp<ICrypto> &crypto) {
1618     jthrowable exception = createCryptoException(
1619             env, err, msg, crypto, /* cryptoInfo */ NULL);
1620     env->Throw(exception);
1621 }
1622 
GetExceptionMessage(const sp<JMediaCodec> & codec,const char * msg)1623 static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1624     if (codec == NULL) {
1625         return msg ?: "codec is released already";
1626     }
1627     return codec->getExceptionMessage(msg);
1628 }
1629 
throwExceptionAsNecessary(JNIEnv * env,status_t err,int32_t actionCode=ACTION_CODE_FATAL,const char * msg=NULL,const sp<ICrypto> & crypto=NULL,const sp<JMediaCodec> & codec=NULL)1630 static jint throwExceptionAsNecessary(
1631         JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1632         const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1633         const sp<JMediaCodec> &codec = NULL) {
1634     switch (err) {
1635         case OK:
1636             return 0;
1637 
1638         case -EAGAIN:
1639             return DEQUEUE_INFO_TRY_AGAIN_LATER;
1640 
1641         case INFO_FORMAT_CHANGED:
1642             return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1643 
1644         case INFO_OUTPUT_BUFFERS_CHANGED:
1645             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1646 
1647         case INVALID_OPERATION:
1648             jniThrowException(
1649                     env, "java/lang/IllegalStateException",
1650                     GetExceptionMessage(codec, msg).c_str());
1651             return 0;
1652 
1653         case BAD_VALUE:
1654             jniThrowException(
1655                     env, "java/lang/IllegalArgumentException",
1656                     GetExceptionMessage(codec, msg).c_str());
1657             return 0;
1658 
1659         default:
1660             if (isCryptoError(err)) {
1661                 throwCryptoException(
1662                         env, err,
1663                         GetExceptionMessage(codec, msg).c_str(),
1664                         crypto);
1665                 return 0;
1666             }
1667             throwCodecException(
1668                     env, err, actionCode,
1669                     GetExceptionMessage(codec, msg).c_str());
1670             return 0;
1671     }
1672 }
1673 
throwExceptionAsNecessary(JNIEnv * env,status_t err,const sp<JMediaCodec> & codec,int32_t actionCode=ACTION_CODE_FATAL)1674 static jint throwExceptionAsNecessary(
1675         JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1676         int32_t actionCode = ACTION_CODE_FATAL) {
1677     return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1678 }
1679 
android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(JNIEnv * env,jobject thiz,jboolean enabled)1680 static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1681         JNIEnv *env,
1682         jobject thiz,
1683         jboolean enabled) {
1684     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1685 
1686     if (codec == NULL || codec->initCheck() != OK) {
1687         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1688         return;
1689     }
1690 
1691     status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1692 
1693     throwExceptionAsNecessary(env, err, codec);
1694 }
1695 
android_media_MediaCodec_native_enableOnFrameRenderedListener(JNIEnv * env,jobject thiz,jboolean enabled)1696 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1697         JNIEnv *env,
1698         jobject thiz,
1699         jboolean enabled) {
1700     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1701 
1702     if (codec == NULL || codec->initCheck() != OK) {
1703         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1704         return;
1705     }
1706 
1707     status_t err = codec->enableOnFrameRenderedListener(enabled);
1708 
1709     throwExceptionAsNecessary(env, err, codec);
1710 }
1711 
android_media_MediaCodec_native_setCallback(JNIEnv * env,jobject thiz,jobject cb)1712 static void android_media_MediaCodec_native_setCallback(
1713         JNIEnv *env,
1714         jobject thiz,
1715         jobject cb) {
1716     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1717 
1718     if (codec == NULL || codec->initCheck() != OK) {
1719         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1720         return;
1721     }
1722 
1723     status_t err = codec->setCallback(cb);
1724 
1725     throwExceptionAsNecessary(env, err, codec);
1726 }
1727 
android_media_MediaCodec_native_configure(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray values,jobject jsurface,jobject jcrypto,jobject descramblerBinderObj,jint flags)1728 static void android_media_MediaCodec_native_configure(
1729         JNIEnv *env,
1730         jobject thiz,
1731         jobjectArray keys, jobjectArray values,
1732         jobject jsurface,
1733         jobject jcrypto,
1734         jobject descramblerBinderObj,
1735         jint flags) {
1736     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1737 
1738     if (codec == NULL || codec->initCheck() != OK) {
1739         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1740         return;
1741     }
1742 
1743     sp<AMessage> format;
1744     status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1745 
1746     if (err != OK) {
1747         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1748         return;
1749     }
1750 
1751     sp<IGraphicBufferProducer> bufferProducer;
1752     if (jsurface != NULL) {
1753         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1754         if (surface != NULL) {
1755             bufferProducer = surface->getIGraphicBufferProducer();
1756         } else {
1757             jniThrowException(
1758                     env,
1759                     "java/lang/IllegalArgumentException",
1760                     "The surface has been released");
1761             return;
1762         }
1763     }
1764 
1765     sp<ICrypto> crypto;
1766     if (jcrypto != NULL) {
1767         crypto = JCrypto::GetCrypto(env, jcrypto);
1768     }
1769 
1770     sp<IDescrambler> descrambler;
1771     if (descramblerBinderObj != NULL) {
1772         descrambler = GetDescrambler(env, descramblerBinderObj);
1773     }
1774 
1775     err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
1776 
1777     throwExceptionAsNecessary(env, err, codec);
1778 }
1779 
android_media_MediaCodec_native_setSurface(JNIEnv * env,jobject thiz,jobject jsurface)1780 static void android_media_MediaCodec_native_setSurface(
1781         JNIEnv *env,
1782         jobject thiz,
1783         jobject jsurface) {
1784     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1785 
1786     if (codec == NULL || codec->initCheck() != OK) {
1787         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1788         return;
1789     }
1790 
1791     sp<IGraphicBufferProducer> bufferProducer;
1792     if (jsurface != NULL) {
1793         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1794         if (surface != NULL) {
1795             bufferProducer = surface->getIGraphicBufferProducer();
1796         } else {
1797             jniThrowException(
1798                     env,
1799                     "java/lang/IllegalArgumentException",
1800                     "The surface has been released");
1801             return;
1802         }
1803     }
1804 
1805     status_t err = codec->setSurface(bufferProducer);
1806     throwExceptionAsNecessary(env, err, codec);
1807 }
1808 
android_media_MediaCodec_native_detachOutputSurface(JNIEnv * env,jobject thiz)1809 static void android_media_MediaCodec_native_detachOutputSurface(
1810         JNIEnv *env,
1811         jobject thiz) {
1812     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1813 
1814     if (codec == NULL || codec->initCheck() != OK) {
1815         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1816         return;
1817     }
1818 
1819     status_t err = codec->detachOutputSurface();
1820     throwExceptionAsNecessary(env, err, codec);
1821 }
1822 
android_media_MediaCodec_getPersistentInputSurface(JNIEnv * env,jobject object)1823 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1824         JNIEnv* env, jobject object) {
1825     sp<PersistentSurface> persistentSurface;
1826 
1827     jobject lock = env->GetObjectField(
1828             object, gPersistentSurfaceClassInfo.mLock);
1829     if (env->MonitorEnter(lock) == JNI_OK) {
1830         persistentSurface = reinterpret_cast<PersistentSurface *>(
1831                 env->GetLongField(object,
1832                         gPersistentSurfaceClassInfo.mPersistentObject));
1833         env->MonitorExit(lock);
1834     }
1835     env->DeleteLocalRef(lock);
1836 
1837     return persistentSurface;
1838 }
1839 
android_media_MediaCodec_createPersistentInputSurface(JNIEnv * env,jclass)1840 static jobject android_media_MediaCodec_createPersistentInputSurface(
1841         JNIEnv* env, jclass /* clazz */) {
1842     ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1843     sp<PersistentSurface> persistentSurface =
1844         MediaCodec::CreatePersistentInputSurface();
1845 
1846     if (persistentSurface == NULL) {
1847         return NULL;
1848     }
1849 
1850     sp<Surface> surface = new Surface(
1851             persistentSurface->getBufferProducer(), true);
1852     if (surface == NULL) {
1853         return NULL;
1854     }
1855 
1856     jobject object = env->NewObject(
1857             gPersistentSurfaceClassInfo.clazz,
1858             gPersistentSurfaceClassInfo.ctor);
1859 
1860     if (object == NULL) {
1861         if (env->ExceptionCheck()) {
1862             ALOGE("Could not create PersistentSurface.");
1863             env->ExceptionClear();
1864         }
1865         return NULL;
1866     }
1867 
1868     jobject lock = env->GetObjectField(
1869             object, gPersistentSurfaceClassInfo.mLock);
1870     if (env->MonitorEnter(lock) == JNI_OK) {
1871         env->CallVoidMethod(
1872                 object,
1873                 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1874                 (jlong)surface.get());
1875         env->SetLongField(
1876                 object,
1877                 gPersistentSurfaceClassInfo.mPersistentObject,
1878                 (jlong)persistentSurface.get());
1879         env->MonitorExit(lock);
1880     } else {
1881         env->DeleteLocalRef(object);
1882         object = NULL;
1883     }
1884     env->DeleteLocalRef(lock);
1885 
1886     if (object != NULL) {
1887         surface->incStrong(&sRefBaseOwner);
1888         persistentSurface->incStrong(&sRefBaseOwner);
1889     }
1890 
1891     return object;
1892 }
1893 
android_media_MediaCodec_releasePersistentInputSurface(JNIEnv * env,jclass,jobject object)1894 static void android_media_MediaCodec_releasePersistentInputSurface(
1895         JNIEnv* env, jclass /* clazz */, jobject object) {
1896     sp<PersistentSurface> persistentSurface;
1897 
1898     jobject lock = env->GetObjectField(
1899             object, gPersistentSurfaceClassInfo.mLock);
1900     if (env->MonitorEnter(lock) == JNI_OK) {
1901         persistentSurface = reinterpret_cast<PersistentSurface *>(
1902             env->GetLongField(
1903                     object, gPersistentSurfaceClassInfo.mPersistentObject));
1904         env->SetLongField(
1905                 object,
1906                 gPersistentSurfaceClassInfo.mPersistentObject,
1907                 (jlong)0);
1908         env->MonitorExit(lock);
1909     }
1910     env->DeleteLocalRef(lock);
1911 
1912     if (persistentSurface != NULL) {
1913         persistentSurface->decStrong(&sRefBaseOwner);
1914     }
1915     // no need to release surface as it will be released by Surface's jni
1916 }
1917 
android_media_MediaCodec_setInputSurface(JNIEnv * env,jobject thiz,jobject object)1918 static void android_media_MediaCodec_setInputSurface(
1919         JNIEnv* env, jobject thiz, jobject object) {
1920     ALOGV("android_media_MediaCodec_setInputSurface");
1921 
1922     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1923     if (codec == NULL || codec->initCheck() != OK) {
1924         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1925         return;
1926     }
1927 
1928     sp<PersistentSurface> persistentSurface =
1929         android_media_MediaCodec_getPersistentInputSurface(env, object);
1930 
1931     if (persistentSurface == NULL) {
1932         throwExceptionAsNecessary(
1933                 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1934         return;
1935     }
1936     status_t err = codec->setInputSurface(persistentSurface);
1937     if (err != NO_ERROR) {
1938         throwExceptionAsNecessary(env, err, codec);
1939     }
1940 }
1941 
android_media_MediaCodec_createInputSurface(JNIEnv * env,jobject thiz)1942 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1943         jobject thiz) {
1944     ALOGV("android_media_MediaCodec_createInputSurface");
1945 
1946     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1947     if (codec == NULL || codec->initCheck() != OK) {
1948         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1949         return NULL;
1950     }
1951 
1952     // Tell the MediaCodec that we want to use a Surface as input.
1953     sp<IGraphicBufferProducer> bufferProducer;
1954     status_t err = codec->createInputSurface(&bufferProducer);
1955     if (err != NO_ERROR) {
1956         throwExceptionAsNecessary(env, err, codec);
1957         return NULL;
1958     }
1959 
1960     // Wrap the IGBP in a Java-language Surface.
1961     return android_view_Surface_createFromIGraphicBufferProducer(env,
1962             bufferProducer);
1963 }
1964 
android_media_MediaCodec_start(JNIEnv * env,jobject thiz)1965 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1966     ALOGV("android_media_MediaCodec_start");
1967 
1968     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1969 
1970     if (codec == NULL || codec->initCheck() != OK) {
1971         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1972         return;
1973     }
1974 
1975     status_t err = codec->start();
1976 
1977     throwExceptionAsNecessary(env, err, codec);
1978 }
1979 
android_media_MediaCodec_stop(JNIEnv * env,jobject thiz)1980 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1981     ALOGV("android_media_MediaCodec_stop");
1982 
1983     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1984 
1985     if (codec == NULL || codec->initCheck() != OK) {
1986         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1987         return;
1988     }
1989 
1990     status_t err = codec->stop();
1991 
1992     throwExceptionAsNecessary(env, err, codec);
1993 }
1994 
android_media_MediaCodec_reset(JNIEnv * env,jobject thiz)1995 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1996     ALOGV("android_media_MediaCodec_reset");
1997 
1998     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1999 
2000     if (codec == NULL || codec->initCheck() != OK) {
2001         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2002         return;
2003     }
2004 
2005     status_t err = codec->reset();
2006     if (err != OK) {
2007         // treat all errors as fatal for now, though resource not available
2008         // errors could be treated as transient.
2009         // we also should avoid sending INVALID_OPERATION here due to
2010         // the transitory nature of reset(), it should not inadvertently
2011         // trigger an IllegalStateException.
2012         err = UNKNOWN_ERROR;
2013     }
2014     throwExceptionAsNecessary(env, err, codec);
2015 }
2016 
android_media_MediaCodec_flush(JNIEnv * env,jobject thiz)2017 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
2018     ALOGV("android_media_MediaCodec_flush");
2019 
2020     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2021 
2022     if (codec == NULL || codec->initCheck() != OK) {
2023         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2024         return;
2025     }
2026 
2027     status_t err = codec->flush();
2028 
2029     throwExceptionAsNecessary(env, err, codec);
2030 }
2031 
android_media_MediaCodec_queueInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jint size,jlong timestampUs,jint flags)2032 static void android_media_MediaCodec_queueInputBuffer(
2033         JNIEnv *env,
2034         jobject thiz,
2035         jint index,
2036         jint offset,
2037         jint size,
2038         jlong timestampUs,
2039         jint flags) {
2040     ALOGV("android_media_MediaCodec_queueInputBuffer");
2041 
2042     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2043 
2044     if (codec == NULL || codec->initCheck() != OK) {
2045         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2046         return;
2047     }
2048 
2049     AString errorDetailMsg;
2050 
2051     status_t err = codec->queueInputBuffer(
2052             index, offset, size, timestampUs, flags, &errorDetailMsg);
2053 
2054     throwExceptionAsNecessary(
2055             env, err, ACTION_CODE_FATAL,
2056             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2057 }
2058 
extractInfosFromObject(JNIEnv * const env,jint * const initialOffset,jint * const totalSize,std::vector<AccessUnitInfo> * const infos,const jobjectArray & objArray,AString * const errorDetailMsg)2059 static status_t extractInfosFromObject(
2060         JNIEnv * const env,
2061         jint * const initialOffset,
2062         jint * const totalSize,
2063         std::vector<AccessUnitInfo> * const infos,
2064         const jobjectArray &objArray,
2065         AString * const errorDetailMsg) {
2066     if (totalSize == nullptr
2067             || initialOffset == nullptr
2068             || infos == nullptr) {
2069         if (errorDetailMsg) {
2070             *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
2071         }
2072         return BAD_VALUE;
2073     }
2074     const jsize numEntries = env->GetArrayLength(objArray);
2075     if (numEntries <= 0) {
2076         if (errorDetailMsg) {
2077             *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
2078         }
2079         return BAD_VALUE;
2080     }
2081     *initialOffset = 0;
2082     *totalSize = 0;
2083     for (jsize i = 0; i < numEntries; i++) {
2084         jobject param = env->GetObjectArrayElement(objArray, i);
2085         if (param == NULL) {
2086             if (errorDetailMsg) {
2087                 *errorDetailMsg = "Error: Queuing a null BufferInfo";
2088             }
2089             return BAD_VALUE;
2090         }
2091         ssize_t offset = static_cast<ssize_t>(env->GetIntField(param, gFields.bufferInfoOffset));
2092         ssize_t size = static_cast<ssize_t>(env->GetIntField(param, gFields.bufferInfoSize));
2093         uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
2094         if (i == 0) {
2095             *initialOffset = offset;
2096         }
2097         if (CC_UNLIKELY((offset < 0)
2098                 || (size < 0)
2099                 || ((INT32_MAX - offset) < size)
2100                 || ((offset - (*initialOffset)) != *totalSize))) {
2101             if (errorDetailMsg) {
2102                 *errorDetailMsg = "Error: offset/size in BufferInfo";
2103             }
2104             return BAD_VALUE;
2105         }
2106         if (flags == 0 && size == 0) {
2107             if (errorDetailMsg) {
2108                 *errorDetailMsg = "Error: Queuing an empty BufferInfo";
2109             }
2110             return BAD_VALUE;
2111         }
2112         infos->emplace_back(
2113                 flags,
2114                 size,
2115                 env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
2116         *totalSize += size;
2117     }
2118     return OK;
2119 }
2120 
android_media_MediaCodec_queueInputBuffers(JNIEnv * env,jobject thiz,jint index,jobjectArray objArray)2121 static void android_media_MediaCodec_queueInputBuffers(
2122         JNIEnv *env,
2123         jobject thiz,
2124         jint index,
2125         jobjectArray objArray) {
2126     ALOGV("android_media_MediaCodec_queueInputBuffers");
2127     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2128     if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
2129         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2130         return;
2131     }
2132     sp<BufferInfosWrapper> infoObj =
2133             new BufferInfosWrapper{decltype(infoObj->value)()};
2134     AString errorDetailMsg;
2135     jint initialOffset = 0;
2136     jint totalSize = 0;
2137     status_t err = extractInfosFromObject(
2138             env,
2139             &initialOffset,
2140             &totalSize,
2141             &infoObj->value,
2142             objArray,
2143             &errorDetailMsg);
2144     if (err == OK) {
2145         err = codec->queueInputBuffers(
2146             index,
2147             initialOffset,
2148             totalSize,
2149             infoObj,
2150             &errorDetailMsg);
2151     }
2152     throwExceptionAsNecessary(
2153             env, err, ACTION_CODE_FATAL,
2154             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2155 }
2156 
2157 struct NativeCryptoInfo {
NativeCryptoInfoNativeCryptoInfo2158     NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
2159         : mEnv{env},
2160           mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
2161           mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
2162         mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2163 
2164         ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
2165                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
2166 
2167         ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
2168                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
2169 
2170         jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2171         if (jmode == gCryptoModes.Unencrypted) {
2172             mMode = CryptoPlugin::kMode_Unencrypted;
2173         } else if (jmode == gCryptoModes.AesCtr) {
2174             mMode = CryptoPlugin::kMode_AES_CTR;
2175         } else if (jmode == gCryptoModes.AesCbc) {
2176             mMode = CryptoPlugin::kMode_AES_CBC;
2177         }  else {
2178             throwExceptionAsNecessary(
2179                     env, INVALID_OPERATION, ACTION_CODE_FATAL,
2180                     base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
2181             return;
2182         }
2183 
2184         ScopedLocalRef<jobject> patternObj{
2185             env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
2186 
2187         if (patternObj.get() == nullptr) {
2188             mPattern.mEncryptBlocks = 0;
2189             mPattern.mSkipBlocks = 0;
2190         } else {
2191             mPattern.mEncryptBlocks = env->GetIntField(
2192                     patternObj.get(), gFields.patternEncryptBlocksID);
2193             mPattern.mSkipBlocks = env->GetIntField(
2194                     patternObj.get(), gFields.patternSkipBlocksID);
2195         }
2196 
2197         mErr = OK;
2198         if (mNumSubSamples <= 0) {
2199             mErr = -EINVAL;
2200         } else if (numBytesOfClearDataObj == nullptr
2201                 && numBytesOfEncryptedDataObj == nullptr) {
2202             mErr = -EINVAL;
2203         } else if (numBytesOfEncryptedDataObj != nullptr
2204                 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
2205             mErr = -ERANGE;
2206         } else if (numBytesOfClearDataObj != nullptr
2207                 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
2208             mErr = -ERANGE;
2209         // subSamples array may silently overflow if number of samples are too large.  Use
2210         // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2211         } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
2212             mErr = -EINVAL;
2213         } else {
2214             jint *numBytesOfClearData =
2215                 (numBytesOfClearDataObj == nullptr)
2216                     ? nullptr
2217                     : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
2218 
2219             jint *numBytesOfEncryptedData =
2220                 (numBytesOfEncryptedDataObj == nullptr)
2221                     ? nullptr
2222                     : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
2223 
2224             mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
2225 
2226             for (jint i = 0; i < mNumSubSamples; ++i) {
2227                 mSubSamples[i].mNumBytesOfClearData =
2228                     (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
2229 
2230                 mSubSamples[i].mNumBytesOfEncryptedData =
2231                     (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
2232             }
2233 
2234             if (numBytesOfEncryptedData != nullptr) {
2235                 env->ReleaseIntArrayElements(
2236                         numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
2237                 numBytesOfEncryptedData = nullptr;
2238             }
2239 
2240             if (numBytesOfClearData != nullptr) {
2241                 env->ReleaseIntArrayElements(
2242                         numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2243                 numBytesOfClearData = nullptr;
2244             }
2245         }
2246 
2247         if (mErr == OK && mKeyObj.get() != nullptr) {
2248             if (env->GetArrayLength(mKeyObj.get()) != 16) {
2249                 mErr = -EINVAL;
2250             } else {
2251                 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2252             }
2253         }
2254 
2255         if (mErr == OK && mIvObj.get() != nullptr) {
2256             if (env->GetArrayLength(mIvObj.get()) != 16) {
2257                 mErr = -EINVAL;
2258             } else {
2259                 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2260             }
2261         }
2262 
2263     }
2264 
NativeCryptoInfoNativeCryptoInfo2265     explicit NativeCryptoInfo(jint size)
2266         : mIvObj{nullptr, nullptr},
2267           mKeyObj{nullptr, nullptr},
2268           mMode{CryptoPlugin::kMode_Unencrypted},
2269           mPattern{0, 0} {
2270         mSubSamples = new CryptoPlugin::SubSample[1];
2271         mNumSubSamples = 1;
2272         mSubSamples[0].mNumBytesOfClearData = size;
2273         mSubSamples[0].mNumBytesOfEncryptedData = 0;
2274     }
2275 
~NativeCryptoInfoNativeCryptoInfo2276     ~NativeCryptoInfo() {
2277         if (mIv != nullptr) {
2278             mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2279         }
2280 
2281         if (mKey != nullptr) {
2282             mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2283         }
2284 
2285         if (mSubSamples != nullptr) {
2286             delete[] mSubSamples;
2287         }
2288     }
2289 
2290     JNIEnv *mEnv{nullptr};
2291     ScopedLocalRef<jbyteArray> mIvObj;
2292     ScopedLocalRef<jbyteArray> mKeyObj;
2293     status_t mErr{OK};
2294 
2295     CryptoPlugin::SubSample *mSubSamples{nullptr};
2296     int32_t mNumSubSamples{0};
2297     jbyte *mIv{nullptr};
2298     jbyte *mKey{nullptr};
2299     enum CryptoPlugin::Mode mMode;
2300     CryptoPlugin::Pattern mPattern;
2301 };
2302 
2303 // This class takes away all dependencies on java(env and jni) and
2304 // could be used for taking cryptoInfo objects to MediaCodec.
2305 struct MediaCodecCryptoInfo: public CodecCryptoInfo {
MediaCodecCryptoInfoMediaCodecCryptoInfo2306     explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
2307         if (cryptoInfo.mErr == OK) {
2308             mNumSubSamples = cryptoInfo.mNumSubSamples;
2309             mMode = cryptoInfo.mMode;
2310             mPattern = cryptoInfo.mPattern;
2311             if (cryptoInfo.mKey != nullptr) {
2312                 mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
2313                 mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
2314             }
2315             if (cryptoInfo.mIv != nullptr) {
2316                mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
2317                mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
2318             }
2319             if (cryptoInfo.mSubSamples != nullptr) {
2320                 mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
2321                 if (mSubSamplesBuffer.get()) {
2322                     CryptoPlugin::SubSample * samples =
2323                             (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2324                     for (int s = 0 ; s < mNumSubSamples ; s++) {
2325                         samples[s].mNumBytesOfClearData =
2326                                 cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
2327                         samples[s].mNumBytesOfEncryptedData =
2328                                 cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
2329                     }
2330                     mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2331                 }
2332             }
2333 
2334         }
2335     }
2336 
MediaCodecCryptoInfoMediaCodecCryptoInfo2337     explicit MediaCodecCryptoInfo(jint size) {
2338         mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
2339         mNumSubSamples = 1;
2340         if (mSubSamplesBuffer.get()) {
2341             CryptoPlugin::SubSample * samples =
2342                     (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2343             samples[0].mNumBytesOfClearData = size;
2344             samples[0].mNumBytesOfEncryptedData = 0;
2345             mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2346         }
2347     }
~MediaCodecCryptoInfoMediaCodecCryptoInfo2348     ~MediaCodecCryptoInfo() {}
2349 
2350 protected:
2351     // all backup buffers for the base object.
2352     sp<ABuffer> mKeyBuffer;
2353     sp<ABuffer> mIvBuffer;
2354     sp<ABuffer> mSubSamplesBuffer;
2355 
2356 };
2357 
android_media_MediaCodec_queueSecureInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jobject cryptoInfoObj,jlong timestampUs,jint flags)2358 static void android_media_MediaCodec_queueSecureInputBuffer(
2359         JNIEnv *env,
2360         jobject thiz,
2361         jint index,
2362         jint offset,
2363         jobject cryptoInfoObj,
2364         jlong timestampUs,
2365         jint flags) {
2366     ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2367 
2368     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2369 
2370     if (codec == NULL || codec->initCheck() != OK) {
2371         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2372         return;
2373     }
2374 
2375     jint numSubSamples =
2376         env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2377 
2378     jintArray numBytesOfClearDataObj =
2379         (jintArray)env->GetObjectField(
2380                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2381 
2382     jintArray numBytesOfEncryptedDataObj =
2383         (jintArray)env->GetObjectField(
2384                 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2385 
2386     jbyteArray keyObj =
2387         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2388 
2389     jbyteArray ivObj =
2390         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2391 
2392     jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2393     enum CryptoPlugin::Mode mode;
2394     if (jmode == gCryptoModes.Unencrypted) {
2395         mode = CryptoPlugin::kMode_Unencrypted;
2396     } else if (jmode == gCryptoModes.AesCtr) {
2397         mode = CryptoPlugin::kMode_AES_CTR;
2398     } else if (jmode == gCryptoModes.AesCbc) {
2399         mode = CryptoPlugin::kMode_AES_CBC;
2400     }  else {
2401         throwExceptionAsNecessary(
2402                 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2403                 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
2404         return;
2405     }
2406 
2407     jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2408 
2409     CryptoPlugin::Pattern pattern;
2410     if (patternObj == NULL) {
2411         pattern.mEncryptBlocks = 0;
2412         pattern.mSkipBlocks = 0;
2413     } else {
2414         pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2415         pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2416     }
2417 
2418     status_t err = OK;
2419 
2420     CryptoPlugin::SubSample *subSamples = NULL;
2421     jbyte *key = NULL;
2422     jbyte *iv = NULL;
2423 
2424     if (numSubSamples <= 0) {
2425         err = -EINVAL;
2426     } else if (numBytesOfClearDataObj == NULL
2427             && numBytesOfEncryptedDataObj == NULL) {
2428         err = -EINVAL;
2429     } else if (numBytesOfEncryptedDataObj != NULL
2430             && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2431         err = -ERANGE;
2432     } else if (numBytesOfClearDataObj != NULL
2433             && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2434         err = -ERANGE;
2435     // subSamples array may silently overflow if number of samples are too large.  Use
2436     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2437     } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2438         err = -EINVAL;
2439     } else {
2440         jboolean isCopy;
2441 
2442         jint *numBytesOfClearData =
2443             (numBytesOfClearDataObj == NULL)
2444                 ? NULL
2445                 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2446 
2447         jint *numBytesOfEncryptedData =
2448             (numBytesOfEncryptedDataObj == NULL)
2449                 ? NULL
2450                 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2451 
2452         subSamples = new CryptoPlugin::SubSample[numSubSamples];
2453 
2454         for (jint i = 0; i < numSubSamples; ++i) {
2455             subSamples[i].mNumBytesOfClearData =
2456                 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2457 
2458             subSamples[i].mNumBytesOfEncryptedData =
2459                 (numBytesOfEncryptedData == NULL)
2460                     ? 0 : numBytesOfEncryptedData[i];
2461         }
2462 
2463         if (numBytesOfEncryptedData != NULL) {
2464             env->ReleaseIntArrayElements(
2465                     numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2466             numBytesOfEncryptedData = NULL;
2467         }
2468 
2469         if (numBytesOfClearData != NULL) {
2470             env->ReleaseIntArrayElements(
2471                     numBytesOfClearDataObj, numBytesOfClearData, 0);
2472             numBytesOfClearData = NULL;
2473         }
2474     }
2475 
2476     if (err == OK && keyObj != NULL) {
2477         if (env->GetArrayLength(keyObj) != 16) {
2478             err = -EINVAL;
2479         } else {
2480             jboolean isCopy;
2481             key = env->GetByteArrayElements(keyObj, &isCopy);
2482         }
2483     }
2484 
2485     if (err == OK && ivObj != NULL) {
2486         if (env->GetArrayLength(ivObj) != 16) {
2487             err = -EINVAL;
2488         } else {
2489             jboolean isCopy;
2490             iv = env->GetByteArrayElements(ivObj, &isCopy);
2491         }
2492     }
2493 
2494     AString errorDetailMsg;
2495 
2496     if (err == OK) {
2497         err = codec->queueSecureInputBuffer(
2498                 index, offset,
2499                 subSamples, numSubSamples,
2500                 (const uint8_t *)key, (const uint8_t *)iv,
2501                 mode,
2502                 pattern,
2503                 timestampUs,
2504                 flags,
2505                 &errorDetailMsg);
2506     }
2507 
2508     if (iv != NULL) {
2509         env->ReleaseByteArrayElements(ivObj, iv, 0);
2510         iv = NULL;
2511     }
2512 
2513     if (key != NULL) {
2514         env->ReleaseByteArrayElements(keyObj, key, 0);
2515         key = NULL;
2516     }
2517 
2518     delete[] subSamples;
2519     subSamples = NULL;
2520 
2521     throwExceptionAsNecessary(
2522             env, err, ACTION_CODE_FATAL,
2523             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
2524 }
2525 
extractCryptoInfosFromObjectArray(JNIEnv * const env,jint * const totalSize,std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,const jobjectArray & objArray,AString * const errorDetailMsg)2526 static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
2527         jint * const totalSize,
2528         std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
2529         const jobjectArray &objArray,
2530         AString * const errorDetailMsg) {
2531     if (env == nullptr
2532             || cryptoInfoObjs == nullptr
2533             || totalSize == nullptr) {
2534         if (errorDetailMsg) {
2535             *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2536         }
2537         return BAD_VALUE;
2538     }
2539     const jsize numEntries = env->GetArrayLength(objArray);
2540     if (numEntries <= 0) {
2541         if (errorDetailMsg) {
2542             *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
2543         }
2544         return BAD_VALUE;
2545     }
2546     cryptoInfoObjs->clear();
2547     *totalSize = 0;
2548     jint size = 0;
2549     for (jsize i = 0; i < numEntries ; i++) {
2550         jobject param = env->GetObjectArrayElement(objArray, i);
2551         if (param == NULL) {
2552             if (errorDetailMsg) {
2553                 *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2554             }
2555             return BAD_VALUE;
2556         }
2557         NativeCryptoInfo nativeInfo(env, param);
2558         std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
2559         for (int i = 0; i < info->mNumSubSamples; i++) {
2560             size += info->mSubSamples[i].mNumBytesOfClearData;
2561             size += info->mSubSamples[i].mNumBytesOfEncryptedData;
2562         }
2563         cryptoInfoObjs->push_back(std::move(info));
2564     }
2565     *totalSize = size;
2566     return OK;
2567 }
2568 
2569 
android_media_MediaCodec_queueSecureInputBuffers(JNIEnv * env,jobject thiz,jint index,jobjectArray bufferInfosObjs,jobjectArray cryptoInfoObjs)2570 static void android_media_MediaCodec_queueSecureInputBuffers(
2571         JNIEnv *env,
2572         jobject thiz,
2573         jint index,
2574         jobjectArray bufferInfosObjs,
2575         jobjectArray cryptoInfoObjs) {
2576     ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
2577 
2578     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2579 
2580     if (codec == NULL || codec->initCheck() != OK) {
2581         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2582         return;
2583     }
2584     sp<BufferInfosWrapper> auInfos =
2585             new BufferInfosWrapper{decltype(auInfos->value)()};
2586     sp<CryptoInfosWrapper> cryptoInfos =
2587         new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
2588     AString errorDetailMsg;
2589     jint initialOffset = 0;
2590     jint totalSize = 0;
2591     status_t err = extractInfosFromObject(
2592             env,
2593             &initialOffset,
2594             &totalSize,
2595             &auInfos->value,
2596             bufferInfosObjs,
2597             &errorDetailMsg);
2598     if (err == OK) {
2599         err = extractCryptoInfosFromObjectArray(env,
2600             &totalSize,
2601             &cryptoInfos->value,
2602             cryptoInfoObjs,
2603             &errorDetailMsg);
2604     }
2605     if (err == OK) {
2606         err = codec->queueSecureInputBuffers(
2607                 index,
2608                 initialOffset,
2609                 totalSize,
2610                 auInfos,
2611                 cryptoInfos,
2612                 &errorDetailMsg);
2613     }
2614     throwExceptionAsNecessary(
2615             env, err, ACTION_CODE_FATAL,
2616             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
2617 }
2618 
android_media_MediaCodec_mapHardwareBuffer(JNIEnv * env,jclass,jobject bufferObj)2619 static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
2620     ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2621     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2622             env, bufferObj);
2623     AHardwareBuffer_Desc desc;
2624     AHardwareBuffer_describe(hardwareBuffer, &desc);
2625     if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2626         ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2627         return nullptr;
2628     }
2629     if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2630         ALOGI("mapHardwareBuffer: buffer not CPU readable");
2631         return nullptr;
2632     }
2633     bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2634 
2635     uint64_t cpuUsage = 0;
2636     cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2637     cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
2638 
2639     AHardwareBuffer_Planes planes;
2640     int err = AHardwareBuffer_lockPlanes(
2641             hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2642     if (err != 0) {
2643         ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2644         return nullptr;
2645     }
2646 
2647     if (planes.planeCount != 3) {
2648         ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2649         return nullptr;
2650     }
2651 
2652     ScopedLocalRef<jobjectArray> buffersArray{
2653             env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2654     ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2655     ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
2656 
2657     jboolean isCopy = JNI_FALSE;
2658     jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2659     jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2660 
2661     // For Y plane
2662     int rowSampling = 1;
2663     int colSampling = 1;
2664     // plane indices are Y-U-V.
2665     for (uint32_t i = 0; i < 3; ++i) {
2666         const AHardwareBuffer_Plane &plane = planes.planes[i];
2667         int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2668         int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2669         int maxOffset = maxRowOffset + maxColOffset;
2670         ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2671                 env,
2672                 plane.data,
2673                 maxOffset + 1,
2674                 0,
2675                 maxOffset + 1,
2676                 readOnly,
2677                 true)};
2678 
2679         env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2680         rowStrides[i] = plane.rowStride;
2681         pixelStrides[i] = plane.pixelStride;
2682         // For U-V planes
2683         rowSampling = 2;
2684         colSampling = 2;
2685     }
2686 
2687     env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2688     env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2689     rowStrides = pixelStrides = nullptr;
2690 
2691     ScopedLocalRef<jclass> imageClazz(
2692             env, env->FindClass("android/media/MediaCodec$MediaImage"));
2693     CHECK(imageClazz.get() != NULL);
2694 
2695     jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
2696             "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
2697 
2698     jobject img = env->NewObject(imageClazz.get(), imageConstructID,
2699             buffersArray.get(),
2700             rowStridesArray.get(),
2701             pixelStridesArray.get(),
2702             desc.width,
2703             desc.height,
2704             desc.format, // ???
2705             (jboolean)readOnly /* readOnly */,
2706             (jlong)0 /* timestamp */,
2707             (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2708             (jlong)hardwareBuffer);
2709 
2710     // if MediaImage creation fails, return null
2711     if (env->ExceptionCheck()) {
2712         env->ExceptionDescribe();
2713         env->ExceptionClear();
2714         return nullptr;
2715     }
2716 
2717     AHardwareBuffer_acquire(hardwareBuffer);
2718 
2719     return img;
2720 }
2721 
android_media_MediaCodec_closeMediaImage(JNIEnv *,jclass,jlong context)2722 static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2723     ALOGV("android_media_MediaCodec_closeMediaImage");
2724     if (context == 0) {
2725         return;
2726     }
2727     AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2728 
2729     int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2730     if (err != 0) {
2731         ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2732         // Continue to release the hardwareBuffer
2733     }
2734 
2735     AHardwareBuffer_release(hardwareBuffer);
2736 }
2737 
ConvertKeyValueListsToAMessage(JNIEnv * env,jobject keys,jobject values,sp<AMessage> * msg)2738 static status_t ConvertKeyValueListsToAMessage(
2739         JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2740     static struct Fields {
2741         explicit Fields(JNIEnv *env) {
2742             ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2743             CHECK(clazz.get() != NULL);
2744             mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2745 
2746             clazz.reset(env->FindClass("java/lang/Integer"));
2747             CHECK(clazz.get() != NULL);
2748             mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2749 
2750             mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2751             CHECK(mIntegerValueId != NULL);
2752 
2753             clazz.reset(env->FindClass("java/lang/Long"));
2754             CHECK(clazz.get() != NULL);
2755             mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2756 
2757             mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2758             CHECK(mLongValueId != NULL);
2759 
2760             clazz.reset(env->FindClass("java/lang/Float"));
2761             CHECK(clazz.get() != NULL);
2762             mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2763 
2764             mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2765             CHECK(mFloatValueId != NULL);
2766 
2767             clazz.reset(env->FindClass("java/util/ArrayList"));
2768             CHECK(clazz.get() != NULL);
2769 
2770             mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2771             CHECK(mByteBufferArrayId != NULL);
2772         }
2773 
2774         jclass mStringClass;
2775         jclass mIntegerClass;
2776         jmethodID mIntegerValueId;
2777         jclass mLongClass;
2778         jmethodID mLongValueId;
2779         jclass mFloatClass;
2780         jmethodID mFloatValueId;
2781         jmethodID mByteBufferArrayId;
2782     } sFields{env};
2783 
2784     jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2785     if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2786         return BAD_VALUE;
2787     }
2788 
2789     sp<AMessage> result{new AMessage};
2790     for (jint i = 0; i < size; ++i) {
2791         ScopedLocalRef<jstring> jkey{
2792             env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2793         const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2794         AString key;
2795         if (tmp) {
2796             key.setTo(tmp);
2797         }
2798         env->ReleaseStringUTFChars(jkey.get(), tmp);
2799         if (key.empty()) {
2800             return NO_MEMORY;
2801         }
2802 
2803         ScopedLocalRef<jobject> jvalue{
2804             env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2805 
2806         if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2807             const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2808             AString value;
2809             if (!tmp) {
2810                 return NO_MEMORY;
2811             }
2812             value.setTo(tmp);
2813             env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
2814             result->setString(key.c_str(), value);
2815         } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2816             jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2817             result->setInt32(key.c_str(), value);
2818         } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2819             jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2820             result->setInt64(key.c_str(), value);
2821         } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2822             jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2823             result->setFloat(key.c_str(), value);
2824         } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
2825             jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2826             jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
2827             sp<ABuffer> buffer{new ABuffer(limit - position)};
2828             void *data = env->GetDirectBufferAddress(jvalue.get());
2829             if (data != nullptr) {
2830                 memcpy(buffer->data(),
2831                        static_cast<const uint8_t *>(data) + position,
2832                        buffer->size());
2833             } else {
2834                 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2835                         jvalue.get(), sFields.mByteBufferArrayId)};
2836                 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2837                                         reinterpret_cast<jbyte *>(buffer->data()));
2838             }
2839             result->setBuffer(key.c_str(), buffer);
2840         }
2841     }
2842 
2843     *msg = result;
2844     return OK;
2845 }
2846 
obtain(JMediaCodecLinearBlock * context,int capacity,const std::vector<std::string> & names,bool secure)2847 static bool obtain(
2848         JMediaCodecLinearBlock *context,
2849         int capacity,
2850         const std::vector<std::string> &names,
2851         bool secure) {
2852     if (secure) {
2853         // Start at 1MB, which is an arbitrary starting point that can
2854         // increase when needed.
2855         constexpr size_t kInitialDealerCapacity = 1048576;
2856         thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2857                 kInitialDealerCapacity, "JNI(1MB)");
2858         context->mMemory = sDealer->allocate(capacity);
2859         if (context->mMemory == nullptr) {
2860             size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2861             while (capacity * 2 > newDealerCapacity) {
2862                 newDealerCapacity *= 2;
2863             }
2864             ALOGI("LinearBlock.native_obtain: "
2865                   "Dealer capacity increasing from %zuMB to %zuMB",
2866                   sDealer->getMemoryHeap()->getSize() / 1048576,
2867                   newDealerCapacity / 1048576);
2868             sDealer = new MemoryDealer(
2869                     newDealerCapacity,
2870                     AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2871             context->mMemory = sDealer->allocate(capacity);
2872         }
2873         context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2874                     &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2875     } else {
2876         context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2877         if (!context->mBlock) {
2878             return false;
2879         }
2880     }
2881     context->mCodecNames = names;
2882     return true;
2883 }
2884 
extractMemoryFromContext(JMediaCodecLinearBlock * context,jint offset,jint size,sp<hardware::HidlMemory> * memory)2885 static void extractMemoryFromContext(
2886         JMediaCodecLinearBlock *context,
2887         jint offset,
2888         jint size,
2889         sp<hardware::HidlMemory> *memory) {
2890     if ((offset + size) > context->capacity()) {
2891         ALOGW("extractMemoryFromContext: offset + size provided exceed capacity");
2892         return;
2893     }
2894     *memory = context->toHidlMemory();
2895     if (*memory == nullptr) {
2896         if (!context->mBlock) {
2897             ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2898             return;
2899         }
2900         ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2901                 context->capacity());
2902         if (!obtain(context, context->capacity(),
2903                     context->mCodecNames, true /* secure */)) {
2904             ALOGW("extractMemoryFromContext: failed to obtain secure block");
2905             return;
2906         }
2907         *memory = context->toHidlMemory();
2908     }
2909     if (context->mBlock == nullptr || context->mReadWriteMapping == nullptr) {
2910         ALOGW("extractMemoryFromContext: Cannot extract memory as C2Block is not created/mapped");
2911         return;
2912     }
2913     if (context->mReadWriteMapping->error() != C2_OK) {
2914         ALOGW("extractMemoryFromContext: failed to map C2Block (%d)",
2915                 context->mReadWriteMapping->error());
2916         return;
2917     }
2918     // We are proceeding to extract memory from C2Block
2919     uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2920     memcpy(memoryPtr + offset, context->mReadWriteMapping->base() + offset, size);
2921 }
2922 
extractBufferFromContext(JMediaCodecLinearBlock * context,jint offset,jint size,std::shared_ptr<C2Buffer> * buffer)2923 static void extractBufferFromContext(
2924         JMediaCodecLinearBlock *context,
2925         jint offset,
2926         jint size,
2927         std::shared_ptr<C2Buffer> *buffer) {
2928     if ((offset + size) > context->capacity()) {
2929         ALOGW("extractBufferFromContext: offset + size provided exceed capacity");
2930         return;
2931     }
2932     *buffer = context->toC2Buffer(offset, size);
2933     if (*buffer == nullptr) {
2934         if (!context->mMemory) {
2935             ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2936             return;
2937         }
2938         ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2939               context->capacity());
2940         if (obtain(context, context->capacity(),
2941                    context->mCodecNames, false /* secure */)) {
2942             ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2943             return;
2944         }
2945         C2WriteView view = context->mBlock->map().get();
2946         if (view.error() != C2_OK) {
2947             ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2948             return;
2949         }
2950         uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2951         memcpy(view.base() + offset, memoryPtr + offset, size);
2952         context->mMemory.clear();
2953         context->mHidlMemory.clear();
2954         context->mHidlMemorySize = 0;
2955         context->mHidlMemoryOffset = 0;
2956         *buffer = context->toC2Buffer(offset, size);
2957     }
2958 }
2959 
android_media_MediaCodec_native_queueLinearBlock(JNIEnv * env,jobject thiz,jint index,jobject bufferObj,jobjectArray cryptoInfoArray,jobjectArray objArray,jobject keys,jobject values)2960 static void android_media_MediaCodec_native_queueLinearBlock(
2961         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2962         jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
2963     ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2964 
2965     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2966 
2967     if (codec == nullptr || codec->initCheck() != OK) {
2968         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2969         return;
2970     }
2971 
2972     sp<AMessage> tunings;
2973     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2974     if (err != OK) {
2975         throwExceptionAsNecessary(
2976                 env, err, ACTION_CODE_FATAL,
2977                 "error occurred while converting tunings from Java to native");
2978         return;
2979     }
2980     jint totalSize = 0;
2981     jint initialOffset = 0;
2982     std::vector<AccessUnitInfo> infoVec;
2983     AString errorDetailMsg;
2984     err = extractInfosFromObject(env,
2985             &initialOffset,
2986             &totalSize,
2987             &infoVec,
2988             objArray,
2989             &errorDetailMsg);
2990     if (err != OK) {
2991         throwExceptionAsNecessary(
2992                 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2993                 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2994         return;
2995     }
2996     sp<BufferInfosWrapper> infos =
2997             new BufferInfosWrapper{std::move(infoVec)};
2998     std::shared_ptr<C2Buffer> buffer;
2999     sp<hardware::HidlMemory> memory;
3000     ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
3001     if (env->MonitorEnter(lock.get()) == JNI_OK) {
3002         if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
3003             JMediaCodecLinearBlock *context =
3004                 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
3005             if (codec->hasCryptoOrDescrambler()) {
3006                 extractMemoryFromContext(context, initialOffset, totalSize, &memory);
3007                 initialOffset += context->mHidlMemoryOffset;
3008             } else {
3009                 extractBufferFromContext(context, initialOffset, totalSize, &buffer);
3010             }
3011         }
3012         env->MonitorExit(lock.get());
3013     } else {
3014         throwExceptionAsNecessary(
3015                 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3016                 "Failed to grab lock for a LinearBlock object");
3017         return;
3018     }
3019 
3020     if (codec->hasCryptoOrDescrambler()) {
3021         if (!memory) {
3022             // It means there was an unexpected failure in extractMemoryFromContext above
3023             ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
3024             throwExceptionAsNecessary(
3025                     env, BAD_VALUE, ACTION_CODE_FATAL,
3026                     "Unexpected error: the input buffer is not compatible with "
3027                     "the secure codec, and a fallback logic failed.\n"
3028                     "Suggestion: please try including the secure codec when calling "
3029                     "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
3030             return;
3031         }
3032         sp<CryptoInfosWrapper> cryptoInfos = nullptr;
3033         jint sampleSize = totalSize;
3034         if (cryptoInfoArray != nullptr) {
3035             cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
3036             extractCryptoInfosFromObjectArray(env,
3037                     &sampleSize,
3038                     &cryptoInfos->value,
3039                     cryptoInfoArray,
3040                     &errorDetailMsg);
3041         }
3042         if (env->ExceptionCheck()) {
3043             // Creation of cryptoInfo failed. Let the exception bubble up.
3044             return;
3045         }
3046         err = codec->queueEncryptedLinearBlock(
3047                 index,
3048                 memory,
3049                 initialOffset,
3050                 sampleSize,
3051                 infos,
3052                 cryptoInfos,
3053                 tunings,
3054                 &errorDetailMsg);
3055         ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
3056     } else {
3057         if (!buffer) {
3058             // It means there was an unexpected failure in extractBufferFromContext above
3059             ALOGI("queueLinearBlock: no C2Buffer found");
3060             throwExceptionAsNecessary(
3061                     env, BAD_VALUE, ACTION_CODE_FATAL,
3062                     "Unexpected error: the input buffer is not compatible with "
3063                     "the non-secure codec, and a fallback logic failed.\n"
3064                     "Suggestion: please do not include the secure codec when calling "
3065                     "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
3066             return;
3067         }
3068         err = codec->queueBuffer(
3069                 index, buffer, infos, tunings, &errorDetailMsg);
3070     }
3071     throwExceptionAsNecessary(
3072             env, err, ACTION_CODE_FATAL,
3073             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
3074 }
3075 
android_media_MediaCodec_native_queueHardwareBuffer(JNIEnv * env,jobject thiz,jint index,jobject bufferObj,jlong presentationTimeUs,jint flags,jobject keys,jobject values)3076 static void android_media_MediaCodec_native_queueHardwareBuffer(
3077         JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
3078         jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
3079     ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
3080 
3081     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3082 
3083     if (codec == NULL || codec->initCheck() != OK) {
3084         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3085         return;
3086     }
3087 
3088     sp<AMessage> tunings;
3089     status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
3090     if (err != OK) {
3091         throwExceptionAsNecessary(
3092                 env, err, ACTION_CODE_FATAL,
3093                 "error occurred while converting tunings from Java to native");
3094         return;
3095     }
3096 
3097     AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
3098             env, bufferObj);
3099     sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
3100     C2Handle *handle = WrapNativeCodec2GrallocHandle(
3101             graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
3102             graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
3103     static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
3104         std::shared_ptr<C2Allocator> alloc;
3105         c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
3106                 C2PlatformAllocatorStore::GRALLOC, &alloc);
3107         if (err == C2_OK) {
3108             return alloc;
3109         }
3110         return nullptr;
3111     }();
3112     std::shared_ptr<C2GraphicAllocation> alloc;
3113     c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
3114     if (c2err != C2_OK) {
3115         ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
3116         native_handle_close(handle);
3117         native_handle_delete(handle);
3118         throwExceptionAsNecessary(
3119                 env, BAD_VALUE, ACTION_CODE_FATAL,
3120                 "HardwareBuffer not recognized");
3121         return;
3122     }
3123     std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
3124     std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
3125             block->crop(), C2Fence{}));
3126     AString errorDetailMsg;
3127     sp<BufferInfosWrapper> infos =
3128         new BufferInfosWrapper{decltype(infos->value)()};
3129     infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
3130     err = codec->queueBuffer(
3131             index, buffer, infos, tunings, &errorDetailMsg);
3132     throwExceptionAsNecessary(
3133             env, err, ACTION_CODE_FATAL,
3134             codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
3135 }
3136 
android_media_MediaCodec_native_getOutputFrame(JNIEnv * env,jobject thiz,jobject frame,jint index)3137 static void android_media_MediaCodec_native_getOutputFrame(
3138         JNIEnv *env, jobject thiz, jobject frame, jint index) {
3139     ALOGV("android_media_MediaCodec_native_getOutputFrame");
3140 
3141     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3142 
3143     if (codec == NULL || codec->initCheck() != OK) {
3144         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3145         return;
3146     }
3147 
3148     status_t err = codec->getOutputFrame(env, frame, index);
3149     if (err != OK) {
3150         throwExceptionAsNecessary(env, err, codec);
3151     }
3152 }
3153 
android_media_MediaCodec_dequeueInputBuffer(JNIEnv * env,jobject thiz,jlong timeoutUs)3154 static jint android_media_MediaCodec_dequeueInputBuffer(
3155         JNIEnv *env, jobject thiz, jlong timeoutUs) {
3156     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
3157 
3158     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3159 
3160     if (codec == NULL || codec->initCheck() != OK) {
3161         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3162         return -1;
3163     }
3164 
3165     size_t index;
3166     status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
3167 
3168     if (err == OK) {
3169         return (jint) index;
3170     }
3171 
3172     return throwExceptionAsNecessary(env, err, codec);
3173 }
3174 
android_media_MediaCodec_dequeueOutputBuffer(JNIEnv * env,jobject thiz,jobject bufferInfo,jlong timeoutUs)3175 static jint android_media_MediaCodec_dequeueOutputBuffer(
3176         JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
3177     ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
3178 
3179     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3180 
3181     if (codec == NULL || codec->initCheck() != OK) {
3182         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3183         return 0;
3184     }
3185 
3186     size_t index;
3187     status_t err = codec->dequeueOutputBuffer(
3188             env, bufferInfo, &index, timeoutUs);
3189 
3190     if (err == OK) {
3191         return (jint) index;
3192     }
3193 
3194     return throwExceptionAsNecessary(env, err, codec);
3195 }
3196 
android_media_MediaCodec_releaseOutputBuffer(JNIEnv * env,jobject thiz,jint index,jboolean render,jboolean updatePTS,jlong timestampNs)3197 static void android_media_MediaCodec_releaseOutputBuffer(
3198         JNIEnv *env, jobject thiz,
3199         jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
3200     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
3201 
3202     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3203 
3204     if (codec == NULL || codec->initCheck() != OK) {
3205         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3206         return;
3207     }
3208 
3209     status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
3210 
3211     throwExceptionAsNecessary(env, err, codec);
3212 }
3213 
android_media_MediaCodec_signalEndOfInputStream(JNIEnv * env,jobject thiz)3214 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
3215         jobject thiz) {
3216     ALOGV("android_media_MediaCodec_signalEndOfInputStream");
3217 
3218     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3219     if (codec == NULL || codec->initCheck() != OK) {
3220         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3221         return;
3222     }
3223 
3224     status_t err = codec->signalEndOfInputStream();
3225 
3226     throwExceptionAsNecessary(env, err, codec);
3227 }
3228 
android_media_MediaCodec_getFormatNative(JNIEnv * env,jobject thiz,jboolean input)3229 static jobject android_media_MediaCodec_getFormatNative(
3230         JNIEnv *env, jobject thiz, jboolean input) {
3231     ALOGV("android_media_MediaCodec_getFormatNative");
3232 
3233     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3234 
3235     if (codec == NULL || codec->initCheck() != OK) {
3236         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3237         return NULL;
3238     }
3239 
3240     jobject format;
3241     status_t err = codec->getFormat(env, input, &format);
3242 
3243     if (err == OK) {
3244         return format;
3245     }
3246 
3247     throwExceptionAsNecessary(env, err, codec);
3248 
3249     return NULL;
3250 }
3251 
android_media_MediaCodec_getOutputFormatForIndexNative(JNIEnv * env,jobject thiz,jint index)3252 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
3253         JNIEnv *env, jobject thiz, jint index) {
3254     ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
3255 
3256     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3257 
3258     if (codec == NULL || codec->initCheck() != OK) {
3259         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3260         return NULL;
3261     }
3262 
3263     jobject format;
3264     status_t err = codec->getOutputFormat(env, index, &format);
3265 
3266     if (err == OK) {
3267         return format;
3268     }
3269 
3270     throwExceptionAsNecessary(env, err, codec);
3271 
3272     return NULL;
3273 }
3274 
android_media_MediaCodec_getBuffers(JNIEnv * env,jobject thiz,jboolean input)3275 static jobjectArray android_media_MediaCodec_getBuffers(
3276         JNIEnv *env, jobject thiz, jboolean input) {
3277     ALOGV("android_media_MediaCodec_getBuffers");
3278 
3279     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3280 
3281     if (codec == NULL || codec->initCheck() != OK) {
3282         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3283         return NULL;
3284     }
3285 
3286     jobjectArray buffers;
3287     status_t err = codec->getBuffers(env, input, &buffers);
3288 
3289     if (err == OK) {
3290         return buffers;
3291     }
3292 
3293     // if we're out of memory, an exception was already thrown
3294     if (err != NO_MEMORY) {
3295         throwExceptionAsNecessary(env, err, codec);
3296     }
3297 
3298     return NULL;
3299 }
3300 
android_media_MediaCodec_getBuffer(JNIEnv * env,jobject thiz,jboolean input,jint index)3301 static jobject android_media_MediaCodec_getBuffer(
3302         JNIEnv *env, jobject thiz, jboolean input, jint index) {
3303     ALOGV("android_media_MediaCodec_getBuffer");
3304 
3305     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3306 
3307     if (codec == NULL || codec->initCheck() != OK) {
3308         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3309         return NULL;
3310     }
3311 
3312     jobject buffer;
3313     status_t err = codec->getBuffer(env, input, index, &buffer);
3314 
3315     if (err == OK) {
3316         return buffer;
3317     }
3318 
3319     // if we're out of memory, an exception was already thrown
3320     if (err != NO_MEMORY) {
3321         throwExceptionAsNecessary(env, err, codec);
3322     }
3323 
3324     return NULL;
3325 }
3326 
android_media_MediaCodec_getImage(JNIEnv * env,jobject thiz,jboolean input,jint index)3327 static jobject android_media_MediaCodec_getImage(
3328         JNIEnv *env, jobject thiz, jboolean input, jint index) {
3329     ALOGV("android_media_MediaCodec_getImage");
3330 
3331     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3332 
3333     if (codec == NULL || codec->initCheck() != OK) {
3334         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3335         return NULL;
3336     }
3337 
3338     jobject image;
3339     status_t err = codec->getImage(env, input, index, &image);
3340 
3341     if (err == OK) {
3342         return image;
3343     }
3344 
3345     // if we're out of memory, an exception was already thrown
3346     if (err != NO_MEMORY) {
3347         throwExceptionAsNecessary(env, err, codec);
3348     }
3349 
3350     return NULL;
3351 }
3352 
android_media_MediaCodec_getName(JNIEnv * env,jobject thiz)3353 static jobject android_media_MediaCodec_getName(
3354         JNIEnv *env, jobject thiz) {
3355     ALOGV("android_media_MediaCodec_getName");
3356 
3357     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3358 
3359     if (codec == NULL || codec->initCheck() != OK) {
3360         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3361         return NULL;
3362     }
3363 
3364     jstring name;
3365     status_t err = codec->getName(env, &name);
3366 
3367     if (err == OK) {
3368         return name;
3369     }
3370 
3371     throwExceptionAsNecessary(env, err, codec);
3372 
3373     return NULL;
3374 }
3375 
android_media_MediaCodec_getOwnCodecInfo(JNIEnv * env,jobject thiz)3376 static jobject android_media_MediaCodec_getOwnCodecInfo(
3377         JNIEnv *env, jobject thiz) {
3378     ALOGV("android_media_MediaCodec_getOwnCodecInfo");
3379 
3380     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3381 
3382     if (codec == NULL || codec->initCheck() != OK) {
3383         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3384         return NULL;
3385     }
3386 
3387     jobject codecInfoObj;
3388     status_t err = codec->getCodecInfo(env, &codecInfoObj);
3389 
3390     if (err == OK) {
3391         return codecInfoObj;
3392     }
3393 
3394     throwExceptionAsNecessary(env, err, codec);
3395 
3396     return NULL;
3397 }
3398 
3399 static jobject
android_media_MediaCodec_native_getMetrics(JNIEnv * env,jobject thiz)3400 android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
3401 {
3402     ALOGV("android_media_MediaCodec_native_getMetrics");
3403 
3404     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3405     if (codec == NULL || codec->initCheck() != OK) {
3406         jniThrowException(env, "java/lang/IllegalStateException",
3407                           GetExceptionMessage(codec, NULL).c_str());
3408         return 0;
3409     }
3410 
3411     // get what we have for the metrics from the codec
3412     mediametrics::Item *item = 0;
3413 
3414     status_t err = codec->getMetrics(env, item);
3415     if (err != OK) {
3416         ALOGE("getMetrics failed");
3417         return (jobject) NULL;
3418     }
3419 
3420     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
3421 
3422     // housekeeping
3423     delete item;
3424     item = 0;
3425 
3426     return mybundle;
3427 }
3428 
android_media_MediaCodec_setParameters(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray vals)3429 static void android_media_MediaCodec_setParameters(
3430         JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3431     ALOGV("android_media_MediaCodec_setParameters");
3432 
3433     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3434 
3435     if (codec == NULL || codec->initCheck() != OK) {
3436         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3437         return;
3438     }
3439 
3440     sp<AMessage> params;
3441     status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3442 
3443     if (err == OK) {
3444         err = codec->setParameters(params);
3445     }
3446 
3447     throwExceptionAsNecessary(env, err, codec);
3448 }
3449 
android_media_MediaCodec_setVideoScalingMode(JNIEnv * env,jobject thiz,jint mode)3450 static void android_media_MediaCodec_setVideoScalingMode(
3451         JNIEnv *env, jobject thiz, jint mode) {
3452     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3453 
3454     if (codec == NULL || codec->initCheck() != OK) {
3455         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3456         return;
3457     }
3458 
3459     if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3460             && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
3461         jniThrowException(env, "java/lang/IllegalArgumentException",
3462                           String8::format("Unrecognized mode: %d", mode).c_str());
3463         return;
3464     }
3465 
3466     codec->setVideoScalingMode(mode);
3467 }
3468 
android_media_MediaCodec_setAudioPresentation(JNIEnv * env,jobject thiz,jint presentationId,jint programId)3469 static void android_media_MediaCodec_setAudioPresentation(
3470         JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3471     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3472 
3473     if (codec == NULL || codec->initCheck() != OK) {
3474         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3475         return;
3476     }
3477 
3478     codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3479 }
3480 
android_media_MediaCodec_getSupportedVendorParameters(JNIEnv * env,jobject thiz)3481 static jobject android_media_MediaCodec_getSupportedVendorParameters(
3482         JNIEnv *env, jobject thiz) {
3483     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3484 
3485     if (codec == NULL || codec->initCheck() != OK) {
3486         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3487         return NULL;
3488     }
3489 
3490     jobject ret = NULL;
3491     status_t status = codec->querySupportedVendorParameters(env, &ret);
3492     if (status != OK) {
3493         throwExceptionAsNecessary(env, status, codec);
3494     }
3495 
3496     return ret;
3497 }
3498 
android_media_MediaCodec_getParameterDescriptor(JNIEnv * env,jobject thiz,jstring name)3499 static jobject android_media_MediaCodec_getParameterDescriptor(
3500         JNIEnv *env, jobject thiz, jstring name) {
3501     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3502 
3503     if (codec == NULL || codec->initCheck() != OK) {
3504         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3505         return NULL;
3506     }
3507 
3508     jobject ret = NULL;
3509     status_t status = codec->describeParameter(env, name, &ret);
3510     if (status != OK) {
3511         ret = NULL;
3512     }
3513     return ret;
3514 }
3515 
android_media_MediaCodec_subscribeToVendorParameters(JNIEnv * env,jobject thiz,jobject names)3516 static void android_media_MediaCodec_subscribeToVendorParameters(
3517         JNIEnv *env, jobject thiz, jobject names) {
3518     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3519 
3520     if (codec == NULL || codec->initCheck() != OK) {
3521         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3522         return;
3523     }
3524 
3525     status_t status = codec->subscribeToVendorParameters(env, names);
3526     if (status != OK) {
3527         throwExceptionAsNecessary(env, status, codec);
3528     }
3529     return;
3530 }
3531 
android_media_MediaCodec_unsubscribeFromVendorParameters(JNIEnv * env,jobject thiz,jobject names)3532 static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3533         JNIEnv *env, jobject thiz, jobject names) {
3534     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3535 
3536     if (codec == NULL || codec->initCheck() != OK) {
3537         throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
3538         return;
3539     }
3540 
3541     status_t status = codec->unsubscribeFromVendorParameters(env, names);
3542     if (status != OK) {
3543         throwExceptionAsNecessary(env, status, codec);
3544     }
3545     return;
3546 }
3547 
android_media_MediaCodec_native_init(JNIEnv * env,jclass)3548 static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
3549     ScopedLocalRef<jclass> clazz(
3550             env, env->FindClass("android/media/MediaCodec"));
3551     CHECK(clazz.get() != NULL);
3552 
3553     gFields.postEventFromNativeID =
3554         env->GetMethodID(
3555                 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
3556     CHECK(gFields.postEventFromNativeID != NULL);
3557 
3558     gFields.lockAndGetContextID =
3559         env->GetMethodID(
3560                 clazz.get(), "lockAndGetContext", "()J");
3561     CHECK(gFields.lockAndGetContextID != NULL);
3562 
3563     gFields.setAndUnlockContextID =
3564         env->GetMethodID(
3565                 clazz.get(), "setAndUnlockContext", "(J)V");
3566     CHECK(gFields.setAndUnlockContextID != NULL);
3567 
3568     jfieldID field;
3569     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3570     CHECK(field != NULL);
3571     gCryptoModes.Unencrypted =
3572         env->GetStaticIntField(clazz.get(), field);
3573 
3574     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3575     CHECK(field != NULL);
3576     gCryptoModes.AesCtr =
3577         env->GetStaticIntField(clazz.get(), field);
3578 
3579     field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3580     CHECK(field != NULL);
3581     gCryptoModes.AesCbc =
3582         env->GetStaticIntField(clazz.get(), field);
3583 
3584     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3585     CHECK(clazz.get() != NULL);
3586 
3587     gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3588     CHECK(gFields.cryptoInfoSetID != NULL);
3589 
3590     gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3591     CHECK(gFields.cryptoInfoSetPatternID != NULL);
3592 
3593     gFields.cryptoInfoNumSubSamplesID =
3594         env->GetFieldID(clazz.get(), "numSubSamples", "I");
3595     CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3596 
3597     gFields.cryptoInfoNumBytesOfClearDataID =
3598         env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
3599     CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3600 
3601     gFields.cryptoInfoNumBytesOfEncryptedDataID =
3602         env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
3603     CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3604 
3605     gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
3606     CHECK(gFields.cryptoInfoKeyID != NULL);
3607 
3608     gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
3609     CHECK(gFields.cryptoInfoIVID != NULL);
3610 
3611     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
3612     CHECK(gFields.cryptoInfoModeID != NULL);
3613 
3614     gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
3615         "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3616     CHECK(gFields.cryptoInfoPatternID != NULL);
3617 
3618     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3619     CHECK(clazz.get() != NULL);
3620 
3621     gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3622     CHECK(gFields.patternEncryptBlocksID != NULL);
3623 
3624     gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3625     CHECK(gFields.patternSkipBlocksID != NULL);
3626 
3627     clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3628     CHECK(clazz.get() != NULL);
3629 
3630     gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3631     CHECK(gFields.queueRequestIndexID != NULL);
3632 
3633     clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3634     CHECK(clazz.get() != NULL);
3635 
3636     gFields.outputFrameLinearBlockID =
3637         env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3638     CHECK(gFields.outputFrameLinearBlockID != NULL);
3639 
3640     gFields.outputFramebufferInfosID =
3641         env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
3642     CHECK(gFields.outputFramebufferInfosID != NULL);
3643 
3644     gFields.outputFrameHardwareBufferID =
3645         env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3646     CHECK(gFields.outputFrameHardwareBufferID != NULL);
3647 
3648     gFields.outputFrameChangedKeysID =
3649         env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3650     CHECK(gFields.outputFrameChangedKeysID != NULL);
3651 
3652     gFields.outputFrameFormatID =
3653         env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3654     CHECK(gFields.outputFrameFormatID != NULL);
3655 
3656     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3657     CHECK(clazz.get() != NULL);
3658 
3659     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
3660     CHECK(field != NULL);
3661     gCryptoErrorCodes.cryptoErrorNoKey =
3662         env->GetStaticIntField(clazz.get(), field);
3663 
3664     field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
3665     CHECK(field != NULL);
3666     gCryptoErrorCodes.cryptoErrorKeyExpired =
3667         env->GetStaticIntField(clazz.get(), field);
3668 
3669     field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
3670     CHECK(field != NULL);
3671     gCryptoErrorCodes.cryptoErrorResourceBusy =
3672         env->GetStaticIntField(clazz.get(), field);
3673 
3674     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3675     CHECK(field != NULL);
3676     gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3677         env->GetStaticIntField(clazz.get(), field);
3678 
3679     field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3680     CHECK(field != NULL);
3681     gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3682         env->GetStaticIntField(clazz.get(), field);
3683 
3684     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3685     CHECK(field != NULL);
3686     gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3687         env->GetStaticIntField(clazz.get(), field);
3688 
3689     field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3690     CHECK(field != NULL);
3691     gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3692         env->GetStaticIntField(clazz.get(), field);
3693 
3694     field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3695     CHECK(field != NULL);
3696     gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3697         env->GetStaticIntField(clazz.get(), field);
3698 
3699     field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3700     CHECK(field != NULL);
3701     gCryptoErrorCodes.cryptoErrorLostState =
3702         env->GetStaticIntField(clazz.get(), field);
3703 
3704     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3705     CHECK(clazz.get() != NULL);
3706     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3707     CHECK(field != NULL);
3708     gCodecActionCodes.codecActionTransient =
3709         env->GetStaticIntField(clazz.get(), field);
3710 
3711     field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3712     CHECK(field != NULL);
3713     gCodecActionCodes.codecActionRecoverable =
3714         env->GetStaticIntField(clazz.get(), field);
3715 
3716     field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
3717     CHECK(field != NULL);
3718     gCodecErrorCodes.errorInsufficientResource =
3719         env->GetStaticIntField(clazz.get(), field);
3720 
3721     field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
3722     CHECK(field != NULL);
3723     gCodecErrorCodes.errorReclaimed =
3724         env->GetStaticIntField(clazz.get(), field);
3725 
3726     clazz.reset(env->FindClass("android/view/Surface"));
3727     CHECK(clazz.get() != NULL);
3728 
3729     field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3730     CHECK(field != NULL);
3731     gPersistentSurfaceClassInfo.mLock = field;
3732 
3733     jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3734     CHECK(method != NULL);
3735     gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3736 
3737     clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3738     CHECK(clazz.get() != NULL);
3739     gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3740 
3741     method = env->GetMethodID(clazz.get(), "<init>", "()V");
3742     CHECK(method != NULL);
3743     gPersistentSurfaceClassInfo.ctor = method;
3744 
3745     field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3746     CHECK(field != NULL);
3747     gPersistentSurfaceClassInfo.mPersistentObject = field;
3748 
3749     clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3750     CHECK(clazz.get() != NULL);
3751     gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3752 
3753     method = env->GetMethodID(clazz.get(), "<init>",
3754             "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
3755             "Ljava/util/Map;Ljava/util/Map;)V");
3756     CHECK(method != NULL);
3757     gCodecInfo.capsCtorId = method;
3758 
3759     clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3760     CHECK(clazz.get() != NULL);
3761     gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3762 
3763     field = env->GetFieldID(clazz.get(), "profile", "I");
3764     CHECK(field != NULL);
3765     gCodecInfo.profileField = field;
3766 
3767     field = env->GetFieldID(clazz.get(), "level", "I");
3768     CHECK(field != NULL);
3769     gCodecInfo.levelField = field;
3770 
3771     clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3772     CHECK(clazz.get() != NULL);
3773     gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3774 
3775     ScopedLocalRef<jclass> byteOrderClass(
3776             env, env->FindClass("java/nio/ByteOrder"));
3777     CHECK(byteOrderClass.get() != NULL);
3778 
3779     jmethodID nativeOrderID = env->GetStaticMethodID(
3780             byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3781     CHECK(nativeOrderID != NULL);
3782 
3783     ScopedLocalRef<jobject> nativeByteOrderObj{
3784         env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3785     gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3786     CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3787     nativeByteOrderObj.reset();
3788 
3789     gByteBufferInfo.orderId = env->GetMethodID(
3790             clazz.get(),
3791             "order",
3792             "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3793     CHECK(gByteBufferInfo.orderId != NULL);
3794 
3795     gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3796             clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3797     CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3798 
3799     gByteBufferInfo.positionId = env->GetMethodID(
3800             clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3801     CHECK(gByteBufferInfo.positionId != NULL);
3802 
3803     gByteBufferInfo.limitId = env->GetMethodID(
3804             clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3805     CHECK(gByteBufferInfo.limitId != NULL);
3806 
3807     gByteBufferInfo.getPositionId = env->GetMethodID(
3808             clazz.get(), "position", "()I");
3809     CHECK(gByteBufferInfo.getPositionId != NULL);
3810 
3811     gByteBufferInfo.getLimitId = env->GetMethodID(
3812             clazz.get(), "limit", "()I");
3813     CHECK(gByteBufferInfo.getLimitId != NULL);
3814 
3815     clazz.reset(env->FindClass("java/util/ArrayList"));
3816     CHECK(clazz.get() != NULL);
3817     gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3818 
3819     gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3820     CHECK(gArrayListInfo.ctorId != NULL);
3821 
3822     gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3823     CHECK(gArrayListInfo.sizeId != NULL);
3824 
3825     gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3826     CHECK(gArrayListInfo.getId != NULL);
3827 
3828     gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3829     CHECK(gArrayListInfo.addId != NULL);
3830 
3831     clazz.reset(env->FindClass("java/util/ArrayDeque"));
3832     CHECK(clazz.get() != NULL);
3833     gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3834 
3835     gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3836     CHECK(gArrayDequeInfo.ctorId != NULL);
3837 
3838     gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3839     CHECK(gArrayDequeInfo.sizeId != NULL);
3840 
3841     gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3842     CHECK(gArrayDequeInfo.addId != NULL);
3843 
3844     clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3845     CHECK(clazz.get() != NULL);
3846 
3847     gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3848 
3849     gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3850     CHECK(gLinearBlockInfo.ctorId != NULL);
3851 
3852     gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3853             clazz.get(), "setInternalStateLocked", "(JZ)V");
3854     CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3855 
3856     gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3857     CHECK(gLinearBlockInfo.contextId != NULL);
3858 
3859     gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3860     CHECK(gLinearBlockInfo.validId != NULL);
3861 
3862     gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3863     CHECK(gLinearBlockInfo.lockId != NULL);
3864 
3865     clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3866     CHECK(clazz.get() != NULL);
3867     gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3868 
3869     gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3870     CHECK(gDescriptorInfo.ctorId != NULL);
3871 
3872     gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3873     CHECK(gDescriptorInfo.nameId != NULL);
3874 
3875     gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3876     CHECK(gDescriptorInfo.typeId != NULL);
3877 
3878     clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3879     CHECK(clazz.get() != NULL);
3880     gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3881 
3882     gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3883     CHECK(gBufferInfo.ctorId != NULL);
3884 
3885     gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3886     CHECK(gBufferInfo.setId != NULL);
3887 
3888     gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
3889     gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
3890     gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
3891     gFields.bufferInfoPresentationTimeUs =
3892             env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
3893 }
3894 
android_media_MediaCodec_native_setup(JNIEnv * env,jobject thiz,jstring name,jboolean nameIsType,jboolean encoder,int pid,int uid)3895 static void android_media_MediaCodec_native_setup(
3896         JNIEnv *env, jobject thiz,
3897         jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
3898     if (name == NULL) {
3899         jniThrowException(env, "java/lang/NullPointerException",
3900                           "No codec name specified");
3901         return;
3902     }
3903 
3904     const char *tmp = env->GetStringUTFChars(name, NULL);
3905 
3906     if (tmp == NULL) {
3907         return;
3908     }
3909 
3910     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
3911 
3912     const status_t err = codec->initCheck();
3913     if (err == NAME_NOT_FOUND) {
3914         // fail and do not try again.
3915         jniThrowException(env, "java/lang/IllegalArgumentException",
3916                 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
3917         env->ReleaseStringUTFChars(name, tmp);
3918         return;
3919     }
3920     if (err == NO_MEMORY) {
3921         throwCodecException(env, err, ACTION_CODE_TRANSIENT,
3922                 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
3923         env->ReleaseStringUTFChars(name, tmp);
3924         return;
3925     }
3926     if (err == PERMISSION_DENIED) {
3927         jniThrowException(env, "java/lang/SecurityException",
3928                 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
3929                 err).c_str());
3930         env->ReleaseStringUTFChars(name, tmp);
3931         return;
3932     }
3933     if (err != OK) {
3934         // believed possible to try again
3935         jniThrowException(env, "java/io/IOException",
3936                 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
3937         env->ReleaseStringUTFChars(name, tmp);
3938         return;
3939     }
3940 
3941     env->ReleaseStringUTFChars(name, tmp);
3942 
3943     codec->registerSelf();
3944 
3945     setMediaCodec(env, thiz, codec);
3946 }
3947 
android_media_MediaCodec_native_finalize(JNIEnv * env,jobject thiz)3948 static void android_media_MediaCodec_native_finalize(
3949         JNIEnv *env, jobject thiz) {
3950     setMediaCodec(env, thiz, NULL);
3951 }
3952 
3953 // MediaCodec.LinearBlock
3954 
android_media_MediaCodec_LinearBlock_native_map(JNIEnv * env,jobject thiz)3955 static jobject android_media_MediaCodec_LinearBlock_native_map(
3956         JNIEnv *env, jobject thiz) {
3957     JMediaCodecLinearBlock *context =
3958         (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3959     if (context->mBuffer) {
3960         std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3961         if (!context->mReadonlyMapping) {
3962             const C2BufferData data = buffer->data();
3963             if (data.type() != C2BufferData::LINEAR) {
3964                 throwExceptionAsNecessary(
3965                         env, INVALID_OPERATION, ACTION_CODE_FATAL,
3966                         "Underlying buffer is not a linear buffer");
3967                 return nullptr;
3968             }
3969             if (data.linearBlocks().size() != 1u) {
3970                 throwExceptionAsNecessary(
3971                         env, INVALID_OPERATION, ACTION_CODE_FATAL,
3972                         "Underlying buffer contains more than one block");
3973                 return nullptr;
3974             }
3975             C2ConstLinearBlock block = data.linearBlocks().front();
3976             context->mReadonlyMapping =
3977                 std::make_shared<C2ReadView>(block.map().get());
3978         }
3979         return CreateByteBuffer(
3980                 env,
3981                 context->mReadonlyMapping->data(),  // base
3982                 context->mReadonlyMapping->capacity(),  // capacity
3983                 0u,  // offset
3984                 context->mReadonlyMapping->capacity(),  // size
3985                 true,  // readOnly
3986                 true /* clearBuffer */);
3987     } else if (context->mBlock) {
3988         std::shared_ptr<C2LinearBlock> block = context->mBlock;
3989         if (!context->mReadWriteMapping) {
3990             context->mReadWriteMapping =
3991                 std::make_shared<C2WriteView>(block->map().get());
3992         }
3993         return CreateByteBuffer(
3994                 env,
3995                 context->mReadWriteMapping->base(),
3996                 context->mReadWriteMapping->capacity(),
3997                 context->mReadWriteMapping->offset(),
3998                 context->mReadWriteMapping->size(),
3999                 false,  // readOnly
4000                 true /* clearBuffer */);
4001     } else if (context->mLegacyBuffer) {
4002         return CreateByteBuffer(
4003                 env,
4004                 context->mLegacyBuffer->base(),
4005                 context->mLegacyBuffer->capacity(),
4006                 context->mLegacyBuffer->offset(),
4007                 context->mLegacyBuffer->size(),
4008                 true,  // readOnly
4009                 true /* clearBuffer */);
4010     } else if (context->mMemory) {
4011         return CreateByteBuffer(
4012                 env,
4013                 context->mMemory->unsecurePointer(),
4014                 context->mMemory->size(),
4015                 0,
4016                 context->mMemory->size(),
4017                 false,  // readOnly
4018                 true /* clearBuffer */);
4019     }
4020     throwExceptionAsNecessary(
4021             env, INVALID_OPERATION, ACTION_CODE_FATAL,
4022             "Underlying buffer is empty");
4023     return nullptr;
4024 }
4025 
android_media_MediaCodec_LinearBlock_native_recycle(JNIEnv * env,jobject thiz)4026 static void android_media_MediaCodec_LinearBlock_native_recycle(
4027         JNIEnv *env, jobject thiz) {
4028     JMediaCodecLinearBlock *context =
4029         (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
4030     env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
4031     delete context;
4032 }
4033 
PopulateNamesVector(JNIEnv * env,jobjectArray codecNames,std::vector<std::string> * names)4034 static void PopulateNamesVector(
4035         JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
4036     jsize length = env->GetArrayLength(codecNames);
4037     for (jsize i = 0; i < length; ++i) {
4038         jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
4039         if (jstr == nullptr) {
4040             // null entries are ignored
4041             continue;
4042         }
4043         const char *cstr = env->GetStringUTFChars(jstr, nullptr);
4044         if (cstr == nullptr) {
4045             throwExceptionAsNecessary(
4046                     env, BAD_VALUE, ACTION_CODE_FATAL,
4047                     "Error converting Java string to native");
4048             return;
4049         }
4050         names->emplace_back(cstr);
4051         env->ReleaseStringUTFChars(jstr, cstr);
4052     }
4053 }
4054 
android_media_MediaCodec_LinearBlock_native_obtain(JNIEnv * env,jobject thiz,jint capacity,jobjectArray codecNames)4055 static void android_media_MediaCodec_LinearBlock_native_obtain(
4056         JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
4057     std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
4058     std::vector<std::string> names;
4059     PopulateNamesVector(env, codecNames, &names);
4060     bool hasSecure = false;
4061     bool hasNonSecure = false;
4062     for (const std::string &name : names) {
4063         if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4064             hasSecure = true;
4065         } else {
4066             hasNonSecure = true;
4067         }
4068     }
4069     if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
4070         jniThrowException(env, "java/io/IOException", nullptr);
4071         return;
4072     }
4073     env->CallVoidMethod(
4074             thiz,
4075             gLinearBlockInfo.setInternalStateId,
4076             (jlong)context.release(),
4077             true /* isMappable */);
4078 }
4079 
android_media_MediaCodec_LinearBlock_checkCompatible(JNIEnv * env,jclass,jobjectArray codecNames)4080 static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
4081         JNIEnv *env, jclass, jobjectArray codecNames) {
4082     std::vector<std::string> names;
4083     PopulateNamesVector(env, codecNames, &names);
4084     bool isCompatible = false;
4085     bool hasSecure = false;
4086     bool hasNonSecure = false;
4087     for (const std::string &name : names) {
4088         if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4089             hasSecure = true;
4090         } else {
4091             hasNonSecure = true;
4092         }
4093     }
4094     if (hasSecure && hasNonSecure) {
4095         return false;
4096     }
4097     status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
4098     if (err != OK) {
4099         // TODO: CodecErrorLog
4100         throwExceptionAsNecessary(env, err);
4101     }
4102     return isCompatible;
4103 }
4104 
4105 static const JNINativeMethod gMethods[] = {
4106     { "native_release", "()V", (void *)android_media_MediaCodec_release },
4107 
4108     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
4109 
4110     { "native_releasePersistentInputSurface",
4111       "(Landroid/view/Surface;)V",
4112        (void *)android_media_MediaCodec_releasePersistentInputSurface},
4113 
4114     { "native_createPersistentInputSurface",
4115       "()Landroid/media/MediaCodec$PersistentSurface;",
4116       (void *)android_media_MediaCodec_createPersistentInputSurface },
4117 
4118     { "native_setInputSurface", "(Landroid/view/Surface;)V",
4119       (void *)android_media_MediaCodec_setInputSurface },
4120 
4121     { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
4122       (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
4123 
4124     { "native_enableOnFrameRenderedListener", "(Z)V",
4125       (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
4126 
4127     { "native_setCallback",
4128       "(Landroid/media/MediaCodec$Callback;)V",
4129       (void *)android_media_MediaCodec_native_setCallback },
4130 
4131     { "native_configure",
4132       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
4133       "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
4134       (void *)android_media_MediaCodec_native_configure },
4135 
4136     { "native_setSurface",
4137       "(Landroid/view/Surface;)V",
4138       (void *)android_media_MediaCodec_native_setSurface },
4139 
4140     { "native_detachOutputSurface",
4141       "()V",
4142       (void *)android_media_MediaCodec_native_detachOutputSurface },
4143 
4144     { "createInputSurface", "()Landroid/view/Surface;",
4145       (void *)android_media_MediaCodec_createInputSurface },
4146 
4147     { "native_start", "()V", (void *)android_media_MediaCodec_start },
4148     { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
4149     { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
4150 
4151     { "native_queueInputBuffer", "(IIIJI)V",
4152       (void *)android_media_MediaCodec_queueInputBuffer },
4153 
4154     { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
4155       (void *)android_media_MediaCodec_queueInputBuffers },
4156 
4157     { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
4158       (void *)android_media_MediaCodec_queueSecureInputBuffer },
4159 
4160     { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
4161       (void *)android_media_MediaCodec_queueSecureInputBuffers },
4162 
4163     { "native_mapHardwareBuffer",
4164       "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
4165       (void *)android_media_MediaCodec_mapHardwareBuffer },
4166 
4167     { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
4168 
4169     { "native_queueLinearBlock",
4170       "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
4171       "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
4172       (void *)android_media_MediaCodec_native_queueLinearBlock },
4173 
4174     { "native_queueHardwareBuffer",
4175       "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
4176       (void *)android_media_MediaCodec_native_queueHardwareBuffer },
4177 
4178     { "native_getOutputFrame",
4179       "(Landroid/media/MediaCodec$OutputFrame;I)V",
4180       (void *)android_media_MediaCodec_native_getOutputFrame },
4181 
4182     { "native_dequeueInputBuffer", "(J)I",
4183       (void *)android_media_MediaCodec_dequeueInputBuffer },
4184 
4185     { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
4186       (void *)android_media_MediaCodec_dequeueOutputBuffer },
4187 
4188     { "releaseOutputBuffer", "(IZZJ)V",
4189       (void *)android_media_MediaCodec_releaseOutputBuffer },
4190 
4191     { "signalEndOfInputStream", "()V",
4192       (void *)android_media_MediaCodec_signalEndOfInputStream },
4193 
4194     { "getFormatNative", "(Z)Ljava/util/Map;",
4195       (void *)android_media_MediaCodec_getFormatNative },
4196 
4197     { "getOutputFormatNative", "(I)Ljava/util/Map;",
4198       (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
4199 
4200     { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
4201       (void *)android_media_MediaCodec_getBuffers },
4202 
4203     { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
4204       (void *)android_media_MediaCodec_getBuffer },
4205 
4206     { "getImage", "(ZI)Landroid/media/Image;",
4207       (void *)android_media_MediaCodec_getImage },
4208 
4209     { "getCanonicalName", "()Ljava/lang/String;",
4210       (void *)android_media_MediaCodec_getName },
4211 
4212     { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
4213         (void *)android_media_MediaCodec_getOwnCodecInfo },
4214 
4215     { "native_getMetrics", "()Landroid/os/PersistableBundle;",
4216       (void *)android_media_MediaCodec_native_getMetrics},
4217 
4218     { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
4219       (void *)android_media_MediaCodec_setParameters },
4220 
4221     { "setVideoScalingMode", "(I)V",
4222       (void *)android_media_MediaCodec_setVideoScalingMode },
4223 
4224     { "native_setAudioPresentation", "(II)V",
4225       (void *)android_media_MediaCodec_setAudioPresentation },
4226 
4227     { "native_getSupportedVendorParameters", "()Ljava/util/List;",
4228       (void *)android_media_MediaCodec_getSupportedVendorParameters },
4229 
4230     { "native_getParameterDescriptor",
4231       "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
4232       (void *)android_media_MediaCodec_getParameterDescriptor },
4233 
4234     { "native_subscribeToVendorParameters",
4235       "(Ljava/util/List;)V",
4236       (void *)android_media_MediaCodec_subscribeToVendorParameters},
4237 
4238     { "native_unsubscribeFromVendorParameters",
4239       "(Ljava/util/List;)V",
4240       (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
4241 
4242     { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
4243 
4244     { "native_setup", "(Ljava/lang/String;ZZII)V",
4245       (void *)android_media_MediaCodec_native_setup },
4246 
4247     { "native_finalize", "()V",
4248       (void *)android_media_MediaCodec_native_finalize },
4249 };
4250 
4251 static const JNINativeMethod gLinearBlockMethods[] = {
4252     { "native_map", "()Ljava/nio/ByteBuffer;",
4253       (void *)android_media_MediaCodec_LinearBlock_native_map },
4254 
4255     { "native_recycle", "()V",
4256       (void *)android_media_MediaCodec_LinearBlock_native_recycle },
4257 
4258     { "native_obtain", "(I[Ljava/lang/String;)V",
4259       (void *)android_media_MediaCodec_LinearBlock_native_obtain },
4260 
4261     { "native_checkCompatible", "([Ljava/lang/String;)Z",
4262       (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
4263 };
4264 
register_android_media_MediaCodec(JNIEnv * env)4265 int register_android_media_MediaCodec(JNIEnv *env) {
4266     int result = AndroidRuntime::registerNativeMethods(env,
4267                 "android/media/MediaCodec", gMethods, NELEM(gMethods));
4268     if (result != JNI_OK) {
4269         return result;
4270     }
4271     result = AndroidRuntime::registerNativeMethods(env,
4272                 "android/media/MediaCodec$LinearBlock",
4273                 gLinearBlockMethods,
4274                 NELEM(gLinearBlockMethods));
4275     return result;
4276 }
4277