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