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