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