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