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