blob: 9a4aa3344374dc7097ae53bd7c7f09a5e2a1874c [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 Kimf7069ce2020-05-13 17:15:47 -070046#include <binder/MemoryDealer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080047
Lajos Molnar7ac4f562014-03-24 15:57:51 -070048#include <cutils/compiler.h>
49
Mathias Agopian8335f1c2012-02-25 18:48:35 -080050#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080051
Wonsik Kimccb7ac62019-12-27 17:12:40 -080052#include <hidlmemory/FrameworkUtils.h>
53
Wonsik Kim4273dd02016-09-27 15:23:35 +090054#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080055#include <media/hardware/VideoAPI.h>
Wonsik Kim8798c8c2021-03-18 21:38:57 -070056#include <media/stagefright/CodecBase.h>
Andreas Huber88572f72012-02-21 11:47:18 -080057#include <media/stagefright/MediaCodec.h>
58#include <media/stagefright/foundation/ABuffer.h>
59#include <media/stagefright/foundation/ADebug.h>
60#include <media/stagefright/foundation/ALooper.h>
61#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070062#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080063#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070064#include <media/stagefright/PersistentSurface.h>
Robert Shih631a80d2021-02-14 02:23:55 -080065#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080066#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070067
Wonsik Kim637afb22020-02-25 14:27:29 -080068#include <private/android/AHardwareBufferHelpers.h>
69
Andreas Huberb12a5392012-04-30 14:18:33 -070070#include <system/window.h>
71
Andreas Huber88572f72012-02-21 11:47:18 -080072namespace android {
73
74// Keep these in sync with their equivalents in MediaCodec.java !!!
75enum {
76 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
77 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
78 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
79};
80
Andreas Huberaba67132013-10-22 12:40:01 -070081enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070082 EVENT_CALLBACK = 1,
83 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070084 EVENT_FRAME_RENDERED = 3,
Guillaume Chelfic072caf2021-02-03 16:18:26 +010085 EVENT_FIRST_TUNNEL_FRAME_READY = 4,
Andreas Huberaba67132013-10-22 12:40:01 -070086};
87
Wonsik Kim8798c8c2021-03-18 21:38:57 -070088// From MediaFormat.java
89enum {
90 TYPE_NULL = 0,
91 TYPE_INTEGER = 1,
92 TYPE_LONG = 2,
93 TYPE_FLOAT = 3,
94 TYPE_STRING = 4,
95 TYPE_BYTE_BUFFER = 5,
96};
97
Andy Hung5f9aa0b2014-07-30 15:48:21 -070098static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070099 jint cryptoErrorNoKey;
100 jint cryptoErrorKeyExpired;
101 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700102 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700103 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -0800104 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800105 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -0800106 jint cryptoErrorFrameTooLarge;
107 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700108} gCryptoErrorCodes;
109
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700110static struct CodecActionCodes {
111 jint codecActionTransient;
112 jint codecActionRecoverable;
113} gCodecActionCodes;
114
Ronghua Wuc53ad692015-05-08 14:40:49 -0700115static struct CodecErrorCodes {
116 jint errorInsufficientResource;
117 jint errorReclaimed;
118} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700119
Chong Zhang8034d602015-04-28 13:38:48 -0700120static struct {
121 jclass clazz;
122 jfieldID mLock;
123 jfieldID mPersistentObject;
124 jmethodID ctor;
125 jmethodID setNativeObjectLocked;
126} gPersistentSurfaceClassInfo;
127
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800128static struct {
129 jint Unencrypted;
130 jint AesCtr;
131 jint AesCbc;
132} gCryptoModes;
133
Chong Zhanga0b72a62018-02-28 18:46:26 -0800134static struct {
135 jclass capsClazz;
136 jmethodID capsCtorId;
137 jclass profileLevelClazz;
138 jfieldID profileField;
139 jfieldID levelField;
140} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800141
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800142static struct {
143 jclass clazz;
144 jobject nativeByteOrder;
145 jmethodID orderId;
146 jmethodID asReadOnlyBufferId;
147 jmethodID positionId;
148 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700149 jmethodID getPositionId;
150 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800151} gByteBufferInfo;
152
153static struct {
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700154 jclass clazz;
155 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800156 jmethodID sizeId;
157 jmethodID getId;
158 jmethodID addId;
159} gArrayListInfo;
160
161static struct {
162 jclass clazz;
163 jmethodID ctorId;
164 jmethodID setInternalStateId;
165 jfieldID contextId;
166 jfieldID validId;
167 jfieldID lockId;
168} gLinearBlockInfo;
169
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700170static struct {
171 jclass clazz;
172 jmethodID ctorId;
173 jfieldID nameId;
174 jfieldID typeId;
175} gDescriptorInfo;
176
Pavel Laboviche53421b2022-11-01 03:53:27 +0000177static struct {
178 jclass clazz;
179 jmethodID ctorId;
180 jmethodID setId;
181} gBufferInfo;
182
Andreas Huber88572f72012-02-21 11:47:18 -0800183struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700184 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700185 jmethodID lockAndGetContextID;
186 jmethodID setAndUnlockContextID;
Arun Johnson5a4c7332022-12-17 00:47:06 +0000187 jmethodID cryptoInfoSetID;
188 jmethodID cryptoInfoSetPatternID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700189 jfieldID cryptoInfoNumSubSamplesID;
190 jfieldID cryptoInfoNumBytesOfClearDataID;
191 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
192 jfieldID cryptoInfoKeyID;
193 jfieldID cryptoInfoIVID;
194 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800195 jfieldID cryptoInfoPatternID;
196 jfieldID patternEncryptBlocksID;
197 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800198 jfieldID queueRequestIndexID;
199 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800200 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800201 jfieldID outputFrameChangedKeysID;
202 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800203};
204
205static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700206static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800207
Arun Johnson5a4c7332022-12-17 00:47:06 +0000208jint MediaErrorToJavaError(status_t err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800209
Andreas Huber88572f72012-02-21 11:47:18 -0800210////////////////////////////////////////////////////////////////////////////////
211
212JMediaCodec::JMediaCodec(
213 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100214 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800215 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700216 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800217 jclass clazz = env->GetObjectClass(thiz);
218 CHECK(clazz != NULL);
219
220 mClass = (jclass)env->NewGlobalRef(clazz);
221 mObject = env->NewWeakGlobalRef(thiz);
222
223 mLooper = new ALooper;
224 mLooper->setName("MediaCodec_looper");
225
226 mLooper->start(
227 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700228 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700229 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800230
231 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100232 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800233 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
234 mNameAtCreation = "(null)";
235 }
Andreas Huber88572f72012-02-21 11:47:18 -0800236 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100237 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800238 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800239 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700240 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800241}
242
243status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700244 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800245}
246
Andreas Huberaba67132013-10-22 12:40:01 -0700247void JMediaCodec::registerSelf() {
248 mLooper->registerHandler(this);
249}
250
Chong Zhang128b0122014-03-01 18:04:13 -0800251void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700252 std::call_once(mReleaseFlag, [this] {
253 if (mCodec != NULL) {
254 mCodec->release();
255 mInitStatus = NO_INIT;
256 }
Andreas Huber88572f72012-02-21 11:47:18 -0800257
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700258 if (mLooper != NULL) {
259 mLooper->unregisterHandler(id());
260 mLooper->stop();
261 mLooper.clear();
262 }
263 });
Chong Zhang128b0122014-03-01 18:04:13 -0800264}
265
Wonsik Kim89666622020-04-28 10:43:47 -0700266void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700267 std::call_once(mAsyncReleaseFlag, [this] {
268 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700269 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
270 // Hold strong reference to this until async release is complete
271 notify->setObject("this", this);
272 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700273 }
274 mInitStatus = NO_INIT;
275 });
Wonsik Kim89666622020-04-28 10:43:47 -0700276}
277
Chong Zhang128b0122014-03-01 18:04:13 -0800278JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700279 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800280 /* MediaCodec and looper should have been released explicitly already
281 * in setMediaCodec() (see comments in setMediaCodec()).
282 *
283 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
284 * message handler, doing release() there risks deadlock as MediaCodec::
285 * release() post synchronous message to the same looper.
286 *
287 * Print a warning and try to proceed with releasing.
288 */
289 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
290 release();
291 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
292 }
293
Andreas Huber88572f72012-02-21 11:47:18 -0800294 JNIEnv *env = AndroidRuntime::getJNIEnv();
295
296 env->DeleteWeakGlobalRef(mObject);
297 mObject = NULL;
298 env->DeleteGlobalRef(mClass);
299 mClass = NULL;
300}
301
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100302status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
303 if (enable) {
304 if (mOnFirstTunnelFrameReadyNotification == NULL) {
305 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
306 }
307 } else {
308 mOnFirstTunnelFrameReadyNotification.clear();
309 }
310
311 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
312}
313
Lajos Molnard8578572015-06-05 20:17:33 -0700314status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
315 if (enable) {
316 if (mOnFrameRenderedNotification == NULL) {
317 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
318 }
319 } else {
320 mOnFrameRenderedNotification.clear();
321 }
322
323 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
324}
325
Chong Zhang8d5e5562014-07-08 18:49:21 -0700326status_t JMediaCodec::setCallback(jobject cb) {
327 if (cb != NULL) {
328 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800329 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700330 }
331 } else {
332 mCallbackNotification.clear();
333 }
334
335 return mCodec->setCallback(mCallbackNotification);
336}
337
Andreas Huber88572f72012-02-21 11:47:18 -0800338status_t JMediaCodec::configure(
339 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800340 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700341 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800342 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800343 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800344 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800345 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700346 mSurfaceTextureClient =
347 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700348 } else {
349 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800350 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700351
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800352 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
353 AString mime;
354 CHECK(format->findString("mime", &mime));
355 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
356 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700357 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800358 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800359
Chong Zhangd5927ae2017-01-03 11:07:18 -0800360 return mCodec->configure(
361 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800362}
363
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700364status_t JMediaCodec::setSurface(
365 const sp<IGraphicBufferProducer> &bufferProducer) {
366 sp<Surface> client;
367 if (bufferProducer != NULL) {
368 client = new Surface(bufferProducer, true /* controlledByApp */);
369 }
370 status_t err = mCodec->setSurface(client);
371 if (err == OK) {
372 mSurfaceTextureClient = client;
373 }
374 return err;
375}
376
Andy McFadden2621e402013-02-19 07:29:21 -0800377status_t JMediaCodec::createInputSurface(
378 sp<IGraphicBufferProducer>* bufferProducer) {
379 return mCodec->createInputSurface(bufferProducer);
380}
381
Chong Zhang9560ddb2015-05-13 10:25:29 -0700382status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700383 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700384 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700385}
386
Andreas Huber88572f72012-02-21 11:47:18 -0800387status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700388 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800389}
390
391status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700392 mSurfaceTextureClient.clear();
393
Chong Zhang8d5e5562014-07-08 18:49:21 -0700394 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800395}
396
397status_t JMediaCodec::flush() {
398 return mCodec->flush();
399}
400
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700401status_t JMediaCodec::reset() {
402 return mCodec->reset();
403}
404
Andreas Huber88572f72012-02-21 11:47:18 -0800405status_t JMediaCodec::queueInputBuffer(
406 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700407 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
408 AString *errorDetailMsg) {
409 return mCodec->queueInputBuffer(
410 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800411}
412
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700413status_t JMediaCodec::queueSecureInputBuffer(
414 size_t index,
415 size_t offset,
416 const CryptoPlugin::SubSample *subSamples,
417 size_t numSubSamples,
418 const uint8_t key[16],
419 const uint8_t iv[16],
420 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800421 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700422 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700423 uint32_t flags,
424 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700425 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800426 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700427 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700428}
429
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800430status_t JMediaCodec::queueBuffer(
431 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
432 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
433 return mCodec->queueBuffer(
434 index, buffer, timeUs, flags, tunings, errorDetailMsg);
435}
436
437status_t JMediaCodec::queueEncryptedLinearBlock(
438 size_t index,
439 const sp<hardware::HidlMemory> &buffer,
440 size_t offset,
441 const CryptoPlugin::SubSample *subSamples,
442 size_t numSubSamples,
443 const uint8_t key[16],
444 const uint8_t iv[16],
445 CryptoPlugin::Mode mode,
446 const CryptoPlugin::Pattern &pattern,
447 int64_t presentationTimeUs,
448 uint32_t flags,
449 const sp<AMessage> &tunings,
450 AString *errorDetailMsg) {
451 return mCodec->queueEncryptedBuffer(
452 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
453 presentationTimeUs, flags, tunings, errorDetailMsg);
454}
455
Andreas Huber88572f72012-02-21 11:47:18 -0800456status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700457 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800458}
459
460status_t JMediaCodec::dequeueOutputBuffer(
461 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
462 size_t size, offset;
463 int64_t timeUs;
464 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700465 status_t err = mCodec->dequeueOutputBuffer(
466 index, &offset, &size, &timeUs, &flags, timeoutUs);
467
Andreas Huberaba67132013-10-22 12:40:01 -0700468 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800469 return err;
470 }
471
Pavel Laboviche53421b2022-11-01 03:53:27 +0000472 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800473
474 return OK;
475}
476
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700477status_t JMediaCodec::releaseOutputBuffer(
478 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
479 if (updatePTS) {
480 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
481 }
Andreas Huber88572f72012-02-21 11:47:18 -0800482 return render
483 ? mCodec->renderOutputBufferAndRelease(index)
484 : mCodec->releaseOutputBuffer(index);
485}
486
Andy McFadden2621e402013-02-19 07:29:21 -0800487status_t JMediaCodec::signalEndOfInputStream() {
488 return mCodec->signalEndOfInputStream();
489}
490
Lajos Molnard4023112014-07-11 15:12:59 -0700491status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800492 sp<AMessage> msg;
493 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700494 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
495 if (err != OK) {
496 return err;
497 }
498
499 return ConvertMessageToMap(env, msg, format);
500}
501
502status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
503 sp<AMessage> msg;
504 status_t err;
505 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800506 return err;
507 }
508
509 return ConvertMessageToMap(env, msg, format);
510}
511
512status_t JMediaCodec::getBuffers(
513 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900514 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800515
516 status_t err =
517 input
518 ? mCodec->getInputBuffers(&buffers)
519 : mCodec->getOutputBuffers(&buffers);
520
521 if (err != OK) {
522 return err;
523 }
524
Andreas Huber88572f72012-02-21 11:47:18 -0800525 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800526 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800527 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800528 return NO_MEMORY;
529 }
Andreas Huber88572f72012-02-21 11:47:18 -0800530
531 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900532 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800533
Lajos Molnar7de28d32014-07-25 07:51:02 -0700534 jobject byteBuffer = NULL;
535 err = createByteBufferFromABuffer(
536 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
537 if (err != OK) {
538 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800539 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700540 if (byteBuffer != NULL) {
541 env->SetObjectArrayElement(
542 *bufArray, i, byteBuffer);
543
Lajos Molnard4023112014-07-11 15:12:59 -0700544 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700545 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700546 }
Andreas Huber88572f72012-02-21 11:47:18 -0800547 }
548
Lajos Molnar7de28d32014-07-25 07:51:02 -0700549 return OK;
550}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700551
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800552template <typename T>
553static jobject CreateByteBuffer(
554 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
555 bool readOnly, bool clearBuffer) {
556 jobject byteBuffer =
557 env->NewDirectByteBuffer(
558 const_cast<typename std::remove_const<T>::type *>(base),
559 capacity);
560 if (readOnly && byteBuffer != NULL) {
561 jobject readOnlyBuffer = env->CallObjectMethod(
562 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
563 env->DeleteLocalRef(byteBuffer);
564 byteBuffer = readOnlyBuffer;
565 }
566 if (byteBuffer == NULL) {
567 return nullptr;
568 }
569 jobject me = env->CallObjectMethod(
570 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
571 env->DeleteLocalRef(me);
572 me = env->CallObjectMethod(
573 byteBuffer, gByteBufferInfo.limitId,
574 clearBuffer ? capacity : offset + size);
575 env->DeleteLocalRef(me);
576 me = env->CallObjectMethod(
577 byteBuffer, gByteBufferInfo.positionId,
578 clearBuffer ? 0 : offset);
579 env->DeleteLocalRef(me);
580 me = NULL;
581 return byteBuffer;
582}
583
584
Lajos Molnar7de28d32014-07-25 07:51:02 -0700585// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900586template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700587status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900588 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700589 jobject *buf) const {
590 // if this is an ABuffer that doesn't actually hold any accessible memory,
591 // use a null ByteBuffer
592 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700593
594 if (buffer == NULL) {
595 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
596 return OK;
597 }
598
Lajos Molnar7de28d32014-07-25 07:51:02 -0700599 if (buffer->base() == NULL) {
600 return OK;
601 }
602
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800603 jobject byteBuffer = CreateByteBuffer(
604 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
605 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700606
607 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800608 return OK;
609}
610
Lajos Molnard4023112014-07-11 15:12:59 -0700611status_t JMediaCodec::getBuffer(
612 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900613 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700614
615 status_t err =
616 input
617 ? mCodec->getInputBuffer(index, &buffer)
618 : mCodec->getOutputBuffer(index, &buffer);
619
620 if (err != OK) {
621 return err;
622 }
623
Lajos Molnar7de28d32014-07-25 07:51:02 -0700624 return createByteBufferFromABuffer(
625 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700626}
627
628status_t JMediaCodec::getImage(
629 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900630 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700631
632 status_t err =
633 input
634 ? mCodec->getInputBuffer(index, &buffer)
635 : mCodec->getOutputBuffer(index, &buffer);
636
637 if (err != OK) {
638 return err;
639 }
640
641 // if this is an ABuffer that doesn't actually hold any accessible memory,
642 // use a null ByteBuffer
643 *buf = NULL;
644 if (buffer->base() == NULL) {
645 return OK;
646 }
647
648 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700649 sp<ABuffer> imageData;
650 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700651 return OK;
652 }
653
Lajos Molnar7de28d32014-07-25 07:51:02 -0700654 int64_t timestamp = 0;
655 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
656 timestamp *= 1000; // adjust to ns
657 }
658
659 jobject byteBuffer = NULL;
660 err = createByteBufferFromABuffer(
661 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
662 if (err != OK) {
663 return OK;
664 }
665
666 jobject infoBuffer = NULL;
667 err = createByteBufferFromABuffer(
668 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
669 if (err != OK) {
670 env->DeleteLocalRef(byteBuffer);
671 byteBuffer = NULL;
672 return OK;
673 }
674
675 jobject cropRect = NULL;
676 int32_t left, top, right, bottom;
677 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
678 ScopedLocalRef<jclass> rectClazz(
679 env, env->FindClass("android/graphics/Rect"));
680 CHECK(rectClazz.get() != NULL);
681
682 jmethodID rectConstructID = env->GetMethodID(
683 rectClazz.get(), "<init>", "(IIII)V");
684
685 cropRect = env->NewObject(
686 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
687 }
688
689 ScopedLocalRef<jclass> imageClazz(
690 env, env->FindClass("android/media/MediaCodec$MediaImage"));
691 CHECK(imageClazz.get() != NULL);
692
693 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
694 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
695
696 *buf = env->NewObject(imageClazz.get(), imageConstructID,
697 byteBuffer, infoBuffer,
698 (jboolean)!input /* readOnly */,
699 (jlong)timestamp,
700 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
701
702 // if MediaImage creation fails, return null
703 if (env->ExceptionCheck()) {
704 env->ExceptionDescribe();
705 env->ExceptionClear();
706 *buf = NULL;
707 }
708
709 if (cropRect != NULL) {
710 env->DeleteLocalRef(cropRect);
711 cropRect = NULL;
712 }
713
714 env->DeleteLocalRef(byteBuffer);
715 byteBuffer = NULL;
716
717 env->DeleteLocalRef(infoBuffer);
718 infoBuffer = NULL;
719
Lajos Molnard4023112014-07-11 15:12:59 -0700720 return OK;
721}
722
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800723status_t JMediaCodec::getOutputFrame(
724 JNIEnv *env, jobject frame, size_t index) const {
725 sp<MediaCodecBuffer> buffer;
726
727 status_t err = mCodec->getOutputBuffer(index, &buffer);
728 if (err != OK) {
729 return err;
730 }
731
732 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800733 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800734 if (c2Buffer) {
735 switch (c2Buffer->data().type()) {
736 case C2BufferData::LINEAR: {
737 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700738 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800739 context->mBuffer = c2Buffer;
740 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
741 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800742 env->CallVoidMethod(
743 linearBlock.get(),
744 gLinearBlockInfo.setInternalStateId,
745 (jlong)context.release(),
746 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800747 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
748 break;
749 }
750 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800751 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
752 uint32_t width, height, format, stride, igbp_slot, generation;
753 uint64_t usage, igbp_id;
754 _UnwrapNativeCodec2GrallocMetadata(
755 c2Handle, &width, &height, &format, &usage, &stride, &generation,
756 &igbp_id, &igbp_slot);
757 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
758 GraphicBuffer* graphicBuffer = new GraphicBuffer(
759 grallocHandle, GraphicBuffer::CLONE_HANDLE,
760 width, height, format, 1, usage, stride);
761 ScopedLocalRef<jobject> hardwareBuffer{
762 env,
763 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
764 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
765 env->SetObjectField(
766 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800767 break;
768 }
769 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
770 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
771 case C2BufferData::INVALID: [[fallthrough]];
772 default:
773 return INVALID_OPERATION;
774 }
775 } else {
776 if (!mGraphicOutput) {
777 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700778 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800779 context->mLegacyBuffer = buffer;
780 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
781 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800782 env->CallVoidMethod(
783 linearBlock.get(),
784 gLinearBlockInfo.setInternalStateId,
785 (jlong)context.release(),
786 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800787 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
788 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800789 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800790 }
791 }
792 }
793
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700794 jobject formatMap;
795 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800796 if (err != OK) {
797 return err;
798 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700799 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
800 ScopedLocalRef<jobject> format{env, env->NewObject(
801 mediaFormatClass.get(),
802 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
803 formatMap)};
804 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
805 env->DeleteLocalRef(formatMap);
806 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800807
808 sp<RefBase> obj;
809 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
810 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
811 (decltype(changedKeys.get()))obj.get()};
812 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
813 frame, gFields.outputFrameChangedKeysID)};
814 for (const std::string &key : changedKeys->value) {
815 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
816 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
817 }
818 }
819 return OK;
820}
821
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300822status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
823 AString name;
824
825 status_t err = mCodec->getName(&name);
826
827 if (err != OK) {
828 return err;
829 }
830
831 *nameStr = env->NewStringUTF(name.c_str());
832
833 return OK;
834}
835
Chong Zhanga0b72a62018-02-28 18:46:26 -0800836static jobject getCodecCapabilitiesObject(
837 JNIEnv *env, const char *mime, bool isEncoder,
838 const sp<MediaCodecInfo::Capabilities> &capabilities) {
839 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
840 Vector<uint32_t> colorFormats;
841
842 sp<AMessage> defaultFormat = new AMessage();
843 defaultFormat->setString("mime", mime);
844
845 capabilities->getSupportedColorFormats(&colorFormats);
846 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800847 sp<AMessage> details = capabilities->getDetails();
848
849 jobject defaultFormatObj = NULL;
850 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
851 return NULL;
852 }
853 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
854
855 jobject detailsObj = NULL;
856 if (ConvertMessageToMap(env, details, &detailsObj)) {
857 return NULL;
858 }
859 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
860
861 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
862 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
863
864 for (size_t i = 0; i < profileLevels.size(); ++i) {
865 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
866
867 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
868 gCodecInfo.profileLevelClazz));
869
870 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
871 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
872
873 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
874 }
875
876 ScopedLocalRef<jintArray> colorFormatsArray(
877 env, env->NewIntArray(colorFormats.size()));
878 for (size_t i = 0; i < colorFormats.size(); ++i) {
879 jint val = colorFormats.itemAt(i);
880 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
881 }
882
883 return env->NewObject(
884 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800885 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800886 defaultFormatRef.get(), detailsRef.get());
887}
888
889status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
890 sp<MediaCodecInfo> codecInfo;
891
892 status_t err = mCodec->getCodecInfo(&codecInfo);
893
894 if (err != OK) {
895 return err;
896 }
897
898 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800899 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800900
Lajos Molnard2a7f472018-11-15 12:49:20 -0800901 ScopedLocalRef<jstring> canonicalNameObject(env,
902 env->NewStringUTF(codecInfo->getCodecName()));
903
904 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800905 bool isEncoder = codecInfo->isEncoder();
906
Lajos Molnard2a7f472018-11-15 12:49:20 -0800907 Vector<AString> mediaTypes;
908 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800909
910 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800911 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800912
Lajos Molnard2a7f472018-11-15 12:49:20 -0800913 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800914 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800915 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800916
917 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800918 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800919
920 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
921 }
922
923 ScopedLocalRef<jclass> codecInfoClazz(env,
924 env->FindClass("android/media/MediaCodecInfo"));
925 CHECK(codecInfoClazz.get() != NULL);
926
927 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800928 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800929
930 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800931 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800932
933 return OK;
934}
935
Ray Essick81fbc5b2019-12-07 06:24:59 -0800936status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
937 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700938 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700939 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800940 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800941 return status;
942}
943
Andreas Huber226065b2013-08-12 10:14:11 -0700944status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
945 return mCodec->setParameters(msg);
946}
947
Andreas Huberb12a5392012-04-30 14:18:33 -0700948void JMediaCodec::setVideoScalingMode(int mode) {
949 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700950 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700951 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700952 // also signal via param for components that queue to IGBP
953 sp<AMessage> msg = new AMessage;
954 msg->setInt32("android._video-scaling", mode);
955 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700956 }
957}
958
ybai5e053202018-11-01 13:02:15 +0800959void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
960 sp<AMessage> msg = new AMessage;
961 msg->setInt32("audio-presentation-presentation-id", presentationId);
962 msg->setInt32("audio-presentation-program-id", programId);
963 (void)mCodec->setParameters(msg);
964}
965
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700966status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
967 std::vector<std::string> names;
968 status_t status = mCodec->querySupportedVendorParameters(&names);
969 if (status != OK) {
970 return status;
971 }
972 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
973 for (const std::string &name : names) {
974 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
975 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
976 }
977 return OK;
978}
979
980status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
981 const char *tmp = env->GetStringUTFChars(name, nullptr);
982 CodecParameterDescriptor desc;
983 status_t status = mCodec->describeParameter(tmp, &desc);
984 env->ReleaseStringUTFChars(name, tmp);
985 if (status != OK) {
986 return status;
987 }
988 jint type = TYPE_NULL;
989 switch (desc.type) {
990 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
991 case AMessage::kTypeSize:
992 case AMessage::kTypeInt64: type = TYPE_LONG; break;
993 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
994 case AMessage::kTypeString: type = TYPE_STRING; break;
995 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
996 default: type = TYPE_NULL; break;
997 }
998 if (type == TYPE_NULL) {
999 return BAD_VALUE;
1000 }
1001 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1002 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1003 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1004 return OK;
1005}
1006
1007static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1008 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1009 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1010 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1011 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1012 jobject it = env->CallObjectMethod(
1013 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1014 while (env->CallBooleanMethod(it, hasNextID)) {
1015 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1016 const char *tmp = env->GetStringUTFChars(name, nullptr);
1017 vec->push_back(tmp);
1018 env->ReleaseStringUTFChars(name, tmp);
1019 }
1020}
1021
1022status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1023 std::vector<std::string> names;
1024 BuildVectorFromList(env, namesObj, &names);
1025 return mCodec->subscribeToVendorParameters(names);
1026}
1027
1028status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1029 std::vector<std::string> names;
1030 BuildVectorFromList(env, namesObj, &names);
1031 return mCodec->unsubscribeFromVendorParameters(names);
1032}
1033
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001034static jthrowable createCodecException(
1035 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1036 ScopedLocalRef<jclass> clazz(
1037 env, env->FindClass("android/media/MediaCodec$CodecException"));
1038 CHECK(clazz.get() != NULL);
1039
Ronghua Wuc53ad692015-05-08 14:40:49 -07001040 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001041 CHECK(ctor != NULL);
1042
1043 ScopedLocalRef<jstring> msgObj(
1044 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
1045
1046 // translate action code to Java equivalent
1047 switch (actionCode) {
1048 case ACTION_CODE_TRANSIENT:
1049 actionCode = gCodecActionCodes.codecActionTransient;
1050 break;
1051 case ACTION_CODE_RECOVERABLE:
1052 actionCode = gCodecActionCodes.codecActionRecoverable;
1053 break;
1054 default:
1055 actionCode = 0; // everything else is fatal
1056 break;
1057 }
1058
Ronghua Wuc53ad692015-05-08 14:40:49 -07001059 /* translate OS errors to Java API CodecException errorCodes */
1060 switch (err) {
1061 case NO_MEMORY:
1062 err = gCodecErrorCodes.errorInsufficientResource;
1063 break;
1064 case DEAD_OBJECT:
1065 err = gCodecErrorCodes.errorReclaimed;
1066 break;
1067 default: /* Other error codes go out as is. */
1068 break;
1069 }
1070
1071 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001072}
1073
Arun Johnson5a4c7332022-12-17 00:47:06 +00001074static void AMessageToCryptoInfo(JNIEnv * env, const jobject & obj,
1075 const sp<AMessage> & msg) {
1076 if(msg == nullptr || obj == nullptr) {
1077 ALOGE("CryptoAsync Nothing to do in AMessagetoCryptoInfo");
1078 return;
1079 }
1080 size_t numSubSamples = 0;
1081 sp<ABuffer> subSamplesBuffer;
1082 sp<ABuffer> keyBuffer;
1083 sp<ABuffer> ivBuffer;
1084 CryptoPlugin::Mode mode;
1085 CryptoPlugin::Pattern pattern;
1086 CHECK(msg->findInt32("mode", (int*)&mode));
1087 CHECK(msg->findSize("numSubSamples", &numSubSamples));
1088 CHECK(msg->findBuffer("subSamples", &subSamplesBuffer));
1089 CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
1090 CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
1091 CHECK(msg->findBuffer("iv", &ivBuffer));
1092 CHECK(msg->findBuffer("key", &keyBuffer));
1093
1094 // subsamples
1095 ScopedLocalRef<jintArray> samplesOfEncryptedDataArr(env, env->NewIntArray(numSubSamples));
1096 ScopedLocalRef<jintArray> samplesOfClearDataArr(env, env->NewIntArray(numSubSamples));
1097 jboolean isCopy;
1098 jint *dstEncryptedSamples =
1099 env->GetIntArrayElements(samplesOfEncryptedDataArr.get(), &isCopy);
1100 jint * dstClearSamples =
1101 env->GetIntArrayElements(samplesOfClearDataArr.get(), &isCopy);
1102
1103 CryptoPlugin::SubSample * samplesArray =
1104 (CryptoPlugin::SubSample*)(subSamplesBuffer.get()->data());
1105
1106 for(int i = 0 ; i < numSubSamples ; i++) {
1107 dstEncryptedSamples[i] = samplesArray[i].mNumBytesOfEncryptedData;
1108 dstClearSamples[i] = samplesArray[i].mNumBytesOfClearData;
1109 }
1110 env->ReleaseIntArrayElements(samplesOfEncryptedDataArr.get(), dstEncryptedSamples, 0);
1111 env->ReleaseIntArrayElements(samplesOfClearDataArr.get(), dstClearSamples, 0);
1112 // key and iv
1113 jbyteArray keyArray = NULL;
1114 jbyteArray ivArray = NULL;
1115 if (keyBuffer.get() != nullptr && keyBuffer->size() > 0) {
1116 keyArray = env->NewByteArray(keyBuffer->size());
1117 jbyte * dstKey = env->GetByteArrayElements(keyArray, &isCopy);
1118 memcpy(dstKey, keyBuffer->data(), keyBuffer->size());
1119 env->ReleaseByteArrayElements(keyArray,dstKey,0);
1120 }
1121 if (ivBuffer.get() != nullptr && ivBuffer->size() > 0) {
1122 ivArray = env->NewByteArray(ivBuffer->size());
1123 jbyte *dstIv = env->GetByteArrayElements(ivArray, &isCopy);
1124 memcpy(dstIv, ivBuffer->data(), ivBuffer->size());
1125 env->ReleaseByteArrayElements(ivArray, dstIv,0);
1126 }
1127 // set samples, key and iv
1128 env->CallVoidMethod(
1129 obj,
1130 gFields.cryptoInfoSetID,
1131 (jint)numSubSamples,
1132 samplesOfClearDataArr.get(),
1133 samplesOfEncryptedDataArr.get(),
1134 keyArray,
1135 ivArray,
1136 mode);
1137 if (keyArray != NULL) {
1138 env->DeleteLocalRef(keyArray);
1139 }
1140 if (ivArray != NULL) {
1141 env->DeleteLocalRef(ivArray);
1142 }
1143 // set pattern
1144 env->CallVoidMethod(
1145 obj,
1146 gFields.cryptoInfoSetPatternID,
1147 pattern.mEncryptBlocks,
1148 pattern.mSkipBlocks);
1149}
1150
1151static void CryptoErrorToJavaError(status_t err, jint& jerr, std::string& defaultMsg) {
1152 switch(err) {
1153 case ERROR_DRM_NO_LICENSE:
1154 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
1155 defaultMsg = "Crypto key not available";
1156 break;
1157 case ERROR_DRM_LICENSE_EXPIRED:
1158 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
1159 defaultMsg = "License expired";
1160 break;
1161 case ERROR_DRM_RESOURCE_BUSY:
1162 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
1163 defaultMsg = "Resource busy or unavailable";
1164 break;
1165 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1166 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
1167 defaultMsg = "Required output protections are not active";
1168 break;
1169 case ERROR_DRM_SESSION_NOT_OPENED:
1170 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
1171 defaultMsg = "Attempted to use a closed session";
1172 break;
1173 case ERROR_DRM_INSUFFICIENT_SECURITY:
1174 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1175 defaultMsg = "Required security level is not met";
1176 break;
1177 case ERROR_DRM_CANNOT_HANDLE:
1178 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1179 defaultMsg = "Operation not supported in this configuration";
1180 break;
1181 case ERROR_DRM_FRAME_TOO_LARGE:
1182 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1183 defaultMsg = "Decrytped frame exceeds size of output buffer";
1184 break;
1185 case ERROR_DRM_SESSION_LOST_STATE:
1186 jerr = gCryptoErrorCodes.cryptoErrorLostState;
1187 defaultMsg = "Session state was lost, open a new session and retry";
1188 break;
1189 default: // Other negative DRM error codes go out best-effort.
1190 jerr = MediaErrorToJavaError(err);
1191 defaultMsg = StrCryptoError(err);
1192 break;
1193 }
1194}
1195static jthrowable createCryptoException(JNIEnv *env, status_t err,
1196 const char * msg = NULL, const sp<ICrypto> & crypto = NULL,
1197 const sp<AMessage> & cryptoInfo = NULL) {
1198 jthrowable exception = nullptr;
1199 jmethodID constructID = nullptr;
1200 ScopedLocalRef<jobject> cryptoInfoObject(env);
1201 std::string defaultMsg = "Unknown Error";
1202 jint jerr = 0;
1203 // Get a class ref for CryptoException
1204 ScopedLocalRef<jclass> clazz(
1205 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1206 CHECK(clazz.get() != NULL);
1207
1208 // Get constructor ref for CryptoException
1209 constructID = env->GetMethodID(clazz.get(), "<init>",
1210 "(Ljava/lang/String;IIIILandroid/media/MediaCodec$CryptoInfo;)V");
1211 CHECK(constructID != NULL);
1212
1213 // create detailed message for exception
1214 CryptoErrorToJavaError(err, jerr, defaultMsg);
1215 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1216 DrmStatus dStatus(err, originalMsg.c_str());
1217 std::string detailedMsg(
1218 DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1219 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
1220
1221 if (cryptoInfo != nullptr) {
1222 // Class ref for CryptoInfo
1223 ScopedLocalRef<jclass> clazzCryptoInfo(
1224 env, env->FindClass("android/media/MediaCodec$CryptoInfo"));
1225 CHECK(clazzCryptoInfo.get() != NULL);
1226
1227 // Constructor reference for CryptoInfo
1228 jmethodID constructCryptoInfo =
1229 env->GetMethodID(clazzCryptoInfo.get(), "<init>", "()V");
1230 CHECK(constructCryptoInfo != NULL);
1231
1232 // Create CryptoInfo jobject
1233 cryptoInfoObject.reset(
1234 env->NewObject(clazzCryptoInfo.get(), constructCryptoInfo));
1235 CHECK(cryptoInfoObject.get() != NULL);
1236
1237 // Translate AMesage to CryptoInfo
1238 AMessageToCryptoInfo(env, cryptoInfoObject.get(), cryptoInfo);
1239 }
1240
1241 exception = (jthrowable)env->NewObject(
1242 clazz.get(), constructID, msgObj, jerr,
1243 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext(),
1244 cryptoInfoObject.get());
1245
1246 return exception;
1247}
Chong Zhang8d5e5562014-07-08 18:49:21 -07001248void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1249 int32_t arg1, arg2 = 0;
1250 jobject obj = NULL;
1251 CHECK(msg->findInt32("callbackID", &arg1));
1252 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001253
Chong Zhang8d5e5562014-07-08 18:49:21 -07001254 switch (arg1) {
1255 case MediaCodec::CB_INPUT_AVAILABLE:
1256 {
1257 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001258 break;
1259 }
1260
Chong Zhang8d5e5562014-07-08 18:49:21 -07001261 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001262 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001263 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001264
Chong Zhang8d5e5562014-07-08 18:49:21 -07001265 size_t size, offset;
1266 int64_t timeUs;
1267 uint32_t flags;
1268 CHECK(msg->findSize("size", &size));
1269 CHECK(msg->findSize("offset", &offset));
1270 CHECK(msg->findInt64("timeUs", &timeUs));
1271 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1272
Pavel Laboviche53421b2022-11-01 03:53:27 +00001273 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001274 if (obj == NULL) {
1275 if (env->ExceptionCheck()) {
1276 ALOGE("Could not create MediaCodec.BufferInfo.");
1277 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001278 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001279 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1280 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001281 }
1282
Pavel Laboviche53421b2022-11-01 03:53:27 +00001283 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001284 break;
1285 }
1286
Arun Johnson5a4c7332022-12-17 00:47:06 +00001287 case MediaCodec::CB_CRYPTO_ERROR:
1288 {
1289 int32_t err, actionCode;
1290 AString errorDetail;
1291 CHECK(msg->findInt32("err", &err));
1292 CHECK(msg->findInt32("actionCode",&actionCode));
1293 CHECK(msg->findString("errorDetail", &errorDetail));
1294 obj = (jobject)createCryptoException(env, err, errorDetail.c_str(), NULL, msg);
1295 break;
1296 }
1297
Chong Zhang8d5e5562014-07-08 18:49:21 -07001298 case MediaCodec::CB_ERROR:
1299 {
Chong Zhang94686d12014-07-11 15:53:58 -07001300 int32_t err, actionCode;
1301 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001302 CHECK(msg->findInt32("actionCode", &actionCode));
1303
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001304 // note that DRM errors could conceivably alias into a CodecException
1305 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001306
1307 if (obj == NULL) {
1308 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001309 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001310 env->ExceptionClear();
1311 }
1312 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1313 return;
1314 }
Andreas Huberaba67132013-10-22 12:40:01 -07001315
1316 break;
1317 }
1318
Chong Zhang8d5e5562014-07-08 18:49:21 -07001319 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001320 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001321 sp<AMessage> format;
1322 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001323
Chong Zhang8d5e5562014-07-08 18:49:21 -07001324 if (OK != ConvertMessageToMap(env, format, &obj)) {
1325 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1326 return;
1327 }
Andreas Huberaba67132013-10-22 12:40:01 -07001328
Andreas Huberaba67132013-10-22 12:40:01 -07001329 break;
1330 }
1331
1332 default:
1333 TRESPASS();
1334 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001335 env->CallVoidMethod(
1336 mObject,
1337 gFields.postEventFromNativeID,
1338 EVENT_CALLBACK,
1339 arg1,
1340 arg2,
1341 obj);
1342
1343 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001344}
1345
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001346void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1347 int32_t arg1 = 0, arg2 = 0;
1348 jobject obj = NULL;
1349 JNIEnv *env = AndroidRuntime::getJNIEnv();
1350
1351 sp<AMessage> data;
1352 CHECK(msg->findMessage("data", &data));
1353
1354 status_t err = ConvertMessageToMap(env, data, &obj);
1355 if (err != OK) {
1356 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1357 return;
1358 }
1359
1360 env->CallVoidMethod(
1361 mObject, gFields.postEventFromNativeID,
1362 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1363
1364 env->DeleteLocalRef(obj);
1365}
1366
Lajos Molnard8578572015-06-05 20:17:33 -07001367void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1368 int32_t arg1 = 0, arg2 = 0;
1369 jobject obj = NULL;
1370 JNIEnv *env = AndroidRuntime::getJNIEnv();
1371
1372 sp<AMessage> data;
1373 CHECK(msg->findMessage("data", &data));
1374
1375 status_t err = ConvertMessageToMap(env, data, &obj);
1376 if (err != OK) {
1377 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1378 return;
1379 }
1380
1381 env->CallVoidMethod(
1382 mObject, gFields.postEventFromNativeID,
1383 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1384
1385 env->DeleteLocalRef(obj);
1386}
1387
Chong Zhang8d5e5562014-07-08 18:49:21 -07001388void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1389 switch (msg->what()) {
1390 case kWhatCallbackNotify:
1391 {
1392 handleCallback(msg);
1393 break;
1394 }
Lajos Molnard8578572015-06-05 20:17:33 -07001395 case kWhatFrameRendered:
1396 {
1397 handleFrameRenderedNotification(msg);
1398 break;
1399 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001400 case kWhatAsyncReleaseComplete:
1401 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001402 if (mLooper != NULL) {
1403 mLooper->unregisterHandler(id());
1404 mLooper->stop();
1405 mLooper.clear();
1406 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001407 break;
1408 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001409 case kWhatFirstTunnelFrameReady:
1410 {
1411 handleFirstTunnelFrameReadyNotification(msg);
1412 break;
1413 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001414 default:
1415 TRESPASS();
1416 }
Andreas Huberaba67132013-10-22 12:40:01 -07001417}
1418
Robert Shih631a80d2021-02-14 02:23:55 -08001419
Andreas Huber88572f72012-02-21 11:47:18 -08001420} // namespace android
1421
1422////////////////////////////////////////////////////////////////////////////////
1423
1424using namespace android;
1425
1426static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001427 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001428 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001429 if (codec != NULL) {
1430 codec->incStrong(thiz);
1431 }
1432 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001433 /* release MediaCodec and stop the looper now before decStrong.
1434 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1435 * its message handler, doing release() from there will deadlock
1436 * (as MediaCodec::release() post synchronous message to the same looper)
1437 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001438 if (release) {
1439 old->release();
1440 }
Andreas Huber88572f72012-02-21 11:47:18 -08001441 old->decStrong(thiz);
1442 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001443 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001444
1445 return old;
1446}
1447
1448static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001449 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1450 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1451 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001452}
1453
1454static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001455 // Clear Java native reference.
1456 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001457 if (codec != NULL) {
1458 codec->releaseAsync();
1459 }
Andreas Huber88572f72012-02-21 11:47:18 -08001460}
1461
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001462static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1463 jthrowable exception = createCodecException(env, err, actionCode, msg);
1464 env->Throw(exception);
1465}
1466
Robert Shih631a80d2021-02-14 02:23:55 -08001467static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1468 const sp<ICrypto> &crypto) {
Arun Johnson5a4c7332022-12-17 00:47:06 +00001469 jthrowable exception = createCryptoException(
1470 env, err, msg, crypto, /* cryptoInfo */ NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001471 env->Throw(exception);
1472}
1473
1474static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001475 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Robert Shih631a80d2021-02-14 02:23:55 -08001476 const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001477 switch (err) {
1478 case OK:
1479 return 0;
1480
1481 case -EAGAIN:
1482 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1483
1484 case INFO_FORMAT_CHANGED:
1485 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1486
1487 case INFO_OUTPUT_BUFFERS_CHANGED:
1488 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1489
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001490 case INVALID_OPERATION:
1491 jniThrowException(env, "java/lang/IllegalStateException", msg);
1492 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001493
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001494 case BAD_VALUE:
1495 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1496 return 0;
1497
Andreas Huber88572f72012-02-21 11:47:18 -08001498 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001499 if (isCryptoError(err)) {
Robert Shih631a80d2021-02-14 02:23:55 -08001500 throwCryptoException(env, err, msg, crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001501 return 0;
1502 }
1503 throwCodecException(env, err, actionCode, msg);
1504 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001505 }
Andreas Huber88572f72012-02-21 11:47:18 -08001506}
1507
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001508static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1509 JNIEnv *env,
1510 jobject thiz,
1511 jboolean enabled) {
1512 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1513
1514 if (codec == NULL || codec->initCheck() != OK) {
1515 throwExceptionAsNecessary(env, INVALID_OPERATION);
1516 return;
1517 }
1518
1519 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1520
1521 throwExceptionAsNecessary(env, err);
1522}
1523
Lajos Molnard8578572015-06-05 20:17:33 -07001524static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1525 JNIEnv *env,
1526 jobject thiz,
1527 jboolean enabled) {
1528 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1529
Wonsik Kim24e53802020-05-08 20:04:26 -07001530 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnard8578572015-06-05 20:17:33 -07001531 throwExceptionAsNecessary(env, INVALID_OPERATION);
1532 return;
1533 }
1534
1535 status_t err = codec->enableOnFrameRenderedListener(enabled);
1536
1537 throwExceptionAsNecessary(env, err);
1538}
1539
Chong Zhang8d5e5562014-07-08 18:49:21 -07001540static void android_media_MediaCodec_native_setCallback(
1541 JNIEnv *env,
1542 jobject thiz,
1543 jobject cb) {
1544 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1545
Wonsik Kim24e53802020-05-08 20:04:26 -07001546 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001547 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001548 return;
1549 }
1550
1551 status_t err = codec->setCallback(cb);
1552
1553 throwExceptionAsNecessary(env, err);
1554}
1555
Andreas Huber88572f72012-02-21 11:47:18 -08001556static void android_media_MediaCodec_native_configure(
1557 JNIEnv *env,
1558 jobject thiz,
1559 jobjectArray keys, jobjectArray values,
1560 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001561 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001562 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001563 jint flags) {
1564 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1565
Wonsik Kim24e53802020-05-08 20:04:26 -07001566 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001567 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001568 return;
1569 }
1570
1571 sp<AMessage> format;
1572 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1573
1574 if (err != OK) {
1575 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1576 return;
1577 }
1578
Andy McFaddend47f7d82012-12-18 09:48:38 -08001579 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001580 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001581 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001582 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001583 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001584 } else {
1585 jniThrowException(
1586 env,
1587 "java/lang/IllegalArgumentException",
1588 "The surface has been released");
1589 return;
1590 }
1591 }
1592
Andreas Huber8240d922012-04-04 14:06:32 -07001593 sp<ICrypto> crypto;
1594 if (jcrypto != NULL) {
1595 crypto = JCrypto::GetCrypto(env, jcrypto);
1596 }
1597
Chong Zhangd5927ae2017-01-03 11:07:18 -08001598 sp<IDescrambler> descrambler;
1599 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001600 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001601 }
1602
1603 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001604
1605 throwExceptionAsNecessary(env, err);
1606}
1607
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001608static void android_media_MediaCodec_native_setSurface(
1609 JNIEnv *env,
1610 jobject thiz,
1611 jobject jsurface) {
1612 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1613
Wonsik Kim24e53802020-05-08 20:04:26 -07001614 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001615 throwExceptionAsNecessary(env, INVALID_OPERATION);
1616 return;
1617 }
1618
1619 sp<IGraphicBufferProducer> bufferProducer;
1620 if (jsurface != NULL) {
1621 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1622 if (surface != NULL) {
1623 bufferProducer = surface->getIGraphicBufferProducer();
1624 } else {
1625 jniThrowException(
1626 env,
1627 "java/lang/IllegalArgumentException",
1628 "The surface has been released");
1629 return;
1630 }
1631 }
1632
1633 status_t err = codec->setSurface(bufferProducer);
1634 throwExceptionAsNecessary(env, err);
1635}
1636
Chong Zhang8034d602015-04-28 13:38:48 -07001637sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1638 JNIEnv* env, jobject object) {
1639 sp<PersistentSurface> persistentSurface;
1640
1641 jobject lock = env->GetObjectField(
1642 object, gPersistentSurfaceClassInfo.mLock);
1643 if (env->MonitorEnter(lock) == JNI_OK) {
1644 persistentSurface = reinterpret_cast<PersistentSurface *>(
1645 env->GetLongField(object,
1646 gPersistentSurfaceClassInfo.mPersistentObject));
1647 env->MonitorExit(lock);
1648 }
1649 env->DeleteLocalRef(lock);
1650
1651 return persistentSurface;
1652}
1653
1654static jobject android_media_MediaCodec_createPersistentInputSurface(
1655 JNIEnv* env, jclass /* clazz */) {
1656 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1657 sp<PersistentSurface> persistentSurface =
1658 MediaCodec::CreatePersistentInputSurface();
1659
1660 if (persistentSurface == NULL) {
1661 return NULL;
1662 }
1663
1664 sp<Surface> surface = new Surface(
1665 persistentSurface->getBufferProducer(), true);
1666 if (surface == NULL) {
1667 return NULL;
1668 }
1669
1670 jobject object = env->NewObject(
1671 gPersistentSurfaceClassInfo.clazz,
1672 gPersistentSurfaceClassInfo.ctor);
1673
1674 if (object == NULL) {
1675 if (env->ExceptionCheck()) {
1676 ALOGE("Could not create PersistentSurface.");
1677 env->ExceptionClear();
1678 }
1679 return NULL;
1680 }
1681
1682 jobject lock = env->GetObjectField(
1683 object, gPersistentSurfaceClassInfo.mLock);
1684 if (env->MonitorEnter(lock) == JNI_OK) {
1685 env->CallVoidMethod(
1686 object,
1687 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1688 (jlong)surface.get());
1689 env->SetLongField(
1690 object,
1691 gPersistentSurfaceClassInfo.mPersistentObject,
1692 (jlong)persistentSurface.get());
1693 env->MonitorExit(lock);
1694 } else {
1695 env->DeleteLocalRef(object);
1696 object = NULL;
1697 }
1698 env->DeleteLocalRef(lock);
1699
1700 if (object != NULL) {
1701 surface->incStrong(&sRefBaseOwner);
1702 persistentSurface->incStrong(&sRefBaseOwner);
1703 }
1704
1705 return object;
1706}
1707
1708static void android_media_MediaCodec_releasePersistentInputSurface(
1709 JNIEnv* env, jclass /* clazz */, jobject object) {
1710 sp<PersistentSurface> persistentSurface;
1711
1712 jobject lock = env->GetObjectField(
1713 object, gPersistentSurfaceClassInfo.mLock);
1714 if (env->MonitorEnter(lock) == JNI_OK) {
1715 persistentSurface = reinterpret_cast<PersistentSurface *>(
1716 env->GetLongField(
1717 object, gPersistentSurfaceClassInfo.mPersistentObject));
1718 env->SetLongField(
1719 object,
1720 gPersistentSurfaceClassInfo.mPersistentObject,
1721 (jlong)0);
1722 env->MonitorExit(lock);
1723 }
1724 env->DeleteLocalRef(lock);
1725
1726 if (persistentSurface != NULL) {
1727 persistentSurface->decStrong(&sRefBaseOwner);
1728 }
1729 // no need to release surface as it will be released by Surface's jni
1730}
1731
Chong Zhang9560ddb2015-05-13 10:25:29 -07001732static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001733 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001734 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001735
1736 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001737 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhang8034d602015-04-28 13:38:48 -07001738 throwExceptionAsNecessary(env, INVALID_OPERATION);
1739 return;
1740 }
1741
1742 sp<PersistentSurface> persistentSurface =
1743 android_media_MediaCodec_getPersistentInputSurface(env, object);
1744
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001745 if (persistentSurface == NULL) {
1746 throwExceptionAsNecessary(
1747 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1748 return;
1749 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001750 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001751 if (err != NO_ERROR) {
1752 throwExceptionAsNecessary(env, err);
1753 }
1754}
1755
Andy McFadden2621e402013-02-19 07:29:21 -08001756static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1757 jobject thiz) {
1758 ALOGV("android_media_MediaCodec_createInputSurface");
1759
1760 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001761 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001762 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001763 return NULL;
1764 }
1765
1766 // Tell the MediaCodec that we want to use a Surface as input.
1767 sp<IGraphicBufferProducer> bufferProducer;
1768 status_t err = codec->createInputSurface(&bufferProducer);
1769 if (err != NO_ERROR) {
1770 throwExceptionAsNecessary(env, err);
1771 return NULL;
1772 }
1773
1774 // Wrap the IGBP in a Java-language Surface.
1775 return android_view_Surface_createFromIGraphicBufferProducer(env,
1776 bufferProducer);
1777}
1778
Andreas Huber88572f72012-02-21 11:47:18 -08001779static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1780 ALOGV("android_media_MediaCodec_start");
1781
1782 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1783
Wonsik Kim24e53802020-05-08 20:04:26 -07001784 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001785 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001786 return;
1787 }
1788
1789 status_t err = codec->start();
1790
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001791 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001792}
1793
1794static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1795 ALOGV("android_media_MediaCodec_stop");
1796
1797 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1798
Wonsik Kim24e53802020-05-08 20:04:26 -07001799 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001800 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001801 return;
1802 }
1803
1804 status_t err = codec->stop();
1805
1806 throwExceptionAsNecessary(env, err);
1807}
1808
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001809static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1810 ALOGV("android_media_MediaCodec_reset");
1811
1812 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1813
Wonsik Kim24e53802020-05-08 20:04:26 -07001814 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001815 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001816 return;
1817 }
1818
1819 status_t err = codec->reset();
1820 if (err != OK) {
1821 // treat all errors as fatal for now, though resource not available
1822 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001823 // we also should avoid sending INVALID_OPERATION here due to
1824 // the transitory nature of reset(), it should not inadvertently
1825 // trigger an IllegalStateException.
1826 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001827 }
1828 throwExceptionAsNecessary(env, err);
1829}
1830
Andreas Huber88572f72012-02-21 11:47:18 -08001831static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1832 ALOGV("android_media_MediaCodec_flush");
1833
1834 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1835
Wonsik Kim24e53802020-05-08 20:04:26 -07001836 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001837 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001838 return;
1839 }
1840
1841 status_t err = codec->flush();
1842
1843 throwExceptionAsNecessary(env, err);
1844}
1845
1846static void android_media_MediaCodec_queueInputBuffer(
1847 JNIEnv *env,
1848 jobject thiz,
1849 jint index,
1850 jint offset,
1851 jint size,
1852 jlong timestampUs,
1853 jint flags) {
1854 ALOGV("android_media_MediaCodec_queueInputBuffer");
1855
1856 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1857
Wonsik Kim24e53802020-05-08 20:04:26 -07001858 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001859 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001860 return;
1861 }
1862
Andreas Huberbfc56f42012-04-19 12:47:07 -07001863 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001864
Andreas Huberbfc56f42012-04-19 12:47:07 -07001865 status_t err = codec->queueInputBuffer(
1866 index, offset, size, timestampUs, flags, &errorDetailMsg);
1867
1868 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001869 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001870}
1871
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001872struct NativeCryptoInfo {
1873 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1874 : mEnv{env},
1875 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1876 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1877 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1878
1879 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1880 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1881
1882 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1883 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1884
1885 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1886 if (jmode == gCryptoModes.Unencrypted) {
1887 mMode = CryptoPlugin::kMode_Unencrypted;
1888 } else if (jmode == gCryptoModes.AesCtr) {
1889 mMode = CryptoPlugin::kMode_AES_CTR;
1890 } else if (jmode == gCryptoModes.AesCbc) {
1891 mMode = CryptoPlugin::kMode_AES_CBC;
1892 } else {
1893 throwExceptionAsNecessary(env, INVALID_OPERATION);
1894 return;
1895 }
1896
1897 ScopedLocalRef<jobject> patternObj{
1898 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1899
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001900 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001901 mPattern.mEncryptBlocks = 0;
1902 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001903 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001904 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001905 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001906 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001907 patternObj.get(), gFields.patternSkipBlocksID);
1908 }
1909
1910 mErr = OK;
1911 if (mNumSubSamples <= 0) {
1912 mErr = -EINVAL;
1913 } else if (numBytesOfClearDataObj == nullptr
1914 && numBytesOfEncryptedDataObj == nullptr) {
1915 mErr = -EINVAL;
1916 } else if (numBytesOfEncryptedDataObj != nullptr
1917 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1918 mErr = -ERANGE;
1919 } else if (numBytesOfClearDataObj != nullptr
1920 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1921 mErr = -ERANGE;
1922 // subSamples array may silently overflow if number of samples are too large. Use
1923 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1924 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1925 mErr = -EINVAL;
1926 } else {
1927 jint *numBytesOfClearData =
1928 (numBytesOfClearDataObj == nullptr)
1929 ? nullptr
1930 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1931
1932 jint *numBytesOfEncryptedData =
1933 (numBytesOfEncryptedDataObj == nullptr)
1934 ? nullptr
1935 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1936
1937 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1938
1939 for (jint i = 0; i < mNumSubSamples; ++i) {
1940 mSubSamples[i].mNumBytesOfClearData =
1941 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1942
1943 mSubSamples[i].mNumBytesOfEncryptedData =
1944 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1945 }
1946
1947 if (numBytesOfEncryptedData != nullptr) {
1948 env->ReleaseIntArrayElements(
1949 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1950 numBytesOfEncryptedData = nullptr;
1951 }
1952
1953 if (numBytesOfClearData != nullptr) {
1954 env->ReleaseIntArrayElements(
1955 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1956 numBytesOfClearData = nullptr;
1957 }
1958 }
1959
1960 if (mErr == OK && mKeyObj.get() != nullptr) {
1961 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1962 mErr = -EINVAL;
1963 } else {
1964 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1965 }
1966 }
1967
1968 if (mErr == OK && mIvObj.get() != nullptr) {
1969 if (env->GetArrayLength(mIvObj.get()) != 16) {
1970 mErr = -EINVAL;
1971 } else {
1972 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1973 }
1974 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001975
1976 }
1977
1978 explicit NativeCryptoInfo(jint size)
1979 : mIvObj{nullptr, nullptr},
1980 mKeyObj{nullptr, nullptr},
1981 mMode{CryptoPlugin::kMode_Unencrypted},
1982 mPattern{0, 0} {
1983 mSubSamples = new CryptoPlugin::SubSample[1];
1984 mNumSubSamples = 1;
1985 mSubSamples[0].mNumBytesOfClearData = size;
1986 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001987 }
1988
1989 ~NativeCryptoInfo() {
1990 if (mIv != nullptr) {
1991 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1992 }
1993
1994 if (mKey != nullptr) {
1995 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1996 }
1997
1998 if (mSubSamples != nullptr) {
1999 delete[] mSubSamples;
2000 }
2001 }
2002
2003 JNIEnv *mEnv{nullptr};
2004 ScopedLocalRef<jbyteArray> mIvObj;
2005 ScopedLocalRef<jbyteArray> mKeyObj;
2006 status_t mErr{OK};
2007
2008 CryptoPlugin::SubSample *mSubSamples{nullptr};
2009 int32_t mNumSubSamples{0};
2010 jbyte *mIv{nullptr};
2011 jbyte *mKey{nullptr};
2012 enum CryptoPlugin::Mode mMode;
2013 CryptoPlugin::Pattern mPattern;
2014};
2015
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002016static void android_media_MediaCodec_queueSecureInputBuffer(
2017 JNIEnv *env,
2018 jobject thiz,
2019 jint index,
2020 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07002021 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002022 jlong timestampUs,
2023 jint flags) {
2024 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
2025
2026 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2027
Wonsik Kim24e53802020-05-08 20:04:26 -07002028 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002029 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002030 return;
2031 }
2032
Wonsik Kim1cac4252020-01-24 11:45:37 -08002033 jint numSubSamples =
2034 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
2035
2036 jintArray numBytesOfClearDataObj =
2037 (jintArray)env->GetObjectField(
2038 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
2039
2040 jintArray numBytesOfEncryptedDataObj =
2041 (jintArray)env->GetObjectField(
2042 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
2043
2044 jbyteArray keyObj =
2045 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
2046
2047 jbyteArray ivObj =
2048 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
2049
2050 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
2051 enum CryptoPlugin::Mode mode;
2052 if (jmode == gCryptoModes.Unencrypted) {
2053 mode = CryptoPlugin::kMode_Unencrypted;
2054 } else if (jmode == gCryptoModes.AesCtr) {
2055 mode = CryptoPlugin::kMode_AES_CTR;
2056 } else if (jmode == gCryptoModes.AesCbc) {
2057 mode = CryptoPlugin::kMode_AES_CBC;
2058 } else {
2059 throwExceptionAsNecessary(env, INVALID_OPERATION);
2060 return;
2061 }
2062
2063 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
2064
2065 CryptoPlugin::Pattern pattern;
2066 if (patternObj == NULL) {
2067 pattern.mEncryptBlocks = 0;
2068 pattern.mSkipBlocks = 0;
2069 } else {
2070 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
2071 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
2072 }
2073
2074 status_t err = OK;
2075
2076 CryptoPlugin::SubSample *subSamples = NULL;
2077 jbyte *key = NULL;
2078 jbyte *iv = NULL;
2079
2080 if (numSubSamples <= 0) {
2081 err = -EINVAL;
2082 } else if (numBytesOfClearDataObj == NULL
2083 && numBytesOfEncryptedDataObj == NULL) {
2084 err = -EINVAL;
2085 } else if (numBytesOfEncryptedDataObj != NULL
2086 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2087 err = -ERANGE;
2088 } else if (numBytesOfClearDataObj != NULL
2089 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2090 err = -ERANGE;
2091 // subSamples array may silently overflow if number of samples are too large. Use
2092 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2093 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2094 err = -EINVAL;
2095 } else {
2096 jboolean isCopy;
2097
2098 jint *numBytesOfClearData =
2099 (numBytesOfClearDataObj == NULL)
2100 ? NULL
2101 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2102
2103 jint *numBytesOfEncryptedData =
2104 (numBytesOfEncryptedDataObj == NULL)
2105 ? NULL
2106 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2107
2108 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2109
2110 for (jint i = 0; i < numSubSamples; ++i) {
2111 subSamples[i].mNumBytesOfClearData =
2112 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2113
2114 subSamples[i].mNumBytesOfEncryptedData =
2115 (numBytesOfEncryptedData == NULL)
2116 ? 0 : numBytesOfEncryptedData[i];
2117 }
2118
2119 if (numBytesOfEncryptedData != NULL) {
2120 env->ReleaseIntArrayElements(
2121 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2122 numBytesOfEncryptedData = NULL;
2123 }
2124
2125 if (numBytesOfClearData != NULL) {
2126 env->ReleaseIntArrayElements(
2127 numBytesOfClearDataObj, numBytesOfClearData, 0);
2128 numBytesOfClearData = NULL;
2129 }
2130 }
2131
2132 if (err == OK && keyObj != NULL) {
2133 if (env->GetArrayLength(keyObj) != 16) {
2134 err = -EINVAL;
2135 } else {
2136 jboolean isCopy;
2137 key = env->GetByteArrayElements(keyObj, &isCopy);
2138 }
2139 }
2140
2141 if (err == OK && ivObj != NULL) {
2142 if (env->GetArrayLength(ivObj) != 16) {
2143 err = -EINVAL;
2144 } else {
2145 jboolean isCopy;
2146 iv = env->GetByteArrayElements(ivObj, &isCopy);
2147 }
2148 }
2149
Andreas Huberbfc56f42012-04-19 12:47:07 -07002150 AString errorDetailMsg;
2151
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002152 if (err == OK) {
2153 err = codec->queueSecureInputBuffer(
2154 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002155 subSamples, numSubSamples,
2156 (const uint8_t *)key, (const uint8_t *)iv,
2157 mode,
2158 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002159 timestampUs,
2160 flags,
2161 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002162 }
2163
Wonsik Kim1cac4252020-01-24 11:45:37 -08002164 if (iv != NULL) {
2165 env->ReleaseByteArrayElements(ivObj, iv, 0);
2166 iv = NULL;
2167 }
2168
2169 if (key != NULL) {
2170 env->ReleaseByteArrayElements(keyObj, key, 0);
2171 key = NULL;
2172 }
2173
2174 delete[] subSamples;
2175 subSamples = NULL;
2176
Andreas Huberbfc56f42012-04-19 12:47:07 -07002177 throwExceptionAsNecessary(
Robert Shih631a80d2021-02-14 02:23:55 -08002178 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
2179 codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002180}
2181
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002182static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002183 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2184 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2185 env, bufferObj);
2186 AHardwareBuffer_Desc desc;
2187 AHardwareBuffer_describe(hardwareBuffer, &desc);
2188 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2189 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2190 return nullptr;
2191 }
2192 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2193 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2194 return nullptr;
2195 }
2196 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2197
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002198 uint64_t cpuUsage = 0;
2199 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2200 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002201
2202 AHardwareBuffer_Planes planes;
2203 int err = AHardwareBuffer_lockPlanes(
2204 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2205 if (err != 0) {
2206 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2207 return nullptr;
2208 }
2209
2210 if (planes.planeCount != 3) {
2211 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2212 return nullptr;
2213 }
2214
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002215 ScopedLocalRef<jobjectArray> buffersArray{
2216 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2217 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2218 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002219
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002220 jboolean isCopy = JNI_FALSE;
2221 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2222 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2223
2224 // For Y plane
2225 int rowSampling = 1;
2226 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002227 // plane indices are Y-U-V.
2228 for (uint32_t i = 0; i < 3; ++i) {
2229 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002230 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2231 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2232 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002233 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2234 env,
2235 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002236 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002237 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002238 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002239 readOnly,
2240 true)};
2241
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002242 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2243 rowStrides[i] = plane.rowStride;
2244 pixelStrides[i] = plane.pixelStride;
2245 // For U-V planes
2246 rowSampling = 2;
2247 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002248 }
2249
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002250 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2251 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2252 rowStrides = pixelStrides = nullptr;
2253
Wonsik Kim637afb22020-02-25 14:27:29 -08002254 ScopedLocalRef<jclass> imageClazz(
2255 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2256 CHECK(imageClazz.get() != NULL);
2257
2258 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002259 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002260
2261 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002262 buffersArray.get(),
2263 rowStridesArray.get(),
2264 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002265 desc.width,
2266 desc.height,
2267 desc.format, // ???
2268 (jboolean)readOnly /* readOnly */,
2269 (jlong)0 /* timestamp */,
2270 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2271 (jlong)hardwareBuffer);
2272
2273 // if MediaImage creation fails, return null
2274 if (env->ExceptionCheck()) {
2275 env->ExceptionDescribe();
2276 env->ExceptionClear();
2277 return nullptr;
2278 }
2279
2280 AHardwareBuffer_acquire(hardwareBuffer);
2281
2282 return img;
2283}
2284
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002285static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2286 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002287 if (context == 0) {
2288 return;
2289 }
2290 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2291
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002292 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2293 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002294 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2295 // Continue to release the hardwareBuffer
2296 }
2297
2298 AHardwareBuffer_release(hardwareBuffer);
2299}
2300
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002301static status_t ConvertKeyValueListsToAMessage(
2302 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2303 static struct Fields {
2304 explicit Fields(JNIEnv *env) {
2305 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2306 CHECK(clazz.get() != NULL);
2307 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2308
2309 clazz.reset(env->FindClass("java/lang/Integer"));
2310 CHECK(clazz.get() != NULL);
2311 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2312
2313 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2314 CHECK(mIntegerValueId != NULL);
2315
2316 clazz.reset(env->FindClass("java/lang/Long"));
2317 CHECK(clazz.get() != NULL);
2318 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2319
2320 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2321 CHECK(mLongValueId != NULL);
2322
2323 clazz.reset(env->FindClass("java/lang/Float"));
2324 CHECK(clazz.get() != NULL);
2325 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2326
2327 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2328 CHECK(mFloatValueId != NULL);
2329
2330 clazz.reset(env->FindClass("java/util/ArrayList"));
2331 CHECK(clazz.get() != NULL);
2332
2333 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2334 CHECK(mByteBufferArrayId != NULL);
2335 }
2336
2337 jclass mStringClass;
2338 jclass mIntegerClass;
2339 jmethodID mIntegerValueId;
2340 jclass mLongClass;
2341 jmethodID mLongValueId;
2342 jclass mFloatClass;
2343 jmethodID mFloatValueId;
2344 jmethodID mByteBufferArrayId;
2345 } sFields{env};
2346
2347 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2348 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2349 return BAD_VALUE;
2350 }
2351
2352 sp<AMessage> result{new AMessage};
2353 for (jint i = 0; i < size; ++i) {
2354 ScopedLocalRef<jstring> jkey{
2355 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2356 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2357 AString key;
2358 if (tmp) {
2359 key.setTo(tmp);
2360 }
2361 env->ReleaseStringUTFChars(jkey.get(), tmp);
2362 if (key.empty()) {
2363 return NO_MEMORY;
2364 }
2365
2366 ScopedLocalRef<jobject> jvalue{
2367 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2368
2369 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2370 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2371 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002372 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002373 return NO_MEMORY;
2374 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002375 value.setTo(tmp);
2376 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002377 result->setString(key.c_str(), value);
2378 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2379 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2380 result->setInt32(key.c_str(), value);
2381 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2382 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2383 result->setInt64(key.c_str(), value);
2384 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2385 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2386 result->setFloat(key.c_str(), value);
2387 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002388 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2389 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002390 sp<ABuffer> buffer{new ABuffer(limit - position)};
2391 void *data = env->GetDirectBufferAddress(jvalue.get());
2392 if (data != nullptr) {
2393 memcpy(buffer->data(),
2394 static_cast<const uint8_t *>(data) + position,
2395 buffer->size());
2396 } else {
2397 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2398 jvalue.get(), sFields.mByteBufferArrayId)};
2399 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2400 reinterpret_cast<jbyte *>(buffer->data()));
2401 }
2402 result->setBuffer(key.c_str(), buffer);
2403 }
2404 }
2405
2406 *msg = result;
2407 return OK;
2408}
2409
Wonsik Kim8569a662022-05-24 14:16:44 -07002410static bool obtain(
2411 JMediaCodecLinearBlock *context,
2412 int capacity,
2413 const std::vector<std::string> &names,
2414 bool secure) {
2415 if (secure) {
2416 // Start at 1MB, which is an arbitrary starting point that can
2417 // increase when needed.
2418 constexpr size_t kInitialDealerCapacity = 1048576;
2419 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2420 kInitialDealerCapacity, "JNI(1MB)");
2421 context->mMemory = sDealer->allocate(capacity);
2422 if (context->mMemory == nullptr) {
2423 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2424 while (capacity * 2 > newDealerCapacity) {
2425 newDealerCapacity *= 2;
2426 }
2427 ALOGI("LinearBlock.native_obtain: "
2428 "Dealer capacity increasing from %zuMB to %zuMB",
2429 sDealer->getMemoryHeap()->getSize() / 1048576,
2430 newDealerCapacity / 1048576);
2431 sDealer = new MemoryDealer(
2432 newDealerCapacity,
2433 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2434 context->mMemory = sDealer->allocate(capacity);
2435 }
2436 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2437 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2438 } else {
2439 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2440 if (!context->mBlock) {
2441 return false;
2442 }
2443 }
2444 context->mCodecNames = names;
2445 return true;
2446}
2447
2448static void extractMemoryFromContext(
2449 JMediaCodecLinearBlock *context,
2450 jint offset,
2451 jint size,
2452 sp<hardware::HidlMemory> *memory) {
2453 *memory = context->toHidlMemory();
2454 if (*memory == nullptr) {
2455 if (!context->mBlock) {
2456 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2457 return;
2458 }
2459 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2460 context->capacity());
2461 if (!obtain(context, context->capacity(),
2462 context->mCodecNames, true /* secure */)) {
2463 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2464 return;
2465 }
2466 C2WriteView view = context->mBlock->map().get();
2467 if (view.error() != C2_OK) {
2468 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2469 return;
2470 }
2471 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2472 memcpy(memoryPtr + offset, view.base() + offset, size);
2473 context->mBlock.reset();
2474 context->mReadWriteMapping.reset();
2475 *memory = context->toHidlMemory();
2476 }
2477}
2478
2479static void extractBufferFromContext(
2480 JMediaCodecLinearBlock *context,
2481 jint offset,
2482 jint size,
2483 std::shared_ptr<C2Buffer> *buffer) {
2484 *buffer = context->toC2Buffer(offset, size);
2485 if (*buffer == nullptr) {
2486 if (!context->mMemory) {
2487 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2488 return;
2489 }
2490 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2491 context->capacity());
2492 if (obtain(context, context->capacity(),
2493 context->mCodecNames, false /* secure */)) {
2494 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2495 return;
2496 }
2497 C2WriteView view = context->mBlock->map().get();
2498 if (view.error() != C2_OK) {
2499 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2500 return;
2501 }
2502 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2503 memcpy(view.base() + offset, memoryPtr + offset, size);
2504 context->mMemory.clear();
2505 context->mHidlMemory.clear();
2506 context->mHidlMemorySize = 0;
2507 context->mHidlMemoryOffset = 0;
2508 *buffer = context->toC2Buffer(offset, size);
2509 }
2510}
2511
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002512static void android_media_MediaCodec_native_queueLinearBlock(
2513 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2514 jint offset, jint size, jobject cryptoInfoObj,
2515 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2516 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2517
2518 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2519
Wonsik Kim24e53802020-05-08 20:04:26 -07002520 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002521 throwExceptionAsNecessary(env, INVALID_OPERATION);
2522 return;
2523 }
2524
2525 sp<AMessage> tunings;
2526 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2527 if (err != OK) {
2528 throwExceptionAsNecessary(env, err);
2529 return;
2530 }
2531
2532 std::shared_ptr<C2Buffer> buffer;
2533 sp<hardware::HidlMemory> memory;
2534 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2535 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2536 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2537 JMediaCodecLinearBlock *context =
2538 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002539 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kim8569a662022-05-24 14:16:44 -07002540 extractMemoryFromContext(context, offset, size, &memory);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002541 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002542 } else {
Wonsik Kim8569a662022-05-24 14:16:44 -07002543 extractBufferFromContext(context, offset, size, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002544 }
2545 }
2546 env->MonitorExit(lock.get());
2547 } else {
2548 throwExceptionAsNecessary(env, INVALID_OPERATION);
2549 return;
2550 }
2551
2552 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002553 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002554 if (!memory) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002555 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002556 throwExceptionAsNecessary(env, BAD_VALUE);
2557 return;
2558 }
George Burgess IV436998b2022-11-02 11:42:33 -06002559 auto cryptoInfo =
2560 cryptoInfoObj ? NativeCryptoInfo{size} : NativeCryptoInfo{env, cryptoInfoObj};
2561 if (env->ExceptionCheck()) {
2562 // Creation of cryptoInfo failed. Let the exception bubble up.
2563 return;
2564 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002565 err = codec->queueEncryptedLinearBlock(
2566 index,
2567 memory,
2568 offset,
2569 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2570 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2571 cryptoInfo.mMode,
2572 cryptoInfo.mPattern,
2573 presentationTimeUs,
2574 flags,
2575 tunings,
2576 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002577 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002578 } else {
2579 if (!buffer) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002580 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002581 throwExceptionAsNecessary(env, BAD_VALUE);
2582 return;
2583 }
2584 err = codec->queueBuffer(
2585 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2586 }
2587 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2588}
2589
Wonsik Kim637afb22020-02-25 14:27:29 -08002590static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002591 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2592 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002593 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002594
2595 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2596
Wonsik Kim24e53802020-05-08 20:04:26 -07002597 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002598 throwExceptionAsNecessary(env, INVALID_OPERATION);
2599 return;
2600 }
2601
2602 sp<AMessage> tunings;
2603 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2604 if (err != OK) {
2605 throwExceptionAsNecessary(env, err);
2606 return;
2607 }
2608
Wonsik Kim637afb22020-02-25 14:27:29 -08002609 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2610 env, bufferObj);
2611 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2612 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002613 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2614 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2615 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2616 std::shared_ptr<C2Allocator> alloc;
2617 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2618 C2PlatformAllocatorStore::GRALLOC, &alloc);
2619 if (err == C2_OK) {
2620 return alloc;
2621 }
2622 return nullptr;
2623 }();
2624 std::shared_ptr<C2GraphicAllocation> alloc;
2625 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2626 if (c2err != C2_OK) {
2627 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002628 native_handle_close(handle);
2629 native_handle_delete(handle);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002630 throwExceptionAsNecessary(env, BAD_VALUE);
2631 return;
2632 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002633 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002634 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2635 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002636 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002637 err = codec->queueBuffer(
2638 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002639 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2640}
2641
2642static void android_media_MediaCodec_native_getOutputFrame(
2643 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2644 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2645
2646 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2647
Wonsik Kim24e53802020-05-08 20:04:26 -07002648 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002649 throwExceptionAsNecessary(env, INVALID_OPERATION);
2650 return;
2651 }
2652
2653 status_t err = codec->getOutputFrame(env, frame, index);
2654 if (err != OK) {
2655 throwExceptionAsNecessary(env, err);
2656 }
2657}
2658
Andreas Huber88572f72012-02-21 11:47:18 -08002659static jint android_media_MediaCodec_dequeueInputBuffer(
2660 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2661 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2662
2663 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2664
Wonsik Kim24e53802020-05-08 20:04:26 -07002665 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002666 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002667 return -1;
2668 }
2669
2670 size_t index;
2671 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2672
2673 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002674 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002675 }
2676
2677 return throwExceptionAsNecessary(env, err);
2678}
2679
2680static jint android_media_MediaCodec_dequeueOutputBuffer(
2681 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2682 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2683
2684 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2685
Wonsik Kim24e53802020-05-08 20:04:26 -07002686 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002687 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002688 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002689 }
2690
2691 size_t index;
2692 status_t err = codec->dequeueOutputBuffer(
2693 env, bufferInfo, &index, timeoutUs);
2694
2695 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002696 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002697 }
2698
2699 return throwExceptionAsNecessary(env, err);
2700}
2701
2702static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002703 JNIEnv *env, jobject thiz,
2704 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002705 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2706
2707 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2708
Wonsik Kim24e53802020-05-08 20:04:26 -07002709 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002710 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002711 return;
2712 }
2713
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002714 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002715
2716 throwExceptionAsNecessary(env, err);
2717}
2718
Andy McFadden2621e402013-02-19 07:29:21 -08002719static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2720 jobject thiz) {
2721 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2722
2723 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002724 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002725 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08002726 return;
2727 }
2728
2729 status_t err = codec->signalEndOfInputStream();
2730
2731 throwExceptionAsNecessary(env, err);
2732}
2733
Lajos Molnard4023112014-07-11 15:12:59 -07002734static jobject android_media_MediaCodec_getFormatNative(
2735 JNIEnv *env, jobject thiz, jboolean input) {
2736 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002737
2738 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2739
Wonsik Kim24e53802020-05-08 20:04:26 -07002740 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002741 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002742 return NULL;
2743 }
2744
2745 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002746 status_t err = codec->getFormat(env, input, &format);
2747
2748 if (err == OK) {
2749 return format;
2750 }
2751
2752 throwExceptionAsNecessary(env, err);
2753
2754 return NULL;
2755}
2756
2757static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2758 JNIEnv *env, jobject thiz, jint index) {
2759 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2760
2761 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2762
Wonsik Kim24e53802020-05-08 20:04:26 -07002763 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002764 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002765 return NULL;
2766 }
2767
2768 jobject format;
2769 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002770
2771 if (err == OK) {
2772 return format;
2773 }
2774
2775 throwExceptionAsNecessary(env, err);
2776
2777 return NULL;
2778}
2779
2780static jobjectArray android_media_MediaCodec_getBuffers(
2781 JNIEnv *env, jobject thiz, jboolean input) {
2782 ALOGV("android_media_MediaCodec_getBuffers");
2783
2784 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2785
Wonsik Kim24e53802020-05-08 20:04:26 -07002786 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002787 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002788 return NULL;
2789 }
2790
2791 jobjectArray buffers;
2792 status_t err = codec->getBuffers(env, input, &buffers);
2793
2794 if (err == OK) {
2795 return buffers;
2796 }
2797
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002798 // if we're out of memory, an exception was already thrown
2799 if (err != NO_MEMORY) {
2800 throwExceptionAsNecessary(env, err);
2801 }
Andreas Huber88572f72012-02-21 11:47:18 -08002802
2803 return NULL;
2804}
2805
Lajos Molnard4023112014-07-11 15:12:59 -07002806static jobject android_media_MediaCodec_getBuffer(
2807 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2808 ALOGV("android_media_MediaCodec_getBuffer");
2809
2810 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2811
Wonsik Kim24e53802020-05-08 20:04:26 -07002812 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002813 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002814 return NULL;
2815 }
2816
2817 jobject buffer;
2818 status_t err = codec->getBuffer(env, input, index, &buffer);
2819
2820 if (err == OK) {
2821 return buffer;
2822 }
2823
2824 // if we're out of memory, an exception was already thrown
2825 if (err != NO_MEMORY) {
2826 throwExceptionAsNecessary(env, err);
2827 }
2828
2829 return NULL;
2830}
2831
2832static jobject android_media_MediaCodec_getImage(
2833 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2834 ALOGV("android_media_MediaCodec_getImage");
2835
2836 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2837
Wonsik Kim24e53802020-05-08 20:04:26 -07002838 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002839 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002840 return NULL;
2841 }
2842
2843 jobject image;
2844 status_t err = codec->getImage(env, input, index, &image);
2845
2846 if (err == OK) {
2847 return image;
2848 }
2849
2850 // if we're out of memory, an exception was already thrown
2851 if (err != NO_MEMORY) {
2852 throwExceptionAsNecessary(env, err);
2853 }
2854
2855 return NULL;
2856}
2857
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002858static jobject android_media_MediaCodec_getName(
2859 JNIEnv *env, jobject thiz) {
2860 ALOGV("android_media_MediaCodec_getName");
2861
2862 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2863
Wonsik Kim24e53802020-05-08 20:04:26 -07002864 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002865 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002866 return NULL;
2867 }
2868
2869 jstring name;
2870 status_t err = codec->getName(env, &name);
2871
2872 if (err == OK) {
2873 return name;
2874 }
2875
2876 throwExceptionAsNecessary(env, err);
2877
2878 return NULL;
2879}
2880
Chong Zhanga0b72a62018-02-28 18:46:26 -08002881static jobject android_media_MediaCodec_getOwnCodecInfo(
2882 JNIEnv *env, jobject thiz) {
2883 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2884
2885 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2886
Wonsik Kim24e53802020-05-08 20:04:26 -07002887 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhanga0b72a62018-02-28 18:46:26 -08002888 throwExceptionAsNecessary(env, INVALID_OPERATION);
2889 return NULL;
2890 }
2891
2892 jobject codecInfoObj;
2893 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2894
2895 if (err == OK) {
2896 return codecInfoObj;
2897 }
2898
2899 throwExceptionAsNecessary(env, err);
2900
2901 return NULL;
2902}
2903
Ray Essick0e0fee12017-01-25 18:01:56 -08002904static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002905android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002906{
Ray Essickf2d0e402017-03-09 10:17:51 -08002907 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002908
2909 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002910 if (codec == NULL || codec->initCheck() != OK) {
Ray Essick0e0fee12017-01-25 18:01:56 -08002911 jniThrowException(env, "java/lang/IllegalStateException", NULL);
2912 return 0;
2913 }
2914
2915 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002916 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002917
2918 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002919 if (err != OK) {
2920 ALOGE("getMetrics failed");
2921 return (jobject) NULL;
2922 }
2923
Ray Essick0e0fee12017-01-25 18:01:56 -08002924 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2925
2926 // housekeeping
2927 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002928 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002929
2930 return mybundle;
2931}
2932
Andreas Huber226065b2013-08-12 10:14:11 -07002933static void android_media_MediaCodec_setParameters(
2934 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2935 ALOGV("android_media_MediaCodec_setParameters");
2936
2937 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2938
Wonsik Kim24e53802020-05-08 20:04:26 -07002939 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002940 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07002941 return;
2942 }
2943
2944 sp<AMessage> params;
2945 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2946
2947 if (err == OK) {
2948 err = codec->setParameters(params);
2949 }
2950
2951 throwExceptionAsNecessary(env, err);
2952}
2953
Andreas Huberb12a5392012-04-30 14:18:33 -07002954static void android_media_MediaCodec_setVideoScalingMode(
2955 JNIEnv *env, jobject thiz, jint mode) {
2956 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2957
Wonsik Kim24e53802020-05-08 20:04:26 -07002958 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002959 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07002960 return;
2961 }
2962
2963 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2964 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07002965 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07002966 return;
2967 }
2968
2969 codec->setVideoScalingMode(mode);
2970}
2971
ybai5e053202018-11-01 13:02:15 +08002972static void android_media_MediaCodec_setAudioPresentation(
2973 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2974 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2975
Wonsik Kim24e53802020-05-08 20:04:26 -07002976 if (codec == NULL || codec->initCheck() != OK) {
ybai5e053202018-11-01 13:02:15 +08002977 throwExceptionAsNecessary(env, INVALID_OPERATION);
2978 return;
2979 }
2980
2981 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2982}
2983
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002984static jobject android_media_MediaCodec_getSupportedVendorParameters(
2985 JNIEnv *env, jobject thiz) {
2986 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2987
2988 if (codec == NULL || codec->initCheck() != OK) {
2989 throwExceptionAsNecessary(env, INVALID_OPERATION);
2990 return NULL;
2991 }
2992
2993 jobject ret = NULL;
2994 status_t status = codec->querySupportedVendorParameters(env, &ret);
2995 if (status != OK) {
2996 throwExceptionAsNecessary(env, status);
2997 }
2998
2999 return ret;
3000}
3001
3002static jobject android_media_MediaCodec_getParameterDescriptor(
3003 JNIEnv *env, jobject thiz, jstring name) {
3004 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3005
3006 if (codec == NULL || codec->initCheck() != OK) {
3007 throwExceptionAsNecessary(env, INVALID_OPERATION);
3008 return NULL;
3009 }
3010
3011 jobject ret = NULL;
3012 status_t status = codec->describeParameter(env, name, &ret);
3013 if (status != OK) {
3014 ret = NULL;
3015 }
3016 return ret;
3017}
3018
3019static void android_media_MediaCodec_subscribeToVendorParameters(
3020 JNIEnv *env, jobject thiz, jobject names) {
3021 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3022
3023 if (codec == NULL || codec->initCheck() != OK) {
3024 throwExceptionAsNecessary(env, INVALID_OPERATION);
3025 return;
3026 }
3027
3028 status_t status = codec->subscribeToVendorParameters(env, names);
3029 if (status != OK) {
3030 throwExceptionAsNecessary(env, status);
3031 }
3032 return;
3033}
3034
3035static void android_media_MediaCodec_unsubscribeFromVendorParameters(
3036 JNIEnv *env, jobject thiz, jobject names) {
3037 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
3038
3039 if (codec == NULL || codec->initCheck() != OK) {
3040 throwExceptionAsNecessary(env, INVALID_OPERATION);
3041 return;
3042 }
3043
3044 status_t status = codec->unsubscribeFromVendorParameters(env, names);
3045 if (status != OK) {
3046 throwExceptionAsNecessary(env, status);
3047 }
3048 return;
3049}
3050
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003051static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003052 ScopedLocalRef<jclass> clazz(
3053 env, env->FindClass("android/media/MediaCodec"));
3054 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003055
Andreas Huberaba67132013-10-22 12:40:01 -07003056 gFields.postEventFromNativeID =
3057 env->GetMethodID(
3058 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003059 CHECK(gFields.postEventFromNativeID != NULL);
3060
Wonsik Kim61796fd2018-09-13 13:15:59 -07003061 gFields.lockAndGetContextID =
3062 env->GetMethodID(
3063 clazz.get(), "lockAndGetContext", "()J");
3064 CHECK(gFields.lockAndGetContextID != NULL);
3065
3066 gFields.setAndUnlockContextID =
3067 env->GetMethodID(
3068 clazz.get(), "setAndUnlockContext", "(J)V");
3069 CHECK(gFields.setAndUnlockContextID != NULL);
3070
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003071 jfieldID field;
3072 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3073 CHECK(field != NULL);
3074 gCryptoModes.Unencrypted =
3075 env->GetStaticIntField(clazz.get(), field);
3076
3077 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3078 CHECK(field != NULL);
3079 gCryptoModes.AesCtr =
3080 env->GetStaticIntField(clazz.get(), field);
3081
3082 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3083 CHECK(field != NULL);
3084 gCryptoModes.AesCbc =
3085 env->GetStaticIntField(clazz.get(), field);
3086
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003087 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3088 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003089
Arun Johnson5a4c7332022-12-17 00:47:06 +00003090 gFields.cryptoInfoSetID = env->GetMethodID(clazz.get(), "set", "(I[I[I[B[BI)V");
3091 CHECK(gFields.cryptoInfoSetID != NULL);
3092
3093 gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz.get(), "setPattern", "(II)V");
3094 CHECK(gFields.cryptoInfoSetPatternID != NULL);
3095
Andreas Huber91befdc2012-04-18 12:19:51 -07003096 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003097 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003098 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3099
3100 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003101 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003102 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3103
3104 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003105 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003106 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3107
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003108 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003109 CHECK(gFields.cryptoInfoKeyID != NULL);
3110
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003111 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003112 CHECK(gFields.cryptoInfoIVID != NULL);
3113
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003114 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003115 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003116
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003117 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003118 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3119 CHECK(gFields.cryptoInfoPatternID != NULL);
3120
3121 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3122 CHECK(clazz.get() != NULL);
3123
3124 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3125 CHECK(gFields.patternEncryptBlocksID != NULL);
3126
3127 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3128 CHECK(gFields.patternSkipBlocksID != NULL);
3129
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003130 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3131 CHECK(clazz.get() != NULL);
3132
3133 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3134 CHECK(gFields.queueRequestIndexID != NULL);
3135
3136 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3137 CHECK(clazz.get() != NULL);
3138
3139 gFields.outputFrameLinearBlockID =
3140 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3141 CHECK(gFields.outputFrameLinearBlockID != NULL);
3142
Wonsik Kim637afb22020-02-25 14:27:29 -08003143 gFields.outputFrameHardwareBufferID =
3144 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3145 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003146
3147 gFields.outputFrameChangedKeysID =
3148 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3149 CHECK(gFields.outputFrameChangedKeysID != NULL);
3150
3151 gFields.outputFrameFormatID =
3152 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3153 CHECK(gFields.outputFrameFormatID != NULL);
3154
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003155 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3156 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003157
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003158 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003159 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003160 gCryptoErrorCodes.cryptoErrorNoKey =
3161 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003162
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003163 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003164 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003165 gCryptoErrorCodes.cryptoErrorKeyExpired =
3166 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003167
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003168 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003169 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003170 gCryptoErrorCodes.cryptoErrorResourceBusy =
3171 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003172
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003173 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3174 CHECK(field != NULL);
3175 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3176 env->GetStaticIntField(clazz.get(), field);
3177
Jeff Tinker96a2a952015-07-01 17:35:18 -07003178 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3179 CHECK(field != NULL);
3180 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3181 env->GetStaticIntField(clazz.get(), field);
3182
Jeff Tinker20594d82018-12-12 08:31:22 -08003183 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3184 CHECK(field != NULL);
3185 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3186 env->GetStaticIntField(clazz.get(), field);
3187
Jeff Tinkerd3932162016-03-05 11:35:20 -08003188 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3189 CHECK(field != NULL);
3190 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3191 env->GetStaticIntField(clazz.get(), field);
3192
Jeff Tinker20594d82018-12-12 08:31:22 -08003193 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3194 CHECK(field != NULL);
3195 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3196 env->GetStaticIntField(clazz.get(), field);
3197
3198 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3199 CHECK(field != NULL);
3200 gCryptoErrorCodes.cryptoErrorLostState =
3201 env->GetStaticIntField(clazz.get(), field);
3202
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003203 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3204 CHECK(clazz.get() != NULL);
3205 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3206 CHECK(field != NULL);
3207 gCodecActionCodes.codecActionTransient =
3208 env->GetStaticIntField(clazz.get(), field);
3209
3210 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3211 CHECK(field != NULL);
3212 gCodecActionCodes.codecActionRecoverable =
3213 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003214
Ronghua Wuc53ad692015-05-08 14:40:49 -07003215 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003216 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003217 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003218 env->GetStaticIntField(clazz.get(), field);
3219
Ronghua Wuc53ad692015-05-08 14:40:49 -07003220 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003221 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003222 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003223 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003224
3225 clazz.reset(env->FindClass("android/view/Surface"));
3226 CHECK(clazz.get() != NULL);
3227
3228 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3229 CHECK(field != NULL);
3230 gPersistentSurfaceClassInfo.mLock = field;
3231
3232 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3233 CHECK(method != NULL);
3234 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3235
3236 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3237 CHECK(clazz.get() != NULL);
3238 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3239
3240 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3241 CHECK(method != NULL);
3242 gPersistentSurfaceClassInfo.ctor = method;
3243
3244 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3245 CHECK(field != NULL);
3246 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003247
3248 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3249 CHECK(clazz.get() != NULL);
3250 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3251
3252 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003253 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003254 "Ljava/util/Map;Ljava/util/Map;)V");
3255 CHECK(method != NULL);
3256 gCodecInfo.capsCtorId = method;
3257
3258 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3259 CHECK(clazz.get() != NULL);
3260 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3261
3262 field = env->GetFieldID(clazz.get(), "profile", "I");
3263 CHECK(field != NULL);
3264 gCodecInfo.profileField = field;
3265
3266 field = env->GetFieldID(clazz.get(), "level", "I");
3267 CHECK(field != NULL);
3268 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003269
3270 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3271 CHECK(clazz.get() != NULL);
3272 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3273
3274 ScopedLocalRef<jclass> byteOrderClass(
3275 env, env->FindClass("java/nio/ByteOrder"));
3276 CHECK(byteOrderClass.get() != NULL);
3277
3278 jmethodID nativeOrderID = env->GetStaticMethodID(
3279 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3280 CHECK(nativeOrderID != NULL);
3281
3282 ScopedLocalRef<jobject> nativeByteOrderObj{
3283 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3284 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3285 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3286 nativeByteOrderObj.reset();
3287
3288 gByteBufferInfo.orderId = env->GetMethodID(
3289 clazz.get(),
3290 "order",
3291 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3292 CHECK(gByteBufferInfo.orderId != NULL);
3293
3294 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3295 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3296 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3297
3298 gByteBufferInfo.positionId = env->GetMethodID(
3299 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3300 CHECK(gByteBufferInfo.positionId != NULL);
3301
3302 gByteBufferInfo.limitId = env->GetMethodID(
3303 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3304 CHECK(gByteBufferInfo.limitId != NULL);
3305
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003306 gByteBufferInfo.getPositionId = env->GetMethodID(
3307 clazz.get(), "position", "()I");
3308 CHECK(gByteBufferInfo.getPositionId != NULL);
3309
3310 gByteBufferInfo.getLimitId = env->GetMethodID(
3311 clazz.get(), "limit", "()I");
3312 CHECK(gByteBufferInfo.getLimitId != NULL);
3313
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003314 clazz.reset(env->FindClass("java/util/ArrayList"));
3315 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003316 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3317
3318 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3319 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003320
3321 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3322 CHECK(gArrayListInfo.sizeId != NULL);
3323
3324 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3325 CHECK(gArrayListInfo.getId != NULL);
3326
3327 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3328 CHECK(gArrayListInfo.addId != NULL);
3329
3330 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3331 CHECK(clazz.get() != NULL);
3332
3333 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3334
3335 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3336 CHECK(gLinearBlockInfo.ctorId != NULL);
3337
3338 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3339 clazz.get(), "setInternalStateLocked", "(JZ)V");
3340 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3341
3342 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3343 CHECK(gLinearBlockInfo.contextId != NULL);
3344
3345 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3346 CHECK(gLinearBlockInfo.validId != NULL);
3347
3348 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3349 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003350
3351 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3352 CHECK(clazz.get() != NULL);
3353 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3354
3355 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3356 CHECK(gDescriptorInfo.ctorId != NULL);
3357
3358 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3359 CHECK(gDescriptorInfo.nameId != NULL);
3360
3361 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3362 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003363
3364 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3365 CHECK(clazz.get() != NULL);
3366 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3367
3368 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3369 CHECK(gBufferInfo.ctorId != NULL);
3370
3371 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3372 CHECK(gBufferInfo.setId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003373}
3374
3375static void android_media_MediaCodec_native_setup(
3376 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003377 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003378 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003379 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003380 return;
3381 }
3382
3383 const char *tmp = env->GetStringUTFChars(name, NULL);
3384
3385 if (tmp == NULL) {
3386 return;
3387 }
3388
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003389 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003390
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003391 const status_t err = codec->initCheck();
3392 if (err == NAME_NOT_FOUND) {
3393 // fail and do not try again.
3394 jniThrowException(env, "java/lang/IllegalArgumentException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003395 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003396 env->ReleaseStringUTFChars(name, tmp);
3397 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003398 }
3399 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003400 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003401 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err));
Ronghua Wuc53ad692015-05-08 14:40:49 -07003402 env->ReleaseStringUTFChars(name, tmp);
3403 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003404 }
3405 if (err == PERMISSION_DENIED) {
3406 jniThrowException(env, "java/lang/SecurityException",
3407 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
3408 err));
3409 env->ReleaseStringUTFChars(name, tmp);
3410 return;
3411 }
3412 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003413 // believed possible to try again
3414 jniThrowException(env, "java/io/IOException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003415 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003416 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003417 return;
3418 }
3419
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003420 env->ReleaseStringUTFChars(name, tmp);
3421
Andreas Huberaba67132013-10-22 12:40:01 -07003422 codec->registerSelf();
3423
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003424 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003425}
3426
3427static void android_media_MediaCodec_native_finalize(
3428 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003429 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003430}
3431
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003432// MediaCodec.LinearBlock
3433
3434static jobject android_media_MediaCodec_LinearBlock_native_map(
3435 JNIEnv *env, jobject thiz) {
3436 JMediaCodecLinearBlock *context =
3437 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3438 if (context->mBuffer) {
3439 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3440 if (!context->mReadonlyMapping) {
3441 const C2BufferData data = buffer->data();
3442 if (data.type() != C2BufferData::LINEAR) {
3443 throwExceptionAsNecessary(env, INVALID_OPERATION);
3444 return nullptr;
3445 }
3446 if (data.linearBlocks().size() != 1u) {
3447 throwExceptionAsNecessary(env, INVALID_OPERATION);
3448 return nullptr;
3449 }
3450 C2ConstLinearBlock block = data.linearBlocks().front();
3451 context->mReadonlyMapping =
3452 std::make_shared<C2ReadView>(block.map().get());
3453 }
3454 return CreateByteBuffer(
3455 env,
3456 context->mReadonlyMapping->data(), // base
3457 context->mReadonlyMapping->capacity(), // capacity
3458 0u, // offset
3459 context->mReadonlyMapping->capacity(), // size
3460 true, // readOnly
3461 true /* clearBuffer */);
3462 } else if (context->mBlock) {
3463 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3464 if (!context->mReadWriteMapping) {
3465 context->mReadWriteMapping =
3466 std::make_shared<C2WriteView>(block->map().get());
3467 }
3468 return CreateByteBuffer(
3469 env,
3470 context->mReadWriteMapping->base(),
3471 context->mReadWriteMapping->capacity(),
3472 context->mReadWriteMapping->offset(),
3473 context->mReadWriteMapping->size(),
3474 false, // readOnly
3475 true /* clearBuffer */);
3476 } else if (context->mLegacyBuffer) {
3477 return CreateByteBuffer(
3478 env,
3479 context->mLegacyBuffer->base(),
3480 context->mLegacyBuffer->capacity(),
3481 context->mLegacyBuffer->offset(),
3482 context->mLegacyBuffer->size(),
3483 true, // readOnly
3484 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003485 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003486 return CreateByteBuffer(
3487 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003488 context->mMemory->unsecurePointer(),
3489 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003490 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003491 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003492 false, // readOnly
3493 true /* clearBuffer */);
3494 }
3495 throwExceptionAsNecessary(env, INVALID_OPERATION);
3496 return nullptr;
3497}
3498
3499static void android_media_MediaCodec_LinearBlock_native_recycle(
3500 JNIEnv *env, jobject thiz) {
3501 JMediaCodecLinearBlock *context =
3502 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003503 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003504 delete context;
3505}
3506
3507static void PopulateNamesVector(
3508 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3509 jsize length = env->GetArrayLength(codecNames);
3510 for (jsize i = 0; i < length; ++i) {
3511 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3512 if (jstr == nullptr) {
3513 // null entries are ignored
3514 continue;
3515 }
3516 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3517 if (cstr == nullptr) {
3518 throwExceptionAsNecessary(env, BAD_VALUE);
3519 return;
3520 }
3521 names->emplace_back(cstr);
3522 env->ReleaseStringUTFChars(jstr, cstr);
3523 }
3524}
3525
3526static void android_media_MediaCodec_LinearBlock_native_obtain(
3527 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3528 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3529 std::vector<std::string> names;
3530 PopulateNamesVector(env, codecNames, &names);
3531 bool hasSecure = false;
3532 bool hasNonSecure = false;
3533 for (const std::string &name : names) {
3534 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3535 hasSecure = true;
3536 } else {
3537 hasNonSecure = true;
3538 }
3539 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003540 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3541 jniThrowException(env, "java/io/IOException", nullptr);
3542 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003543 }
3544 env->CallVoidMethod(
3545 thiz,
3546 gLinearBlockInfo.setInternalStateId,
3547 (jlong)context.release(),
3548 true /* isMappable */);
3549}
3550
3551static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003552 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003553 std::vector<std::string> names;
3554 PopulateNamesVector(env, codecNames, &names);
3555 bool isCompatible = false;
3556 bool hasSecure = false;
3557 bool hasNonSecure = false;
3558 for (const std::string &name : names) {
3559 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3560 hasSecure = true;
3561 } else {
3562 hasNonSecure = true;
3563 }
3564 }
3565 if (hasSecure && hasNonSecure) {
3566 return false;
3567 }
3568 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3569 if (err != OK) {
3570 throwExceptionAsNecessary(env, err);
3571 }
3572 return isCompatible;
3573}
3574
Daniel Micay76f6a862015-09-19 17:31:01 -04003575static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003576 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003577
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003578 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3579
Chong Zhang8034d602015-04-28 13:38:48 -07003580 { "native_releasePersistentInputSurface",
3581 "(Landroid/view/Surface;)V",
3582 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3583
3584 { "native_createPersistentInputSurface",
3585 "()Landroid/media/MediaCodec$PersistentSurface;",
3586 (void *)android_media_MediaCodec_createPersistentInputSurface },
3587
Chong Zhang9560ddb2015-05-13 10:25:29 -07003588 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3589 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003590
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003591 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3592 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3593
Lajos Molnard8578572015-06-05 20:17:33 -07003594 { "native_enableOnFrameRenderedListener", "(Z)V",
3595 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3596
Chong Zhang8d5e5562014-07-08 18:49:21 -07003597 { "native_setCallback",
3598 "(Landroid/media/MediaCodec$Callback;)V",
3599 (void *)android_media_MediaCodec_native_setCallback },
3600
Andreas Huber88572f72012-02-21 11:47:18 -08003601 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003602 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003603 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003604 (void *)android_media_MediaCodec_native_configure },
3605
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003606 { "native_setSurface",
3607 "(Landroid/view/Surface;)V",
3608 (void *)android_media_MediaCodec_native_setSurface },
3609
Andy McFadden2621e402013-02-19 07:29:21 -08003610 { "createInputSurface", "()Landroid/view/Surface;",
3611 (void *)android_media_MediaCodec_createInputSurface },
3612
Lajos Molnard4023112014-07-11 15:12:59 -07003613 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003614 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003615 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003616
Lajos Molnard4023112014-07-11 15:12:59 -07003617 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003618 (void *)android_media_MediaCodec_queueInputBuffer },
3619
Lajos Molnard4023112014-07-11 15:12:59 -07003620 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003621 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3622
Wonsik Kim637afb22020-02-25 14:27:29 -08003623 { "native_mapHardwareBuffer",
3624 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3625 (void *)android_media_MediaCodec_mapHardwareBuffer },
3626
3627 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3628
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003629 { "native_queueLinearBlock",
3630 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3631 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3632 (void *)android_media_MediaCodec_native_queueLinearBlock },
3633
Wonsik Kim637afb22020-02-25 14:27:29 -08003634 { "native_queueHardwareBuffer",
3635 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3636 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003637
3638 { "native_getOutputFrame",
3639 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3640 (void *)android_media_MediaCodec_native_getOutputFrame },
3641
Lajos Molnard4023112014-07-11 15:12:59 -07003642 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003643 (void *)android_media_MediaCodec_dequeueInputBuffer },
3644
Lajos Molnard4023112014-07-11 15:12:59 -07003645 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003646 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3647
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003648 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003649 (void *)android_media_MediaCodec_releaseOutputBuffer },
3650
Andy McFadden2621e402013-02-19 07:29:21 -08003651 { "signalEndOfInputStream", "()V",
3652 (void *)android_media_MediaCodec_signalEndOfInputStream },
3653
Lajos Molnard4023112014-07-11 15:12:59 -07003654 { "getFormatNative", "(Z)Ljava/util/Map;",
3655 (void *)android_media_MediaCodec_getFormatNative },
3656
3657 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3658 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003659
3660 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3661 (void *)android_media_MediaCodec_getBuffers },
3662
Lajos Molnard4023112014-07-11 15:12:59 -07003663 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3664 (void *)android_media_MediaCodec_getBuffer },
3665
3666 { "getImage", "(ZI)Landroid/media/Image;",
3667 (void *)android_media_MediaCodec_getImage },
3668
Lajos Molnard2a7f472018-11-15 12:49:20 -08003669 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003670 (void *)android_media_MediaCodec_getName },
3671
Chong Zhanga0b72a62018-02-28 18:46:26 -08003672 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3673 (void *)android_media_MediaCodec_getOwnCodecInfo },
3674
Ray Essick10353e32017-04-14 10:22:55 -07003675 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003676 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003677
Andreas Huber226065b2013-08-12 10:14:11 -07003678 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3679 (void *)android_media_MediaCodec_setParameters },
3680
Andreas Huberb12a5392012-04-30 14:18:33 -07003681 { "setVideoScalingMode", "(I)V",
3682 (void *)android_media_MediaCodec_setVideoScalingMode },
3683
ybai5e053202018-11-01 13:02:15 +08003684 { "native_setAudioPresentation", "(II)V",
3685 (void *)android_media_MediaCodec_setAudioPresentation },
3686
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003687 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
3688 (void *)android_media_MediaCodec_getSupportedVendorParameters },
3689
3690 { "native_getParameterDescriptor",
3691 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
3692 (void *)android_media_MediaCodec_getParameterDescriptor },
3693
3694 { "native_subscribeToVendorParameters",
3695 "(Ljava/util/List;)V",
3696 (void *)android_media_MediaCodec_subscribeToVendorParameters},
3697
3698 { "native_unsubscribeFromVendorParameters",
3699 "(Ljava/util/List;)V",
3700 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
3701
Andreas Huber88572f72012-02-21 11:47:18 -08003702 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3703
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003704 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003705 (void *)android_media_MediaCodec_native_setup },
3706
3707 { "native_finalize", "()V",
3708 (void *)android_media_MediaCodec_native_finalize },
3709};
3710
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003711static const JNINativeMethod gLinearBlockMethods[] = {
3712 { "native_map", "()Ljava/nio/ByteBuffer;",
3713 (void *)android_media_MediaCodec_LinearBlock_native_map },
3714
3715 { "native_recycle", "()V",
3716 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3717
3718 { "native_obtain", "(I[Ljava/lang/String;)V",
3719 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3720
3721 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3722 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3723};
3724
Andreas Huber88572f72012-02-21 11:47:18 -08003725int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003726 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003727 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003728 if (result != JNI_OK) {
3729 return result;
3730 }
3731 result = AndroidRuntime::registerNativeMethods(env,
3732 "android/media/MediaCodec$LinearBlock",
3733 gLinearBlockMethods,
3734 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003735 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003736}