blob: 8a13c034995da615a1c2ad4c7c7c892a4a9695c2 [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec-JNI"
19#include <utils/Log.h>
20
Wonsik Kimccb7ac62019-12-27 17:12:40 -080021#include <type_traits>
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include "android_media_MediaCodec.h"
24
shubangd49681e2020-02-17 21:32:30 -080025#include "android_media_MediaCodecLinearBlock.h"
Andreas Huber07ea4262012-04-11 12:21:20 -070026#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070027#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080028#include "android_media_MediaMetricsJNI.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090029#include "android_media_Streams.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "android_runtime/AndroidRuntime.h"
31#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080032#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080033#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080035#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080036
Wonsik Kim637afb22020-02-25 14:27:29 -080037#include <C2AllocatorGralloc.h>
38#include <C2BlockInternal.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080039#include <C2Buffer.h>
Wonsik Kimb8ebdb32020-04-21 17:00:13 -070040#include <C2PlatformSupport.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080041
Chong Zhang2659c2f2017-04-27 13:18:20 -070042#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080043
Wonsik Kim637afb22020-02-25 14:27:29 -080044#include <android_runtime/android_hardware_HardwareBuffer.h>
45
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -080046#include <android-base/stringprintf.h>
47
Wonsik Kimf7069ce2020-05-13 17:15:47 -070048#include <binder/MemoryDealer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080049
Lajos Molnar7ac4f562014-03-24 15:57:51 -070050#include <cutils/compiler.h>
51
Mathias Agopian8335f1c2012-02-25 18:48:35 -080052#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080053
Wonsik Kimccb7ac62019-12-27 17:12:40 -080054#include <hidlmemory/FrameworkUtils.h>
55
Wonsik Kim4273dd02016-09-27 15:23:35 +090056#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080057#include <media/hardware/VideoAPI.h>
Wonsik Kim8798c8c2021-03-18 21:38:57 -070058#include <media/stagefright/CodecBase.h>
Andreas Huber88572f72012-02-21 11:47:18 -080059#include <media/stagefright/MediaCodec.h>
60#include <media/stagefright/foundation/ABuffer.h>
61#include <media/stagefright/foundation/ADebug.h>
62#include <media/stagefright/foundation/ALooper.h>
63#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070064#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080065#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070066#include <media/stagefright/PersistentSurface.h>
Robert Shih631a80d2021-02-14 02:23:55 -080067#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080068#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070069
Wonsik Kim637afb22020-02-25 14:27:29 -080070#include <private/android/AHardwareBufferHelpers.h>
71
Andreas Huberb12a5392012-04-30 14:18:33 -070072#include <system/window.h>
73
Andreas Huber88572f72012-02-21 11:47:18 -080074namespace android {
75
76// Keep these in sync with their equivalents in MediaCodec.java !!!
77enum {
78 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
79 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
80 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
81};
82
Andreas Huberaba67132013-10-22 12:40:01 -070083enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070084 EVENT_CALLBACK = 1,
85 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070086 EVENT_FRAME_RENDERED = 3,
Guillaume Chelfic072caf2021-02-03 16:18:26 +010087 EVENT_FIRST_TUNNEL_FRAME_READY = 4,
Andreas Huberaba67132013-10-22 12:40:01 -070088};
89
Wonsik Kim8798c8c2021-03-18 21:38:57 -070090// From MediaFormat.java
91enum {
92 TYPE_NULL = 0,
93 TYPE_INTEGER = 1,
94 TYPE_LONG = 2,
95 TYPE_FLOAT = 3,
96 TYPE_STRING = 4,
97 TYPE_BYTE_BUFFER = 5,
98};
99
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700100static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -0700101 jint cryptoErrorNoKey;
102 jint cryptoErrorKeyExpired;
103 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700104 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700105 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -0800106 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800107 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -0800108 jint cryptoErrorFrameTooLarge;
109 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700110} gCryptoErrorCodes;
111
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700112static struct CodecActionCodes {
113 jint codecActionTransient;
114 jint codecActionRecoverable;
115} gCodecActionCodes;
116
Ronghua Wuc53ad692015-05-08 14:40:49 -0700117static struct CodecErrorCodes {
118 jint errorInsufficientResource;
119 jint errorReclaimed;
120} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700121
Chong Zhang8034d602015-04-28 13:38:48 -0700122static struct {
123 jclass clazz;
124 jfieldID mLock;
125 jfieldID mPersistentObject;
126 jmethodID ctor;
127 jmethodID setNativeObjectLocked;
128} gPersistentSurfaceClassInfo;
129
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800130static struct {
131 jint Unencrypted;
132 jint AesCtr;
133 jint AesCbc;
134} gCryptoModes;
135
Chong Zhanga0b72a62018-02-28 18:46:26 -0800136static struct {
137 jclass capsClazz;
138 jmethodID capsCtorId;
139 jclass profileLevelClazz;
140 jfieldID profileField;
141 jfieldID levelField;
142} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800143
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800144static struct {
145 jclass clazz;
146 jobject nativeByteOrder;
147 jmethodID orderId;
148 jmethodID asReadOnlyBufferId;
149 jmethodID positionId;
150 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700151 jmethodID getPositionId;
152 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800153} gByteBufferInfo;
154
155static struct {
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700156 jclass clazz;
157 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800158 jmethodID sizeId;
159 jmethodID getId;
160 jmethodID addId;
161} gArrayListInfo;
162
163static struct {
164 jclass clazz;
165 jmethodID ctorId;
Arun Johnson206270e2023-10-31 20:40:12 +0000166 jmethodID sizeId;
167 jmethodID addId;
168} gArrayDequeInfo;
169
170static struct {
171 jclass clazz;
172 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800173 jmethodID setInternalStateId;
174 jfieldID contextId;
175 jfieldID validId;
176 jfieldID lockId;
177} gLinearBlockInfo;
178
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700179static struct {
180 jclass clazz;
181 jmethodID ctorId;
182 jfieldID nameId;
183 jfieldID typeId;
184} gDescriptorInfo;
185
Pavel Laboviche53421b2022-11-01 03:53:27 +0000186static struct {
187 jclass clazz;
188 jmethodID ctorId;
189 jmethodID setId;
190} gBufferInfo;
191
Andreas Huber88572f72012-02-21 11:47:18 -0800192struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700193 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700194 jmethodID lockAndGetContextID;
195 jmethodID setAndUnlockContextID;
Arun Johnson5a4c7332022-12-17 00:47:06 +0000196 jmethodID cryptoInfoSetID;
197 jmethodID cryptoInfoSetPatternID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700198 jfieldID cryptoInfoNumSubSamplesID;
199 jfieldID cryptoInfoNumBytesOfClearDataID;
200 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
201 jfieldID cryptoInfoKeyID;
202 jfieldID cryptoInfoIVID;
203 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800204 jfieldID cryptoInfoPatternID;
205 jfieldID patternEncryptBlocksID;
206 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800207 jfieldID queueRequestIndexID;
208 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800209 jfieldID outputFrameHardwareBufferID;
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000210 jfieldID outputFramebufferInfosID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800211 jfieldID outputFrameChangedKeysID;
212 jfieldID outputFrameFormatID;
Arun Johnson206270e2023-10-31 20:40:12 +0000213 jfieldID bufferInfoFlags;
214 jfieldID bufferInfoOffset;
215 jfieldID bufferInfoSize;
216 jfieldID bufferInfoPresentationTimeUs;
217
Andreas Huber88572f72012-02-21 11:47:18 -0800218};
219
220static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700221static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800222
Arun Johnson5a4c7332022-12-17 00:47:06 +0000223jint MediaErrorToJavaError(status_t err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800224
Andreas Huber88572f72012-02-21 11:47:18 -0800225////////////////////////////////////////////////////////////////////////////////
226
227JMediaCodec::JMediaCodec(
228 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100229 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800230 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700231 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800232 jclass clazz = env->GetObjectClass(thiz);
233 CHECK(clazz != NULL);
234
235 mClass = (jclass)env->NewGlobalRef(clazz);
236 mObject = env->NewWeakGlobalRef(thiz);
237
238 mLooper = new ALooper;
239 mLooper->setName("MediaCodec_looper");
240
241 mLooper->start(
242 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700243 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700244 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800245
246 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100247 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800248 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
249 mNameAtCreation = "(null)";
250 }
Andreas Huber88572f72012-02-21 11:47:18 -0800251 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100252 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800253 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800254 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700255 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800256}
257
258status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700259 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800260}
261
Andreas Huberaba67132013-10-22 12:40:01 -0700262void JMediaCodec::registerSelf() {
263 mLooper->registerHandler(this);
264}
265
Chong Zhang128b0122014-03-01 18:04:13 -0800266void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700267 std::call_once(mReleaseFlag, [this] {
268 if (mCodec != NULL) {
269 mCodec->release();
270 mInitStatus = NO_INIT;
271 }
Andreas Huber88572f72012-02-21 11:47:18 -0800272
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700273 if (mLooper != NULL) {
274 mLooper->unregisterHandler(id());
275 mLooper->stop();
276 mLooper.clear();
277 }
278 });
Chong Zhang128b0122014-03-01 18:04:13 -0800279}
280
Wonsik Kim89666622020-04-28 10:43:47 -0700281void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700282 std::call_once(mAsyncReleaseFlag, [this] {
283 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700284 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
285 // Hold strong reference to this until async release is complete
286 notify->setObject("this", this);
287 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700288 }
289 mInitStatus = NO_INIT;
290 });
Wonsik Kim89666622020-04-28 10:43:47 -0700291}
292
Chong Zhang128b0122014-03-01 18:04:13 -0800293JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700294 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800295 /* MediaCodec and looper should have been released explicitly already
296 * in setMediaCodec() (see comments in setMediaCodec()).
297 *
298 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
299 * message handler, doing release() there risks deadlock as MediaCodec::
300 * release() post synchronous message to the same looper.
301 *
302 * Print a warning and try to proceed with releasing.
303 */
304 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
305 release();
306 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
307 }
308
Andreas Huber88572f72012-02-21 11:47:18 -0800309 JNIEnv *env = AndroidRuntime::getJNIEnv();
310
311 env->DeleteWeakGlobalRef(mObject);
312 mObject = NULL;
313 env->DeleteGlobalRef(mClass);
314 mClass = NULL;
315}
316
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100317status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
318 if (enable) {
319 if (mOnFirstTunnelFrameReadyNotification == NULL) {
320 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
321 }
322 } else {
323 mOnFirstTunnelFrameReadyNotification.clear();
324 }
325
326 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
327}
328
Lajos Molnard8578572015-06-05 20:17:33 -0700329status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
330 if (enable) {
331 if (mOnFrameRenderedNotification == NULL) {
332 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
333 }
334 } else {
335 mOnFrameRenderedNotification.clear();
336 }
337
338 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
339}
340
Chong Zhang8d5e5562014-07-08 18:49:21 -0700341status_t JMediaCodec::setCallback(jobject cb) {
342 if (cb != NULL) {
343 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800344 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700345 }
346 } else {
347 mCallbackNotification.clear();
348 }
349
350 return mCodec->setCallback(mCallbackNotification);
351}
352
Andreas Huber88572f72012-02-21 11:47:18 -0800353status_t JMediaCodec::configure(
354 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800355 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700356 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800357 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800358 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800359 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800360 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700361 mSurfaceTextureClient =
362 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700363 } else {
364 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800365 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700366
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800367 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
368 AString mime;
369 CHECK(format->findString("mime", &mime));
370 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
371 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700372 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800373 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800374
Chong Zhangd5927ae2017-01-03 11:07:18 -0800375 return mCodec->configure(
376 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800377}
378
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700379status_t JMediaCodec::setSurface(
380 const sp<IGraphicBufferProducer> &bufferProducer) {
381 sp<Surface> client;
382 if (bufferProducer != NULL) {
383 client = new Surface(bufferProducer, true /* controlledByApp */);
384 }
385 status_t err = mCodec->setSurface(client);
386 if (err == OK) {
387 mSurfaceTextureClient = client;
388 }
389 return err;
390}
391
Lajos Molnar3a7c83a2024-03-29 08:15:59 -0700392status_t JMediaCodec::detachOutputSurface() {
393 status_t err = mCodec->detachOutputSurface();
394 if (err == OK) {
395 mSurfaceTextureClient.clear();
396 }
397 return err;
398}
399
Andy McFadden2621e402013-02-19 07:29:21 -0800400status_t JMediaCodec::createInputSurface(
401 sp<IGraphicBufferProducer>* bufferProducer) {
402 return mCodec->createInputSurface(bufferProducer);
403}
404
Chong Zhang9560ddb2015-05-13 10:25:29 -0700405status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700406 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700407 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700408}
409
Andreas Huber88572f72012-02-21 11:47:18 -0800410status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700411 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800412}
413
414status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700415 mSurfaceTextureClient.clear();
416
Chong Zhang8d5e5562014-07-08 18:49:21 -0700417 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800418}
419
420status_t JMediaCodec::flush() {
421 return mCodec->flush();
422}
423
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700424status_t JMediaCodec::reset() {
425 return mCodec->reset();
426}
427
Andreas Huber88572f72012-02-21 11:47:18 -0800428status_t JMediaCodec::queueInputBuffer(
429 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700430 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
431 AString *errorDetailMsg) {
432 return mCodec->queueInputBuffer(
433 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800434}
435
Arun Johnson206270e2023-10-31 20:40:12 +0000436status_t JMediaCodec::queueInputBuffers(
437 size_t index,
438 size_t offset,
439 size_t size,
440 const sp<RefBase> &infos,
441 AString *errorDetailMsg) {
442
443 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
444 return mCodec->queueInputBuffers(
445 index,
446 offset,
447 size,
448 auInfo,
449 errorDetailMsg);
450}
451
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700452status_t JMediaCodec::queueSecureInputBuffer(
453 size_t index,
454 size_t offset,
455 const CryptoPlugin::SubSample *subSamples,
456 size_t numSubSamples,
457 const uint8_t key[16],
458 const uint8_t iv[16],
459 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800460 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700461 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700462 uint32_t flags,
463 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700464 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800465 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700466 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700467}
468
Arun Johnson4ca49092024-02-01 19:07:15 +0000469status_t JMediaCodec::queueSecureInputBuffers(
470 size_t index,
471 size_t offset,
472 size_t size,
473 const sp<RefBase> &auInfos_,
474 const sp<RefBase> &cryptoInfos_,
475 AString *errorDetailMsg) {
476 sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
477 sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
478 return mCodec->queueSecureInputBuffers(
479 index,
480 offset,
481 size,
482 auInfos,
483 cryptoInfos,
484 errorDetailMsg);
485}
486
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800487status_t JMediaCodec::queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000488 size_t index, const std::shared_ptr<C2Buffer> &buffer,
489 const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
490 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800491 return mCodec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000492 index, buffer, auInfo, tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800493}
494
495status_t JMediaCodec::queueEncryptedLinearBlock(
496 size_t index,
497 const sp<hardware::HidlMemory> &buffer,
498 size_t offset,
Arun Johnson677a8812024-02-06 12:32:54 +0000499 size_t size,
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000500 const sp<RefBase> &infos,
Arun Johnson677a8812024-02-06 12:32:54 +0000501 const sp<RefBase> &cryptoInfos_,
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800502 const sp<AMessage> &tunings,
503 AString *errorDetailMsg) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000504 sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
Arun Johnson677a8812024-02-06 12:32:54 +0000505 sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800506 return mCodec->queueEncryptedBuffer(
Arun Johnson677a8812024-02-06 12:32:54 +0000507 index, buffer, offset, size, auInfo, cryptoInfos,
508 tunings, errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800509}
510
Andreas Huber88572f72012-02-21 11:47:18 -0800511status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700512 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800513}
514
515status_t JMediaCodec::dequeueOutputBuffer(
516 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
517 size_t size, offset;
518 int64_t timeUs;
519 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700520 status_t err = mCodec->dequeueOutputBuffer(
521 index, &offset, &size, &timeUs, &flags, timeoutUs);
522
Andreas Huberaba67132013-10-22 12:40:01 -0700523 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800524 return err;
525 }
526
Pavel Laboviche53421b2022-11-01 03:53:27 +0000527 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800528
529 return OK;
530}
531
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700532status_t JMediaCodec::releaseOutputBuffer(
533 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
534 if (updatePTS) {
535 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
536 }
Andreas Huber88572f72012-02-21 11:47:18 -0800537 return render
538 ? mCodec->renderOutputBufferAndRelease(index)
539 : mCodec->releaseOutputBuffer(index);
540}
541
Andy McFadden2621e402013-02-19 07:29:21 -0800542status_t JMediaCodec::signalEndOfInputStream() {
543 return mCodec->signalEndOfInputStream();
544}
545
Lajos Molnard4023112014-07-11 15:12:59 -0700546status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800547 sp<AMessage> msg;
548 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700549 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
550 if (err != OK) {
551 return err;
552 }
553
554 return ConvertMessageToMap(env, msg, format);
555}
556
557status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
558 sp<AMessage> msg;
559 status_t err;
560 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800561 return err;
562 }
563
564 return ConvertMessageToMap(env, msg, format);
565}
566
567status_t JMediaCodec::getBuffers(
568 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900569 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800570
571 status_t err =
572 input
573 ? mCodec->getInputBuffers(&buffers)
574 : mCodec->getOutputBuffers(&buffers);
575
576 if (err != OK) {
577 return err;
578 }
579
Andreas Huber88572f72012-02-21 11:47:18 -0800580 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800581 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800582 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800583 return NO_MEMORY;
584 }
Andreas Huber88572f72012-02-21 11:47:18 -0800585
586 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900587 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800588
Lajos Molnar7de28d32014-07-25 07:51:02 -0700589 jobject byteBuffer = NULL;
590 err = createByteBufferFromABuffer(
591 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
592 if (err != OK) {
593 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800594 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700595 if (byteBuffer != NULL) {
596 env->SetObjectArrayElement(
597 *bufArray, i, byteBuffer);
598
Lajos Molnard4023112014-07-11 15:12:59 -0700599 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700600 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700601 }
Andreas Huber88572f72012-02-21 11:47:18 -0800602 }
603
Lajos Molnar7de28d32014-07-25 07:51:02 -0700604 return OK;
605}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700606
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800607template <typename T>
608static jobject CreateByteBuffer(
609 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
610 bool readOnly, bool clearBuffer) {
611 jobject byteBuffer =
612 env->NewDirectByteBuffer(
613 const_cast<typename std::remove_const<T>::type *>(base),
614 capacity);
615 if (readOnly && byteBuffer != NULL) {
616 jobject readOnlyBuffer = env->CallObjectMethod(
617 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
618 env->DeleteLocalRef(byteBuffer);
619 byteBuffer = readOnlyBuffer;
620 }
621 if (byteBuffer == NULL) {
622 return nullptr;
623 }
624 jobject me = env->CallObjectMethod(
625 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
626 env->DeleteLocalRef(me);
627 me = env->CallObjectMethod(
628 byteBuffer, gByteBufferInfo.limitId,
629 clearBuffer ? capacity : offset + size);
630 env->DeleteLocalRef(me);
631 me = env->CallObjectMethod(
632 byteBuffer, gByteBufferInfo.positionId,
633 clearBuffer ? 0 : offset);
634 env->DeleteLocalRef(me);
635 me = NULL;
636 return byteBuffer;
637}
638
639
Lajos Molnar7de28d32014-07-25 07:51:02 -0700640// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900641template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700642status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900643 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700644 jobject *buf) const {
645 // if this is an ABuffer that doesn't actually hold any accessible memory,
646 // use a null ByteBuffer
647 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700648
649 if (buffer == NULL) {
650 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
651 return OK;
652 }
653
Lajos Molnar7de28d32014-07-25 07:51:02 -0700654 if (buffer->base() == NULL) {
655 return OK;
656 }
657
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800658 jobject byteBuffer = CreateByteBuffer(
659 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
660 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700661
662 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800663 return OK;
664}
665
Lajos Molnard4023112014-07-11 15:12:59 -0700666status_t JMediaCodec::getBuffer(
667 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900668 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700669
670 status_t err =
671 input
672 ? mCodec->getInputBuffer(index, &buffer)
673 : mCodec->getOutputBuffer(index, &buffer);
674
675 if (err != OK) {
676 return err;
677 }
678
Lajos Molnar7de28d32014-07-25 07:51:02 -0700679 return createByteBufferFromABuffer(
680 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700681}
682
683status_t JMediaCodec::getImage(
684 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900685 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700686
687 status_t err =
688 input
689 ? mCodec->getInputBuffer(index, &buffer)
690 : mCodec->getOutputBuffer(index, &buffer);
691
692 if (err != OK) {
693 return err;
694 }
695
696 // if this is an ABuffer that doesn't actually hold any accessible memory,
697 // use a null ByteBuffer
698 *buf = NULL;
699 if (buffer->base() == NULL) {
700 return OK;
701 }
702
703 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700704 sp<ABuffer> imageData;
705 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700706 return OK;
707 }
708
Lajos Molnar7de28d32014-07-25 07:51:02 -0700709 int64_t timestamp = 0;
710 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
711 timestamp *= 1000; // adjust to ns
712 }
713
714 jobject byteBuffer = NULL;
715 err = createByteBufferFromABuffer(
716 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
717 if (err != OK) {
718 return OK;
719 }
720
721 jobject infoBuffer = NULL;
722 err = createByteBufferFromABuffer(
723 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
724 if (err != OK) {
725 env->DeleteLocalRef(byteBuffer);
726 byteBuffer = NULL;
727 return OK;
728 }
729
730 jobject cropRect = NULL;
731 int32_t left, top, right, bottom;
732 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
733 ScopedLocalRef<jclass> rectClazz(
734 env, env->FindClass("android/graphics/Rect"));
735 CHECK(rectClazz.get() != NULL);
736
737 jmethodID rectConstructID = env->GetMethodID(
738 rectClazz.get(), "<init>", "(IIII)V");
739
740 cropRect = env->NewObject(
741 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
742 }
743
744 ScopedLocalRef<jclass> imageClazz(
745 env, env->FindClass("android/media/MediaCodec$MediaImage"));
746 CHECK(imageClazz.get() != NULL);
747
748 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
749 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
750
751 *buf = env->NewObject(imageClazz.get(), imageConstructID,
752 byteBuffer, infoBuffer,
753 (jboolean)!input /* readOnly */,
754 (jlong)timestamp,
755 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
756
757 // if MediaImage creation fails, return null
758 if (env->ExceptionCheck()) {
759 env->ExceptionDescribe();
760 env->ExceptionClear();
761 *buf = NULL;
762 }
763
764 if (cropRect != NULL) {
765 env->DeleteLocalRef(cropRect);
766 cropRect = NULL;
767 }
768
769 env->DeleteLocalRef(byteBuffer);
770 byteBuffer = NULL;
771
772 env->DeleteLocalRef(infoBuffer);
773 infoBuffer = NULL;
774
Lajos Molnard4023112014-07-11 15:12:59 -0700775 return OK;
776}
777
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000778void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
779 if (!bufInfos) {
780 return;
781 }
782 std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
783 if (infos.empty()) {
784 return;
785 }
786 ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
787 gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
788 jint offset = 0;
789 std::vector<jobject> jObjectInfos;
790 for (int i = 0 ; i < infos.size(); i++) {
791 jobject bufferInfo = env->NewObject(
792 gBufferInfo.clazz, gBufferInfo.ctorId);
793 if (bufferInfo != NULL) {
794 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
795 offset,
796 (jint)(infos)[i].mSize,
797 (infos)[i].mTimestamp,
798 (infos)[i].mFlags);
799 (void)env->CallBooleanMethod(
800 dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
801 offset += (infos)[i].mSize;
802 jObjectInfos.push_back(bufferInfo);
803 }
804 }
805 env->SetObjectField(
806 frame,
807 gFields.outputFramebufferInfosID,
808 dequeObj.get());
809 for (int i = 0; i < jObjectInfos.size(); i++) {
810 env->DeleteLocalRef(jObjectInfos[i]);
811 }
812}
813
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800814status_t JMediaCodec::getOutputFrame(
815 JNIEnv *env, jobject frame, size_t index) const {
816 sp<MediaCodecBuffer> buffer;
817
818 status_t err = mCodec->getOutputBuffer(index, &buffer);
819 if (err != OK) {
820 return err;
821 }
822
823 if (buffer->size() > 0) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000824 sp<RefBase> obj;
825 sp<BufferInfosWrapper> bufInfos;
826 if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
827 bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
828 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800829 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800830 if (c2Buffer) {
831 switch (c2Buffer->data().type()) {
832 case C2BufferData::LINEAR: {
833 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700834 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800835 context->mBuffer = c2Buffer;
836 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
837 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800838 env->CallVoidMethod(
839 linearBlock.get(),
840 gLinearBlockInfo.setInternalStateId,
841 (jlong)context.release(),
842 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800843 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000844 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800845 break;
846 }
847 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800848 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
849 uint32_t width, height, format, stride, igbp_slot, generation;
850 uint64_t usage, igbp_id;
851 _UnwrapNativeCodec2GrallocMetadata(
852 c2Handle, &width, &height, &format, &usage, &stride, &generation,
853 &igbp_id, &igbp_slot);
854 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
855 GraphicBuffer* graphicBuffer = new GraphicBuffer(
856 grallocHandle, GraphicBuffer::CLONE_HANDLE,
857 width, height, format, 1, usage, stride);
858 ScopedLocalRef<jobject> hardwareBuffer{
859 env,
860 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
861 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
862 env->SetObjectField(
863 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800864 break;
865 }
866 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
867 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
868 case C2BufferData::INVALID: [[fallthrough]];
869 default:
870 return INVALID_OPERATION;
871 }
872 } else {
873 if (!mGraphicOutput) {
874 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700875 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800876 context->mLegacyBuffer = buffer;
877 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
878 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800879 env->CallVoidMethod(
880 linearBlock.get(),
881 gLinearBlockInfo.setInternalStateId,
882 (jlong)context.release(),
883 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800884 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
Arun Johnson8d6a41a2024-01-10 21:14:14 +0000885 maybeSetBufferInfos(env, frame, bufInfos);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800886 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800887 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800888 }
889 }
890 }
891
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700892 jobject formatMap;
893 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800894 if (err != OK) {
895 return err;
896 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700897 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
898 ScopedLocalRef<jobject> format{env, env->NewObject(
899 mediaFormatClass.get(),
900 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
901 formatMap)};
902 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
903 env->DeleteLocalRef(formatMap);
904 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800905
906 sp<RefBase> obj;
907 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
908 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
909 (decltype(changedKeys.get()))obj.get()};
910 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
911 frame, gFields.outputFrameChangedKeysID)};
912 for (const std::string &key : changedKeys->value) {
913 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
914 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
915 }
916 }
917 return OK;
918}
919
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300920status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
921 AString name;
922
923 status_t err = mCodec->getName(&name);
924
925 if (err != OK) {
926 return err;
927 }
928
929 *nameStr = env->NewStringUTF(name.c_str());
930
931 return OK;
932}
933
Chong Zhanga0b72a62018-02-28 18:46:26 -0800934static jobject getCodecCapabilitiesObject(
935 JNIEnv *env, const char *mime, bool isEncoder,
936 const sp<MediaCodecInfo::Capabilities> &capabilities) {
937 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
938 Vector<uint32_t> colorFormats;
939
940 sp<AMessage> defaultFormat = new AMessage();
941 defaultFormat->setString("mime", mime);
942
943 capabilities->getSupportedColorFormats(&colorFormats);
944 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800945 sp<AMessage> details = capabilities->getDetails();
946
947 jobject defaultFormatObj = NULL;
948 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
949 return NULL;
950 }
951 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
952
953 jobject detailsObj = NULL;
954 if (ConvertMessageToMap(env, details, &detailsObj)) {
955 return NULL;
956 }
957 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
958
959 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
960 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
961
962 for (size_t i = 0; i < profileLevels.size(); ++i) {
963 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
964
965 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
966 gCodecInfo.profileLevelClazz));
967
968 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
969 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
970
971 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
972 }
973
974 ScopedLocalRef<jintArray> colorFormatsArray(
975 env, env->NewIntArray(colorFormats.size()));
976 for (size_t i = 0; i < colorFormats.size(); ++i) {
977 jint val = colorFormats.itemAt(i);
978 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
979 }
980
981 return env->NewObject(
982 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800983 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800984 defaultFormatRef.get(), detailsRef.get());
985}
986
987status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
988 sp<MediaCodecInfo> codecInfo;
989
990 status_t err = mCodec->getCodecInfo(&codecInfo);
991
992 if (err != OK) {
993 return err;
994 }
995
996 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800997 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800998
Lajos Molnard2a7f472018-11-15 12:49:20 -0800999 ScopedLocalRef<jstring> canonicalNameObject(env,
1000 env->NewStringUTF(codecInfo->getCodecName()));
1001
1002 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -08001003 bool isEncoder = codecInfo->isEncoder();
1004
Lajos Molnard2a7f472018-11-15 12:49:20 -08001005 Vector<AString> mediaTypes;
1006 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -08001007
1008 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -08001009 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -08001010
Lajos Molnard2a7f472018-11-15 12:49:20 -08001011 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -08001012 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -08001013 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -08001014
1015 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -08001016 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -08001017
1018 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
1019 }
1020
1021 ScopedLocalRef<jclass> codecInfoClazz(env,
1022 env->FindClass("android/media/MediaCodecInfo"));
1023 CHECK(codecInfoClazz.get() != NULL);
1024
1025 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -08001026 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -08001027
1028 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -08001029 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -08001030
1031 return OK;
1032}
1033
Ray Essick81fbc5b2019-12-07 06:24:59 -08001034status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
1035 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -07001036 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -07001037 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -08001038 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -08001039 return status;
1040}
1041
Andreas Huber226065b2013-08-12 10:14:11 -07001042status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
1043 return mCodec->setParameters(msg);
1044}
1045
Andreas Huberb12a5392012-04-30 14:18:33 -07001046void JMediaCodec::setVideoScalingMode(int mode) {
1047 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -07001048 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -07001049 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -07001050 // also signal via param for components that queue to IGBP
1051 sp<AMessage> msg = new AMessage;
1052 msg->setInt32("android._video-scaling", mode);
1053 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -07001054 }
1055}
1056
ybai5e053202018-11-01 13:02:15 +08001057void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
1058 sp<AMessage> msg = new AMessage;
1059 msg->setInt32("audio-presentation-presentation-id", presentationId);
1060 msg->setInt32("audio-presentation-program-id", programId);
1061 (void)mCodec->setParameters(msg);
1062}
1063
Wonsik Kim8798c8c2021-03-18 21:38:57 -07001064status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
1065 std::vector<std::string> names;
1066 status_t status = mCodec->querySupportedVendorParameters(&names);
1067 if (status != OK) {
1068 return status;
1069 }
1070 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
1071 for (const std::string &name : names) {
1072 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
1073 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
1074 }
1075 return OK;
1076}
1077
1078status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
1079 const char *tmp = env->GetStringUTFChars(name, nullptr);
1080 CodecParameterDescriptor desc;
1081 status_t status = mCodec->describeParameter(tmp, &desc);
1082 env->ReleaseStringUTFChars(name, tmp);
1083 if (status != OK) {
1084 return status;
1085 }
1086 jint type = TYPE_NULL;
1087 switch (desc.type) {
1088 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
1089 case AMessage::kTypeSize:
1090 case AMessage::kTypeInt64: type = TYPE_LONG; break;
1091 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
1092 case AMessage::kTypeString: type = TYPE_STRING; break;
1093 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
1094 default: type = TYPE_NULL; break;
1095 }
1096 if (type == TYPE_NULL) {
1097 return BAD_VALUE;
1098 }
1099 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1100 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1101 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1102 return OK;
1103}
1104
1105static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1106 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1107 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1108 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1109 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1110 jobject it = env->CallObjectMethod(
1111 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1112 while (env->CallBooleanMethod(it, hasNextID)) {
1113 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1114 const char *tmp = env->GetStringUTFChars(name, nullptr);
1115 vec->push_back(tmp);
1116 env->ReleaseStringUTFChars(name, tmp);
1117 }
1118}
1119
1120status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1121 std::vector<std::string> names;
1122 BuildVectorFromList(env, namesObj, &names);
1123 return mCodec->subscribeToVendorParameters(names);
1124}
1125
1126status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1127 std::vector<std::string> names;
1128 BuildVectorFromList(env, namesObj, &names);
1129 return mCodec->unsubscribeFromVendorParameters(names);
1130}
1131
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001132static jthrowable createCodecException(
1133 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1134 ScopedLocalRef<jclass> clazz(
1135 env, env->FindClass("android/media/MediaCodec$CodecException"));
1136 CHECK(clazz.get() != NULL);
1137
Ronghua Wuc53ad692015-05-08 14:40:49 -07001138 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001139 CHECK(ctor != NULL);
1140
1141 ScopedLocalRef<jstring> msgObj(
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00001142 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001143
1144 // translate action code to Java equivalent
1145 switch (actionCode) {
1146 case ACTION_CODE_TRANSIENT:
1147 actionCode = gCodecActionCodes.codecActionTransient;
1148 break;
1149 case ACTION_CODE_RECOVERABLE:
1150 actionCode = gCodecActionCodes.codecActionRecoverable;
1151 break;
1152 default:
1153 actionCode = 0; // everything else is fatal
1154 break;
1155 }
1156
Ronghua Wuc53ad692015-05-08 14:40:49 -07001157 /* translate OS errors to Java API CodecException errorCodes */
1158 switch (err) {
1159 case NO_MEMORY:
1160 err = gCodecErrorCodes.errorInsufficientResource;
1161 break;
1162 case DEAD_OBJECT:
1163 err = gCodecErrorCodes.errorReclaimed;
1164 break;
1165 default: /* Other error codes go out as is. */
1166 break;
1167 }
1168
1169 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001170}
1171
Arun Johnson5a4c7332022-12-17 00:47:06 +00001172static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1173 const sp<AMessage> & msg) {
1174 if(msg == nullptr || obj == nullptr) {
1175 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1176 return;
1177 }
1178 size_t numSubSamples = 0;
1179 sp<ABuffer> subSamplesBuffer;
1180 sp<ABuffer> keyBuffer;
1181 sp<ABuffer> ivBuffer;
1182 CryptoPlugin::Mode mode;
1183 CryptoPlugin::Pattern pattern;
1184 CHECK(msg->findInt32("mode", (int*)&mode));
1185 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1186 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1187 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1188 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1189 CHECK(msg->findBuffer("iv", &ivBuffer));
1190 CHECK(msg->findBuffer("key", &keyBuffer));
1191
1192 // subsamples
1193 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1194 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1195 jboolean isCopy;
1196 jint *dstEncryptedSamples =
1197 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1198 jint * dstClearSamples =
1199 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1200
1201 CryptoPlugin::SubSample * samplesArray =
1202 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1203
1204 for(int i = 0 ; i < numSubSamples ; i++) {
1205 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1206 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1207 }
1208 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1209 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1210 // key and iv
1211 jbyteArray keyArray = NULL;
1212 jbyteArray ivArray = NULL;
1213 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1214 keyArray = env->NewByteArray(keyBuffer->size());
1215 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1216 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1217 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1218 }
1219 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1220 ivArray = env->NewByteArray(ivBuffer->size());
1221 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1222 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1223 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1224 }
1225 // set samples, key and iv
1226 env->CallVoidMethod(
1227 obj,
1228 gFields.cryptoInfoSetID,
1229 (jint)numSubSamples,
1230 samplesOfClearDataArr.get(),
1231 samplesOfEncryptedDataArr.get(),
1232 keyArray,
1233 ivArray,
1234 mode);
1235 if (keyArray != NULL) {
1236 env->DeleteLocalRef(keyArray);
1237 }
1238 if (ivArray != NULL) {
1239 env->DeleteLocalRef(ivArray);
1240 }
1241 // set pattern
1242 env->CallVoidMethod(
1243 obj,
1244 gFields.cryptoInfoSetPatternID,
1245 pattern.mEncryptBlocks,
1246 pattern.mSkipBlocks);
1247}
1248
1249static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1250 switch(err) {
1251 case ERROR_DRM_NO_LICENSE:
1252 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1253 defaultMsg = "Crypto key not available";
1254 break;
1255 case ERROR_DRM_LICENSE_EXPIRED:
1256 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1257 defaultMsg = "License expired";
1258 break;
1259 case ERROR_DRM_RESOURCE_BUSY:
1260 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1261 defaultMsg = "Resource busy or unavailable";
1262 break;
1263 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1264 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1265 defaultMsg = "Required output protections are not active";
1266 break;
1267 case ERROR_DRM_SESSION_NOT_OPENED:
1268 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1269 defaultMsg = "Attempted to use a closed session";
1270 break;
1271 case ERROR_DRM_INSUFFICIENT_SECURITY:
1272 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1273 defaultMsg = "Required security level is not met";
1274 break;
1275 case ERROR_DRM_CANNOT_HANDLE:
1276 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1277 defaultMsg = "Operation not supported in this configuration";
1278 break;
1279 case ERROR_DRM_FRAME_TOO_LARGE:
1280 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1281 defaultMsg = "Decrytped frame exceeds size of output buffer";
1282 break;
1283 case ERROR_DRM_SESSION_LOST_STATE:
1284 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1285 defaultMsg = "Session state was lost, open a new session and retry";
1286 break;
1287 default: // Other negative DRM error codes go out best-effort.
1288 jerr = MediaErrorToJavaError(err);
1289 defaultMsg = StrCryptoError(err);
1290 break;
1291 }
1292}
1293static jthrowable createCryptoException(JNIEnv *env, status_t err,
1294 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1295 const sp<AMessage> & cryptoInfo = NULL) {
1296 jthrowable exception = nullptr;
1297 jmethodID constructID = nullptr;
1298 ScopedLocalRef<jobject> cryptoInfoObject(env);
1299 std::string defaultMsg = "Unknown Error";
1300 jint jerr = 0;
1301 // Get a class ref for CryptoException
1302 ScopedLocalRef<jclass> clazz(
1303 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1304 CHECK(clazz.get() != NULL);
1305
1306 // Get constructor ref for CryptoException
1307 constructID = env->GetMethodID(clazz.get(), "<init>",
1308 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1309 CHECK(constructID != NULL);
1310
1311 // create detailed message for exception
1312 CryptoErrorToJavaError(err, jerr, defaultMsg);
1313 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1314 DrmStatus dStatus(err, originalMsg.c_str());
1315 std::string detailedMsg(
1316 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1317 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1318
1319 if (cryptoInfo != nullptr) {
1320 // Class ref for CryptoInfo
1321 ScopedLocalRef<jclass> clazzCryptoInfo(
1322 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1323 CHECK(clazzCryptoInfo.get() != NULL);
1324
1325 // Constructor reference for CryptoInfo
1326 jmethodID constructCryptoInfo =
1327 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1328 CHECK(constructCryptoInfo != NULL);
1329
1330 // Create CryptoInfo jobject
1331 cryptoInfoObject.reset(
1332 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1333 CHECK(cryptoInfoObject.get() != NULL);
1334
1335 // Translate AMesage to CryptoInfo
1336 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1337 }
1338
1339 exception = (jthrowable)env->NewObject(
1340 clazz.get(), constructID, msgObj, jerr,
1341 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1342 cryptoInfoObject.get());
1343
1344 return exception;
1345}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001346void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1347 int32_t arg1, arg2 = 0;
1348 jobject obj = NULL;
Arun Johnson206270e2023-10-31 20:40:12 +00001349 std::vector<jobject> jObjectInfos;
Chong Zhang8d5e5562014-07-08 18:49:21 -07001350 CHECK(msg->findInt32("callbackID", &arg1));
1351 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001352
Chong Zhang8d5e5562014-07-08 18:49:21 -07001353 switch (arg1) {
1354 case MediaCodec::CB_INPUT_AVAILABLE:
1355 {
1356 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001357 break;
1358 }
1359
Chong Zhang8d5e5562014-07-08 18:49:21 -07001360 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001361 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001362 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001363
Chong Zhang8d5e5562014-07-08 18:49:21 -07001364 size_t size, offset;
1365 int64_t timeUs;
1366 uint32_t flags;
1367 CHECK(msg->findSize("size", &size));
1368 CHECK(msg->findSize("offset", &offset));
1369 CHECK(msg->findInt64("timeUs", &timeUs));
1370 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1371
Pavel Laboviche53421b2022-11-01 03:53:27 +00001372 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001373 if (obj == NULL) {
1374 if (env->ExceptionCheck()) {
1375 ALOGE("Could not create MediaCodec.BufferInfo.");
1376 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001377 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001378 jniThrowException(env, "java/lang/IllegalStateException",
1379 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001380 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001381 }
1382
Pavel Laboviche53421b2022-11-01 03:53:27 +00001383 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001384 break;
1385 }
1386
Arun Johnson206270e2023-10-31 20:40:12 +00001387 case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
1388 {
1389 sp<RefBase> spobj = nullptr;
1390 CHECK(msg->findInt32("index", &arg2));
1391 CHECK(msg->findObject("accessUnitInfo", &spobj));
1392 if (spobj != nullptr) {
1393 sp<BufferInfosWrapper> bufferInfoParamsWrapper {
1394 (BufferInfosWrapper *)spobj.get()};
1395 std::vector<AccessUnitInfo> &bufferInfoParams =
1396 bufferInfoParamsWrapper.get()->value;
1397 obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
1398 jint offset = 0;
1399 for (int i = 0 ; i < bufferInfoParams.size(); i++) {
1400 jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
1401 if (bufferInfo != NULL) {
1402 env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
1403 offset,
1404 (jint)(bufferInfoParams)[i].mSize,
1405 (bufferInfoParams)[i].mTimestamp,
1406 (bufferInfoParams)[i].mFlags);
1407 (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
1408 offset += (bufferInfoParams)[i].mSize;
1409 jObjectInfos.push_back(bufferInfo);
1410 }
1411 }
1412 }
1413 break;
1414 }
1415
Arun Johnson5a4c7332022-12-17 00:47:06 +00001416 case MediaCodec::CB_CRYPTO_ERROR:
1417 {
1418 int32_t err, actionCode;
1419 AString errorDetail;
1420 CHECK(msg->findInt32("err", &err));
1421 CHECK(msg->findInt32("actionCode",&actionCode));
1422 CHECK(msg->findString("errorDetail", &errorDetail));
1423 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1424 break;
1425 }
1426
Chong Zhang8d5e5562014-07-08 18:49:21 -07001427 case MediaCodec::CB_ERROR:
1428 {
Chong Zhang94686d12014-07-11 15:53:58 -07001429 int32_t err, actionCode;
1430 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001431 CHECK(msg->findInt32("actionCode", &actionCode));
1432
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001433 // note that DRM errors could conceivably alias into a CodecException
1434 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001435
1436 if (obj == NULL) {
1437 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001438 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001439 env->ExceptionClear();
1440 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001441 jniThrowException(env, "java/lang/IllegalStateException",
1442 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001443 return;
1444 }
Andreas Huberaba67132013-10-22 12:40:01 -07001445
1446 break;
1447 }
1448
Chong Zhang8d5e5562014-07-08 18:49:21 -07001449 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001450 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001451 sp<AMessage> format;
1452 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001453
Chong Zhang8d5e5562014-07-08 18:49:21 -07001454 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001455 jniThrowException(env, "java/lang/IllegalStateException",
1456 "Fatal error: failed to convert format "
1457 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001458 return;
1459 }
Andreas Huberaba67132013-10-22 12:40:01 -07001460
Andreas Huberaba67132013-10-22 12:40:01 -07001461 break;
1462 }
1463
1464 default:
1465 TRESPASS();
1466 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001467 env->CallVoidMethod(
1468 mObject,
1469 gFields.postEventFromNativeID,
1470 EVENT_CALLBACK,
1471 arg1,
1472 arg2,
1473 obj);
1474
Arun Johnson206270e2023-10-31 20:40:12 +00001475 for (int i = 0; i < jObjectInfos.size(); i++) {
1476 env->DeleteLocalRef(jObjectInfos[i]);
1477 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001478 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001479}
1480
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001481void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1482 int32_t arg1 = 0, arg2 = 0;
1483 jobject obj = NULL;
1484 JNIEnv *env = AndroidRuntime::getJNIEnv();
1485
1486 sp<AMessage> data;
1487 CHECK(msg->findMessage("data", &data));
1488
1489 status_t err = ConvertMessageToMap(env, data, &obj);
1490 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001491 jniThrowException(env, "java/lang/IllegalStateException",
1492 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001493 return;
1494 }
1495
1496 env->CallVoidMethod(
1497 mObject, gFields.postEventFromNativeID,
1498 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1499
1500 env->DeleteLocalRef(obj);
1501}
1502
Lajos Molnard8578572015-06-05 20:17:33 -07001503void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1504 int32_t arg1 = 0, arg2 = 0;
1505 jobject obj = NULL;
1506 JNIEnv *env = AndroidRuntime::getJNIEnv();
1507
1508 sp<AMessage> data;
1509 CHECK(msg->findMessage("data", &data));
1510
1511 status_t err = ConvertMessageToMap(env, data, &obj);
1512 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001513 jniThrowException(env, "java/lang/IllegalStateException",
1514 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001515 return;
1516 }
1517
1518 env->CallVoidMethod(
1519 mObject, gFields.postEventFromNativeID,
1520 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1521
1522 env->DeleteLocalRef(obj);
1523}
1524
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001525std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1526 if (mCodec == nullptr) {
1527 return msg ?: "";
1528 }
1529 std::string prefix = "";
1530 if (msg && msg[0] != '\0') {
1531 prefix.append(msg);
1532 prefix.append("\n");
1533 }
1534 return prefix + mCodec->getErrorLog().extract();
1535}
1536
Chong Zhang8d5e5562014-07-08 18:49:21 -07001537void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1538 switch (msg->what()) {
1539 case kWhatCallbackNotify:
1540 {
1541 handleCallback(msg);
1542 break;
1543 }
Lajos Molnard8578572015-06-05 20:17:33 -07001544 case kWhatFrameRendered:
1545 {
1546 handleFrameRenderedNotification(msg);
1547 break;
1548 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001549 case kWhatAsyncReleaseComplete:
1550 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001551 if (mLooper != NULL) {
1552 mLooper->unregisterHandler(id());
1553 mLooper->stop();
1554 mLooper.clear();
1555 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001556 break;
1557 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001558 case kWhatFirstTunnelFrameReady:
1559 {
1560 handleFirstTunnelFrameReadyNotification(msg);
1561 break;
1562 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001563 default:
1564 TRESPASS();
1565 }
Andreas Huberaba67132013-10-22 12:40:01 -07001566}
1567
Robert Shih631a80d2021-02-14 02:23:55 -08001568
Andreas Huber88572f72012-02-21 11:47:18 -08001569} // namespace android
1570
1571////////////////////////////////////////////////////////////////////////////////
1572
1573using namespace android;
1574
1575static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001576 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001577 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001578 if (codec != NULL) {
1579 codec->incStrong(thiz);
1580 }
1581 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001582 /* release MediaCodec and stop the looper now before decStrong.
1583 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1584 * its message handler, doing release() from there will deadlock
1585 * (as MediaCodec::release() post synchronous message to the same looper)
1586 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001587 if (release) {
1588 old->release();
1589 }
Andreas Huber88572f72012-02-21 11:47:18 -08001590 old->decStrong(thiz);
1591 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001592 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001593
1594 return old;
1595}
1596
1597static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001598 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1599 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1600 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001601}
1602
1603static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001604 // Clear Java native reference.
1605 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001606 if (codec != NULL) {
1607 codec->releaseAsync();
1608 }
Andreas Huber88572f72012-02-21 11:47:18 -08001609}
1610
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001611static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1612 jthrowable exception = createCodecException(env, err, actionCode, msg);
1613 env->Throw(exception);
1614}
1615
Robert Shih631a80d2021-02-14 02:23:55 -08001616static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1617 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001618 jthrowable exception = createCryptoException(
1619 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001620 env->Throw(exception);
1621}
1622
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001623static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1624 if (codec == NULL) {
1625 return msg ?: "codec is released already";
1626 }
1627 return codec->getExceptionMessage(msg);
1628}
1629
Andreas Huberbfc56f42012-04-19 12:47:07 -07001630static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001631 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001632 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1633 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001634 switch (err) {
1635 case OK:
1636 return 0;
1637
1638 case -EAGAIN:
1639 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1640
1641 case INFO_FORMAT_CHANGED:
1642 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1643
1644 case INFO_OUTPUT_BUFFERS_CHANGED:
1645 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1646
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001647 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001648 jniThrowException(
1649 env, "java/lang/IllegalStateException",
1650 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001651 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001652
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001653 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001654 jniThrowException(
1655 env, "java/lang/IllegalArgumentException",
1656 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001657 return 0;
1658
Andreas Huber88572f72012-02-21 11:47:18 -08001659 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001660 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001661 throwCryptoException(
1662 env, err,
1663 GetExceptionMessage(codec, msg).c_str(),
1664 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001665 return 0;
1666 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001667 throwCodecException(
1668 env, err, actionCode,
1669 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001670 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001671 }
Andreas Huber88572f72012-02-21 11:47:18 -08001672}
1673
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001674static jint throwExceptionAsNecessary(
1675 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1676 int32_t actionCode = ACTION_CODE_FATAL) {
1677 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1678}
1679
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001680static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1681 JNIEnv *env,
1682 jobject thiz,
1683 jboolean enabled) {
1684 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1685
1686 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001687 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001688 return;
1689 }
1690
1691 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1692
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001693 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001694}
1695
Lajos Molnard8578572015-06-05 20:17:33 -07001696static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1697 JNIEnv *env,
1698 jobject thiz,
1699 jboolean enabled) {
1700 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1701
Wonsik Kim24e53802020-05-08 20:04:26 -07001702 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001703 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001704 return;
1705 }
1706
1707 status_t err = codec->enableOnFrameRenderedListener(enabled);
1708
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001709 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001710}
1711
Chong Zhang8d5e5562014-07-08 18:49:21 -07001712static void android_media_MediaCodec_native_setCallback(
1713 JNIEnv *env,
1714 jobject thiz,
1715 jobject cb) {
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);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001720 return;
1721 }
1722
1723 status_t err = codec->setCallback(cb);
1724
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001725 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001726}
1727
Andreas Huber88572f72012-02-21 11:47:18 -08001728static void android_media_MediaCodec_native_configure(
1729 JNIEnv *env,
1730 jobject thiz,
1731 jobjectArray keys, jobjectArray values,
1732 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001733 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001734 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001735 jint flags) {
1736 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1737
Wonsik Kim24e53802020-05-08 20:04:26 -07001738 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001739 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001740 return;
1741 }
1742
1743 sp<AMessage> format;
1744 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1745
1746 if (err != OK) {
1747 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1748 return;
1749 }
1750
Andy McFaddend47f7d82012-12-18 09:48:38 -08001751 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001752 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001753 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001754 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001755 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001756 } else {
1757 jniThrowException(
1758 env,
1759 "java/lang/IllegalArgumentException",
1760 "The surface has been released");
1761 return;
1762 }
1763 }
1764
Andreas Huber8240d922012-04-04 14:06:32 -07001765 sp<ICrypto> crypto;
1766 if (jcrypto != NULL) {
1767 crypto = JCrypto::GetCrypto(env, jcrypto);
1768 }
1769
Chong Zhangd5927ae2017-01-03 11:07:18 -08001770 sp<IDescrambler> descrambler;
1771 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001772 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001773 }
1774
1775 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001776
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001777 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001778}
1779
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001780static void android_media_MediaCodec_native_setSurface(
1781 JNIEnv *env,
1782 jobject thiz,
1783 jobject jsurface) {
1784 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1785
Wonsik Kim24e53802020-05-08 20:04:26 -07001786 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001787 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001788 return;
1789 }
1790
1791 sp<IGraphicBufferProducer> bufferProducer;
1792 if (jsurface != NULL) {
1793 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1794 if (surface != NULL) {
1795 bufferProducer = surface->getIGraphicBufferProducer();
1796 } else {
1797 jniThrowException(
1798 env,
1799 "java/lang/IllegalArgumentException",
1800 "The surface has been released");
1801 return;
1802 }
1803 }
1804
1805 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001806 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001807}
1808
Lajos Molnar3a7c83a2024-03-29 08:15:59 -07001809static void android_media_MediaCodec_native_detachOutputSurface(
1810 JNIEnv *env,
1811 jobject thiz) {
1812 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1813
1814 if (codec == NULL || codec->initCheck() != OK) {
1815 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
1816 return;
1817 }
1818
1819 status_t err = codec->detachOutputSurface();
1820 throwExceptionAsNecessary(env, err, codec);
1821}
1822
Chong Zhang8034d602015-04-28 13:38:48 -07001823sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1824 JNIEnv* env, jobject object) {
1825 sp<PersistentSurface> persistentSurface;
1826
1827 jobject lock = env->GetObjectField(
1828 object, gPersistentSurfaceClassInfo.mLock);
1829 if (env->MonitorEnter(lock) == JNI_OK) {
1830 persistentSurface = reinterpret_cast<PersistentSurface *>(
1831 env->GetLongField(object,
1832 gPersistentSurfaceClassInfo.mPersistentObject));
1833 env->MonitorExit(lock);
1834 }
1835 env->DeleteLocalRef(lock);
1836
1837 return persistentSurface;
1838}
1839
1840static jobject android_media_MediaCodec_createPersistentInputSurface(
1841 JNIEnv* env, jclass /* clazz */) {
1842 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1843 sp<PersistentSurface> persistentSurface =
1844 MediaCodec::CreatePersistentInputSurface();
1845
1846 if (persistentSurface == NULL) {
1847 return NULL;
1848 }
1849
1850 sp<Surface> surface = new Surface(
1851 persistentSurface->getBufferProducer(), true);
1852 if (surface == NULL) {
1853 return NULL;
1854 }
1855
1856 jobject object = env->NewObject(
1857 gPersistentSurfaceClassInfo.clazz,
1858 gPersistentSurfaceClassInfo.ctor);
1859
1860 if (object == NULL) {
1861 if (env->ExceptionCheck()) {
1862 ALOGE("Could not create PersistentSurface.");
1863 env->ExceptionClear();
1864 }
1865 return NULL;
1866 }
1867
1868 jobject lock = env->GetObjectField(
1869 object, gPersistentSurfaceClassInfo.mLock);
1870 if (env->MonitorEnter(lock) == JNI_OK) {
1871 env->CallVoidMethod(
1872 object,
1873 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1874 (jlong)surface.get());
1875 env->SetLongField(
1876 object,
1877 gPersistentSurfaceClassInfo.mPersistentObject,
1878 (jlong)persistentSurface.get());
1879 env->MonitorExit(lock);
1880 } else {
1881 env->DeleteLocalRef(object);
1882 object = NULL;
1883 }
1884 env->DeleteLocalRef(lock);
1885
1886 if (object != NULL) {
1887 surface->incStrong(&sRefBaseOwner);
1888 persistentSurface->incStrong(&sRefBaseOwner);
1889 }
1890
1891 return object;
1892}
1893
1894static void android_media_MediaCodec_releasePersistentInputSurface(
1895 JNIEnv* env, jclass /* clazz */, jobject object) {
1896 sp<PersistentSurface> persistentSurface;
1897
1898 jobject lock = env->GetObjectField(
1899 object, gPersistentSurfaceClassInfo.mLock);
1900 if (env->MonitorEnter(lock) == JNI_OK) {
1901 persistentSurface = reinterpret_cast<PersistentSurface *>(
1902 env->GetLongField(
1903 object, gPersistentSurfaceClassInfo.mPersistentObject));
1904 env->SetLongField(
1905 object,
1906 gPersistentSurfaceClassInfo.mPersistentObject,
1907 (jlong)0);
1908 env->MonitorExit(lock);
1909 }
1910 env->DeleteLocalRef(lock);
1911
1912 if (persistentSurface != NULL) {
1913 persistentSurface->decStrong(&sRefBaseOwner);
1914 }
1915 // no need to release surface as it will be released by Surface's jni
1916}
1917
Chong Zhang9560ddb2015-05-13 10:25:29 -07001918static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001919 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001920 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001921
1922 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001923 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001924 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001925 return;
1926 }
1927
1928 sp<PersistentSurface> persistentSurface =
1929 android_media_MediaCodec_getPersistentInputSurface(env, object);
1930
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001931 if (persistentSurface == NULL) {
1932 throwExceptionAsNecessary(
1933 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1934 return;
1935 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001936 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001937 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001938 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001939 }
1940}
1941
Andy McFadden2621e402013-02-19 07:29:21 -08001942static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1943 jobject thiz) {
1944 ALOGV("android_media_MediaCodec_createInputSurface");
1945
1946 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001947 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001948 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001949 return NULL;
1950 }
1951
1952 // Tell the MediaCodec that we want to use a Surface as input.
1953 sp<IGraphicBufferProducer> bufferProducer;
1954 status_t err = codec->createInputSurface(&bufferProducer);
1955 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001956 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001957 return NULL;
1958 }
1959
1960 // Wrap the IGBP in a Java-language Surface.
1961 return android_view_Surface_createFromIGraphicBufferProducer(env,
1962 bufferProducer);
1963}
1964
Andreas Huber88572f72012-02-21 11:47:18 -08001965static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1966 ALOGV("android_media_MediaCodec_start");
1967
1968 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1969
Wonsik Kim24e53802020-05-08 20:04:26 -07001970 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001971 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001972 return;
1973 }
1974
1975 status_t err = codec->start();
1976
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001977 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001978}
1979
1980static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1981 ALOGV("android_media_MediaCodec_stop");
1982
1983 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1984
Wonsik Kim24e53802020-05-08 20:04:26 -07001985 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001986 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001987 return;
1988 }
1989
1990 status_t err = codec->stop();
1991
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001992 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001993}
1994
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001995static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1996 ALOGV("android_media_MediaCodec_reset");
1997
1998 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1999
Wonsik Kim24e53802020-05-08 20:04:26 -07002000 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002001 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07002002 return;
2003 }
2004
2005 status_t err = codec->reset();
2006 if (err != OK) {
2007 // treat all errors as fatal for now, though resource not available
2008 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002009 // we also should avoid sending INVALID_OPERATION here due to
2010 // the transitory nature of reset(), it should not inadvertently
2011 // trigger an IllegalStateException.
2012 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07002013 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002014 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07002015}
2016
Andreas Huber88572f72012-02-21 11:47:18 -08002017static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
2018 ALOGV("android_media_MediaCodec_flush");
2019
2020 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2021
Wonsik Kim24e53802020-05-08 20:04:26 -07002022 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002023 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002024 return;
2025 }
2026
2027 status_t err = codec->flush();
2028
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002029 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002030}
2031
2032static void android_media_MediaCodec_queueInputBuffer(
2033 JNIEnv *env,
2034 jobject thiz,
2035 jint index,
2036 jint offset,
2037 jint size,
2038 jlong timestampUs,
2039 jint flags) {
2040 ALOGV("android_media_MediaCodec_queueInputBuffer");
2041
2042 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2043
Wonsik Kim24e53802020-05-08 20:04:26 -07002044 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002045 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002046 return;
2047 }
2048
Andreas Huberbfc56f42012-04-19 12:47:07 -07002049 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08002050
Andreas Huberbfc56f42012-04-19 12:47:07 -07002051 status_t err = codec->queueInputBuffer(
2052 index, offset, size, timestampUs, flags, &errorDetailMsg);
2053
2054 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002055 env, err, ACTION_CODE_FATAL,
2056 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08002057}
2058
Arun Johnson206270e2023-10-31 20:40:12 +00002059static status_t extractInfosFromObject(
2060 JNIEnv * const env,
2061 jint * const initialOffset,
2062 jint * const totalSize,
2063 std::vector<AccessUnitInfo> * const infos,
2064 const jobjectArray &objArray,
2065 AString * const errorDetailMsg) {
2066 if (totalSize == nullptr
2067 || initialOffset == nullptr
2068 || infos == nullptr) {
2069 if (errorDetailMsg) {
2070 *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
2071 }
2072 return BAD_VALUE;
2073 }
2074 const jsize numEntries = env->GetArrayLength(objArray);
2075 if (numEntries <= 0) {
2076 if (errorDetailMsg) {
2077 *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
2078 }
2079 return BAD_VALUE;
2080 }
2081 *initialOffset = 0;
2082 *totalSize = 0;
2083 for (jsize i = 0; i < numEntries; i++) {
2084 jobject param = env->GetObjectArrayElement(objArray, i);
2085 if (param == NULL) {
2086 if (errorDetailMsg) {
2087 *errorDetailMsg = "Error: Queuing a null BufferInfo";
2088 }
2089 return BAD_VALUE;
2090 }
2091 size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
2092 size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
2093 uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
2094 if (flags == 0 && size == 0) {
2095 if (errorDetailMsg) {
2096 *errorDetailMsg = "Error: Queuing an empty BufferInfo";
2097 }
2098 return BAD_VALUE;
2099 }
2100 if (i == 0) {
2101 *initialOffset = offset;
Arun Johnson8b390cb2024-04-16 16:54:26 +00002102 if (CC_UNLIKELY(*initialOffset < 0)) {
2103 if (errorDetailMsg) {
2104 *errorDetailMsg = "Error: offset/size in BufferInfo";
2105 }
2106 return BAD_VALUE;
2107 }
Arun Johnson206270e2023-10-31 20:40:12 +00002108 }
Arun Johnson8b390cb2024-04-16 16:54:26 +00002109 if (CC_UNLIKELY(((ssize_t)(UINT32_MAX - offset) < (ssize_t)size)
Arun Johnson206270e2023-10-31 20:40:12 +00002110 || ((offset - *initialOffset) != *totalSize))) {
2111 if (errorDetailMsg) {
2112 *errorDetailMsg = "Error: offset/size in BufferInfo";
2113 }
2114 return BAD_VALUE;
2115 }
2116 infos->emplace_back(
2117 flags,
2118 size,
2119 env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
2120 *totalSize += size;
2121 }
2122 return OK;
2123}
2124
2125static void android_media_MediaCodec_queueInputBuffers(
2126 JNIEnv *env,
2127 jobject thiz,
2128 jint index,
2129 jobjectArray objArray) {
2130 ALOGV("android_media_MediaCodec_queueInputBuffers");
2131 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2132 if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
2133 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2134 return;
2135 }
2136 sp<BufferInfosWrapper> infoObj =
2137 new BufferInfosWrapper{decltype(infoObj->value)()};
2138 AString errorDetailMsg;
2139 jint initialOffset = 0;
2140 jint totalSize = 0;
2141 status_t err = extractInfosFromObject(
2142 env,
2143 &initialOffset,
2144 &totalSize,
2145 &infoObj->value,
2146 objArray,
2147 &errorDetailMsg);
2148 if (err == OK) {
2149 err = codec->queueInputBuffers(
2150 index,
2151 initialOffset,
2152 totalSize,
2153 infoObj,
2154 &errorDetailMsg);
2155 }
2156 throwExceptionAsNecessary(
2157 env, err, ACTION_CODE_FATAL,
2158 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2159}
2160
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002161struct NativeCryptoInfo {
2162 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
2163 : mEnv{env},
2164 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
2165 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
2166 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2167
2168 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
2169 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
2170
2171 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
2172 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
2173
2174 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2175 if (jmode == gCryptoModes.Unencrypted) {
2176 mMode = CryptoPlugin::kMode_Unencrypted;
2177 } else if (jmode == gCryptoModes.AesCtr) {
2178 mMode = CryptoPlugin::kMode_AES_CTR;
2179 } else if (jmode == gCryptoModes.AesCbc) {
2180 mMode = CryptoPlugin::kMode_AES_CBC;
2181 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002182 throwExceptionAsNecessary(
2183 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2184 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002185 return;
2186 }
2187
2188 ScopedLocalRef<jobject> patternObj{
2189 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
2190
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002191 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002192 mPattern.mEncryptBlocks = 0;
2193 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002194 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002195 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002196 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002197 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002198 patternObj.get(), gFields.patternSkipBlocksID);
2199 }
2200
2201 mErr = OK;
2202 if (mNumSubSamples <= 0) {
2203 mErr = -EINVAL;
2204 } else if (numBytesOfClearDataObj == nullptr
2205 && numBytesOfEncryptedDataObj == nullptr) {
2206 mErr = -EINVAL;
2207 } else if (numBytesOfEncryptedDataObj != nullptr
2208 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
2209 mErr = -ERANGE;
2210 } else if (numBytesOfClearDataObj != nullptr
2211 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
2212 mErr = -ERANGE;
2213 // subSamples array may silently overflow if number of samples are too large. Use
2214 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2215 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
2216 mErr = -EINVAL;
2217 } else {
2218 jint *numBytesOfClearData =
2219 (numBytesOfClearDataObj == nullptr)
2220 ? nullptr
2221 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
2222
2223 jint *numBytesOfEncryptedData =
2224 (numBytesOfEncryptedDataObj == nullptr)
2225 ? nullptr
2226 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
2227
2228 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
2229
2230 for (jint i = 0; i < mNumSubSamples; ++i) {
2231 mSubSamples[i].mNumBytesOfClearData =
2232 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
2233
2234 mSubSamples[i].mNumBytesOfEncryptedData =
2235 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
2236 }
2237
2238 if (numBytesOfEncryptedData != nullptr) {
2239 env->ReleaseIntArrayElements(
2240 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
2241 numBytesOfEncryptedData = nullptr;
2242 }
2243
2244 if (numBytesOfClearData != nullptr) {
2245 env->ReleaseIntArrayElements(
2246 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2247 numBytesOfClearData = nullptr;
2248 }
2249 }
2250
2251 if (mErr == OK && mKeyObj.get() != nullptr) {
2252 if (env->GetArrayLength(mKeyObj.get()) != 16) {
2253 mErr = -EINVAL;
2254 } else {
2255 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2256 }
2257 }
2258
2259 if (mErr == OK && mIvObj.get() != nullptr) {
2260 if (env->GetArrayLength(mIvObj.get()) != 16) {
2261 mErr = -EINVAL;
2262 } else {
2263 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2264 }
2265 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002266
2267 }
2268
2269 explicit NativeCryptoInfo(jint size)
2270 : mIvObj{nullptr, nullptr},
2271 mKeyObj{nullptr, nullptr},
2272 mMode{CryptoPlugin::kMode_Unencrypted},
2273 mPattern{0, 0} {
2274 mSubSamples = new CryptoPlugin::SubSample[1];
2275 mNumSubSamples = 1;
2276 mSubSamples[0].mNumBytesOfClearData = size;
2277 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002278 }
2279
2280 ~NativeCryptoInfo() {
2281 if (mIv != nullptr) {
2282 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2283 }
2284
2285 if (mKey != nullptr) {
2286 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2287 }
2288
2289 if (mSubSamples != nullptr) {
2290 delete[] mSubSamples;
2291 }
2292 }
2293
2294 JNIEnv *mEnv{nullptr};
2295 ScopedLocalRef<jbyteArray> mIvObj;
2296 ScopedLocalRef<jbyteArray> mKeyObj;
2297 status_t mErr{OK};
2298
2299 CryptoPlugin::SubSample *mSubSamples{nullptr};
2300 int32_t mNumSubSamples{0};
2301 jbyte *mIv{nullptr};
2302 jbyte *mKey{nullptr};
2303 enum CryptoPlugin::Mode mMode;
2304 CryptoPlugin::Pattern mPattern;
2305};
2306
Arun Johnson4ca49092024-02-01 19:07:15 +00002307// This class takes away all dependencies on java(env and jni) and
2308// could be used for taking cryptoInfo objects to MediaCodec.
2309struct MediaCodecCryptoInfo: public CodecCryptoInfo {
2310 explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
2311 if (cryptoInfo.mErr == OK) {
2312 mNumSubSamples = cryptoInfo.mNumSubSamples;
2313 mMode = cryptoInfo.mMode;
2314 mPattern = cryptoInfo.mPattern;
2315 if (cryptoInfo.mKey != nullptr) {
2316 mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
2317 mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
2318 }
2319 if (cryptoInfo.mIv != nullptr) {
2320 mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
2321 mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
2322 }
2323 if (cryptoInfo.mSubSamples != nullptr) {
2324 mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
2325 if (mSubSamplesBuffer.get()) {
2326 CryptoPlugin::SubSample * samples =
2327 (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2328 for (int s = 0 ; s < mNumSubSamples ; s++) {
2329 samples[s].mNumBytesOfClearData =
2330 cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
2331 samples[s].mNumBytesOfEncryptedData =
2332 cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
2333 }
2334 mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2335 }
2336 }
2337
2338 }
2339 }
2340
2341 explicit MediaCodecCryptoInfo(jint size) {
2342 mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
2343 mNumSubSamples = 1;
2344 if (mSubSamplesBuffer.get()) {
2345 CryptoPlugin::SubSample * samples =
2346 (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
2347 samples[0].mNumBytesOfClearData = size;
2348 samples[0].mNumBytesOfEncryptedData = 0;
2349 mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
2350 }
2351 }
2352 ~MediaCodecCryptoInfo() {}
2353
2354protected:
2355 // all backup buffers for the base object.
2356 sp<ABuffer> mKeyBuffer;
2357 sp<ABuffer> mIvBuffer;
2358 sp<ABuffer> mSubSamplesBuffer;
2359
2360};
2361
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002362static void android_media_MediaCodec_queueSecureInputBuffer(
2363 JNIEnv *env,
2364 jobject thiz,
2365 jint index,
2366 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002367 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002368 jlong timestampUs,
2369 jint flags) {
2370 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2371
2372 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2373
Wonsik Kim24e53802020-05-08 20:04:26 -07002374 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002375 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002376 return;
2377 }
2378
Wonsik Kim1cac4252020-01-24 11:45:37 -08002379 jint numSubSamples =
2380 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2381
2382 jintArray numBytesOfClearDataObj =
2383 (jintArray)env->GetObjectField(
2384 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2385
2386 jintArray numBytesOfEncryptedDataObj =
2387 (jintArray)env->GetObjectField(
2388 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2389
2390 jbyteArray keyObj =
2391 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2392
2393 jbyteArray ivObj =
2394 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2395
2396 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2397 enum CryptoPlugin::Mode mode;
2398 if (jmode == gCryptoModes.Unencrypted) {
2399 mode = CryptoPlugin::kMode_Unencrypted;
2400 } else if (jmode == gCryptoModes.AesCtr) {
2401 mode = CryptoPlugin::kMode_AES_CTR;
2402 } else if (jmode == gCryptoModes.AesCbc) {
2403 mode = CryptoPlugin::kMode_AES_CBC;
2404 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002405 throwExceptionAsNecessary(
2406 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2407 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08002408 return;
2409 }
2410
2411 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2412
2413 CryptoPlugin::Pattern pattern;
2414 if (patternObj == NULL) {
2415 pattern.mEncryptBlocks = 0;
2416 pattern.mSkipBlocks = 0;
2417 } else {
2418 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2419 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2420 }
2421
2422 status_t err = OK;
2423
2424 CryptoPlugin::SubSample *subSamples = NULL;
2425 jbyte *key = NULL;
2426 jbyte *iv = NULL;
2427
2428 if (numSubSamples <= 0) {
2429 err = -EINVAL;
2430 } else if (numBytesOfClearDataObj == NULL
2431 && numBytesOfEncryptedDataObj == NULL) {
2432 err = -EINVAL;
2433 } else if (numBytesOfEncryptedDataObj != NULL
2434 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2435 err = -ERANGE;
2436 } else if (numBytesOfClearDataObj != NULL
2437 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2438 err = -ERANGE;
2439 // subSamples array may silently overflow if number of samples are too large. Use
2440 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2441 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2442 err = -EINVAL;
2443 } else {
2444 jboolean isCopy;
2445
2446 jint *numBytesOfClearData =
2447 (numBytesOfClearDataObj == NULL)
2448 ? NULL
2449 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2450
2451 jint *numBytesOfEncryptedData =
2452 (numBytesOfEncryptedDataObj == NULL)
2453 ? NULL
2454 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2455
2456 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2457
2458 for (jint i = 0; i < numSubSamples; ++i) {
2459 subSamples[i].mNumBytesOfClearData =
2460 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2461
2462 subSamples[i].mNumBytesOfEncryptedData =
2463 (numBytesOfEncryptedData == NULL)
2464 ? 0 : numBytesOfEncryptedData[i];
2465 }
2466
2467 if (numBytesOfEncryptedData != NULL) {
2468 env->ReleaseIntArrayElements(
2469 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2470 numBytesOfEncryptedData = NULL;
2471 }
2472
2473 if (numBytesOfClearData != NULL) {
2474 env->ReleaseIntArrayElements(
2475 numBytesOfClearDataObj, numBytesOfClearData, 0);
2476 numBytesOfClearData = NULL;
2477 }
2478 }
2479
2480 if (err == OK && keyObj != NULL) {
2481 if (env->GetArrayLength(keyObj) != 16) {
2482 err = -EINVAL;
2483 } else {
2484 jboolean isCopy;
2485 key = env->GetByteArrayElements(keyObj, &isCopy);
2486 }
2487 }
2488
2489 if (err == OK && ivObj != NULL) {
2490 if (env->GetArrayLength(ivObj) != 16) {
2491 err = -EINVAL;
2492 } else {
2493 jboolean isCopy;
2494 iv = env->GetByteArrayElements(ivObj, &isCopy);
2495 }
2496 }
2497
Andreas Huberbfc56f42012-04-19 12:47:07 -07002498 AString errorDetailMsg;
2499
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002500 if (err == OK) {
2501 err = codec->queueSecureInputBuffer(
2502 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002503 subSamples, numSubSamples,
2504 (const uint8_t *)key, (const uint8_t *)iv,
2505 mode,
2506 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002507 timestampUs,
2508 flags,
2509 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002510 }
2511
Wonsik Kim1cac4252020-01-24 11:45:37 -08002512 if (iv != NULL) {
2513 env->ReleaseByteArrayElements(ivObj, iv, 0);
2514 iv = NULL;
2515 }
2516
2517 if (key != NULL) {
2518 env->ReleaseByteArrayElements(keyObj, key, 0);
2519 key = NULL;
2520 }
2521
2522 delete[] subSamples;
2523 subSamples = NULL;
2524
Andreas Huberbfc56f42012-04-19 12:47:07 -07002525 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002526 env, err, ACTION_CODE_FATAL,
2527 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002528}
2529
Arun Johnson4ca49092024-02-01 19:07:15 +00002530static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
2531 jint * const totalSize,
2532 std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
2533 const jobjectArray &objArray,
2534 AString * const errorDetailMsg) {
2535 if (env == nullptr
2536 || cryptoInfoObjs == nullptr
2537 || totalSize == nullptr) {
2538 if (errorDetailMsg) {
2539 *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2540 }
2541 return BAD_VALUE;
2542 }
2543 const jsize numEntries = env->GetArrayLength(objArray);
2544 if (numEntries <= 0) {
2545 if (errorDetailMsg) {
2546 *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
2547 }
2548 return BAD_VALUE;
2549 }
2550 cryptoInfoObjs->clear();
2551 *totalSize = 0;
2552 jint size = 0;
2553 for (jsize i = 0; i < numEntries ; i++) {
2554 jobject param = env->GetObjectArrayElement(objArray, i);
2555 if (param == NULL) {
2556 if (errorDetailMsg) {
2557 *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
2558 }
2559 return BAD_VALUE;
2560 }
2561 NativeCryptoInfo nativeInfo(env, param);
2562 std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
2563 for (int i = 0; i < info->mNumSubSamples; i++) {
2564 size += info->mSubSamples[i].mNumBytesOfClearData;
2565 size += info->mSubSamples[i].mNumBytesOfEncryptedData;
2566 }
2567 cryptoInfoObjs->push_back(std::move(info));
2568 }
2569 *totalSize = size;
2570 return OK;
2571}
2572
2573
2574static void android_media_MediaCodec_queueSecureInputBuffers(
2575 JNIEnv *env,
2576 jobject thiz,
2577 jint index,
2578 jobjectArray bufferInfosObjs,
2579 jobjectArray cryptoInfoObjs) {
2580 ALOGV("android_media_MediaCodec_queueSecureInputBuffers");
2581
2582 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2583
2584 if (codec == NULL || codec->initCheck() != OK) {
2585 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
2586 return;
2587 }
2588 sp<BufferInfosWrapper> auInfos =
2589 new BufferInfosWrapper{decltype(auInfos->value)()};
2590 sp<CryptoInfosWrapper> cryptoInfos =
2591 new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
2592 AString errorDetailMsg;
2593 jint initialOffset = 0;
2594 jint totalSize = 0;
2595 status_t err = extractInfosFromObject(
2596 env,
2597 &initialOffset,
2598 &totalSize,
2599 &auInfos->value,
2600 bufferInfosObjs,
2601 &errorDetailMsg);
2602 if (err == OK) {
2603 err = extractCryptoInfosFromObjectArray(env,
2604 &totalSize,
2605 &cryptoInfos->value,
2606 cryptoInfoObjs,
2607 &errorDetailMsg);
2608 }
2609 if (err == OK) {
2610 err = codec->queueSecureInputBuffers(
2611 index,
2612 initialOffset,
2613 totalSize,
2614 auInfos,
2615 cryptoInfos,
2616 &errorDetailMsg);
2617 }
2618 throwExceptionAsNecessary(
2619 env, err, ACTION_CODE_FATAL,
2620 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
2621}
2622
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002623static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002624 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2625 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2626 env, bufferObj);
2627 AHardwareBuffer_Desc desc;
2628 AHardwareBuffer_describe(hardwareBuffer, &desc);
2629 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2630 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2631 return nullptr;
2632 }
2633 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2634 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2635 return nullptr;
2636 }
2637 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2638
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002639 uint64_t cpuUsage = 0;
2640 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2641 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002642
2643 AHardwareBuffer_Planes planes;
2644 int err = AHardwareBuffer_lockPlanes(
2645 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2646 if (err != 0) {
2647 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2648 return nullptr;
2649 }
2650
2651 if (planes.planeCount != 3) {
2652 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2653 return nullptr;
2654 }
2655
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002656 ScopedLocalRef<jobjectArray> buffersArray{
2657 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2658 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2659 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002660
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002661 jboolean isCopy = JNI_FALSE;
2662 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2663 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2664
2665 // For Y plane
2666 int rowSampling = 1;
2667 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002668 // plane indices are Y-U-V.
2669 for (uint32_t i = 0; i < 3; ++i) {
2670 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002671 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2672 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2673 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002674 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2675 env,
2676 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002677 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002678 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002679 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002680 readOnly,
2681 true)};
2682
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002683 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2684 rowStrides[i] = plane.rowStride;
2685 pixelStrides[i] = plane.pixelStride;
2686 // For U-V planes
2687 rowSampling = 2;
2688 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002689 }
2690
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002691 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2692 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2693 rowStrides = pixelStrides = nullptr;
2694
Wonsik Kim637afb22020-02-25 14:27:29 -08002695 ScopedLocalRef<jclass> imageClazz(
2696 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2697 CHECK(imageClazz.get() != NULL);
2698
2699 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002700 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002701
2702 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002703 buffersArray.get(),
2704 rowStridesArray.get(),
2705 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002706 desc.width,
2707 desc.height,
2708 desc.format, // ???
2709 (jboolean)readOnly /* readOnly */,
2710 (jlong)0 /* timestamp */,
2711 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2712 (jlong)hardwareBuffer);
2713
2714 // if MediaImage creation fails, return null
2715 if (env->ExceptionCheck()) {
2716 env->ExceptionDescribe();
2717 env->ExceptionClear();
2718 return nullptr;
2719 }
2720
2721 AHardwareBuffer_acquire(hardwareBuffer);
2722
2723 return img;
2724}
2725
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002726static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2727 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002728 if (context == 0) {
2729 return;
2730 }
2731 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2732
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002733 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2734 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002735 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2736 // Continue to release the hardwareBuffer
2737 }
2738
2739 AHardwareBuffer_release(hardwareBuffer);
2740}
2741
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002742static status_t ConvertKeyValueListsToAMessage(
2743 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2744 static struct Fields {
2745 explicit Fields(JNIEnv *env) {
2746 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2747 CHECK(clazz.get() != NULL);
2748 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2749
2750 clazz.reset(env->FindClass("java/lang/Integer"));
2751 CHECK(clazz.get() != NULL);
2752 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2753
2754 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2755 CHECK(mIntegerValueId != NULL);
2756
2757 clazz.reset(env->FindClass("java/lang/Long"));
2758 CHECK(clazz.get() != NULL);
2759 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2760
2761 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2762 CHECK(mLongValueId != NULL);
2763
2764 clazz.reset(env->FindClass("java/lang/Float"));
2765 CHECK(clazz.get() != NULL);
2766 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2767
2768 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2769 CHECK(mFloatValueId != NULL);
2770
2771 clazz.reset(env->FindClass("java/util/ArrayList"));
2772 CHECK(clazz.get() != NULL);
2773
2774 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2775 CHECK(mByteBufferArrayId != NULL);
2776 }
2777
2778 jclass mStringClass;
2779 jclass mIntegerClass;
2780 jmethodID mIntegerValueId;
2781 jclass mLongClass;
2782 jmethodID mLongValueId;
2783 jclass mFloatClass;
2784 jmethodID mFloatValueId;
2785 jmethodID mByteBufferArrayId;
2786 } sFields{env};
2787
2788 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2789 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2790 return BAD_VALUE;
2791 }
2792
2793 sp<AMessage> result{new AMessage};
2794 for (jint i = 0; i < size; ++i) {
2795 ScopedLocalRef<jstring> jkey{
2796 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2797 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2798 AString key;
2799 if (tmp) {
2800 key.setTo(tmp);
2801 }
2802 env->ReleaseStringUTFChars(jkey.get(), tmp);
2803 if (key.empty()) {
2804 return NO_MEMORY;
2805 }
2806
2807 ScopedLocalRef<jobject> jvalue{
2808 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2809
2810 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2811 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2812 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002813 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002814 return NO_MEMORY;
2815 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002816 value.setTo(tmp);
2817 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002818 result->setString(key.c_str(), value);
2819 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2820 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2821 result->setInt32(key.c_str(), value);
2822 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2823 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2824 result->setInt64(key.c_str(), value);
2825 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2826 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2827 result->setFloat(key.c_str(), value);
2828 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002829 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2830 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002831 sp<ABuffer> buffer{new ABuffer(limit - position)};
2832 void *data = env->GetDirectBufferAddress(jvalue.get());
2833 if (data != nullptr) {
2834 memcpy(buffer->data(),
2835 static_cast<const uint8_t *>(data) + position,
2836 buffer->size());
2837 } else {
2838 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2839 jvalue.get(), sFields.mByteBufferArrayId)};
2840 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2841 reinterpret_cast<jbyte *>(buffer->data()));
2842 }
2843 result->setBuffer(key.c_str(), buffer);
2844 }
2845 }
2846
2847 *msg = result;
2848 return OK;
2849}
2850
Wonsik Kim8569a662022-05-24 14:16:44 -07002851static bool obtain(
2852 JMediaCodecLinearBlock *context,
2853 int capacity,
2854 const std::vector<std::string> &names,
2855 bool secure) {
2856 if (secure) {
2857 // Start at 1MB, which is an arbitrary starting point that can
2858 // increase when needed.
2859 constexpr size_t kInitialDealerCapacity = 1048576;
2860 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2861 kInitialDealerCapacity, "JNI(1MB)");
2862 context->mMemory = sDealer->allocate(capacity);
2863 if (context->mMemory == nullptr) {
2864 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2865 while (capacity * 2 > newDealerCapacity) {
2866 newDealerCapacity *= 2;
2867 }
2868 ALOGI("LinearBlock.native_obtain: "
2869 "Dealer capacity increasing from %zuMB to %zuMB",
2870 sDealer->getMemoryHeap()->getSize() / 1048576,
2871 newDealerCapacity / 1048576);
2872 sDealer = new MemoryDealer(
2873 newDealerCapacity,
2874 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2875 context->mMemory = sDealer->allocate(capacity);
2876 }
2877 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2878 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2879 } else {
2880 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2881 if (!context->mBlock) {
2882 return false;
2883 }
2884 }
2885 context->mCodecNames = names;
2886 return true;
2887}
2888
2889static void extractMemoryFromContext(
2890 JMediaCodecLinearBlock *context,
2891 jint offset,
2892 jint size,
2893 sp<hardware::HidlMemory> *memory) {
Arun Johnson5fb6f672024-04-12 17:04:01 +00002894 if ((offset + size) > context->capacity()) {
2895 ALOGW("extractMemoryFromContext: offset + size provided exceed capacity");
2896 return;
2897 }
Wonsik Kim8569a662022-05-24 14:16:44 -07002898 *memory = context->toHidlMemory();
2899 if (*memory == nullptr) {
2900 if (!context->mBlock) {
2901 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2902 return;
2903 }
2904 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
Arun Johnson5fb6f672024-04-12 17:04:01 +00002905 context->capacity());
Wonsik Kim8569a662022-05-24 14:16:44 -07002906 if (!obtain(context, context->capacity(),
2907 context->mCodecNames, true /* secure */)) {
2908 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2909 return;
2910 }
Wonsik Kim8569a662022-05-24 14:16:44 -07002911 *memory = context->toHidlMemory();
2912 }
Arun Johnson5fb6f672024-04-12 17:04:01 +00002913 if (context->mBlock == nullptr || context->mReadWriteMapping == nullptr) {
2914 ALOGW("extractMemoryFromContext: Cannot extract memory as C2Block is not created/mapped");
2915 return;
2916 }
2917 if (context->mReadWriteMapping->error() != C2_OK) {
2918 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)",
2919 context->mReadWriteMapping->error());
2920 return;
2921 }
2922 // We are proceeding to extract memory from C2Block
2923 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2924 memcpy(memoryPtr + offset, context->mReadWriteMapping->base() + offset, size);
Wonsik Kim8569a662022-05-24 14:16:44 -07002925}
2926
2927static void extractBufferFromContext(
2928 JMediaCodecLinearBlock *context,
2929 jint offset,
2930 jint size,
2931 std::shared_ptr<C2Buffer> *buffer) {
Arun Johnson2aef16f2024-02-24 00:01:33 +00002932 if ((offset + size) > context->capacity()) {
2933 ALOGW("extractBufferFromContext: offset + size provided exceed capacity");
2934 return;
2935 }
Wonsik Kim8569a662022-05-24 14:16:44 -07002936 *buffer = context->toC2Buffer(offset, size);
2937 if (*buffer == nullptr) {
2938 if (!context->mMemory) {
2939 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2940 return;
2941 }
2942 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2943 context->capacity());
2944 if (obtain(context, context->capacity(),
2945 context->mCodecNames, false /* secure */)) {
2946 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2947 return;
2948 }
2949 C2WriteView view = context->mBlock->map().get();
2950 if (view.error() != C2_OK) {
2951 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2952 return;
2953 }
2954 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2955 memcpy(view.base() + offset, memoryPtr + offset, size);
2956 context->mMemory.clear();
2957 context->mHidlMemory.clear();
2958 context->mHidlMemorySize = 0;
2959 context->mHidlMemoryOffset = 0;
2960 *buffer = context->toC2Buffer(offset, size);
2961 }
2962}
2963
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002964static void android_media_MediaCodec_native_queueLinearBlock(
2965 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
Arun Johnson677a8812024-02-06 12:32:54 +00002966 jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002967 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2968
2969 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2970
Wonsik Kim24e53802020-05-08 20:04:26 -07002971 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002972 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002973 return;
2974 }
2975
2976 sp<AMessage> tunings;
2977 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2978 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002979 throwExceptionAsNecessary(
2980 env, err, ACTION_CODE_FATAL,
2981 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002982 return;
2983 }
Arun Johnson4ca49092024-02-01 19:07:15 +00002984 jint totalSize = 0;
2985 jint initialOffset = 0;
Arun Johnson8d6a41a2024-01-10 21:14:14 +00002986 std::vector<AccessUnitInfo> infoVec;
2987 AString errorDetailMsg;
2988 err = extractInfosFromObject(env,
2989 &initialOffset,
2990 &totalSize,
2991 &infoVec,
2992 objArray,
2993 &errorDetailMsg);
2994 if (err != OK) {
2995 throwExceptionAsNecessary(
2996 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2997 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
2998 return;
2999 }
3000 sp<BufferInfosWrapper> infos =
3001 new BufferInfosWrapper{std::move(infoVec)};
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003002 std::shared_ptr<C2Buffer> buffer;
3003 sp<hardware::HidlMemory> memory;
3004 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
3005 if (env->MonitorEnter(lock.get()) == JNI_OK) {
3006 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
3007 JMediaCodecLinearBlock *context =
3008 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003009 if (codec->hasCryptoOrDescrambler()) {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003010 extractMemoryFromContext(context, initialOffset, totalSize, &memory);
3011 initialOffset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003012 } else {
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003013 extractBufferFromContext(context, initialOffset, totalSize, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003014 }
3015 }
3016 env->MonitorExit(lock.get());
3017 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003018 throwExceptionAsNecessary(
3019 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3020 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003021 return;
3022 }
3023
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003024 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003025 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003026 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003027 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003028 throwExceptionAsNecessary(
3029 env, BAD_VALUE, ACTION_CODE_FATAL,
3030 "Unexpected error: the input buffer is not compatible with "
3031 "the secure codec, and a fallback logic failed.\n"
3032 "Suggestion: please try including the secure codec when calling "
3033 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003034 return;
3035 }
Arun Johnsona7a04b52024-03-04 06:38:43 +00003036 sp<CryptoInfosWrapper> cryptoInfos = nullptr;
3037 jint sampleSize = totalSize;
Arun Johnson677a8812024-02-06 12:32:54 +00003038 if (cryptoInfoArray != nullptr) {
Arun Johnsona7a04b52024-03-04 06:38:43 +00003039 cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
Arun Johnson677a8812024-02-06 12:32:54 +00003040 extractCryptoInfosFromObjectArray(env,
3041 &sampleSize,
3042 &cryptoInfos->value,
3043 cryptoInfoArray,
3044 &errorDetailMsg);
Arun Johnson677a8812024-02-06 12:32:54 +00003045 }
George Burgess IV436998b2022-11-02 11:42:33 -06003046 if (env->ExceptionCheck()) {
3047 // Creation of cryptoInfo failed. Let the exception bubble up.
3048 return;
3049 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003050 err = codec->queueEncryptedLinearBlock(
3051 index,
3052 memory,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003053 initialOffset,
Arun Johnson677a8812024-02-06 12:32:54 +00003054 sampleSize,
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003055 infos,
Arun Johnson677a8812024-02-06 12:32:54 +00003056 cryptoInfos,
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003057 tunings,
3058 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07003059 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003060 } else {
3061 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003062 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003063 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003064 throwExceptionAsNecessary(
3065 env, BAD_VALUE, ACTION_CODE_FATAL,
3066 "Unexpected error: the input buffer is not compatible with "
3067 "the non-secure codec, and a fallback logic failed.\n"
3068 "Suggestion: please do not include the secure codec when calling "
3069 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003070 return;
3071 }
3072 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003073 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003074 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003075 throwExceptionAsNecessary(
3076 env, err, ACTION_CODE_FATAL,
3077 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003078}
3079
Wonsik Kim637afb22020-02-25 14:27:29 -08003080static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003081 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
3082 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08003083 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003084
3085 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3086
Wonsik Kim24e53802020-05-08 20:04:26 -07003087 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003088 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003089 return;
3090 }
3091
3092 sp<AMessage> tunings;
3093 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
3094 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003095 throwExceptionAsNecessary(
3096 env, err, ACTION_CODE_FATAL,
3097 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003098 return;
3099 }
3100
Wonsik Kim637afb22020-02-25 14:27:29 -08003101 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
3102 env, bufferObj);
3103 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
3104 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003105 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
3106 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
3107 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
3108 std::shared_ptr<C2Allocator> alloc;
3109 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
3110 C2PlatformAllocatorStore::GRALLOC, &alloc);
3111 if (err == C2_OK) {
3112 return alloc;
3113 }
3114 return nullptr;
3115 }();
3116 std::shared_ptr<C2GraphicAllocation> alloc;
3117 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
3118 if (c2err != C2_OK) {
3119 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09003120 native_handle_close(handle);
3121 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003122 throwExceptionAsNecessary(
3123 env, BAD_VALUE, ACTION_CODE_FATAL,
3124 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003125 return;
3126 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003127 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08003128 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
3129 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003130 AString errorDetailMsg;
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003131 sp<BufferInfosWrapper> infos =
3132 new BufferInfosWrapper{decltype(infos->value)()};
3133 infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07003134 err = codec->queueBuffer(
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003135 index, buffer, infos, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003136 throwExceptionAsNecessary(
3137 env, err, ACTION_CODE_FATAL,
3138 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003139}
3140
3141static void android_media_MediaCodec_native_getOutputFrame(
3142 JNIEnv *env, jobject thiz, jobject frame, jint index) {
3143 ALOGV("android_media_MediaCodec_native_getOutputFrame");
3144
3145 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3146
Wonsik Kim24e53802020-05-08 20:04:26 -07003147 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003148 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003149 return;
3150 }
3151
3152 status_t err = codec->getOutputFrame(env, frame, index);
3153 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003154 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003155 }
3156}
3157
Andreas Huber88572f72012-02-21 11:47:18 -08003158static jint android_media_MediaCodec_dequeueInputBuffer(
3159 JNIEnv *env, jobject thiz, jlong timeoutUs) {
3160 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
3161
3162 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3163
Wonsik Kim24e53802020-05-08 20:04:26 -07003164 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003165 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003166 return -1;
3167 }
3168
3169 size_t index;
3170 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
3171
3172 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00003173 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08003174 }
3175
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003176 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003177}
3178
3179static jint android_media_MediaCodec_dequeueOutputBuffer(
3180 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
3181 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
3182
3183 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3184
Wonsik Kim24e53802020-05-08 20:04:26 -07003185 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003186 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07003187 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08003188 }
3189
3190 size_t index;
3191 status_t err = codec->dequeueOutputBuffer(
3192 env, bufferInfo, &index, timeoutUs);
3193
3194 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00003195 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08003196 }
3197
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003198 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003199}
3200
3201static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003202 JNIEnv *env, jobject thiz,
3203 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08003204 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
3205
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);
Andreas Huber88572f72012-02-21 11:47:18 -08003210 return;
3211 }
3212
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003213 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08003214
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003215 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003216}
3217
Andy McFadden2621e402013-02-19 07:29:21 -08003218static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
3219 jobject thiz) {
3220 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
3221
3222 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003223 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003224 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003225 return;
3226 }
3227
3228 status_t err = codec->signalEndOfInputStream();
3229
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003230 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08003231}
3232
Lajos Molnard4023112014-07-11 15:12:59 -07003233static jobject android_media_MediaCodec_getFormatNative(
3234 JNIEnv *env, jobject thiz, jboolean input) {
3235 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08003236
3237 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3238
Wonsik Kim24e53802020-05-08 20:04:26 -07003239 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003240 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003241 return NULL;
3242 }
3243
3244 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07003245 status_t err = codec->getFormat(env, input, &format);
3246
3247 if (err == OK) {
3248 return format;
3249 }
3250
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003251 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003252
3253 return NULL;
3254}
3255
3256static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
3257 JNIEnv *env, jobject thiz, jint index) {
3258 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
3259
3260 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3261
Wonsik Kim24e53802020-05-08 20:04:26 -07003262 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003263 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003264 return NULL;
3265 }
3266
3267 jobject format;
3268 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08003269
3270 if (err == OK) {
3271 return format;
3272 }
3273
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003274 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003275
3276 return NULL;
3277}
3278
3279static jobjectArray android_media_MediaCodec_getBuffers(
3280 JNIEnv *env, jobject thiz, jboolean input) {
3281 ALOGV("android_media_MediaCodec_getBuffers");
3282
3283 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3284
Wonsik Kim24e53802020-05-08 20:04:26 -07003285 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003286 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003287 return NULL;
3288 }
3289
3290 jobjectArray buffers;
3291 status_t err = codec->getBuffers(env, input, &buffers);
3292
3293 if (err == OK) {
3294 return buffers;
3295 }
3296
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003297 // if we're out of memory, an exception was already thrown
3298 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003299 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08003300 }
Andreas Huber88572f72012-02-21 11:47:18 -08003301
3302 return NULL;
3303}
3304
Lajos Molnard4023112014-07-11 15:12:59 -07003305static jobject android_media_MediaCodec_getBuffer(
3306 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3307 ALOGV("android_media_MediaCodec_getBuffer");
3308
3309 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3310
Wonsik Kim24e53802020-05-08 20:04:26 -07003311 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003312 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003313 return NULL;
3314 }
3315
3316 jobject buffer;
3317 status_t err = codec->getBuffer(env, input, index, &buffer);
3318
3319 if (err == OK) {
3320 return buffer;
3321 }
3322
3323 // if we're out of memory, an exception was already thrown
3324 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003325 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003326 }
3327
3328 return NULL;
3329}
3330
3331static jobject android_media_MediaCodec_getImage(
3332 JNIEnv *env, jobject thiz, jboolean input, jint index) {
3333 ALOGV("android_media_MediaCodec_getImage");
3334
3335 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3336
Wonsik Kim24e53802020-05-08 20:04:26 -07003337 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003338 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003339 return NULL;
3340 }
3341
3342 jobject image;
3343 status_t err = codec->getImage(env, input, index, &image);
3344
3345 if (err == OK) {
3346 return image;
3347 }
3348
3349 // if we're out of memory, an exception was already thrown
3350 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003351 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07003352 }
3353
3354 return NULL;
3355}
3356
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003357static jobject android_media_MediaCodec_getName(
3358 JNIEnv *env, jobject thiz) {
3359 ALOGV("android_media_MediaCodec_getName");
3360
3361 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3362
Wonsik Kim24e53802020-05-08 20:04:26 -07003363 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003364 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003365 return NULL;
3366 }
3367
3368 jstring name;
3369 status_t err = codec->getName(env, &name);
3370
3371 if (err == OK) {
3372 return name;
3373 }
3374
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003375 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003376
3377 return NULL;
3378}
3379
Chong Zhanga0b72a62018-02-28 18:46:26 -08003380static jobject android_media_MediaCodec_getOwnCodecInfo(
3381 JNIEnv *env, jobject thiz) {
3382 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
3383
3384 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3385
Wonsik Kim24e53802020-05-08 20:04:26 -07003386 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003387 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003388 return NULL;
3389 }
3390
3391 jobject codecInfoObj;
3392 status_t err = codec->getCodecInfo(env, &codecInfoObj);
3393
3394 if (err == OK) {
3395 return codecInfoObj;
3396 }
3397
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003398 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08003399
3400 return NULL;
3401}
3402
Ray Essick0e0fee12017-01-25 18:01:56 -08003403static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08003404android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08003405{
Ray Essickf2d0e402017-03-09 10:17:51 -08003406 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08003407
3408 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07003409 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003410 jniThrowException(env, "java/lang/IllegalStateException",
3411 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08003412 return 0;
3413 }
3414
3415 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08003416 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08003417
3418 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08003419 if (err != OK) {
3420 ALOGE("getMetrics failed");
3421 return (jobject) NULL;
3422 }
3423
Ray Essick0e0fee12017-01-25 18:01:56 -08003424 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
3425
3426 // housekeeping
3427 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07003428 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08003429
3430 return mybundle;
3431}
3432
Andreas Huber226065b2013-08-12 10:14:11 -07003433static void android_media_MediaCodec_setParameters(
3434 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3435 ALOGV("android_media_MediaCodec_setParameters");
3436
3437 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3438
Wonsik Kim24e53802020-05-08 20:04:26 -07003439 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003440 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003441 return;
3442 }
3443
3444 sp<AMessage> params;
3445 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3446
3447 if (err == OK) {
3448 err = codec->setParameters(params);
3449 }
3450
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003451 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003452}
3453
Andreas Huberb12a5392012-04-30 14:18:33 -07003454static void android_media_MediaCodec_setVideoScalingMode(
3455 JNIEnv *env, jobject thiz, jint mode) {
3456 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3457
Wonsik Kim24e53802020-05-08 20:04:26 -07003458 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003459 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huberb12a5392012-04-30 14:18:33 -07003460 return;
3461 }
3462
3463 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3464 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003465 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003466 String8::format("Unrecognized mode: %d", mode).c_str());
Andreas Huberb12a5392012-04-30 14:18:33 -07003467 return;
3468 }
3469
3470 codec->setVideoScalingMode(mode);
3471}
3472
ybai5e053202018-11-01 13:02:15 +08003473static void android_media_MediaCodec_setAudioPresentation(
3474 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3475 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3476
Wonsik Kim24e53802020-05-08 20:04:26 -07003477 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003478 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08003479 return;
3480 }
3481
3482 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3483}
3484
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003485static jobject android_media_MediaCodec_getSupportedVendorParameters(
3486 JNIEnv *env, jobject thiz) {
3487 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3488
3489 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003490 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003491 return NULL;
3492 }
3493
3494 jobject ret = NULL;
3495 status_t status = codec->querySupportedVendorParameters(env, &ret);
3496 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003497 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003498 }
3499
3500 return ret;
3501}
3502
3503static jobject android_media_MediaCodec_getParameterDescriptor(
3504 JNIEnv *env, jobject thiz, jstring name) {
3505 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3506
3507 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003508 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003509 return NULL;
3510 }
3511
3512 jobject ret = NULL;
3513 status_t status = codec->describeParameter(env, name, &ret);
3514 if (status != OK) {
3515 ret = NULL;
3516 }
3517 return ret;
3518}
3519
3520static void android_media_MediaCodec_subscribeToVendorParameters(
3521 JNIEnv *env, jobject thiz, jobject names) {
3522 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3523
3524 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003525 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003526 return;
3527 }
3528
3529 status_t status = codec->subscribeToVendorParameters(env, names);
3530 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003531 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003532 }
3533 return;
3534}
3535
3536static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3537 JNIEnv *env, jobject thiz, jobject names) {
3538 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3539
3540 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003541 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003542 return;
3543 }
3544
3545 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3546 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003547 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003548 }
3549 return;
3550}
3551
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003552static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003553 ScopedLocalRef<jclass> clazz(
3554 env, env->FindClass("android/media/MediaCodec"));
3555 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003556
Andreas Huberaba67132013-10-22 12:40:01 -07003557 gFields.postEventFromNativeID =
3558 env->GetMethodID(
3559 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003560 CHECK(gFields.postEventFromNativeID != NULL);
3561
Wonsik Kim61796fd2018-09-13 13:15:59 -07003562 gFields.lockAndGetContextID =
3563 env->GetMethodID(
3564 clazz.get(), "lockAndGetContext", "()J");
3565 CHECK(gFields.lockAndGetContextID != NULL);
3566
3567 gFields.setAndUnlockContextID =
3568 env->GetMethodID(
3569 clazz.get(), "setAndUnlockContext", "(J)V");
3570 CHECK(gFields.setAndUnlockContextID != NULL);
3571
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003572 jfieldID field;
3573 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3574 CHECK(field != NULL);
3575 gCryptoModes.Unencrypted =
3576 env->GetStaticIntField(clazz.get(), field);
3577
3578 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3579 CHECK(field != NULL);
3580 gCryptoModes.AesCtr =
3581 env->GetStaticIntField(clazz.get(), field);
3582
3583 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3584 CHECK(field != NULL);
3585 gCryptoModes.AesCbc =
3586 env->GetStaticIntField(clazz.get(), field);
3587
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003588 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3589 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003590
Arun Johnson5a4c7332022-12-17 00:47:06 +00003591 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3592 CHECK(gFields.cryptoInfoSetID != NULL);
3593
3594 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3595 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3596
Andreas Huber91befdc2012-04-18 12:19:51 -07003597 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003598 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003599 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3600
3601 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003602 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003603 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3604
3605 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003606 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003607 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3608
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003609 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003610 CHECK(gFields.cryptoInfoKeyID != NULL);
3611
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003612 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003613 CHECK(gFields.cryptoInfoIVID != NULL);
3614
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003615 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003616 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003617
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003618 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003619 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3620 CHECK(gFields.cryptoInfoPatternID != NULL);
3621
3622 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3623 CHECK(clazz.get() != NULL);
3624
3625 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3626 CHECK(gFields.patternEncryptBlocksID != NULL);
3627
3628 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3629 CHECK(gFields.patternSkipBlocksID != NULL);
3630
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003631 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3632 CHECK(clazz.get() != NULL);
3633
3634 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3635 CHECK(gFields.queueRequestIndexID != NULL);
3636
3637 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3638 CHECK(clazz.get() != NULL);
3639
3640 gFields.outputFrameLinearBlockID =
3641 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3642 CHECK(gFields.outputFrameLinearBlockID != NULL);
3643
Arun Johnson8d6a41a2024-01-10 21:14:14 +00003644 gFields.outputFramebufferInfosID =
3645 env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
3646 CHECK(gFields.outputFramebufferInfosID != NULL);
3647
Wonsik Kim637afb22020-02-25 14:27:29 -08003648 gFields.outputFrameHardwareBufferID =
3649 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3650 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003651
3652 gFields.outputFrameChangedKeysID =
3653 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3654 CHECK(gFields.outputFrameChangedKeysID != NULL);
3655
3656 gFields.outputFrameFormatID =
3657 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3658 CHECK(gFields.outputFrameFormatID != NULL);
3659
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003660 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3661 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003662
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003663 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003664 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003665 gCryptoErrorCodes.cryptoErrorNoKey =
3666 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003667
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003668 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003669 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003670 gCryptoErrorCodes.cryptoErrorKeyExpired =
3671 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003672
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003673 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003674 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003675 gCryptoErrorCodes.cryptoErrorResourceBusy =
3676 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003677
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003678 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3679 CHECK(field != NULL);
3680 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3681 env->GetStaticIntField(clazz.get(), field);
3682
Jeff Tinker96a2a952015-07-01 17:35:18 -07003683 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3684 CHECK(field != NULL);
3685 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3686 env->GetStaticIntField(clazz.get(), field);
3687
Jeff Tinker20594d82018-12-12 08:31:22 -08003688 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3689 CHECK(field != NULL);
3690 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3691 env->GetStaticIntField(clazz.get(), field);
3692
Jeff Tinkerd3932162016-03-05 11:35:20 -08003693 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3694 CHECK(field != NULL);
3695 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3696 env->GetStaticIntField(clazz.get(), field);
3697
Jeff Tinker20594d82018-12-12 08:31:22 -08003698 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3699 CHECK(field != NULL);
3700 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3701 env->GetStaticIntField(clazz.get(), field);
3702
3703 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3704 CHECK(field != NULL);
3705 gCryptoErrorCodes.cryptoErrorLostState =
3706 env->GetStaticIntField(clazz.get(), field);
3707
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003708 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3709 CHECK(clazz.get() != NULL);
3710 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3711 CHECK(field != NULL);
3712 gCodecActionCodes.codecActionTransient =
3713 env->GetStaticIntField(clazz.get(), field);
3714
3715 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3716 CHECK(field != NULL);
3717 gCodecActionCodes.codecActionRecoverable =
3718 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003719
Ronghua Wuc53ad692015-05-08 14:40:49 -07003720 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003721 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003722 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003723 env->GetStaticIntField(clazz.get(), field);
3724
Ronghua Wuc53ad692015-05-08 14:40:49 -07003725 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003726 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003727 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003728 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003729
3730 clazz.reset(env->FindClass("android/view/Surface"));
3731 CHECK(clazz.get() != NULL);
3732
3733 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3734 CHECK(field != NULL);
3735 gPersistentSurfaceClassInfo.mLock = field;
3736
3737 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3738 CHECK(method != NULL);
3739 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3740
3741 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3742 CHECK(clazz.get() != NULL);
3743 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3744
3745 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3746 CHECK(method != NULL);
3747 gPersistentSurfaceClassInfo.ctor = method;
3748
3749 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3750 CHECK(field != NULL);
3751 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003752
3753 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3754 CHECK(clazz.get() != NULL);
3755 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3756
3757 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003758 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003759 "Ljava/util/Map;Ljava/util/Map;)V");
3760 CHECK(method != NULL);
3761 gCodecInfo.capsCtorId = method;
3762
3763 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3764 CHECK(clazz.get() != NULL);
3765 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3766
3767 field = env->GetFieldID(clazz.get(), "profile", "I");
3768 CHECK(field != NULL);
3769 gCodecInfo.profileField = field;
3770
3771 field = env->GetFieldID(clazz.get(), "level", "I");
3772 CHECK(field != NULL);
3773 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003774
3775 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3776 CHECK(clazz.get() != NULL);
3777 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3778
3779 ScopedLocalRef<jclass> byteOrderClass(
3780 env, env->FindClass("java/nio/ByteOrder"));
3781 CHECK(byteOrderClass.get() != NULL);
3782
3783 jmethodID nativeOrderID = env->GetStaticMethodID(
3784 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3785 CHECK(nativeOrderID != NULL);
3786
3787 ScopedLocalRef<jobject> nativeByteOrderObj{
3788 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3789 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3790 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3791 nativeByteOrderObj.reset();
3792
3793 gByteBufferInfo.orderId = env->GetMethodID(
3794 clazz.get(),
3795 "order",
3796 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3797 CHECK(gByteBufferInfo.orderId != NULL);
3798
3799 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3800 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3801 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3802
3803 gByteBufferInfo.positionId = env->GetMethodID(
3804 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3805 CHECK(gByteBufferInfo.positionId != NULL);
3806
3807 gByteBufferInfo.limitId = env->GetMethodID(
3808 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3809 CHECK(gByteBufferInfo.limitId != NULL);
3810
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003811 gByteBufferInfo.getPositionId = env->GetMethodID(
3812 clazz.get(), "position", "()I");
3813 CHECK(gByteBufferInfo.getPositionId != NULL);
3814
3815 gByteBufferInfo.getLimitId = env->GetMethodID(
3816 clazz.get(), "limit", "()I");
3817 CHECK(gByteBufferInfo.getLimitId != NULL);
3818
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003819 clazz.reset(env->FindClass("java/util/ArrayList"));
3820 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003821 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3822
3823 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3824 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003825
3826 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3827 CHECK(gArrayListInfo.sizeId != NULL);
3828
3829 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3830 CHECK(gArrayListInfo.getId != NULL);
3831
3832 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3833 CHECK(gArrayListInfo.addId != NULL);
3834
Arun Johnson206270e2023-10-31 20:40:12 +00003835 clazz.reset(env->FindClass("java/util/ArrayDeque"));
3836 CHECK(clazz.get() != NULL);
3837 gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3838
3839 gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3840 CHECK(gArrayDequeInfo.ctorId != NULL);
3841
3842 gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3843 CHECK(gArrayDequeInfo.sizeId != NULL);
3844
3845 gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3846 CHECK(gArrayDequeInfo.addId != NULL);
3847
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003848 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3849 CHECK(clazz.get() != NULL);
3850
3851 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3852
3853 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3854 CHECK(gLinearBlockInfo.ctorId != NULL);
3855
3856 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3857 clazz.get(), "setInternalStateLocked", "(JZ)V");
3858 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3859
3860 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3861 CHECK(gLinearBlockInfo.contextId != NULL);
3862
3863 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3864 CHECK(gLinearBlockInfo.validId != NULL);
3865
3866 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3867 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003868
3869 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3870 CHECK(clazz.get() != NULL);
3871 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3872
3873 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3874 CHECK(gDescriptorInfo.ctorId != NULL);
3875
3876 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3877 CHECK(gDescriptorInfo.nameId != NULL);
3878
3879 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3880 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003881
3882 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3883 CHECK(clazz.get() != NULL);
3884 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3885
3886 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3887 CHECK(gBufferInfo.ctorId != NULL);
3888
3889 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3890 CHECK(gBufferInfo.setId != NULL);
Arun Johnson206270e2023-10-31 20:40:12 +00003891
3892 gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
3893 gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
3894 gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
3895 gFields.bufferInfoPresentationTimeUs =
3896 env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08003897}
3898
3899static void android_media_MediaCodec_native_setup(
3900 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003901 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003902 if (name == NULL) {
Ray Essickbd5fdaa2023-08-10 21:04:18 -05003903 jniThrowException(env, "java/lang/NullPointerException",
3904 "No codec name specified");
Andreas Huber88572f72012-02-21 11:47:18 -08003905 return;
3906 }
3907
3908 const char *tmp = env->GetStringUTFChars(name, NULL);
3909
3910 if (tmp == NULL) {
3911 return;
3912 }
3913
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003914 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003915
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003916 const status_t err = codec->initCheck();
3917 if (err == NAME_NOT_FOUND) {
3918 // fail and do not try again.
3919 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003920 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003921 env->ReleaseStringUTFChars(name, tmp);
3922 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003923 }
3924 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003925 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003926 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
Ronghua Wuc53ad692015-05-08 14:40:49 -07003927 env->ReleaseStringUTFChars(name, tmp);
3928 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003929 }
3930 if (err == PERMISSION_DENIED) {
3931 jniThrowException(env, "java/lang/SecurityException",
3932 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003933 err).c_str());
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003934 env->ReleaseStringUTFChars(name, tmp);
3935 return;
3936 }
3937 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003938 // believed possible to try again
3939 jniThrowException(env, "java/io/IOException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003940 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003941 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003942 return;
3943 }
3944
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003945 env->ReleaseStringUTFChars(name, tmp);
3946
Andreas Huberaba67132013-10-22 12:40:01 -07003947 codec->registerSelf();
3948
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003949 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003950}
3951
3952static void android_media_MediaCodec_native_finalize(
3953 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003954 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003955}
3956
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003957// MediaCodec.LinearBlock
3958
3959static jobject android_media_MediaCodec_LinearBlock_native_map(
3960 JNIEnv *env, jobject thiz) {
3961 JMediaCodecLinearBlock *context =
3962 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3963 if (context->mBuffer) {
3964 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3965 if (!context->mReadonlyMapping) {
3966 const C2BufferData data = buffer->data();
3967 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003968 throwExceptionAsNecessary(
3969 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3970 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003971 return nullptr;
3972 }
3973 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003974 throwExceptionAsNecessary(
3975 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3976 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003977 return nullptr;
3978 }
3979 C2ConstLinearBlock block = data.linearBlocks().front();
3980 context->mReadonlyMapping =
3981 std::make_shared<C2ReadView>(block.map().get());
3982 }
3983 return CreateByteBuffer(
3984 env,
3985 context->mReadonlyMapping->data(), // base
3986 context->mReadonlyMapping->capacity(), // capacity
3987 0u, // offset
3988 context->mReadonlyMapping->capacity(), // size
3989 true, // readOnly
3990 true /* clearBuffer */);
3991 } else if (context->mBlock) {
3992 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3993 if (!context->mReadWriteMapping) {
3994 context->mReadWriteMapping =
3995 std::make_shared<C2WriteView>(block->map().get());
3996 }
3997 return CreateByteBuffer(
3998 env,
3999 context->mReadWriteMapping->base(),
4000 context->mReadWriteMapping->capacity(),
4001 context->mReadWriteMapping->offset(),
4002 context->mReadWriteMapping->size(),
4003 false, // readOnly
4004 true /* clearBuffer */);
4005 } else if (context->mLegacyBuffer) {
4006 return CreateByteBuffer(
4007 env,
4008 context->mLegacyBuffer->base(),
4009 context->mLegacyBuffer->capacity(),
4010 context->mLegacyBuffer->offset(),
4011 context->mLegacyBuffer->size(),
4012 true, // readOnly
4013 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07004014 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004015 return CreateByteBuffer(
4016 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07004017 context->mMemory->unsecurePointer(),
4018 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004019 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07004020 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004021 false, // readOnly
4022 true /* clearBuffer */);
4023 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08004024 throwExceptionAsNecessary(
4025 env, INVALID_OPERATION, ACTION_CODE_FATAL,
4026 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004027 return nullptr;
4028}
4029
4030static void android_media_MediaCodec_LinearBlock_native_recycle(
4031 JNIEnv *env, jobject thiz) {
4032 JMediaCodecLinearBlock *context =
4033 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07004034 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004035 delete context;
4036}
4037
4038static void PopulateNamesVector(
4039 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
4040 jsize length = env->GetArrayLength(codecNames);
4041 for (jsize i = 0; i < length; ++i) {
4042 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
4043 if (jstr == nullptr) {
4044 // null entries are ignored
4045 continue;
4046 }
4047 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
4048 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08004049 throwExceptionAsNecessary(
4050 env, BAD_VALUE, ACTION_CODE_FATAL,
4051 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004052 return;
4053 }
4054 names->emplace_back(cstr);
4055 env->ReleaseStringUTFChars(jstr, cstr);
4056 }
4057}
4058
4059static void android_media_MediaCodec_LinearBlock_native_obtain(
4060 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
4061 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
4062 std::vector<std::string> names;
4063 PopulateNamesVector(env, codecNames, &names);
4064 bool hasSecure = false;
4065 bool hasNonSecure = false;
4066 for (const std::string &name : names) {
4067 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4068 hasSecure = true;
4069 } else {
4070 hasNonSecure = true;
4071 }
4072 }
Wonsik Kim8569a662022-05-24 14:16:44 -07004073 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
4074 jniThrowException(env, "java/io/IOException", nullptr);
4075 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004076 }
4077 env->CallVoidMethod(
4078 thiz,
4079 gLinearBlockInfo.setInternalStateId,
4080 (jlong)context.release(),
4081 true /* isMappable */);
4082}
4083
4084static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07004085 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004086 std::vector<std::string> names;
4087 PopulateNamesVector(env, codecNames, &names);
4088 bool isCompatible = false;
4089 bool hasSecure = false;
4090 bool hasNonSecure = false;
4091 for (const std::string &name : names) {
4092 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
4093 hasSecure = true;
4094 } else {
4095 hasNonSecure = true;
4096 }
4097 }
4098 if (hasSecure && hasNonSecure) {
4099 return false;
4100 }
4101 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
4102 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08004103 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004104 throwExceptionAsNecessary(env, err);
4105 }
4106 return isCompatible;
4107}
4108
Daniel Micay76f6a862015-09-19 17:31:01 -04004109static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07004110 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08004111
Lajos Molnar1e6e8012014-07-15 16:07:13 -07004112 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
4113
Chong Zhang8034d602015-04-28 13:38:48 -07004114 { "native_releasePersistentInputSurface",
4115 "(Landroid/view/Surface;)V",
4116 (void *)android_media_MediaCodec_releasePersistentInputSurface},
4117
4118 { "native_createPersistentInputSurface",
4119 "()Landroid/media/MediaCodec$PersistentSurface;",
4120 (void *)android_media_MediaCodec_createPersistentInputSurface },
4121
Chong Zhang9560ddb2015-05-13 10:25:29 -07004122 { "native_setInputSurface", "(Landroid/view/Surface;)V",
4123 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07004124
Guillaume Chelfic072caf2021-02-03 16:18:26 +01004125 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
4126 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
4127
Lajos Molnard8578572015-06-05 20:17:33 -07004128 { "native_enableOnFrameRenderedListener", "(Z)V",
4129 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
4130
Chong Zhang8d5e5562014-07-08 18:49:21 -07004131 { "native_setCallback",
4132 "(Landroid/media/MediaCodec$Callback;)V",
4133 (void *)android_media_MediaCodec_native_setCallback },
4134
Andreas Huber88572f72012-02-21 11:47:18 -08004135 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07004136 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07004137 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004138 (void *)android_media_MediaCodec_native_configure },
4139
Lajos Molnar5e02ba92015-05-01 15:59:35 -07004140 { "native_setSurface",
4141 "(Landroid/view/Surface;)V",
4142 (void *)android_media_MediaCodec_native_setSurface },
4143
Lajos Molnar3a7c83a2024-03-29 08:15:59 -07004144 { "native_detachOutputSurface",
4145 "()V",
4146 (void *)android_media_MediaCodec_native_detachOutputSurface },
4147
Andy McFadden2621e402013-02-19 07:29:21 -08004148 { "createInputSurface", "()Landroid/view/Surface;",
4149 (void *)android_media_MediaCodec_createInputSurface },
4150
Lajos Molnard4023112014-07-11 15:12:59 -07004151 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07004152 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07004153 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08004154
Lajos Molnard4023112014-07-11 15:12:59 -07004155 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004156 (void *)android_media_MediaCodec_queueInputBuffer },
4157
Arun Johnson206270e2023-10-31 20:40:12 +00004158 { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
4159 (void *)android_media_MediaCodec_queueInputBuffers },
4160
Lajos Molnard4023112014-07-11 15:12:59 -07004161 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07004162 (void *)android_media_MediaCodec_queueSecureInputBuffer },
4163
Arun Johnson4ca49092024-02-01 19:07:15 +00004164 { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
4165 (void *)android_media_MediaCodec_queueSecureInputBuffers },
4166
Wonsik Kim637afb22020-02-25 14:27:29 -08004167 { "native_mapHardwareBuffer",
4168 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
4169 (void *)android_media_MediaCodec_mapHardwareBuffer },
4170
4171 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
4172
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004173 { "native_queueLinearBlock",
Arun Johnson677a8812024-02-06 12:32:54 +00004174 "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
Arun Johnson8d6a41a2024-01-10 21:14:14 +00004175 "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004176 (void *)android_media_MediaCodec_native_queueLinearBlock },
4177
Wonsik Kim637afb22020-02-25 14:27:29 -08004178 { "native_queueHardwareBuffer",
4179 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
4180 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004181
4182 { "native_getOutputFrame",
4183 "(Landroid/media/MediaCodec$OutputFrame;I)V",
4184 (void *)android_media_MediaCodec_native_getOutputFrame },
4185
Lajos Molnard4023112014-07-11 15:12:59 -07004186 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08004187 (void *)android_media_MediaCodec_dequeueInputBuffer },
4188
Lajos Molnard4023112014-07-11 15:12:59 -07004189 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08004190 (void *)android_media_MediaCodec_dequeueOutputBuffer },
4191
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07004192 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004193 (void *)android_media_MediaCodec_releaseOutputBuffer },
4194
Andy McFadden2621e402013-02-19 07:29:21 -08004195 { "signalEndOfInputStream", "()V",
4196 (void *)android_media_MediaCodec_signalEndOfInputStream },
4197
Lajos Molnard4023112014-07-11 15:12:59 -07004198 { "getFormatNative", "(Z)Ljava/util/Map;",
4199 (void *)android_media_MediaCodec_getFormatNative },
4200
4201 { "getOutputFormatNative", "(I)Ljava/util/Map;",
4202 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08004203
4204 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
4205 (void *)android_media_MediaCodec_getBuffers },
4206
Lajos Molnard4023112014-07-11 15:12:59 -07004207 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
4208 (void *)android_media_MediaCodec_getBuffer },
4209
4210 { "getImage", "(ZI)Landroid/media/Image;",
4211 (void *)android_media_MediaCodec_getImage },
4212
Lajos Molnard2a7f472018-11-15 12:49:20 -08004213 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03004214 (void *)android_media_MediaCodec_getName },
4215
Chong Zhanga0b72a62018-02-28 18:46:26 -08004216 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
4217 (void *)android_media_MediaCodec_getOwnCodecInfo },
4218
Ray Essick10353e32017-04-14 10:22:55 -07004219 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08004220 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08004221
Andreas Huber226065b2013-08-12 10:14:11 -07004222 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
4223 (void *)android_media_MediaCodec_setParameters },
4224
Andreas Huberb12a5392012-04-30 14:18:33 -07004225 { "setVideoScalingMode", "(I)V",
4226 (void *)android_media_MediaCodec_setVideoScalingMode },
4227
ybai5e053202018-11-01 13:02:15 +08004228 { "native_setAudioPresentation", "(II)V",
4229 (void *)android_media_MediaCodec_setAudioPresentation },
4230
Wonsik Kim8798c8c2021-03-18 21:38:57 -07004231 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
4232 (void *)android_media_MediaCodec_getSupportedVendorParameters },
4233
4234 { "native_getParameterDescriptor",
4235 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
4236 (void *)android_media_MediaCodec_getParameterDescriptor },
4237
4238 { "native_subscribeToVendorParameters",
4239 "(Ljava/util/List;)V",
4240 (void *)android_media_MediaCodec_subscribeToVendorParameters},
4241
4242 { "native_unsubscribeFromVendorParameters",
4243 "(Ljava/util/List;)V",
4244 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
4245
Andreas Huber88572f72012-02-21 11:47:18 -08004246 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
4247
Brian Lindahl6ceeed42022-02-01 11:10:30 +01004248 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08004249 (void *)android_media_MediaCodec_native_setup },
4250
4251 { "native_finalize", "()V",
4252 (void *)android_media_MediaCodec_native_finalize },
4253};
4254
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004255static const JNINativeMethod gLinearBlockMethods[] = {
4256 { "native_map", "()Ljava/nio/ByteBuffer;",
4257 (void *)android_media_MediaCodec_LinearBlock_native_map },
4258
4259 { "native_recycle", "()V",
4260 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
4261
4262 { "native_obtain", "(I[Ljava/lang/String;)V",
4263 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
4264
4265 { "native_checkCompatible", "([Ljava/lang/String;)Z",
4266 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
4267};
4268
Andreas Huber88572f72012-02-21 11:47:18 -08004269int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004270 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08004271 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004272 if (result != JNI_OK) {
4273 return result;
4274 }
4275 result = AndroidRuntime::registerNativeMethods(env,
4276 "android/media/MediaCodec$LinearBlock",
4277 gLinearBlockMethods,
4278 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08004279 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08004280}