blob: 40187479b10daefb8a9354abfa931a7a7c942785 [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;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800210 jfieldID outputFrameChangedKeysID;
211 jfieldID outputFrameFormatID;
Arun Johnson206270e2023-10-31 20:40:12 +0000212 jfieldID bufferInfoFlags;
213 jfieldID bufferInfoOffset;
214 jfieldID bufferInfoSize;
215 jfieldID bufferInfoPresentationTimeUs;
216
Andreas Huber88572f72012-02-21 11:47:18 -0800217};
218
219static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700220static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800221
Arun Johnson5a4c7332022-12-17 00:47:06 +0000222jint MediaErrorToJavaError(status_t err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800223
Andreas Huber88572f72012-02-21 11:47:18 -0800224////////////////////////////////////////////////////////////////////////////////
225
226JMediaCodec::JMediaCodec(
227 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100228 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800229 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700230 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800231 jclass clazz = env->GetObjectClass(thiz);
232 CHECK(clazz != NULL);
233
234 mClass = (jclass)env->NewGlobalRef(clazz);
235 mObject = env->NewWeakGlobalRef(thiz);
236
237 mLooper = new ALooper;
238 mLooper->setName("MediaCodec_looper");
239
240 mLooper->start(
241 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700242 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700243 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800244
245 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100246 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800247 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
248 mNameAtCreation = "(null)";
249 }
Andreas Huber88572f72012-02-21 11:47:18 -0800250 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100251 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800252 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800253 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700254 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800255}
256
257status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700258 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800259}
260
Andreas Huberaba67132013-10-22 12:40:01 -0700261void JMediaCodec::registerSelf() {
262 mLooper->registerHandler(this);
263}
264
Chong Zhang128b0122014-03-01 18:04:13 -0800265void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700266 std::call_once(mReleaseFlag, [this] {
267 if (mCodec != NULL) {
268 mCodec->release();
269 mInitStatus = NO_INIT;
270 }
Andreas Huber88572f72012-02-21 11:47:18 -0800271
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700272 if (mLooper != NULL) {
273 mLooper->unregisterHandler(id());
274 mLooper->stop();
275 mLooper.clear();
276 }
277 });
Chong Zhang128b0122014-03-01 18:04:13 -0800278}
279
Wonsik Kim89666622020-04-28 10:43:47 -0700280void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700281 std::call_once(mAsyncReleaseFlag, [this] {
282 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700283 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
284 // Hold strong reference to this until async release is complete
285 notify->setObject("this", this);
286 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700287 }
288 mInitStatus = NO_INIT;
289 });
Wonsik Kim89666622020-04-28 10:43:47 -0700290}
291
Chong Zhang128b0122014-03-01 18:04:13 -0800292JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700293 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800294 /* MediaCodec and looper should have been released explicitly already
295 * in setMediaCodec() (see comments in setMediaCodec()).
296 *
297 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
298 * message handler, doing release() there risks deadlock as MediaCodec::
299 * release() post synchronous message to the same looper.
300 *
301 * Print a warning and try to proceed with releasing.
302 */
303 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
304 release();
305 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
306 }
307
Andreas Huber88572f72012-02-21 11:47:18 -0800308 JNIEnv *env = AndroidRuntime::getJNIEnv();
309
310 env->DeleteWeakGlobalRef(mObject);
311 mObject = NULL;
312 env->DeleteGlobalRef(mClass);
313 mClass = NULL;
314}
315
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100316status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
317 if (enable) {
318 if (mOnFirstTunnelFrameReadyNotification == NULL) {
319 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
320 }
321 } else {
322 mOnFirstTunnelFrameReadyNotification.clear();
323 }
324
325 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
326}
327
Lajos Molnard8578572015-06-05 20:17:33 -0700328status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
329 if (enable) {
330 if (mOnFrameRenderedNotification == NULL) {
331 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
332 }
333 } else {
334 mOnFrameRenderedNotification.clear();
335 }
336
337 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
338}
339
Chong Zhang8d5e5562014-07-08 18:49:21 -0700340status_t JMediaCodec::setCallback(jobject cb) {
341 if (cb != NULL) {
342 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800343 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700344 }
345 } else {
346 mCallbackNotification.clear();
347 }
348
349 return mCodec->setCallback(mCallbackNotification);
350}
351
Andreas Huber88572f72012-02-21 11:47:18 -0800352status_t JMediaCodec::configure(
353 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800354 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700355 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800356 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800357 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800358 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800359 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700360 mSurfaceTextureClient =
361 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700362 } else {
363 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800364 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700365
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800366 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
367 AString mime;
368 CHECK(format->findString("mime", &mime));
369 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
370 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700371 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800372 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800373
Chong Zhangd5927ae2017-01-03 11:07:18 -0800374 return mCodec->configure(
375 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800376}
377
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700378status_t JMediaCodec::setSurface(
379 const sp<IGraphicBufferProducer> &bufferProducer) {
380 sp<Surface> client;
381 if (bufferProducer != NULL) {
382 client = new Surface(bufferProducer, true /* controlledByApp */);
383 }
384 status_t err = mCodec->setSurface(client);
385 if (err == OK) {
386 mSurfaceTextureClient = client;
387 }
388 return err;
389}
390
Andy McFadden2621e402013-02-19 07:29:21 -0800391status_t JMediaCodec::createInputSurface(
392 sp<IGraphicBufferProducer>* bufferProducer) {
393 return mCodec->createInputSurface(bufferProducer);
394}
395
Chong Zhang9560ddb2015-05-13 10:25:29 -0700396status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700397 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700398 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700399}
400
Andreas Huber88572f72012-02-21 11:47:18 -0800401status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700402 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800403}
404
405status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700406 mSurfaceTextureClient.clear();
407
Chong Zhang8d5e5562014-07-08 18:49:21 -0700408 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800409}
410
411status_t JMediaCodec::flush() {
412 return mCodec->flush();
413}
414
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700415status_t JMediaCodec::reset() {
416 return mCodec->reset();
417}
418
Andreas Huber88572f72012-02-21 11:47:18 -0800419status_t JMediaCodec::queueInputBuffer(
420 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700421 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
422 AString *errorDetailMsg) {
423 return mCodec->queueInputBuffer(
424 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800425}
426
Arun Johnson206270e2023-10-31 20:40:12 +0000427status_t JMediaCodec::queueInputBuffers(
428 size_t index,
429 size_t offset,
430 size_t size,
431 const sp<RefBase> &infos,
432 AString *errorDetailMsg) {
433
434 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
435 return mCodec->queueInputBuffers(
436 index,
437 offset,
438 size,
439 auInfo,
440 errorDetailMsg);
441}
442
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700443status_t JMediaCodec::queueSecureInputBuffer(
444 size_t index,
445 size_t offset,
446 const CryptoPlugin::SubSample *subSamples,
447 size_t numSubSamples,
448 const uint8_t key[16],
449 const uint8_t iv[16],
450 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800451 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700452 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700453 uint32_t flags,
454 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700455 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800456 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700457 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700458}
459
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800460status_t JMediaCodec::queueBuffer(
461 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
462 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
463 return mCodec->queueBuffer(
464 index, buffer, timeUs, flags, tunings, errorDetailMsg);
465}
466
467status_t JMediaCodec::queueEncryptedLinearBlock(
468 size_t index,
469 const sp<hardware::HidlMemory> &buffer,
470 size_t offset,
471 const CryptoPlugin::SubSample *subSamples,
472 size_t numSubSamples,
473 const uint8_t key[16],
474 const uint8_t iv[16],
475 CryptoPlugin::Mode mode,
476 const CryptoPlugin::Pattern &pattern,
477 int64_t presentationTimeUs,
478 uint32_t flags,
479 const sp<AMessage> &tunings,
480 AString *errorDetailMsg) {
481 return mCodec->queueEncryptedBuffer(
482 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
483 presentationTimeUs, flags, tunings, errorDetailMsg);
484}
485
Andreas Huber88572f72012-02-21 11:47:18 -0800486status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700487 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800488}
489
490status_t JMediaCodec::dequeueOutputBuffer(
491 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
492 size_t size, offset;
493 int64_t timeUs;
494 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700495 status_t err = mCodec->dequeueOutputBuffer(
496 index, &offset, &size, &timeUs, &flags, timeoutUs);
497
Andreas Huberaba67132013-10-22 12:40:01 -0700498 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800499 return err;
500 }
501
Pavel Laboviche53421b2022-11-01 03:53:27 +0000502 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800503
504 return OK;
505}
506
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700507status_t JMediaCodec::releaseOutputBuffer(
508 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
509 if (updatePTS) {
510 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
511 }
Andreas Huber88572f72012-02-21 11:47:18 -0800512 return render
513 ? mCodec->renderOutputBufferAndRelease(index)
514 : mCodec->releaseOutputBuffer(index);
515}
516
Andy McFadden2621e402013-02-19 07:29:21 -0800517status_t JMediaCodec::signalEndOfInputStream() {
518 return mCodec->signalEndOfInputStream();
519}
520
Lajos Molnard4023112014-07-11 15:12:59 -0700521status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800522 sp<AMessage> msg;
523 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700524 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
525 if (err != OK) {
526 return err;
527 }
528
529 return ConvertMessageToMap(env, msg, format);
530}
531
532status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
533 sp<AMessage> msg;
534 status_t err;
535 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800536 return err;
537 }
538
539 return ConvertMessageToMap(env, msg, format);
540}
541
542status_t JMediaCodec::getBuffers(
543 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900544 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800545
546 status_t err =
547 input
548 ? mCodec->getInputBuffers(&buffers)
549 : mCodec->getOutputBuffers(&buffers);
550
551 if (err != OK) {
552 return err;
553 }
554
Andreas Huber88572f72012-02-21 11:47:18 -0800555 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800556 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800557 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800558 return NO_MEMORY;
559 }
Andreas Huber88572f72012-02-21 11:47:18 -0800560
561 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900562 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800563
Lajos Molnar7de28d32014-07-25 07:51:02 -0700564 jobject byteBuffer = NULL;
565 err = createByteBufferFromABuffer(
566 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
567 if (err != OK) {
568 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800569 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700570 if (byteBuffer != NULL) {
571 env->SetObjectArrayElement(
572 *bufArray, i, byteBuffer);
573
Lajos Molnard4023112014-07-11 15:12:59 -0700574 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700575 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700576 }
Andreas Huber88572f72012-02-21 11:47:18 -0800577 }
578
Lajos Molnar7de28d32014-07-25 07:51:02 -0700579 return OK;
580}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700581
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800582template <typename T>
583static jobject CreateByteBuffer(
584 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
585 bool readOnly, bool clearBuffer) {
586 jobject byteBuffer =
587 env->NewDirectByteBuffer(
588 const_cast<typename std::remove_const<T>::type *>(base),
589 capacity);
590 if (readOnly && byteBuffer != NULL) {
591 jobject readOnlyBuffer = env->CallObjectMethod(
592 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
593 env->DeleteLocalRef(byteBuffer);
594 byteBuffer = readOnlyBuffer;
595 }
596 if (byteBuffer == NULL) {
597 return nullptr;
598 }
599 jobject me = env->CallObjectMethod(
600 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
601 env->DeleteLocalRef(me);
602 me = env->CallObjectMethod(
603 byteBuffer, gByteBufferInfo.limitId,
604 clearBuffer ? capacity : offset + size);
605 env->DeleteLocalRef(me);
606 me = env->CallObjectMethod(
607 byteBuffer, gByteBufferInfo.positionId,
608 clearBuffer ? 0 : offset);
609 env->DeleteLocalRef(me);
610 me = NULL;
611 return byteBuffer;
612}
613
614
Lajos Molnar7de28d32014-07-25 07:51:02 -0700615// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900616template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700617status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900618 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700619 jobject *buf) const {
620 // if this is an ABuffer that doesn't actually hold any accessible memory,
621 // use a null ByteBuffer
622 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700623
624 if (buffer == NULL) {
625 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
626 return OK;
627 }
628
Lajos Molnar7de28d32014-07-25 07:51:02 -0700629 if (buffer->base() == NULL) {
630 return OK;
631 }
632
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800633 jobject byteBuffer = CreateByteBuffer(
634 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
635 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700636
637 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800638 return OK;
639}
640
Lajos Molnard4023112014-07-11 15:12:59 -0700641status_t JMediaCodec::getBuffer(
642 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900643 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700644
645 status_t err =
646 input
647 ? mCodec->getInputBuffer(index, &buffer)
648 : mCodec->getOutputBuffer(index, &buffer);
649
650 if (err != OK) {
651 return err;
652 }
653
Lajos Molnar7de28d32014-07-25 07:51:02 -0700654 return createByteBufferFromABuffer(
655 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700656}
657
658status_t JMediaCodec::getImage(
659 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900660 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700661
662 status_t err =
663 input
664 ? mCodec->getInputBuffer(index, &buffer)
665 : mCodec->getOutputBuffer(index, &buffer);
666
667 if (err != OK) {
668 return err;
669 }
670
671 // if this is an ABuffer that doesn't actually hold any accessible memory,
672 // use a null ByteBuffer
673 *buf = NULL;
674 if (buffer->base() == NULL) {
675 return OK;
676 }
677
678 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700679 sp<ABuffer> imageData;
680 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700681 return OK;
682 }
683
Lajos Molnar7de28d32014-07-25 07:51:02 -0700684 int64_t timestamp = 0;
685 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
686 timestamp *= 1000; // adjust to ns
687 }
688
689 jobject byteBuffer = NULL;
690 err = createByteBufferFromABuffer(
691 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
692 if (err != OK) {
693 return OK;
694 }
695
696 jobject infoBuffer = NULL;
697 err = createByteBufferFromABuffer(
698 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
699 if (err != OK) {
700 env->DeleteLocalRef(byteBuffer);
701 byteBuffer = NULL;
702 return OK;
703 }
704
705 jobject cropRect = NULL;
706 int32_t left, top, right, bottom;
707 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
708 ScopedLocalRef<jclass> rectClazz(
709 env, env->FindClass("android/graphics/Rect"));
710 CHECK(rectClazz.get() != NULL);
711
712 jmethodID rectConstructID = env->GetMethodID(
713 rectClazz.get(), "<init>", "(IIII)V");
714
715 cropRect = env->NewObject(
716 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
717 }
718
719 ScopedLocalRef<jclass> imageClazz(
720 env, env->FindClass("android/media/MediaCodec$MediaImage"));
721 CHECK(imageClazz.get() != NULL);
722
723 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
724 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
725
726 *buf = env->NewObject(imageClazz.get(), imageConstructID,
727 byteBuffer, infoBuffer,
728 (jboolean)!input /* readOnly */,
729 (jlong)timestamp,
730 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
731
732 // if MediaImage creation fails, return null
733 if (env->ExceptionCheck()) {
734 env->ExceptionDescribe();
735 env->ExceptionClear();
736 *buf = NULL;
737 }
738
739 if (cropRect != NULL) {
740 env->DeleteLocalRef(cropRect);
741 cropRect = NULL;
742 }
743
744 env->DeleteLocalRef(byteBuffer);
745 byteBuffer = NULL;
746
747 env->DeleteLocalRef(infoBuffer);
748 infoBuffer = NULL;
749
Lajos Molnard4023112014-07-11 15:12:59 -0700750 return OK;
751}
752
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800753status_t JMediaCodec::getOutputFrame(
754 JNIEnv *env, jobject frame, size_t index) const {
755 sp<MediaCodecBuffer> buffer;
756
757 status_t err = mCodec->getOutputBuffer(index, &buffer);
758 if (err != OK) {
759 return err;
760 }
761
762 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800763 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800764 if (c2Buffer) {
765 switch (c2Buffer->data().type()) {
766 case C2BufferData::LINEAR: {
767 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700768 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800769 context->mBuffer = c2Buffer;
770 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
771 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800772 env->CallVoidMethod(
773 linearBlock.get(),
774 gLinearBlockInfo.setInternalStateId,
775 (jlong)context.release(),
776 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800777 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
778 break;
779 }
780 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800781 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
782 uint32_t width, height, format, stride, igbp_slot, generation;
783 uint64_t usage, igbp_id;
784 _UnwrapNativeCodec2GrallocMetadata(
785 c2Handle, &width, &height, &format, &usage, &stride, &generation,
786 &igbp_id, &igbp_slot);
787 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
788 GraphicBuffer* graphicBuffer = new GraphicBuffer(
789 grallocHandle, GraphicBuffer::CLONE_HANDLE,
790 width, height, format, 1, usage, stride);
791 ScopedLocalRef<jobject> hardwareBuffer{
792 env,
793 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
794 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
795 env->SetObjectField(
796 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800797 break;
798 }
799 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
800 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
801 case C2BufferData::INVALID: [[fallthrough]];
802 default:
803 return INVALID_OPERATION;
804 }
805 } else {
806 if (!mGraphicOutput) {
807 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700808 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800809 context->mLegacyBuffer = buffer;
810 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
811 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800812 env->CallVoidMethod(
813 linearBlock.get(),
814 gLinearBlockInfo.setInternalStateId,
815 (jlong)context.release(),
816 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800817 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
818 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800819 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800820 }
821 }
822 }
823
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700824 jobject formatMap;
825 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800826 if (err != OK) {
827 return err;
828 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700829 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
830 ScopedLocalRef<jobject> format{env, env->NewObject(
831 mediaFormatClass.get(),
832 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
833 formatMap)};
834 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
835 env->DeleteLocalRef(formatMap);
836 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800837
838 sp<RefBase> obj;
839 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
840 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
841 (decltype(changedKeys.get()))obj.get()};
842 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
843 frame, gFields.outputFrameChangedKeysID)};
844 for (const std::string &key : changedKeys->value) {
845 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
846 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
847 }
848 }
849 return OK;
850}
851
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300852status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
853 AString name;
854
855 status_t err = mCodec->getName(&name);
856
857 if (err != OK) {
858 return err;
859 }
860
861 *nameStr = env->NewStringUTF(name.c_str());
862
863 return OK;
864}
865
Chong Zhanga0b72a62018-02-28 18:46:26 -0800866static jobject getCodecCapabilitiesObject(
867 JNIEnv *env, const char *mime, bool isEncoder,
868 const sp<MediaCodecInfo::Capabilities> &capabilities) {
869 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
870 Vector<uint32_t> colorFormats;
871
872 sp<AMessage> defaultFormat = new AMessage();
873 defaultFormat->setString("mime", mime);
874
875 capabilities->getSupportedColorFormats(&colorFormats);
876 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800877 sp<AMessage> details = capabilities->getDetails();
878
879 jobject defaultFormatObj = NULL;
880 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
881 return NULL;
882 }
883 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
884
885 jobject detailsObj = NULL;
886 if (ConvertMessageToMap(env, details, &detailsObj)) {
887 return NULL;
888 }
889 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
890
891 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
892 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
893
894 for (size_t i = 0; i < profileLevels.size(); ++i) {
895 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
896
897 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
898 gCodecInfo.profileLevelClazz));
899
900 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
901 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
902
903 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
904 }
905
906 ScopedLocalRef<jintArray> colorFormatsArray(
907 env, env->NewIntArray(colorFormats.size()));
908 for (size_t i = 0; i < colorFormats.size(); ++i) {
909 jint val = colorFormats.itemAt(i);
910 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
911 }
912
913 return env->NewObject(
914 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800915 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800916 defaultFormatRef.get(), detailsRef.get());
917}
918
919status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
920 sp<MediaCodecInfo> codecInfo;
921
922 status_t err = mCodec->getCodecInfo(&codecInfo);
923
924 if (err != OK) {
925 return err;
926 }
927
928 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800929 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800930
Lajos Molnard2a7f472018-11-15 12:49:20 -0800931 ScopedLocalRef<jstring> canonicalNameObject(env,
932 env->NewStringUTF(codecInfo->getCodecName()));
933
934 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800935 bool isEncoder = codecInfo->isEncoder();
936
Lajos Molnard2a7f472018-11-15 12:49:20 -0800937 Vector<AString> mediaTypes;
938 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800939
940 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800941 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800942
Lajos Molnard2a7f472018-11-15 12:49:20 -0800943 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800944 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800945 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800946
947 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800948 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800949
950 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
951 }
952
953 ScopedLocalRef<jclass> codecInfoClazz(env,
954 env->FindClass("android/media/MediaCodecInfo"));
955 CHECK(codecInfoClazz.get() != NULL);
956
957 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800958 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800959
960 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800961 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800962
963 return OK;
964}
965
Ray Essick81fbc5b2019-12-07 06:24:59 -0800966status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
967 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700968 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700969 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800970 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800971 return status;
972}
973
Andreas Huber226065b2013-08-12 10:14:11 -0700974status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
975 return mCodec->setParameters(msg);
976}
977
Andreas Huberb12a5392012-04-30 14:18:33 -0700978void JMediaCodec::setVideoScalingMode(int mode) {
979 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700980 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700981 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700982 // also signal via param for components that queue to IGBP
983 sp<AMessage> msg = new AMessage;
984 msg->setInt32("android._video-scaling", mode);
985 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700986 }
987}
988
ybai5e053202018-11-01 13:02:15 +0800989void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
990 sp<AMessage> msg = new AMessage;
991 msg->setInt32("audio-presentation-presentation-id", presentationId);
992 msg->setInt32("audio-presentation-program-id", programId);
993 (void)mCodec->setParameters(msg);
994}
995
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700996status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
997 std::vector<std::string> names;
998 status_t status = mCodec->querySupportedVendorParameters(&names);
999 if (status != OK) {
1000 return status;
1001 }
1002 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
1003 for (const std::string &name : names) {
1004 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
1005 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
1006 }
1007 return OK;
1008}
1009
1010status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
1011 const char *tmp = env->GetStringUTFChars(name, nullptr);
1012 CodecParameterDescriptor desc;
1013 status_t status = mCodec->describeParameter(tmp, &desc);
1014 env->ReleaseStringUTFChars(name, tmp);
1015 if (status != OK) {
1016 return status;
1017 }
1018 jint type = TYPE_NULL;
1019 switch (desc.type) {
1020 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
1021 case AMessage::kTypeSize:
1022 case AMessage::kTypeInt64: type = TYPE_LONG; break;
1023 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
1024 case AMessage::kTypeString: type = TYPE_STRING; break;
1025 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
1026 default: type = TYPE_NULL; break;
1027 }
1028 if (type == TYPE_NULL) {
1029 return BAD_VALUE;
1030 }
1031 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1032 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1033 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1034 return OK;
1035}
1036
1037static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1038 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1039 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1040 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1041 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1042 jobject it = env->CallObjectMethod(
1043 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1044 while (env->CallBooleanMethod(it, hasNextID)) {
1045 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1046 const char *tmp = env->GetStringUTFChars(name, nullptr);
1047 vec->push_back(tmp);
1048 env->ReleaseStringUTFChars(name, tmp);
1049 }
1050}
1051
1052status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1053 std::vector<std::string> names;
1054 BuildVectorFromList(env, namesObj, &names);
1055 return mCodec->subscribeToVendorParameters(names);
1056}
1057
1058status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1059 std::vector<std::string> names;
1060 BuildVectorFromList(env, namesObj, &names);
1061 return mCodec->unsubscribeFromVendorParameters(names);
1062}
1063
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001064static jthrowable createCodecException(
1065 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1066 ScopedLocalRef<jclass> clazz(
1067 env, env->FindClass("android/media/MediaCodec$CodecException"));
1068 CHECK(clazz.get() != NULL);
1069
Ronghua Wuc53ad692015-05-08 14:40:49 -07001070 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001071 CHECK(ctor != NULL);
1072
1073 ScopedLocalRef<jstring> msgObj(
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00001074 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001075
1076 // translate action code to Java equivalent
1077 switch (actionCode) {
1078 case ACTION_CODE_TRANSIENT:
1079 actionCode = gCodecActionCodes.codecActionTransient;
1080 break;
1081 case ACTION_CODE_RECOVERABLE:
1082 actionCode = gCodecActionCodes.codecActionRecoverable;
1083 break;
1084 default:
1085 actionCode = 0; // everything else is fatal
1086 break;
1087 }
1088
Ronghua Wuc53ad692015-05-08 14:40:49 -07001089 /* translate OS errors to Java API CodecException errorCodes */
1090 switch (err) {
1091 case NO_MEMORY:
1092 err = gCodecErrorCodes.errorInsufficientResource;
1093 break;
1094 case DEAD_OBJECT:
1095 err = gCodecErrorCodes.errorReclaimed;
1096 break;
1097 default: /* Other error codes go out as is. */
1098 break;
1099 }
1100
1101 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001102}
1103
Arun Johnson5a4c7332022-12-17 00:47:06 +00001104static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1105 const sp<AMessage> & msg) {
1106 if(msg == nullptr || obj == nullptr) {
1107 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1108 return;
1109 }
1110 size_t numSubSamples = 0;
1111 sp<ABuffer> subSamplesBuffer;
1112 sp<ABuffer> keyBuffer;
1113 sp<ABuffer> ivBuffer;
1114 CryptoPlugin::Mode mode;
1115 CryptoPlugin::Pattern pattern;
1116 CHECK(msg->findInt32("mode", (int*)&mode));
1117 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1118 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1119 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1120 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1121 CHECK(msg->findBuffer("iv", &ivBuffer));
1122 CHECK(msg->findBuffer("key", &keyBuffer));
1123
1124 // subsamples
1125 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1126 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1127 jboolean isCopy;
1128 jint *dstEncryptedSamples =
1129 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1130 jint * dstClearSamples =
1131 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1132
1133 CryptoPlugin::SubSample * samplesArray =
1134 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1135
1136 for(int i = 0 ; i < numSubSamples ; i++) {
1137 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1138 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1139 }
1140 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1141 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1142 // key and iv
1143 jbyteArray keyArray = NULL;
1144 jbyteArray ivArray = NULL;
1145 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1146 keyArray = env->NewByteArray(keyBuffer->size());
1147 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1148 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1149 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1150 }
1151 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1152 ivArray = env->NewByteArray(ivBuffer->size());
1153 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1154 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1155 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1156 }
1157 // set samples, key and iv
1158 env->CallVoidMethod(
1159 obj,
1160 gFields.cryptoInfoSetID,
1161 (jint)numSubSamples,
1162 samplesOfClearDataArr.get(),
1163 samplesOfEncryptedDataArr.get(),
1164 keyArray,
1165 ivArray,
1166 mode);
1167 if (keyArray != NULL) {
1168 env->DeleteLocalRef(keyArray);
1169 }
1170 if (ivArray != NULL) {
1171 env->DeleteLocalRef(ivArray);
1172 }
1173 // set pattern
1174 env->CallVoidMethod(
1175 obj,
1176 gFields.cryptoInfoSetPatternID,
1177 pattern.mEncryptBlocks,
1178 pattern.mSkipBlocks);
1179}
1180
1181static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1182 switch(err) {
1183 case ERROR_DRM_NO_LICENSE:
1184 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1185 defaultMsg = "Crypto key not available";
1186 break;
1187 case ERROR_DRM_LICENSE_EXPIRED:
1188 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1189 defaultMsg = "License expired";
1190 break;
1191 case ERROR_DRM_RESOURCE_BUSY:
1192 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1193 defaultMsg = "Resource busy or unavailable";
1194 break;
1195 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1196 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1197 defaultMsg = "Required output protections are not active";
1198 break;
1199 case ERROR_DRM_SESSION_NOT_OPENED:
1200 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1201 defaultMsg = "Attempted to use a closed session";
1202 break;
1203 case ERROR_DRM_INSUFFICIENT_SECURITY:
1204 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1205 defaultMsg = "Required security level is not met";
1206 break;
1207 case ERROR_DRM_CANNOT_HANDLE:
1208 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1209 defaultMsg = "Operation not supported in this configuration";
1210 break;
1211 case ERROR_DRM_FRAME_TOO_LARGE:
1212 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1213 defaultMsg = "Decrytped frame exceeds size of output buffer";
1214 break;
1215 case ERROR_DRM_SESSION_LOST_STATE:
1216 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1217 defaultMsg = "Session state was lost, open a new session and retry";
1218 break;
1219 default: // Other negative DRM error codes go out best-effort.
1220 jerr = MediaErrorToJavaError(err);
1221 defaultMsg = StrCryptoError(err);
1222 break;
1223 }
1224}
1225static jthrowable createCryptoException(JNIEnv *env, status_t err,
1226 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1227 const sp<AMessage> & cryptoInfo = NULL) {
1228 jthrowable exception = nullptr;
1229 jmethodID constructID = nullptr;
1230 ScopedLocalRef<jobject> cryptoInfoObject(env);
1231 std::string defaultMsg = "Unknown Error";
1232 jint jerr = 0;
1233 // Get a class ref for CryptoException
1234 ScopedLocalRef<jclass> clazz(
1235 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1236 CHECK(clazz.get() != NULL);
1237
1238 // Get constructor ref for CryptoException
1239 constructID = env->GetMethodID(clazz.get(), "<init>",
1240 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1241 CHECK(constructID != NULL);
1242
1243 // create detailed message for exception
1244 CryptoErrorToJavaError(err, jerr, defaultMsg);
1245 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1246 DrmStatus dStatus(err, originalMsg.c_str());
1247 std::string detailedMsg(
1248 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1249 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1250
1251 if (cryptoInfo != nullptr) {
1252 // Class ref for CryptoInfo
1253 ScopedLocalRef<jclass> clazzCryptoInfo(
1254 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1255 CHECK(clazzCryptoInfo.get() != NULL);
1256
1257 // Constructor reference for CryptoInfo
1258 jmethodID constructCryptoInfo =
1259 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1260 CHECK(constructCryptoInfo != NULL);
1261
1262 // Create CryptoInfo jobject
1263 cryptoInfoObject.reset(
1264 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1265 CHECK(cryptoInfoObject.get() != NULL);
1266
1267 // Translate AMesage to CryptoInfo
1268 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1269 }
1270
1271 exception = (jthrowable)env->NewObject(
1272 clazz.get(), constructID, msgObj, jerr,
1273 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1274 cryptoInfoObject.get());
1275
1276 return exception;
1277}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001278void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1279 int32_t arg1, arg2 = 0;
1280 jobject obj = NULL;
Arun Johnson206270e2023-10-31 20:40:12 +00001281 std::vector<jobject> jObjectInfos;
Chong Zhang8d5e5562014-07-08 18:49:21 -07001282 CHECK(msg->findInt32("callbackID", &arg1));
1283 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001284
Chong Zhang8d5e5562014-07-08 18:49:21 -07001285 switch (arg1) {
1286 case MediaCodec::CB_INPUT_AVAILABLE:
1287 {
1288 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001289 break;
1290 }
1291
Chong Zhang8d5e5562014-07-08 18:49:21 -07001292 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001293 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001294 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001295
Chong Zhang8d5e5562014-07-08 18:49:21 -07001296 size_t size, offset;
1297 int64_t timeUs;
1298 uint32_t flags;
1299 CHECK(msg->findSize("size", &size));
1300 CHECK(msg->findSize("offset", &offset));
1301 CHECK(msg->findInt64("timeUs", &timeUs));
1302 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1303
Pavel Laboviche53421b2022-11-01 03:53:27 +00001304 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001305 if (obj == NULL) {
1306 if (env->ExceptionCheck()) {
1307 ALOGE("Could not create MediaCodec.BufferInfo.");
1308 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001309 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001310 jniThrowException(env, "java/lang/IllegalStateException",
1311 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001312 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001313 }
1314
Pavel Laboviche53421b2022-11-01 03:53:27 +00001315 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001316 break;
1317 }
1318
Arun Johnson206270e2023-10-31 20:40:12 +00001319 case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
1320 {
1321 sp<RefBase> spobj = nullptr;
1322 CHECK(msg->findInt32("index", &arg2));
1323 CHECK(msg->findObject("accessUnitInfo", &spobj));
1324 if (spobj != nullptr) {
1325 sp<BufferInfosWrapper> bufferInfoParamsWrapper {
1326 (BufferInfosWrapper *)spobj.get()};
1327 std::vector<AccessUnitInfo> &bufferInfoParams =
1328 bufferInfoParamsWrapper.get()->value;
1329 obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
1330 jint offset = 0;
1331 for (int i = 0 ; i < bufferInfoParams.size(); i++) {
1332 jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1333 if (bufferInfo != NULL) {
1334 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
1335 offset,
1336 (jint)(bufferInfoParams)[i].mSize,
1337 (bufferInfoParams)[i].mTimestamp,
1338 (bufferInfoParams)[i].mFlags);
1339 (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
1340 offset += (bufferInfoParams)[i].mSize;
1341 jObjectInfos.push_back(bufferInfo);
1342 }
1343 }
1344 }
1345 break;
1346 }
1347
Arun Johnson5a4c7332022-12-17 00:47:06 +00001348 case MediaCodec::CB_CRYPTO_ERROR:
1349 {
1350 int32_t err, actionCode;
1351 AString errorDetail;
1352 CHECK(msg->findInt32("err", &err));
1353 CHECK(msg->findInt32("actionCode",&actionCode));
1354 CHECK(msg->findString("errorDetail", &errorDetail));
1355 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1356 break;
1357 }
1358
Chong Zhang8d5e5562014-07-08 18:49:21 -07001359 case MediaCodec::CB_ERROR:
1360 {
Chong Zhang94686d12014-07-11 15:53:58 -07001361 int32_t err, actionCode;
1362 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001363 CHECK(msg->findInt32("actionCode", &actionCode));
1364
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001365 // note that DRM errors could conceivably alias into a CodecException
1366 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001367
1368 if (obj == NULL) {
1369 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001370 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001371 env->ExceptionClear();
1372 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001373 jniThrowException(env, "java/lang/IllegalStateException",
1374 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001375 return;
1376 }
Andreas Huberaba67132013-10-22 12:40:01 -07001377
1378 break;
1379 }
1380
Chong Zhang8d5e5562014-07-08 18:49:21 -07001381 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001382 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001383 sp<AMessage> format;
1384 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001385
Chong Zhang8d5e5562014-07-08 18:49:21 -07001386 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001387 jniThrowException(env, "java/lang/IllegalStateException",
1388 "Fatal error: failed to convert format "
1389 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001390 return;
1391 }
Andreas Huberaba67132013-10-22 12:40:01 -07001392
Andreas Huberaba67132013-10-22 12:40:01 -07001393 break;
1394 }
1395
1396 default:
1397 TRESPASS();
1398 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001399 env->CallVoidMethod(
1400 mObject,
1401 gFields.postEventFromNativeID,
1402 EVENT_CALLBACK,
1403 arg1,
1404 arg2,
1405 obj);
1406
Arun Johnson206270e2023-10-31 20:40:12 +00001407 for (int i = 0; i < jObjectInfos.size(); i++) {
1408 env->DeleteLocalRef(jObjectInfos[i]);
1409 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001410 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001411}
1412
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001413void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1414 int32_t arg1 = 0, arg2 = 0;
1415 jobject obj = NULL;
1416 JNIEnv *env = AndroidRuntime::getJNIEnv();
1417
1418 sp<AMessage> data;
1419 CHECK(msg->findMessage("data", &data));
1420
1421 status_t err = ConvertMessageToMap(env, data, &obj);
1422 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001423 jniThrowException(env, "java/lang/IllegalStateException",
1424 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001425 return;
1426 }
1427
1428 env->CallVoidMethod(
1429 mObject, gFields.postEventFromNativeID,
1430 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1431
1432 env->DeleteLocalRef(obj);
1433}
1434
Lajos Molnard8578572015-06-05 20:17:33 -07001435void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1436 int32_t arg1 = 0, arg2 = 0;
1437 jobject obj = NULL;
1438 JNIEnv *env = AndroidRuntime::getJNIEnv();
1439
1440 sp<AMessage> data;
1441 CHECK(msg->findMessage("data", &data));
1442
1443 status_t err = ConvertMessageToMap(env, data, &obj);
1444 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001445 jniThrowException(env, "java/lang/IllegalStateException",
1446 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001447 return;
1448 }
1449
1450 env->CallVoidMethod(
1451 mObject, gFields.postEventFromNativeID,
1452 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1453
1454 env->DeleteLocalRef(obj);
1455}
1456
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001457std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1458 if (mCodec == nullptr) {
1459 return msg ?: "";
1460 }
1461 std::string prefix = "";
1462 if (msg && msg[0] != '\0') {
1463 prefix.append(msg);
1464 prefix.append("\n");
1465 }
1466 return prefix + mCodec->getErrorLog().extract();
1467}
1468
Chong Zhang8d5e5562014-07-08 18:49:21 -07001469void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1470 switch (msg->what()) {
1471 case kWhatCallbackNotify:
1472 {
1473 handleCallback(msg);
1474 break;
1475 }
Lajos Molnard8578572015-06-05 20:17:33 -07001476 case kWhatFrameRendered:
1477 {
1478 handleFrameRenderedNotification(msg);
1479 break;
1480 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001481 case kWhatAsyncReleaseComplete:
1482 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001483 if (mLooper != NULL) {
1484 mLooper->unregisterHandler(id());
1485 mLooper->stop();
1486 mLooper.clear();
1487 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001488 break;
1489 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001490 case kWhatFirstTunnelFrameReady:
1491 {
1492 handleFirstTunnelFrameReadyNotification(msg);
1493 break;
1494 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001495 default:
1496 TRESPASS();
1497 }
Andreas Huberaba67132013-10-22 12:40:01 -07001498}
1499
Robert Shih631a80d2021-02-14 02:23:55 -08001500
Andreas Huber88572f72012-02-21 11:47:18 -08001501} // namespace android
1502
1503////////////////////////////////////////////////////////////////////////////////
1504
1505using namespace android;
1506
1507static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001508 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001509 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001510 if (codec != NULL) {
1511 codec->incStrong(thiz);
1512 }
1513 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001514 /* release MediaCodec and stop the looper now before decStrong.
1515 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1516 * its message handler, doing release() from there will deadlock
1517 * (as MediaCodec::release() post synchronous message to the same looper)
1518 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001519 if (release) {
1520 old->release();
1521 }
Andreas Huber88572f72012-02-21 11:47:18 -08001522 old->decStrong(thiz);
1523 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001524 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001525
1526 return old;
1527}
1528
1529static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001530 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1531 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1532 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001533}
1534
1535static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001536 // Clear Java native reference.
1537 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001538 if (codec != NULL) {
1539 codec->releaseAsync();
1540 }
Andreas Huber88572f72012-02-21 11:47:18 -08001541}
1542
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001543static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1544 jthrowable exception = createCodecException(env, err, actionCode, msg);
1545 env->Throw(exception);
1546}
1547
Robert Shih631a80d2021-02-14 02:23:55 -08001548static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1549 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001550 jthrowable exception = createCryptoException(
1551 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001552 env->Throw(exception);
1553}
1554
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001555static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1556 if (codec == NULL) {
1557 return msg ?: "codec is released already";
1558 }
1559 return codec->getExceptionMessage(msg);
1560}
1561
Andreas Huberbfc56f42012-04-19 12:47:07 -07001562static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001563 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001564 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1565 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001566 switch (err) {
1567 case OK:
1568 return 0;
1569
1570 case -EAGAIN:
1571 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1572
1573 case INFO_FORMAT_CHANGED:
1574 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1575
1576 case INFO_OUTPUT_BUFFERS_CHANGED:
1577 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1578
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001579 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001580 jniThrowException(
1581 env, "java/lang/IllegalStateException",
1582 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001583 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001584
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001585 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001586 jniThrowException(
1587 env, "java/lang/IllegalArgumentException",
1588 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001589 return 0;
1590
Andreas Huber88572f72012-02-21 11:47:18 -08001591 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001592 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001593 throwCryptoException(
1594 env, err,
1595 GetExceptionMessage(codec, msg).c_str(),
1596 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001597 return 0;
1598 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001599 throwCodecException(
1600 env, err, actionCode,
1601 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001602 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001603 }
Andreas Huber88572f72012-02-21 11:47:18 -08001604}
1605
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001606static jint throwExceptionAsNecessary(
1607 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1608 int32_t actionCode = ACTION_CODE_FATAL) {
1609 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1610}
1611
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001612static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1613 JNIEnv *env,
1614 jobject thiz,
1615 jboolean enabled) {
1616 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1617
1618 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001619 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001620 return;
1621 }
1622
1623 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1624
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001625 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001626}
1627
Lajos Molnard8578572015-06-05 20:17:33 -07001628static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1629 JNIEnv *env,
1630 jobject thiz,
1631 jboolean enabled) {
1632 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1633
Wonsik Kim24e53802020-05-08 20:04:26 -07001634 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001635 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001636 return;
1637 }
1638
1639 status_t err = codec->enableOnFrameRenderedListener(enabled);
1640
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001641 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001642}
1643
Chong Zhang8d5e5562014-07-08 18:49:21 -07001644static void android_media_MediaCodec_native_setCallback(
1645 JNIEnv *env,
1646 jobject thiz,
1647 jobject cb) {
1648 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1649
Wonsik Kim24e53802020-05-08 20:04:26 -07001650 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001651 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001652 return;
1653 }
1654
1655 status_t err = codec->setCallback(cb);
1656
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001657 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001658}
1659
Andreas Huber88572f72012-02-21 11:47:18 -08001660static void android_media_MediaCodec_native_configure(
1661 JNIEnv *env,
1662 jobject thiz,
1663 jobjectArray keys, jobjectArray values,
1664 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001665 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001666 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001667 jint flags) {
1668 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1669
Wonsik Kim24e53802020-05-08 20:04:26 -07001670 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001671 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001672 return;
1673 }
1674
1675 sp<AMessage> format;
1676 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1677
1678 if (err != OK) {
1679 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1680 return;
1681 }
1682
Andy McFaddend47f7d82012-12-18 09:48:38 -08001683 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001684 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001685 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001686 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001687 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001688 } else {
1689 jniThrowException(
1690 env,
1691 "java/lang/IllegalArgumentException",
1692 "The surface has been released");
1693 return;
1694 }
1695 }
1696
Andreas Huber8240d922012-04-04 14:06:32 -07001697 sp<ICrypto> crypto;
1698 if (jcrypto != NULL) {
1699 crypto = JCrypto::GetCrypto(env, jcrypto);
1700 }
1701
Chong Zhangd5927ae2017-01-03 11:07:18 -08001702 sp<IDescrambler> descrambler;
1703 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001704 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001705 }
1706
1707 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001708
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001709 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001710}
1711
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001712static void android_media_MediaCodec_native_setSurface(
1713 JNIEnv *env,
1714 jobject thiz,
1715 jobject jsurface) {
1716 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1717
Wonsik Kim24e53802020-05-08 20:04:26 -07001718 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001719 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001720 return;
1721 }
1722
1723 sp<IGraphicBufferProducer> bufferProducer;
1724 if (jsurface != NULL) {
1725 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1726 if (surface != NULL) {
1727 bufferProducer = surface->getIGraphicBufferProducer();
1728 } else {
1729 jniThrowException(
1730 env,
1731 "java/lang/IllegalArgumentException",
1732 "The surface has been released");
1733 return;
1734 }
1735 }
1736
1737 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001738 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001739}
1740
Chong Zhang8034d602015-04-28 13:38:48 -07001741sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1742 JNIEnv* env, jobject object) {
1743 sp<PersistentSurface> persistentSurface;
1744
1745 jobject lock = env->GetObjectField(
1746 object, gPersistentSurfaceClassInfo.mLock);
1747 if (env->MonitorEnter(lock) == JNI_OK) {
1748 persistentSurface = reinterpret_cast<PersistentSurface *>(
1749 env->GetLongField(object,
1750 gPersistentSurfaceClassInfo.mPersistentObject));
1751 env->MonitorExit(lock);
1752 }
1753 env->DeleteLocalRef(lock);
1754
1755 return persistentSurface;
1756}
1757
1758static jobject android_media_MediaCodec_createPersistentInputSurface(
1759 JNIEnv* env, jclass /* clazz */) {
1760 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1761 sp<PersistentSurface> persistentSurface =
1762 MediaCodec::CreatePersistentInputSurface();
1763
1764 if (persistentSurface == NULL) {
1765 return NULL;
1766 }
1767
1768 sp<Surface> surface = new Surface(
1769 persistentSurface->getBufferProducer(), true);
1770 if (surface == NULL) {
1771 return NULL;
1772 }
1773
1774 jobject object = env->NewObject(
1775 gPersistentSurfaceClassInfo.clazz,
1776 gPersistentSurfaceClassInfo.ctor);
1777
1778 if (object == NULL) {
1779 if (env->ExceptionCheck()) {
1780 ALOGE("Could not create PersistentSurface.");
1781 env->ExceptionClear();
1782 }
1783 return NULL;
1784 }
1785
1786 jobject lock = env->GetObjectField(
1787 object, gPersistentSurfaceClassInfo.mLock);
1788 if (env->MonitorEnter(lock) == JNI_OK) {
1789 env->CallVoidMethod(
1790 object,
1791 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1792 (jlong)surface.get());
1793 env->SetLongField(
1794 object,
1795 gPersistentSurfaceClassInfo.mPersistentObject,
1796 (jlong)persistentSurface.get());
1797 env->MonitorExit(lock);
1798 } else {
1799 env->DeleteLocalRef(object);
1800 object = NULL;
1801 }
1802 env->DeleteLocalRef(lock);
1803
1804 if (object != NULL) {
1805 surface->incStrong(&sRefBaseOwner);
1806 persistentSurface->incStrong(&sRefBaseOwner);
1807 }
1808
1809 return object;
1810}
1811
1812static void android_media_MediaCodec_releasePersistentInputSurface(
1813 JNIEnv* env, jclass /* clazz */, jobject object) {
1814 sp<PersistentSurface> persistentSurface;
1815
1816 jobject lock = env->GetObjectField(
1817 object, gPersistentSurfaceClassInfo.mLock);
1818 if (env->MonitorEnter(lock) == JNI_OK) {
1819 persistentSurface = reinterpret_cast<PersistentSurface *>(
1820 env->GetLongField(
1821 object, gPersistentSurfaceClassInfo.mPersistentObject));
1822 env->SetLongField(
1823 object,
1824 gPersistentSurfaceClassInfo.mPersistentObject,
1825 (jlong)0);
1826 env->MonitorExit(lock);
1827 }
1828 env->DeleteLocalRef(lock);
1829
1830 if (persistentSurface != NULL) {
1831 persistentSurface->decStrong(&sRefBaseOwner);
1832 }
1833 // no need to release surface as it will be released by Surface's jni
1834}
1835
Chong Zhang9560ddb2015-05-13 10:25:29 -07001836static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001837 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001838 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001839
1840 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001841 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001842 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001843 return;
1844 }
1845
1846 sp<PersistentSurface> persistentSurface =
1847 android_media_MediaCodec_getPersistentInputSurface(env, object);
1848
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001849 if (persistentSurface == NULL) {
1850 throwExceptionAsNecessary(
1851 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1852 return;
1853 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001854 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001855 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001856 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001857 }
1858}
1859
Andy McFadden2621e402013-02-19 07:29:21 -08001860static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1861 jobject thiz) {
1862 ALOGV("android_media_MediaCodec_createInputSurface");
1863
1864 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001865 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001866 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001867 return NULL;
1868 }
1869
1870 // Tell the MediaCodec that we want to use a Surface as input.
1871 sp<IGraphicBufferProducer> bufferProducer;
1872 status_t err = codec->createInputSurface(&bufferProducer);
1873 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001874 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001875 return NULL;
1876 }
1877
1878 // Wrap the IGBP in a Java-language Surface.
1879 return android_view_Surface_createFromIGraphicBufferProducer(env,
1880 bufferProducer);
1881}
1882
Andreas Huber88572f72012-02-21 11:47:18 -08001883static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1884 ALOGV("android_media_MediaCodec_start");
1885
1886 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1887
Wonsik Kim24e53802020-05-08 20:04:26 -07001888 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001889 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001890 return;
1891 }
1892
1893 status_t err = codec->start();
1894
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001895 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001896}
1897
1898static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1899 ALOGV("android_media_MediaCodec_stop");
1900
1901 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1902
Wonsik Kim24e53802020-05-08 20:04:26 -07001903 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001904 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001905 return;
1906 }
1907
1908 status_t err = codec->stop();
1909
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001910 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001911}
1912
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001913static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1914 ALOGV("android_media_MediaCodec_reset");
1915
1916 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1917
Wonsik Kim24e53802020-05-08 20:04:26 -07001918 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001919 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001920 return;
1921 }
1922
1923 status_t err = codec->reset();
1924 if (err != OK) {
1925 // treat all errors as fatal for now, though resource not available
1926 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001927 // we also should avoid sending INVALID_OPERATION here due to
1928 // the transitory nature of reset(), it should not inadvertently
1929 // trigger an IllegalStateException.
1930 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001931 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001932 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001933}
1934
Andreas Huber88572f72012-02-21 11:47:18 -08001935static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1936 ALOGV("android_media_MediaCodec_flush");
1937
1938 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1939
Wonsik Kim24e53802020-05-08 20:04:26 -07001940 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001941 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001942 return;
1943 }
1944
1945 status_t err = codec->flush();
1946
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001947 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001948}
1949
1950static void android_media_MediaCodec_queueInputBuffer(
1951 JNIEnv *env,
1952 jobject thiz,
1953 jint index,
1954 jint offset,
1955 jint size,
1956 jlong timestampUs,
1957 jint flags) {
1958 ALOGV("android_media_MediaCodec_queueInputBuffer");
1959
1960 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1961
Wonsik Kim24e53802020-05-08 20:04:26 -07001962 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001963 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001964 return;
1965 }
1966
Andreas Huberbfc56f42012-04-19 12:47:07 -07001967 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001968
Andreas Huberbfc56f42012-04-19 12:47:07 -07001969 status_t err = codec->queueInputBuffer(
1970 index, offset, size, timestampUs, flags, &errorDetailMsg);
1971
1972 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001973 env, err, ACTION_CODE_FATAL,
1974 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001975}
1976
Arun Johnson206270e2023-10-31 20:40:12 +00001977static status_t extractInfosFromObject(
1978 JNIEnv * const env,
1979 jint * const initialOffset,
1980 jint * const totalSize,
1981 std::vector<AccessUnitInfo> * const infos,
1982 const jobjectArray &objArray,
1983 AString * const errorDetailMsg) {
1984 if (totalSize == nullptr
1985 || initialOffset == nullptr
1986 || infos == nullptr) {
1987 if (errorDetailMsg) {
1988 *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
1989 }
1990 return BAD_VALUE;
1991 }
1992 const jsize numEntries = env->GetArrayLength(objArray);
1993 if (numEntries <= 0) {
1994 if (errorDetailMsg) {
1995 *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
1996 }
1997 return BAD_VALUE;
1998 }
1999 *initialOffset = 0;
2000 *totalSize = 0;
2001 for (jsize i = 0; i < numEntries; i++) {
2002 jobject param = env->GetObjectArrayElement(objArray, i);
2003 if (param == NULL) {
2004 if (errorDetailMsg) {
2005 *errorDetailMsg = "Error: Queuing a null BufferInfo";
2006 }
2007 return BAD_VALUE;
2008 }
2009 size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
2010 size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
2011 uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
2012 if (flags == 0 && size == 0) {
2013 if (errorDetailMsg) {
2014 *errorDetailMsg = "Error: Queuing an empty BufferInfo";
2015 }
2016 return BAD_VALUE;
2017 }
2018 if (i == 0) {
2019 *initialOffset = offset;
2020 }
2021 if (CC_UNLIKELY((offset > UINT32_MAX)
2022 || ((long)(offset + size) > UINT32_MAX)
2023 || ((offset - *initialOffset) != *totalSize))) {
2024 if (errorDetailMsg) {
2025 *errorDetailMsg = "Error: offset/size in BufferInfo";
2026 }
2027 return BAD_VALUE;
2028 }
2029 infos->emplace_back(
2030 flags,
2031 size,
2032 env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
2033 *totalSize += size;
2034 }
2035 return OK;
2036}
2037
2038static void android_media_MediaCodec_queueInputBuffers(
2039 JNIEnv *env,
2040 jobject thiz,
2041 jint index,
2042 jobjectArray objArray) {
2043 ALOGV("android_media_MediaCodec_queueInputBuffers");
2044 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2045 if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
2046 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2047 return;
2048 }
2049 sp<BufferInfosWrapper> infoObj =
2050 new BufferInfosWrapper{decltype(infoObj->value)()};
2051 AString errorDetailMsg;
2052 jint initialOffset = 0;
2053 jint totalSize = 0;
2054 status_t err = extractInfosFromObject(
2055 env,
2056 &initialOffset,
2057 &totalSize,
2058 &infoObj->value,
2059 objArray,
2060 &errorDetailMsg);
2061 if (err == OK) {
2062 err = codec->queueInputBuffers(
2063 index,
2064 initialOffset,
2065 totalSize,
2066 infoObj,
2067 &errorDetailMsg);
2068 }
2069 throwExceptionAsNecessary(
2070 env, err, ACTION_CODE_FATAL,
2071 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2072}
2073
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002074struct NativeCryptoInfo {
2075 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
2076 : mEnv{env},
2077 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
2078 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
2079 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2080
2081 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
2082 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
2083
2084 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
2085 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
2086
2087 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2088 if (jmode == gCryptoModes.Unencrypted) {
2089 mMode = CryptoPlugin::kMode_Unencrypted;
2090 } else if (jmode == gCryptoModes.AesCtr) {
2091 mMode = CryptoPlugin::kMode_AES_CTR;
2092 } else if (jmode == gCryptoModes.AesCbc) {
2093 mMode = CryptoPlugin::kMode_AES_CBC;
2094 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002095 throwExceptionAsNecessary(
2096 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2097 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002098 return;
2099 }
2100
2101 ScopedLocalRef<jobject> patternObj{
2102 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
2103
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002104 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002105 mPattern.mEncryptBlocks = 0;
2106 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002107 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002108 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002109 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002110 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002111 patternObj.get(), gFields.patternSkipBlocksID);
2112 }
2113
2114 mErr = OK;
2115 if (mNumSubSamples <= 0) {
2116 mErr = -EINVAL;
2117 } else if (numBytesOfClearDataObj == nullptr
2118 && numBytesOfEncryptedDataObj == nullptr) {
2119 mErr = -EINVAL;
2120 } else if (numBytesOfEncryptedDataObj != nullptr
2121 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
2122 mErr = -ERANGE;
2123 } else if (numBytesOfClearDataObj != nullptr
2124 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
2125 mErr = -ERANGE;
2126 // subSamples array may silently overflow if number of samples are too large. Use
2127 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2128 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
2129 mErr = -EINVAL;
2130 } else {
2131 jint *numBytesOfClearData =
2132 (numBytesOfClearDataObj == nullptr)
2133 ? nullptr
2134 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
2135
2136 jint *numBytesOfEncryptedData =
2137 (numBytesOfEncryptedDataObj == nullptr)
2138 ? nullptr
2139 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
2140
2141 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
2142
2143 for (jint i = 0; i < mNumSubSamples; ++i) {
2144 mSubSamples[i].mNumBytesOfClearData =
2145 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
2146
2147 mSubSamples[i].mNumBytesOfEncryptedData =
2148 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
2149 }
2150
2151 if (numBytesOfEncryptedData != nullptr) {
2152 env->ReleaseIntArrayElements(
2153 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
2154 numBytesOfEncryptedData = nullptr;
2155 }
2156
2157 if (numBytesOfClearData != nullptr) {
2158 env->ReleaseIntArrayElements(
2159 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2160 numBytesOfClearData = nullptr;
2161 }
2162 }
2163
2164 if (mErr == OK && mKeyObj.get() != nullptr) {
2165 if (env->GetArrayLength(mKeyObj.get()) != 16) {
2166 mErr = -EINVAL;
2167 } else {
2168 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2169 }
2170 }
2171
2172 if (mErr == OK && mIvObj.get() != nullptr) {
2173 if (env->GetArrayLength(mIvObj.get()) != 16) {
2174 mErr = -EINVAL;
2175 } else {
2176 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2177 }
2178 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002179
2180 }
2181
2182 explicit NativeCryptoInfo(jint size)
2183 : mIvObj{nullptr, nullptr},
2184 mKeyObj{nullptr, nullptr},
2185 mMode{CryptoPlugin::kMode_Unencrypted},
2186 mPattern{0, 0} {
2187 mSubSamples = new CryptoPlugin::SubSample[1];
2188 mNumSubSamples = 1;
2189 mSubSamples[0].mNumBytesOfClearData = size;
2190 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002191 }
2192
2193 ~NativeCryptoInfo() {
2194 if (mIv != nullptr) {
2195 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2196 }
2197
2198 if (mKey != nullptr) {
2199 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2200 }
2201
2202 if (mSubSamples != nullptr) {
2203 delete[] mSubSamples;
2204 }
2205 }
2206
2207 JNIEnv *mEnv{nullptr};
2208 ScopedLocalRef<jbyteArray> mIvObj;
2209 ScopedLocalRef<jbyteArray> mKeyObj;
2210 status_t mErr{OK};
2211
2212 CryptoPlugin::SubSample *mSubSamples{nullptr};
2213 int32_t mNumSubSamples{0};
2214 jbyte *mIv{nullptr};
2215 jbyte *mKey{nullptr};
2216 enum CryptoPlugin::Mode mMode;
2217 CryptoPlugin::Pattern mPattern;
2218};
2219
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002220static void android_media_MediaCodec_queueSecureInputBuffer(
2221 JNIEnv *env,
2222 jobject thiz,
2223 jint index,
2224 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002225 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002226 jlong timestampUs,
2227 jint flags) {
2228 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2229
2230 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2231
Wonsik Kim24e53802020-05-08 20:04:26 -07002232 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002233 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002234 return;
2235 }
2236
Wonsik Kim1cac4252020-01-24 11:45:37 -08002237 jint numSubSamples =
2238 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2239
2240 jintArray numBytesOfClearDataObj =
2241 (jintArray)env->GetObjectField(
2242 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2243
2244 jintArray numBytesOfEncryptedDataObj =
2245 (jintArray)env->GetObjectField(
2246 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2247
2248 jbyteArray keyObj =
2249 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2250
2251 jbyteArray ivObj =
2252 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2253
2254 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2255 enum CryptoPlugin::Mode mode;
2256 if (jmode == gCryptoModes.Unencrypted) {
2257 mode = CryptoPlugin::kMode_Unencrypted;
2258 } else if (jmode == gCryptoModes.AesCtr) {
2259 mode = CryptoPlugin::kMode_AES_CTR;
2260 } else if (jmode == gCryptoModes.AesCbc) {
2261 mode = CryptoPlugin::kMode_AES_CBC;
2262 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002263 throwExceptionAsNecessary(
2264 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2265 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08002266 return;
2267 }
2268
2269 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2270
2271 CryptoPlugin::Pattern pattern;
2272 if (patternObj == NULL) {
2273 pattern.mEncryptBlocks = 0;
2274 pattern.mSkipBlocks = 0;
2275 } else {
2276 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2277 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2278 }
2279
2280 status_t err = OK;
2281
2282 CryptoPlugin::SubSample *subSamples = NULL;
2283 jbyte *key = NULL;
2284 jbyte *iv = NULL;
2285
2286 if (numSubSamples <= 0) {
2287 err = -EINVAL;
2288 } else if (numBytesOfClearDataObj == NULL
2289 && numBytesOfEncryptedDataObj == NULL) {
2290 err = -EINVAL;
2291 } else if (numBytesOfEncryptedDataObj != NULL
2292 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2293 err = -ERANGE;
2294 } else if (numBytesOfClearDataObj != NULL
2295 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2296 err = -ERANGE;
2297 // subSamples array may silently overflow if number of samples are too large. Use
2298 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2299 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2300 err = -EINVAL;
2301 } else {
2302 jboolean isCopy;
2303
2304 jint *numBytesOfClearData =
2305 (numBytesOfClearDataObj == NULL)
2306 ? NULL
2307 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2308
2309 jint *numBytesOfEncryptedData =
2310 (numBytesOfEncryptedDataObj == NULL)
2311 ? NULL
2312 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2313
2314 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2315
2316 for (jint i = 0; i < numSubSamples; ++i) {
2317 subSamples[i].mNumBytesOfClearData =
2318 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2319
2320 subSamples[i].mNumBytesOfEncryptedData =
2321 (numBytesOfEncryptedData == NULL)
2322 ? 0 : numBytesOfEncryptedData[i];
2323 }
2324
2325 if (numBytesOfEncryptedData != NULL) {
2326 env->ReleaseIntArrayElements(
2327 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2328 numBytesOfEncryptedData = NULL;
2329 }
2330
2331 if (numBytesOfClearData != NULL) {
2332 env->ReleaseIntArrayElements(
2333 numBytesOfClearDataObj, numBytesOfClearData, 0);
2334 numBytesOfClearData = NULL;
2335 }
2336 }
2337
2338 if (err == OK && keyObj != NULL) {
2339 if (env->GetArrayLength(keyObj) != 16) {
2340 err = -EINVAL;
2341 } else {
2342 jboolean isCopy;
2343 key = env->GetByteArrayElements(keyObj, &isCopy);
2344 }
2345 }
2346
2347 if (err == OK && ivObj != NULL) {
2348 if (env->GetArrayLength(ivObj) != 16) {
2349 err = -EINVAL;
2350 } else {
2351 jboolean isCopy;
2352 iv = env->GetByteArrayElements(ivObj, &isCopy);
2353 }
2354 }
2355
Andreas Huberbfc56f42012-04-19 12:47:07 -07002356 AString errorDetailMsg;
2357
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002358 if (err == OK) {
2359 err = codec->queueSecureInputBuffer(
2360 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002361 subSamples, numSubSamples,
2362 (const uint8_t *)key, (const uint8_t *)iv,
2363 mode,
2364 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002365 timestampUs,
2366 flags,
2367 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002368 }
2369
Wonsik Kim1cac4252020-01-24 11:45:37 -08002370 if (iv != NULL) {
2371 env->ReleaseByteArrayElements(ivObj, iv, 0);
2372 iv = NULL;
2373 }
2374
2375 if (key != NULL) {
2376 env->ReleaseByteArrayElements(keyObj, key, 0);
2377 key = NULL;
2378 }
2379
2380 delete[] subSamples;
2381 subSamples = NULL;
2382
Andreas Huberbfc56f42012-04-19 12:47:07 -07002383 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002384 env, err, ACTION_CODE_FATAL,
2385 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002386}
2387
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002388static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002389 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2390 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2391 env, bufferObj);
2392 AHardwareBuffer_Desc desc;
2393 AHardwareBuffer_describe(hardwareBuffer, &desc);
2394 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2395 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2396 return nullptr;
2397 }
2398 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2399 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2400 return nullptr;
2401 }
2402 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2403
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002404 uint64_t cpuUsage = 0;
2405 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2406 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002407
2408 AHardwareBuffer_Planes planes;
2409 int err = AHardwareBuffer_lockPlanes(
2410 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2411 if (err != 0) {
2412 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2413 return nullptr;
2414 }
2415
2416 if (planes.planeCount != 3) {
2417 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2418 return nullptr;
2419 }
2420
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002421 ScopedLocalRef<jobjectArray> buffersArray{
2422 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2423 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2424 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002425
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002426 jboolean isCopy = JNI_FALSE;
2427 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2428 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2429
2430 // For Y plane
2431 int rowSampling = 1;
2432 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002433 // plane indices are Y-U-V.
2434 for (uint32_t i = 0; i < 3; ++i) {
2435 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002436 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2437 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2438 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002439 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2440 env,
2441 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002442 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002443 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002444 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002445 readOnly,
2446 true)};
2447
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002448 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2449 rowStrides[i] = plane.rowStride;
2450 pixelStrides[i] = plane.pixelStride;
2451 // For U-V planes
2452 rowSampling = 2;
2453 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002454 }
2455
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002456 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2457 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2458 rowStrides = pixelStrides = nullptr;
2459
Wonsik Kim637afb22020-02-25 14:27:29 -08002460 ScopedLocalRef<jclass> imageClazz(
2461 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2462 CHECK(imageClazz.get() != NULL);
2463
2464 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002465 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002466
2467 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002468 buffersArray.get(),
2469 rowStridesArray.get(),
2470 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002471 desc.width,
2472 desc.height,
2473 desc.format, // ???
2474 (jboolean)readOnly /* readOnly */,
2475 (jlong)0 /* timestamp */,
2476 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2477 (jlong)hardwareBuffer);
2478
2479 // if MediaImage creation fails, return null
2480 if (env->ExceptionCheck()) {
2481 env->ExceptionDescribe();
2482 env->ExceptionClear();
2483 return nullptr;
2484 }
2485
2486 AHardwareBuffer_acquire(hardwareBuffer);
2487
2488 return img;
2489}
2490
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002491static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2492 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002493 if (context == 0) {
2494 return;
2495 }
2496 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2497
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002498 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2499 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002500 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2501 // Continue to release the hardwareBuffer
2502 }
2503
2504 AHardwareBuffer_release(hardwareBuffer);
2505}
2506
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002507static status_t ConvertKeyValueListsToAMessage(
2508 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2509 static struct Fields {
2510 explicit Fields(JNIEnv *env) {
2511 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2512 CHECK(clazz.get() != NULL);
2513 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2514
2515 clazz.reset(env->FindClass("java/lang/Integer"));
2516 CHECK(clazz.get() != NULL);
2517 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2518
2519 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2520 CHECK(mIntegerValueId != NULL);
2521
2522 clazz.reset(env->FindClass("java/lang/Long"));
2523 CHECK(clazz.get() != NULL);
2524 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2525
2526 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2527 CHECK(mLongValueId != NULL);
2528
2529 clazz.reset(env->FindClass("java/lang/Float"));
2530 CHECK(clazz.get() != NULL);
2531 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2532
2533 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2534 CHECK(mFloatValueId != NULL);
2535
2536 clazz.reset(env->FindClass("java/util/ArrayList"));
2537 CHECK(clazz.get() != NULL);
2538
2539 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2540 CHECK(mByteBufferArrayId != NULL);
2541 }
2542
2543 jclass mStringClass;
2544 jclass mIntegerClass;
2545 jmethodID mIntegerValueId;
2546 jclass mLongClass;
2547 jmethodID mLongValueId;
2548 jclass mFloatClass;
2549 jmethodID mFloatValueId;
2550 jmethodID mByteBufferArrayId;
2551 } sFields{env};
2552
2553 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2554 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2555 return BAD_VALUE;
2556 }
2557
2558 sp<AMessage> result{new AMessage};
2559 for (jint i = 0; i < size; ++i) {
2560 ScopedLocalRef<jstring> jkey{
2561 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2562 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2563 AString key;
2564 if (tmp) {
2565 key.setTo(tmp);
2566 }
2567 env->ReleaseStringUTFChars(jkey.get(), tmp);
2568 if (key.empty()) {
2569 return NO_MEMORY;
2570 }
2571
2572 ScopedLocalRef<jobject> jvalue{
2573 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2574
2575 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2576 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2577 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002578 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002579 return NO_MEMORY;
2580 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002581 value.setTo(tmp);
2582 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002583 result->setString(key.c_str(), value);
2584 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2585 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2586 result->setInt32(key.c_str(), value);
2587 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2588 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2589 result->setInt64(key.c_str(), value);
2590 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2591 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2592 result->setFloat(key.c_str(), value);
2593 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002594 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2595 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002596 sp<ABuffer> buffer{new ABuffer(limit - position)};
2597 void *data = env->GetDirectBufferAddress(jvalue.get());
2598 if (data != nullptr) {
2599 memcpy(buffer->data(),
2600 static_cast<const uint8_t *>(data) + position,
2601 buffer->size());
2602 } else {
2603 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2604 jvalue.get(), sFields.mByteBufferArrayId)};
2605 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2606 reinterpret_cast<jbyte *>(buffer->data()));
2607 }
2608 result->setBuffer(key.c_str(), buffer);
2609 }
2610 }
2611
2612 *msg = result;
2613 return OK;
2614}
2615
Wonsik Kim8569a662022-05-24 14:16:44 -07002616static bool obtain(
2617 JMediaCodecLinearBlock *context,
2618 int capacity,
2619 const std::vector<std::string> &names,
2620 bool secure) {
2621 if (secure) {
2622 // Start at 1MB, which is an arbitrary starting point that can
2623 // increase when needed.
2624 constexpr size_t kInitialDealerCapacity = 1048576;
2625 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2626 kInitialDealerCapacity, "JNI(1MB)");
2627 context->mMemory = sDealer->allocate(capacity);
2628 if (context->mMemory == nullptr) {
2629 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2630 while (capacity * 2 > newDealerCapacity) {
2631 newDealerCapacity *= 2;
2632 }
2633 ALOGI("LinearBlock.native_obtain: "
2634 "Dealer capacity increasing from %zuMB to %zuMB",
2635 sDealer->getMemoryHeap()->getSize() / 1048576,
2636 newDealerCapacity / 1048576);
2637 sDealer = new MemoryDealer(
2638 newDealerCapacity,
2639 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2640 context->mMemory = sDealer->allocate(capacity);
2641 }
2642 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2643 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2644 } else {
2645 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2646 if (!context->mBlock) {
2647 return false;
2648 }
2649 }
2650 context->mCodecNames = names;
2651 return true;
2652}
2653
2654static void extractMemoryFromContext(
2655 JMediaCodecLinearBlock *context,
2656 jint offset,
2657 jint size,
2658 sp<hardware::HidlMemory> *memory) {
2659 *memory = context->toHidlMemory();
2660 if (*memory == nullptr) {
2661 if (!context->mBlock) {
2662 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2663 return;
2664 }
2665 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2666 context->capacity());
2667 if (!obtain(context, context->capacity(),
2668 context->mCodecNames, true /* secure */)) {
2669 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2670 return;
2671 }
2672 C2WriteView view = context->mBlock->map().get();
2673 if (view.error() != C2_OK) {
2674 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2675 return;
2676 }
2677 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2678 memcpy(memoryPtr + offset, view.base() + offset, size);
2679 context->mBlock.reset();
2680 context->mReadWriteMapping.reset();
2681 *memory = context->toHidlMemory();
2682 }
2683}
2684
2685static void extractBufferFromContext(
2686 JMediaCodecLinearBlock *context,
2687 jint offset,
2688 jint size,
2689 std::shared_ptr<C2Buffer> *buffer) {
2690 *buffer = context->toC2Buffer(offset, size);
2691 if (*buffer == nullptr) {
2692 if (!context->mMemory) {
2693 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2694 return;
2695 }
2696 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2697 context->capacity());
2698 if (obtain(context, context->capacity(),
2699 context->mCodecNames, false /* secure */)) {
2700 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2701 return;
2702 }
2703 C2WriteView view = context->mBlock->map().get();
2704 if (view.error() != C2_OK) {
2705 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2706 return;
2707 }
2708 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2709 memcpy(view.base() + offset, memoryPtr + offset, size);
2710 context->mMemory.clear();
2711 context->mHidlMemory.clear();
2712 context->mHidlMemorySize = 0;
2713 context->mHidlMemoryOffset = 0;
2714 *buffer = context->toC2Buffer(offset, size);
2715 }
2716}
2717
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002718static void android_media_MediaCodec_native_queueLinearBlock(
2719 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2720 jint offset, jint size, jobject cryptoInfoObj,
2721 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2722 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2723
2724 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2725
Wonsik Kim24e53802020-05-08 20:04:26 -07002726 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002727 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002728 return;
2729 }
2730
2731 sp<AMessage> tunings;
2732 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2733 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002734 throwExceptionAsNecessary(
2735 env, err, ACTION_CODE_FATAL,
2736 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002737 return;
2738 }
2739
2740 std::shared_ptr<C2Buffer> buffer;
2741 sp<hardware::HidlMemory> memory;
2742 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2743 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2744 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2745 JMediaCodecLinearBlock *context =
2746 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002747 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kim8569a662022-05-24 14:16:44 -07002748 extractMemoryFromContext(context, offset, size, &memory);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002749 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002750 } else {
Wonsik Kim8569a662022-05-24 14:16:44 -07002751 extractBufferFromContext(context, offset, size, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002752 }
2753 }
2754 env->MonitorExit(lock.get());
2755 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002756 throwExceptionAsNecessary(
2757 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2758 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002759 return;
2760 }
2761
2762 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002763 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002764 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002765 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002766 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002767 throwExceptionAsNecessary(
2768 env, BAD_VALUE, ACTION_CODE_FATAL,
2769 "Unexpected error: the input buffer is not compatible with "
2770 "the secure codec, and a fallback logic failed.\n"
2771 "Suggestion: please try including the secure codec when calling "
2772 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002773 return;
2774 }
George Burgess IV436998b2022-11-02 11:42:33 -06002775 auto cryptoInfo =
Robert Shihfe3785c2023-07-11 07:27:02 +00002776 cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{size};
George Burgess IV436998b2022-11-02 11:42:33 -06002777 if (env->ExceptionCheck()) {
2778 // Creation of cryptoInfo failed. Let the exception bubble up.
2779 return;
2780 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002781 err = codec->queueEncryptedLinearBlock(
2782 index,
2783 memory,
2784 offset,
2785 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2786 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2787 cryptoInfo.mMode,
2788 cryptoInfo.mPattern,
2789 presentationTimeUs,
2790 flags,
2791 tunings,
2792 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002793 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002794 } else {
2795 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002796 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002797 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002798 throwExceptionAsNecessary(
2799 env, BAD_VALUE, ACTION_CODE_FATAL,
2800 "Unexpected error: the input buffer is not compatible with "
2801 "the non-secure codec, and a fallback logic failed.\n"
2802 "Suggestion: please do not include the secure codec when calling "
2803 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002804 return;
2805 }
2806 err = codec->queueBuffer(
2807 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2808 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002809 throwExceptionAsNecessary(
2810 env, err, ACTION_CODE_FATAL,
2811 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002812}
2813
Wonsik Kim637afb22020-02-25 14:27:29 -08002814static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002815 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2816 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002817 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002818
2819 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2820
Wonsik Kim24e53802020-05-08 20:04:26 -07002821 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002822 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002823 return;
2824 }
2825
2826 sp<AMessage> tunings;
2827 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2828 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002829 throwExceptionAsNecessary(
2830 env, err, ACTION_CODE_FATAL,
2831 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002832 return;
2833 }
2834
Wonsik Kim637afb22020-02-25 14:27:29 -08002835 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2836 env, bufferObj);
2837 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2838 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002839 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2840 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2841 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2842 std::shared_ptr<C2Allocator> alloc;
2843 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2844 C2PlatformAllocatorStore::GRALLOC, &alloc);
2845 if (err == C2_OK) {
2846 return alloc;
2847 }
2848 return nullptr;
2849 }();
2850 std::shared_ptr<C2GraphicAllocation> alloc;
2851 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2852 if (c2err != C2_OK) {
2853 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002854 native_handle_close(handle);
2855 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002856 throwExceptionAsNecessary(
2857 env, BAD_VALUE, ACTION_CODE_FATAL,
2858 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002859 return;
2860 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002861 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002862 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2863 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002864 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002865 err = codec->queueBuffer(
2866 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002867 throwExceptionAsNecessary(
2868 env, err, ACTION_CODE_FATAL,
2869 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002870}
2871
2872static void android_media_MediaCodec_native_getOutputFrame(
2873 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2874 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2875
2876 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2877
Wonsik Kim24e53802020-05-08 20:04:26 -07002878 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002879 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002880 return;
2881 }
2882
2883 status_t err = codec->getOutputFrame(env, frame, index);
2884 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002885 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002886 }
2887}
2888
Andreas Huber88572f72012-02-21 11:47:18 -08002889static jint android_media_MediaCodec_dequeueInputBuffer(
2890 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2891 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2892
2893 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2894
Wonsik Kim24e53802020-05-08 20:04:26 -07002895 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002896 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002897 return -1;
2898 }
2899
2900 size_t index;
2901 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2902
2903 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002904 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002905 }
2906
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002907 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002908}
2909
2910static jint android_media_MediaCodec_dequeueOutputBuffer(
2911 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2912 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2913
2914 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2915
Wonsik Kim24e53802020-05-08 20:04:26 -07002916 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002917 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002918 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002919 }
2920
2921 size_t index;
2922 status_t err = codec->dequeueOutputBuffer(
2923 env, bufferInfo, &index, timeoutUs);
2924
2925 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002926 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002927 }
2928
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002929 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002930}
2931
2932static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002933 JNIEnv *env, jobject thiz,
2934 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002935 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2936
2937 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2938
Wonsik Kim24e53802020-05-08 20:04:26 -07002939 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002940 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002941 return;
2942 }
2943
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002944 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002945
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002946 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002947}
2948
Andy McFadden2621e402013-02-19 07:29:21 -08002949static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2950 jobject thiz) {
2951 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2952
2953 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002954 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002955 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002956 return;
2957 }
2958
2959 status_t err = codec->signalEndOfInputStream();
2960
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002961 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002962}
2963
Lajos Molnard4023112014-07-11 15:12:59 -07002964static jobject android_media_MediaCodec_getFormatNative(
2965 JNIEnv *env, jobject thiz, jboolean input) {
2966 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002967
2968 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2969
Wonsik Kim24e53802020-05-08 20:04:26 -07002970 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002971 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002972 return NULL;
2973 }
2974
2975 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002976 status_t err = codec->getFormat(env, input, &format);
2977
2978 if (err == OK) {
2979 return format;
2980 }
2981
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002982 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002983
2984 return NULL;
2985}
2986
2987static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2988 JNIEnv *env, jobject thiz, jint index) {
2989 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2990
2991 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2992
Wonsik Kim24e53802020-05-08 20:04:26 -07002993 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002994 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002995 return NULL;
2996 }
2997
2998 jobject format;
2999 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08003000
3001 if (err == OK) {
3002 return format;
3003 }
3004
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003005 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003006
3007 return NULL;
3008}
3009
3010static jobjectArray android_media_MediaCodec_getBuffers(
3011 JNIEnv *env, jobject thiz, jboolean input) {
3012 ALOGV("android_media_MediaCodec_getBuffers");
3013
3014 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3015
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);
Andreas Huber88572f72012-02-21 11:47:18 -08003018 return NULL;
3019 }
3020
3021 jobjectArray buffers;
3022 status_t err = codec->getBuffers(env, input, &buffers);
3023
3024 if (err == OK) {
3025 return buffers;
3026 }
3027
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003028 // if we're out of memory, an exception was already thrown
3029 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003030 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003031 }
Andreas Huber88572f72012-02-21 11:47:18 -08003032
3033 return NULL;
3034}
3035
Lajos Molnard4023112014-07-11 15:12:59 -07003036static jobject android_media_MediaCodec_getBuffer(
3037 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3038 ALOGV("android_media_MediaCodec_getBuffer");
3039
3040 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3041
Wonsik Kim24e53802020-05-08 20:04:26 -07003042 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003043 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003044 return NULL;
3045 }
3046
3047 jobject buffer;
3048 status_t err = codec->getBuffer(env, input, index, &buffer);
3049
3050 if (err == OK) {
3051 return buffer;
3052 }
3053
3054 // if we're out of memory, an exception was already thrown
3055 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003056 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003057 }
3058
3059 return NULL;
3060}
3061
3062static jobject android_media_MediaCodec_getImage(
3063 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3064 ALOGV("android_media_MediaCodec_getImage");
3065
3066 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3067
Wonsik Kim24e53802020-05-08 20:04:26 -07003068 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003069 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003070 return NULL;
3071 }
3072
3073 jobject image;
3074 status_t err = codec->getImage(env, input, index, &image);
3075
3076 if (err == OK) {
3077 return image;
3078 }
3079
3080 // if we're out of memory, an exception was already thrown
3081 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003082 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003083 }
3084
3085 return NULL;
3086}
3087
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003088static jobject android_media_MediaCodec_getName(
3089 JNIEnv *env, jobject thiz) {
3090 ALOGV("android_media_MediaCodec_getName");
3091
3092 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3093
Wonsik Kim24e53802020-05-08 20:04:26 -07003094 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003095 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003096 return NULL;
3097 }
3098
3099 jstring name;
3100 status_t err = codec->getName(env, &name);
3101
3102 if (err == OK) {
3103 return name;
3104 }
3105
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003106 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003107
3108 return NULL;
3109}
3110
Chong Zhanga0b72a62018-02-28 18:46:26 -08003111static jobject android_media_MediaCodec_getOwnCodecInfo(
3112 JNIEnv *env, jobject thiz) {
3113 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
3114
3115 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3116
Wonsik Kim24e53802020-05-08 20:04:26 -07003117 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003118 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003119 return NULL;
3120 }
3121
3122 jobject codecInfoObj;
3123 status_t err = codec->getCodecInfo(env, &codecInfoObj);
3124
3125 if (err == OK) {
3126 return codecInfoObj;
3127 }
3128
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003129 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003130
3131 return NULL;
3132}
3133
Ray Essick0e0fee12017-01-25 18:01:56 -08003134static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08003135android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08003136{
Ray Essickf2d0e402017-03-09 10:17:51 -08003137 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08003138
3139 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003140 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003141 jniThrowException(env, "java/lang/IllegalStateException",
3142 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08003143 return 0;
3144 }
3145
3146 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08003147 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08003148
3149 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08003150 if (err != OK) {
3151 ALOGE("getMetrics failed");
3152 return (jobject) NULL;
3153 }
3154
Ray Essick0e0fee12017-01-25 18:01:56 -08003155 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
3156
3157 // housekeeping
3158 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07003159 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08003160
3161 return mybundle;
3162}
3163
Andreas Huber226065b2013-08-12 10:14:11 -07003164static void android_media_MediaCodec_setParameters(
3165 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3166 ALOGV("android_media_MediaCodec_setParameters");
3167
3168 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3169
Wonsik Kim24e53802020-05-08 20:04:26 -07003170 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003171 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003172 return;
3173 }
3174
3175 sp<AMessage> params;
3176 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3177
3178 if (err == OK) {
3179 err = codec->setParameters(params);
3180 }
3181
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003182 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003183}
3184
Andreas Huberb12a5392012-04-30 14:18:33 -07003185static void android_media_MediaCodec_setVideoScalingMode(
3186 JNIEnv *env, jobject thiz, jint mode) {
3187 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3188
Wonsik Kim24e53802020-05-08 20:04:26 -07003189 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003190 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huberb12a5392012-04-30 14:18:33 -07003191 return;
3192 }
3193
3194 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3195 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003196 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003197 String8::format("Unrecognized mode: %d", mode).c_str());
Andreas Huberb12a5392012-04-30 14:18:33 -07003198 return;
3199 }
3200
3201 codec->setVideoScalingMode(mode);
3202}
3203
ybai5e053202018-11-01 13:02:15 +08003204static void android_media_MediaCodec_setAudioPresentation(
3205 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3206 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3207
Wonsik Kim24e53802020-05-08 20:04:26 -07003208 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003209 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08003210 return;
3211 }
3212
3213 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3214}
3215
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003216static jobject android_media_MediaCodec_getSupportedVendorParameters(
3217 JNIEnv *env, jobject thiz) {
3218 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3219
3220 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003221 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003222 return NULL;
3223 }
3224
3225 jobject ret = NULL;
3226 status_t status = codec->querySupportedVendorParameters(env, &ret);
3227 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003228 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003229 }
3230
3231 return ret;
3232}
3233
3234static jobject android_media_MediaCodec_getParameterDescriptor(
3235 JNIEnv *env, jobject thiz, jstring name) {
3236 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3237
3238 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003239 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003240 return NULL;
3241 }
3242
3243 jobject ret = NULL;
3244 status_t status = codec->describeParameter(env, name, &ret);
3245 if (status != OK) {
3246 ret = NULL;
3247 }
3248 return ret;
3249}
3250
3251static void android_media_MediaCodec_subscribeToVendorParameters(
3252 JNIEnv *env, jobject thiz, jobject names) {
3253 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3254
3255 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003256 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003257 return;
3258 }
3259
3260 status_t status = codec->subscribeToVendorParameters(env, names);
3261 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003262 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003263 }
3264 return;
3265}
3266
3267static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3268 JNIEnv *env, jobject thiz, jobject names) {
3269 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3270
3271 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003272 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003273 return;
3274 }
3275
3276 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3277 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003278 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003279 }
3280 return;
3281}
3282
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003283static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003284 ScopedLocalRef<jclass> clazz(
3285 env, env->FindClass("android/media/MediaCodec"));
3286 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003287
Andreas Huberaba67132013-10-22 12:40:01 -07003288 gFields.postEventFromNativeID =
3289 env->GetMethodID(
3290 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003291 CHECK(gFields.postEventFromNativeID != NULL);
3292
Wonsik Kim61796fd2018-09-13 13:15:59 -07003293 gFields.lockAndGetContextID =
3294 env->GetMethodID(
3295 clazz.get(), "lockAndGetContext", "()J");
3296 CHECK(gFields.lockAndGetContextID != NULL);
3297
3298 gFields.setAndUnlockContextID =
3299 env->GetMethodID(
3300 clazz.get(), "setAndUnlockContext", "(J)V");
3301 CHECK(gFields.setAndUnlockContextID != NULL);
3302
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003303 jfieldID field;
3304 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3305 CHECK(field != NULL);
3306 gCryptoModes.Unencrypted =
3307 env->GetStaticIntField(clazz.get(), field);
3308
3309 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3310 CHECK(field != NULL);
3311 gCryptoModes.AesCtr =
3312 env->GetStaticIntField(clazz.get(), field);
3313
3314 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3315 CHECK(field != NULL);
3316 gCryptoModes.AesCbc =
3317 env->GetStaticIntField(clazz.get(), field);
3318
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003319 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3320 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003321
Arun Johnson5a4c7332022-12-17 00:47:06 +00003322 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3323 CHECK(gFields.cryptoInfoSetID != NULL);
3324
3325 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3326 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3327
Andreas Huber91befdc2012-04-18 12:19:51 -07003328 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003329 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003330 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3331
3332 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003333 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003334 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3335
3336 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003337 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003338 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3339
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003340 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003341 CHECK(gFields.cryptoInfoKeyID != NULL);
3342
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003343 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003344 CHECK(gFields.cryptoInfoIVID != NULL);
3345
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003346 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003347 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003348
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003349 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003350 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3351 CHECK(gFields.cryptoInfoPatternID != NULL);
3352
3353 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3354 CHECK(clazz.get() != NULL);
3355
3356 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3357 CHECK(gFields.patternEncryptBlocksID != NULL);
3358
3359 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3360 CHECK(gFields.patternSkipBlocksID != NULL);
3361
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003362 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3363 CHECK(clazz.get() != NULL);
3364
3365 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3366 CHECK(gFields.queueRequestIndexID != NULL);
3367
3368 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3369 CHECK(clazz.get() != NULL);
3370
3371 gFields.outputFrameLinearBlockID =
3372 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3373 CHECK(gFields.outputFrameLinearBlockID != NULL);
3374
Wonsik Kim637afb22020-02-25 14:27:29 -08003375 gFields.outputFrameHardwareBufferID =
3376 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3377 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003378
3379 gFields.outputFrameChangedKeysID =
3380 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3381 CHECK(gFields.outputFrameChangedKeysID != NULL);
3382
3383 gFields.outputFrameFormatID =
3384 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3385 CHECK(gFields.outputFrameFormatID != NULL);
3386
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003387 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3388 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003389
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003390 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003391 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003392 gCryptoErrorCodes.cryptoErrorNoKey =
3393 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003394
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003395 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003396 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003397 gCryptoErrorCodes.cryptoErrorKeyExpired =
3398 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003399
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003400 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003401 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003402 gCryptoErrorCodes.cryptoErrorResourceBusy =
3403 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003404
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003405 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3406 CHECK(field != NULL);
3407 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3408 env->GetStaticIntField(clazz.get(), field);
3409
Jeff Tinker96a2a952015-07-01 17:35:18 -07003410 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3411 CHECK(field != NULL);
3412 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3413 env->GetStaticIntField(clazz.get(), field);
3414
Jeff Tinker20594d82018-12-12 08:31:22 -08003415 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3416 CHECK(field != NULL);
3417 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3418 env->GetStaticIntField(clazz.get(), field);
3419
Jeff Tinkerd3932162016-03-05 11:35:20 -08003420 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3421 CHECK(field != NULL);
3422 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3423 env->GetStaticIntField(clazz.get(), field);
3424
Jeff Tinker20594d82018-12-12 08:31:22 -08003425 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3426 CHECK(field != NULL);
3427 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3428 env->GetStaticIntField(clazz.get(), field);
3429
3430 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3431 CHECK(field != NULL);
3432 gCryptoErrorCodes.cryptoErrorLostState =
3433 env->GetStaticIntField(clazz.get(), field);
3434
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003435 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3436 CHECK(clazz.get() != NULL);
3437 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3438 CHECK(field != NULL);
3439 gCodecActionCodes.codecActionTransient =
3440 env->GetStaticIntField(clazz.get(), field);
3441
3442 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3443 CHECK(field != NULL);
3444 gCodecActionCodes.codecActionRecoverable =
3445 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003446
Ronghua Wuc53ad692015-05-08 14:40:49 -07003447 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003448 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003449 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003450 env->GetStaticIntField(clazz.get(), field);
3451
Ronghua Wuc53ad692015-05-08 14:40:49 -07003452 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003453 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003454 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003455 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003456
3457 clazz.reset(env->FindClass("android/view/Surface"));
3458 CHECK(clazz.get() != NULL);
3459
3460 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3461 CHECK(field != NULL);
3462 gPersistentSurfaceClassInfo.mLock = field;
3463
3464 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3465 CHECK(method != NULL);
3466 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3467
3468 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3469 CHECK(clazz.get() != NULL);
3470 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3471
3472 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3473 CHECK(method != NULL);
3474 gPersistentSurfaceClassInfo.ctor = method;
3475
3476 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3477 CHECK(field != NULL);
3478 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003479
3480 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3481 CHECK(clazz.get() != NULL);
3482 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3483
3484 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003485 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003486 "Ljava/util/Map;Ljava/util/Map;)V");
3487 CHECK(method != NULL);
3488 gCodecInfo.capsCtorId = method;
3489
3490 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3491 CHECK(clazz.get() != NULL);
3492 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3493
3494 field = env->GetFieldID(clazz.get(), "profile", "I");
3495 CHECK(field != NULL);
3496 gCodecInfo.profileField = field;
3497
3498 field = env->GetFieldID(clazz.get(), "level", "I");
3499 CHECK(field != NULL);
3500 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003501
3502 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3503 CHECK(clazz.get() != NULL);
3504 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3505
3506 ScopedLocalRef<jclass> byteOrderClass(
3507 env, env->FindClass("java/nio/ByteOrder"));
3508 CHECK(byteOrderClass.get() != NULL);
3509
3510 jmethodID nativeOrderID = env->GetStaticMethodID(
3511 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3512 CHECK(nativeOrderID != NULL);
3513
3514 ScopedLocalRef<jobject> nativeByteOrderObj{
3515 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3516 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3517 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3518 nativeByteOrderObj.reset();
3519
3520 gByteBufferInfo.orderId = env->GetMethodID(
3521 clazz.get(),
3522 "order",
3523 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3524 CHECK(gByteBufferInfo.orderId != NULL);
3525
3526 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3527 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3528 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3529
3530 gByteBufferInfo.positionId = env->GetMethodID(
3531 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3532 CHECK(gByteBufferInfo.positionId != NULL);
3533
3534 gByteBufferInfo.limitId = env->GetMethodID(
3535 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3536 CHECK(gByteBufferInfo.limitId != NULL);
3537
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003538 gByteBufferInfo.getPositionId = env->GetMethodID(
3539 clazz.get(), "position", "()I");
3540 CHECK(gByteBufferInfo.getPositionId != NULL);
3541
3542 gByteBufferInfo.getLimitId = env->GetMethodID(
3543 clazz.get(), "limit", "()I");
3544 CHECK(gByteBufferInfo.getLimitId != NULL);
3545
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003546 clazz.reset(env->FindClass("java/util/ArrayList"));
3547 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003548 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3549
3550 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3551 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003552
3553 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3554 CHECK(gArrayListInfo.sizeId != NULL);
3555
3556 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3557 CHECK(gArrayListInfo.getId != NULL);
3558
3559 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3560 CHECK(gArrayListInfo.addId != NULL);
3561
Arun Johnson206270e2023-10-31 20:40:12 +00003562 clazz.reset(env->FindClass("java/util/ArrayDeque"));
3563 CHECK(clazz.get() != NULL);
3564 gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3565
3566 gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3567 CHECK(gArrayDequeInfo.ctorId != NULL);
3568
3569 gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3570 CHECK(gArrayDequeInfo.sizeId != NULL);
3571
3572 gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3573 CHECK(gArrayDequeInfo.addId != NULL);
3574
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003575 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3576 CHECK(clazz.get() != NULL);
3577
3578 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3579
3580 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3581 CHECK(gLinearBlockInfo.ctorId != NULL);
3582
3583 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3584 clazz.get(), "setInternalStateLocked", "(JZ)V");
3585 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3586
3587 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3588 CHECK(gLinearBlockInfo.contextId != NULL);
3589
3590 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3591 CHECK(gLinearBlockInfo.validId != NULL);
3592
3593 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3594 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003595
3596 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3597 CHECK(clazz.get() != NULL);
3598 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3599
3600 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3601 CHECK(gDescriptorInfo.ctorId != NULL);
3602
3603 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3604 CHECK(gDescriptorInfo.nameId != NULL);
3605
3606 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3607 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003608
3609 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3610 CHECK(clazz.get() != NULL);
3611 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3612
3613 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3614 CHECK(gBufferInfo.ctorId != NULL);
3615
3616 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3617 CHECK(gBufferInfo.setId != NULL);
Arun Johnson206270e2023-10-31 20:40:12 +00003618
3619 gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
3620 gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
3621 gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
3622 gFields.bufferInfoPresentationTimeUs =
3623 env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08003624}
3625
3626static void android_media_MediaCodec_native_setup(
3627 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003628 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003629 if (name == NULL) {
Ray Essickbd5fdaa2023-08-10 21:04:18 -05003630 jniThrowException(env, "java/lang/NullPointerException",
3631 "No codec name specified");
Andreas Huber88572f72012-02-21 11:47:18 -08003632 return;
3633 }
3634
3635 const char *tmp = env->GetStringUTFChars(name, NULL);
3636
3637 if (tmp == NULL) {
3638 return;
3639 }
3640
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003641 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003642
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003643 const status_t err = codec->initCheck();
3644 if (err == NAME_NOT_FOUND) {
3645 // fail and do not try again.
3646 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003647 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003648 env->ReleaseStringUTFChars(name, tmp);
3649 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003650 }
3651 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003652 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003653 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
Ronghua Wuc53ad692015-05-08 14:40:49 -07003654 env->ReleaseStringUTFChars(name, tmp);
3655 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003656 }
3657 if (err == PERMISSION_DENIED) {
3658 jniThrowException(env, "java/lang/SecurityException",
3659 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003660 err).c_str());
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003661 env->ReleaseStringUTFChars(name, tmp);
3662 return;
3663 }
3664 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003665 // believed possible to try again
3666 jniThrowException(env, "java/io/IOException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003667 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003668 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003669 return;
3670 }
3671
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003672 env->ReleaseStringUTFChars(name, tmp);
3673
Andreas Huberaba67132013-10-22 12:40:01 -07003674 codec->registerSelf();
3675
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003676 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003677}
3678
3679static void android_media_MediaCodec_native_finalize(
3680 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003681 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003682}
3683
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003684// MediaCodec.LinearBlock
3685
3686static jobject android_media_MediaCodec_LinearBlock_native_map(
3687 JNIEnv *env, jobject thiz) {
3688 JMediaCodecLinearBlock *context =
3689 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3690 if (context->mBuffer) {
3691 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3692 if (!context->mReadonlyMapping) {
3693 const C2BufferData data = buffer->data();
3694 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003695 throwExceptionAsNecessary(
3696 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3697 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003698 return nullptr;
3699 }
3700 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003701 throwExceptionAsNecessary(
3702 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3703 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003704 return nullptr;
3705 }
3706 C2ConstLinearBlock block = data.linearBlocks().front();
3707 context->mReadonlyMapping =
3708 std::make_shared<C2ReadView>(block.map().get());
3709 }
3710 return CreateByteBuffer(
3711 env,
3712 context->mReadonlyMapping->data(), // base
3713 context->mReadonlyMapping->capacity(), // capacity
3714 0u, // offset
3715 context->mReadonlyMapping->capacity(), // size
3716 true, // readOnly
3717 true /* clearBuffer */);
3718 } else if (context->mBlock) {
3719 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3720 if (!context->mReadWriteMapping) {
3721 context->mReadWriteMapping =
3722 std::make_shared<C2WriteView>(block->map().get());
3723 }
3724 return CreateByteBuffer(
3725 env,
3726 context->mReadWriteMapping->base(),
3727 context->mReadWriteMapping->capacity(),
3728 context->mReadWriteMapping->offset(),
3729 context->mReadWriteMapping->size(),
3730 false, // readOnly
3731 true /* clearBuffer */);
3732 } else if (context->mLegacyBuffer) {
3733 return CreateByteBuffer(
3734 env,
3735 context->mLegacyBuffer->base(),
3736 context->mLegacyBuffer->capacity(),
3737 context->mLegacyBuffer->offset(),
3738 context->mLegacyBuffer->size(),
3739 true, // readOnly
3740 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003741 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003742 return CreateByteBuffer(
3743 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003744 context->mMemory->unsecurePointer(),
3745 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003746 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003747 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003748 false, // readOnly
3749 true /* clearBuffer */);
3750 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003751 throwExceptionAsNecessary(
3752 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3753 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003754 return nullptr;
3755}
3756
3757static void android_media_MediaCodec_LinearBlock_native_recycle(
3758 JNIEnv *env, jobject thiz) {
3759 JMediaCodecLinearBlock *context =
3760 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003761 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003762 delete context;
3763}
3764
3765static void PopulateNamesVector(
3766 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3767 jsize length = env->GetArrayLength(codecNames);
3768 for (jsize i = 0; i < length; ++i) {
3769 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3770 if (jstr == nullptr) {
3771 // null entries are ignored
3772 continue;
3773 }
3774 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3775 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003776 throwExceptionAsNecessary(
3777 env, BAD_VALUE, ACTION_CODE_FATAL,
3778 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003779 return;
3780 }
3781 names->emplace_back(cstr);
3782 env->ReleaseStringUTFChars(jstr, cstr);
3783 }
3784}
3785
3786static void android_media_MediaCodec_LinearBlock_native_obtain(
3787 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3788 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3789 std::vector<std::string> names;
3790 PopulateNamesVector(env, codecNames, &names);
3791 bool hasSecure = false;
3792 bool hasNonSecure = false;
3793 for (const std::string &name : names) {
3794 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3795 hasSecure = true;
3796 } else {
3797 hasNonSecure = true;
3798 }
3799 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003800 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3801 jniThrowException(env, "java/io/IOException", nullptr);
3802 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003803 }
3804 env->CallVoidMethod(
3805 thiz,
3806 gLinearBlockInfo.setInternalStateId,
3807 (jlong)context.release(),
3808 true /* isMappable */);
3809}
3810
3811static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003812 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003813 std::vector<std::string> names;
3814 PopulateNamesVector(env, codecNames, &names);
3815 bool isCompatible = false;
3816 bool hasSecure = false;
3817 bool hasNonSecure = false;
3818 for (const std::string &name : names) {
3819 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3820 hasSecure = true;
3821 } else {
3822 hasNonSecure = true;
3823 }
3824 }
3825 if (hasSecure && hasNonSecure) {
3826 return false;
3827 }
3828 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3829 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003830 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003831 throwExceptionAsNecessary(env, err);
3832 }
3833 return isCompatible;
3834}
3835
Daniel Micay76f6a862015-09-19 17:31:01 -04003836static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003837 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003838
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003839 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3840
Chong Zhang8034d602015-04-28 13:38:48 -07003841 { "native_releasePersistentInputSurface",
3842 "(Landroid/view/Surface;)V",
3843 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3844
3845 { "native_createPersistentInputSurface",
3846 "()Landroid/media/MediaCodec$PersistentSurface;",
3847 (void *)android_media_MediaCodec_createPersistentInputSurface },
3848
Chong Zhang9560ddb2015-05-13 10:25:29 -07003849 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3850 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003851
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003852 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3853 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3854
Lajos Molnard8578572015-06-05 20:17:33 -07003855 { "native_enableOnFrameRenderedListener", "(Z)V",
3856 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3857
Chong Zhang8d5e5562014-07-08 18:49:21 -07003858 { "native_setCallback",
3859 "(Landroid/media/MediaCodec$Callback;)V",
3860 (void *)android_media_MediaCodec_native_setCallback },
3861
Andreas Huber88572f72012-02-21 11:47:18 -08003862 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003863 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003864 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003865 (void *)android_media_MediaCodec_native_configure },
3866
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003867 { "native_setSurface",
3868 "(Landroid/view/Surface;)V",
3869 (void *)android_media_MediaCodec_native_setSurface },
3870
Andy McFadden2621e402013-02-19 07:29:21 -08003871 { "createInputSurface", "()Landroid/view/Surface;",
3872 (void *)android_media_MediaCodec_createInputSurface },
3873
Lajos Molnard4023112014-07-11 15:12:59 -07003874 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003875 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003876 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003877
Lajos Molnard4023112014-07-11 15:12:59 -07003878 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003879 (void *)android_media_MediaCodec_queueInputBuffer },
3880
Arun Johnson206270e2023-10-31 20:40:12 +00003881 { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
3882 (void *)android_media_MediaCodec_queueInputBuffers },
3883
Lajos Molnard4023112014-07-11 15:12:59 -07003884 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003885 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3886
Wonsik Kim637afb22020-02-25 14:27:29 -08003887 { "native_mapHardwareBuffer",
3888 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3889 (void *)android_media_MediaCodec_mapHardwareBuffer },
3890
3891 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3892
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003893 { "native_queueLinearBlock",
3894 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3895 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3896 (void *)android_media_MediaCodec_native_queueLinearBlock },
3897
Wonsik Kim637afb22020-02-25 14:27:29 -08003898 { "native_queueHardwareBuffer",
3899 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3900 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003901
3902 { "native_getOutputFrame",
3903 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3904 (void *)android_media_MediaCodec_native_getOutputFrame },
3905
Lajos Molnard4023112014-07-11 15:12:59 -07003906 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003907 (void *)android_media_MediaCodec_dequeueInputBuffer },
3908
Lajos Molnard4023112014-07-11 15:12:59 -07003909 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003910 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3911
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003912 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003913 (void *)android_media_MediaCodec_releaseOutputBuffer },
3914
Andy McFadden2621e402013-02-19 07:29:21 -08003915 { "signalEndOfInputStream", "()V",
3916 (void *)android_media_MediaCodec_signalEndOfInputStream },
3917
Lajos Molnard4023112014-07-11 15:12:59 -07003918 { "getFormatNative", "(Z)Ljava/util/Map;",
3919 (void *)android_media_MediaCodec_getFormatNative },
3920
3921 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3922 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003923
3924 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3925 (void *)android_media_MediaCodec_getBuffers },
3926
Lajos Molnard4023112014-07-11 15:12:59 -07003927 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3928 (void *)android_media_MediaCodec_getBuffer },
3929
3930 { "getImage", "(ZI)Landroid/media/Image;",
3931 (void *)android_media_MediaCodec_getImage },
3932
Lajos Molnard2a7f472018-11-15 12:49:20 -08003933 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003934 (void *)android_media_MediaCodec_getName },
3935
Chong Zhanga0b72a62018-02-28 18:46:26 -08003936 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3937 (void *)android_media_MediaCodec_getOwnCodecInfo },
3938
Ray Essick10353e32017-04-14 10:22:55 -07003939 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003940 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003941
Andreas Huber226065b2013-08-12 10:14:11 -07003942 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3943 (void *)android_media_MediaCodec_setParameters },
3944
Andreas Huberb12a5392012-04-30 14:18:33 -07003945 { "setVideoScalingMode", "(I)V",
3946 (void *)android_media_MediaCodec_setVideoScalingMode },
3947
ybai5e053202018-11-01 13:02:15 +08003948 { "native_setAudioPresentation", "(II)V",
3949 (void *)android_media_MediaCodec_setAudioPresentation },
3950
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003951 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
3952 (void *)android_media_MediaCodec_getSupportedVendorParameters },
3953
3954 { "native_getParameterDescriptor",
3955 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
3956 (void *)android_media_MediaCodec_getParameterDescriptor },
3957
3958 { "native_subscribeToVendorParameters",
3959 "(Ljava/util/List;)V",
3960 (void *)android_media_MediaCodec_subscribeToVendorParameters},
3961
3962 { "native_unsubscribeFromVendorParameters",
3963 "(Ljava/util/List;)V",
3964 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
3965
Andreas Huber88572f72012-02-21 11:47:18 -08003966 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3967
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003968 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003969 (void *)android_media_MediaCodec_native_setup },
3970
3971 { "native_finalize", "()V",
3972 (void *)android_media_MediaCodec_native_finalize },
3973};
3974
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003975static const JNINativeMethod gLinearBlockMethods[] = {
3976 { "native_map", "()Ljava/nio/ByteBuffer;",
3977 (void *)android_media_MediaCodec_LinearBlock_native_map },
3978
3979 { "native_recycle", "()V",
3980 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3981
3982 { "native_obtain", "(I[Ljava/lang/String;)V",
3983 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3984
3985 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3986 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3987};
3988
Andreas Huber88572f72012-02-21 11:47:18 -08003989int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003990 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003991 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003992 if (result != JNI_OK) {
3993 return result;
3994 }
3995 result = AndroidRuntime::registerNativeMethods(env,
3996 "android/media/MediaCodec$LinearBlock",
3997 gLinearBlockMethods,
3998 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003999 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08004000}