blob: 8cdd59e51ffed6f9ab72ce455e39831b945106be [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
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800461status_t JMediaCodec::queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000462 size_t index, const std::shared_ptr<C2Buffer> &buffer,
463 const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
464 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800465 return mCodec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000466 index, buffer, auInfo, tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800467}
468
469status_t JMediaCodec::queueEncryptedLinearBlock(
470 size_t index,
471 const sp<hardware::HidlMemory> &buffer,
472 size_t offset,
473 const CryptoPlugin::SubSample *subSamples,
474 size_t numSubSamples,
475 const uint8_t key[16],
476 const uint8_t iv[16],
477 CryptoPlugin::Mode mode,
478 const CryptoPlugin::Pattern &pattern,
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000479 const sp<RefBase> &infos,
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800480 const sp<AMessage> &tunings,
481 AString *errorDetailMsg) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000482 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800483 return mCodec->queueEncryptedBuffer(
484 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000485 auInfo, tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800486}
487
Andreas Huber88572f72012-02-21 11:47:18 -0800488status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700489 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800490}
491
492status_t JMediaCodec::dequeueOutputBuffer(
493 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
494 size_t size, offset;
495 int64_t timeUs;
496 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700497 status_t err = mCodec->dequeueOutputBuffer(
498 index, &offset, &size, &timeUs, &flags, timeoutUs);
499
Andreas Huberaba67132013-10-22 12:40:01 -0700500 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800501 return err;
502 }
503
Pavel Laboviche53421b2022-11-01 03:53:27 +0000504 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800505
506 return OK;
507}
508
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700509status_t JMediaCodec::releaseOutputBuffer(
510 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
511 if (updatePTS) {
512 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
513 }
Andreas Huber88572f72012-02-21 11:47:18 -0800514 return render
515 ? mCodec->renderOutputBufferAndRelease(index)
516 : mCodec->releaseOutputBuffer(index);
517}
518
Andy McFadden2621e402013-02-19 07:29:21 -0800519status_t JMediaCodec::signalEndOfInputStream() {
520 return mCodec->signalEndOfInputStream();
521}
522
Lajos Molnard4023112014-07-11 15:12:59 -0700523status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800524 sp<AMessage> msg;
525 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700526 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
527 if (err != OK) {
528 return err;
529 }
530
531 return ConvertMessageToMap(env, msg, format);
532}
533
534status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
535 sp<AMessage> msg;
536 status_t err;
537 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800538 return err;
539 }
540
541 return ConvertMessageToMap(env, msg, format);
542}
543
544status_t JMediaCodec::getBuffers(
545 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900546 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800547
548 status_t err =
549 input
550 ? mCodec->getInputBuffers(&buffers)
551 : mCodec->getOutputBuffers(&buffers);
552
553 if (err != OK) {
554 return err;
555 }
556
Andreas Huber88572f72012-02-21 11:47:18 -0800557 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800558 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800559 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800560 return NO_MEMORY;
561 }
Andreas Huber88572f72012-02-21 11:47:18 -0800562
563 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900564 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800565
Lajos Molnar7de28d32014-07-25 07:51:02 -0700566 jobject byteBuffer = NULL;
567 err = createByteBufferFromABuffer(
568 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
569 if (err != OK) {
570 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800571 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700572 if (byteBuffer != NULL) {
573 env->SetObjectArrayElement(
574 *bufArray, i, byteBuffer);
575
Lajos Molnard4023112014-07-11 15:12:59 -0700576 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700577 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700578 }
Andreas Huber88572f72012-02-21 11:47:18 -0800579 }
580
Lajos Molnar7de28d32014-07-25 07:51:02 -0700581 return OK;
582}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700583
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800584template <typename T>
585static jobject CreateByteBuffer(
586 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
587 bool readOnly, bool clearBuffer) {
588 jobject byteBuffer =
589 env->NewDirectByteBuffer(
590 const_cast<typename std::remove_const<T>::type *>(base),
591 capacity);
592 if (readOnly && byteBuffer != NULL) {
593 jobject readOnlyBuffer = env->CallObjectMethod(
594 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
595 env->DeleteLocalRef(byteBuffer);
596 byteBuffer = readOnlyBuffer;
597 }
598 if (byteBuffer == NULL) {
599 return nullptr;
600 }
601 jobject me = env->CallObjectMethod(
602 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
603 env->DeleteLocalRef(me);
604 me = env->CallObjectMethod(
605 byteBuffer, gByteBufferInfo.limitId,
606 clearBuffer ? capacity : offset + size);
607 env->DeleteLocalRef(me);
608 me = env->CallObjectMethod(
609 byteBuffer, gByteBufferInfo.positionId,
610 clearBuffer ? 0 : offset);
611 env->DeleteLocalRef(me);
612 me = NULL;
613 return byteBuffer;
614}
615
616
Lajos Molnar7de28d32014-07-25 07:51:02 -0700617// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900618template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700619status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900620 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700621 jobject *buf) const {
622 // if this is an ABuffer that doesn't actually hold any accessible memory,
623 // use a null ByteBuffer
624 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700625
626 if (buffer == NULL) {
627 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
628 return OK;
629 }
630
Lajos Molnar7de28d32014-07-25 07:51:02 -0700631 if (buffer->base() == NULL) {
632 return OK;
633 }
634
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800635 jobject byteBuffer = CreateByteBuffer(
636 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
637 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700638
639 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800640 return OK;
641}
642
Lajos Molnard4023112014-07-11 15:12:59 -0700643status_t JMediaCodec::getBuffer(
644 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900645 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700646
647 status_t err =
648 input
649 ? mCodec->getInputBuffer(index, &buffer)
650 : mCodec->getOutputBuffer(index, &buffer);
651
652 if (err != OK) {
653 return err;
654 }
655
Lajos Molnar7de28d32014-07-25 07:51:02 -0700656 return createByteBufferFromABuffer(
657 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700658}
659
660status_t JMediaCodec::getImage(
661 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900662 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700663
664 status_t err =
665 input
666 ? mCodec->getInputBuffer(index, &buffer)
667 : mCodec->getOutputBuffer(index, &buffer);
668
669 if (err != OK) {
670 return err;
671 }
672
673 // if this is an ABuffer that doesn't actually hold any accessible memory,
674 // use a null ByteBuffer
675 *buf = NULL;
676 if (buffer->base() == NULL) {
677 return OK;
678 }
679
680 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700681 sp<ABuffer> imageData;
682 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700683 return OK;
684 }
685
Lajos Molnar7de28d32014-07-25 07:51:02 -0700686 int64_t timestamp = 0;
687 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
688 timestamp *= 1000; // adjust to ns
689 }
690
691 jobject byteBuffer = NULL;
692 err = createByteBufferFromABuffer(
693 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
694 if (err != OK) {
695 return OK;
696 }
697
698 jobject infoBuffer = NULL;
699 err = createByteBufferFromABuffer(
700 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
701 if (err != OK) {
702 env->DeleteLocalRef(byteBuffer);
703 byteBuffer = NULL;
704 return OK;
705 }
706
707 jobject cropRect = NULL;
708 int32_t left, top, right, bottom;
709 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
710 ScopedLocalRef<jclass> rectClazz(
711 env, env->FindClass("android/graphics/Rect"));
712 CHECK(rectClazz.get() != NULL);
713
714 jmethodID rectConstructID = env->GetMethodID(
715 rectClazz.get(), "<init>", "(IIII)V");
716
717 cropRect = env->NewObject(
718 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
719 }
720
721 ScopedLocalRef<jclass> imageClazz(
722 env, env->FindClass("android/media/MediaCodec$MediaImage"));
723 CHECK(imageClazz.get() != NULL);
724
725 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
726 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
727
728 *buf = env->NewObject(imageClazz.get(), imageConstructID,
729 byteBuffer, infoBuffer,
730 (jboolean)!input /* readOnly */,
731 (jlong)timestamp,
732 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
733
734 // if MediaImage creation fails, return null
735 if (env->ExceptionCheck()) {
736 env->ExceptionDescribe();
737 env->ExceptionClear();
738 *buf = NULL;
739 }
740
741 if (cropRect != NULL) {
742 env->DeleteLocalRef(cropRect);
743 cropRect = NULL;
744 }
745
746 env->DeleteLocalRef(byteBuffer);
747 byteBuffer = NULL;
748
749 env->DeleteLocalRef(infoBuffer);
750 infoBuffer = NULL;
751
Lajos Molnard4023112014-07-11 15:12:59 -0700752 return OK;
753}
754
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000755void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
756 if (!bufInfos) {
757 return;
758 }
759 std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
760 if (infos.empty()) {
761 return;
762 }
763 ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
764 gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
765 jint offset = 0;
766 std::vector<jobject> jObjectInfos;
767 for (int i = 0 ; i < infos.size(); i++) {
768 jobject bufferInfo = env->NewObject(
769 gBufferInfo.clazz, gBufferInfo.ctorId);
770 if (bufferInfo != NULL) {
771 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
772 offset,
773 (jint)(infos)[i].mSize,
774 (infos)[i].mTimestamp,
775 (infos)[i].mFlags);
776 (void)env->CallBooleanMethod(
777 dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
778 offset += (infos)[i].mSize;
779 jObjectInfos.push_back(bufferInfo);
780 }
781 }
782 env->SetObjectField(
783 frame,
784 gFields.outputFramebufferInfosID,
785 dequeObj.get());
786 for (int i = 0; i < jObjectInfos.size(); i++) {
787 env->DeleteLocalRef(jObjectInfos[i]);
788 }
789}
790
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800791status_t JMediaCodec::getOutputFrame(
792 JNIEnv *env, jobject frame, size_t index) const {
793 sp<MediaCodecBuffer> buffer;
794
795 status_t err = mCodec->getOutputBuffer(index, &buffer);
796 if (err != OK) {
797 return err;
798 }
799
800 if (buffer->size() > 0) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000801 sp<RefBase> obj;
802 sp<BufferInfosWrapper> bufInfos;
803 if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
804 bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
805 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800806 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800807 if (c2Buffer) {
808 switch (c2Buffer->data().type()) {
809 case C2BufferData::LINEAR: {
810 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700811 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800812 context->mBuffer = c2Buffer;
813 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
814 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800815 env->CallVoidMethod(
816 linearBlock.get(),
817 gLinearBlockInfo.setInternalStateId,
818 (jlong)context.release(),
819 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800820 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000821 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800822 break;
823 }
824 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800825 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
826 uint32_t width, height, format, stride, igbp_slot, generation;
827 uint64_t usage, igbp_id;
828 _UnwrapNativeCodec2GrallocMetadata(
829 c2Handle, &width, &height, &format, &usage, &stride, &generation,
830 &igbp_id, &igbp_slot);
831 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
832 GraphicBuffer* graphicBuffer = new GraphicBuffer(
833 grallocHandle, GraphicBuffer::CLONE_HANDLE,
834 width, height, format, 1, usage, stride);
835 ScopedLocalRef<jobject> hardwareBuffer{
836 env,
837 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
838 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
839 env->SetObjectField(
840 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800841 break;
842 }
843 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
844 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
845 case C2BufferData::INVALID: [[fallthrough]];
846 default:
847 return INVALID_OPERATION;
848 }
849 } else {
850 if (!mGraphicOutput) {
851 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700852 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800853 context->mLegacyBuffer = buffer;
854 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
855 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800856 env->CallVoidMethod(
857 linearBlock.get(),
858 gLinearBlockInfo.setInternalStateId,
859 (jlong)context.release(),
860 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800861 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000862 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800863 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800864 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800865 }
866 }
867 }
868
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700869 jobject formatMap;
870 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800871 if (err != OK) {
872 return err;
873 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700874 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
875 ScopedLocalRef<jobject> format{env, env->NewObject(
876 mediaFormatClass.get(),
877 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
878 formatMap)};
879 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
880 env->DeleteLocalRef(formatMap);
881 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800882
883 sp<RefBase> obj;
884 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
885 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
886 (decltype(changedKeys.get()))obj.get()};
887 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
888 frame, gFields.outputFrameChangedKeysID)};
889 for (const std::string &key : changedKeys->value) {
890 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
891 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
892 }
893 }
894 return OK;
895}
896
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300897status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
898 AString name;
899
900 status_t err = mCodec->getName(&name);
901
902 if (err != OK) {
903 return err;
904 }
905
906 *nameStr = env->NewStringUTF(name.c_str());
907
908 return OK;
909}
910
Chong Zhanga0b72a62018-02-28 18:46:26 -0800911static jobject getCodecCapabilitiesObject(
912 JNIEnv *env, const char *mime, bool isEncoder,
913 const sp<MediaCodecInfo::Capabilities> &capabilities) {
914 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
915 Vector<uint32_t> colorFormats;
916
917 sp<AMessage> defaultFormat = new AMessage();
918 defaultFormat->setString("mime", mime);
919
920 capabilities->getSupportedColorFormats(&colorFormats);
921 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800922 sp<AMessage> details = capabilities->getDetails();
923
924 jobject defaultFormatObj = NULL;
925 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
926 return NULL;
927 }
928 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
929
930 jobject detailsObj = NULL;
931 if (ConvertMessageToMap(env, details, &detailsObj)) {
932 return NULL;
933 }
934 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
935
936 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
937 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
938
939 for (size_t i = 0; i < profileLevels.size(); ++i) {
940 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
941
942 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
943 gCodecInfo.profileLevelClazz));
944
945 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
946 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
947
948 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
949 }
950
951 ScopedLocalRef<jintArray> colorFormatsArray(
952 env, env->NewIntArray(colorFormats.size()));
953 for (size_t i = 0; i < colorFormats.size(); ++i) {
954 jint val = colorFormats.itemAt(i);
955 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
956 }
957
958 return env->NewObject(
959 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800960 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800961 defaultFormatRef.get(), detailsRef.get());
962}
963
964status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
965 sp<MediaCodecInfo> codecInfo;
966
967 status_t err = mCodec->getCodecInfo(&codecInfo);
968
969 if (err != OK) {
970 return err;
971 }
972
973 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800974 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800975
Lajos Molnard2a7f472018-11-15 12:49:20 -0800976 ScopedLocalRef<jstring> canonicalNameObject(env,
977 env->NewStringUTF(codecInfo->getCodecName()));
978
979 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800980 bool isEncoder = codecInfo->isEncoder();
981
Lajos Molnard2a7f472018-11-15 12:49:20 -0800982 Vector<AString> mediaTypes;
983 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800984
985 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800986 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800987
Lajos Molnard2a7f472018-11-15 12:49:20 -0800988 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800989 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800990 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800991
992 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800993 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800994
995 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
996 }
997
998 ScopedLocalRef<jclass> codecInfoClazz(env,
999 env->FindClass("android/media/MediaCodecInfo"));
1000 CHECK(codecInfoClazz.get() != NULL);
1001
1002 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -08001003 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -08001004
1005 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -08001006 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -08001007
1008 return OK;
1009}
1010
Ray Essick81fbc5b2019-12-07 06:24:59 -08001011status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
1012 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -07001013 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -07001014 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -08001015 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -08001016 return status;
1017}
1018
Andreas Huber226065b2013-08-12 10:14:11 -07001019status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
1020 return mCodec->setParameters(msg);
1021}
1022
Andreas Huberb12a5392012-04-30 14:18:33 -07001023void JMediaCodec::setVideoScalingMode(int mode) {
1024 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -07001025 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -07001026 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -07001027 // also signal via param for components that queue to IGBP
1028 sp<AMessage> msg = new AMessage;
1029 msg->setInt32("android._video-scaling", mode);
1030 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -07001031 }
1032}
1033
ybai5e053202018-11-01 13:02:15 +08001034void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
1035 sp<AMessage> msg = new AMessage;
1036 msg->setInt32("audio-presentation-presentation-id", presentationId);
1037 msg->setInt32("audio-presentation-program-id", programId);
1038 (void)mCodec->setParameters(msg);
1039}
1040
Wonsik Kim8798c8c2021-03-18 21:38:57 -07001041status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
1042 std::vector<std::string> names;
1043 status_t status = mCodec->querySupportedVendorParameters(&names);
1044 if (status != OK) {
1045 return status;
1046 }
1047 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
1048 for (const std::string &name : names) {
1049 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
1050 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
1051 }
1052 return OK;
1053}
1054
1055status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
1056 const char *tmp = env->GetStringUTFChars(name, nullptr);
1057 CodecParameterDescriptor desc;
1058 status_t status = mCodec->describeParameter(tmp, &desc);
1059 env->ReleaseStringUTFChars(name, tmp);
1060 if (status != OK) {
1061 return status;
1062 }
1063 jint type = TYPE_NULL;
1064 switch (desc.type) {
1065 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
1066 case AMessage::kTypeSize:
1067 case AMessage::kTypeInt64: type = TYPE_LONG; break;
1068 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
1069 case AMessage::kTypeString: type = TYPE_STRING; break;
1070 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
1071 default: type = TYPE_NULL; break;
1072 }
1073 if (type == TYPE_NULL) {
1074 return BAD_VALUE;
1075 }
1076 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1077 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1078 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1079 return OK;
1080}
1081
1082static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1083 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1084 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1085 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1086 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1087 jobject it = env->CallObjectMethod(
1088 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1089 while (env->CallBooleanMethod(it, hasNextID)) {
1090 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1091 const char *tmp = env->GetStringUTFChars(name, nullptr);
1092 vec->push_back(tmp);
1093 env->ReleaseStringUTFChars(name, tmp);
1094 }
1095}
1096
1097status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1098 std::vector<std::string> names;
1099 BuildVectorFromList(env, namesObj, &names);
1100 return mCodec->subscribeToVendorParameters(names);
1101}
1102
1103status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1104 std::vector<std::string> names;
1105 BuildVectorFromList(env, namesObj, &names);
1106 return mCodec->unsubscribeFromVendorParameters(names);
1107}
1108
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001109static jthrowable createCodecException(
1110 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1111 ScopedLocalRef<jclass> clazz(
1112 env, env->FindClass("android/media/MediaCodec$CodecException"));
1113 CHECK(clazz.get() != NULL);
1114
Ronghua Wuc53ad692015-05-08 14:40:49 -07001115 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001116 CHECK(ctor != NULL);
1117
1118 ScopedLocalRef<jstring> msgObj(
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00001119 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001120
1121 // translate action code to Java equivalent
1122 switch (actionCode) {
1123 case ACTION_CODE_TRANSIENT:
1124 actionCode = gCodecActionCodes.codecActionTransient;
1125 break;
1126 case ACTION_CODE_RECOVERABLE:
1127 actionCode = gCodecActionCodes.codecActionRecoverable;
1128 break;
1129 default:
1130 actionCode = 0; // everything else is fatal
1131 break;
1132 }
1133
Ronghua Wuc53ad692015-05-08 14:40:49 -07001134 /* translate OS errors to Java API CodecException errorCodes */
1135 switch (err) {
1136 case NO_MEMORY:
1137 err = gCodecErrorCodes.errorInsufficientResource;
1138 break;
1139 case DEAD_OBJECT:
1140 err = gCodecErrorCodes.errorReclaimed;
1141 break;
1142 default: /* Other error codes go out as is. */
1143 break;
1144 }
1145
1146 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001147}
1148
Arun Johnson5a4c7332022-12-17 00:47:06 +00001149static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1150 const sp<AMessage> & msg) {
1151 if(msg == nullptr || obj == nullptr) {
1152 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1153 return;
1154 }
1155 size_t numSubSamples = 0;
1156 sp<ABuffer> subSamplesBuffer;
1157 sp<ABuffer> keyBuffer;
1158 sp<ABuffer> ivBuffer;
1159 CryptoPlugin::Mode mode;
1160 CryptoPlugin::Pattern pattern;
1161 CHECK(msg->findInt32("mode", (int*)&mode));
1162 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1163 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1164 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1165 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1166 CHECK(msg->findBuffer("iv", &ivBuffer));
1167 CHECK(msg->findBuffer("key", &keyBuffer));
1168
1169 // subsamples
1170 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1171 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1172 jboolean isCopy;
1173 jint *dstEncryptedSamples =
1174 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1175 jint * dstClearSamples =
1176 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1177
1178 CryptoPlugin::SubSample * samplesArray =
1179 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1180
1181 for(int i = 0 ; i < numSubSamples ; i++) {
1182 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1183 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1184 }
1185 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1186 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1187 // key and iv
1188 jbyteArray keyArray = NULL;
1189 jbyteArray ivArray = NULL;
1190 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1191 keyArray = env->NewByteArray(keyBuffer->size());
1192 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1193 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1194 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1195 }
1196 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1197 ivArray = env->NewByteArray(ivBuffer->size());
1198 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1199 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1200 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1201 }
1202 // set samples, key and iv
1203 env->CallVoidMethod(
1204 obj,
1205 gFields.cryptoInfoSetID,
1206 (jint)numSubSamples,
1207 samplesOfClearDataArr.get(),
1208 samplesOfEncryptedDataArr.get(),
1209 keyArray,
1210 ivArray,
1211 mode);
1212 if (keyArray != NULL) {
1213 env->DeleteLocalRef(keyArray);
1214 }
1215 if (ivArray != NULL) {
1216 env->DeleteLocalRef(ivArray);
1217 }
1218 // set pattern
1219 env->CallVoidMethod(
1220 obj,
1221 gFields.cryptoInfoSetPatternID,
1222 pattern.mEncryptBlocks,
1223 pattern.mSkipBlocks);
1224}
1225
1226static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1227 switch(err) {
1228 case ERROR_DRM_NO_LICENSE:
1229 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1230 defaultMsg = "Crypto key not available";
1231 break;
1232 case ERROR_DRM_LICENSE_EXPIRED:
1233 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1234 defaultMsg = "License expired";
1235 break;
1236 case ERROR_DRM_RESOURCE_BUSY:
1237 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1238 defaultMsg = "Resource busy or unavailable";
1239 break;
1240 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1241 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1242 defaultMsg = "Required output protections are not active";
1243 break;
1244 case ERROR_DRM_SESSION_NOT_OPENED:
1245 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1246 defaultMsg = "Attempted to use a closed session";
1247 break;
1248 case ERROR_DRM_INSUFFICIENT_SECURITY:
1249 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1250 defaultMsg = "Required security level is not met";
1251 break;
1252 case ERROR_DRM_CANNOT_HANDLE:
1253 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1254 defaultMsg = "Operation not supported in this configuration";
1255 break;
1256 case ERROR_DRM_FRAME_TOO_LARGE:
1257 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1258 defaultMsg = "Decrytped frame exceeds size of output buffer";
1259 break;
1260 case ERROR_DRM_SESSION_LOST_STATE:
1261 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1262 defaultMsg = "Session state was lost, open a new session and retry";
1263 break;
1264 default: // Other negative DRM error codes go out best-effort.
1265 jerr = MediaErrorToJavaError(err);
1266 defaultMsg = StrCryptoError(err);
1267 break;
1268 }
1269}
1270static jthrowable createCryptoException(JNIEnv *env, status_t err,
1271 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1272 const sp<AMessage> & cryptoInfo = NULL) {
1273 jthrowable exception = nullptr;
1274 jmethodID constructID = nullptr;
1275 ScopedLocalRef<jobject> cryptoInfoObject(env);
1276 std::string defaultMsg = "Unknown Error";
1277 jint jerr = 0;
1278 // Get a class ref for CryptoException
1279 ScopedLocalRef<jclass> clazz(
1280 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1281 CHECK(clazz.get() != NULL);
1282
1283 // Get constructor ref for CryptoException
1284 constructID = env->GetMethodID(clazz.get(), "<init>",
1285 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1286 CHECK(constructID != NULL);
1287
1288 // create detailed message for exception
1289 CryptoErrorToJavaError(err, jerr, defaultMsg);
1290 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1291 DrmStatus dStatus(err, originalMsg.c_str());
1292 std::string detailedMsg(
1293 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1294 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1295
1296 if (cryptoInfo != nullptr) {
1297 // Class ref for CryptoInfo
1298 ScopedLocalRef<jclass> clazzCryptoInfo(
1299 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1300 CHECK(clazzCryptoInfo.get() != NULL);
1301
1302 // Constructor reference for CryptoInfo
1303 jmethodID constructCryptoInfo =
1304 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1305 CHECK(constructCryptoInfo != NULL);
1306
1307 // Create CryptoInfo jobject
1308 cryptoInfoObject.reset(
1309 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1310 CHECK(cryptoInfoObject.get() != NULL);
1311
1312 // Translate AMesage to CryptoInfo
1313 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1314 }
1315
1316 exception = (jthrowable)env->NewObject(
1317 clazz.get(), constructID, msgObj, jerr,
1318 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1319 cryptoInfoObject.get());
1320
1321 return exception;
1322}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001323void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1324 int32_t arg1, arg2 = 0;
1325 jobject obj = NULL;
Arun Johnson206270e2023-10-31 20:40:12 +00001326 std::vector<jobject> jObjectInfos;
Chong Zhang8d5e5562014-07-08 18:49:21 -07001327 CHECK(msg->findInt32("callbackID", &arg1));
1328 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001329
Chong Zhang8d5e5562014-07-08 18:49:21 -07001330 switch (arg1) {
1331 case MediaCodec::CB_INPUT_AVAILABLE:
1332 {
1333 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001334 break;
1335 }
1336
Chong Zhang8d5e5562014-07-08 18:49:21 -07001337 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001338 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001339 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001340
Chong Zhang8d5e5562014-07-08 18:49:21 -07001341 size_t size, offset;
1342 int64_t timeUs;
1343 uint32_t flags;
1344 CHECK(msg->findSize("size", &size));
1345 CHECK(msg->findSize("offset", &offset));
1346 CHECK(msg->findInt64("timeUs", &timeUs));
1347 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1348
Pavel Laboviche53421b2022-11-01 03:53:27 +00001349 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001350 if (obj == NULL) {
1351 if (env->ExceptionCheck()) {
1352 ALOGE("Could not create MediaCodec.BufferInfo.");
1353 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001354 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001355 jniThrowException(env, "java/lang/IllegalStateException",
1356 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001357 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001358 }
1359
Pavel Laboviche53421b2022-11-01 03:53:27 +00001360 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001361 break;
1362 }
1363
Arun Johnson206270e2023-10-31 20:40:12 +00001364 case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
1365 {
1366 sp<RefBase> spobj = nullptr;
1367 CHECK(msg->findInt32("index", &arg2));
1368 CHECK(msg->findObject("accessUnitInfo", &spobj));
1369 if (spobj != nullptr) {
1370 sp<BufferInfosWrapper> bufferInfoParamsWrapper {
1371 (BufferInfosWrapper *)spobj.get()};
1372 std::vector<AccessUnitInfo> &bufferInfoParams =
1373 bufferInfoParamsWrapper.get()->value;
1374 obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
1375 jint offset = 0;
1376 for (int i = 0 ; i < bufferInfoParams.size(); i++) {
1377 jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1378 if (bufferInfo != NULL) {
1379 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
1380 offset,
1381 (jint)(bufferInfoParams)[i].mSize,
1382 (bufferInfoParams)[i].mTimestamp,
1383 (bufferInfoParams)[i].mFlags);
1384 (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
1385 offset += (bufferInfoParams)[i].mSize;
1386 jObjectInfos.push_back(bufferInfo);
1387 }
1388 }
1389 }
1390 break;
1391 }
1392
Arun Johnson5a4c7332022-12-17 00:47:06 +00001393 case MediaCodec::CB_CRYPTO_ERROR:
1394 {
1395 int32_t err, actionCode;
1396 AString errorDetail;
1397 CHECK(msg->findInt32("err", &err));
1398 CHECK(msg->findInt32("actionCode",&actionCode));
1399 CHECK(msg->findString("errorDetail", &errorDetail));
1400 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1401 break;
1402 }
1403
Chong Zhang8d5e5562014-07-08 18:49:21 -07001404 case MediaCodec::CB_ERROR:
1405 {
Chong Zhang94686d12014-07-11 15:53:58 -07001406 int32_t err, actionCode;
1407 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001408 CHECK(msg->findInt32("actionCode", &actionCode));
1409
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001410 // note that DRM errors could conceivably alias into a CodecException
1411 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001412
1413 if (obj == NULL) {
1414 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001415 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001416 env->ExceptionClear();
1417 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001418 jniThrowException(env, "java/lang/IllegalStateException",
1419 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001420 return;
1421 }
Andreas Huberaba67132013-10-22 12:40:01 -07001422
1423 break;
1424 }
1425
Chong Zhang8d5e5562014-07-08 18:49:21 -07001426 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001427 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001428 sp<AMessage> format;
1429 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001430
Chong Zhang8d5e5562014-07-08 18:49:21 -07001431 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001432 jniThrowException(env, "java/lang/IllegalStateException",
1433 "Fatal error: failed to convert format "
1434 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001435 return;
1436 }
Andreas Huberaba67132013-10-22 12:40:01 -07001437
Andreas Huberaba67132013-10-22 12:40:01 -07001438 break;
1439 }
1440
1441 default:
1442 TRESPASS();
1443 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001444 env->CallVoidMethod(
1445 mObject,
1446 gFields.postEventFromNativeID,
1447 EVENT_CALLBACK,
1448 arg1,
1449 arg2,
1450 obj);
1451
Arun Johnson206270e2023-10-31 20:40:12 +00001452 for (int i = 0; i < jObjectInfos.size(); i++) {
1453 env->DeleteLocalRef(jObjectInfos[i]);
1454 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001455 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001456}
1457
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001458void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1459 int32_t arg1 = 0, arg2 = 0;
1460 jobject obj = NULL;
1461 JNIEnv *env = AndroidRuntime::getJNIEnv();
1462
1463 sp<AMessage> data;
1464 CHECK(msg->findMessage("data", &data));
1465
1466 status_t err = ConvertMessageToMap(env, data, &obj);
1467 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001468 jniThrowException(env, "java/lang/IllegalStateException",
1469 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001470 return;
1471 }
1472
1473 env->CallVoidMethod(
1474 mObject, gFields.postEventFromNativeID,
1475 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1476
1477 env->DeleteLocalRef(obj);
1478}
1479
Lajos Molnard8578572015-06-05 20:17:33 -07001480void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1481 int32_t arg1 = 0, arg2 = 0;
1482 jobject obj = NULL;
1483 JNIEnv *env = AndroidRuntime::getJNIEnv();
1484
1485 sp<AMessage> data;
1486 CHECK(msg->findMessage("data", &data));
1487
1488 status_t err = ConvertMessageToMap(env, data, &obj);
1489 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001490 jniThrowException(env, "java/lang/IllegalStateException",
1491 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001492 return;
1493 }
1494
1495 env->CallVoidMethod(
1496 mObject, gFields.postEventFromNativeID,
1497 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1498
1499 env->DeleteLocalRef(obj);
1500}
1501
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001502std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1503 if (mCodec == nullptr) {
1504 return msg ?: "";
1505 }
1506 std::string prefix = "";
1507 if (msg && msg[0] != '\0') {
1508 prefix.append(msg);
1509 prefix.append("\n");
1510 }
1511 return prefix + mCodec->getErrorLog().extract();
1512}
1513
Chong Zhang8d5e5562014-07-08 18:49:21 -07001514void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1515 switch (msg->what()) {
1516 case kWhatCallbackNotify:
1517 {
1518 handleCallback(msg);
1519 break;
1520 }
Lajos Molnard8578572015-06-05 20:17:33 -07001521 case kWhatFrameRendered:
1522 {
1523 handleFrameRenderedNotification(msg);
1524 break;
1525 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001526 case kWhatAsyncReleaseComplete:
1527 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001528 if (mLooper != NULL) {
1529 mLooper->unregisterHandler(id());
1530 mLooper->stop();
1531 mLooper.clear();
1532 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001533 break;
1534 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001535 case kWhatFirstTunnelFrameReady:
1536 {
1537 handleFirstTunnelFrameReadyNotification(msg);
1538 break;
1539 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001540 default:
1541 TRESPASS();
1542 }
Andreas Huberaba67132013-10-22 12:40:01 -07001543}
1544
Robert Shih631a80d2021-02-14 02:23:55 -08001545
Andreas Huber88572f72012-02-21 11:47:18 -08001546} // namespace android
1547
1548////////////////////////////////////////////////////////////////////////////////
1549
1550using namespace android;
1551
1552static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001553 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001554 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001555 if (codec != NULL) {
1556 codec->incStrong(thiz);
1557 }
1558 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001559 /* release MediaCodec and stop the looper now before decStrong.
1560 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1561 * its message handler, doing release() from there will deadlock
1562 * (as MediaCodec::release() post synchronous message to the same looper)
1563 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001564 if (release) {
1565 old->release();
1566 }
Andreas Huber88572f72012-02-21 11:47:18 -08001567 old->decStrong(thiz);
1568 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001569 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001570
1571 return old;
1572}
1573
1574static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001575 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1576 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1577 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001578}
1579
1580static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001581 // Clear Java native reference.
1582 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001583 if (codec != NULL) {
1584 codec->releaseAsync();
1585 }
Andreas Huber88572f72012-02-21 11:47:18 -08001586}
1587
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001588static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1589 jthrowable exception = createCodecException(env, err, actionCode, msg);
1590 env->Throw(exception);
1591}
1592
Robert Shih631a80d2021-02-14 02:23:55 -08001593static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1594 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001595 jthrowable exception = createCryptoException(
1596 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001597 env->Throw(exception);
1598}
1599
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001600static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1601 if (codec == NULL) {
1602 return msg ?: "codec is released already";
1603 }
1604 return codec->getExceptionMessage(msg);
1605}
1606
Andreas Huberbfc56f42012-04-19 12:47:07 -07001607static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001608 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001609 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1610 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001611 switch (err) {
1612 case OK:
1613 return 0;
1614
1615 case -EAGAIN:
1616 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1617
1618 case INFO_FORMAT_CHANGED:
1619 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1620
1621 case INFO_OUTPUT_BUFFERS_CHANGED:
1622 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1623
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001624 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001625 jniThrowException(
1626 env, "java/lang/IllegalStateException",
1627 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001628 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001629
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001630 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001631 jniThrowException(
1632 env, "java/lang/IllegalArgumentException",
1633 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001634 return 0;
1635
Andreas Huber88572f72012-02-21 11:47:18 -08001636 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001637 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001638 throwCryptoException(
1639 env, err,
1640 GetExceptionMessage(codec, msg).c_str(),
1641 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001642 return 0;
1643 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001644 throwCodecException(
1645 env, err, actionCode,
1646 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001647 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001648 }
Andreas Huber88572f72012-02-21 11:47:18 -08001649}
1650
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001651static jint throwExceptionAsNecessary(
1652 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1653 int32_t actionCode = ACTION_CODE_FATAL) {
1654 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1655}
1656
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001657static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1658 JNIEnv *env,
1659 jobject thiz,
1660 jboolean enabled) {
1661 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1662
1663 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001664 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001665 return;
1666 }
1667
1668 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1669
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001670 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001671}
1672
Lajos Molnard8578572015-06-05 20:17:33 -07001673static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1674 JNIEnv *env,
1675 jobject thiz,
1676 jboolean enabled) {
1677 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1678
Wonsik Kim24e53802020-05-08 20:04:26 -07001679 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001680 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001681 return;
1682 }
1683
1684 status_t err = codec->enableOnFrameRenderedListener(enabled);
1685
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001686 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001687}
1688
Chong Zhang8d5e5562014-07-08 18:49:21 -07001689static void android_media_MediaCodec_native_setCallback(
1690 JNIEnv *env,
1691 jobject thiz,
1692 jobject cb) {
1693 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1694
Wonsik Kim24e53802020-05-08 20:04:26 -07001695 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001696 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001697 return;
1698 }
1699
1700 status_t err = codec->setCallback(cb);
1701
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001702 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001703}
1704
Andreas Huber88572f72012-02-21 11:47:18 -08001705static void android_media_MediaCodec_native_configure(
1706 JNIEnv *env,
1707 jobject thiz,
1708 jobjectArray keys, jobjectArray values,
1709 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001710 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001711 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001712 jint flags) {
1713 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1714
Wonsik Kim24e53802020-05-08 20:04:26 -07001715 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001716 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001717 return;
1718 }
1719
1720 sp<AMessage> format;
1721 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1722
1723 if (err != OK) {
1724 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1725 return;
1726 }
1727
Andy McFaddend47f7d82012-12-18 09:48:38 -08001728 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001729 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001730 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001731 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001732 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001733 } else {
1734 jniThrowException(
1735 env,
1736 "java/lang/IllegalArgumentException",
1737 "The surface has been released");
1738 return;
1739 }
1740 }
1741
Andreas Huber8240d922012-04-04 14:06:32 -07001742 sp<ICrypto> crypto;
1743 if (jcrypto != NULL) {
1744 crypto = JCrypto::GetCrypto(env, jcrypto);
1745 }
1746
Chong Zhangd5927ae2017-01-03 11:07:18 -08001747 sp<IDescrambler> descrambler;
1748 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001749 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001750 }
1751
1752 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001753
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001754 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001755}
1756
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001757static void android_media_MediaCodec_native_setSurface(
1758 JNIEnv *env,
1759 jobject thiz,
1760 jobject jsurface) {
1761 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1762
Wonsik Kim24e53802020-05-08 20:04:26 -07001763 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001764 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001765 return;
1766 }
1767
1768 sp<IGraphicBufferProducer> bufferProducer;
1769 if (jsurface != NULL) {
1770 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1771 if (surface != NULL) {
1772 bufferProducer = surface->getIGraphicBufferProducer();
1773 } else {
1774 jniThrowException(
1775 env,
1776 "java/lang/IllegalArgumentException",
1777 "The surface has been released");
1778 return;
1779 }
1780 }
1781
1782 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001783 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001784}
1785
Chong Zhang8034d602015-04-28 13:38:48 -07001786sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1787 JNIEnv* env, jobject object) {
1788 sp<PersistentSurface> persistentSurface;
1789
1790 jobject lock = env->GetObjectField(
1791 object, gPersistentSurfaceClassInfo.mLock);
1792 if (env->MonitorEnter(lock) == JNI_OK) {
1793 persistentSurface = reinterpret_cast<PersistentSurface *>(
1794 env->GetLongField(object,
1795 gPersistentSurfaceClassInfo.mPersistentObject));
1796 env->MonitorExit(lock);
1797 }
1798 env->DeleteLocalRef(lock);
1799
1800 return persistentSurface;
1801}
1802
1803static jobject android_media_MediaCodec_createPersistentInputSurface(
1804 JNIEnv* env, jclass /* clazz */) {
1805 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1806 sp<PersistentSurface> persistentSurface =
1807 MediaCodec::CreatePersistentInputSurface();
1808
1809 if (persistentSurface == NULL) {
1810 return NULL;
1811 }
1812
1813 sp<Surface> surface = new Surface(
1814 persistentSurface->getBufferProducer(), true);
1815 if (surface == NULL) {
1816 return NULL;
1817 }
1818
1819 jobject object = env->NewObject(
1820 gPersistentSurfaceClassInfo.clazz,
1821 gPersistentSurfaceClassInfo.ctor);
1822
1823 if (object == NULL) {
1824 if (env->ExceptionCheck()) {
1825 ALOGE("Could not create PersistentSurface.");
1826 env->ExceptionClear();
1827 }
1828 return NULL;
1829 }
1830
1831 jobject lock = env->GetObjectField(
1832 object, gPersistentSurfaceClassInfo.mLock);
1833 if (env->MonitorEnter(lock) == JNI_OK) {
1834 env->CallVoidMethod(
1835 object,
1836 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1837 (jlong)surface.get());
1838 env->SetLongField(
1839 object,
1840 gPersistentSurfaceClassInfo.mPersistentObject,
1841 (jlong)persistentSurface.get());
1842 env->MonitorExit(lock);
1843 } else {
1844 env->DeleteLocalRef(object);
1845 object = NULL;
1846 }
1847 env->DeleteLocalRef(lock);
1848
1849 if (object != NULL) {
1850 surface->incStrong(&sRefBaseOwner);
1851 persistentSurface->incStrong(&sRefBaseOwner);
1852 }
1853
1854 return object;
1855}
1856
1857static void android_media_MediaCodec_releasePersistentInputSurface(
1858 JNIEnv* env, jclass /* clazz */, jobject object) {
1859 sp<PersistentSurface> persistentSurface;
1860
1861 jobject lock = env->GetObjectField(
1862 object, gPersistentSurfaceClassInfo.mLock);
1863 if (env->MonitorEnter(lock) == JNI_OK) {
1864 persistentSurface = reinterpret_cast<PersistentSurface *>(
1865 env->GetLongField(
1866 object, gPersistentSurfaceClassInfo.mPersistentObject));
1867 env->SetLongField(
1868 object,
1869 gPersistentSurfaceClassInfo.mPersistentObject,
1870 (jlong)0);
1871 env->MonitorExit(lock);
1872 }
1873 env->DeleteLocalRef(lock);
1874
1875 if (persistentSurface != NULL) {
1876 persistentSurface->decStrong(&sRefBaseOwner);
1877 }
1878 // no need to release surface as it will be released by Surface's jni
1879}
1880
Chong Zhang9560ddb2015-05-13 10:25:29 -07001881static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001882 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001883 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001884
1885 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001886 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001887 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001888 return;
1889 }
1890
1891 sp<PersistentSurface> persistentSurface =
1892 android_media_MediaCodec_getPersistentInputSurface(env, object);
1893
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001894 if (persistentSurface == NULL) {
1895 throwExceptionAsNecessary(
1896 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1897 return;
1898 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001899 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001900 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001901 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001902 }
1903}
1904
Andy McFadden2621e402013-02-19 07:29:21 -08001905static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1906 jobject thiz) {
1907 ALOGV("android_media_MediaCodec_createInputSurface");
1908
1909 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001910 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001911 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001912 return NULL;
1913 }
1914
1915 // Tell the MediaCodec that we want to use a Surface as input.
1916 sp<IGraphicBufferProducer> bufferProducer;
1917 status_t err = codec->createInputSurface(&bufferProducer);
1918 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001919 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001920 return NULL;
1921 }
1922
1923 // Wrap the IGBP in a Java-language Surface.
1924 return android_view_Surface_createFromIGraphicBufferProducer(env,
1925 bufferProducer);
1926}
1927
Andreas Huber88572f72012-02-21 11:47:18 -08001928static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1929 ALOGV("android_media_MediaCodec_start");
1930
1931 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1932
Wonsik Kim24e53802020-05-08 20:04:26 -07001933 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001934 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001935 return;
1936 }
1937
1938 status_t err = codec->start();
1939
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001940 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001941}
1942
1943static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1944 ALOGV("android_media_MediaCodec_stop");
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->stop();
1954
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001955 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001956}
1957
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001958static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1959 ALOGV("android_media_MediaCodec_reset");
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);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001965 return;
1966 }
1967
1968 status_t err = codec->reset();
1969 if (err != OK) {
1970 // treat all errors as fatal for now, though resource not available
1971 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001972 // we also should avoid sending INVALID_OPERATION here due to
1973 // the transitory nature of reset(), it should not inadvertently
1974 // trigger an IllegalStateException.
1975 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001976 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001977 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001978}
1979
Andreas Huber88572f72012-02-21 11:47:18 -08001980static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1981 ALOGV("android_media_MediaCodec_flush");
1982
1983 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1984
Wonsik Kim24e53802020-05-08 20:04:26 -07001985 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001986 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001987 return;
1988 }
1989
1990 status_t err = codec->flush();
1991
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001992 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001993}
1994
1995static void android_media_MediaCodec_queueInputBuffer(
1996 JNIEnv *env,
1997 jobject thiz,
1998 jint index,
1999 jint offset,
2000 jint size,
2001 jlong timestampUs,
2002 jint flags) {
2003 ALOGV("android_media_MediaCodec_queueInputBuffer");
2004
2005 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2006
Wonsik Kim24e53802020-05-08 20:04:26 -07002007 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002008 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002009 return;
2010 }
2011
Andreas Huberbfc56f42012-04-19 12:47:07 -07002012 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08002013
Andreas Huberbfc56f42012-04-19 12:47:07 -07002014 status_t err = codec->queueInputBuffer(
2015 index, offset, size, timestampUs, flags, &errorDetailMsg);
2016
2017 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002018 env, err, ACTION_CODE_FATAL,
2019 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08002020}
2021
Arun Johnson206270e2023-10-31 20:40:12 +00002022static status_t extractInfosFromObject(
2023 JNIEnv * const env,
2024 jint * const initialOffset,
2025 jint * const totalSize,
2026 std::vector<AccessUnitInfo> * const infos,
2027 const jobjectArray &objArray,
2028 AString * const errorDetailMsg) {
2029 if (totalSize == nullptr
2030 || initialOffset == nullptr
2031 || infos == nullptr) {
2032 if (errorDetailMsg) {
2033 *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
2034 }
2035 return BAD_VALUE;
2036 }
2037 const jsize numEntries = env->GetArrayLength(objArray);
2038 if (numEntries <= 0) {
2039 if (errorDetailMsg) {
2040 *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
2041 }
2042 return BAD_VALUE;
2043 }
2044 *initialOffset = 0;
2045 *totalSize = 0;
2046 for (jsize i = 0; i < numEntries; i++) {
2047 jobject param = env->GetObjectArrayElement(objArray, i);
2048 if (param == NULL) {
2049 if (errorDetailMsg) {
2050 *errorDetailMsg = "Error: Queuing a null BufferInfo";
2051 }
2052 return BAD_VALUE;
2053 }
2054 size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
2055 size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
2056 uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
2057 if (flags == 0 && size == 0) {
2058 if (errorDetailMsg) {
2059 *errorDetailMsg = "Error: Queuing an empty BufferInfo";
2060 }
2061 return BAD_VALUE;
2062 }
2063 if (i == 0) {
2064 *initialOffset = offset;
2065 }
2066 if (CC_UNLIKELY((offset > UINT32_MAX)
2067 || ((long)(offset + size) > UINT32_MAX)
2068 || ((offset - *initialOffset) != *totalSize))) {
2069 if (errorDetailMsg) {
2070 *errorDetailMsg = "Error: offset/size in BufferInfo";
2071 }
2072 return BAD_VALUE;
2073 }
2074 infos->emplace_back(
2075 flags,
2076 size,
2077 env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
2078 *totalSize += size;
2079 }
2080 return OK;
2081}
2082
2083static void android_media_MediaCodec_queueInputBuffers(
2084 JNIEnv *env,
2085 jobject thiz,
2086 jint index,
2087 jobjectArray objArray) {
2088 ALOGV("android_media_MediaCodec_queueInputBuffers");
2089 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2090 if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
2091 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2092 return;
2093 }
2094 sp<BufferInfosWrapper> infoObj =
2095 new BufferInfosWrapper{decltype(infoObj->value)()};
2096 AString errorDetailMsg;
2097 jint initialOffset = 0;
2098 jint totalSize = 0;
2099 status_t err = extractInfosFromObject(
2100 env,
2101 &initialOffset,
2102 &totalSize,
2103 &infoObj->value,
2104 objArray,
2105 &errorDetailMsg);
2106 if (err == OK) {
2107 err = codec->queueInputBuffers(
2108 index,
2109 initialOffset,
2110 totalSize,
2111 infoObj,
2112 &errorDetailMsg);
2113 }
2114 throwExceptionAsNecessary(
2115 env, err, ACTION_CODE_FATAL,
2116 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2117}
2118
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002119struct NativeCryptoInfo {
2120 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
2121 : mEnv{env},
2122 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
2123 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
2124 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2125
2126 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
2127 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
2128
2129 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
2130 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
2131
2132 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2133 if (jmode == gCryptoModes.Unencrypted) {
2134 mMode = CryptoPlugin::kMode_Unencrypted;
2135 } else if (jmode == gCryptoModes.AesCtr) {
2136 mMode = CryptoPlugin::kMode_AES_CTR;
2137 } else if (jmode == gCryptoModes.AesCbc) {
2138 mMode = CryptoPlugin::kMode_AES_CBC;
2139 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002140 throwExceptionAsNecessary(
2141 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2142 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002143 return;
2144 }
2145
2146 ScopedLocalRef<jobject> patternObj{
2147 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
2148
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002149 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002150 mPattern.mEncryptBlocks = 0;
2151 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002152 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002153 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002154 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002155 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002156 patternObj.get(), gFields.patternSkipBlocksID);
2157 }
2158
2159 mErr = OK;
2160 if (mNumSubSamples <= 0) {
2161 mErr = -EINVAL;
2162 } else if (numBytesOfClearDataObj == nullptr
2163 && numBytesOfEncryptedDataObj == nullptr) {
2164 mErr = -EINVAL;
2165 } else if (numBytesOfEncryptedDataObj != nullptr
2166 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
2167 mErr = -ERANGE;
2168 } else if (numBytesOfClearDataObj != nullptr
2169 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
2170 mErr = -ERANGE;
2171 // subSamples array may silently overflow if number of samples are too large. Use
2172 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2173 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
2174 mErr = -EINVAL;
2175 } else {
2176 jint *numBytesOfClearData =
2177 (numBytesOfClearDataObj == nullptr)
2178 ? nullptr
2179 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
2180
2181 jint *numBytesOfEncryptedData =
2182 (numBytesOfEncryptedDataObj == nullptr)
2183 ? nullptr
2184 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
2185
2186 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
2187
2188 for (jint i = 0; i < mNumSubSamples; ++i) {
2189 mSubSamples[i].mNumBytesOfClearData =
2190 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
2191
2192 mSubSamples[i].mNumBytesOfEncryptedData =
2193 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
2194 }
2195
2196 if (numBytesOfEncryptedData != nullptr) {
2197 env->ReleaseIntArrayElements(
2198 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
2199 numBytesOfEncryptedData = nullptr;
2200 }
2201
2202 if (numBytesOfClearData != nullptr) {
2203 env->ReleaseIntArrayElements(
2204 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2205 numBytesOfClearData = nullptr;
2206 }
2207 }
2208
2209 if (mErr == OK && mKeyObj.get() != nullptr) {
2210 if (env->GetArrayLength(mKeyObj.get()) != 16) {
2211 mErr = -EINVAL;
2212 } else {
2213 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2214 }
2215 }
2216
2217 if (mErr == OK && mIvObj.get() != nullptr) {
2218 if (env->GetArrayLength(mIvObj.get()) != 16) {
2219 mErr = -EINVAL;
2220 } else {
2221 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2222 }
2223 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002224
2225 }
2226
2227 explicit NativeCryptoInfo(jint size)
2228 : mIvObj{nullptr, nullptr},
2229 mKeyObj{nullptr, nullptr},
2230 mMode{CryptoPlugin::kMode_Unencrypted},
2231 mPattern{0, 0} {
2232 mSubSamples = new CryptoPlugin::SubSample[1];
2233 mNumSubSamples = 1;
2234 mSubSamples[0].mNumBytesOfClearData = size;
2235 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002236 }
2237
2238 ~NativeCryptoInfo() {
2239 if (mIv != nullptr) {
2240 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2241 }
2242
2243 if (mKey != nullptr) {
2244 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2245 }
2246
2247 if (mSubSamples != nullptr) {
2248 delete[] mSubSamples;
2249 }
2250 }
2251
2252 JNIEnv *mEnv{nullptr};
2253 ScopedLocalRef<jbyteArray> mIvObj;
2254 ScopedLocalRef<jbyteArray> mKeyObj;
2255 status_t mErr{OK};
2256
2257 CryptoPlugin::SubSample *mSubSamples{nullptr};
2258 int32_t mNumSubSamples{0};
2259 jbyte *mIv{nullptr};
2260 jbyte *mKey{nullptr};
2261 enum CryptoPlugin::Mode mMode;
2262 CryptoPlugin::Pattern mPattern;
2263};
2264
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002265static void android_media_MediaCodec_queueSecureInputBuffer(
2266 JNIEnv *env,
2267 jobject thiz,
2268 jint index,
2269 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002270 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002271 jlong timestampUs,
2272 jint flags) {
2273 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2274
2275 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2276
Wonsik Kim24e53802020-05-08 20:04:26 -07002277 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002278 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002279 return;
2280 }
2281
Wonsik Kim1cac4252020-01-24 11:45:37 -08002282 jint numSubSamples =
2283 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2284
2285 jintArray numBytesOfClearDataObj =
2286 (jintArray)env->GetObjectField(
2287 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2288
2289 jintArray numBytesOfEncryptedDataObj =
2290 (jintArray)env->GetObjectField(
2291 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2292
2293 jbyteArray keyObj =
2294 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2295
2296 jbyteArray ivObj =
2297 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2298
2299 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2300 enum CryptoPlugin::Mode mode;
2301 if (jmode == gCryptoModes.Unencrypted) {
2302 mode = CryptoPlugin::kMode_Unencrypted;
2303 } else if (jmode == gCryptoModes.AesCtr) {
2304 mode = CryptoPlugin::kMode_AES_CTR;
2305 } else if (jmode == gCryptoModes.AesCbc) {
2306 mode = CryptoPlugin::kMode_AES_CBC;
2307 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002308 throwExceptionAsNecessary(
2309 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2310 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08002311 return;
2312 }
2313
2314 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2315
2316 CryptoPlugin::Pattern pattern;
2317 if (patternObj == NULL) {
2318 pattern.mEncryptBlocks = 0;
2319 pattern.mSkipBlocks = 0;
2320 } else {
2321 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2322 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2323 }
2324
2325 status_t err = OK;
2326
2327 CryptoPlugin::SubSample *subSamples = NULL;
2328 jbyte *key = NULL;
2329 jbyte *iv = NULL;
2330
2331 if (numSubSamples <= 0) {
2332 err = -EINVAL;
2333 } else if (numBytesOfClearDataObj == NULL
2334 && numBytesOfEncryptedDataObj == NULL) {
2335 err = -EINVAL;
2336 } else if (numBytesOfEncryptedDataObj != NULL
2337 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2338 err = -ERANGE;
2339 } else if (numBytesOfClearDataObj != NULL
2340 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2341 err = -ERANGE;
2342 // subSamples array may silently overflow if number of samples are too large. Use
2343 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2344 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2345 err = -EINVAL;
2346 } else {
2347 jboolean isCopy;
2348
2349 jint *numBytesOfClearData =
2350 (numBytesOfClearDataObj == NULL)
2351 ? NULL
2352 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2353
2354 jint *numBytesOfEncryptedData =
2355 (numBytesOfEncryptedDataObj == NULL)
2356 ? NULL
2357 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2358
2359 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2360
2361 for (jint i = 0; i < numSubSamples; ++i) {
2362 subSamples[i].mNumBytesOfClearData =
2363 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2364
2365 subSamples[i].mNumBytesOfEncryptedData =
2366 (numBytesOfEncryptedData == NULL)
2367 ? 0 : numBytesOfEncryptedData[i];
2368 }
2369
2370 if (numBytesOfEncryptedData != NULL) {
2371 env->ReleaseIntArrayElements(
2372 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2373 numBytesOfEncryptedData = NULL;
2374 }
2375
2376 if (numBytesOfClearData != NULL) {
2377 env->ReleaseIntArrayElements(
2378 numBytesOfClearDataObj, numBytesOfClearData, 0);
2379 numBytesOfClearData = NULL;
2380 }
2381 }
2382
2383 if (err == OK && keyObj != NULL) {
2384 if (env->GetArrayLength(keyObj) != 16) {
2385 err = -EINVAL;
2386 } else {
2387 jboolean isCopy;
2388 key = env->GetByteArrayElements(keyObj, &isCopy);
2389 }
2390 }
2391
2392 if (err == OK && ivObj != NULL) {
2393 if (env->GetArrayLength(ivObj) != 16) {
2394 err = -EINVAL;
2395 } else {
2396 jboolean isCopy;
2397 iv = env->GetByteArrayElements(ivObj, &isCopy);
2398 }
2399 }
2400
Andreas Huberbfc56f42012-04-19 12:47:07 -07002401 AString errorDetailMsg;
2402
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002403 if (err == OK) {
2404 err = codec->queueSecureInputBuffer(
2405 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002406 subSamples, numSubSamples,
2407 (const uint8_t *)key, (const uint8_t *)iv,
2408 mode,
2409 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002410 timestampUs,
2411 flags,
2412 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002413 }
2414
Wonsik Kim1cac4252020-01-24 11:45:37 -08002415 if (iv != NULL) {
2416 env->ReleaseByteArrayElements(ivObj, iv, 0);
2417 iv = NULL;
2418 }
2419
2420 if (key != NULL) {
2421 env->ReleaseByteArrayElements(keyObj, key, 0);
2422 key = NULL;
2423 }
2424
2425 delete[] subSamples;
2426 subSamples = NULL;
2427
Andreas Huberbfc56f42012-04-19 12:47:07 -07002428 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002429 env, err, ACTION_CODE_FATAL,
2430 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002431}
2432
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002433static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002434 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2435 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2436 env, bufferObj);
2437 AHardwareBuffer_Desc desc;
2438 AHardwareBuffer_describe(hardwareBuffer, &desc);
2439 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2440 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2441 return nullptr;
2442 }
2443 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2444 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2445 return nullptr;
2446 }
2447 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2448
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002449 uint64_t cpuUsage = 0;
2450 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2451 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002452
2453 AHardwareBuffer_Planes planes;
2454 int err = AHardwareBuffer_lockPlanes(
2455 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2456 if (err != 0) {
2457 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2458 return nullptr;
2459 }
2460
2461 if (planes.planeCount != 3) {
2462 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2463 return nullptr;
2464 }
2465
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002466 ScopedLocalRef<jobjectArray> buffersArray{
2467 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2468 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2469 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002470
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002471 jboolean isCopy = JNI_FALSE;
2472 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2473 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2474
2475 // For Y plane
2476 int rowSampling = 1;
2477 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002478 // plane indices are Y-U-V.
2479 for (uint32_t i = 0; i < 3; ++i) {
2480 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002481 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2482 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2483 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002484 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2485 env,
2486 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002487 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002488 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002489 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002490 readOnly,
2491 true)};
2492
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002493 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2494 rowStrides[i] = plane.rowStride;
2495 pixelStrides[i] = plane.pixelStride;
2496 // For U-V planes
2497 rowSampling = 2;
2498 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002499 }
2500
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002501 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2502 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2503 rowStrides = pixelStrides = nullptr;
2504
Wonsik Kim637afb22020-02-25 14:27:29 -08002505 ScopedLocalRef<jclass> imageClazz(
2506 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2507 CHECK(imageClazz.get() != NULL);
2508
2509 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002510 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002511
2512 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002513 buffersArray.get(),
2514 rowStridesArray.get(),
2515 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002516 desc.width,
2517 desc.height,
2518 desc.format, // ???
2519 (jboolean)readOnly /* readOnly */,
2520 (jlong)0 /* timestamp */,
2521 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2522 (jlong)hardwareBuffer);
2523
2524 // if MediaImage creation fails, return null
2525 if (env->ExceptionCheck()) {
2526 env->ExceptionDescribe();
2527 env->ExceptionClear();
2528 return nullptr;
2529 }
2530
2531 AHardwareBuffer_acquire(hardwareBuffer);
2532
2533 return img;
2534}
2535
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002536static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2537 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002538 if (context == 0) {
2539 return;
2540 }
2541 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2542
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002543 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2544 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002545 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2546 // Continue to release the hardwareBuffer
2547 }
2548
2549 AHardwareBuffer_release(hardwareBuffer);
2550}
2551
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002552static status_t ConvertKeyValueListsToAMessage(
2553 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2554 static struct Fields {
2555 explicit Fields(JNIEnv *env) {
2556 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2557 CHECK(clazz.get() != NULL);
2558 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2559
2560 clazz.reset(env->FindClass("java/lang/Integer"));
2561 CHECK(clazz.get() != NULL);
2562 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2563
2564 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2565 CHECK(mIntegerValueId != NULL);
2566
2567 clazz.reset(env->FindClass("java/lang/Long"));
2568 CHECK(clazz.get() != NULL);
2569 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2570
2571 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2572 CHECK(mLongValueId != NULL);
2573
2574 clazz.reset(env->FindClass("java/lang/Float"));
2575 CHECK(clazz.get() != NULL);
2576 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2577
2578 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2579 CHECK(mFloatValueId != NULL);
2580
2581 clazz.reset(env->FindClass("java/util/ArrayList"));
2582 CHECK(clazz.get() != NULL);
2583
2584 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2585 CHECK(mByteBufferArrayId != NULL);
2586 }
2587
2588 jclass mStringClass;
2589 jclass mIntegerClass;
2590 jmethodID mIntegerValueId;
2591 jclass mLongClass;
2592 jmethodID mLongValueId;
2593 jclass mFloatClass;
2594 jmethodID mFloatValueId;
2595 jmethodID mByteBufferArrayId;
2596 } sFields{env};
2597
2598 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2599 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2600 return BAD_VALUE;
2601 }
2602
2603 sp<AMessage> result{new AMessage};
2604 for (jint i = 0; i < size; ++i) {
2605 ScopedLocalRef<jstring> jkey{
2606 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2607 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2608 AString key;
2609 if (tmp) {
2610 key.setTo(tmp);
2611 }
2612 env->ReleaseStringUTFChars(jkey.get(), tmp);
2613 if (key.empty()) {
2614 return NO_MEMORY;
2615 }
2616
2617 ScopedLocalRef<jobject> jvalue{
2618 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2619
2620 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2621 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2622 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002623 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002624 return NO_MEMORY;
2625 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002626 value.setTo(tmp);
2627 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002628 result->setString(key.c_str(), value);
2629 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2630 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2631 result->setInt32(key.c_str(), value);
2632 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2633 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2634 result->setInt64(key.c_str(), value);
2635 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2636 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2637 result->setFloat(key.c_str(), value);
2638 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002639 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2640 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002641 sp<ABuffer> buffer{new ABuffer(limit - position)};
2642 void *data = env->GetDirectBufferAddress(jvalue.get());
2643 if (data != nullptr) {
2644 memcpy(buffer->data(),
2645 static_cast<const uint8_t *>(data) + position,
2646 buffer->size());
2647 } else {
2648 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2649 jvalue.get(), sFields.mByteBufferArrayId)};
2650 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2651 reinterpret_cast<jbyte *>(buffer->data()));
2652 }
2653 result->setBuffer(key.c_str(), buffer);
2654 }
2655 }
2656
2657 *msg = result;
2658 return OK;
2659}
2660
Wonsik Kim8569a662022-05-24 14:16:44 -07002661static bool obtain(
2662 JMediaCodecLinearBlock *context,
2663 int capacity,
2664 const std::vector<std::string> &names,
2665 bool secure) {
2666 if (secure) {
2667 // Start at 1MB, which is an arbitrary starting point that can
2668 // increase when needed.
2669 constexpr size_t kInitialDealerCapacity = 1048576;
2670 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2671 kInitialDealerCapacity, "JNI(1MB)");
2672 context->mMemory = sDealer->allocate(capacity);
2673 if (context->mMemory == nullptr) {
2674 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2675 while (capacity * 2 > newDealerCapacity) {
2676 newDealerCapacity *= 2;
2677 }
2678 ALOGI("LinearBlock.native_obtain: "
2679 "Dealer capacity increasing from %zuMB to %zuMB",
2680 sDealer->getMemoryHeap()->getSize() / 1048576,
2681 newDealerCapacity / 1048576);
2682 sDealer = new MemoryDealer(
2683 newDealerCapacity,
2684 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2685 context->mMemory = sDealer->allocate(capacity);
2686 }
2687 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2688 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2689 } else {
2690 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2691 if (!context->mBlock) {
2692 return false;
2693 }
2694 }
2695 context->mCodecNames = names;
2696 return true;
2697}
2698
2699static void extractMemoryFromContext(
2700 JMediaCodecLinearBlock *context,
2701 jint offset,
2702 jint size,
2703 sp<hardware::HidlMemory> *memory) {
2704 *memory = context->toHidlMemory();
2705 if (*memory == nullptr) {
2706 if (!context->mBlock) {
2707 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2708 return;
2709 }
2710 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2711 context->capacity());
2712 if (!obtain(context, context->capacity(),
2713 context->mCodecNames, true /* secure */)) {
2714 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2715 return;
2716 }
2717 C2WriteView view = context->mBlock->map().get();
2718 if (view.error() != C2_OK) {
2719 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2720 return;
2721 }
2722 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2723 memcpy(memoryPtr + offset, view.base() + offset, size);
2724 context->mBlock.reset();
2725 context->mReadWriteMapping.reset();
2726 *memory = context->toHidlMemory();
2727 }
2728}
2729
2730static void extractBufferFromContext(
2731 JMediaCodecLinearBlock *context,
2732 jint offset,
2733 jint size,
2734 std::shared_ptr<C2Buffer> *buffer) {
2735 *buffer = context->toC2Buffer(offset, size);
2736 if (*buffer == nullptr) {
2737 if (!context->mMemory) {
2738 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2739 return;
2740 }
2741 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2742 context->capacity());
2743 if (obtain(context, context->capacity(),
2744 context->mCodecNames, false /* secure */)) {
2745 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2746 return;
2747 }
2748 C2WriteView view = context->mBlock->map().get();
2749 if (view.error() != C2_OK) {
2750 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2751 return;
2752 }
2753 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2754 memcpy(view.base() + offset, memoryPtr + offset, size);
2755 context->mMemory.clear();
2756 context->mHidlMemory.clear();
2757 context->mHidlMemorySize = 0;
2758 context->mHidlMemoryOffset = 0;
2759 *buffer = context->toC2Buffer(offset, size);
2760 }
2761}
2762
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002763static void android_media_MediaCodec_native_queueLinearBlock(
2764 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002765 jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002766 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2767
2768 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2769
Wonsik Kim24e53802020-05-08 20:04:26 -07002770 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002771 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002772 return;
2773 }
2774
2775 sp<AMessage> tunings;
2776 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2777 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002778 throwExceptionAsNecessary(
2779 env, err, ACTION_CODE_FATAL,
2780 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002781 return;
2782 }
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002783 jint totalSize;
2784 jint initialOffset;
2785 std::vector<AccessUnitInfo> infoVec;
2786 AString errorDetailMsg;
2787 err = extractInfosFromObject(env,
2788 &initialOffset,
2789 &totalSize,
2790 &infoVec,
2791 objArray,
2792 &errorDetailMsg);
2793 if (err != OK) {
2794 throwExceptionAsNecessary(
2795 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2796 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2797 return;
2798 }
2799 sp<BufferInfosWrapper> infos =
2800 new BufferInfosWrapper{std::move(infoVec)};
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002801 std::shared_ptr<C2Buffer> buffer;
2802 sp<hardware::HidlMemory> memory;
2803 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2804 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2805 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2806 JMediaCodecLinearBlock *context =
2807 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002808 if (codec->hasCryptoOrDescrambler()) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002809 extractMemoryFromContext(context, initialOffset, totalSize, &memory);
2810 initialOffset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002811 } else {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002812 extractBufferFromContext(context, initialOffset, totalSize, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002813 }
2814 }
2815 env->MonitorExit(lock.get());
2816 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002817 throwExceptionAsNecessary(
2818 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2819 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002820 return;
2821 }
2822
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002823 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002824 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002825 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002826 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002827 throwExceptionAsNecessary(
2828 env, BAD_VALUE, ACTION_CODE_FATAL,
2829 "Unexpected error: the input buffer is not compatible with "
2830 "the secure codec, and a fallback logic failed.\n"
2831 "Suggestion: please try including the secure codec when calling "
2832 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002833 return;
2834 }
George Burgess IV436998b2022-11-02 11:42:33 -06002835 auto cryptoInfo =
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002836 cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
George Burgess IV436998b2022-11-02 11:42:33 -06002837 if (env->ExceptionCheck()) {
2838 // Creation of cryptoInfo failed. Let the exception bubble up.
2839 return;
2840 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002841 err = codec->queueEncryptedLinearBlock(
2842 index,
2843 memory,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002844 initialOffset,
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002845 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2846 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2847 cryptoInfo.mMode,
2848 cryptoInfo.mPattern,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002849 infos,
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002850 tunings,
2851 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002852 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002853 } else {
2854 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002855 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002856 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002857 throwExceptionAsNecessary(
2858 env, BAD_VALUE, ACTION_CODE_FATAL,
2859 "Unexpected error: the input buffer is not compatible with "
2860 "the non-secure codec, and a fallback logic failed.\n"
2861 "Suggestion: please do not include the secure codec when calling "
2862 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002863 return;
2864 }
2865 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002866 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002867 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002868 throwExceptionAsNecessary(
2869 env, err, ACTION_CODE_FATAL,
2870 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002871}
2872
Wonsik Kim637afb22020-02-25 14:27:29 -08002873static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002874 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2875 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002876 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002877
2878 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2879
Wonsik Kim24e53802020-05-08 20:04:26 -07002880 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002881 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002882 return;
2883 }
2884
2885 sp<AMessage> tunings;
2886 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2887 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002888 throwExceptionAsNecessary(
2889 env, err, ACTION_CODE_FATAL,
2890 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002891 return;
2892 }
2893
Wonsik Kim637afb22020-02-25 14:27:29 -08002894 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2895 env, bufferObj);
2896 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2897 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002898 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2899 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2900 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2901 std::shared_ptr<C2Allocator> alloc;
2902 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2903 C2PlatformAllocatorStore::GRALLOC, &alloc);
2904 if (err == C2_OK) {
2905 return alloc;
2906 }
2907 return nullptr;
2908 }();
2909 std::shared_ptr<C2GraphicAllocation> alloc;
2910 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2911 if (c2err != C2_OK) {
2912 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002913 native_handle_close(handle);
2914 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002915 throwExceptionAsNecessary(
2916 env, BAD_VALUE, ACTION_CODE_FATAL,
2917 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002918 return;
2919 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002920 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002921 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2922 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002923 AString errorDetailMsg;
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002924 sp<BufferInfosWrapper> infos =
2925 new BufferInfosWrapper{decltype(infos->value)()};
2926 infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002927 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002928 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002929 throwExceptionAsNecessary(
2930 env, err, ACTION_CODE_FATAL,
2931 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002932}
2933
2934static void android_media_MediaCodec_native_getOutputFrame(
2935 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2936 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2937
2938 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2939
Wonsik Kim24e53802020-05-08 20:04:26 -07002940 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002941 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002942 return;
2943 }
2944
2945 status_t err = codec->getOutputFrame(env, frame, index);
2946 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002947 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002948 }
2949}
2950
Andreas Huber88572f72012-02-21 11:47:18 -08002951static jint android_media_MediaCodec_dequeueInputBuffer(
2952 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2953 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2954
2955 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2956
Wonsik Kim24e53802020-05-08 20:04:26 -07002957 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002958 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002959 return -1;
2960 }
2961
2962 size_t index;
2963 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2964
2965 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002966 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002967 }
2968
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002969 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002970}
2971
2972static jint android_media_MediaCodec_dequeueOutputBuffer(
2973 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2974 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2975
2976 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2977
Wonsik Kim24e53802020-05-08 20:04:26 -07002978 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002979 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002980 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002981 }
2982
2983 size_t index;
2984 status_t err = codec->dequeueOutputBuffer(
2985 env, bufferInfo, &index, timeoutUs);
2986
2987 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002988 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002989 }
2990
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002991 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002992}
2993
2994static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002995 JNIEnv *env, jobject thiz,
2996 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002997 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2998
2999 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3000
Wonsik Kim24e53802020-05-08 20:04:26 -07003001 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003002 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003003 return;
3004 }
3005
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003006 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08003007
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003008 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003009}
3010
Andy McFadden2621e402013-02-19 07:29:21 -08003011static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
3012 jobject thiz) {
3013 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
3014
3015 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003016 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003017 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003018 return;
3019 }
3020
3021 status_t err = codec->signalEndOfInputStream();
3022
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003023 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003024}
3025
Lajos Molnard4023112014-07-11 15:12:59 -07003026static jobject android_media_MediaCodec_getFormatNative(
3027 JNIEnv *env, jobject thiz, jboolean input) {
3028 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08003029
3030 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3031
Wonsik Kim24e53802020-05-08 20:04:26 -07003032 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003033 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003034 return NULL;
3035 }
3036
3037 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07003038 status_t err = codec->getFormat(env, input, &format);
3039
3040 if (err == OK) {
3041 return format;
3042 }
3043
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003044 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003045
3046 return NULL;
3047}
3048
3049static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
3050 JNIEnv *env, jobject thiz, jint index) {
3051 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
3052
3053 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3054
Wonsik Kim24e53802020-05-08 20:04:26 -07003055 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003056 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003057 return NULL;
3058 }
3059
3060 jobject format;
3061 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08003062
3063 if (err == OK) {
3064 return format;
3065 }
3066
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003067 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003068
3069 return NULL;
3070}
3071
3072static jobjectArray android_media_MediaCodec_getBuffers(
3073 JNIEnv *env, jobject thiz, jboolean input) {
3074 ALOGV("android_media_MediaCodec_getBuffers");
3075
3076 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3077
Wonsik Kim24e53802020-05-08 20:04:26 -07003078 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003079 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003080 return NULL;
3081 }
3082
3083 jobjectArray buffers;
3084 status_t err = codec->getBuffers(env, input, &buffers);
3085
3086 if (err == OK) {
3087 return buffers;
3088 }
3089
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003090 // if we're out of memory, an exception was already thrown
3091 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003092 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003093 }
Andreas Huber88572f72012-02-21 11:47:18 -08003094
3095 return NULL;
3096}
3097
Lajos Molnard4023112014-07-11 15:12:59 -07003098static jobject android_media_MediaCodec_getBuffer(
3099 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3100 ALOGV("android_media_MediaCodec_getBuffer");
3101
3102 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3103
Wonsik Kim24e53802020-05-08 20:04:26 -07003104 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003105 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003106 return NULL;
3107 }
3108
3109 jobject buffer;
3110 status_t err = codec->getBuffer(env, input, index, &buffer);
3111
3112 if (err == OK) {
3113 return buffer;
3114 }
3115
3116 // if we're out of memory, an exception was already thrown
3117 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003118 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003119 }
3120
3121 return NULL;
3122}
3123
3124static jobject android_media_MediaCodec_getImage(
3125 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3126 ALOGV("android_media_MediaCodec_getImage");
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);
Lajos Molnard4023112014-07-11 15:12:59 -07003132 return NULL;
3133 }
3134
3135 jobject image;
3136 status_t err = codec->getImage(env, input, index, &image);
3137
3138 if (err == OK) {
3139 return image;
3140 }
3141
3142 // if we're out of memory, an exception was already thrown
3143 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003144 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003145 }
3146
3147 return NULL;
3148}
3149
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003150static jobject android_media_MediaCodec_getName(
3151 JNIEnv *env, jobject thiz) {
3152 ALOGV("android_media_MediaCodec_getName");
3153
3154 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3155
Wonsik Kim24e53802020-05-08 20:04:26 -07003156 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003157 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003158 return NULL;
3159 }
3160
3161 jstring name;
3162 status_t err = codec->getName(env, &name);
3163
3164 if (err == OK) {
3165 return name;
3166 }
3167
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003168 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003169
3170 return NULL;
3171}
3172
Chong Zhanga0b72a62018-02-28 18:46:26 -08003173static jobject android_media_MediaCodec_getOwnCodecInfo(
3174 JNIEnv *env, jobject thiz) {
3175 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
3176
3177 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3178
Wonsik Kim24e53802020-05-08 20:04:26 -07003179 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003180 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003181 return NULL;
3182 }
3183
3184 jobject codecInfoObj;
3185 status_t err = codec->getCodecInfo(env, &codecInfoObj);
3186
3187 if (err == OK) {
3188 return codecInfoObj;
3189 }
3190
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003191 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003192
3193 return NULL;
3194}
3195
Ray Essick0e0fee12017-01-25 18:01:56 -08003196static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08003197android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08003198{
Ray Essickf2d0e402017-03-09 10:17:51 -08003199 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08003200
3201 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003202 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003203 jniThrowException(env, "java/lang/IllegalStateException",
3204 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08003205 return 0;
3206 }
3207
3208 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08003209 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08003210
3211 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08003212 if (err != OK) {
3213 ALOGE("getMetrics failed");
3214 return (jobject) NULL;
3215 }
3216
Ray Essick0e0fee12017-01-25 18:01:56 -08003217 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
3218
3219 // housekeeping
3220 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07003221 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08003222
3223 return mybundle;
3224}
3225
Andreas Huber226065b2013-08-12 10:14:11 -07003226static void android_media_MediaCodec_setParameters(
3227 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3228 ALOGV("android_media_MediaCodec_setParameters");
3229
3230 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3231
Wonsik Kim24e53802020-05-08 20:04:26 -07003232 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003233 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003234 return;
3235 }
3236
3237 sp<AMessage> params;
3238 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3239
3240 if (err == OK) {
3241 err = codec->setParameters(params);
3242 }
3243
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003244 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003245}
3246
Andreas Huberb12a5392012-04-30 14:18:33 -07003247static void android_media_MediaCodec_setVideoScalingMode(
3248 JNIEnv *env, jobject thiz, jint mode) {
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 Huberb12a5392012-04-30 14:18:33 -07003253 return;
3254 }
3255
3256 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3257 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003258 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003259 String8::format("Unrecognized mode: %d", mode).c_str());
Andreas Huberb12a5392012-04-30 14:18:33 -07003260 return;
3261 }
3262
3263 codec->setVideoScalingMode(mode);
3264}
3265
ybai5e053202018-11-01 13:02:15 +08003266static void android_media_MediaCodec_setAudioPresentation(
3267 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3268 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3269
Wonsik Kim24e53802020-05-08 20:04:26 -07003270 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003271 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08003272 return;
3273 }
3274
3275 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3276}
3277
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003278static jobject android_media_MediaCodec_getSupportedVendorParameters(
3279 JNIEnv *env, jobject thiz) {
3280 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3281
3282 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003283 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003284 return NULL;
3285 }
3286
3287 jobject ret = NULL;
3288 status_t status = codec->querySupportedVendorParameters(env, &ret);
3289 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003290 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003291 }
3292
3293 return ret;
3294}
3295
3296static jobject android_media_MediaCodec_getParameterDescriptor(
3297 JNIEnv *env, jobject thiz, jstring name) {
3298 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3299
3300 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003301 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003302 return NULL;
3303 }
3304
3305 jobject ret = NULL;
3306 status_t status = codec->describeParameter(env, name, &ret);
3307 if (status != OK) {
3308 ret = NULL;
3309 }
3310 return ret;
3311}
3312
3313static void android_media_MediaCodec_subscribeToVendorParameters(
3314 JNIEnv *env, jobject thiz, jobject names) {
3315 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3316
3317 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003318 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003319 return;
3320 }
3321
3322 status_t status = codec->subscribeToVendorParameters(env, names);
3323 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003324 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003325 }
3326 return;
3327}
3328
3329static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3330 JNIEnv *env, jobject thiz, jobject names) {
3331 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3332
3333 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003334 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003335 return;
3336 }
3337
3338 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3339 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003340 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003341 }
3342 return;
3343}
3344
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003345static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003346 ScopedLocalRef<jclass> clazz(
3347 env, env->FindClass("android/media/MediaCodec"));
3348 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003349
Andreas Huberaba67132013-10-22 12:40:01 -07003350 gFields.postEventFromNativeID =
3351 env->GetMethodID(
3352 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003353 CHECK(gFields.postEventFromNativeID != NULL);
3354
Wonsik Kim61796fd2018-09-13 13:15:59 -07003355 gFields.lockAndGetContextID =
3356 env->GetMethodID(
3357 clazz.get(), "lockAndGetContext", "()J");
3358 CHECK(gFields.lockAndGetContextID != NULL);
3359
3360 gFields.setAndUnlockContextID =
3361 env->GetMethodID(
3362 clazz.get(), "setAndUnlockContext", "(J)V");
3363 CHECK(gFields.setAndUnlockContextID != NULL);
3364
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003365 jfieldID field;
3366 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3367 CHECK(field != NULL);
3368 gCryptoModes.Unencrypted =
3369 env->GetStaticIntField(clazz.get(), field);
3370
3371 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3372 CHECK(field != NULL);
3373 gCryptoModes.AesCtr =
3374 env->GetStaticIntField(clazz.get(), field);
3375
3376 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3377 CHECK(field != NULL);
3378 gCryptoModes.AesCbc =
3379 env->GetStaticIntField(clazz.get(), field);
3380
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003381 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3382 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003383
Arun Johnson5a4c7332022-12-17 00:47:06 +00003384 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3385 CHECK(gFields.cryptoInfoSetID != NULL);
3386
3387 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3388 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3389
Andreas Huber91befdc2012-04-18 12:19:51 -07003390 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003391 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003392 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3393
3394 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003395 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003396 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3397
3398 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003399 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003400 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3401
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003402 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003403 CHECK(gFields.cryptoInfoKeyID != NULL);
3404
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003405 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003406 CHECK(gFields.cryptoInfoIVID != NULL);
3407
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003408 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003409 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003410
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003411 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003412 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3413 CHECK(gFields.cryptoInfoPatternID != NULL);
3414
3415 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3416 CHECK(clazz.get() != NULL);
3417
3418 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3419 CHECK(gFields.patternEncryptBlocksID != NULL);
3420
3421 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3422 CHECK(gFields.patternSkipBlocksID != NULL);
3423
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003424 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3425 CHECK(clazz.get() != NULL);
3426
3427 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3428 CHECK(gFields.queueRequestIndexID != NULL);
3429
3430 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3431 CHECK(clazz.get() != NULL);
3432
3433 gFields.outputFrameLinearBlockID =
3434 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3435 CHECK(gFields.outputFrameLinearBlockID != NULL);
3436
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003437 gFields.outputFramebufferInfosID =
3438 env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
3439 CHECK(gFields.outputFramebufferInfosID != NULL);
3440
Wonsik Kim637afb22020-02-25 14:27:29 -08003441 gFields.outputFrameHardwareBufferID =
3442 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3443 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003444
3445 gFields.outputFrameChangedKeysID =
3446 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3447 CHECK(gFields.outputFrameChangedKeysID != NULL);
3448
3449 gFields.outputFrameFormatID =
3450 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3451 CHECK(gFields.outputFrameFormatID != NULL);
3452
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003453 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3454 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003455
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003456 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003457 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003458 gCryptoErrorCodes.cryptoErrorNoKey =
3459 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003460
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003461 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003462 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003463 gCryptoErrorCodes.cryptoErrorKeyExpired =
3464 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003465
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003466 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003467 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003468 gCryptoErrorCodes.cryptoErrorResourceBusy =
3469 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003470
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003471 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3472 CHECK(field != NULL);
3473 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3474 env->GetStaticIntField(clazz.get(), field);
3475
Jeff Tinker96a2a952015-07-01 17:35:18 -07003476 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3477 CHECK(field != NULL);
3478 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3479 env->GetStaticIntField(clazz.get(), field);
3480
Jeff Tinker20594d82018-12-12 08:31:22 -08003481 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3482 CHECK(field != NULL);
3483 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3484 env->GetStaticIntField(clazz.get(), field);
3485
Jeff Tinkerd3932162016-03-05 11:35:20 -08003486 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3487 CHECK(field != NULL);
3488 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3489 env->GetStaticIntField(clazz.get(), field);
3490
Jeff Tinker20594d82018-12-12 08:31:22 -08003491 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3492 CHECK(field != NULL);
3493 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3494 env->GetStaticIntField(clazz.get(), field);
3495
3496 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3497 CHECK(field != NULL);
3498 gCryptoErrorCodes.cryptoErrorLostState =
3499 env->GetStaticIntField(clazz.get(), field);
3500
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003501 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3502 CHECK(clazz.get() != NULL);
3503 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3504 CHECK(field != NULL);
3505 gCodecActionCodes.codecActionTransient =
3506 env->GetStaticIntField(clazz.get(), field);
3507
3508 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3509 CHECK(field != NULL);
3510 gCodecActionCodes.codecActionRecoverable =
3511 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003512
Ronghua Wuc53ad692015-05-08 14:40:49 -07003513 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003514 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003515 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003516 env->GetStaticIntField(clazz.get(), field);
3517
Ronghua Wuc53ad692015-05-08 14:40:49 -07003518 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003519 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003520 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003521 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003522
3523 clazz.reset(env->FindClass("android/view/Surface"));
3524 CHECK(clazz.get() != NULL);
3525
3526 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3527 CHECK(field != NULL);
3528 gPersistentSurfaceClassInfo.mLock = field;
3529
3530 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3531 CHECK(method != NULL);
3532 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3533
3534 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3535 CHECK(clazz.get() != NULL);
3536 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3537
3538 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3539 CHECK(method != NULL);
3540 gPersistentSurfaceClassInfo.ctor = method;
3541
3542 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3543 CHECK(field != NULL);
3544 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003545
3546 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3547 CHECK(clazz.get() != NULL);
3548 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3549
3550 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003551 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003552 "Ljava/util/Map;Ljava/util/Map;)V");
3553 CHECK(method != NULL);
3554 gCodecInfo.capsCtorId = method;
3555
3556 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3557 CHECK(clazz.get() != NULL);
3558 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3559
3560 field = env->GetFieldID(clazz.get(), "profile", "I");
3561 CHECK(field != NULL);
3562 gCodecInfo.profileField = field;
3563
3564 field = env->GetFieldID(clazz.get(), "level", "I");
3565 CHECK(field != NULL);
3566 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003567
3568 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3569 CHECK(clazz.get() != NULL);
3570 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3571
3572 ScopedLocalRef<jclass> byteOrderClass(
3573 env, env->FindClass("java/nio/ByteOrder"));
3574 CHECK(byteOrderClass.get() != NULL);
3575
3576 jmethodID nativeOrderID = env->GetStaticMethodID(
3577 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3578 CHECK(nativeOrderID != NULL);
3579
3580 ScopedLocalRef<jobject> nativeByteOrderObj{
3581 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3582 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3583 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3584 nativeByteOrderObj.reset();
3585
3586 gByteBufferInfo.orderId = env->GetMethodID(
3587 clazz.get(),
3588 "order",
3589 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3590 CHECK(gByteBufferInfo.orderId != NULL);
3591
3592 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3593 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3594 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3595
3596 gByteBufferInfo.positionId = env->GetMethodID(
3597 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3598 CHECK(gByteBufferInfo.positionId != NULL);
3599
3600 gByteBufferInfo.limitId = env->GetMethodID(
3601 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3602 CHECK(gByteBufferInfo.limitId != NULL);
3603
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003604 gByteBufferInfo.getPositionId = env->GetMethodID(
3605 clazz.get(), "position", "()I");
3606 CHECK(gByteBufferInfo.getPositionId != NULL);
3607
3608 gByteBufferInfo.getLimitId = env->GetMethodID(
3609 clazz.get(), "limit", "()I");
3610 CHECK(gByteBufferInfo.getLimitId != NULL);
3611
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003612 clazz.reset(env->FindClass("java/util/ArrayList"));
3613 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003614 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3615
3616 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3617 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003618
3619 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3620 CHECK(gArrayListInfo.sizeId != NULL);
3621
3622 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3623 CHECK(gArrayListInfo.getId != NULL);
3624
3625 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3626 CHECK(gArrayListInfo.addId != NULL);
3627
Arun Johnson206270e2023-10-31 20:40:12 +00003628 clazz.reset(env->FindClass("java/util/ArrayDeque"));
3629 CHECK(clazz.get() != NULL);
3630 gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3631
3632 gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3633 CHECK(gArrayDequeInfo.ctorId != NULL);
3634
3635 gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3636 CHECK(gArrayDequeInfo.sizeId != NULL);
3637
3638 gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3639 CHECK(gArrayDequeInfo.addId != NULL);
3640
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003641 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3642 CHECK(clazz.get() != NULL);
3643
3644 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3645
3646 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3647 CHECK(gLinearBlockInfo.ctorId != NULL);
3648
3649 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3650 clazz.get(), "setInternalStateLocked", "(JZ)V");
3651 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3652
3653 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3654 CHECK(gLinearBlockInfo.contextId != NULL);
3655
3656 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3657 CHECK(gLinearBlockInfo.validId != NULL);
3658
3659 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3660 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003661
3662 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3663 CHECK(clazz.get() != NULL);
3664 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3665
3666 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3667 CHECK(gDescriptorInfo.ctorId != NULL);
3668
3669 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3670 CHECK(gDescriptorInfo.nameId != NULL);
3671
3672 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3673 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003674
3675 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3676 CHECK(clazz.get() != NULL);
3677 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3678
3679 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3680 CHECK(gBufferInfo.ctorId != NULL);
3681
3682 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3683 CHECK(gBufferInfo.setId != NULL);
Arun Johnson206270e2023-10-31 20:40:12 +00003684
3685 gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
3686 gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
3687 gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
3688 gFields.bufferInfoPresentationTimeUs =
3689 env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08003690}
3691
3692static void android_media_MediaCodec_native_setup(
3693 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003694 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003695 if (name == NULL) {
Ray Essickbd5fdaa2023-08-10 21:04:18 -05003696 jniThrowException(env, "java/lang/NullPointerException",
3697 "No codec name specified");
Andreas Huber88572f72012-02-21 11:47:18 -08003698 return;
3699 }
3700
3701 const char *tmp = env->GetStringUTFChars(name, NULL);
3702
3703 if (tmp == NULL) {
3704 return;
3705 }
3706
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003707 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003708
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003709 const status_t err = codec->initCheck();
3710 if (err == NAME_NOT_FOUND) {
3711 // fail and do not try again.
3712 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003713 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003714 env->ReleaseStringUTFChars(name, tmp);
3715 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003716 }
3717 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003718 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003719 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
Ronghua Wuc53ad692015-05-08 14:40:49 -07003720 env->ReleaseStringUTFChars(name, tmp);
3721 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003722 }
3723 if (err == PERMISSION_DENIED) {
3724 jniThrowException(env, "java/lang/SecurityException",
3725 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003726 err).c_str());
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003727 env->ReleaseStringUTFChars(name, tmp);
3728 return;
3729 }
3730 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003731 // believed possible to try again
3732 jniThrowException(env, "java/io/IOException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003733 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003734 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003735 return;
3736 }
3737
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003738 env->ReleaseStringUTFChars(name, tmp);
3739
Andreas Huberaba67132013-10-22 12:40:01 -07003740 codec->registerSelf();
3741
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003742 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003743}
3744
3745static void android_media_MediaCodec_native_finalize(
3746 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003747 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003748}
3749
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003750// MediaCodec.LinearBlock
3751
3752static jobject android_media_MediaCodec_LinearBlock_native_map(
3753 JNIEnv *env, jobject thiz) {
3754 JMediaCodecLinearBlock *context =
3755 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3756 if (context->mBuffer) {
3757 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3758 if (!context->mReadonlyMapping) {
3759 const C2BufferData data = buffer->data();
3760 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003761 throwExceptionAsNecessary(
3762 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3763 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003764 return nullptr;
3765 }
3766 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003767 throwExceptionAsNecessary(
3768 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3769 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003770 return nullptr;
3771 }
3772 C2ConstLinearBlock block = data.linearBlocks().front();
3773 context->mReadonlyMapping =
3774 std::make_shared<C2ReadView>(block.map().get());
3775 }
3776 return CreateByteBuffer(
3777 env,
3778 context->mReadonlyMapping->data(), // base
3779 context->mReadonlyMapping->capacity(), // capacity
3780 0u, // offset
3781 context->mReadonlyMapping->capacity(), // size
3782 true, // readOnly
3783 true /* clearBuffer */);
3784 } else if (context->mBlock) {
3785 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3786 if (!context->mReadWriteMapping) {
3787 context->mReadWriteMapping =
3788 std::make_shared<C2WriteView>(block->map().get());
3789 }
3790 return CreateByteBuffer(
3791 env,
3792 context->mReadWriteMapping->base(),
3793 context->mReadWriteMapping->capacity(),
3794 context->mReadWriteMapping->offset(),
3795 context->mReadWriteMapping->size(),
3796 false, // readOnly
3797 true /* clearBuffer */);
3798 } else if (context->mLegacyBuffer) {
3799 return CreateByteBuffer(
3800 env,
3801 context->mLegacyBuffer->base(),
3802 context->mLegacyBuffer->capacity(),
3803 context->mLegacyBuffer->offset(),
3804 context->mLegacyBuffer->size(),
3805 true, // readOnly
3806 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003807 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003808 return CreateByteBuffer(
3809 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003810 context->mMemory->unsecurePointer(),
3811 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003812 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003813 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003814 false, // readOnly
3815 true /* clearBuffer */);
3816 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003817 throwExceptionAsNecessary(
3818 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3819 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003820 return nullptr;
3821}
3822
3823static void android_media_MediaCodec_LinearBlock_native_recycle(
3824 JNIEnv *env, jobject thiz) {
3825 JMediaCodecLinearBlock *context =
3826 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003827 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003828 delete context;
3829}
3830
3831static void PopulateNamesVector(
3832 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3833 jsize length = env->GetArrayLength(codecNames);
3834 for (jsize i = 0; i < length; ++i) {
3835 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3836 if (jstr == nullptr) {
3837 // null entries are ignored
3838 continue;
3839 }
3840 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3841 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003842 throwExceptionAsNecessary(
3843 env, BAD_VALUE, ACTION_CODE_FATAL,
3844 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003845 return;
3846 }
3847 names->emplace_back(cstr);
3848 env->ReleaseStringUTFChars(jstr, cstr);
3849 }
3850}
3851
3852static void android_media_MediaCodec_LinearBlock_native_obtain(
3853 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3854 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3855 std::vector<std::string> names;
3856 PopulateNamesVector(env, codecNames, &names);
3857 bool hasSecure = false;
3858 bool hasNonSecure = false;
3859 for (const std::string &name : names) {
3860 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3861 hasSecure = true;
3862 } else {
3863 hasNonSecure = true;
3864 }
3865 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003866 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3867 jniThrowException(env, "java/io/IOException", nullptr);
3868 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003869 }
3870 env->CallVoidMethod(
3871 thiz,
3872 gLinearBlockInfo.setInternalStateId,
3873 (jlong)context.release(),
3874 true /* isMappable */);
3875}
3876
3877static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003878 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003879 std::vector<std::string> names;
3880 PopulateNamesVector(env, codecNames, &names);
3881 bool isCompatible = false;
3882 bool hasSecure = false;
3883 bool hasNonSecure = false;
3884 for (const std::string &name : names) {
3885 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3886 hasSecure = true;
3887 } else {
3888 hasNonSecure = true;
3889 }
3890 }
3891 if (hasSecure && hasNonSecure) {
3892 return false;
3893 }
3894 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3895 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003896 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003897 throwExceptionAsNecessary(env, err);
3898 }
3899 return isCompatible;
3900}
3901
Daniel Micay76f6a862015-09-19 17:31:01 -04003902static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003903 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003904
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003905 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3906
Chong Zhang8034d602015-04-28 13:38:48 -07003907 { "native_releasePersistentInputSurface",
3908 "(Landroid/view/Surface;)V",
3909 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3910
3911 { "native_createPersistentInputSurface",
3912 "()Landroid/media/MediaCodec$PersistentSurface;",
3913 (void *)android_media_MediaCodec_createPersistentInputSurface },
3914
Chong Zhang9560ddb2015-05-13 10:25:29 -07003915 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3916 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003917
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003918 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3919 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3920
Lajos Molnard8578572015-06-05 20:17:33 -07003921 { "native_enableOnFrameRenderedListener", "(Z)V",
3922 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3923
Chong Zhang8d5e5562014-07-08 18:49:21 -07003924 { "native_setCallback",
3925 "(Landroid/media/MediaCodec$Callback;)V",
3926 (void *)android_media_MediaCodec_native_setCallback },
3927
Andreas Huber88572f72012-02-21 11:47:18 -08003928 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003929 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003930 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003931 (void *)android_media_MediaCodec_native_configure },
3932
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003933 { "native_setSurface",
3934 "(Landroid/view/Surface;)V",
3935 (void *)android_media_MediaCodec_native_setSurface },
3936
Andy McFadden2621e402013-02-19 07:29:21 -08003937 { "createInputSurface", "()Landroid/view/Surface;",
3938 (void *)android_media_MediaCodec_createInputSurface },
3939
Lajos Molnard4023112014-07-11 15:12:59 -07003940 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003941 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003942 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003943
Lajos Molnard4023112014-07-11 15:12:59 -07003944 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003945 (void *)android_media_MediaCodec_queueInputBuffer },
3946
Arun Johnson206270e2023-10-31 20:40:12 +00003947 { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
3948 (void *)android_media_MediaCodec_queueInputBuffers },
3949
Lajos Molnard4023112014-07-11 15:12:59 -07003950 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003951 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3952
Wonsik Kim637afb22020-02-25 14:27:29 -08003953 { "native_mapHardwareBuffer",
3954 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3955 (void *)android_media_MediaCodec_mapHardwareBuffer },
3956
3957 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3958
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003959 { "native_queueLinearBlock",
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003960 "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
3961 "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003962 (void *)android_media_MediaCodec_native_queueLinearBlock },
3963
Wonsik Kim637afb22020-02-25 14:27:29 -08003964 { "native_queueHardwareBuffer",
3965 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3966 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003967
3968 { "native_getOutputFrame",
3969 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3970 (void *)android_media_MediaCodec_native_getOutputFrame },
3971
Lajos Molnard4023112014-07-11 15:12:59 -07003972 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003973 (void *)android_media_MediaCodec_dequeueInputBuffer },
3974
Lajos Molnard4023112014-07-11 15:12:59 -07003975 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003976 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3977
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003978 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003979 (void *)android_media_MediaCodec_releaseOutputBuffer },
3980
Andy McFadden2621e402013-02-19 07:29:21 -08003981 { "signalEndOfInputStream", "()V",
3982 (void *)android_media_MediaCodec_signalEndOfInputStream },
3983
Lajos Molnard4023112014-07-11 15:12:59 -07003984 { "getFormatNative", "(Z)Ljava/util/Map;",
3985 (void *)android_media_MediaCodec_getFormatNative },
3986
3987 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3988 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003989
3990 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3991 (void *)android_media_MediaCodec_getBuffers },
3992
Lajos Molnard4023112014-07-11 15:12:59 -07003993 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3994 (void *)android_media_MediaCodec_getBuffer },
3995
3996 { "getImage", "(ZI)Landroid/media/Image;",
3997 (void *)android_media_MediaCodec_getImage },
3998
Lajos Molnard2a7f472018-11-15 12:49:20 -08003999 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03004000 (void *)android_media_MediaCodec_getName },
4001
Chong Zhanga0b72a62018-02-28 18:46:26 -08004002 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
4003 (void *)android_media_MediaCodec_getOwnCodecInfo },
4004
Ray Essick10353e32017-04-14 10:22:55 -07004005 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08004006 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08004007
Andreas Huber226065b2013-08-12 10:14:11 -07004008 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
4009 (void *)android_media_MediaCodec_setParameters },
4010
Andreas Huberb12a5392012-04-30 14:18:33 -07004011 { "setVideoScalingMode", "(I)V",
4012 (void *)android_media_MediaCodec_setVideoScalingMode },
4013
ybai5e053202018-11-01 13:02:15 +08004014 { "native_setAudioPresentation", "(II)V",
4015 (void *)android_media_MediaCodec_setAudioPresentation },
4016
Wonsik Kim8798c8c2021-03-18 21:38:57 -07004017 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
4018 (void *)android_media_MediaCodec_getSupportedVendorParameters },
4019
4020 { "native_getParameterDescriptor",
4021 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
4022 (void *)android_media_MediaCodec_getParameterDescriptor },
4023
4024 { "native_subscribeToVendorParameters",
4025 "(Ljava/util/List;)V",
4026 (void *)android_media_MediaCodec_subscribeToVendorParameters},
4027
4028 { "native_unsubscribeFromVendorParameters",
4029 "(Ljava/util/List;)V",
4030 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
4031
Andreas Huber88572f72012-02-21 11:47:18 -08004032 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
4033
Brian Lindahl6ceeed42022-02-01 11:10:30 +01004034 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004035 (void *)android_media_MediaCodec_native_setup },
4036
4037 { "native_finalize", "()V",
4038 (void *)android_media_MediaCodec_native_finalize },
4039};
4040
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004041static const JNINativeMethod gLinearBlockMethods[] = {
4042 { "native_map", "()Ljava/nio/ByteBuffer;",
4043 (void *)android_media_MediaCodec_LinearBlock_native_map },
4044
4045 { "native_recycle", "()V",
4046 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
4047
4048 { "native_obtain", "(I[Ljava/lang/String;)V",
4049 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
4050
4051 { "native_checkCompatible", "([Ljava/lang/String;)Z",
4052 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
4053};
4054
Andreas Huber88572f72012-02-21 11:47:18 -08004055int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004056 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08004057 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004058 if (result != JNI_OK) {
4059 return result;
4060 }
4061 result = AndroidRuntime::registerNativeMethods(env,
4062 "android/media/MediaCodec$LinearBlock",
4063 gLinearBlockMethods,
4064 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004065 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08004066}