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