blob: ef90bf993437bbb7bd8d8ff1d9939093ef88a7ea [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;
166 jmethodID setInternalStateId;
167 jfieldID contextId;
168 jfieldID validId;
169 jfieldID lockId;
170} gLinearBlockInfo;
171
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700172static struct {
173 jclass clazz;
174 jmethodID ctorId;
175 jfieldID nameId;
176 jfieldID typeId;
177} gDescriptorInfo;
178
Pavel Laboviche53421b2022-11-01 03:53:27 +0000179static struct {
180 jclass clazz;
181 jmethodID ctorId;
182 jmethodID setId;
183} gBufferInfo;
184
Andreas Huber88572f72012-02-21 11:47:18 -0800185struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700186 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700187 jmethodID lockAndGetContextID;
188 jmethodID setAndUnlockContextID;
Arun Johnson5a4c7332022-12-17 00:47:06 +0000189 jmethodID cryptoInfoSetID;
190 jmethodID cryptoInfoSetPatternID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700191 jfieldID cryptoInfoNumSubSamplesID;
192 jfieldID cryptoInfoNumBytesOfClearDataID;
193 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
194 jfieldID cryptoInfoKeyID;
195 jfieldID cryptoInfoIVID;
196 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800197 jfieldID cryptoInfoPatternID;
198 jfieldID patternEncryptBlocksID;
199 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800200 jfieldID queueRequestIndexID;
201 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800202 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800203 jfieldID outputFrameChangedKeysID;
204 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800205};
206
207static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700208static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800209
Arun Johnson5a4c7332022-12-17 00:47:06 +0000210jint MediaErrorToJavaError(status_t err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800211
Andreas Huber88572f72012-02-21 11:47:18 -0800212////////////////////////////////////////////////////////////////////////////////
213
214JMediaCodec::JMediaCodec(
215 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100216 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800217 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700218 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800219 jclass clazz = env->GetObjectClass(thiz);
220 CHECK(clazz != NULL);
221
222 mClass = (jclass)env->NewGlobalRef(clazz);
223 mObject = env->NewWeakGlobalRef(thiz);
224
225 mLooper = new ALooper;
226 mLooper->setName("MediaCodec_looper");
227
228 mLooper->start(
229 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700230 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700231 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800232
233 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100234 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800235 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
236 mNameAtCreation = "(null)";
237 }
Andreas Huber88572f72012-02-21 11:47:18 -0800238 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100239 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800240 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800241 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700242 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800243}
244
245status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700246 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800247}
248
Andreas Huberaba67132013-10-22 12:40:01 -0700249void JMediaCodec::registerSelf() {
250 mLooper->registerHandler(this);
251}
252
Chong Zhang128b0122014-03-01 18:04:13 -0800253void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700254 std::call_once(mReleaseFlag, [this] {
255 if (mCodec != NULL) {
256 mCodec->release();
257 mInitStatus = NO_INIT;
258 }
Andreas Huber88572f72012-02-21 11:47:18 -0800259
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700260 if (mLooper != NULL) {
261 mLooper->unregisterHandler(id());
262 mLooper->stop();
263 mLooper.clear();
264 }
265 });
Chong Zhang128b0122014-03-01 18:04:13 -0800266}
267
Wonsik Kim89666622020-04-28 10:43:47 -0700268void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700269 std::call_once(mAsyncReleaseFlag, [this] {
270 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700271 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
272 // Hold strong reference to this until async release is complete
273 notify->setObject("this", this);
274 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700275 }
276 mInitStatus = NO_INIT;
277 });
Wonsik Kim89666622020-04-28 10:43:47 -0700278}
279
Chong Zhang128b0122014-03-01 18:04:13 -0800280JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700281 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800282 /* MediaCodec and looper should have been released explicitly already
283 * in setMediaCodec() (see comments in setMediaCodec()).
284 *
285 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
286 * message handler, doing release() there risks deadlock as MediaCodec::
287 * release() post synchronous message to the same looper.
288 *
289 * Print a warning and try to proceed with releasing.
290 */
291 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
292 release();
293 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
294 }
295
Andreas Huber88572f72012-02-21 11:47:18 -0800296 JNIEnv *env = AndroidRuntime::getJNIEnv();
297
298 env->DeleteWeakGlobalRef(mObject);
299 mObject = NULL;
300 env->DeleteGlobalRef(mClass);
301 mClass = NULL;
302}
303
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100304status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
305 if (enable) {
306 if (mOnFirstTunnelFrameReadyNotification == NULL) {
307 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
308 }
309 } else {
310 mOnFirstTunnelFrameReadyNotification.clear();
311 }
312
313 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
314}
315
Lajos Molnard8578572015-06-05 20:17:33 -0700316status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
317 if (enable) {
318 if (mOnFrameRenderedNotification == NULL) {
319 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
320 }
321 } else {
322 mOnFrameRenderedNotification.clear();
323 }
324
325 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
326}
327
Chong Zhang8d5e5562014-07-08 18:49:21 -0700328status_t JMediaCodec::setCallback(jobject cb) {
329 if (cb != NULL) {
330 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800331 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700332 }
333 } else {
334 mCallbackNotification.clear();
335 }
336
337 return mCodec->setCallback(mCallbackNotification);
338}
339
Andreas Huber88572f72012-02-21 11:47:18 -0800340status_t JMediaCodec::configure(
341 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800342 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700343 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800344 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800345 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800346 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800347 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700348 mSurfaceTextureClient =
349 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700350 } else {
351 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800352 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700353
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800354 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
355 AString mime;
356 CHECK(format->findString("mime", &mime));
357 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
358 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700359 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800360 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800361
Chong Zhangd5927ae2017-01-03 11:07:18 -0800362 return mCodec->configure(
363 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800364}
365
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700366status_t JMediaCodec::setSurface(
367 const sp<IGraphicBufferProducer> &bufferProducer) {
368 sp<Surface> client;
369 if (bufferProducer != NULL) {
370 client = new Surface(bufferProducer, true /* controlledByApp */);
371 }
372 status_t err = mCodec->setSurface(client);
373 if (err == OK) {
374 mSurfaceTextureClient = client;
375 }
376 return err;
377}
378
Andy McFadden2621e402013-02-19 07:29:21 -0800379status_t JMediaCodec::createInputSurface(
380 sp<IGraphicBufferProducer>* bufferProducer) {
381 return mCodec->createInputSurface(bufferProducer);
382}
383
Chong Zhang9560ddb2015-05-13 10:25:29 -0700384status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700385 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700386 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700387}
388
Andreas Huber88572f72012-02-21 11:47:18 -0800389status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700390 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800391}
392
393status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700394 mSurfaceTextureClient.clear();
395
Chong Zhang8d5e5562014-07-08 18:49:21 -0700396 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800397}
398
399status_t JMediaCodec::flush() {
400 return mCodec->flush();
401}
402
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700403status_t JMediaCodec::reset() {
404 return mCodec->reset();
405}
406
Andreas Huber88572f72012-02-21 11:47:18 -0800407status_t JMediaCodec::queueInputBuffer(
408 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700409 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
410 AString *errorDetailMsg) {
411 return mCodec->queueInputBuffer(
412 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800413}
414
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700415status_t JMediaCodec::queueSecureInputBuffer(
416 size_t index,
417 size_t offset,
418 const CryptoPlugin::SubSample *subSamples,
419 size_t numSubSamples,
420 const uint8_t key[16],
421 const uint8_t iv[16],
422 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800423 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700424 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700425 uint32_t flags,
426 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700427 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800428 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700429 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700430}
431
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800432status_t JMediaCodec::queueBuffer(
433 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
434 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
435 return mCodec->queueBuffer(
436 index, buffer, timeUs, flags, tunings, errorDetailMsg);
437}
438
439status_t JMediaCodec::queueEncryptedLinearBlock(
440 size_t index,
441 const sp<hardware::HidlMemory> &buffer,
442 size_t offset,
443 const CryptoPlugin::SubSample *subSamples,
444 size_t numSubSamples,
445 const uint8_t key[16],
446 const uint8_t iv[16],
447 CryptoPlugin::Mode mode,
448 const CryptoPlugin::Pattern &pattern,
449 int64_t presentationTimeUs,
450 uint32_t flags,
451 const sp<AMessage> &tunings,
452 AString *errorDetailMsg) {
453 return mCodec->queueEncryptedBuffer(
454 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
455 presentationTimeUs, flags, tunings, errorDetailMsg);
456}
457
Andreas Huber88572f72012-02-21 11:47:18 -0800458status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700459 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800460}
461
462status_t JMediaCodec::dequeueOutputBuffer(
463 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
464 size_t size, offset;
465 int64_t timeUs;
466 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700467 status_t err = mCodec->dequeueOutputBuffer(
468 index, &offset, &size, &timeUs, &flags, timeoutUs);
469
Andreas Huberaba67132013-10-22 12:40:01 -0700470 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800471 return err;
472 }
473
Pavel Laboviche53421b2022-11-01 03:53:27 +0000474 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800475
476 return OK;
477}
478
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700479status_t JMediaCodec::releaseOutputBuffer(
480 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
481 if (updatePTS) {
482 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
483 }
Andreas Huber88572f72012-02-21 11:47:18 -0800484 return render
485 ? mCodec->renderOutputBufferAndRelease(index)
486 : mCodec->releaseOutputBuffer(index);
487}
488
Andy McFadden2621e402013-02-19 07:29:21 -0800489status_t JMediaCodec::signalEndOfInputStream() {
490 return mCodec->signalEndOfInputStream();
491}
492
Lajos Molnard4023112014-07-11 15:12:59 -0700493status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800494 sp<AMessage> msg;
495 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700496 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
497 if (err != OK) {
498 return err;
499 }
500
501 return ConvertMessageToMap(env, msg, format);
502}
503
504status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
505 sp<AMessage> msg;
506 status_t err;
507 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800508 return err;
509 }
510
511 return ConvertMessageToMap(env, msg, format);
512}
513
514status_t JMediaCodec::getBuffers(
515 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900516 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800517
518 status_t err =
519 input
520 ? mCodec->getInputBuffers(&buffers)
521 : mCodec->getOutputBuffers(&buffers);
522
523 if (err != OK) {
524 return err;
525 }
526
Andreas Huber88572f72012-02-21 11:47:18 -0800527 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800528 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800529 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800530 return NO_MEMORY;
531 }
Andreas Huber88572f72012-02-21 11:47:18 -0800532
533 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900534 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800535
Lajos Molnar7de28d32014-07-25 07:51:02 -0700536 jobject byteBuffer = NULL;
537 err = createByteBufferFromABuffer(
538 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
539 if (err != OK) {
540 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800541 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700542 if (byteBuffer != NULL) {
543 env->SetObjectArrayElement(
544 *bufArray, i, byteBuffer);
545
Lajos Molnard4023112014-07-11 15:12:59 -0700546 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700547 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700548 }
Andreas Huber88572f72012-02-21 11:47:18 -0800549 }
550
Lajos Molnar7de28d32014-07-25 07:51:02 -0700551 return OK;
552}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700553
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800554template <typename T>
555static jobject CreateByteBuffer(
556 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
557 bool readOnly, bool clearBuffer) {
558 jobject byteBuffer =
559 env->NewDirectByteBuffer(
560 const_cast<typename std::remove_const<T>::type *>(base),
561 capacity);
562 if (readOnly && byteBuffer != NULL) {
563 jobject readOnlyBuffer = env->CallObjectMethod(
564 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
565 env->DeleteLocalRef(byteBuffer);
566 byteBuffer = readOnlyBuffer;
567 }
568 if (byteBuffer == NULL) {
569 return nullptr;
570 }
571 jobject me = env->CallObjectMethod(
572 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
573 env->DeleteLocalRef(me);
574 me = env->CallObjectMethod(
575 byteBuffer, gByteBufferInfo.limitId,
576 clearBuffer ? capacity : offset + size);
577 env->DeleteLocalRef(me);
578 me = env->CallObjectMethod(
579 byteBuffer, gByteBufferInfo.positionId,
580 clearBuffer ? 0 : offset);
581 env->DeleteLocalRef(me);
582 me = NULL;
583 return byteBuffer;
584}
585
586
Lajos Molnar7de28d32014-07-25 07:51:02 -0700587// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900588template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700589status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900590 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700591 jobject *buf) const {
592 // if this is an ABuffer that doesn't actually hold any accessible memory,
593 // use a null ByteBuffer
594 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700595
596 if (buffer == NULL) {
597 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
598 return OK;
599 }
600
Lajos Molnar7de28d32014-07-25 07:51:02 -0700601 if (buffer->base() == NULL) {
602 return OK;
603 }
604
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800605 jobject byteBuffer = CreateByteBuffer(
606 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
607 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700608
609 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800610 return OK;
611}
612
Lajos Molnard4023112014-07-11 15:12:59 -0700613status_t JMediaCodec::getBuffer(
614 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900615 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700616
617 status_t err =
618 input
619 ? mCodec->getInputBuffer(index, &buffer)
620 : mCodec->getOutputBuffer(index, &buffer);
621
622 if (err != OK) {
623 return err;
624 }
625
Lajos Molnar7de28d32014-07-25 07:51:02 -0700626 return createByteBufferFromABuffer(
627 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700628}
629
630status_t JMediaCodec::getImage(
631 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900632 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700633
634 status_t err =
635 input
636 ? mCodec->getInputBuffer(index, &buffer)
637 : mCodec->getOutputBuffer(index, &buffer);
638
639 if (err != OK) {
640 return err;
641 }
642
643 // if this is an ABuffer that doesn't actually hold any accessible memory,
644 // use a null ByteBuffer
645 *buf = NULL;
646 if (buffer->base() == NULL) {
647 return OK;
648 }
649
650 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700651 sp<ABuffer> imageData;
652 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700653 return OK;
654 }
655
Lajos Molnar7de28d32014-07-25 07:51:02 -0700656 int64_t timestamp = 0;
657 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
658 timestamp *= 1000; // adjust to ns
659 }
660
661 jobject byteBuffer = NULL;
662 err = createByteBufferFromABuffer(
663 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
664 if (err != OK) {
665 return OK;
666 }
667
668 jobject infoBuffer = NULL;
669 err = createByteBufferFromABuffer(
670 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
671 if (err != OK) {
672 env->DeleteLocalRef(byteBuffer);
673 byteBuffer = NULL;
674 return OK;
675 }
676
677 jobject cropRect = NULL;
678 int32_t left, top, right, bottom;
679 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
680 ScopedLocalRef<jclass> rectClazz(
681 env, env->FindClass("android/graphics/Rect"));
682 CHECK(rectClazz.get() != NULL);
683
684 jmethodID rectConstructID = env->GetMethodID(
685 rectClazz.get(), "<init>", "(IIII)V");
686
687 cropRect = env->NewObject(
688 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
689 }
690
691 ScopedLocalRef<jclass> imageClazz(
692 env, env->FindClass("android/media/MediaCodec$MediaImage"));
693 CHECK(imageClazz.get() != NULL);
694
695 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
696 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
697
698 *buf = env->NewObject(imageClazz.get(), imageConstructID,
699 byteBuffer, infoBuffer,
700 (jboolean)!input /* readOnly */,
701 (jlong)timestamp,
702 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
703
704 // if MediaImage creation fails, return null
705 if (env->ExceptionCheck()) {
706 env->ExceptionDescribe();
707 env->ExceptionClear();
708 *buf = NULL;
709 }
710
711 if (cropRect != NULL) {
712 env->DeleteLocalRef(cropRect);
713 cropRect = NULL;
714 }
715
716 env->DeleteLocalRef(byteBuffer);
717 byteBuffer = NULL;
718
719 env->DeleteLocalRef(infoBuffer);
720 infoBuffer = NULL;
721
Lajos Molnard4023112014-07-11 15:12:59 -0700722 return OK;
723}
724
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800725status_t JMediaCodec::getOutputFrame(
726 JNIEnv *env, jobject frame, size_t index) const {
727 sp<MediaCodecBuffer> buffer;
728
729 status_t err = mCodec->getOutputBuffer(index, &buffer);
730 if (err != OK) {
731 return err;
732 }
733
734 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800735 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800736 if (c2Buffer) {
737 switch (c2Buffer->data().type()) {
738 case C2BufferData::LINEAR: {
739 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700740 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800741 context->mBuffer = c2Buffer;
742 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
743 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800744 env->CallVoidMethod(
745 linearBlock.get(),
746 gLinearBlockInfo.setInternalStateId,
747 (jlong)context.release(),
748 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800749 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
750 break;
751 }
752 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800753 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
754 uint32_t width, height, format, stride, igbp_slot, generation;
755 uint64_t usage, igbp_id;
756 _UnwrapNativeCodec2GrallocMetadata(
757 c2Handle, &width, &height, &format, &usage, &stride, &generation,
758 &igbp_id, &igbp_slot);
759 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
760 GraphicBuffer* graphicBuffer = new GraphicBuffer(
761 grallocHandle, GraphicBuffer::CLONE_HANDLE,
762 width, height, format, 1, usage, stride);
763 ScopedLocalRef<jobject> hardwareBuffer{
764 env,
765 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
766 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
767 env->SetObjectField(
768 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800769 break;
770 }
771 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
772 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
773 case C2BufferData::INVALID: [[fallthrough]];
774 default:
775 return INVALID_OPERATION;
776 }
777 } else {
778 if (!mGraphicOutput) {
779 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700780 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800781 context->mLegacyBuffer = buffer;
782 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
783 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800784 env->CallVoidMethod(
785 linearBlock.get(),
786 gLinearBlockInfo.setInternalStateId,
787 (jlong)context.release(),
788 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800789 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
790 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800791 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800792 }
793 }
794 }
795
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700796 jobject formatMap;
797 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800798 if (err != OK) {
799 return err;
800 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700801 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
802 ScopedLocalRef<jobject> format{env, env->NewObject(
803 mediaFormatClass.get(),
804 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
805 formatMap)};
806 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
807 env->DeleteLocalRef(formatMap);
808 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800809
810 sp<RefBase> obj;
811 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
812 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
813 (decltype(changedKeys.get()))obj.get()};
814 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
815 frame, gFields.outputFrameChangedKeysID)};
816 for (const std::string &key : changedKeys->value) {
817 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
818 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
819 }
820 }
821 return OK;
822}
823
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300824status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
825 AString name;
826
827 status_t err = mCodec->getName(&name);
828
829 if (err != OK) {
830 return err;
831 }
832
833 *nameStr = env->NewStringUTF(name.c_str());
834
835 return OK;
836}
837
Chong Zhanga0b72a62018-02-28 18:46:26 -0800838static jobject getCodecCapabilitiesObject(
839 JNIEnv *env, const char *mime, bool isEncoder,
840 const sp<MediaCodecInfo::Capabilities> &capabilities) {
841 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
842 Vector<uint32_t> colorFormats;
843
844 sp<AMessage> defaultFormat = new AMessage();
845 defaultFormat->setString("mime", mime);
846
847 capabilities->getSupportedColorFormats(&colorFormats);
848 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800849 sp<AMessage> details = capabilities->getDetails();
850
851 jobject defaultFormatObj = NULL;
852 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
853 return NULL;
854 }
855 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
856
857 jobject detailsObj = NULL;
858 if (ConvertMessageToMap(env, details, &detailsObj)) {
859 return NULL;
860 }
861 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
862
863 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
864 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
865
866 for (size_t i = 0; i < profileLevels.size(); ++i) {
867 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
868
869 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
870 gCodecInfo.profileLevelClazz));
871
872 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
873 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
874
875 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
876 }
877
878 ScopedLocalRef<jintArray> colorFormatsArray(
879 env, env->NewIntArray(colorFormats.size()));
880 for (size_t i = 0; i < colorFormats.size(); ++i) {
881 jint val = colorFormats.itemAt(i);
882 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
883 }
884
885 return env->NewObject(
886 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800887 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800888 defaultFormatRef.get(), detailsRef.get());
889}
890
891status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
892 sp<MediaCodecInfo> codecInfo;
893
894 status_t err = mCodec->getCodecInfo(&codecInfo);
895
896 if (err != OK) {
897 return err;
898 }
899
900 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800901 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800902
Lajos Molnard2a7f472018-11-15 12:49:20 -0800903 ScopedLocalRef<jstring> canonicalNameObject(env,
904 env->NewStringUTF(codecInfo->getCodecName()));
905
906 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800907 bool isEncoder = codecInfo->isEncoder();
908
Lajos Molnard2a7f472018-11-15 12:49:20 -0800909 Vector<AString> mediaTypes;
910 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800911
912 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800913 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800914
Lajos Molnard2a7f472018-11-15 12:49:20 -0800915 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800916 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800917 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800918
919 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800920 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800921
922 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
923 }
924
925 ScopedLocalRef<jclass> codecInfoClazz(env,
926 env->FindClass("android/media/MediaCodecInfo"));
927 CHECK(codecInfoClazz.get() != NULL);
928
929 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800930 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800931
932 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800933 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800934
935 return OK;
936}
937
Ray Essick81fbc5b2019-12-07 06:24:59 -0800938status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
939 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700940 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700941 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800942 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800943 return status;
944}
945
Andreas Huber226065b2013-08-12 10:14:11 -0700946status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
947 return mCodec->setParameters(msg);
948}
949
Andreas Huberb12a5392012-04-30 14:18:33 -0700950void JMediaCodec::setVideoScalingMode(int mode) {
951 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700952 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700953 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700954 // also signal via param for components that queue to IGBP
955 sp<AMessage> msg = new AMessage;
956 msg->setInt32("android._video-scaling", mode);
957 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700958 }
959}
960
ybai5e053202018-11-01 13:02:15 +0800961void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
962 sp<AMessage> msg = new AMessage;
963 msg->setInt32("audio-presentation-presentation-id", presentationId);
964 msg->setInt32("audio-presentation-program-id", programId);
965 (void)mCodec->setParameters(msg);
966}
967
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700968status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
969 std::vector<std::string> names;
970 status_t status = mCodec->querySupportedVendorParameters(&names);
971 if (status != OK) {
972 return status;
973 }
974 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
975 for (const std::string &name : names) {
976 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
977 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
978 }
979 return OK;
980}
981
982status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
983 const char *tmp = env->GetStringUTFChars(name, nullptr);
984 CodecParameterDescriptor desc;
985 status_t status = mCodec->describeParameter(tmp, &desc);
986 env->ReleaseStringUTFChars(name, tmp);
987 if (status != OK) {
988 return status;
989 }
990 jint type = TYPE_NULL;
991 switch (desc.type) {
992 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
993 case AMessage::kTypeSize:
994 case AMessage::kTypeInt64: type = TYPE_LONG; break;
995 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
996 case AMessage::kTypeString: type = TYPE_STRING; break;
997 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
998 default: type = TYPE_NULL; break;
999 }
1000 if (type == TYPE_NULL) {
1001 return BAD_VALUE;
1002 }
1003 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1004 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1005 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1006 return OK;
1007}
1008
1009static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1010 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1011 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1012 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1013 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1014 jobject it = env->CallObjectMethod(
1015 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1016 while (env->CallBooleanMethod(it, hasNextID)) {
1017 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1018 const char *tmp = env->GetStringUTFChars(name, nullptr);
1019 vec->push_back(tmp);
1020 env->ReleaseStringUTFChars(name, tmp);
1021 }
1022}
1023
1024status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1025 std::vector<std::string> names;
1026 BuildVectorFromList(env, namesObj, &names);
1027 return mCodec->subscribeToVendorParameters(names);
1028}
1029
1030status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1031 std::vector<std::string> names;
1032 BuildVectorFromList(env, namesObj, &names);
1033 return mCodec->unsubscribeFromVendorParameters(names);
1034}
1035
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001036static jthrowable createCodecException(
1037 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1038 ScopedLocalRef<jclass> clazz(
1039 env, env->FindClass("android/media/MediaCodec$CodecException"));
1040 CHECK(clazz.get() != NULL);
1041
Ronghua Wuc53ad692015-05-08 14:40:49 -07001042 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001043 CHECK(ctor != NULL);
1044
1045 ScopedLocalRef<jstring> msgObj(
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00001046 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err).c_str()));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001047
1048 // translate action code to Java equivalent
1049 switch (actionCode) {
1050 case ACTION_CODE_TRANSIENT:
1051 actionCode = gCodecActionCodes.codecActionTransient;
1052 break;
1053 case ACTION_CODE_RECOVERABLE:
1054 actionCode = gCodecActionCodes.codecActionRecoverable;
1055 break;
1056 default:
1057 actionCode = 0; // everything else is fatal
1058 break;
1059 }
1060
Ronghua Wuc53ad692015-05-08 14:40:49 -07001061 /* translate OS errors to Java API CodecException errorCodes */
1062 switch (err) {
1063 case NO_MEMORY:
1064 err = gCodecErrorCodes.errorInsufficientResource;
1065 break;
1066 case DEAD_OBJECT:
1067 err = gCodecErrorCodes.errorReclaimed;
1068 break;
1069 default: /* Other error codes go out as is. */
1070 break;
1071 }
1072
1073 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001074}
1075
Arun Johnson5a4c7332022-12-17 00:47:06 +00001076static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1077 const sp<AMessage> & msg) {
1078 if(msg == nullptr || obj == nullptr) {
1079 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1080 return;
1081 }
1082 size_t numSubSamples = 0;
1083 sp<ABuffer> subSamplesBuffer;
1084 sp<ABuffer> keyBuffer;
1085 sp<ABuffer> ivBuffer;
1086 CryptoPlugin::Mode mode;
1087 CryptoPlugin::Pattern pattern;
1088 CHECK(msg->findInt32("mode", (int*)&mode));
1089 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1090 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1091 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1092 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1093 CHECK(msg->findBuffer("iv", &ivBuffer));
1094 CHECK(msg->findBuffer("key", &keyBuffer));
1095
1096 // subsamples
1097 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1098 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1099 jboolean isCopy;
1100 jint *dstEncryptedSamples =
1101 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1102 jint * dstClearSamples =
1103 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1104
1105 CryptoPlugin::SubSample * samplesArray =
1106 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1107
1108 for(int i = 0 ; i < numSubSamples ; i++) {
1109 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1110 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1111 }
1112 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1113 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1114 // key and iv
1115 jbyteArray keyArray = NULL;
1116 jbyteArray ivArray = NULL;
1117 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1118 keyArray = env->NewByteArray(keyBuffer->size());
1119 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1120 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1121 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1122 }
1123 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1124 ivArray = env->NewByteArray(ivBuffer->size());
1125 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1126 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1127 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1128 }
1129 // set samples, key and iv
1130 env->CallVoidMethod(
1131 obj,
1132 gFields.cryptoInfoSetID,
1133 (jint)numSubSamples,
1134 samplesOfClearDataArr.get(),
1135 samplesOfEncryptedDataArr.get(),
1136 keyArray,
1137 ivArray,
1138 mode);
1139 if (keyArray != NULL) {
1140 env->DeleteLocalRef(keyArray);
1141 }
1142 if (ivArray != NULL) {
1143 env->DeleteLocalRef(ivArray);
1144 }
1145 // set pattern
1146 env->CallVoidMethod(
1147 obj,
1148 gFields.cryptoInfoSetPatternID,
1149 pattern.mEncryptBlocks,
1150 pattern.mSkipBlocks);
1151}
1152
1153static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1154 switch(err) {
1155 case ERROR_DRM_NO_LICENSE:
1156 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1157 defaultMsg = "Crypto key not available";
1158 break;
1159 case ERROR_DRM_LICENSE_EXPIRED:
1160 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1161 defaultMsg = "License expired";
1162 break;
1163 case ERROR_DRM_RESOURCE_BUSY:
1164 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1165 defaultMsg = "Resource busy or unavailable";
1166 break;
1167 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1168 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1169 defaultMsg = "Required output protections are not active";
1170 break;
1171 case ERROR_DRM_SESSION_NOT_OPENED:
1172 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1173 defaultMsg = "Attempted to use a closed session";
1174 break;
1175 case ERROR_DRM_INSUFFICIENT_SECURITY:
1176 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1177 defaultMsg = "Required security level is not met";
1178 break;
1179 case ERROR_DRM_CANNOT_HANDLE:
1180 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1181 defaultMsg = "Operation not supported in this configuration";
1182 break;
1183 case ERROR_DRM_FRAME_TOO_LARGE:
1184 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1185 defaultMsg = "Decrytped frame exceeds size of output buffer";
1186 break;
1187 case ERROR_DRM_SESSION_LOST_STATE:
1188 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1189 defaultMsg = "Session state was lost, open a new session and retry";
1190 break;
1191 default: // Other negative DRM error codes go out best-effort.
1192 jerr = MediaErrorToJavaError(err);
1193 defaultMsg = StrCryptoError(err);
1194 break;
1195 }
1196}
1197static jthrowable createCryptoException(JNIEnv *env, status_t err,
1198 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1199 const sp<AMessage> & cryptoInfo = NULL) {
1200 jthrowable exception = nullptr;
1201 jmethodID constructID = nullptr;
1202 ScopedLocalRef<jobject> cryptoInfoObject(env);
1203 std::string defaultMsg = "Unknown Error";
1204 jint jerr = 0;
1205 // Get a class ref for CryptoException
1206 ScopedLocalRef<jclass> clazz(
1207 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1208 CHECK(clazz.get() != NULL);
1209
1210 // Get constructor ref for CryptoException
1211 constructID = env->GetMethodID(clazz.get(), "<init>",
1212 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1213 CHECK(constructID != NULL);
1214
1215 // create detailed message for exception
1216 CryptoErrorToJavaError(err, jerr, defaultMsg);
1217 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1218 DrmStatus dStatus(err, originalMsg.c_str());
1219 std::string detailedMsg(
1220 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1221 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1222
1223 if (cryptoInfo != nullptr) {
1224 // Class ref for CryptoInfo
1225 ScopedLocalRef<jclass> clazzCryptoInfo(
1226 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1227 CHECK(clazzCryptoInfo.get() != NULL);
1228
1229 // Constructor reference for CryptoInfo
1230 jmethodID constructCryptoInfo =
1231 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1232 CHECK(constructCryptoInfo != NULL);
1233
1234 // Create CryptoInfo jobject
1235 cryptoInfoObject.reset(
1236 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1237 CHECK(cryptoInfoObject.get() != NULL);
1238
1239 // Translate AMesage to CryptoInfo
1240 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1241 }
1242
1243 exception = (jthrowable)env->NewObject(
1244 clazz.get(), constructID, msgObj, jerr,
1245 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1246 cryptoInfoObject.get());
1247
1248 return exception;
1249}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001250void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1251 int32_t arg1, arg2 = 0;
1252 jobject obj = NULL;
1253 CHECK(msg->findInt32("callbackID", &arg1));
1254 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001255
Chong Zhang8d5e5562014-07-08 18:49:21 -07001256 switch (arg1) {
1257 case MediaCodec::CB_INPUT_AVAILABLE:
1258 {
1259 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001260 break;
1261 }
1262
Chong Zhang8d5e5562014-07-08 18:49:21 -07001263 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001264 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001265 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001266
Chong Zhang8d5e5562014-07-08 18:49:21 -07001267 size_t size, offset;
1268 int64_t timeUs;
1269 uint32_t flags;
1270 CHECK(msg->findSize("size", &size));
1271 CHECK(msg->findSize("offset", &offset));
1272 CHECK(msg->findInt64("timeUs", &timeUs));
1273 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1274
Pavel Laboviche53421b2022-11-01 03:53:27 +00001275 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001276 if (obj == NULL) {
1277 if (env->ExceptionCheck()) {
1278 ALOGE("Could not create MediaCodec.BufferInfo.");
1279 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001280 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001281 jniThrowException(env, "java/lang/IllegalStateException",
1282 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001283 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001284 }
1285
Pavel Laboviche53421b2022-11-01 03:53:27 +00001286 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001287 break;
1288 }
1289
Arun Johnson5a4c7332022-12-17 00:47:06 +00001290 case MediaCodec::CB_CRYPTO_ERROR:
1291 {
1292 int32_t err, actionCode;
1293 AString errorDetail;
1294 CHECK(msg->findInt32("err", &err));
1295 CHECK(msg->findInt32("actionCode",&actionCode));
1296 CHECK(msg->findString("errorDetail", &errorDetail));
1297 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1298 break;
1299 }
1300
Chong Zhang8d5e5562014-07-08 18:49:21 -07001301 case MediaCodec::CB_ERROR:
1302 {
Chong Zhang94686d12014-07-11 15:53:58 -07001303 int32_t err, actionCode;
1304 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001305 CHECK(msg->findInt32("actionCode", &actionCode));
1306
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001307 // note that DRM errors could conceivably alias into a CodecException
1308 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001309
1310 if (obj == NULL) {
1311 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001312 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001313 env->ExceptionClear();
1314 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001315 jniThrowException(env, "java/lang/IllegalStateException",
1316 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001317 return;
1318 }
Andreas Huberaba67132013-10-22 12:40:01 -07001319
1320 break;
1321 }
1322
Chong Zhang8d5e5562014-07-08 18:49:21 -07001323 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001324 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001325 sp<AMessage> format;
1326 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001327
Chong Zhang8d5e5562014-07-08 18:49:21 -07001328 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001329 jniThrowException(env, "java/lang/IllegalStateException",
1330 "Fatal error: failed to convert format "
1331 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001332 return;
1333 }
Andreas Huberaba67132013-10-22 12:40:01 -07001334
Andreas Huberaba67132013-10-22 12:40:01 -07001335 break;
1336 }
1337
1338 default:
1339 TRESPASS();
1340 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001341 env->CallVoidMethod(
1342 mObject,
1343 gFields.postEventFromNativeID,
1344 EVENT_CALLBACK,
1345 arg1,
1346 arg2,
1347 obj);
1348
1349 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001350}
1351
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001352void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1353 int32_t arg1 = 0, arg2 = 0;
1354 jobject obj = NULL;
1355 JNIEnv *env = AndroidRuntime::getJNIEnv();
1356
1357 sp<AMessage> data;
1358 CHECK(msg->findMessage("data", &data));
1359
1360 status_t err = ConvertMessageToMap(env, data, &obj);
1361 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001362 jniThrowException(env, "java/lang/IllegalStateException",
1363 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001364 return;
1365 }
1366
1367 env->CallVoidMethod(
1368 mObject, gFields.postEventFromNativeID,
1369 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1370
1371 env->DeleteLocalRef(obj);
1372}
1373
Lajos Molnard8578572015-06-05 20:17:33 -07001374void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1375 int32_t arg1 = 0, arg2 = 0;
1376 jobject obj = NULL;
1377 JNIEnv *env = AndroidRuntime::getJNIEnv();
1378
1379 sp<AMessage> data;
1380 CHECK(msg->findMessage("data", &data));
1381
1382 status_t err = ConvertMessageToMap(env, data, &obj);
1383 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001384 jniThrowException(env, "java/lang/IllegalStateException",
1385 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001386 return;
1387 }
1388
1389 env->CallVoidMethod(
1390 mObject, gFields.postEventFromNativeID,
1391 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1392
1393 env->DeleteLocalRef(obj);
1394}
1395
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001396std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1397 if (mCodec == nullptr) {
1398 return msg ?: "";
1399 }
1400 std::string prefix = "";
1401 if (msg && msg[0] != '\0') {
1402 prefix.append(msg);
1403 prefix.append("\n");
1404 }
1405 return prefix + mCodec->getErrorLog().extract();
1406}
1407
Chong Zhang8d5e5562014-07-08 18:49:21 -07001408void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1409 switch (msg->what()) {
1410 case kWhatCallbackNotify:
1411 {
1412 handleCallback(msg);
1413 break;
1414 }
Lajos Molnard8578572015-06-05 20:17:33 -07001415 case kWhatFrameRendered:
1416 {
1417 handleFrameRenderedNotification(msg);
1418 break;
1419 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001420 case kWhatAsyncReleaseComplete:
1421 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001422 if (mLooper != NULL) {
1423 mLooper->unregisterHandler(id());
1424 mLooper->stop();
1425 mLooper.clear();
1426 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001427 break;
1428 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001429 case kWhatFirstTunnelFrameReady:
1430 {
1431 handleFirstTunnelFrameReadyNotification(msg);
1432 break;
1433 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001434 default:
1435 TRESPASS();
1436 }
Andreas Huberaba67132013-10-22 12:40:01 -07001437}
1438
Robert Shih631a80d2021-02-14 02:23:55 -08001439
Andreas Huber88572f72012-02-21 11:47:18 -08001440} // namespace android
1441
1442////////////////////////////////////////////////////////////////////////////////
1443
1444using namespace android;
1445
1446static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001447 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001448 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001449 if (codec != NULL) {
1450 codec->incStrong(thiz);
1451 }
1452 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001453 /* release MediaCodec and stop the looper now before decStrong.
1454 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1455 * its message handler, doing release() from there will deadlock
1456 * (as MediaCodec::release() post synchronous message to the same looper)
1457 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001458 if (release) {
1459 old->release();
1460 }
Andreas Huber88572f72012-02-21 11:47:18 -08001461 old->decStrong(thiz);
1462 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001463 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001464
1465 return old;
1466}
1467
1468static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001469 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1470 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1471 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001472}
1473
1474static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001475 // Clear Java native reference.
1476 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001477 if (codec != NULL) {
1478 codec->releaseAsync();
1479 }
Andreas Huber88572f72012-02-21 11:47:18 -08001480}
1481
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001482static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1483 jthrowable exception = createCodecException(env, err, actionCode, msg);
1484 env->Throw(exception);
1485}
1486
Robert Shih631a80d2021-02-14 02:23:55 -08001487static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1488 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001489 jthrowable exception = createCryptoException(
1490 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001491 env->Throw(exception);
1492}
1493
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001494static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1495 if (codec == NULL) {
1496 return msg ?: "codec is released already";
1497 }
1498 return codec->getExceptionMessage(msg);
1499}
1500
Andreas Huberbfc56f42012-04-19 12:47:07 -07001501static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001502 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001503 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1504 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001505 switch (err) {
1506 case OK:
1507 return 0;
1508
1509 case -EAGAIN:
1510 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1511
1512 case INFO_FORMAT_CHANGED:
1513 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1514
1515 case INFO_OUTPUT_BUFFERS_CHANGED:
1516 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1517
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001518 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001519 jniThrowException(
1520 env, "java/lang/IllegalStateException",
1521 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001522 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001523
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001524 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001525 jniThrowException(
1526 env, "java/lang/IllegalArgumentException",
1527 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001528 return 0;
1529
Andreas Huber88572f72012-02-21 11:47:18 -08001530 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001531 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001532 throwCryptoException(
1533 env, err,
1534 GetExceptionMessage(codec, msg).c_str(),
1535 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001536 return 0;
1537 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001538 throwCodecException(
1539 env, err, actionCode,
1540 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001541 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001542 }
Andreas Huber88572f72012-02-21 11:47:18 -08001543}
1544
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001545static jint throwExceptionAsNecessary(
1546 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1547 int32_t actionCode = ACTION_CODE_FATAL) {
1548 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1549}
1550
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001551static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1552 JNIEnv *env,
1553 jobject thiz,
1554 jboolean enabled) {
1555 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1556
1557 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001558 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001559 return;
1560 }
1561
1562 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1563
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001564 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001565}
1566
Lajos Molnard8578572015-06-05 20:17:33 -07001567static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1568 JNIEnv *env,
1569 jobject thiz,
1570 jboolean enabled) {
1571 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1572
Wonsik Kim24e53802020-05-08 20:04:26 -07001573 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001574 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001575 return;
1576 }
1577
1578 status_t err = codec->enableOnFrameRenderedListener(enabled);
1579
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001580 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001581}
1582
Chong Zhang8d5e5562014-07-08 18:49:21 -07001583static void android_media_MediaCodec_native_setCallback(
1584 JNIEnv *env,
1585 jobject thiz,
1586 jobject cb) {
1587 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1588
Wonsik Kim24e53802020-05-08 20:04:26 -07001589 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001590 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001591 return;
1592 }
1593
1594 status_t err = codec->setCallback(cb);
1595
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001596 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001597}
1598
Andreas Huber88572f72012-02-21 11:47:18 -08001599static void android_media_MediaCodec_native_configure(
1600 JNIEnv *env,
1601 jobject thiz,
1602 jobjectArray keys, jobjectArray values,
1603 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001604 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001605 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001606 jint flags) {
1607 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1608
Wonsik Kim24e53802020-05-08 20:04:26 -07001609 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001610 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001611 return;
1612 }
1613
1614 sp<AMessage> format;
1615 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1616
1617 if (err != OK) {
1618 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1619 return;
1620 }
1621
Andy McFaddend47f7d82012-12-18 09:48:38 -08001622 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001623 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001624 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001625 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001626 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001627 } else {
1628 jniThrowException(
1629 env,
1630 "java/lang/IllegalArgumentException",
1631 "The surface has been released");
1632 return;
1633 }
1634 }
1635
Andreas Huber8240d922012-04-04 14:06:32 -07001636 sp<ICrypto> crypto;
1637 if (jcrypto != NULL) {
1638 crypto = JCrypto::GetCrypto(env, jcrypto);
1639 }
1640
Chong Zhangd5927ae2017-01-03 11:07:18 -08001641 sp<IDescrambler> descrambler;
1642 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001643 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001644 }
1645
1646 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001647
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001648 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001649}
1650
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001651static void android_media_MediaCodec_native_setSurface(
1652 JNIEnv *env,
1653 jobject thiz,
1654 jobject jsurface) {
1655 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1656
Wonsik Kim24e53802020-05-08 20:04:26 -07001657 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001658 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001659 return;
1660 }
1661
1662 sp<IGraphicBufferProducer> bufferProducer;
1663 if (jsurface != NULL) {
1664 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1665 if (surface != NULL) {
1666 bufferProducer = surface->getIGraphicBufferProducer();
1667 } else {
1668 jniThrowException(
1669 env,
1670 "java/lang/IllegalArgumentException",
1671 "The surface has been released");
1672 return;
1673 }
1674 }
1675
1676 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001677 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001678}
1679
Chong Zhang8034d602015-04-28 13:38:48 -07001680sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1681 JNIEnv* env, jobject object) {
1682 sp<PersistentSurface> persistentSurface;
1683
1684 jobject lock = env->GetObjectField(
1685 object, gPersistentSurfaceClassInfo.mLock);
1686 if (env->MonitorEnter(lock) == JNI_OK) {
1687 persistentSurface = reinterpret_cast<PersistentSurface *>(
1688 env->GetLongField(object,
1689 gPersistentSurfaceClassInfo.mPersistentObject));
1690 env->MonitorExit(lock);
1691 }
1692 env->DeleteLocalRef(lock);
1693
1694 return persistentSurface;
1695}
1696
1697static jobject android_media_MediaCodec_createPersistentInputSurface(
1698 JNIEnv* env, jclass /* clazz */) {
1699 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1700 sp<PersistentSurface> persistentSurface =
1701 MediaCodec::CreatePersistentInputSurface();
1702
1703 if (persistentSurface == NULL) {
1704 return NULL;
1705 }
1706
1707 sp<Surface> surface = new Surface(
1708 persistentSurface->getBufferProducer(), true);
1709 if (surface == NULL) {
1710 return NULL;
1711 }
1712
1713 jobject object = env->NewObject(
1714 gPersistentSurfaceClassInfo.clazz,
1715 gPersistentSurfaceClassInfo.ctor);
1716
1717 if (object == NULL) {
1718 if (env->ExceptionCheck()) {
1719 ALOGE("Could not create PersistentSurface.");
1720 env->ExceptionClear();
1721 }
1722 return NULL;
1723 }
1724
1725 jobject lock = env->GetObjectField(
1726 object, gPersistentSurfaceClassInfo.mLock);
1727 if (env->MonitorEnter(lock) == JNI_OK) {
1728 env->CallVoidMethod(
1729 object,
1730 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1731 (jlong)surface.get());
1732 env->SetLongField(
1733 object,
1734 gPersistentSurfaceClassInfo.mPersistentObject,
1735 (jlong)persistentSurface.get());
1736 env->MonitorExit(lock);
1737 } else {
1738 env->DeleteLocalRef(object);
1739 object = NULL;
1740 }
1741 env->DeleteLocalRef(lock);
1742
1743 if (object != NULL) {
1744 surface->incStrong(&sRefBaseOwner);
1745 persistentSurface->incStrong(&sRefBaseOwner);
1746 }
1747
1748 return object;
1749}
1750
1751static void android_media_MediaCodec_releasePersistentInputSurface(
1752 JNIEnv* env, jclass /* clazz */, jobject object) {
1753 sp<PersistentSurface> persistentSurface;
1754
1755 jobject lock = env->GetObjectField(
1756 object, gPersistentSurfaceClassInfo.mLock);
1757 if (env->MonitorEnter(lock) == JNI_OK) {
1758 persistentSurface = reinterpret_cast<PersistentSurface *>(
1759 env->GetLongField(
1760 object, gPersistentSurfaceClassInfo.mPersistentObject));
1761 env->SetLongField(
1762 object,
1763 gPersistentSurfaceClassInfo.mPersistentObject,
1764 (jlong)0);
1765 env->MonitorExit(lock);
1766 }
1767 env->DeleteLocalRef(lock);
1768
1769 if (persistentSurface != NULL) {
1770 persistentSurface->decStrong(&sRefBaseOwner);
1771 }
1772 // no need to release surface as it will be released by Surface's jni
1773}
1774
Chong Zhang9560ddb2015-05-13 10:25:29 -07001775static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001776 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001777 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001778
1779 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001780 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001781 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001782 return;
1783 }
1784
1785 sp<PersistentSurface> persistentSurface =
1786 android_media_MediaCodec_getPersistentInputSurface(env, object);
1787
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001788 if (persistentSurface == NULL) {
1789 throwExceptionAsNecessary(
1790 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1791 return;
1792 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001793 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001794 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001795 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001796 }
1797}
1798
Andy McFadden2621e402013-02-19 07:29:21 -08001799static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1800 jobject thiz) {
1801 ALOGV("android_media_MediaCodec_createInputSurface");
1802
1803 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001804 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001805 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001806 return NULL;
1807 }
1808
1809 // Tell the MediaCodec that we want to use a Surface as input.
1810 sp<IGraphicBufferProducer> bufferProducer;
1811 status_t err = codec->createInputSurface(&bufferProducer);
1812 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001813 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001814 return NULL;
1815 }
1816
1817 // Wrap the IGBP in a Java-language Surface.
1818 return android_view_Surface_createFromIGraphicBufferProducer(env,
1819 bufferProducer);
1820}
1821
Andreas Huber88572f72012-02-21 11:47:18 -08001822static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1823 ALOGV("android_media_MediaCodec_start");
1824
1825 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1826
Wonsik Kim24e53802020-05-08 20:04:26 -07001827 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001828 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001829 return;
1830 }
1831
1832 status_t err = codec->start();
1833
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001834 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001835}
1836
1837static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1838 ALOGV("android_media_MediaCodec_stop");
1839
1840 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1841
Wonsik Kim24e53802020-05-08 20:04:26 -07001842 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001843 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001844 return;
1845 }
1846
1847 status_t err = codec->stop();
1848
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001849 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001850}
1851
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001852static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1853 ALOGV("android_media_MediaCodec_reset");
1854
1855 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1856
Wonsik Kim24e53802020-05-08 20:04:26 -07001857 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001858 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001859 return;
1860 }
1861
1862 status_t err = codec->reset();
1863 if (err != OK) {
1864 // treat all errors as fatal for now, though resource not available
1865 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001866 // we also should avoid sending INVALID_OPERATION here due to
1867 // the transitory nature of reset(), it should not inadvertently
1868 // trigger an IllegalStateException.
1869 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001870 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001871 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001872}
1873
Andreas Huber88572f72012-02-21 11:47:18 -08001874static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1875 ALOGV("android_media_MediaCodec_flush");
1876
1877 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1878
Wonsik Kim24e53802020-05-08 20:04:26 -07001879 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001880 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001881 return;
1882 }
1883
1884 status_t err = codec->flush();
1885
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001886 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001887}
1888
1889static void android_media_MediaCodec_queueInputBuffer(
1890 JNIEnv *env,
1891 jobject thiz,
1892 jint index,
1893 jint offset,
1894 jint size,
1895 jlong timestampUs,
1896 jint flags) {
1897 ALOGV("android_media_MediaCodec_queueInputBuffer");
1898
1899 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1900
Wonsik Kim24e53802020-05-08 20:04:26 -07001901 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001902 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001903 return;
1904 }
1905
Andreas Huberbfc56f42012-04-19 12:47:07 -07001906 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001907
Andreas Huberbfc56f42012-04-19 12:47:07 -07001908 status_t err = codec->queueInputBuffer(
1909 index, offset, size, timestampUs, flags, &errorDetailMsg);
1910
1911 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001912 env, err, ACTION_CODE_FATAL,
1913 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001914}
1915
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001916struct NativeCryptoInfo {
1917 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1918 : mEnv{env},
1919 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1920 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1921 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1922
1923 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1924 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1925
1926 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1927 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1928
1929 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1930 if (jmode == gCryptoModes.Unencrypted) {
1931 mMode = CryptoPlugin::kMode_Unencrypted;
1932 } else if (jmode == gCryptoModes.AesCtr) {
1933 mMode = CryptoPlugin::kMode_AES_CTR;
1934 } else if (jmode == gCryptoModes.AesCbc) {
1935 mMode = CryptoPlugin::kMode_AES_CBC;
1936 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001937 throwExceptionAsNecessary(
1938 env, INVALID_OPERATION, ACTION_CODE_FATAL,
1939 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001940 return;
1941 }
1942
1943 ScopedLocalRef<jobject> patternObj{
1944 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1945
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001946 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001947 mPattern.mEncryptBlocks = 0;
1948 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001949 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001950 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001951 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001952 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001953 patternObj.get(), gFields.patternSkipBlocksID);
1954 }
1955
1956 mErr = OK;
1957 if (mNumSubSamples <= 0) {
1958 mErr = -EINVAL;
1959 } else if (numBytesOfClearDataObj == nullptr
1960 && numBytesOfEncryptedDataObj == nullptr) {
1961 mErr = -EINVAL;
1962 } else if (numBytesOfEncryptedDataObj != nullptr
1963 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1964 mErr = -ERANGE;
1965 } else if (numBytesOfClearDataObj != nullptr
1966 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1967 mErr = -ERANGE;
1968 // subSamples array may silently overflow if number of samples are too large. Use
1969 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1970 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1971 mErr = -EINVAL;
1972 } else {
1973 jint *numBytesOfClearData =
1974 (numBytesOfClearDataObj == nullptr)
1975 ? nullptr
1976 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1977
1978 jint *numBytesOfEncryptedData =
1979 (numBytesOfEncryptedDataObj == nullptr)
1980 ? nullptr
1981 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1982
1983 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1984
1985 for (jint i = 0; i < mNumSubSamples; ++i) {
1986 mSubSamples[i].mNumBytesOfClearData =
1987 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1988
1989 mSubSamples[i].mNumBytesOfEncryptedData =
1990 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1991 }
1992
1993 if (numBytesOfEncryptedData != nullptr) {
1994 env->ReleaseIntArrayElements(
1995 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1996 numBytesOfEncryptedData = nullptr;
1997 }
1998
1999 if (numBytesOfClearData != nullptr) {
2000 env->ReleaseIntArrayElements(
2001 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
2002 numBytesOfClearData = nullptr;
2003 }
2004 }
2005
2006 if (mErr == OK && mKeyObj.get() != nullptr) {
2007 if (env->GetArrayLength(mKeyObj.get()) != 16) {
2008 mErr = -EINVAL;
2009 } else {
2010 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
2011 }
2012 }
2013
2014 if (mErr == OK && mIvObj.get() != nullptr) {
2015 if (env->GetArrayLength(mIvObj.get()) != 16) {
2016 mErr = -EINVAL;
2017 } else {
2018 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
2019 }
2020 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002021
2022 }
2023
2024 explicit NativeCryptoInfo(jint size)
2025 : mIvObj{nullptr, nullptr},
2026 mKeyObj{nullptr, nullptr},
2027 mMode{CryptoPlugin::kMode_Unencrypted},
2028 mPattern{0, 0} {
2029 mSubSamples = new CryptoPlugin::SubSample[1];
2030 mNumSubSamples = 1;
2031 mSubSamples[0].mNumBytesOfClearData = size;
2032 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002033 }
2034
2035 ~NativeCryptoInfo() {
2036 if (mIv != nullptr) {
2037 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
2038 }
2039
2040 if (mKey != nullptr) {
2041 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
2042 }
2043
2044 if (mSubSamples != nullptr) {
2045 delete[] mSubSamples;
2046 }
2047 }
2048
2049 JNIEnv *mEnv{nullptr};
2050 ScopedLocalRef<jbyteArray> mIvObj;
2051 ScopedLocalRef<jbyteArray> mKeyObj;
2052 status_t mErr{OK};
2053
2054 CryptoPlugin::SubSample *mSubSamples{nullptr};
2055 int32_t mNumSubSamples{0};
2056 jbyte *mIv{nullptr};
2057 jbyte *mKey{nullptr};
2058 enum CryptoPlugin::Mode mMode;
2059 CryptoPlugin::Pattern mPattern;
2060};
2061
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002062static void android_media_MediaCodec_queueSecureInputBuffer(
2063 JNIEnv *env,
2064 jobject thiz,
2065 jint index,
2066 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002067 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002068 jlong timestampUs,
2069 jint flags) {
2070 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2071
2072 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2073
Wonsik Kim24e53802020-05-08 20:04:26 -07002074 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002075 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002076 return;
2077 }
2078
Wonsik Kim1cac4252020-01-24 11:45:37 -08002079 jint numSubSamples =
2080 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2081
2082 jintArray numBytesOfClearDataObj =
2083 (jintArray)env->GetObjectField(
2084 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2085
2086 jintArray numBytesOfEncryptedDataObj =
2087 (jintArray)env->GetObjectField(
2088 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2089
2090 jbyteArray keyObj =
2091 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2092
2093 jbyteArray ivObj =
2094 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2095
2096 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2097 enum CryptoPlugin::Mode mode;
2098 if (jmode == gCryptoModes.Unencrypted) {
2099 mode = CryptoPlugin::kMode_Unencrypted;
2100 } else if (jmode == gCryptoModes.AesCtr) {
2101 mode = CryptoPlugin::kMode_AES_CTR;
2102 } else if (jmode == gCryptoModes.AesCbc) {
2103 mode = CryptoPlugin::kMode_AES_CBC;
2104 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002105 throwExceptionAsNecessary(
2106 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2107 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08002108 return;
2109 }
2110
2111 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2112
2113 CryptoPlugin::Pattern pattern;
2114 if (patternObj == NULL) {
2115 pattern.mEncryptBlocks = 0;
2116 pattern.mSkipBlocks = 0;
2117 } else {
2118 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2119 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2120 }
2121
2122 status_t err = OK;
2123
2124 CryptoPlugin::SubSample *subSamples = NULL;
2125 jbyte *key = NULL;
2126 jbyte *iv = NULL;
2127
2128 if (numSubSamples <= 0) {
2129 err = -EINVAL;
2130 } else if (numBytesOfClearDataObj == NULL
2131 && numBytesOfEncryptedDataObj == NULL) {
2132 err = -EINVAL;
2133 } else if (numBytesOfEncryptedDataObj != NULL
2134 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2135 err = -ERANGE;
2136 } else if (numBytesOfClearDataObj != NULL
2137 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2138 err = -ERANGE;
2139 // subSamples array may silently overflow if number of samples are too large. Use
2140 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2141 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2142 err = -EINVAL;
2143 } else {
2144 jboolean isCopy;
2145
2146 jint *numBytesOfClearData =
2147 (numBytesOfClearDataObj == NULL)
2148 ? NULL
2149 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2150
2151 jint *numBytesOfEncryptedData =
2152 (numBytesOfEncryptedDataObj == NULL)
2153 ? NULL
2154 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2155
2156 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2157
2158 for (jint i = 0; i < numSubSamples; ++i) {
2159 subSamples[i].mNumBytesOfClearData =
2160 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2161
2162 subSamples[i].mNumBytesOfEncryptedData =
2163 (numBytesOfEncryptedData == NULL)
2164 ? 0 : numBytesOfEncryptedData[i];
2165 }
2166
2167 if (numBytesOfEncryptedData != NULL) {
2168 env->ReleaseIntArrayElements(
2169 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2170 numBytesOfEncryptedData = NULL;
2171 }
2172
2173 if (numBytesOfClearData != NULL) {
2174 env->ReleaseIntArrayElements(
2175 numBytesOfClearDataObj, numBytesOfClearData, 0);
2176 numBytesOfClearData = NULL;
2177 }
2178 }
2179
2180 if (err == OK && keyObj != NULL) {
2181 if (env->GetArrayLength(keyObj) != 16) {
2182 err = -EINVAL;
2183 } else {
2184 jboolean isCopy;
2185 key = env->GetByteArrayElements(keyObj, &isCopy);
2186 }
2187 }
2188
2189 if (err == OK && ivObj != NULL) {
2190 if (env->GetArrayLength(ivObj) != 16) {
2191 err = -EINVAL;
2192 } else {
2193 jboolean isCopy;
2194 iv = env->GetByteArrayElements(ivObj, &isCopy);
2195 }
2196 }
2197
Andreas Huberbfc56f42012-04-19 12:47:07 -07002198 AString errorDetailMsg;
2199
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002200 if (err == OK) {
2201 err = codec->queueSecureInputBuffer(
2202 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002203 subSamples, numSubSamples,
2204 (const uint8_t *)key, (const uint8_t *)iv,
2205 mode,
2206 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002207 timestampUs,
2208 flags,
2209 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002210 }
2211
Wonsik Kim1cac4252020-01-24 11:45:37 -08002212 if (iv != NULL) {
2213 env->ReleaseByteArrayElements(ivObj, iv, 0);
2214 iv = NULL;
2215 }
2216
2217 if (key != NULL) {
2218 env->ReleaseByteArrayElements(keyObj, key, 0);
2219 key = NULL;
2220 }
2221
2222 delete[] subSamples;
2223 subSamples = NULL;
2224
Andreas Huberbfc56f42012-04-19 12:47:07 -07002225 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002226 env, err, ACTION_CODE_FATAL,
2227 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002228}
2229
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002230static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002231 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2232 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2233 env, bufferObj);
2234 AHardwareBuffer_Desc desc;
2235 AHardwareBuffer_describe(hardwareBuffer, &desc);
2236 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2237 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2238 return nullptr;
2239 }
2240 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2241 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2242 return nullptr;
2243 }
2244 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2245
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002246 uint64_t cpuUsage = 0;
2247 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2248 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002249
2250 AHardwareBuffer_Planes planes;
2251 int err = AHardwareBuffer_lockPlanes(
2252 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2253 if (err != 0) {
2254 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2255 return nullptr;
2256 }
2257
2258 if (planes.planeCount != 3) {
2259 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2260 return nullptr;
2261 }
2262
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002263 ScopedLocalRef<jobjectArray> buffersArray{
2264 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2265 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2266 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002267
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002268 jboolean isCopy = JNI_FALSE;
2269 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2270 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2271
2272 // For Y plane
2273 int rowSampling = 1;
2274 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002275 // plane indices are Y-U-V.
2276 for (uint32_t i = 0; i < 3; ++i) {
2277 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002278 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2279 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2280 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002281 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2282 env,
2283 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002284 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002285 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002286 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002287 readOnly,
2288 true)};
2289
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002290 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2291 rowStrides[i] = plane.rowStride;
2292 pixelStrides[i] = plane.pixelStride;
2293 // For U-V planes
2294 rowSampling = 2;
2295 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002296 }
2297
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002298 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2299 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2300 rowStrides = pixelStrides = nullptr;
2301
Wonsik Kim637afb22020-02-25 14:27:29 -08002302 ScopedLocalRef<jclass> imageClazz(
2303 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2304 CHECK(imageClazz.get() != NULL);
2305
2306 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002307 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002308
2309 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002310 buffersArray.get(),
2311 rowStridesArray.get(),
2312 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002313 desc.width,
2314 desc.height,
2315 desc.format, // ???
2316 (jboolean)readOnly /* readOnly */,
2317 (jlong)0 /* timestamp */,
2318 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2319 (jlong)hardwareBuffer);
2320
2321 // if MediaImage creation fails, return null
2322 if (env->ExceptionCheck()) {
2323 env->ExceptionDescribe();
2324 env->ExceptionClear();
2325 return nullptr;
2326 }
2327
2328 AHardwareBuffer_acquire(hardwareBuffer);
2329
2330 return img;
2331}
2332
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002333static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2334 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002335 if (context == 0) {
2336 return;
2337 }
2338 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2339
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002340 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2341 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002342 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2343 // Continue to release the hardwareBuffer
2344 }
2345
2346 AHardwareBuffer_release(hardwareBuffer);
2347}
2348
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002349static status_t ConvertKeyValueListsToAMessage(
2350 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2351 static struct Fields {
2352 explicit Fields(JNIEnv *env) {
2353 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2354 CHECK(clazz.get() != NULL);
2355 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2356
2357 clazz.reset(env->FindClass("java/lang/Integer"));
2358 CHECK(clazz.get() != NULL);
2359 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2360
2361 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2362 CHECK(mIntegerValueId != NULL);
2363
2364 clazz.reset(env->FindClass("java/lang/Long"));
2365 CHECK(clazz.get() != NULL);
2366 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2367
2368 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2369 CHECK(mLongValueId != NULL);
2370
2371 clazz.reset(env->FindClass("java/lang/Float"));
2372 CHECK(clazz.get() != NULL);
2373 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2374
2375 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2376 CHECK(mFloatValueId != NULL);
2377
2378 clazz.reset(env->FindClass("java/util/ArrayList"));
2379 CHECK(clazz.get() != NULL);
2380
2381 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2382 CHECK(mByteBufferArrayId != NULL);
2383 }
2384
2385 jclass mStringClass;
2386 jclass mIntegerClass;
2387 jmethodID mIntegerValueId;
2388 jclass mLongClass;
2389 jmethodID mLongValueId;
2390 jclass mFloatClass;
2391 jmethodID mFloatValueId;
2392 jmethodID mByteBufferArrayId;
2393 } sFields{env};
2394
2395 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2396 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2397 return BAD_VALUE;
2398 }
2399
2400 sp<AMessage> result{new AMessage};
2401 for (jint i = 0; i < size; ++i) {
2402 ScopedLocalRef<jstring> jkey{
2403 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2404 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2405 AString key;
2406 if (tmp) {
2407 key.setTo(tmp);
2408 }
2409 env->ReleaseStringUTFChars(jkey.get(), tmp);
2410 if (key.empty()) {
2411 return NO_MEMORY;
2412 }
2413
2414 ScopedLocalRef<jobject> jvalue{
2415 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2416
2417 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2418 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2419 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002420 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002421 return NO_MEMORY;
2422 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002423 value.setTo(tmp);
2424 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002425 result->setString(key.c_str(), value);
2426 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2427 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2428 result->setInt32(key.c_str(), value);
2429 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2430 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2431 result->setInt64(key.c_str(), value);
2432 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2433 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2434 result->setFloat(key.c_str(), value);
2435 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002436 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2437 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002438 sp<ABuffer> buffer{new ABuffer(limit - position)};
2439 void *data = env->GetDirectBufferAddress(jvalue.get());
2440 if (data != nullptr) {
2441 memcpy(buffer->data(),
2442 static_cast<const uint8_t *>(data) + position,
2443 buffer->size());
2444 } else {
2445 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2446 jvalue.get(), sFields.mByteBufferArrayId)};
2447 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2448 reinterpret_cast<jbyte *>(buffer->data()));
2449 }
2450 result->setBuffer(key.c_str(), buffer);
2451 }
2452 }
2453
2454 *msg = result;
2455 return OK;
2456}
2457
Wonsik Kim8569a662022-05-24 14:16:44 -07002458static bool obtain(
2459 JMediaCodecLinearBlock *context,
2460 int capacity,
2461 const std::vector<std::string> &names,
2462 bool secure) {
2463 if (secure) {
2464 // Start at 1MB, which is an arbitrary starting point that can
2465 // increase when needed.
2466 constexpr size_t kInitialDealerCapacity = 1048576;
2467 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2468 kInitialDealerCapacity, "JNI(1MB)");
2469 context->mMemory = sDealer->allocate(capacity);
2470 if (context->mMemory == nullptr) {
2471 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2472 while (capacity * 2 > newDealerCapacity) {
2473 newDealerCapacity *= 2;
2474 }
2475 ALOGI("LinearBlock.native_obtain: "
2476 "Dealer capacity increasing from %zuMB to %zuMB",
2477 sDealer->getMemoryHeap()->getSize() / 1048576,
2478 newDealerCapacity / 1048576);
2479 sDealer = new MemoryDealer(
2480 newDealerCapacity,
2481 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2482 context->mMemory = sDealer->allocate(capacity);
2483 }
2484 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2485 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2486 } else {
2487 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2488 if (!context->mBlock) {
2489 return false;
2490 }
2491 }
2492 context->mCodecNames = names;
2493 return true;
2494}
2495
2496static void extractMemoryFromContext(
2497 JMediaCodecLinearBlock *context,
2498 jint offset,
2499 jint size,
2500 sp<hardware::HidlMemory> *memory) {
2501 *memory = context->toHidlMemory();
2502 if (*memory == nullptr) {
2503 if (!context->mBlock) {
2504 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2505 return;
2506 }
2507 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2508 context->capacity());
2509 if (!obtain(context, context->capacity(),
2510 context->mCodecNames, true /* secure */)) {
2511 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2512 return;
2513 }
2514 C2WriteView view = context->mBlock->map().get();
2515 if (view.error() != C2_OK) {
2516 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2517 return;
2518 }
2519 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2520 memcpy(memoryPtr + offset, view.base() + offset, size);
2521 context->mBlock.reset();
2522 context->mReadWriteMapping.reset();
2523 *memory = context->toHidlMemory();
2524 }
2525}
2526
2527static void extractBufferFromContext(
2528 JMediaCodecLinearBlock *context,
2529 jint offset,
2530 jint size,
2531 std::shared_ptr<C2Buffer> *buffer) {
2532 *buffer = context->toC2Buffer(offset, size);
2533 if (*buffer == nullptr) {
2534 if (!context->mMemory) {
2535 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2536 return;
2537 }
2538 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2539 context->capacity());
2540 if (obtain(context, context->capacity(),
2541 context->mCodecNames, false /* secure */)) {
2542 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2543 return;
2544 }
2545 C2WriteView view = context->mBlock->map().get();
2546 if (view.error() != C2_OK) {
2547 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2548 return;
2549 }
2550 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2551 memcpy(view.base() + offset, memoryPtr + offset, size);
2552 context->mMemory.clear();
2553 context->mHidlMemory.clear();
2554 context->mHidlMemorySize = 0;
2555 context->mHidlMemoryOffset = 0;
2556 *buffer = context->toC2Buffer(offset, size);
2557 }
2558}
2559
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002560static void android_media_MediaCodec_native_queueLinearBlock(
2561 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2562 jint offset, jint size, jobject cryptoInfoObj,
2563 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2564 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2565
2566 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2567
Wonsik Kim24e53802020-05-08 20:04:26 -07002568 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002569 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002570 return;
2571 }
2572
2573 sp<AMessage> tunings;
2574 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2575 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002576 throwExceptionAsNecessary(
2577 env, err, ACTION_CODE_FATAL,
2578 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002579 return;
2580 }
2581
2582 std::shared_ptr<C2Buffer> buffer;
2583 sp<hardware::HidlMemory> memory;
2584 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2585 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2586 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2587 JMediaCodecLinearBlock *context =
2588 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002589 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kim8569a662022-05-24 14:16:44 -07002590 extractMemoryFromContext(context, offset, size, &memory);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002591 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002592 } else {
Wonsik Kim8569a662022-05-24 14:16:44 -07002593 extractBufferFromContext(context, offset, size, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002594 }
2595 }
2596 env->MonitorExit(lock.get());
2597 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002598 throwExceptionAsNecessary(
2599 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2600 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002601 return;
2602 }
2603
2604 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002605 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002606 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002607 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002608 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002609 throwExceptionAsNecessary(
2610 env, BAD_VALUE, ACTION_CODE_FATAL,
2611 "Unexpected error: the input buffer is not compatible with "
2612 "the secure codec, and a fallback logic failed.\n"
2613 "Suggestion: please try including the secure codec when calling "
2614 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002615 return;
2616 }
George Burgess IV436998b2022-11-02 11:42:33 -06002617 auto cryptoInfo =
Robert Shihfe3785c2023-07-11 07:27:02 +00002618 cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{size};
George Burgess IV436998b2022-11-02 11:42:33 -06002619 if (env->ExceptionCheck()) {
2620 // Creation of cryptoInfo failed. Let the exception bubble up.
2621 return;
2622 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002623 err = codec->queueEncryptedLinearBlock(
2624 index,
2625 memory,
2626 offset,
2627 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2628 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2629 cryptoInfo.mMode,
2630 cryptoInfo.mPattern,
2631 presentationTimeUs,
2632 flags,
2633 tunings,
2634 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002635 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002636 } else {
2637 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002638 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002639 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002640 throwExceptionAsNecessary(
2641 env, BAD_VALUE, ACTION_CODE_FATAL,
2642 "Unexpected error: the input buffer is not compatible with "
2643 "the non-secure codec, and a fallback logic failed.\n"
2644 "Suggestion: please do not include the secure codec when calling "
2645 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002646 return;
2647 }
2648 err = codec->queueBuffer(
2649 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2650 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002651 throwExceptionAsNecessary(
2652 env, err, ACTION_CODE_FATAL,
2653 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002654}
2655
Wonsik Kim637afb22020-02-25 14:27:29 -08002656static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002657 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2658 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002659 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002660
2661 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2662
Wonsik Kim24e53802020-05-08 20:04:26 -07002663 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002664 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002665 return;
2666 }
2667
2668 sp<AMessage> tunings;
2669 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2670 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002671 throwExceptionAsNecessary(
2672 env, err, ACTION_CODE_FATAL,
2673 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002674 return;
2675 }
2676
Wonsik Kim637afb22020-02-25 14:27:29 -08002677 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2678 env, bufferObj);
2679 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2680 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002681 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2682 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2683 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2684 std::shared_ptr<C2Allocator> alloc;
2685 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2686 C2PlatformAllocatorStore::GRALLOC, &alloc);
2687 if (err == C2_OK) {
2688 return alloc;
2689 }
2690 return nullptr;
2691 }();
2692 std::shared_ptr<C2GraphicAllocation> alloc;
2693 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2694 if (c2err != C2_OK) {
2695 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002696 native_handle_close(handle);
2697 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002698 throwExceptionAsNecessary(
2699 env, BAD_VALUE, ACTION_CODE_FATAL,
2700 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002701 return;
2702 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002703 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002704 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2705 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002706 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002707 err = codec->queueBuffer(
2708 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002709 throwExceptionAsNecessary(
2710 env, err, ACTION_CODE_FATAL,
2711 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002712}
2713
2714static void android_media_MediaCodec_native_getOutputFrame(
2715 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2716 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2717
2718 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2719
Wonsik Kim24e53802020-05-08 20:04:26 -07002720 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002721 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002722 return;
2723 }
2724
2725 status_t err = codec->getOutputFrame(env, frame, index);
2726 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002727 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002728 }
2729}
2730
Andreas Huber88572f72012-02-21 11:47:18 -08002731static jint android_media_MediaCodec_dequeueInputBuffer(
2732 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2733 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2734
2735 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2736
Wonsik Kim24e53802020-05-08 20:04:26 -07002737 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002738 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002739 return -1;
2740 }
2741
2742 size_t index;
2743 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2744
2745 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002746 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002747 }
2748
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002749 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002750}
2751
2752static jint android_media_MediaCodec_dequeueOutputBuffer(
2753 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2754 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2755
2756 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2757
Wonsik Kim24e53802020-05-08 20:04:26 -07002758 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002759 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002760 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002761 }
2762
2763 size_t index;
2764 status_t err = codec->dequeueOutputBuffer(
2765 env, bufferInfo, &index, timeoutUs);
2766
2767 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002768 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002769 }
2770
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002771 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002772}
2773
2774static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002775 JNIEnv *env, jobject thiz,
2776 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002777 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2778
2779 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2780
Wonsik Kim24e53802020-05-08 20:04:26 -07002781 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002782 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002783 return;
2784 }
2785
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002786 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002787
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002788 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002789}
2790
Andy McFadden2621e402013-02-19 07:29:21 -08002791static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2792 jobject thiz) {
2793 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2794
2795 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002796 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002797 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002798 return;
2799 }
2800
2801 status_t err = codec->signalEndOfInputStream();
2802
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002803 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002804}
2805
Lajos Molnard4023112014-07-11 15:12:59 -07002806static jobject android_media_MediaCodec_getFormatNative(
2807 JNIEnv *env, jobject thiz, jboolean input) {
2808 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002809
2810 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2811
Wonsik Kim24e53802020-05-08 20:04:26 -07002812 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002813 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002814 return NULL;
2815 }
2816
2817 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002818 status_t err = codec->getFormat(env, input, &format);
2819
2820 if (err == OK) {
2821 return format;
2822 }
2823
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002824 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002825
2826 return NULL;
2827}
2828
2829static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2830 JNIEnv *env, jobject thiz, jint index) {
2831 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2832
2833 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2834
Wonsik Kim24e53802020-05-08 20:04:26 -07002835 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002836 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002837 return NULL;
2838 }
2839
2840 jobject format;
2841 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002842
2843 if (err == OK) {
2844 return format;
2845 }
2846
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002847 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002848
2849 return NULL;
2850}
2851
2852static jobjectArray android_media_MediaCodec_getBuffers(
2853 JNIEnv *env, jobject thiz, jboolean input) {
2854 ALOGV("android_media_MediaCodec_getBuffers");
2855
2856 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2857
Wonsik Kim24e53802020-05-08 20:04:26 -07002858 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002859 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002860 return NULL;
2861 }
2862
2863 jobjectArray buffers;
2864 status_t err = codec->getBuffers(env, input, &buffers);
2865
2866 if (err == OK) {
2867 return buffers;
2868 }
2869
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002870 // if we're out of memory, an exception was already thrown
2871 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002872 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002873 }
Andreas Huber88572f72012-02-21 11:47:18 -08002874
2875 return NULL;
2876}
2877
Lajos Molnard4023112014-07-11 15:12:59 -07002878static jobject android_media_MediaCodec_getBuffer(
2879 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2880 ALOGV("android_media_MediaCodec_getBuffer");
2881
2882 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2883
Wonsik Kim24e53802020-05-08 20:04:26 -07002884 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002885 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002886 return NULL;
2887 }
2888
2889 jobject buffer;
2890 status_t err = codec->getBuffer(env, input, index, &buffer);
2891
2892 if (err == OK) {
2893 return buffer;
2894 }
2895
2896 // if we're out of memory, an exception was already thrown
2897 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002898 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002899 }
2900
2901 return NULL;
2902}
2903
2904static jobject android_media_MediaCodec_getImage(
2905 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2906 ALOGV("android_media_MediaCodec_getImage");
2907
2908 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2909
Wonsik Kim24e53802020-05-08 20:04:26 -07002910 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002911 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002912 return NULL;
2913 }
2914
2915 jobject image;
2916 status_t err = codec->getImage(env, input, index, &image);
2917
2918 if (err == OK) {
2919 return image;
2920 }
2921
2922 // if we're out of memory, an exception was already thrown
2923 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002924 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002925 }
2926
2927 return NULL;
2928}
2929
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002930static jobject android_media_MediaCodec_getName(
2931 JNIEnv *env, jobject thiz) {
2932 ALOGV("android_media_MediaCodec_getName");
2933
2934 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2935
Wonsik Kim24e53802020-05-08 20:04:26 -07002936 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002937 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002938 return NULL;
2939 }
2940
2941 jstring name;
2942 status_t err = codec->getName(env, &name);
2943
2944 if (err == OK) {
2945 return name;
2946 }
2947
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002948 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002949
2950 return NULL;
2951}
2952
Chong Zhanga0b72a62018-02-28 18:46:26 -08002953static jobject android_media_MediaCodec_getOwnCodecInfo(
2954 JNIEnv *env, jobject thiz) {
2955 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2956
2957 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2958
Wonsik Kim24e53802020-05-08 20:04:26 -07002959 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002960 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08002961 return NULL;
2962 }
2963
2964 jobject codecInfoObj;
2965 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2966
2967 if (err == OK) {
2968 return codecInfoObj;
2969 }
2970
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002971 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08002972
2973 return NULL;
2974}
2975
Ray Essick0e0fee12017-01-25 18:01:56 -08002976static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002977android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002978{
Ray Essickf2d0e402017-03-09 10:17:51 -08002979 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002980
2981 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002982 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002983 jniThrowException(env, "java/lang/IllegalStateException",
2984 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08002985 return 0;
2986 }
2987
2988 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002989 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002990
2991 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002992 if (err != OK) {
2993 ALOGE("getMetrics failed");
2994 return (jobject) NULL;
2995 }
2996
Ray Essick0e0fee12017-01-25 18:01:56 -08002997 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2998
2999 // housekeeping
3000 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07003001 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08003002
3003 return mybundle;
3004}
3005
Andreas Huber226065b2013-08-12 10:14:11 -07003006static void android_media_MediaCodec_setParameters(
3007 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
3008 ALOGV("android_media_MediaCodec_setParameters");
3009
3010 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3011
Wonsik Kim24e53802020-05-08 20:04:26 -07003012 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003013 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003014 return;
3015 }
3016
3017 sp<AMessage> params;
3018 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
3019
3020 if (err == OK) {
3021 err = codec->setParameters(params);
3022 }
3023
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003024 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07003025}
3026
Andreas Huberb12a5392012-04-30 14:18:33 -07003027static void android_media_MediaCodec_setVideoScalingMode(
3028 JNIEnv *env, jobject thiz, jint mode) {
3029 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3030
Wonsik Kim24e53802020-05-08 20:04:26 -07003031 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003032 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huberb12a5392012-04-30 14:18:33 -07003033 return;
3034 }
3035
3036 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
3037 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003038 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003039 String8::format("Unrecognized mode: %d", mode).c_str());
Andreas Huberb12a5392012-04-30 14:18:33 -07003040 return;
3041 }
3042
3043 codec->setVideoScalingMode(mode);
3044}
3045
ybai5e053202018-11-01 13:02:15 +08003046static void android_media_MediaCodec_setAudioPresentation(
3047 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
3048 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3049
Wonsik Kim24e53802020-05-08 20:04:26 -07003050 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003051 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08003052 return;
3053 }
3054
3055 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
3056}
3057
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003058static jobject android_media_MediaCodec_getSupportedVendorParameters(
3059 JNIEnv *env, jobject thiz) {
3060 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3061
3062 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003063 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003064 return NULL;
3065 }
3066
3067 jobject ret = NULL;
3068 status_t status = codec->querySupportedVendorParameters(env, &ret);
3069 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003070 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003071 }
3072
3073 return ret;
3074}
3075
3076static jobject android_media_MediaCodec_getParameterDescriptor(
3077 JNIEnv *env, jobject thiz, jstring name) {
3078 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3079
3080 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003081 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003082 return NULL;
3083 }
3084
3085 jobject ret = NULL;
3086 status_t status = codec->describeParameter(env, name, &ret);
3087 if (status != OK) {
3088 ret = NULL;
3089 }
3090 return ret;
3091}
3092
3093static void android_media_MediaCodec_subscribeToVendorParameters(
3094 JNIEnv *env, jobject thiz, jobject names) {
3095 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3096
3097 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003098 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003099 return;
3100 }
3101
3102 status_t status = codec->subscribeToVendorParameters(env, names);
3103 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003104 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003105 }
3106 return;
3107}
3108
3109static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3110 JNIEnv *env, jobject thiz, jobject names) {
3111 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3112
3113 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003114 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003115 return;
3116 }
3117
3118 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3119 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003120 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003121 }
3122 return;
3123}
3124
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003125static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003126 ScopedLocalRef<jclass> clazz(
3127 env, env->FindClass("android/media/MediaCodec"));
3128 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003129
Andreas Huberaba67132013-10-22 12:40:01 -07003130 gFields.postEventFromNativeID =
3131 env->GetMethodID(
3132 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003133 CHECK(gFields.postEventFromNativeID != NULL);
3134
Wonsik Kim61796fd2018-09-13 13:15:59 -07003135 gFields.lockAndGetContextID =
3136 env->GetMethodID(
3137 clazz.get(), "lockAndGetContext", "()J");
3138 CHECK(gFields.lockAndGetContextID != NULL);
3139
3140 gFields.setAndUnlockContextID =
3141 env->GetMethodID(
3142 clazz.get(), "setAndUnlockContext", "(J)V");
3143 CHECK(gFields.setAndUnlockContextID != NULL);
3144
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003145 jfieldID field;
3146 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3147 CHECK(field != NULL);
3148 gCryptoModes.Unencrypted =
3149 env->GetStaticIntField(clazz.get(), field);
3150
3151 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3152 CHECK(field != NULL);
3153 gCryptoModes.AesCtr =
3154 env->GetStaticIntField(clazz.get(), field);
3155
3156 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3157 CHECK(field != NULL);
3158 gCryptoModes.AesCbc =
3159 env->GetStaticIntField(clazz.get(), field);
3160
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003161 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3162 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003163
Arun Johnson5a4c7332022-12-17 00:47:06 +00003164 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3165 CHECK(gFields.cryptoInfoSetID != NULL);
3166
3167 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3168 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3169
Andreas Huber91befdc2012-04-18 12:19:51 -07003170 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003171 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003172 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3173
3174 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003175 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003176 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3177
3178 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003179 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003180 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3181
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003182 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003183 CHECK(gFields.cryptoInfoKeyID != NULL);
3184
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003185 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003186 CHECK(gFields.cryptoInfoIVID != NULL);
3187
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003188 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003189 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003190
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003191 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003192 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3193 CHECK(gFields.cryptoInfoPatternID != NULL);
3194
3195 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3196 CHECK(clazz.get() != NULL);
3197
3198 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3199 CHECK(gFields.patternEncryptBlocksID != NULL);
3200
3201 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3202 CHECK(gFields.patternSkipBlocksID != NULL);
3203
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003204 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3205 CHECK(clazz.get() != NULL);
3206
3207 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3208 CHECK(gFields.queueRequestIndexID != NULL);
3209
3210 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3211 CHECK(clazz.get() != NULL);
3212
3213 gFields.outputFrameLinearBlockID =
3214 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3215 CHECK(gFields.outputFrameLinearBlockID != NULL);
3216
Wonsik Kim637afb22020-02-25 14:27:29 -08003217 gFields.outputFrameHardwareBufferID =
3218 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3219 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003220
3221 gFields.outputFrameChangedKeysID =
3222 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3223 CHECK(gFields.outputFrameChangedKeysID != NULL);
3224
3225 gFields.outputFrameFormatID =
3226 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3227 CHECK(gFields.outputFrameFormatID != NULL);
3228
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003229 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3230 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003231
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003232 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003233 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003234 gCryptoErrorCodes.cryptoErrorNoKey =
3235 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003236
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003237 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003238 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003239 gCryptoErrorCodes.cryptoErrorKeyExpired =
3240 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003241
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003242 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003243 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003244 gCryptoErrorCodes.cryptoErrorResourceBusy =
3245 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003246
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003247 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3248 CHECK(field != NULL);
3249 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3250 env->GetStaticIntField(clazz.get(), field);
3251
Jeff Tinker96a2a952015-07-01 17:35:18 -07003252 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3253 CHECK(field != NULL);
3254 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3255 env->GetStaticIntField(clazz.get(), field);
3256
Jeff Tinker20594d82018-12-12 08:31:22 -08003257 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3258 CHECK(field != NULL);
3259 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3260 env->GetStaticIntField(clazz.get(), field);
3261
Jeff Tinkerd3932162016-03-05 11:35:20 -08003262 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3263 CHECK(field != NULL);
3264 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3265 env->GetStaticIntField(clazz.get(), field);
3266
Jeff Tinker20594d82018-12-12 08:31:22 -08003267 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3268 CHECK(field != NULL);
3269 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3270 env->GetStaticIntField(clazz.get(), field);
3271
3272 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3273 CHECK(field != NULL);
3274 gCryptoErrorCodes.cryptoErrorLostState =
3275 env->GetStaticIntField(clazz.get(), field);
3276
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003277 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3278 CHECK(clazz.get() != NULL);
3279 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3280 CHECK(field != NULL);
3281 gCodecActionCodes.codecActionTransient =
3282 env->GetStaticIntField(clazz.get(), field);
3283
3284 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3285 CHECK(field != NULL);
3286 gCodecActionCodes.codecActionRecoverable =
3287 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003288
Ronghua Wuc53ad692015-05-08 14:40:49 -07003289 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003290 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003291 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003292 env->GetStaticIntField(clazz.get(), field);
3293
Ronghua Wuc53ad692015-05-08 14:40:49 -07003294 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003295 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003296 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003297 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003298
3299 clazz.reset(env->FindClass("android/view/Surface"));
3300 CHECK(clazz.get() != NULL);
3301
3302 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3303 CHECK(field != NULL);
3304 gPersistentSurfaceClassInfo.mLock = field;
3305
3306 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3307 CHECK(method != NULL);
3308 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3309
3310 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3311 CHECK(clazz.get() != NULL);
3312 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3313
3314 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3315 CHECK(method != NULL);
3316 gPersistentSurfaceClassInfo.ctor = method;
3317
3318 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3319 CHECK(field != NULL);
3320 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003321
3322 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3323 CHECK(clazz.get() != NULL);
3324 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3325
3326 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003327 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003328 "Ljava/util/Map;Ljava/util/Map;)V");
3329 CHECK(method != NULL);
3330 gCodecInfo.capsCtorId = method;
3331
3332 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3333 CHECK(clazz.get() != NULL);
3334 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3335
3336 field = env->GetFieldID(clazz.get(), "profile", "I");
3337 CHECK(field != NULL);
3338 gCodecInfo.profileField = field;
3339
3340 field = env->GetFieldID(clazz.get(), "level", "I");
3341 CHECK(field != NULL);
3342 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003343
3344 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3345 CHECK(clazz.get() != NULL);
3346 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3347
3348 ScopedLocalRef<jclass> byteOrderClass(
3349 env, env->FindClass("java/nio/ByteOrder"));
3350 CHECK(byteOrderClass.get() != NULL);
3351
3352 jmethodID nativeOrderID = env->GetStaticMethodID(
3353 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3354 CHECK(nativeOrderID != NULL);
3355
3356 ScopedLocalRef<jobject> nativeByteOrderObj{
3357 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3358 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3359 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3360 nativeByteOrderObj.reset();
3361
3362 gByteBufferInfo.orderId = env->GetMethodID(
3363 clazz.get(),
3364 "order",
3365 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3366 CHECK(gByteBufferInfo.orderId != NULL);
3367
3368 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3369 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3370 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3371
3372 gByteBufferInfo.positionId = env->GetMethodID(
3373 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3374 CHECK(gByteBufferInfo.positionId != NULL);
3375
3376 gByteBufferInfo.limitId = env->GetMethodID(
3377 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3378 CHECK(gByteBufferInfo.limitId != NULL);
3379
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003380 gByteBufferInfo.getPositionId = env->GetMethodID(
3381 clazz.get(), "position", "()I");
3382 CHECK(gByteBufferInfo.getPositionId != NULL);
3383
3384 gByteBufferInfo.getLimitId = env->GetMethodID(
3385 clazz.get(), "limit", "()I");
3386 CHECK(gByteBufferInfo.getLimitId != NULL);
3387
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003388 clazz.reset(env->FindClass("java/util/ArrayList"));
3389 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003390 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3391
3392 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3393 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003394
3395 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3396 CHECK(gArrayListInfo.sizeId != NULL);
3397
3398 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3399 CHECK(gArrayListInfo.getId != NULL);
3400
3401 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3402 CHECK(gArrayListInfo.addId != NULL);
3403
3404 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3405 CHECK(clazz.get() != NULL);
3406
3407 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3408
3409 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3410 CHECK(gLinearBlockInfo.ctorId != NULL);
3411
3412 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3413 clazz.get(), "setInternalStateLocked", "(JZ)V");
3414 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3415
3416 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3417 CHECK(gLinearBlockInfo.contextId != NULL);
3418
3419 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3420 CHECK(gLinearBlockInfo.validId != NULL);
3421
3422 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3423 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003424
3425 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3426 CHECK(clazz.get() != NULL);
3427 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3428
3429 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3430 CHECK(gDescriptorInfo.ctorId != NULL);
3431
3432 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3433 CHECK(gDescriptorInfo.nameId != NULL);
3434
3435 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3436 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003437
3438 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3439 CHECK(clazz.get() != NULL);
3440 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3441
3442 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3443 CHECK(gBufferInfo.ctorId != NULL);
3444
3445 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3446 CHECK(gBufferInfo.setId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003447}
3448
3449static void android_media_MediaCodec_native_setup(
3450 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003451 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003452 if (name == NULL) {
Ray Essickbd5fdaa2023-08-10 21:04:18 -05003453 jniThrowException(env, "java/lang/NullPointerException",
3454 "No codec name specified");
Andreas Huber88572f72012-02-21 11:47:18 -08003455 return;
3456 }
3457
3458 const char *tmp = env->GetStringUTFChars(name, NULL);
3459
3460 if (tmp == NULL) {
3461 return;
3462 }
3463
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003464 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003465
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003466 const status_t err = codec->initCheck();
3467 if (err == NAME_NOT_FOUND) {
3468 // fail and do not try again.
3469 jniThrowException(env, "java/lang/IllegalArgumentException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003470 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003471 env->ReleaseStringUTFChars(name, tmp);
3472 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003473 }
3474 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003475 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003476 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err).c_str());
Ronghua Wuc53ad692015-05-08 14:40:49 -07003477 env->ReleaseStringUTFChars(name, tmp);
3478 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003479 }
3480 if (err == PERMISSION_DENIED) {
3481 jniThrowException(env, "java/lang/SecurityException",
3482 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003483 err).c_str());
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003484 env->ReleaseStringUTFChars(name, tmp);
3485 return;
3486 }
3487 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003488 // believed possible to try again
3489 jniThrowException(env, "java/io/IOException",
Tomasz Wasilczyk835dfe52023-08-17 16:27:22 +00003490 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003491 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003492 return;
3493 }
3494
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003495 env->ReleaseStringUTFChars(name, tmp);
3496
Andreas Huberaba67132013-10-22 12:40:01 -07003497 codec->registerSelf();
3498
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003499 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003500}
3501
3502static void android_media_MediaCodec_native_finalize(
3503 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003504 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003505}
3506
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003507// MediaCodec.LinearBlock
3508
3509static jobject android_media_MediaCodec_LinearBlock_native_map(
3510 JNIEnv *env, jobject thiz) {
3511 JMediaCodecLinearBlock *context =
3512 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3513 if (context->mBuffer) {
3514 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3515 if (!context->mReadonlyMapping) {
3516 const C2BufferData data = buffer->data();
3517 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003518 throwExceptionAsNecessary(
3519 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3520 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003521 return nullptr;
3522 }
3523 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003524 throwExceptionAsNecessary(
3525 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3526 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003527 return nullptr;
3528 }
3529 C2ConstLinearBlock block = data.linearBlocks().front();
3530 context->mReadonlyMapping =
3531 std::make_shared<C2ReadView>(block.map().get());
3532 }
3533 return CreateByteBuffer(
3534 env,
3535 context->mReadonlyMapping->data(), // base
3536 context->mReadonlyMapping->capacity(), // capacity
3537 0u, // offset
3538 context->mReadonlyMapping->capacity(), // size
3539 true, // readOnly
3540 true /* clearBuffer */);
3541 } else if (context->mBlock) {
3542 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3543 if (!context->mReadWriteMapping) {
3544 context->mReadWriteMapping =
3545 std::make_shared<C2WriteView>(block->map().get());
3546 }
3547 return CreateByteBuffer(
3548 env,
3549 context->mReadWriteMapping->base(),
3550 context->mReadWriteMapping->capacity(),
3551 context->mReadWriteMapping->offset(),
3552 context->mReadWriteMapping->size(),
3553 false, // readOnly
3554 true /* clearBuffer */);
3555 } else if (context->mLegacyBuffer) {
3556 return CreateByteBuffer(
3557 env,
3558 context->mLegacyBuffer->base(),
3559 context->mLegacyBuffer->capacity(),
3560 context->mLegacyBuffer->offset(),
3561 context->mLegacyBuffer->size(),
3562 true, // readOnly
3563 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003564 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003565 return CreateByteBuffer(
3566 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003567 context->mMemory->unsecurePointer(),
3568 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003569 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003570 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003571 false, // readOnly
3572 true /* clearBuffer */);
3573 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003574 throwExceptionAsNecessary(
3575 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3576 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003577 return nullptr;
3578}
3579
3580static void android_media_MediaCodec_LinearBlock_native_recycle(
3581 JNIEnv *env, jobject thiz) {
3582 JMediaCodecLinearBlock *context =
3583 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003584 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003585 delete context;
3586}
3587
3588static void PopulateNamesVector(
3589 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3590 jsize length = env->GetArrayLength(codecNames);
3591 for (jsize i = 0; i < length; ++i) {
3592 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3593 if (jstr == nullptr) {
3594 // null entries are ignored
3595 continue;
3596 }
3597 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3598 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003599 throwExceptionAsNecessary(
3600 env, BAD_VALUE, ACTION_CODE_FATAL,
3601 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003602 return;
3603 }
3604 names->emplace_back(cstr);
3605 env->ReleaseStringUTFChars(jstr, cstr);
3606 }
3607}
3608
3609static void android_media_MediaCodec_LinearBlock_native_obtain(
3610 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3611 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3612 std::vector<std::string> names;
3613 PopulateNamesVector(env, codecNames, &names);
3614 bool hasSecure = false;
3615 bool hasNonSecure = false;
3616 for (const std::string &name : names) {
3617 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3618 hasSecure = true;
3619 } else {
3620 hasNonSecure = true;
3621 }
3622 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003623 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3624 jniThrowException(env, "java/io/IOException", nullptr);
3625 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003626 }
3627 env->CallVoidMethod(
3628 thiz,
3629 gLinearBlockInfo.setInternalStateId,
3630 (jlong)context.release(),
3631 true /* isMappable */);
3632}
3633
3634static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003635 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003636 std::vector<std::string> names;
3637 PopulateNamesVector(env, codecNames, &names);
3638 bool isCompatible = false;
3639 bool hasSecure = false;
3640 bool hasNonSecure = false;
3641 for (const std::string &name : names) {
3642 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3643 hasSecure = true;
3644 } else {
3645 hasNonSecure = true;
3646 }
3647 }
3648 if (hasSecure && hasNonSecure) {
3649 return false;
3650 }
3651 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3652 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003653 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003654 throwExceptionAsNecessary(env, err);
3655 }
3656 return isCompatible;
3657}
3658
Daniel Micay76f6a862015-09-19 17:31:01 -04003659static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003660 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003661
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003662 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3663
Chong Zhang8034d602015-04-28 13:38:48 -07003664 { "native_releasePersistentInputSurface",
3665 "(Landroid/view/Surface;)V",
3666 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3667
3668 { "native_createPersistentInputSurface",
3669 "()Landroid/media/MediaCodec$PersistentSurface;",
3670 (void *)android_media_MediaCodec_createPersistentInputSurface },
3671
Chong Zhang9560ddb2015-05-13 10:25:29 -07003672 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3673 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003674
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003675 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3676 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3677
Lajos Molnard8578572015-06-05 20:17:33 -07003678 { "native_enableOnFrameRenderedListener", "(Z)V",
3679 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3680
Chong Zhang8d5e5562014-07-08 18:49:21 -07003681 { "native_setCallback",
3682 "(Landroid/media/MediaCodec$Callback;)V",
3683 (void *)android_media_MediaCodec_native_setCallback },
3684
Andreas Huber88572f72012-02-21 11:47:18 -08003685 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003686 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003687 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003688 (void *)android_media_MediaCodec_native_configure },
3689
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003690 { "native_setSurface",
3691 "(Landroid/view/Surface;)V",
3692 (void *)android_media_MediaCodec_native_setSurface },
3693
Andy McFadden2621e402013-02-19 07:29:21 -08003694 { "createInputSurface", "()Landroid/view/Surface;",
3695 (void *)android_media_MediaCodec_createInputSurface },
3696
Lajos Molnard4023112014-07-11 15:12:59 -07003697 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003698 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003699 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003700
Lajos Molnard4023112014-07-11 15:12:59 -07003701 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003702 (void *)android_media_MediaCodec_queueInputBuffer },
3703
Lajos Molnard4023112014-07-11 15:12:59 -07003704 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003705 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3706
Wonsik Kim637afb22020-02-25 14:27:29 -08003707 { "native_mapHardwareBuffer",
3708 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3709 (void *)android_media_MediaCodec_mapHardwareBuffer },
3710
3711 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3712
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003713 { "native_queueLinearBlock",
3714 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3715 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3716 (void *)android_media_MediaCodec_native_queueLinearBlock },
3717
Wonsik Kim637afb22020-02-25 14:27:29 -08003718 { "native_queueHardwareBuffer",
3719 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3720 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003721
3722 { "native_getOutputFrame",
3723 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3724 (void *)android_media_MediaCodec_native_getOutputFrame },
3725
Lajos Molnard4023112014-07-11 15:12:59 -07003726 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003727 (void *)android_media_MediaCodec_dequeueInputBuffer },
3728
Lajos Molnard4023112014-07-11 15:12:59 -07003729 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003730 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3731
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003732 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003733 (void *)android_media_MediaCodec_releaseOutputBuffer },
3734
Andy McFadden2621e402013-02-19 07:29:21 -08003735 { "signalEndOfInputStream", "()V",
3736 (void *)android_media_MediaCodec_signalEndOfInputStream },
3737
Lajos Molnard4023112014-07-11 15:12:59 -07003738 { "getFormatNative", "(Z)Ljava/util/Map;",
3739 (void *)android_media_MediaCodec_getFormatNative },
3740
3741 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3742 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003743
3744 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3745 (void *)android_media_MediaCodec_getBuffers },
3746
Lajos Molnard4023112014-07-11 15:12:59 -07003747 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3748 (void *)android_media_MediaCodec_getBuffer },
3749
3750 { "getImage", "(ZI)Landroid/media/Image;",
3751 (void *)android_media_MediaCodec_getImage },
3752
Lajos Molnard2a7f472018-11-15 12:49:20 -08003753 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003754 (void *)android_media_MediaCodec_getName },
3755
Chong Zhanga0b72a62018-02-28 18:46:26 -08003756 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3757 (void *)android_media_MediaCodec_getOwnCodecInfo },
3758
Ray Essick10353e32017-04-14 10:22:55 -07003759 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003760 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003761
Andreas Huber226065b2013-08-12 10:14:11 -07003762 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3763 (void *)android_media_MediaCodec_setParameters },
3764
Andreas Huberb12a5392012-04-30 14:18:33 -07003765 { "setVideoScalingMode", "(I)V",
3766 (void *)android_media_MediaCodec_setVideoScalingMode },
3767
ybai5e053202018-11-01 13:02:15 +08003768 { "native_setAudioPresentation", "(II)V",
3769 (void *)android_media_MediaCodec_setAudioPresentation },
3770
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003771 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
3772 (void *)android_media_MediaCodec_getSupportedVendorParameters },
3773
3774 { "native_getParameterDescriptor",
3775 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
3776 (void *)android_media_MediaCodec_getParameterDescriptor },
3777
3778 { "native_subscribeToVendorParameters",
3779 "(Ljava/util/List;)V",
3780 (void *)android_media_MediaCodec_subscribeToVendorParameters},
3781
3782 { "native_unsubscribeFromVendorParameters",
3783 "(Ljava/util/List;)V",
3784 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
3785
Andreas Huber88572f72012-02-21 11:47:18 -08003786 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3787
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003788 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003789 (void *)android_media_MediaCodec_native_setup },
3790
3791 { "native_finalize", "()V",
3792 (void *)android_media_MediaCodec_native_finalize },
3793};
3794
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003795static const JNINativeMethod gLinearBlockMethods[] = {
3796 { "native_map", "()Ljava/nio/ByteBuffer;",
3797 (void *)android_media_MediaCodec_LinearBlock_native_map },
3798
3799 { "native_recycle", "()V",
3800 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3801
3802 { "native_obtain", "(I[Ljava/lang/String;)V",
3803 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3804
3805 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3806 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3807};
3808
Andreas Huber88572f72012-02-21 11:47:18 -08003809int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003810 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003811 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003812 if (result != JNI_OK) {
3813 return result;
3814 }
3815 result = AndroidRuntime::registerNativeMethods(env,
3816 "android/media/MediaCodec$LinearBlock",
3817 gLinearBlockMethods,
3818 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003819 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003820}