blob: 0fc80dd55fa93b2979861e76ea2a2fba60047168 [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
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
Wonsik Kimccb7ac62019-12-27 17:12:40 -080021#include <type_traits>
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include "android_media_MediaCodec.h"
24
shubangd49681e2020-02-17 21:32:30 -080025#include "android_media_MediaCodecLinearBlock.h"
Andreas Huber07ea4262012-04-11 12:21:20 -070026#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070027#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080028#include "android_media_MediaMetricsJNI.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090029#include "android_media_Streams.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "android_runtime/AndroidRuntime.h"
31#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080032#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080033#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080035#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080036
Wonsik Kim637afb22020-02-25 14:27:29 -080037#include <C2AllocatorGralloc.h>
38#include <C2BlockInternal.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080039#include <C2Buffer.h>
Wonsik Kimb8ebdb32020-04-21 17:00:13 -070040#include <C2PlatformSupport.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080041
Chong Zhang2659c2f2017-04-27 13:18:20 -070042#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080043
Wonsik Kim637afb22020-02-25 14:27:29 -080044#include <android_runtime/android_hardware_HardwareBuffer.h>
45
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -080046#include <android-base/stringprintf.h>
47
Wonsik Kimf7069ce2020-05-13 17:15:47 -070048#include <binder/MemoryDealer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080049
Lajos Molnar7ac4f562014-03-24 15:57:51 -070050#include <cutils/compiler.h>
51
Mathias Agopian8335f1c2012-02-25 18:48:35 -080052#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080053
Wonsik Kimccb7ac62019-12-27 17:12:40 -080054#include <hidlmemory/FrameworkUtils.h>
55
Wonsik Kim4273dd02016-09-27 15:23:35 +090056#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080057#include <media/hardware/VideoAPI.h>
Wonsik Kim8798c8c2021-03-18 21:38:57 -070058#include <media/stagefright/CodecBase.h>
Andreas Huber88572f72012-02-21 11:47:18 -080059#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>
Andreas Huberbfc56f42012-04-19 12:47:07 -070064#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080065#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070066#include <media/stagefright/PersistentSurface.h>
Robert Shih631a80d2021-02-14 02:23:55 -080067#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080068#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070069
Wonsik Kim637afb22020-02-25 14:27:29 -080070#include <private/android/AHardwareBufferHelpers.h>
71
Andreas Huberb12a5392012-04-30 14:18:33 -070072#include <system/window.h>
73
Andreas Huber88572f72012-02-21 11:47:18 -080074namespace android {
75
76// Keep these in sync with their equivalents in MediaCodec.java !!!
77enum {
78 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
79 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
80 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
81};
82
Andreas Huberaba67132013-10-22 12:40:01 -070083enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070084 EVENT_CALLBACK = 1,
85 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070086 EVENT_FRAME_RENDERED = 3,
Guillaume Chelfic072caf2021-02-03 16:18:26 +010087 EVENT_FIRST_TUNNEL_FRAME_READY = 4,
Andreas Huberaba67132013-10-22 12:40:01 -070088};
89
Wonsik Kim8798c8c2021-03-18 21:38:57 -070090// From MediaFormat.java
91enum {
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
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700100static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -0700101 jint cryptoErrorNoKey;
102 jint cryptoErrorKeyExpired;
103 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700104 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700105 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -0800106 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800107 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -0800108 jint cryptoErrorFrameTooLarge;
109 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700110} gCryptoErrorCodes;
111
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700112static struct CodecActionCodes {
113 jint codecActionTransient;
114 jint codecActionRecoverable;
115} gCodecActionCodes;
116
Ronghua Wuc53ad692015-05-08 14:40:49 -0700117static struct CodecErrorCodes {
118 jint errorInsufficientResource;
119 jint errorReclaimed;
120} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700121
Chong Zhang8034d602015-04-28 13:38:48 -0700122static struct {
123 jclass clazz;
124 jfieldID mLock;
125 jfieldID mPersistentObject;
126 jmethodID ctor;
127 jmethodID setNativeObjectLocked;
128} gPersistentSurfaceClassInfo;
129
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800130static struct {
131 jint Unencrypted;
132 jint AesCtr;
133 jint AesCbc;
134} gCryptoModes;
135
Chong Zhanga0b72a62018-02-28 18:46:26 -0800136static struct {
137 jclass capsClazz;
138 jmethodID capsCtorId;
139 jclass profileLevelClazz;
140 jfieldID profileField;
141 jfieldID levelField;
142} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800143
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800144static struct {
145 jclass clazz;
146 jobject nativeByteOrder;
147 jmethodID orderId;
148 jmethodID asReadOnlyBufferId;
149 jmethodID positionId;
150 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700151 jmethodID getPositionId;
152 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800153} gByteBufferInfo;
154
155static struct {
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700156 jclass clazz;
157 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800158 jmethodID sizeId;
159 jmethodID getId;
160 jmethodID addId;
161} gArrayListInfo;
162
163static struct {
164 jclass clazz;
165 jmethodID ctorId;
Arun Johnson206270e2023-10-31 20:40:12 +0000166 jmethodID sizeId;
167 jmethodID addId;
168} gArrayDequeInfo;
169
170static struct {
171 jclass clazz;
172 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800173 jmethodID setInternalStateId;
174 jfieldID contextId;
175 jfieldID validId;
176 jfieldID lockId;
177} gLinearBlockInfo;
178
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700179static struct {
180 jclass clazz;
181 jmethodID ctorId;
182 jfieldID nameId;
183 jfieldID typeId;
184} gDescriptorInfo;
185
Pavel Laboviche53421b2022-11-01 03:53:27 +0000186static struct {
187 jclass clazz;
188 jmethodID ctorId;
189 jmethodID setId;
190} gBufferInfo;
191
Andreas Huber88572f72012-02-21 11:47:18 -0800192struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700193 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700194 jmethodID lockAndGetContextID;
195 jmethodID setAndUnlockContextID;
Arun Johnson5a4c7332022-12-17 00:47:06 +0000196 jmethodID cryptoInfoSetID;
197 jmethodID cryptoInfoSetPatternID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700198 jfieldID cryptoInfoNumSubSamplesID;
199 jfieldID cryptoInfoNumBytesOfClearDataID;
200 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
201 jfieldID cryptoInfoKeyID;
202 jfieldID cryptoInfoIVID;
203 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800204 jfieldID cryptoInfoPatternID;
205 jfieldID patternEncryptBlocksID;
206 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800207 jfieldID queueRequestIndexID;
208 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800209 jfieldID outputFrameHardwareBufferID;
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000210 jfieldID outputFramebufferInfosID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800211 jfieldID outputFrameChangedKeysID;
212 jfieldID outputFrameFormatID;
Arun Johnson206270e2023-10-31 20:40:12 +0000213 jfieldID bufferInfoFlags;
214 jfieldID bufferInfoOffset;
215 jfieldID bufferInfoSize;
216 jfieldID bufferInfoPresentationTimeUs;
217
Andreas Huber88572f72012-02-21 11:47:18 -0800218};
219
220static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700221static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800222
Arun Johnson5a4c7332022-12-17 00:47:06 +0000223jint MediaErrorToJavaError(status_t err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800224
Andreas Huber88572f72012-02-21 11:47:18 -0800225////////////////////////////////////////////////////////////////////////////////
226
227JMediaCodec::JMediaCodec(
228 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100229 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800230 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700231 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800232 jclass clazz = env->GetObjectClass(thiz);
233 CHECK(clazz != NULL);
234
235 mClass = (jclass)env->NewGlobalRef(clazz);
236 mObject = env->NewWeakGlobalRef(thiz);
237
238 mLooper = new ALooper;
239 mLooper->setName("MediaCodec_looper");
240
241 mLooper->start(
242 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700243 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700244 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800245
246 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100247 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800248 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
249 mNameAtCreation = "(null)";
250 }
Andreas Huber88572f72012-02-21 11:47:18 -0800251 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100252 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800253 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800254 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700255 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800256}
257
258status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700259 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800260}
261
Andreas Huberaba67132013-10-22 12:40:01 -0700262void JMediaCodec::registerSelf() {
263 mLooper->registerHandler(this);
264}
265
Chong Zhang128b0122014-03-01 18:04:13 -0800266void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700267 std::call_once(mReleaseFlag, [this] {
268 if (mCodec != NULL) {
269 mCodec->release();
270 mInitStatus = NO_INIT;
271 }
Andreas Huber88572f72012-02-21 11:47:18 -0800272
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700273 if (mLooper != NULL) {
274 mLooper->unregisterHandler(id());
275 mLooper->stop();
276 mLooper.clear();
277 }
278 });
Chong Zhang128b0122014-03-01 18:04:13 -0800279}
280
Wonsik Kim89666622020-04-28 10:43:47 -0700281void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700282 std::call_once(mAsyncReleaseFlag, [this] {
283 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700284 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
285 // Hold strong reference to this until async release is complete
286 notify->setObject("this", this);
287 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700288 }
289 mInitStatus = NO_INIT;
290 });
Wonsik Kim89666622020-04-28 10:43:47 -0700291}
292
Chong Zhang128b0122014-03-01 18:04:13 -0800293JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700294 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800295 /* MediaCodec and looper should have been released explicitly already
296 * in setMediaCodec() (see comments in setMediaCodec()).
297 *
298 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
299 * message handler, doing release() there risks deadlock as MediaCodec::
300 * release() post synchronous message to the same looper.
301 *
302 * Print a warning and try to proceed with releasing.
303 */
304 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
305 release();
306 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
307 }
308
Andreas Huber88572f72012-02-21 11:47:18 -0800309 JNIEnv *env = AndroidRuntime::getJNIEnv();
310
311 env->DeleteWeakGlobalRef(mObject);
312 mObject = NULL;
313 env->DeleteGlobalRef(mClass);
314 mClass = NULL;
315}
316
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100317status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
318 if (enable) {
319 if (mOnFirstTunnelFrameReadyNotification == NULL) {
320 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
321 }
322 } else {
323 mOnFirstTunnelFrameReadyNotification.clear();
324 }
325
326 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
327}
328
Lajos Molnard8578572015-06-05 20:17:33 -0700329status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
330 if (enable) {
331 if (mOnFrameRenderedNotification == NULL) {
332 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
333 }
334 } else {
335 mOnFrameRenderedNotification.clear();
336 }
337
338 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
339}
340
Chong Zhang8d5e5562014-07-08 18:49:21 -0700341status_t JMediaCodec::setCallback(jobject cb) {
342 if (cb != NULL) {
343 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800344 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700345 }
346 } else {
347 mCallbackNotification.clear();
348 }
349
350 return mCodec->setCallback(mCallbackNotification);
351}
352
Andreas Huber88572f72012-02-21 11:47:18 -0800353status_t JMediaCodec::configure(
354 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800355 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700356 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800357 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800358 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800359 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800360 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700361 mSurfaceTextureClient =
362 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700363 } else {
364 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800365 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700366
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800367 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
368 AString mime;
369 CHECK(format->findString("mime", &mime));
370 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
371 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700372 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800373 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800374
Chong Zhangd5927ae2017-01-03 11:07:18 -0800375 return mCodec->configure(
376 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800377}
378
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700379status_t JMediaCodec::setSurface(
380 const sp<IGraphicBufferProducer> &bufferProducer) {
381 sp<Surface> client;
382 if (bufferProducer != NULL) {
383 client = new Surface(bufferProducer, true /* controlledByApp */);
384 }
385 status_t err = mCodec->setSurface(client);
386 if (err == OK) {
387 mSurfaceTextureClient = client;
388 }
389 return err;
390}
391
Andy McFadden2621e402013-02-19 07:29:21 -0800392status_t JMediaCodec::createInputSurface(
393 sp<IGraphicBufferProducer>* bufferProducer) {
394 return mCodec->createInputSurface(bufferProducer);
395}
396
Chong Zhang9560ddb2015-05-13 10:25:29 -0700397status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700398 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700399 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700400}
401
Andreas Huber88572f72012-02-21 11:47:18 -0800402status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700403 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800404}
405
406status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700407 mSurfaceTextureClient.clear();
408
Chong Zhang8d5e5562014-07-08 18:49:21 -0700409 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800410}
411
412status_t JMediaCodec::flush() {
413 return mCodec->flush();
414}
415
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700416status_t JMediaCodec::reset() {
417 return mCodec->reset();
418}
419
Andreas Huber88572f72012-02-21 11:47:18 -0800420status_t JMediaCodec::queueInputBuffer(
421 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700422 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
423 AString *errorDetailMsg) {
424 return mCodec->queueInputBuffer(
425 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800426}
427
Arun Johnson206270e2023-10-31 20:40:12 +0000428status_t JMediaCodec::queueInputBuffers(
429 size_t index,
430 size_t offset,
431 size_t size,
432 const sp<RefBase> &infos,
433 AString *errorDetailMsg) {
434
435 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
436 return mCodec->queueInputBuffers(
437 index,
438 offset,
439 size,
440 auInfo,
441 errorDetailMsg);
442}
443
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700444status_t JMediaCodec::queueSecureInputBuffer(
445 size_t index,
446 size_t offset,
447 const CryptoPlugin::SubSample *subSamples,
448 size_t numSubSamples,
449 const uint8_t key[16],
450 const uint8_t iv[16],
451 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800452 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700453 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700454 uint32_t flags,
455 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700456 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800457 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700458 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700459}
460
Arun Johnson4ca49092024-02-01 19:07:15 +0000461status_t JMediaCodec::queueSecureInputBuffers(
462 size_t index,
463 size_t offset,
464 size_t size,
465 const sp<RefBase> &auInfos_,
466 const sp<RefBase> &cryptoInfos_,
467 AString *errorDetailMsg) {
468 sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
469 sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
470 return mCodec->queueSecureInputBuffers(
471 index,
472 offset,
473 size,
474 auInfos,
475 cryptoInfos,
476 errorDetailMsg);
477}
478
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800479status_t JMediaCodec::queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000480 size_t index, const std::shared_ptr<C2Buffer> &buffer,
481 const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
482 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800483 return mCodec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000484 index, buffer, auInfo, tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800485}
486
487status_t JMediaCodec::queueEncryptedLinearBlock(
488 size_t index,
489 const sp<hardware::HidlMemory> &buffer,
490 size_t offset,
Arun Johnson677a8812024-02-06 12:32:54 +0000491 size_t size,
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000492 const sp<RefBase> &infos,
Arun Johnson677a8812024-02-06 12:32:54 +0000493 const sp<RefBase> &cryptoInfos_,
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800494 const sp<AMessage> &tunings,
495 AString *errorDetailMsg) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000496 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Arun Johnson677a8812024-02-06 12:32:54 +0000497 sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800498 return mCodec->queueEncryptedBuffer(
Arun Johnson677a8812024-02-06 12:32:54 +0000499 index, buffer, offset, size, auInfo, cryptoInfos,
500 tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800501}
502
Andreas Huber88572f72012-02-21 11:47:18 -0800503status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700504 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800505}
506
507status_t JMediaCodec::dequeueOutputBuffer(
508 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
509 size_t size, offset;
510 int64_t timeUs;
511 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700512 status_t err = mCodec->dequeueOutputBuffer(
513 index, &offset, &size, &timeUs, &flags, timeoutUs);
514
Andreas Huberaba67132013-10-22 12:40:01 -0700515 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800516 return err;
517 }
518
Pavel Laboviche53421b2022-11-01 03:53:27 +0000519 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800520
521 return OK;
522}
523
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700524status_t JMediaCodec::releaseOutputBuffer(
525 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
526 if (updatePTS) {
527 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
528 }
Andreas Huber88572f72012-02-21 11:47:18 -0800529 return render
530 ? mCodec->renderOutputBufferAndRelease(index)
531 : mCodec->releaseOutputBuffer(index);
532}
533
Andy McFadden2621e402013-02-19 07:29:21 -0800534status_t JMediaCodec::signalEndOfInputStream() {
535 return mCodec->signalEndOfInputStream();
536}
537
Lajos Molnard4023112014-07-11 15:12:59 -0700538status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800539 sp<AMessage> msg;
540 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700541 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
542 if (err != OK) {
543 return err;
544 }
545
546 return ConvertMessageToMap(env, msg, format);
547}
548
549status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
550 sp<AMessage> msg;
551 status_t err;
552 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800553 return err;
554 }
555
556 return ConvertMessageToMap(env, msg, format);
557}
558
559status_t JMediaCodec::getBuffers(
560 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900561 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800562
563 status_t err =
564 input
565 ? mCodec->getInputBuffers(&buffers)
566 : mCodec->getOutputBuffers(&buffers);
567
568 if (err != OK) {
569 return err;
570 }
571
Andreas Huber88572f72012-02-21 11:47:18 -0800572 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800573 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800574 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800575 return NO_MEMORY;
576 }
Andreas Huber88572f72012-02-21 11:47:18 -0800577
578 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900579 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800580
Lajos Molnar7de28d32014-07-25 07:51:02 -0700581 jobject byteBuffer = NULL;
582 err = createByteBufferFromABuffer(
583 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
584 if (err != OK) {
585 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800586 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700587 if (byteBuffer != NULL) {
588 env->SetObjectArrayElement(
589 *bufArray, i, byteBuffer);
590
Lajos Molnard4023112014-07-11 15:12:59 -0700591 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700592 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700593 }
Andreas Huber88572f72012-02-21 11:47:18 -0800594 }
595
Lajos Molnar7de28d32014-07-25 07:51:02 -0700596 return OK;
597}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700598
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800599template <typename T>
600static jobject CreateByteBuffer(
601 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
602 bool readOnly, bool clearBuffer) {
603 jobject byteBuffer =
604 env->NewDirectByteBuffer(
605 const_cast<typename std::remove_const<T>::type *>(base),
606 capacity);
607 if (readOnly && byteBuffer != NULL) {
608 jobject readOnlyBuffer = env->CallObjectMethod(
609 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
610 env->DeleteLocalRef(byteBuffer);
611 byteBuffer = readOnlyBuffer;
612 }
613 if (byteBuffer == NULL) {
614 return nullptr;
615 }
616 jobject me = env->CallObjectMethod(
617 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
618 env->DeleteLocalRef(me);
619 me = env->CallObjectMethod(
620 byteBuffer, gByteBufferInfo.limitId,
621 clearBuffer ? capacity : offset + size);
622 env->DeleteLocalRef(me);
623 me = env->CallObjectMethod(
624 byteBuffer, gByteBufferInfo.positionId,
625 clearBuffer ? 0 : offset);
626 env->DeleteLocalRef(me);
627 me = NULL;
628 return byteBuffer;
629}
630
631
Lajos Molnar7de28d32014-07-25 07:51:02 -0700632// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900633template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700634status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900635 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700636 jobject *buf) const {
637 // if this is an ABuffer that doesn't actually hold any accessible memory,
638 // use a null ByteBuffer
639 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700640
641 if (buffer == NULL) {
642 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
643 return OK;
644 }
645
Lajos Molnar7de28d32014-07-25 07:51:02 -0700646 if (buffer->base() == NULL) {
647 return OK;
648 }
649
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800650 jobject byteBuffer = CreateByteBuffer(
651 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
652 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700653
654 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800655 return OK;
656}
657
Lajos Molnard4023112014-07-11 15:12:59 -0700658status_t JMediaCodec::getBuffer(
659 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900660 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700661
662 status_t err =
663 input
664 ? mCodec->getInputBuffer(index, &buffer)
665 : mCodec->getOutputBuffer(index, &buffer);
666
667 if (err != OK) {
668 return err;
669 }
670
Lajos Molnar7de28d32014-07-25 07:51:02 -0700671 return createByteBufferFromABuffer(
672 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700673}
674
675status_t JMediaCodec::getImage(
676 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900677 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700678
679 status_t err =
680 input
681 ? mCodec->getInputBuffer(index, &buffer)
682 : mCodec->getOutputBuffer(index, &buffer);
683
684 if (err != OK) {
685 return err;
686 }
687
688 // if this is an ABuffer that doesn't actually hold any accessible memory,
689 // use a null ByteBuffer
690 *buf = NULL;
691 if (buffer->base() == NULL) {
692 return OK;
693 }
694
695 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700696 sp<ABuffer> imageData;
697 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700698 return OK;
699 }
700
Lajos Molnar7de28d32014-07-25 07:51:02 -0700701 int64_t timestamp = 0;
702 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
703 timestamp *= 1000; // adjust to ns
704 }
705
706 jobject byteBuffer = NULL;
707 err = createByteBufferFromABuffer(
708 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
709 if (err != OK) {
710 return OK;
711 }
712
713 jobject infoBuffer = NULL;
714 err = createByteBufferFromABuffer(
715 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
716 if (err != OK) {
717 env->DeleteLocalRef(byteBuffer);
718 byteBuffer = NULL;
719 return OK;
720 }
721
722 jobject cropRect = NULL;
723 int32_t left, top, right, bottom;
724 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
725 ScopedLocalRef<jclass> rectClazz(
726 env, env->FindClass("android/graphics/Rect"));
727 CHECK(rectClazz.get() != NULL);
728
729 jmethodID rectConstructID = env->GetMethodID(
730 rectClazz.get(), "<init>", "(IIII)V");
731
732 cropRect = env->NewObject(
733 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
734 }
735
736 ScopedLocalRef<jclass> imageClazz(
737 env, env->FindClass("android/media/MediaCodec$MediaImage"));
738 CHECK(imageClazz.get() != NULL);
739
740 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
741 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
742
743 *buf = env->NewObject(imageClazz.get(), imageConstructID,
744 byteBuffer, infoBuffer,
745 (jboolean)!input /* readOnly */,
746 (jlong)timestamp,
747 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
748
749 // if MediaImage creation fails, return null
750 if (env->ExceptionCheck()) {
751 env->ExceptionDescribe();
752 env->ExceptionClear();
753 *buf = NULL;
754 }
755
756 if (cropRect != NULL) {
757 env->DeleteLocalRef(cropRect);
758 cropRect = NULL;
759 }
760
761 env->DeleteLocalRef(byteBuffer);
762 byteBuffer = NULL;
763
764 env->DeleteLocalRef(infoBuffer);
765 infoBuffer = NULL;
766
Lajos Molnard4023112014-07-11 15:12:59 -0700767 return OK;
768}
769
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000770void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
771 if (!bufInfos) {
772 return;
773 }
774 std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
775 if (infos.empty()) {
776 return;
777 }
778 ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
779 gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
780 jint offset = 0;
781 std::vector<jobject> jObjectInfos;
782 for (int i = 0 ; i < infos.size(); i++) {
783 jobject bufferInfo = env->NewObject(
784 gBufferInfo.clazz, gBufferInfo.ctorId);
785 if (bufferInfo != NULL) {
786 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
787 offset,
788 (jint)(infos)[i].mSize,
789 (infos)[i].mTimestamp,
790 (infos)[i].mFlags);
791 (void)env->CallBooleanMethod(
792 dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
793 offset += (infos)[i].mSize;
794 jObjectInfos.push_back(bufferInfo);
795 }
796 }
797 env->SetObjectField(
798 frame,
799 gFields.outputFramebufferInfosID,
800 dequeObj.get());
801 for (int i = 0; i < jObjectInfos.size(); i++) {
802 env->DeleteLocalRef(jObjectInfos[i]);
803 }
804}
805
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800806status_t JMediaCodec::getOutputFrame(
807 JNIEnv *env, jobject frame, size_t index) const {
808 sp<MediaCodecBuffer> buffer;
809
810 status_t err = mCodec->getOutputBuffer(index, &buffer);
811 if (err != OK) {
812 return err;
813 }
814
815 if (buffer->size() > 0) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000816 sp<RefBase> obj;
817 sp<BufferInfosWrapper> bufInfos;
818 if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
819 bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
820 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800821 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800822 if (c2Buffer) {
823 switch (c2Buffer->data().type()) {
824 case C2BufferData::LINEAR: {
825 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700826 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800827 context->mBuffer = c2Buffer;
828 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
829 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800830 env->CallVoidMethod(
831 linearBlock.get(),
832 gLinearBlockInfo.setInternalStateId,
833 (jlong)context.release(),
834 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800835 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000836 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800837 break;
838 }
839 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800840 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
841 uint32_t width, height, format, stride, igbp_slot, generation;
842 uint64_t usage, igbp_id;
843 _UnwrapNativeCodec2GrallocMetadata(
844 c2Handle, &width, &height, &format, &usage, &stride, &generation,
845 &igbp_id, &igbp_slot);
846 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
847 GraphicBuffer* graphicBuffer = new GraphicBuffer(
848 grallocHandle, GraphicBuffer::CLONE_HANDLE,
849 width, height, format, 1, usage, stride);
850 ScopedLocalRef<jobject> hardwareBuffer{
851 env,
852 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
853 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
854 env->SetObjectField(
855 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800856 break;
857 }
858 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
859 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
860 case C2BufferData::INVALID: [[fallthrough]];
861 default:
862 return INVALID_OPERATION;
863 }
864 } else {
865 if (!mGraphicOutput) {
866 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700867 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800868 context->mLegacyBuffer = buffer;
869 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
870 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800871 env->CallVoidMethod(
872 linearBlock.get(),
873 gLinearBlockInfo.setInternalStateId,
874 (jlong)context.release(),
875 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800876 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000877 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800878 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800879 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800880 }
881 }
882 }
883
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700884 jobject formatMap;
885 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800886 if (err != OK) {
887 return err;
888 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700889 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
890 ScopedLocalRef<jobject> format{env, env->NewObject(
891 mediaFormatClass.get(),
892 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
893 formatMap)};
894 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
895 env->DeleteLocalRef(formatMap);
896 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800897
898 sp<RefBase> obj;
899 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
900 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
901 (decltype(changedKeys.get()))obj.get()};
902 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
903 frame, gFields.outputFrameChangedKeysID)};
904 for (const std::string &key : changedKeys->value) {
905 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
906 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
907 }
908 }
909 return OK;
910}
911
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300912status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
913 AString name;
914
915 status_t err = mCodec->getName(&name);
916
917 if (err != OK) {
918 return err;
919 }
920
921 *nameStr = env->NewStringUTF(name.c_str());
922
923 return OK;
924}
925
Chong Zhanga0b72a62018-02-28 18:46:26 -0800926static jobject getCodecCapabilitiesObject(
927 JNIEnv *env, const char *mime, bool isEncoder,
928 const sp<MediaCodecInfo::Capabilities> &capabilities) {
929 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
930 Vector<uint32_t> colorFormats;
931
932 sp<AMessage> defaultFormat = new AMessage();
933 defaultFormat->setString("mime", mime);
934
935 capabilities->getSupportedColorFormats(&colorFormats);
936 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800937 sp<AMessage> details = capabilities->getDetails();
938
939 jobject defaultFormatObj = NULL;
940 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
941 return NULL;
942 }
943 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
944
945 jobject detailsObj = NULL;
946 if (ConvertMessageToMap(env, details, &detailsObj)) {
947 return NULL;
948 }
949 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
950
951 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
952 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
953
954 for (size_t i = 0; i < profileLevels.size(); ++i) {
955 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
956
957 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
958 gCodecInfo.profileLevelClazz));
959
960 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
961 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
962
963 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
964 }
965
966 ScopedLocalRef<jintArray> colorFormatsArray(
967 env, env->NewIntArray(colorFormats.size()));
968 for (size_t i = 0; i < colorFormats.size(); ++i) {
969 jint val = colorFormats.itemAt(i);
970 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
971 }
972
973 return env->NewObject(
974 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800975 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800976 defaultFormatRef.get(), detailsRef.get());
977}
978
979status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
980 sp<MediaCodecInfo> codecInfo;
981
982 status_t err = mCodec->getCodecInfo(&codecInfo);
983
984 if (err != OK) {
985 return err;
986 }
987
988 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800989 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800990
Lajos Molnard2a7f472018-11-15 12:49:20 -0800991 ScopedLocalRef<jstring> canonicalNameObject(env,
992 env->NewStringUTF(codecInfo->getCodecName()));
993
994 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800995 bool isEncoder = codecInfo->isEncoder();
996
Lajos Molnard2a7f472018-11-15 12:49:20 -0800997 Vector<AString> mediaTypes;
998 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800999
1000 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -08001001 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -08001002
Lajos Molnard2a7f472018-11-15 12:49:20 -08001003 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -08001004 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -08001005 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -08001006
1007 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -08001008 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -08001009
1010 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
1011 }
1012
1013 ScopedLocalRef<jclass> codecInfoClazz(env,
1014 env->FindClass("android/media/MediaCodecInfo"));
1015 CHECK(codecInfoClazz.get() != NULL);
1016
1017 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -08001018 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -08001019
1020 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -08001021 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -08001022
1023 return OK;
1024}
1025
Ray Essick81fbc5b2019-12-07 06:24:59 -08001026status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
1027 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -07001028 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -07001029 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -08001030 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -08001031 return status;
1032}
1033
Andreas Huber226065b2013-08-12 10:14:11 -07001034status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
1035 return mCodec->setParameters(msg);
1036}
1037
Andreas Huberb12a5392012-04-30 14:18:33 -07001038void JMediaCodec::setVideoScalingMode(int mode) {
1039 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -07001040 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -07001041 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -07001042 // also signal via param for components that queue to IGBP
1043 sp<AMessage> msg = new AMessage;
1044 msg->setInt32("android._video-scaling", mode);
1045 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -07001046 }
1047}
1048
ybai5e053202018-11-01 13:02:15 +08001049void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
1050 sp<AMessage> msg = new AMessage;
1051 msg->setInt32("audio-presentation-presentation-id", presentationId);
1052 msg->setInt32("audio-presentation-program-id", programId);
1053 (void)mCodec->setParameters(msg);
1054}
1055
Wonsik Kim8798c8c2021-03-18 21:38:57 -07001056status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
1057 std::vector<std::string> names;
1058 status_t status = mCodec->querySupportedVendorParameters(&names);
1059 if (status != OK) {
1060 return status;
1061 }
1062 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
1063 for (const std::string &name : names) {
1064 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
1065 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
1066 }
1067 return OK;
1068}
1069
1070status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
1071 const char *tmp = env->GetStringUTFChars(name, nullptr);
1072 CodecParameterDescriptor desc;
1073 status_t status = mCodec->describeParameter(tmp, &desc);
1074 env->ReleaseStringUTFChars(name, tmp);
1075 if (status != OK) {
1076 return status;
1077 }
1078 jint type = TYPE_NULL;
1079 switch (desc.type) {
1080 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
1081 case AMessage::kTypeSize:
1082 case AMessage::kTypeInt64: type = TYPE_LONG; break;
1083 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
1084 case AMessage::kTypeString: type = TYPE_STRING; break;
1085 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
1086 default: type = TYPE_NULL; break;
1087 }
1088 if (type == TYPE_NULL) {
1089 return BAD_VALUE;
1090 }
1091 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1092 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1093 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1094 return OK;
1095}
1096
1097static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1098 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1099 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1100 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1101 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1102 jobject it = env->CallObjectMethod(
1103 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1104 while (env->CallBooleanMethod(it, hasNextID)) {
1105 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1106 const char *tmp = env->GetStringUTFChars(name, nullptr);
1107 vec->push_back(tmp);
1108 env->ReleaseStringUTFChars(name, tmp);
1109 }
1110}
1111
1112status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1113 std::vector<std::string> names;
1114 BuildVectorFromList(env, namesObj, &names);
1115 return mCodec->subscribeToVendorParameters(names);
1116}
1117
1118status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1119 std::vector<std::string> names;
1120 BuildVectorFromList(env, namesObj, &names);
1121 return mCodec->unsubscribeFromVendorParameters(names);
1122}
1123
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001124static jthrowable createCodecException(
1125 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1126 ScopedLocalRef<jclass> clazz(
1127 env, env->FindClass("android/media/MediaCodec$CodecException"));
1128 CHECK(clazz.get() != NULL);
1129
Ronghua Wuc53ad692015-05-08 14:40:49 -07001130 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001131 CHECK(ctor != NULL);
1132
1133 ScopedLocalRef<jstring> msgObj(
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00001134 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001135
1136 // translate action code to Java equivalent
1137 switch (actionCode) {
1138 case ACTION_CODE_TRANSIENT:
1139 actionCode = gCodecActionCodes.codecActionTransient;
1140 break;
1141 case ACTION_CODE_RECOVERABLE:
1142 actionCode = gCodecActionCodes.codecActionRecoverable;
1143 break;
1144 default:
1145 actionCode = 0; // everything else is fatal
1146 break;
1147 }
1148
Ronghua Wuc53ad692015-05-08 14:40:49 -07001149 /* translate OS errors to Java API CodecException errorCodes */
1150 switch (err) {
1151 case NO_MEMORY:
1152 err = gCodecErrorCodes.errorInsufficientResource;
1153 break;
1154 case DEAD_OBJECT:
1155 err = gCodecErrorCodes.errorReclaimed;
1156 break;
1157 default: /* Other error codes go out as is. */
1158 break;
1159 }
1160
1161 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001162}
1163
Arun Johnson5a4c7332022-12-17 00:47:06 +00001164static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1165 const sp<AMessage> & msg) {
1166 if(msg == nullptr || obj == nullptr) {
1167 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1168 return;
1169 }
1170 size_t numSubSamples = 0;
1171 sp<ABuffer> subSamplesBuffer;
1172 sp<ABuffer> keyBuffer;
1173 sp<ABuffer> ivBuffer;
1174 CryptoPlugin::Mode mode;
1175 CryptoPlugin::Pattern pattern;
1176 CHECK(msg->findInt32("mode", (int*)&mode));
1177 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1178 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1179 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1180 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1181 CHECK(msg->findBuffer("iv", &ivBuffer));
1182 CHECK(msg->findBuffer("key", &keyBuffer));
1183
1184 // subsamples
1185 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1186 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1187 jboolean isCopy;
1188 jint *dstEncryptedSamples =
1189 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1190 jint * dstClearSamples =
1191 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1192
1193 CryptoPlugin::SubSample * samplesArray =
1194 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1195
1196 for(int i = 0 ; i < numSubSamples ; i++) {
1197 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1198 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1199 }
1200 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1201 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1202 // key and iv
1203 jbyteArray keyArray = NULL;
1204 jbyteArray ivArray = NULL;
1205 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1206 keyArray = env->NewByteArray(keyBuffer->size());
1207 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1208 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1209 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1210 }
1211 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1212 ivArray = env->NewByteArray(ivBuffer->size());
1213 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1214 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1215 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1216 }
1217 // set samples, key and iv
1218 env->CallVoidMethod(
1219 obj,
1220 gFields.cryptoInfoSetID,
1221 (jint)numSubSamples,
1222 samplesOfClearDataArr.get(),
1223 samplesOfEncryptedDataArr.get(),
1224 keyArray,
1225 ivArray,
1226 mode);
1227 if (keyArray != NULL) {
1228 env->DeleteLocalRef(keyArray);
1229 }
1230 if (ivArray != NULL) {
1231 env->DeleteLocalRef(ivArray);
1232 }
1233 // set pattern
1234 env->CallVoidMethod(
1235 obj,
1236 gFields.cryptoInfoSetPatternID,
1237 pattern.mEncryptBlocks,
1238 pattern.mSkipBlocks);
1239}
1240
1241static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1242 switch(err) {
1243 case ERROR_DRM_NO_LICENSE:
1244 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1245 defaultMsg = "Crypto key not available";
1246 break;
1247 case ERROR_DRM_LICENSE_EXPIRED:
1248 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1249 defaultMsg = "License expired";
1250 break;
1251 case ERROR_DRM_RESOURCE_BUSY:
1252 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1253 defaultMsg = "Resource busy or unavailable";
1254 break;
1255 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1256 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1257 defaultMsg = "Required output protections are not active";
1258 break;
1259 case ERROR_DRM_SESSION_NOT_OPENED:
1260 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1261 defaultMsg = "Attempted to use a closed session";
1262 break;
1263 case ERROR_DRM_INSUFFICIENT_SECURITY:
1264 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1265 defaultMsg = "Required security level is not met";
1266 break;
1267 case ERROR_DRM_CANNOT_HANDLE:
1268 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1269 defaultMsg = "Operation not supported in this configuration";
1270 break;
1271 case ERROR_DRM_FRAME_TOO_LARGE:
1272 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1273 defaultMsg = "Decrytped frame exceeds size of output buffer";
1274 break;
1275 case ERROR_DRM_SESSION_LOST_STATE:
1276 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1277 defaultMsg = "Session state was lost, open a new session and retry";
1278 break;
1279 default: // Other negative DRM error codes go out best-effort.
1280 jerr = MediaErrorToJavaError(err);
1281 defaultMsg = StrCryptoError(err);
1282 break;
1283 }
1284}
1285static jthrowable createCryptoException(JNIEnv *env, status_t err,
1286 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1287 const sp<AMessage> & cryptoInfo = NULL) {
1288 jthrowable exception = nullptr;
1289 jmethodID constructID = nullptr;
1290 ScopedLocalRef<jobject> cryptoInfoObject(env);
1291 std::string defaultMsg = "Unknown Error";
1292 jint jerr = 0;
1293 // Get a class ref for CryptoException
1294 ScopedLocalRef<jclass> clazz(
1295 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1296 CHECK(clazz.get() != NULL);
1297
1298 // Get constructor ref for CryptoException
1299 constructID = env->GetMethodID(clazz.get(), "<init>",
1300 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1301 CHECK(constructID != NULL);
1302
1303 // create detailed message for exception
1304 CryptoErrorToJavaError(err, jerr, defaultMsg);
1305 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1306 DrmStatus dStatus(err, originalMsg.c_str());
1307 std::string detailedMsg(
1308 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1309 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1310
1311 if (cryptoInfo != nullptr) {
1312 // Class ref for CryptoInfo
1313 ScopedLocalRef<jclass> clazzCryptoInfo(
1314 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1315 CHECK(clazzCryptoInfo.get() != NULL);
1316
1317 // Constructor reference for CryptoInfo
1318 jmethodID constructCryptoInfo =
1319 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1320 CHECK(constructCryptoInfo != NULL);
1321
1322 // Create CryptoInfo jobject
1323 cryptoInfoObject.reset(
1324 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1325 CHECK(cryptoInfoObject.get() != NULL);
1326
1327 // Translate AMesage to CryptoInfo
1328 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1329 }
1330
1331 exception = (jthrowable)env->NewObject(
1332 clazz.get(), constructID, msgObj, jerr,
1333 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1334 cryptoInfoObject.get());
1335
1336 return exception;
1337}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001338void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1339 int32_t arg1, arg2 = 0;
1340 jobject obj = NULL;
Arun Johnson206270e2023-10-31 20:40:12 +00001341 std::vector<jobject> jObjectInfos;
Chong Zhang8d5e5562014-07-08 18:49:21 -07001342 CHECK(msg->findInt32("callbackID", &arg1));
1343 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001344
Chong Zhang8d5e5562014-07-08 18:49:21 -07001345 switch (arg1) {
1346 case MediaCodec::CB_INPUT_AVAILABLE:
1347 {
1348 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001349 break;
1350 }
1351
Chong Zhang8d5e5562014-07-08 18:49:21 -07001352 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001353 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001354 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001355
Chong Zhang8d5e5562014-07-08 18:49:21 -07001356 size_t size, offset;
1357 int64_t timeUs;
1358 uint32_t flags;
1359 CHECK(msg->findSize("size", &size));
1360 CHECK(msg->findSize("offset", &offset));
1361 CHECK(msg->findInt64("timeUs", &timeUs));
1362 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1363
Pavel Laboviche53421b2022-11-01 03:53:27 +00001364 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001365 if (obj == NULL) {
1366 if (env->ExceptionCheck()) {
1367 ALOGE("Could not create MediaCodec.BufferInfo.");
1368 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001369 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001370 jniThrowException(env, "java/lang/IllegalStateException",
1371 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001372 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001373 }
1374
Pavel Laboviche53421b2022-11-01 03:53:27 +00001375 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001376 break;
1377 }
1378
Arun Johnson206270e2023-10-31 20:40:12 +00001379 case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
1380 {
1381 sp<RefBase> spobj = nullptr;
1382 CHECK(msg->findInt32("index", &arg2));
1383 CHECK(msg->findObject("accessUnitInfo", &spobj));
1384 if (spobj != nullptr) {
1385 sp<BufferInfosWrapper> bufferInfoParamsWrapper {
1386 (BufferInfosWrapper *)spobj.get()};
1387 std::vector<AccessUnitInfo> &bufferInfoParams =
1388 bufferInfoParamsWrapper.get()->value;
1389 obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
1390 jint offset = 0;
1391 for (int i = 0 ; i < bufferInfoParams.size(); i++) {
1392 jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1393 if (bufferInfo != NULL) {
1394 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
1395 offset,
1396 (jint)(bufferInfoParams)[i].mSize,
1397 (bufferInfoParams)[i].mTimestamp,
1398 (bufferInfoParams)[i].mFlags);
1399 (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
1400 offset += (bufferInfoParams)[i].mSize;
1401 jObjectInfos.push_back(bufferInfo);
1402 }
1403 }
1404 }
1405 break;
1406 }
1407
Arun Johnson5a4c7332022-12-17 00:47:06 +00001408 case MediaCodec::CB_CRYPTO_ERROR:
1409 {
1410 int32_t err, actionCode;
1411 AString errorDetail;
1412 CHECK(msg->findInt32("err", &err));
1413 CHECK(msg->findInt32("actionCode",&actionCode));
1414 CHECK(msg->findString("errorDetail", &errorDetail));
1415 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1416 break;
1417 }
1418
Chong Zhang8d5e5562014-07-08 18:49:21 -07001419 case MediaCodec::CB_ERROR:
1420 {
Chong Zhang94686d12014-07-11 15:53:58 -07001421 int32_t err, actionCode;
1422 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001423 CHECK(msg->findInt32("actionCode", &actionCode));
1424
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001425 // note that DRM errors could conceivably alias into a CodecException
1426 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001427
1428 if (obj == NULL) {
1429 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001430 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001431 env->ExceptionClear();
1432 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001433 jniThrowException(env, "java/lang/IllegalStateException",
1434 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001435 return;
1436 }
Andreas Huberaba67132013-10-22 12:40:01 -07001437
1438 break;
1439 }
1440
Chong Zhang8d5e5562014-07-08 18:49:21 -07001441 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001442 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001443 sp<AMessage> format;
1444 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001445
Chong Zhang8d5e5562014-07-08 18:49:21 -07001446 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001447 jniThrowException(env, "java/lang/IllegalStateException",
1448 "Fatal error: failed to convert format "
1449 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001450 return;
1451 }
Andreas Huberaba67132013-10-22 12:40:01 -07001452
Andreas Huberaba67132013-10-22 12:40:01 -07001453 break;
1454 }
1455
1456 default:
1457 TRESPASS();
1458 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001459 env->CallVoidMethod(
1460 mObject,
1461 gFields.postEventFromNativeID,
1462 EVENT_CALLBACK,
1463 arg1,
1464 arg2,
1465 obj);
1466
Arun Johnson206270e2023-10-31 20:40:12 +00001467 for (int i = 0; i < jObjectInfos.size(); i++) {
1468 env->DeleteLocalRef(jObjectInfos[i]);
1469 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001470 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001471}
1472
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001473void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1474 int32_t arg1 = 0, arg2 = 0;
1475 jobject obj = NULL;
1476 JNIEnv *env = AndroidRuntime::getJNIEnv();
1477
1478 sp<AMessage> data;
1479 CHECK(msg->findMessage("data", &data));
1480
1481 status_t err = ConvertMessageToMap(env, data, &obj);
1482 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001483 jniThrowException(env, "java/lang/IllegalStateException",
1484 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001485 return;
1486 }
1487
1488 env->CallVoidMethod(
1489 mObject, gFields.postEventFromNativeID,
1490 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1491
1492 env->DeleteLocalRef(obj);
1493}
1494
Lajos Molnard8578572015-06-05 20:17:33 -07001495void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1496 int32_t arg1 = 0, arg2 = 0;
1497 jobject obj = NULL;
1498 JNIEnv *env = AndroidRuntime::getJNIEnv();
1499
1500 sp<AMessage> data;
1501 CHECK(msg->findMessage("data", &data));
1502
1503 status_t err = ConvertMessageToMap(env, data, &obj);
1504 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001505 jniThrowException(env, "java/lang/IllegalStateException",
1506 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001507 return;
1508 }
1509
1510 env->CallVoidMethod(
1511 mObject, gFields.postEventFromNativeID,
1512 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1513
1514 env->DeleteLocalRef(obj);
1515}
1516
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001517std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1518 if (mCodec == nullptr) {
1519 return msg ?: "";
1520 }
1521 std::string prefix = "";
1522 if (msg && msg[0] != '\0') {
1523 prefix.append(msg);
1524 prefix.append("\n");
1525 }
1526 return prefix + mCodec->getErrorLog().extract();
1527}
1528
Chong Zhang8d5e5562014-07-08 18:49:21 -07001529void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1530 switch (msg->what()) {
1531 case kWhatCallbackNotify:
1532 {
1533 handleCallback(msg);
1534 break;
1535 }
Lajos Molnard8578572015-06-05 20:17:33 -07001536 case kWhatFrameRendered:
1537 {
1538 handleFrameRenderedNotification(msg);
1539 break;
1540 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001541 case kWhatAsyncReleaseComplete:
1542 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001543 if (mLooper != NULL) {
1544 mLooper->unregisterHandler(id());
1545 mLooper->stop();
1546 mLooper.clear();
1547 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001548 break;
1549 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001550 case kWhatFirstTunnelFrameReady:
1551 {
1552 handleFirstTunnelFrameReadyNotification(msg);
1553 break;
1554 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001555 default:
1556 TRESPASS();
1557 }
Andreas Huberaba67132013-10-22 12:40:01 -07001558}
1559
Robert Shih631a80d2021-02-14 02:23:55 -08001560
Andreas Huber88572f72012-02-21 11:47:18 -08001561} // namespace android
1562
1563////////////////////////////////////////////////////////////////////////////////
1564
1565using namespace android;
1566
1567static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001568 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001569 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001570 if (codec != NULL) {
1571 codec->incStrong(thiz);
1572 }
1573 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001574 /* release MediaCodec and stop the looper now before decStrong.
1575 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1576 * its message handler, doing release() from there will deadlock
1577 * (as MediaCodec::release() post synchronous message to the same looper)
1578 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001579 if (release) {
1580 old->release();
1581 }
Andreas Huber88572f72012-02-21 11:47:18 -08001582 old->decStrong(thiz);
1583 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001584 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001585
1586 return old;
1587}
1588
1589static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001590 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1591 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1592 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001593}
1594
1595static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001596 // Clear Java native reference.
1597 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001598 if (codec != NULL) {
1599 codec->releaseAsync();
1600 }
Andreas Huber88572f72012-02-21 11:47:18 -08001601}
1602
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001603static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1604 jthrowable exception = createCodecException(env, err, actionCode, msg);
1605 env->Throw(exception);
1606}
1607
Robert Shih631a80d2021-02-14 02:23:55 -08001608static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1609 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001610 jthrowable exception = createCryptoException(
1611 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001612 env->Throw(exception);
1613}
1614
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001615static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1616 if (codec == NULL) {
1617 return msg ?: "codec is released already";
1618 }
1619 return codec->getExceptionMessage(msg);
1620}
1621
Andreas Huberbfc56f42012-04-19 12:47:07 -07001622static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001623 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001624 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1625 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001626 switch (err) {
1627 case OK:
1628 return 0;
1629
1630 case -EAGAIN:
1631 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1632
1633 case INFO_FORMAT_CHANGED:
1634 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1635
1636 case INFO_OUTPUT_BUFFERS_CHANGED:
1637 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1638
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001639 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001640 jniThrowException(
1641 env, "java/lang/IllegalStateException",
1642 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001643 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001644
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001645 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001646 jniThrowException(
1647 env, "java/lang/IllegalArgumentException",
1648 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001649 return 0;
1650
Andreas Huber88572f72012-02-21 11:47:18 -08001651 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001652 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001653 throwCryptoException(
1654 env, err,
1655 GetExceptionMessage(codec, msg).c_str(),
1656 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001657 return 0;
1658 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001659 throwCodecException(
1660 env, err, actionCode,
1661 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001662 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001663 }
Andreas Huber88572f72012-02-21 11:47:18 -08001664}
1665
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001666static jint throwExceptionAsNecessary(
1667 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1668 int32_t actionCode = ACTION_CODE_FATAL) {
1669 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1670}
1671
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001672static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1673 JNIEnv *env,
1674 jobject thiz,
1675 jboolean enabled) {
1676 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1677
1678 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001679 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001680 return;
1681 }
1682
1683 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1684
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001685 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001686}
1687
Lajos Molnard8578572015-06-05 20:17:33 -07001688static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1689 JNIEnv *env,
1690 jobject thiz,
1691 jboolean enabled) {
1692 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1693
Wonsik Kim24e53802020-05-08 20:04:26 -07001694 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001695 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001696 return;
1697 }
1698
1699 status_t err = codec->enableOnFrameRenderedListener(enabled);
1700
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001701 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001702}
1703
Chong Zhang8d5e5562014-07-08 18:49:21 -07001704static void android_media_MediaCodec_native_setCallback(
1705 JNIEnv *env,
1706 jobject thiz,
1707 jobject cb) {
1708 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1709
Wonsik Kim24e53802020-05-08 20:04:26 -07001710 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001711 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001712 return;
1713 }
1714
1715 status_t err = codec->setCallback(cb);
1716
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001717 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001718}
1719
Andreas Huber88572f72012-02-21 11:47:18 -08001720static void android_media_MediaCodec_native_configure(
1721 JNIEnv *env,
1722 jobject thiz,
1723 jobjectArray keys, jobjectArray values,
1724 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001725 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001726 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001727 jint flags) {
1728 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1729
Wonsik Kim24e53802020-05-08 20:04:26 -07001730 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001731 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001732 return;
1733 }
1734
1735 sp<AMessage> format;
1736 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1737
1738 if (err != OK) {
1739 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1740 return;
1741 }
1742
Andy McFaddend47f7d82012-12-18 09:48:38 -08001743 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001744 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001745 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001746 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001747 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001748 } else {
1749 jniThrowException(
1750 env,
1751 "java/lang/IllegalArgumentException",
1752 "The surface has been released");
1753 return;
1754 }
1755 }
1756
Andreas Huber8240d922012-04-04 14:06:32 -07001757 sp<ICrypto> crypto;
1758 if (jcrypto != NULL) {
1759 crypto = JCrypto::GetCrypto(env, jcrypto);
1760 }
1761
Chong Zhangd5927ae2017-01-03 11:07:18 -08001762 sp<IDescrambler> descrambler;
1763 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001764 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001765 }
1766
1767 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001768
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001769 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001770}
1771
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001772static void android_media_MediaCodec_native_setSurface(
1773 JNIEnv *env,
1774 jobject thiz,
1775 jobject jsurface) {
1776 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1777
Wonsik Kim24e53802020-05-08 20:04:26 -07001778 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001779 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001780 return;
1781 }
1782
1783 sp<IGraphicBufferProducer> bufferProducer;
1784 if (jsurface != NULL) {
1785 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1786 if (surface != NULL) {
1787 bufferProducer = surface->getIGraphicBufferProducer();
1788 } else {
1789 jniThrowException(
1790 env,
1791 "java/lang/IllegalArgumentException",
1792 "The surface has been released");
1793 return;
1794 }
1795 }
1796
1797 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001798 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001799}
1800
Chong Zhang8034d602015-04-28 13:38:48 -07001801sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1802 JNIEnv* env, jobject object) {
1803 sp<PersistentSurface> persistentSurface;
1804
1805 jobject lock = env->GetObjectField(
1806 object, gPersistentSurfaceClassInfo.mLock);
1807 if (env->MonitorEnter(lock) == JNI_OK) {
1808 persistentSurface = reinterpret_cast<PersistentSurface *>(
1809 env->GetLongField(object,
1810 gPersistentSurfaceClassInfo.mPersistentObject));
1811 env->MonitorExit(lock);
1812 }
1813 env->DeleteLocalRef(lock);
1814
1815 return persistentSurface;
1816}
1817
1818static jobject android_media_MediaCodec_createPersistentInputSurface(
1819 JNIEnv* env, jclass /* clazz */) {
1820 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1821 sp<PersistentSurface> persistentSurface =
1822 MediaCodec::CreatePersistentInputSurface();
1823
1824 if (persistentSurface == NULL) {
1825 return NULL;
1826 }
1827
1828 sp<Surface> surface = new Surface(
1829 persistentSurface->getBufferProducer(), true);
1830 if (surface == NULL) {
1831 return NULL;
1832 }
1833
1834 jobject object = env->NewObject(
1835 gPersistentSurfaceClassInfo.clazz,
1836 gPersistentSurfaceClassInfo.ctor);
1837
1838 if (object == NULL) {
1839 if (env->ExceptionCheck()) {
1840 ALOGE("Could not create PersistentSurface.");
1841 env->ExceptionClear();
1842 }
1843 return NULL;
1844 }
1845
1846 jobject lock = env->GetObjectField(
1847 object, gPersistentSurfaceClassInfo.mLock);
1848 if (env->MonitorEnter(lock) == JNI_OK) {
1849 env->CallVoidMethod(
1850 object,
1851 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1852 (jlong)surface.get());
1853 env->SetLongField(
1854 object,
1855 gPersistentSurfaceClassInfo.mPersistentObject,
1856 (jlong)persistentSurface.get());
1857 env->MonitorExit(lock);
1858 } else {
1859 env->DeleteLocalRef(object);
1860 object = NULL;
1861 }
1862 env->DeleteLocalRef(lock);
1863
1864 if (object != NULL) {
1865 surface->incStrong(&sRefBaseOwner);
1866 persistentSurface->incStrong(&sRefBaseOwner);
1867 }
1868
1869 return object;
1870}
1871
1872static void android_media_MediaCodec_releasePersistentInputSurface(
1873 JNIEnv* env, jclass /* clazz */, jobject object) {
1874 sp<PersistentSurface> persistentSurface;
1875
1876 jobject lock = env->GetObjectField(
1877 object, gPersistentSurfaceClassInfo.mLock);
1878 if (env->MonitorEnter(lock) == JNI_OK) {
1879 persistentSurface = reinterpret_cast<PersistentSurface *>(
1880 env->GetLongField(
1881 object, gPersistentSurfaceClassInfo.mPersistentObject));
1882 env->SetLongField(
1883 object,
1884 gPersistentSurfaceClassInfo.mPersistentObject,
1885 (jlong)0);
1886 env->MonitorExit(lock);
1887 }
1888 env->DeleteLocalRef(lock);
1889
1890 if (persistentSurface != NULL) {
1891 persistentSurface->decStrong(&sRefBaseOwner);
1892 }
1893 // no need to release surface as it will be released by Surface's jni
1894}
1895
Chong Zhang9560ddb2015-05-13 10:25:29 -07001896static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001897 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001898 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001899
1900 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001901 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001902 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001903 return;
1904 }
1905
1906 sp<PersistentSurface> persistentSurface =
1907 android_media_MediaCodec_getPersistentInputSurface(env, object);
1908
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001909 if (persistentSurface == NULL) {
1910 throwExceptionAsNecessary(
1911 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1912 return;
1913 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001914 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001915 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001916 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001917 }
1918}
1919
Andy McFadden2621e402013-02-19 07:29:21 -08001920static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1921 jobject thiz) {
1922 ALOGV("android_media_MediaCodec_createInputSurface");
1923
1924 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001925 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001926 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001927 return NULL;
1928 }
1929
1930 // Tell the MediaCodec that we want to use a Surface as input.
1931 sp<IGraphicBufferProducer> bufferProducer;
1932 status_t err = codec->createInputSurface(&bufferProducer);
1933 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001934 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001935 return NULL;
1936 }
1937
1938 // Wrap the IGBP in a Java-language Surface.
1939 return android_view_Surface_createFromIGraphicBufferProducer(env,
1940 bufferProducer);
1941}
1942
Andreas Huber88572f72012-02-21 11:47:18 -08001943static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1944 ALOGV("android_media_MediaCodec_start");
1945
1946 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1947
Wonsik Kim24e53802020-05-08 20:04:26 -07001948 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001949 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001950 return;
1951 }
1952
1953 status_t err = codec->start();
1954
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001955 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001956}
1957
1958static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1959 ALOGV("android_media_MediaCodec_stop");
1960
1961 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1962
Wonsik Kim24e53802020-05-08 20:04:26 -07001963 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001964 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001965 return;
1966 }
1967
1968 status_t err = codec->stop();
1969
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001970 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001971}
1972
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001973static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1974 ALOGV("android_media_MediaCodec_reset");
1975
1976 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1977
Wonsik Kim24e53802020-05-08 20:04:26 -07001978 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001979 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001980 return;
1981 }
1982
1983 status_t err = codec->reset();
1984 if (err != OK) {
1985 // treat all errors as fatal for now, though resource not available
1986 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001987 // we also should avoid sending INVALID_OPERATION here due to
1988 // the transitory nature of reset(), it should not inadvertently
1989 // trigger an IllegalStateException.
1990 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001991 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001992 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001993}
1994
Andreas Huber88572f72012-02-21 11:47:18 -08001995static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1996 ALOGV("android_media_MediaCodec_flush");
1997
1998 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1999
Wonsik Kim24e53802020-05-08 20:04:26 -07002000 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002001 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002002 return;
2003 }
2004
2005 status_t err = codec->flush();
2006
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002007 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002008}
2009
2010static void android_media_MediaCodec_queueInputBuffer(
2011 JNIEnv *env,
2012 jobject thiz,
2013 jint index,
2014 jint offset,
2015 jint size,
2016 jlong timestampUs,
2017 jint flags) {
2018 ALOGV("android_media_MediaCodec_queueInputBuffer");
2019
2020 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2021
Wonsik Kim24e53802020-05-08 20:04:26 -07002022 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002023 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002024 return;
2025 }
2026
Andreas Huberbfc56f42012-04-19 12:47:07 -07002027 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08002028
Andreas Huberbfc56f42012-04-19 12:47:07 -07002029 status_t err = codec->queueInputBuffer(
2030 index, offset, size, timestampUs, flags, &errorDetailMsg);
2031
2032 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002033 env, err, ACTION_CODE_FATAL,
2034 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08002035}
2036
Arun Johnson206270e2023-10-31 20:40:12 +00002037static status_t extractInfosFromObject(
2038 JNIEnv * const env,
2039 jint * const initialOffset,
2040 jint * const totalSize,
2041 std::vector<AccessUnitInfo> * const infos,
2042 const jobjectArray &objArray,
2043 AString * const errorDetailMsg) {
2044 if (totalSize == nullptr
2045 || initialOffset == nullptr
2046 || infos == nullptr) {
2047 if (errorDetailMsg) {
2048 *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
2049 }
2050 return BAD_VALUE;
2051 }
2052 const jsize numEntries = env->GetArrayLength(objArray);
2053 if (numEntries <= 0) {
2054 if (errorDetailMsg) {
2055 *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
2056 }
2057 return BAD_VALUE;
2058 }
2059 *initialOffset = 0;
2060 *totalSize = 0;
2061 for (jsize i = 0; i < numEntries; i++) {
2062 jobject param = env->GetObjectArrayElement(objArray, i);
2063 if (param == NULL) {
2064 if (errorDetailMsg) {
2065 *errorDetailMsg = "Error: Queuing a null BufferInfo";
2066 }
2067 return BAD_VALUE;
2068 }
2069 size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
2070 size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
2071 uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
2072 if (flags == 0 && size == 0) {
2073 if (errorDetailMsg) {
2074 *errorDetailMsg = "Error: Queuing an empty BufferInfo";
2075 }
2076 return BAD_VALUE;
2077 }
2078 if (i == 0) {
2079 *initialOffset = offset;
2080 }
2081 if (CC_UNLIKELY((offset > UINT32_MAX)
2082 || ((long)(offset + size) > UINT32_MAX)
2083 || ((offset - *initialOffset) != *totalSize))) {
2084 if (errorDetailMsg) {
2085 *errorDetailMsg = "Error: offset/size in BufferInfo";
2086 }
2087 return BAD_VALUE;
2088 }
2089 infos->emplace_back(
2090 flags,
2091 size,
2092 env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
2093 *totalSize += size;
2094 }
2095 return OK;
2096}
2097
2098static void android_media_MediaCodec_queueInputBuffers(
2099 JNIEnv *env,
2100 jobject thiz,
2101 jint index,
2102 jobjectArray objArray) {
2103 ALOGV("android_media_MediaCodec_queueInputBuffers");
2104 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2105 if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
2106 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2107 return;
2108 }
2109 sp<BufferInfosWrapper> infoObj =
2110 new BufferInfosWrapper{decltype(infoObj->value)()};
2111 AString errorDetailMsg;
2112 jint initialOffset = 0;
2113 jint totalSize = 0;
2114 status_t err = extractInfosFromObject(
2115 env,
2116 &initialOffset,
2117 &totalSize,
2118 &infoObj->value,
2119 objArray,
2120 &errorDetailMsg);
2121 if (err == OK) {
2122 err = codec->queueInputBuffers(
2123 index,
2124 initialOffset,
2125 totalSize,
2126 infoObj,
2127 &errorDetailMsg);
2128 }
2129 throwExceptionAsNecessary(
2130 env, err, ACTION_CODE_FATAL,
2131 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2132}
2133
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002134struct NativeCryptoInfo {
2135 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
2136 : mEnv{env},
2137 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
2138 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
2139 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2140
2141 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
2142 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
2143
2144 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
2145 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
2146
2147 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2148 if (jmode == gCryptoModes.Unencrypted) {
2149 mMode = CryptoPlugin::kMode_Unencrypted;
2150 } else if (jmode == gCryptoModes.AesCtr) {
2151 mMode = CryptoPlugin::kMode_AES_CTR;
2152 } else if (jmode == gCryptoModes.AesCbc) {
2153 mMode = CryptoPlugin::kMode_AES_CBC;
2154 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002155 throwExceptionAsNecessary(
2156 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2157 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002158 return;
2159 }
2160
2161 ScopedLocalRef<jobject> patternObj{
2162 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
2163
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002164 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002165 mPattern.mEncryptBlocks = 0;
2166 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002167 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002168 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002169 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002170 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002171 patternObj.get(), gFields.patternSkipBlocksID);
2172 }
2173
2174 mErr = OK;
2175 if (mNumSubSamples <= 0) {
2176 mErr = -EINVAL;
2177 } else if (numBytesOfClearDataObj == nullptr
2178 && numBytesOfEncryptedDataObj == nullptr) {
2179 mErr = -EINVAL;
2180 } else if (numBytesOfEncryptedDataObj != nullptr
2181 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
2182 mErr = -ERANGE;
2183 } else if (numBytesOfClearDataObj != nullptr
2184 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
2185 mErr = -ERANGE;
2186 // subSamples array may silently overflow if number of samples are too large. Use
2187 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2188 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
2189 mErr = -EINVAL;
2190 } else {
2191 jint *numBytesOfClearData =
2192 (numBytesOfClearDataObj == nullptr)
2193 ? nullptr
2194 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
2195
2196 jint *numBytesOfEncryptedData =
2197 (numBytesOfEncryptedDataObj == nullptr)
2198 ? nullptr
2199 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
2200
2201 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
2202
2203 for (jint i = 0; i < mNumSubSamples; ++i) {
2204 mSubSamples[i].mNumBytesOfClearData =
2205 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
2206
2207 mSubSamples[i].mNumBytesOfEncryptedData =
2208 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
2209 }
2210
2211 if (numBytesOfEncryptedData != nullptr) {
2212 env->ReleaseIntArrayElements(
2213 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
2214 numBytesOfEncryptedData = nullptr;
2215 }
2216
2217 if (numBytesOfClearData != nullptr) {
2218 env->ReleaseIntArrayElements(
2219 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2220 numBytesOfClearData = nullptr;
2221 }
2222 }
2223
2224 if (mErr == OK && mKeyObj.get() != nullptr) {
2225 if (env->GetArrayLength(mKeyObj.get()) != 16) {
2226 mErr = -EINVAL;
2227 } else {
2228 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2229 }
2230 }
2231
2232 if (mErr == OK && mIvObj.get() != nullptr) {
2233 if (env->GetArrayLength(mIvObj.get()) != 16) {
2234 mErr = -EINVAL;
2235 } else {
2236 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2237 }
2238 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002239
2240 }
2241
2242 explicit NativeCryptoInfo(jint size)
2243 : mIvObj{nullptr, nullptr},
2244 mKeyObj{nullptr, nullptr},
2245 mMode{CryptoPlugin::kMode_Unencrypted},
2246 mPattern{0, 0} {
2247 mSubSamples = new CryptoPlugin::SubSample[1];
2248 mNumSubSamples = 1;
2249 mSubSamples[0].mNumBytesOfClearData = size;
2250 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002251 }
2252
2253 ~NativeCryptoInfo() {
2254 if (mIv != nullptr) {
2255 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2256 }
2257
2258 if (mKey != nullptr) {
2259 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2260 }
2261
2262 if (mSubSamples != nullptr) {
2263 delete[] mSubSamples;
2264 }
2265 }
2266
2267 JNIEnv *mEnv{nullptr};
2268 ScopedLocalRef<jbyteArray> mIvObj;
2269 ScopedLocalRef<jbyteArray> mKeyObj;
2270 status_t mErr{OK};
2271
2272 CryptoPlugin::SubSample *mSubSamples{nullptr};
2273 int32_t mNumSubSamples{0};
2274 jbyte *mIv{nullptr};
2275 jbyte *mKey{nullptr};
2276 enum CryptoPlugin::Mode mMode;
2277 CryptoPlugin::Pattern mPattern;
2278};
2279
Arun Johnson4ca49092024-02-01 19:07:15 +00002280// This class takes away all dependencies on java(env and jni) and
2281// could be used for taking cryptoInfo objects to MediaCodec.
2282struct MediaCodecCryptoInfo: public CodecCryptoInfo {
2283 explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
2284 if (cryptoInfo.mErr == OK) {
2285 mNumSubSamples = cryptoInfo.mNumSubSamples;
2286 mMode = cryptoInfo.mMode;
2287 mPattern = cryptoInfo.mPattern;
2288 if (cryptoInfo.mKey != nullptr) {
2289 mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
2290 mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
2291 }
2292 if (cryptoInfo.mIv != nullptr) {
2293 mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
2294 mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
2295 }
2296 if (cryptoInfo.mSubSamples != nullptr) {
2297 mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
2298 if (mSubSamplesBuffer.get()) {
2299 CryptoPlugin::SubSample * samples =
2300 (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2301 for (int s = 0 ; s < mNumSubSamples ; s++) {
2302 samples[s].mNumBytesOfClearData =
2303 cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
2304 samples[s].mNumBytesOfEncryptedData =
2305 cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
2306 }
2307 mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2308 }
2309 }
2310
2311 }
2312 }
2313
2314 explicit MediaCodecCryptoInfo(jint size) {
2315 mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
2316 mNumSubSamples = 1;
2317 if (mSubSamplesBuffer.get()) {
2318 CryptoPlugin::SubSample * samples =
2319 (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2320 samples[0].mNumBytesOfClearData = size;
2321 samples[0].mNumBytesOfEncryptedData = 0;
2322 mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2323 }
2324 }
2325 ~MediaCodecCryptoInfo() {}
2326
2327protected:
2328 // all backup buffers for the base object.
2329 sp<ABuffer> mKeyBuffer;
2330 sp<ABuffer> mIvBuffer;
2331 sp<ABuffer> mSubSamplesBuffer;
2332
2333};
2334
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002335static void android_media_MediaCodec_queueSecureInputBuffer(
2336 JNIEnv *env,
2337 jobject thiz,
2338 jint index,
2339 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002340 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002341 jlong timestampUs,
2342 jint flags) {
2343 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2344
2345 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2346
Wonsik Kim24e53802020-05-08 20:04:26 -07002347 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002348 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002349 return;
2350 }
2351
Wonsik Kim1cac4252020-01-24 11:45:37 -08002352 jint numSubSamples =
2353 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2354
2355 jintArray numBytesOfClearDataObj =
2356 (jintArray)env->GetObjectField(
2357 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2358
2359 jintArray numBytesOfEncryptedDataObj =
2360 (jintArray)env->GetObjectField(
2361 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2362
2363 jbyteArray keyObj =
2364 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2365
2366 jbyteArray ivObj =
2367 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2368
2369 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2370 enum CryptoPlugin::Mode mode;
2371 if (jmode == gCryptoModes.Unencrypted) {
2372 mode = CryptoPlugin::kMode_Unencrypted;
2373 } else if (jmode == gCryptoModes.AesCtr) {
2374 mode = CryptoPlugin::kMode_AES_CTR;
2375 } else if (jmode == gCryptoModes.AesCbc) {
2376 mode = CryptoPlugin::kMode_AES_CBC;
2377 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002378 throwExceptionAsNecessary(
2379 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2380 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08002381 return;
2382 }
2383
2384 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2385
2386 CryptoPlugin::Pattern pattern;
2387 if (patternObj == NULL) {
2388 pattern.mEncryptBlocks = 0;
2389 pattern.mSkipBlocks = 0;
2390 } else {
2391 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2392 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2393 }
2394
2395 status_t err = OK;
2396
2397 CryptoPlugin::SubSample *subSamples = NULL;
2398 jbyte *key = NULL;
2399 jbyte *iv = NULL;
2400
2401 if (numSubSamples <= 0) {
2402 err = -EINVAL;
2403 } else if (numBytesOfClearDataObj == NULL
2404 && numBytesOfEncryptedDataObj == NULL) {
2405 err = -EINVAL;
2406 } else if (numBytesOfEncryptedDataObj != NULL
2407 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2408 err = -ERANGE;
2409 } else if (numBytesOfClearDataObj != NULL
2410 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2411 err = -ERANGE;
2412 // subSamples array may silently overflow if number of samples are too large. Use
2413 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2414 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2415 err = -EINVAL;
2416 } else {
2417 jboolean isCopy;
2418
2419 jint *numBytesOfClearData =
2420 (numBytesOfClearDataObj == NULL)
2421 ? NULL
2422 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2423
2424 jint *numBytesOfEncryptedData =
2425 (numBytesOfEncryptedDataObj == NULL)
2426 ? NULL
2427 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2428
2429 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2430
2431 for (jint i = 0; i < numSubSamples; ++i) {
2432 subSamples[i].mNumBytesOfClearData =
2433 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2434
2435 subSamples[i].mNumBytesOfEncryptedData =
2436 (numBytesOfEncryptedData == NULL)
2437 ? 0 : numBytesOfEncryptedData[i];
2438 }
2439
2440 if (numBytesOfEncryptedData != NULL) {
2441 env->ReleaseIntArrayElements(
2442 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2443 numBytesOfEncryptedData = NULL;
2444 }
2445
2446 if (numBytesOfClearData != NULL) {
2447 env->ReleaseIntArrayElements(
2448 numBytesOfClearDataObj, numBytesOfClearData, 0);
2449 numBytesOfClearData = NULL;
2450 }
2451 }
2452
2453 if (err == OK && keyObj != NULL) {
2454 if (env->GetArrayLength(keyObj) != 16) {
2455 err = -EINVAL;
2456 } else {
2457 jboolean isCopy;
2458 key = env->GetByteArrayElements(keyObj, &isCopy);
2459 }
2460 }
2461
2462 if (err == OK && ivObj != NULL) {
2463 if (env->GetArrayLength(ivObj) != 16) {
2464 err = -EINVAL;
2465 } else {
2466 jboolean isCopy;
2467 iv = env->GetByteArrayElements(ivObj, &isCopy);
2468 }
2469 }
2470
Andreas Huberbfc56f42012-04-19 12:47:07 -07002471 AString errorDetailMsg;
2472
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002473 if (err == OK) {
2474 err = codec->queueSecureInputBuffer(
2475 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002476 subSamples, numSubSamples,
2477 (const uint8_t *)key, (const uint8_t *)iv,
2478 mode,
2479 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002480 timestampUs,
2481 flags,
2482 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002483 }
2484
Wonsik Kim1cac4252020-01-24 11:45:37 -08002485 if (iv != NULL) {
2486 env->ReleaseByteArrayElements(ivObj, iv, 0);
2487 iv = NULL;
2488 }
2489
2490 if (key != NULL) {
2491 env->ReleaseByteArrayElements(keyObj, key, 0);
2492 key = NULL;
2493 }
2494
2495 delete[] subSamples;
2496 subSamples = NULL;
2497
Andreas Huberbfc56f42012-04-19 12:47:07 -07002498 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002499 env, err, ACTION_CODE_FATAL,
2500 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002501}
2502
Arun Johnson4ca49092024-02-01 19:07:15 +00002503static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
2504 jint * const totalSize,
2505 std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
2506 const jobjectArray &objArray,
2507 AString * const errorDetailMsg) {
2508 if (env == nullptr
2509 || cryptoInfoObjs == nullptr
2510 || totalSize == nullptr) {
2511 if (errorDetailMsg) {
2512 *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2513 }
2514 return BAD_VALUE;
2515 }
2516 const jsize numEntries = env->GetArrayLength(objArray);
2517 if (numEntries <= 0) {
2518 if (errorDetailMsg) {
2519 *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
2520 }
2521 return BAD_VALUE;
2522 }
2523 cryptoInfoObjs->clear();
2524 *totalSize = 0;
2525 jint size = 0;
2526 for (jsize i = 0; i < numEntries ; i++) {
2527 jobject param = env->GetObjectArrayElement(objArray, i);
2528 if (param == NULL) {
2529 if (errorDetailMsg) {
2530 *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2531 }
2532 return BAD_VALUE;
2533 }
2534 NativeCryptoInfo nativeInfo(env, param);
2535 std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
2536 for (int i = 0; i < info->mNumSubSamples; i++) {
2537 size += info->mSubSamples[i].mNumBytesOfClearData;
2538 size += info->mSubSamples[i].mNumBytesOfEncryptedData;
2539 }
2540 cryptoInfoObjs->push_back(std::move(info));
2541 }
2542 *totalSize = size;
2543 return OK;
2544}
2545
2546
2547static void android_media_MediaCodec_queueSecureInputBuffers(
2548 JNIEnv *env,
2549 jobject thiz,
2550 jint index,
2551 jobjectArray bufferInfosObjs,
2552 jobjectArray cryptoInfoObjs) {
2553 ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
2554
2555 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2556
2557 if (codec == NULL || codec->initCheck() != OK) {
2558 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2559 return;
2560 }
2561 sp<BufferInfosWrapper> auInfos =
2562 new BufferInfosWrapper{decltype(auInfos->value)()};
2563 sp<CryptoInfosWrapper> cryptoInfos =
2564 new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
2565 AString errorDetailMsg;
2566 jint initialOffset = 0;
2567 jint totalSize = 0;
2568 status_t err = extractInfosFromObject(
2569 env,
2570 &initialOffset,
2571 &totalSize,
2572 &auInfos->value,
2573 bufferInfosObjs,
2574 &errorDetailMsg);
2575 if (err == OK) {
2576 err = extractCryptoInfosFromObjectArray(env,
2577 &totalSize,
2578 &cryptoInfos->value,
2579 cryptoInfoObjs,
2580 &errorDetailMsg);
2581 }
2582 if (err == OK) {
2583 err = codec->queueSecureInputBuffers(
2584 index,
2585 initialOffset,
2586 totalSize,
2587 auInfos,
2588 cryptoInfos,
2589 &errorDetailMsg);
2590 }
2591 throwExceptionAsNecessary(
2592 env, err, ACTION_CODE_FATAL,
2593 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
2594}
2595
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002596static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002597 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2598 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2599 env, bufferObj);
2600 AHardwareBuffer_Desc desc;
2601 AHardwareBuffer_describe(hardwareBuffer, &desc);
2602 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2603 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2604 return nullptr;
2605 }
2606 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2607 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2608 return nullptr;
2609 }
2610 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2611
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002612 uint64_t cpuUsage = 0;
2613 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2614 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002615
2616 AHardwareBuffer_Planes planes;
2617 int err = AHardwareBuffer_lockPlanes(
2618 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2619 if (err != 0) {
2620 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2621 return nullptr;
2622 }
2623
2624 if (planes.planeCount != 3) {
2625 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2626 return nullptr;
2627 }
2628
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002629 ScopedLocalRef<jobjectArray> buffersArray{
2630 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2631 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2632 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002633
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002634 jboolean isCopy = JNI_FALSE;
2635 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2636 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2637
2638 // For Y plane
2639 int rowSampling = 1;
2640 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002641 // plane indices are Y-U-V.
2642 for (uint32_t i = 0; i < 3; ++i) {
2643 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002644 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2645 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2646 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002647 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2648 env,
2649 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002650 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002651 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002652 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002653 readOnly,
2654 true)};
2655
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002656 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2657 rowStrides[i] = plane.rowStride;
2658 pixelStrides[i] = plane.pixelStride;
2659 // For U-V planes
2660 rowSampling = 2;
2661 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002662 }
2663
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002664 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2665 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2666 rowStrides = pixelStrides = nullptr;
2667
Wonsik Kim637afb22020-02-25 14:27:29 -08002668 ScopedLocalRef<jclass> imageClazz(
2669 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2670 CHECK(imageClazz.get() != NULL);
2671
2672 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002673 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002674
2675 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002676 buffersArray.get(),
2677 rowStridesArray.get(),
2678 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002679 desc.width,
2680 desc.height,
2681 desc.format, // ???
2682 (jboolean)readOnly /* readOnly */,
2683 (jlong)0 /* timestamp */,
2684 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2685 (jlong)hardwareBuffer);
2686
2687 // if MediaImage creation fails, return null
2688 if (env->ExceptionCheck()) {
2689 env->ExceptionDescribe();
2690 env->ExceptionClear();
2691 return nullptr;
2692 }
2693
2694 AHardwareBuffer_acquire(hardwareBuffer);
2695
2696 return img;
2697}
2698
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002699static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2700 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002701 if (context == 0) {
2702 return;
2703 }
2704 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2705
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002706 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2707 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002708 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2709 // Continue to release the hardwareBuffer
2710 }
2711
2712 AHardwareBuffer_release(hardwareBuffer);
2713}
2714
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002715static status_t ConvertKeyValueListsToAMessage(
2716 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2717 static struct Fields {
2718 explicit Fields(JNIEnv *env) {
2719 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2720 CHECK(clazz.get() != NULL);
2721 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2722
2723 clazz.reset(env->FindClass("java/lang/Integer"));
2724 CHECK(clazz.get() != NULL);
2725 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2726
2727 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2728 CHECK(mIntegerValueId != NULL);
2729
2730 clazz.reset(env->FindClass("java/lang/Long"));
2731 CHECK(clazz.get() != NULL);
2732 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2733
2734 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2735 CHECK(mLongValueId != NULL);
2736
2737 clazz.reset(env->FindClass("java/lang/Float"));
2738 CHECK(clazz.get() != NULL);
2739 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2740
2741 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2742 CHECK(mFloatValueId != NULL);
2743
2744 clazz.reset(env->FindClass("java/util/ArrayList"));
2745 CHECK(clazz.get() != NULL);
2746
2747 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2748 CHECK(mByteBufferArrayId != NULL);
2749 }
2750
2751 jclass mStringClass;
2752 jclass mIntegerClass;
2753 jmethodID mIntegerValueId;
2754 jclass mLongClass;
2755 jmethodID mLongValueId;
2756 jclass mFloatClass;
2757 jmethodID mFloatValueId;
2758 jmethodID mByteBufferArrayId;
2759 } sFields{env};
2760
2761 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2762 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2763 return BAD_VALUE;
2764 }
2765
2766 sp<AMessage> result{new AMessage};
2767 for (jint i = 0; i < size; ++i) {
2768 ScopedLocalRef<jstring> jkey{
2769 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2770 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2771 AString key;
2772 if (tmp) {
2773 key.setTo(tmp);
2774 }
2775 env->ReleaseStringUTFChars(jkey.get(), tmp);
2776 if (key.empty()) {
2777 return NO_MEMORY;
2778 }
2779
2780 ScopedLocalRef<jobject> jvalue{
2781 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2782
2783 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2784 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2785 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002786 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002787 return NO_MEMORY;
2788 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002789 value.setTo(tmp);
2790 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002791 result->setString(key.c_str(), value);
2792 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2793 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2794 result->setInt32(key.c_str(), value);
2795 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2796 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2797 result->setInt64(key.c_str(), value);
2798 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2799 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2800 result->setFloat(key.c_str(), value);
2801 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002802 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2803 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002804 sp<ABuffer> buffer{new ABuffer(limit - position)};
2805 void *data = env->GetDirectBufferAddress(jvalue.get());
2806 if (data != nullptr) {
2807 memcpy(buffer->data(),
2808 static_cast<const uint8_t *>(data) + position,
2809 buffer->size());
2810 } else {
2811 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2812 jvalue.get(), sFields.mByteBufferArrayId)};
2813 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2814 reinterpret_cast<jbyte *>(buffer->data()));
2815 }
2816 result->setBuffer(key.c_str(), buffer);
2817 }
2818 }
2819
2820 *msg = result;
2821 return OK;
2822}
2823
Wonsik Kim8569a662022-05-24 14:16:44 -07002824static bool obtain(
2825 JMediaCodecLinearBlock *context,
2826 int capacity,
2827 const std::vector<std::string> &names,
2828 bool secure) {
2829 if (secure) {
2830 // Start at 1MB, which is an arbitrary starting point that can
2831 // increase when needed.
2832 constexpr size_t kInitialDealerCapacity = 1048576;
2833 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2834 kInitialDealerCapacity, "JNI(1MB)");
2835 context->mMemory = sDealer->allocate(capacity);
2836 if (context->mMemory == nullptr) {
2837 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2838 while (capacity * 2 > newDealerCapacity) {
2839 newDealerCapacity *= 2;
2840 }
2841 ALOGI("LinearBlock.native_obtain: "
2842 "Dealer capacity increasing from %zuMB to %zuMB",
2843 sDealer->getMemoryHeap()->getSize() / 1048576,
2844 newDealerCapacity / 1048576);
2845 sDealer = new MemoryDealer(
2846 newDealerCapacity,
2847 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2848 context->mMemory = sDealer->allocate(capacity);
2849 }
2850 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2851 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2852 } else {
2853 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2854 if (!context->mBlock) {
2855 return false;
2856 }
2857 }
2858 context->mCodecNames = names;
2859 return true;
2860}
2861
2862static void extractMemoryFromContext(
2863 JMediaCodecLinearBlock *context,
2864 jint offset,
2865 jint size,
2866 sp<hardware::HidlMemory> *memory) {
2867 *memory = context->toHidlMemory();
2868 if (*memory == nullptr) {
2869 if (!context->mBlock) {
2870 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2871 return;
2872 }
2873 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2874 context->capacity());
2875 if (!obtain(context, context->capacity(),
2876 context->mCodecNames, true /* secure */)) {
2877 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2878 return;
2879 }
2880 C2WriteView view = context->mBlock->map().get();
2881 if (view.error() != C2_OK) {
2882 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2883 return;
2884 }
2885 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2886 memcpy(memoryPtr + offset, view.base() + offset, size);
2887 context->mBlock.reset();
2888 context->mReadWriteMapping.reset();
2889 *memory = context->toHidlMemory();
2890 }
2891}
2892
2893static void extractBufferFromContext(
2894 JMediaCodecLinearBlock *context,
2895 jint offset,
2896 jint size,
2897 std::shared_ptr<C2Buffer> *buffer) {
Arun Johnson2aef16f2024-02-24 00:01:33 +00002898 if ((offset + size) > context->capacity()) {
2899 ALOGW("extractBufferFromContext: offset + size provided exceed capacity");
2900 return;
2901 }
Wonsik Kim8569a662022-05-24 14:16:44 -07002902 *buffer = context->toC2Buffer(offset, size);
2903 if (*buffer == nullptr) {
2904 if (!context->mMemory) {
2905 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2906 return;
2907 }
2908 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2909 context->capacity());
2910 if (obtain(context, context->capacity(),
2911 context->mCodecNames, false /* secure */)) {
2912 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2913 return;
2914 }
2915 C2WriteView view = context->mBlock->map().get();
2916 if (view.error() != C2_OK) {
2917 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2918 return;
2919 }
2920 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2921 memcpy(view.base() + offset, memoryPtr + offset, size);
2922 context->mMemory.clear();
2923 context->mHidlMemory.clear();
2924 context->mHidlMemorySize = 0;
2925 context->mHidlMemoryOffset = 0;
2926 *buffer = context->toC2Buffer(offset, size);
2927 }
2928}
2929
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002930static void android_media_MediaCodec_native_queueLinearBlock(
2931 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
Arun Johnson677a8812024-02-06 12:32:54 +00002932 jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002933 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2934
2935 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2936
Wonsik Kim24e53802020-05-08 20:04:26 -07002937 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002938 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002939 return;
2940 }
2941
2942 sp<AMessage> tunings;
2943 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2944 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002945 throwExceptionAsNecessary(
2946 env, err, ACTION_CODE_FATAL,
2947 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002948 return;
2949 }
Arun Johnson4ca49092024-02-01 19:07:15 +00002950 jint totalSize = 0;
2951 jint initialOffset = 0;
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002952 std::vector<AccessUnitInfo> infoVec;
2953 AString errorDetailMsg;
2954 err = extractInfosFromObject(env,
2955 &initialOffset,
2956 &totalSize,
2957 &infoVec,
2958 objArray,
2959 &errorDetailMsg);
2960 if (err != OK) {
2961 throwExceptionAsNecessary(
2962 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2963 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2964 return;
2965 }
2966 sp<BufferInfosWrapper> infos =
2967 new BufferInfosWrapper{std::move(infoVec)};
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002968 std::shared_ptr<C2Buffer> buffer;
2969 sp<hardware::HidlMemory> memory;
2970 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2971 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2972 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2973 JMediaCodecLinearBlock *context =
2974 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002975 if (codec->hasCryptoOrDescrambler()) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002976 extractMemoryFromContext(context, initialOffset, totalSize, &memory);
2977 initialOffset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002978 } else {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002979 extractBufferFromContext(context, initialOffset, totalSize, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002980 }
2981 }
2982 env->MonitorExit(lock.get());
2983 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002984 throwExceptionAsNecessary(
2985 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2986 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002987 return;
2988 }
2989
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002990 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002991 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002992 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002993 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002994 throwExceptionAsNecessary(
2995 env, BAD_VALUE, ACTION_CODE_FATAL,
2996 "Unexpected error: the input buffer is not compatible with "
2997 "the secure codec, and a fallback logic failed.\n"
2998 "Suggestion: please try including the secure codec when calling "
2999 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003000 return;
3001 }
Arun Johnsona7a04b52024-03-04 06:38:43 +00003002 sp<CryptoInfosWrapper> cryptoInfos = nullptr;
3003 jint sampleSize = totalSize;
Arun Johnson677a8812024-02-06 12:32:54 +00003004 if (cryptoInfoArray != nullptr) {
Arun Johnsona7a04b52024-03-04 06:38:43 +00003005 cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
Arun Johnson677a8812024-02-06 12:32:54 +00003006 extractCryptoInfosFromObjectArray(env,
3007 &sampleSize,
3008 &cryptoInfos->value,
3009 cryptoInfoArray,
3010 &errorDetailMsg);
Arun Johnson677a8812024-02-06 12:32:54 +00003011 }
George Burgess IV436998b2022-11-02 11:42:33 -06003012 if (env->ExceptionCheck()) {
3013 // Creation of cryptoInfo failed. Let the exception bubble up.
3014 return;
3015 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003016 err = codec->queueEncryptedLinearBlock(
3017 index,
3018 memory,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003019 initialOffset,
Arun Johnson677a8812024-02-06 12:32:54 +00003020 sampleSize,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003021 infos,
Arun Johnson677a8812024-02-06 12:32:54 +00003022 cryptoInfos,
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003023 tunings,
3024 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07003025 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003026 } else {
3027 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003028 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003029 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003030 throwExceptionAsNecessary(
3031 env, BAD_VALUE, ACTION_CODE_FATAL,
3032 "Unexpected error: the input buffer is not compatible with "
3033 "the non-secure codec, and a fallback logic failed.\n"
3034 "Suggestion: please do not include the secure codec when calling "
3035 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003036 return;
3037 }
3038 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003039 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003040 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003041 throwExceptionAsNecessary(
3042 env, err, ACTION_CODE_FATAL,
3043 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003044}
3045
Wonsik Kim637afb22020-02-25 14:27:29 -08003046static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003047 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
3048 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08003049 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003050
3051 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3052
Wonsik Kim24e53802020-05-08 20:04:26 -07003053 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003054 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003055 return;
3056 }
3057
3058 sp<AMessage> tunings;
3059 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
3060 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003061 throwExceptionAsNecessary(
3062 env, err, ACTION_CODE_FATAL,
3063 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003064 return;
3065 }
3066
Wonsik Kim637afb22020-02-25 14:27:29 -08003067 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
3068 env, bufferObj);
3069 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
3070 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003071 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
3072 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
3073 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
3074 std::shared_ptr<C2Allocator> alloc;
3075 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
3076 C2PlatformAllocatorStore::GRALLOC, &alloc);
3077 if (err == C2_OK) {
3078 return alloc;
3079 }
3080 return nullptr;
3081 }();
3082 std::shared_ptr<C2GraphicAllocation> alloc;
3083 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
3084 if (c2err != C2_OK) {
3085 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09003086 native_handle_close(handle);
3087 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003088 throwExceptionAsNecessary(
3089 env, BAD_VALUE, ACTION_CODE_FATAL,
3090 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003091 return;
3092 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003093 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08003094 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
3095 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003096 AString errorDetailMsg;
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003097 sp<BufferInfosWrapper> infos =
3098 new BufferInfosWrapper{decltype(infos->value)()};
3099 infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003100 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003101 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003102 throwExceptionAsNecessary(
3103 env, err, ACTION_CODE_FATAL,
3104 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003105}
3106
3107static void android_media_MediaCodec_native_getOutputFrame(
3108 JNIEnv *env, jobject thiz, jobject frame, jint index) {
3109 ALOGV("android_media_MediaCodec_native_getOutputFrame");
3110
3111 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3112
Wonsik Kim24e53802020-05-08 20:04:26 -07003113 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003114 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003115 return;
3116 }
3117
3118 status_t err = codec->getOutputFrame(env, frame, index);
3119 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003120 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003121 }
3122}
3123
Andreas Huber88572f72012-02-21 11:47:18 -08003124static jint android_media_MediaCodec_dequeueInputBuffer(
3125 JNIEnv *env, jobject thiz, jlong timeoutUs) {
3126 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
3127
3128 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3129
Wonsik Kim24e53802020-05-08 20:04:26 -07003130 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003131 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003132 return -1;
3133 }
3134
3135 size_t index;
3136 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
3137
3138 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00003139 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08003140 }
3141
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003142 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003143}
3144
3145static jint android_media_MediaCodec_dequeueOutputBuffer(
3146 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
3147 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
3148
3149 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3150
Wonsik Kim24e53802020-05-08 20:04:26 -07003151 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003152 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07003153 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08003154 }
3155
3156 size_t index;
3157 status_t err = codec->dequeueOutputBuffer(
3158 env, bufferInfo, &index, timeoutUs);
3159
3160 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00003161 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08003162 }
3163
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003164 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003165}
3166
3167static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003168 JNIEnv *env, jobject thiz,
3169 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08003170 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
3171
3172 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3173
Wonsik Kim24e53802020-05-08 20:04:26 -07003174 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003175 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003176 return;
3177 }
3178
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003179 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08003180
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003181 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003182}
3183
Andy McFadden2621e402013-02-19 07:29:21 -08003184static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
3185 jobject thiz) {
3186 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
3187
3188 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003189 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003190 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003191 return;
3192 }
3193
3194 status_t err = codec->signalEndOfInputStream();
3195
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003196 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003197}
3198
Lajos Molnard4023112014-07-11 15:12:59 -07003199static jobject android_media_MediaCodec_getFormatNative(
3200 JNIEnv *env, jobject thiz, jboolean input) {
3201 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08003202
3203 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3204
Wonsik Kim24e53802020-05-08 20:04:26 -07003205 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003206 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003207 return NULL;
3208 }
3209
3210 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07003211 status_t err = codec->getFormat(env, input, &format);
3212
3213 if (err == OK) {
3214 return format;
3215 }
3216
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003217 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003218
3219 return NULL;
3220}
3221
3222static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
3223 JNIEnv *env, jobject thiz, jint index) {
3224 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
3225
3226 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3227
Wonsik Kim24e53802020-05-08 20:04:26 -07003228 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003229 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003230 return NULL;
3231 }
3232
3233 jobject format;
3234 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08003235
3236 if (err == OK) {
3237 return format;
3238 }
3239
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003240 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003241
3242 return NULL;
3243}
3244
3245static jobjectArray android_media_MediaCodec_getBuffers(
3246 JNIEnv *env, jobject thiz, jboolean input) {
3247 ALOGV("android_media_MediaCodec_getBuffers");
3248
3249 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3250
Wonsik Kim24e53802020-05-08 20:04:26 -07003251 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003252 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003253 return NULL;
3254 }
3255
3256 jobjectArray buffers;
3257 status_t err = codec->getBuffers(env, input, &buffers);
3258
3259 if (err == OK) {
3260 return buffers;
3261 }
3262
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003263 // if we're out of memory, an exception was already thrown
3264 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003265 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003266 }
Andreas Huber88572f72012-02-21 11:47:18 -08003267
3268 return NULL;
3269}
3270
Lajos Molnard4023112014-07-11 15:12:59 -07003271static jobject android_media_MediaCodec_getBuffer(
3272 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3273 ALOGV("android_media_MediaCodec_getBuffer");
3274
3275 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3276
Wonsik Kim24e53802020-05-08 20:04:26 -07003277 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003278 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003279 return NULL;
3280 }
3281
3282 jobject buffer;
3283 status_t err = codec->getBuffer(env, input, index, &buffer);
3284
3285 if (err == OK) {
3286 return buffer;
3287 }
3288
3289 // if we're out of memory, an exception was already thrown
3290 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003291 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003292 }
3293
3294 return NULL;
3295}
3296
3297static jobject android_media_MediaCodec_getImage(
3298 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3299 ALOGV("android_media_MediaCodec_getImage");
3300
3301 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3302
Wonsik Kim24e53802020-05-08 20:04:26 -07003303 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003304 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003305 return NULL;
3306 }
3307
3308 jobject image;
3309 status_t err = codec->getImage(env, input, index, &image);
3310
3311 if (err == OK) {
3312 return image;
3313 }
3314
3315 // if we're out of memory, an exception was already thrown
3316 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003317 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003318 }
3319
3320 return NULL;
3321}
3322
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003323static jobject android_media_MediaCodec_getName(
3324 JNIEnv *env, jobject thiz) {
3325 ALOGV("android_media_MediaCodec_getName");
3326
3327 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3328
Wonsik Kim24e53802020-05-08 20:04:26 -07003329 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003330 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003331 return NULL;
3332 }
3333
3334 jstring name;
3335 status_t err = codec->getName(env, &name);
3336
3337 if (err == OK) {
3338 return name;
3339 }
3340
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003341 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003342
3343 return NULL;
3344}
3345
Chong Zhanga0b72a62018-02-28 18:46:26 -08003346static jobject android_media_MediaCodec_getOwnCodecInfo(
3347 JNIEnv *env, jobject thiz) {
3348 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
3349
3350 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3351
Wonsik Kim24e53802020-05-08 20:04:26 -07003352 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003353 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003354 return NULL;
3355 }
3356
3357 jobject codecInfoObj;
3358 status_t err = codec->getCodecInfo(env, &codecInfoObj);
3359
3360 if (err == OK) {
3361 return codecInfoObj;
3362 }
3363
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003364 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003365
3366 return NULL;
3367}
3368
Ray Essick0e0fee12017-01-25 18:01:56 -08003369static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08003370android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08003371{
Ray Essickf2d0e402017-03-09 10:17:51 -08003372 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08003373
3374 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003375 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003376 jniThrowException(env, "java/lang/IllegalStateException",
3377 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08003378 return 0;
3379 }
3380
3381 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08003382 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08003383
3384 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08003385 if (err != OK) {
3386 ALOGE("getMetrics failed");
3387 return (jobject) NULL;
3388 }
3389
Ray Essick0e0fee12017-01-25 18:01:56 -08003390 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
3391
3392 // housekeeping
3393 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07003394 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08003395
3396 return mybundle;
3397}
3398
Andreas Huber226065b2013-08-12 10:14:11 -07003399static void android_media_MediaCodec_setParameters(
3400 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3401 ALOGV("android_media_MediaCodec_setParameters");
3402
3403 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3404
Wonsik Kim24e53802020-05-08 20:04:26 -07003405 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003406 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003407 return;
3408 }
3409
3410 sp<AMessage> params;
3411 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3412
3413 if (err == OK) {
3414 err = codec->setParameters(params);
3415 }
3416
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003417 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003418}
3419
Andreas Huberb12a5392012-04-30 14:18:33 -07003420static void android_media_MediaCodec_setVideoScalingMode(
3421 JNIEnv *env, jobject thiz, jint mode) {
3422 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3423
Wonsik Kim24e53802020-05-08 20:04:26 -07003424 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003425 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huberb12a5392012-04-30 14:18:33 -07003426 return;
3427 }
3428
3429 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3430 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003431 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003432 String8::format("Unrecognized mode: %d", mode).c_str());
Andreas Huberb12a5392012-04-30 14:18:33 -07003433 return;
3434 }
3435
3436 codec->setVideoScalingMode(mode);
3437}
3438
ybai5e053202018-11-01 13:02:15 +08003439static void android_media_MediaCodec_setAudioPresentation(
3440 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3441 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3442
Wonsik Kim24e53802020-05-08 20:04:26 -07003443 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003444 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08003445 return;
3446 }
3447
3448 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3449}
3450
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003451static jobject android_media_MediaCodec_getSupportedVendorParameters(
3452 JNIEnv *env, jobject thiz) {
3453 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3454
3455 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003456 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003457 return NULL;
3458 }
3459
3460 jobject ret = NULL;
3461 status_t status = codec->querySupportedVendorParameters(env, &ret);
3462 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003463 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003464 }
3465
3466 return ret;
3467}
3468
3469static jobject android_media_MediaCodec_getParameterDescriptor(
3470 JNIEnv *env, jobject thiz, jstring name) {
3471 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3472
3473 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003474 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003475 return NULL;
3476 }
3477
3478 jobject ret = NULL;
3479 status_t status = codec->describeParameter(env, name, &ret);
3480 if (status != OK) {
3481 ret = NULL;
3482 }
3483 return ret;
3484}
3485
3486static void android_media_MediaCodec_subscribeToVendorParameters(
3487 JNIEnv *env, jobject thiz, jobject names) {
3488 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3489
3490 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003491 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003492 return;
3493 }
3494
3495 status_t status = codec->subscribeToVendorParameters(env, names);
3496 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003497 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003498 }
3499 return;
3500}
3501
3502static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3503 JNIEnv *env, jobject thiz, jobject names) {
3504 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3505
3506 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003507 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003508 return;
3509 }
3510
3511 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3512 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003513 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003514 }
3515 return;
3516}
3517
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003518static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003519 ScopedLocalRef<jclass> clazz(
3520 env, env->FindClass("android/media/MediaCodec"));
3521 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003522
Andreas Huberaba67132013-10-22 12:40:01 -07003523 gFields.postEventFromNativeID =
3524 env->GetMethodID(
3525 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003526 CHECK(gFields.postEventFromNativeID != NULL);
3527
Wonsik Kim61796fd2018-09-13 13:15:59 -07003528 gFields.lockAndGetContextID =
3529 env->GetMethodID(
3530 clazz.get(), "lockAndGetContext", "()J");
3531 CHECK(gFields.lockAndGetContextID != NULL);
3532
3533 gFields.setAndUnlockContextID =
3534 env->GetMethodID(
3535 clazz.get(), "setAndUnlockContext", "(J)V");
3536 CHECK(gFields.setAndUnlockContextID != NULL);
3537
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003538 jfieldID field;
3539 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3540 CHECK(field != NULL);
3541 gCryptoModes.Unencrypted =
3542 env->GetStaticIntField(clazz.get(), field);
3543
3544 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3545 CHECK(field != NULL);
3546 gCryptoModes.AesCtr =
3547 env->GetStaticIntField(clazz.get(), field);
3548
3549 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3550 CHECK(field != NULL);
3551 gCryptoModes.AesCbc =
3552 env->GetStaticIntField(clazz.get(), field);
3553
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003554 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3555 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003556
Arun Johnson5a4c7332022-12-17 00:47:06 +00003557 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3558 CHECK(gFields.cryptoInfoSetID != NULL);
3559
3560 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3561 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3562
Andreas Huber91befdc2012-04-18 12:19:51 -07003563 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003564 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003565 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3566
3567 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003568 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003569 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3570
3571 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003572 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003573 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3574
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003575 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003576 CHECK(gFields.cryptoInfoKeyID != NULL);
3577
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003578 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003579 CHECK(gFields.cryptoInfoIVID != NULL);
3580
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003581 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003582 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003583
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003584 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003585 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3586 CHECK(gFields.cryptoInfoPatternID != NULL);
3587
3588 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3589 CHECK(clazz.get() != NULL);
3590
3591 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3592 CHECK(gFields.patternEncryptBlocksID != NULL);
3593
3594 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3595 CHECK(gFields.patternSkipBlocksID != NULL);
3596
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003597 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3598 CHECK(clazz.get() != NULL);
3599
3600 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3601 CHECK(gFields.queueRequestIndexID != NULL);
3602
3603 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3604 CHECK(clazz.get() != NULL);
3605
3606 gFields.outputFrameLinearBlockID =
3607 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3608 CHECK(gFields.outputFrameLinearBlockID != NULL);
3609
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003610 gFields.outputFramebufferInfosID =
3611 env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
3612 CHECK(gFields.outputFramebufferInfosID != NULL);
3613
Wonsik Kim637afb22020-02-25 14:27:29 -08003614 gFields.outputFrameHardwareBufferID =
3615 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3616 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003617
3618 gFields.outputFrameChangedKeysID =
3619 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3620 CHECK(gFields.outputFrameChangedKeysID != NULL);
3621
3622 gFields.outputFrameFormatID =
3623 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3624 CHECK(gFields.outputFrameFormatID != NULL);
3625
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003626 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3627 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003628
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003629 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003630 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003631 gCryptoErrorCodes.cryptoErrorNoKey =
3632 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003633
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003634 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003635 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003636 gCryptoErrorCodes.cryptoErrorKeyExpired =
3637 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003638
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003639 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003640 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003641 gCryptoErrorCodes.cryptoErrorResourceBusy =
3642 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003643
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003644 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3645 CHECK(field != NULL);
3646 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3647 env->GetStaticIntField(clazz.get(), field);
3648
Jeff Tinker96a2a952015-07-01 17:35:18 -07003649 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3650 CHECK(field != NULL);
3651 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3652 env->GetStaticIntField(clazz.get(), field);
3653
Jeff Tinker20594d82018-12-12 08:31:22 -08003654 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3655 CHECK(field != NULL);
3656 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3657 env->GetStaticIntField(clazz.get(), field);
3658
Jeff Tinkerd3932162016-03-05 11:35:20 -08003659 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3660 CHECK(field != NULL);
3661 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3662 env->GetStaticIntField(clazz.get(), field);
3663
Jeff Tinker20594d82018-12-12 08:31:22 -08003664 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3665 CHECK(field != NULL);
3666 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3667 env->GetStaticIntField(clazz.get(), field);
3668
3669 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3670 CHECK(field != NULL);
3671 gCryptoErrorCodes.cryptoErrorLostState =
3672 env->GetStaticIntField(clazz.get(), field);
3673
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003674 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3675 CHECK(clazz.get() != NULL);
3676 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3677 CHECK(field != NULL);
3678 gCodecActionCodes.codecActionTransient =
3679 env->GetStaticIntField(clazz.get(), field);
3680
3681 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3682 CHECK(field != NULL);
3683 gCodecActionCodes.codecActionRecoverable =
3684 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003685
Ronghua Wuc53ad692015-05-08 14:40:49 -07003686 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003687 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003688 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003689 env->GetStaticIntField(clazz.get(), field);
3690
Ronghua Wuc53ad692015-05-08 14:40:49 -07003691 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003692 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003693 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003694 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003695
3696 clazz.reset(env->FindClass("android/view/Surface"));
3697 CHECK(clazz.get() != NULL);
3698
3699 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3700 CHECK(field != NULL);
3701 gPersistentSurfaceClassInfo.mLock = field;
3702
3703 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3704 CHECK(method != NULL);
3705 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3706
3707 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3708 CHECK(clazz.get() != NULL);
3709 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3710
3711 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3712 CHECK(method != NULL);
3713 gPersistentSurfaceClassInfo.ctor = method;
3714
3715 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3716 CHECK(field != NULL);
3717 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003718
3719 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3720 CHECK(clazz.get() != NULL);
3721 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3722
3723 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003724 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003725 "Ljava/util/Map;Ljava/util/Map;)V");
3726 CHECK(method != NULL);
3727 gCodecInfo.capsCtorId = method;
3728
3729 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3730 CHECK(clazz.get() != NULL);
3731 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3732
3733 field = env->GetFieldID(clazz.get(), "profile", "I");
3734 CHECK(field != NULL);
3735 gCodecInfo.profileField = field;
3736
3737 field = env->GetFieldID(clazz.get(), "level", "I");
3738 CHECK(field != NULL);
3739 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003740
3741 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3742 CHECK(clazz.get() != NULL);
3743 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3744
3745 ScopedLocalRef<jclass> byteOrderClass(
3746 env, env->FindClass("java/nio/ByteOrder"));
3747 CHECK(byteOrderClass.get() != NULL);
3748
3749 jmethodID nativeOrderID = env->GetStaticMethodID(
3750 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3751 CHECK(nativeOrderID != NULL);
3752
3753 ScopedLocalRef<jobject> nativeByteOrderObj{
3754 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3755 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3756 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3757 nativeByteOrderObj.reset();
3758
3759 gByteBufferInfo.orderId = env->GetMethodID(
3760 clazz.get(),
3761 "order",
3762 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3763 CHECK(gByteBufferInfo.orderId != NULL);
3764
3765 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3766 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3767 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3768
3769 gByteBufferInfo.positionId = env->GetMethodID(
3770 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3771 CHECK(gByteBufferInfo.positionId != NULL);
3772
3773 gByteBufferInfo.limitId = env->GetMethodID(
3774 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3775 CHECK(gByteBufferInfo.limitId != NULL);
3776
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003777 gByteBufferInfo.getPositionId = env->GetMethodID(
3778 clazz.get(), "position", "()I");
3779 CHECK(gByteBufferInfo.getPositionId != NULL);
3780
3781 gByteBufferInfo.getLimitId = env->GetMethodID(
3782 clazz.get(), "limit", "()I");
3783 CHECK(gByteBufferInfo.getLimitId != NULL);
3784
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003785 clazz.reset(env->FindClass("java/util/ArrayList"));
3786 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003787 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3788
3789 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3790 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003791
3792 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3793 CHECK(gArrayListInfo.sizeId != NULL);
3794
3795 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3796 CHECK(gArrayListInfo.getId != NULL);
3797
3798 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3799 CHECK(gArrayListInfo.addId != NULL);
3800
Arun Johnson206270e2023-10-31 20:40:12 +00003801 clazz.reset(env->FindClass("java/util/ArrayDeque"));
3802 CHECK(clazz.get() != NULL);
3803 gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3804
3805 gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3806 CHECK(gArrayDequeInfo.ctorId != NULL);
3807
3808 gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3809 CHECK(gArrayDequeInfo.sizeId != NULL);
3810
3811 gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3812 CHECK(gArrayDequeInfo.addId != NULL);
3813
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003814 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3815 CHECK(clazz.get() != NULL);
3816
3817 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3818
3819 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3820 CHECK(gLinearBlockInfo.ctorId != NULL);
3821
3822 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3823 clazz.get(), "setInternalStateLocked", "(JZ)V");
3824 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3825
3826 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3827 CHECK(gLinearBlockInfo.contextId != NULL);
3828
3829 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3830 CHECK(gLinearBlockInfo.validId != NULL);
3831
3832 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3833 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003834
3835 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3836 CHECK(clazz.get() != NULL);
3837 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3838
3839 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3840 CHECK(gDescriptorInfo.ctorId != NULL);
3841
3842 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3843 CHECK(gDescriptorInfo.nameId != NULL);
3844
3845 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3846 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003847
3848 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3849 CHECK(clazz.get() != NULL);
3850 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3851
3852 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3853 CHECK(gBufferInfo.ctorId != NULL);
3854
3855 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3856 CHECK(gBufferInfo.setId != NULL);
Arun Johnson206270e2023-10-31 20:40:12 +00003857
3858 gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
3859 gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
3860 gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
3861 gFields.bufferInfoPresentationTimeUs =
3862 env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08003863}
3864
3865static void android_media_MediaCodec_native_setup(
3866 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003867 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003868 if (name == NULL) {
Ray Essickbd5fdaa2023-08-10 21:04:18 -05003869 jniThrowException(env, "java/lang/NullPointerException",
3870 "No codec name specified");
Andreas Huber88572f72012-02-21 11:47:18 -08003871 return;
3872 }
3873
3874 const char *tmp = env->GetStringUTFChars(name, NULL);
3875
3876 if (tmp == NULL) {
3877 return;
3878 }
3879
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003880 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003881
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003882 const status_t err = codec->initCheck();
3883 if (err == NAME_NOT_FOUND) {
3884 // fail and do not try again.
3885 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003886 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003887 env->ReleaseStringUTFChars(name, tmp);
3888 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003889 }
3890 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003891 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003892 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
Ronghua Wuc53ad692015-05-08 14:40:49 -07003893 env->ReleaseStringUTFChars(name, tmp);
3894 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003895 }
3896 if (err == PERMISSION_DENIED) {
3897 jniThrowException(env, "java/lang/SecurityException",
3898 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003899 err).c_str());
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003900 env->ReleaseStringUTFChars(name, tmp);
3901 return;
3902 }
3903 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003904 // believed possible to try again
3905 jniThrowException(env, "java/io/IOException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003906 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003907 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003908 return;
3909 }
3910
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003911 env->ReleaseStringUTFChars(name, tmp);
3912
Andreas Huberaba67132013-10-22 12:40:01 -07003913 codec->registerSelf();
3914
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003915 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003916}
3917
3918static void android_media_MediaCodec_native_finalize(
3919 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003920 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003921}
3922
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003923// MediaCodec.LinearBlock
3924
3925static jobject android_media_MediaCodec_LinearBlock_native_map(
3926 JNIEnv *env, jobject thiz) {
3927 JMediaCodecLinearBlock *context =
3928 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3929 if (context->mBuffer) {
3930 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3931 if (!context->mReadonlyMapping) {
3932 const C2BufferData data = buffer->data();
3933 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003934 throwExceptionAsNecessary(
3935 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3936 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003937 return nullptr;
3938 }
3939 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003940 throwExceptionAsNecessary(
3941 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3942 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003943 return nullptr;
3944 }
3945 C2ConstLinearBlock block = data.linearBlocks().front();
3946 context->mReadonlyMapping =
3947 std::make_shared<C2ReadView>(block.map().get());
3948 }
3949 return CreateByteBuffer(
3950 env,
3951 context->mReadonlyMapping->data(), // base
3952 context->mReadonlyMapping->capacity(), // capacity
3953 0u, // offset
3954 context->mReadonlyMapping->capacity(), // size
3955 true, // readOnly
3956 true /* clearBuffer */);
3957 } else if (context->mBlock) {
3958 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3959 if (!context->mReadWriteMapping) {
3960 context->mReadWriteMapping =
3961 std::make_shared<C2WriteView>(block->map().get());
3962 }
3963 return CreateByteBuffer(
3964 env,
3965 context->mReadWriteMapping->base(),
3966 context->mReadWriteMapping->capacity(),
3967 context->mReadWriteMapping->offset(),
3968 context->mReadWriteMapping->size(),
3969 false, // readOnly
3970 true /* clearBuffer */);
3971 } else if (context->mLegacyBuffer) {
3972 return CreateByteBuffer(
3973 env,
3974 context->mLegacyBuffer->base(),
3975 context->mLegacyBuffer->capacity(),
3976 context->mLegacyBuffer->offset(),
3977 context->mLegacyBuffer->size(),
3978 true, // readOnly
3979 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003980 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003981 return CreateByteBuffer(
3982 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003983 context->mMemory->unsecurePointer(),
3984 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003985 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003986 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003987 false, // readOnly
3988 true /* clearBuffer */);
3989 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003990 throwExceptionAsNecessary(
3991 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3992 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003993 return nullptr;
3994}
3995
3996static void android_media_MediaCodec_LinearBlock_native_recycle(
3997 JNIEnv *env, jobject thiz) {
3998 JMediaCodecLinearBlock *context =
3999 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07004000 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004001 delete context;
4002}
4003
4004static void PopulateNamesVector(
4005 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
4006 jsize length = env->GetArrayLength(codecNames);
4007 for (jsize i = 0; i < length; ++i) {
4008 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
4009 if (jstr == nullptr) {
4010 // null entries are ignored
4011 continue;
4012 }
4013 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
4014 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08004015 throwExceptionAsNecessary(
4016 env, BAD_VALUE, ACTION_CODE_FATAL,
4017 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004018 return;
4019 }
4020 names->emplace_back(cstr);
4021 env->ReleaseStringUTFChars(jstr, cstr);
4022 }
4023}
4024
4025static void android_media_MediaCodec_LinearBlock_native_obtain(
4026 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
4027 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
4028 std::vector<std::string> names;
4029 PopulateNamesVector(env, codecNames, &names);
4030 bool hasSecure = false;
4031 bool hasNonSecure = false;
4032 for (const std::string &name : names) {
4033 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4034 hasSecure = true;
4035 } else {
4036 hasNonSecure = true;
4037 }
4038 }
Wonsik Kim8569a662022-05-24 14:16:44 -07004039 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
4040 jniThrowException(env, "java/io/IOException", nullptr);
4041 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004042 }
4043 env->CallVoidMethod(
4044 thiz,
4045 gLinearBlockInfo.setInternalStateId,
4046 (jlong)context.release(),
4047 true /* isMappable */);
4048}
4049
4050static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07004051 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004052 std::vector<std::string> names;
4053 PopulateNamesVector(env, codecNames, &names);
4054 bool isCompatible = false;
4055 bool hasSecure = false;
4056 bool hasNonSecure = false;
4057 for (const std::string &name : names) {
4058 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4059 hasSecure = true;
4060 } else {
4061 hasNonSecure = true;
4062 }
4063 }
4064 if (hasSecure && hasNonSecure) {
4065 return false;
4066 }
4067 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
4068 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08004069 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004070 throwExceptionAsNecessary(env, err);
4071 }
4072 return isCompatible;
4073}
4074
Daniel Micay76f6a862015-09-19 17:31:01 -04004075static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07004076 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08004077
Lajos Molnar1e6e8012014-07-15 16:07:13 -07004078 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
4079
Chong Zhang8034d602015-04-28 13:38:48 -07004080 { "native_releasePersistentInputSurface",
4081 "(Landroid/view/Surface;)V",
4082 (void *)android_media_MediaCodec_releasePersistentInputSurface},
4083
4084 { "native_createPersistentInputSurface",
4085 "()Landroid/media/MediaCodec$PersistentSurface;",
4086 (void *)android_media_MediaCodec_createPersistentInputSurface },
4087
Chong Zhang9560ddb2015-05-13 10:25:29 -07004088 { "native_setInputSurface", "(Landroid/view/Surface;)V",
4089 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07004090
Guillaume Chelfic072caf2021-02-03 16:18:26 +01004091 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
4092 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
4093
Lajos Molnard8578572015-06-05 20:17:33 -07004094 { "native_enableOnFrameRenderedListener", "(Z)V",
4095 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
4096
Chong Zhang8d5e5562014-07-08 18:49:21 -07004097 { "native_setCallback",
4098 "(Landroid/media/MediaCodec$Callback;)V",
4099 (void *)android_media_MediaCodec_native_setCallback },
4100
Andreas Huber88572f72012-02-21 11:47:18 -08004101 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07004102 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07004103 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004104 (void *)android_media_MediaCodec_native_configure },
4105
Lajos Molnar5e02ba92015-05-01 15:59:35 -07004106 { "native_setSurface",
4107 "(Landroid/view/Surface;)V",
4108 (void *)android_media_MediaCodec_native_setSurface },
4109
Andy McFadden2621e402013-02-19 07:29:21 -08004110 { "createInputSurface", "()Landroid/view/Surface;",
4111 (void *)android_media_MediaCodec_createInputSurface },
4112
Lajos Molnard4023112014-07-11 15:12:59 -07004113 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07004114 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07004115 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08004116
Lajos Molnard4023112014-07-11 15:12:59 -07004117 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004118 (void *)android_media_MediaCodec_queueInputBuffer },
4119
Arun Johnson206270e2023-10-31 20:40:12 +00004120 { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
4121 (void *)android_media_MediaCodec_queueInputBuffers },
4122
Lajos Molnard4023112014-07-11 15:12:59 -07004123 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07004124 (void *)android_media_MediaCodec_queueSecureInputBuffer },
4125
Arun Johnson4ca49092024-02-01 19:07:15 +00004126 { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
4127 (void *)android_media_MediaCodec_queueSecureInputBuffers },
4128
Wonsik Kim637afb22020-02-25 14:27:29 -08004129 { "native_mapHardwareBuffer",
4130 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
4131 (void *)android_media_MediaCodec_mapHardwareBuffer },
4132
4133 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
4134
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004135 { "native_queueLinearBlock",
Arun Johnson677a8812024-02-06 12:32:54 +00004136 "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
Arun Johnson8d6a41a2024-01-10 21:14:14 +00004137 "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004138 (void *)android_media_MediaCodec_native_queueLinearBlock },
4139
Wonsik Kim637afb22020-02-25 14:27:29 -08004140 { "native_queueHardwareBuffer",
4141 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
4142 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004143
4144 { "native_getOutputFrame",
4145 "(Landroid/media/MediaCodec$OutputFrame;I)V",
4146 (void *)android_media_MediaCodec_native_getOutputFrame },
4147
Lajos Molnard4023112014-07-11 15:12:59 -07004148 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08004149 (void *)android_media_MediaCodec_dequeueInputBuffer },
4150
Lajos Molnard4023112014-07-11 15:12:59 -07004151 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08004152 (void *)android_media_MediaCodec_dequeueOutputBuffer },
4153
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07004154 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004155 (void *)android_media_MediaCodec_releaseOutputBuffer },
4156
Andy McFadden2621e402013-02-19 07:29:21 -08004157 { "signalEndOfInputStream", "()V",
4158 (void *)android_media_MediaCodec_signalEndOfInputStream },
4159
Lajos Molnard4023112014-07-11 15:12:59 -07004160 { "getFormatNative", "(Z)Ljava/util/Map;",
4161 (void *)android_media_MediaCodec_getFormatNative },
4162
4163 { "getOutputFormatNative", "(I)Ljava/util/Map;",
4164 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08004165
4166 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
4167 (void *)android_media_MediaCodec_getBuffers },
4168
Lajos Molnard4023112014-07-11 15:12:59 -07004169 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
4170 (void *)android_media_MediaCodec_getBuffer },
4171
4172 { "getImage", "(ZI)Landroid/media/Image;",
4173 (void *)android_media_MediaCodec_getImage },
4174
Lajos Molnard2a7f472018-11-15 12:49:20 -08004175 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03004176 (void *)android_media_MediaCodec_getName },
4177
Chong Zhanga0b72a62018-02-28 18:46:26 -08004178 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
4179 (void *)android_media_MediaCodec_getOwnCodecInfo },
4180
Ray Essick10353e32017-04-14 10:22:55 -07004181 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08004182 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08004183
Andreas Huber226065b2013-08-12 10:14:11 -07004184 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
4185 (void *)android_media_MediaCodec_setParameters },
4186
Andreas Huberb12a5392012-04-30 14:18:33 -07004187 { "setVideoScalingMode", "(I)V",
4188 (void *)android_media_MediaCodec_setVideoScalingMode },
4189
ybai5e053202018-11-01 13:02:15 +08004190 { "native_setAudioPresentation", "(II)V",
4191 (void *)android_media_MediaCodec_setAudioPresentation },
4192
Wonsik Kim8798c8c2021-03-18 21:38:57 -07004193 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
4194 (void *)android_media_MediaCodec_getSupportedVendorParameters },
4195
4196 { "native_getParameterDescriptor",
4197 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
4198 (void *)android_media_MediaCodec_getParameterDescriptor },
4199
4200 { "native_subscribeToVendorParameters",
4201 "(Ljava/util/List;)V",
4202 (void *)android_media_MediaCodec_subscribeToVendorParameters},
4203
4204 { "native_unsubscribeFromVendorParameters",
4205 "(Ljava/util/List;)V",
4206 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
4207
Andreas Huber88572f72012-02-21 11:47:18 -08004208 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
4209
Brian Lindahl6ceeed42022-02-01 11:10:30 +01004210 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004211 (void *)android_media_MediaCodec_native_setup },
4212
4213 { "native_finalize", "()V",
4214 (void *)android_media_MediaCodec_native_finalize },
4215};
4216
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004217static const JNINativeMethod gLinearBlockMethods[] = {
4218 { "native_map", "()Ljava/nio/ByteBuffer;",
4219 (void *)android_media_MediaCodec_LinearBlock_native_map },
4220
4221 { "native_recycle", "()V",
4222 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
4223
4224 { "native_obtain", "(I[Ljava/lang/String;)V",
4225 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
4226
4227 { "native_checkCompatible", "([Ljava/lang/String;)Z",
4228 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
4229};
4230
Andreas Huber88572f72012-02-21 11:47:18 -08004231int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004232 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08004233 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004234 if (result != JNI_OK) {
4235 return result;
4236 }
4237 result = AndroidRuntime::registerNativeMethods(env,
4238 "android/media/MediaCodec$LinearBlock",
4239 gLinearBlockMethods,
4240 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004241 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08004242}