blob: d8705a7ce9ca179239f566d583fdff7ece8d5d0b [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;
Andreas Huber91befdc2012-04-18 12:19:51 -0700187 jfieldID cryptoInfoNumSubSamplesID;
188 jfieldID cryptoInfoNumBytesOfClearDataID;
189 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
190 jfieldID cryptoInfoKeyID;
191 jfieldID cryptoInfoIVID;
192 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800193 jfieldID cryptoInfoPatternID;
194 jfieldID patternEncryptBlocksID;
195 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800196 jfieldID queueRequestIndexID;
197 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800198 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800199 jfieldID outputFrameChangedKeysID;
200 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800201};
202
203static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700204static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800205
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800206
Andreas Huber88572f72012-02-21 11:47:18 -0800207////////////////////////////////////////////////////////////////////////////////
208
209JMediaCodec::JMediaCodec(
210 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100211 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800212 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700213 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800214 jclass clazz = env->GetObjectClass(thiz);
215 CHECK(clazz != NULL);
216
217 mClass = (jclass)env->NewGlobalRef(clazz);
218 mObject = env->NewWeakGlobalRef(thiz);
219
220 mLooper = new ALooper;
221 mLooper->setName("MediaCodec_looper");
222
223 mLooper->start(
224 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700225 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700226 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800227
228 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100229 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800230 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
231 mNameAtCreation = "(null)";
232 }
Andreas Huber88572f72012-02-21 11:47:18 -0800233 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100234 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800235 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800236 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700237 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800238}
239
240status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700241 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800242}
243
Andreas Huberaba67132013-10-22 12:40:01 -0700244void JMediaCodec::registerSelf() {
245 mLooper->registerHandler(this);
246}
247
Chong Zhang128b0122014-03-01 18:04:13 -0800248void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700249 std::call_once(mReleaseFlag, [this] {
250 if (mCodec != NULL) {
251 mCodec->release();
252 mInitStatus = NO_INIT;
253 }
Andreas Huber88572f72012-02-21 11:47:18 -0800254
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700255 if (mLooper != NULL) {
256 mLooper->unregisterHandler(id());
257 mLooper->stop();
258 mLooper.clear();
259 }
260 });
Chong Zhang128b0122014-03-01 18:04:13 -0800261}
262
Wonsik Kim89666622020-04-28 10:43:47 -0700263void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700264 std::call_once(mAsyncReleaseFlag, [this] {
265 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700266 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
267 // Hold strong reference to this until async release is complete
268 notify->setObject("this", this);
269 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700270 }
271 mInitStatus = NO_INIT;
272 });
Wonsik Kim89666622020-04-28 10:43:47 -0700273}
274
Chong Zhang128b0122014-03-01 18:04:13 -0800275JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700276 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800277 /* MediaCodec and looper should have been released explicitly already
278 * in setMediaCodec() (see comments in setMediaCodec()).
279 *
280 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
281 * message handler, doing release() there risks deadlock as MediaCodec::
282 * release() post synchronous message to the same looper.
283 *
284 * Print a warning and try to proceed with releasing.
285 */
286 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
287 release();
288 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
289 }
290
Andreas Huber88572f72012-02-21 11:47:18 -0800291 JNIEnv *env = AndroidRuntime::getJNIEnv();
292
293 env->DeleteWeakGlobalRef(mObject);
294 mObject = NULL;
295 env->DeleteGlobalRef(mClass);
296 mClass = NULL;
297}
298
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100299status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
300 if (enable) {
301 if (mOnFirstTunnelFrameReadyNotification == NULL) {
302 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
303 }
304 } else {
305 mOnFirstTunnelFrameReadyNotification.clear();
306 }
307
308 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
309}
310
Lajos Molnard8578572015-06-05 20:17:33 -0700311status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
312 if (enable) {
313 if (mOnFrameRenderedNotification == NULL) {
314 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
315 }
316 } else {
317 mOnFrameRenderedNotification.clear();
318 }
319
320 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
321}
322
Chong Zhang8d5e5562014-07-08 18:49:21 -0700323status_t JMediaCodec::setCallback(jobject cb) {
324 if (cb != NULL) {
325 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800326 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700327 }
328 } else {
329 mCallbackNotification.clear();
330 }
331
332 return mCodec->setCallback(mCallbackNotification);
333}
334
Andreas Huber88572f72012-02-21 11:47:18 -0800335status_t JMediaCodec::configure(
336 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800337 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700338 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800339 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800340 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800341 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800342 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700343 mSurfaceTextureClient =
344 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700345 } else {
346 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800347 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700348
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800349 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
350 AString mime;
351 CHECK(format->findString("mime", &mime));
352 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
353 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700354 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800355 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800356
Chong Zhangd5927ae2017-01-03 11:07:18 -0800357 return mCodec->configure(
358 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800359}
360
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700361status_t JMediaCodec::setSurface(
362 const sp<IGraphicBufferProducer> &bufferProducer) {
363 sp<Surface> client;
364 if (bufferProducer != NULL) {
365 client = new Surface(bufferProducer, true /* controlledByApp */);
366 }
367 status_t err = mCodec->setSurface(client);
368 if (err == OK) {
369 mSurfaceTextureClient = client;
370 }
371 return err;
372}
373
Andy McFadden2621e402013-02-19 07:29:21 -0800374status_t JMediaCodec::createInputSurface(
375 sp<IGraphicBufferProducer>* bufferProducer) {
376 return mCodec->createInputSurface(bufferProducer);
377}
378
Chong Zhang9560ddb2015-05-13 10:25:29 -0700379status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700380 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700381 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700382}
383
Andreas Huber88572f72012-02-21 11:47:18 -0800384status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700385 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800386}
387
388status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700389 mSurfaceTextureClient.clear();
390
Chong Zhang8d5e5562014-07-08 18:49:21 -0700391 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800392}
393
394status_t JMediaCodec::flush() {
395 return mCodec->flush();
396}
397
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700398status_t JMediaCodec::reset() {
399 return mCodec->reset();
400}
401
Andreas Huber88572f72012-02-21 11:47:18 -0800402status_t JMediaCodec::queueInputBuffer(
403 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700404 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
405 AString *errorDetailMsg) {
406 return mCodec->queueInputBuffer(
407 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800408}
409
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700410status_t JMediaCodec::queueSecureInputBuffer(
411 size_t index,
412 size_t offset,
413 const CryptoPlugin::SubSample *subSamples,
414 size_t numSubSamples,
415 const uint8_t key[16],
416 const uint8_t iv[16],
417 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800418 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700419 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700420 uint32_t flags,
421 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700422 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800423 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700424 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700425}
426
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800427status_t JMediaCodec::queueBuffer(
428 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
429 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
430 return mCodec->queueBuffer(
431 index, buffer, timeUs, flags, tunings, errorDetailMsg);
432}
433
434status_t JMediaCodec::queueEncryptedLinearBlock(
435 size_t index,
436 const sp<hardware::HidlMemory> &buffer,
437 size_t offset,
438 const CryptoPlugin::SubSample *subSamples,
439 size_t numSubSamples,
440 const uint8_t key[16],
441 const uint8_t iv[16],
442 CryptoPlugin::Mode mode,
443 const CryptoPlugin::Pattern &pattern,
444 int64_t presentationTimeUs,
445 uint32_t flags,
446 const sp<AMessage> &tunings,
447 AString *errorDetailMsg) {
448 return mCodec->queueEncryptedBuffer(
449 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
450 presentationTimeUs, flags, tunings, errorDetailMsg);
451}
452
Andreas Huber88572f72012-02-21 11:47:18 -0800453status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700454 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800455}
456
457status_t JMediaCodec::dequeueOutputBuffer(
458 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
459 size_t size, offset;
460 int64_t timeUs;
461 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700462 status_t err = mCodec->dequeueOutputBuffer(
463 index, &offset, &size, &timeUs, &flags, timeoutUs);
464
Andreas Huberaba67132013-10-22 12:40:01 -0700465 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800466 return err;
467 }
468
Pavel Laboviche53421b2022-11-01 03:53:27 +0000469 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800470
471 return OK;
472}
473
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700474status_t JMediaCodec::releaseOutputBuffer(
475 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
476 if (updatePTS) {
477 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
478 }
Andreas Huber88572f72012-02-21 11:47:18 -0800479 return render
480 ? mCodec->renderOutputBufferAndRelease(index)
481 : mCodec->releaseOutputBuffer(index);
482}
483
Andy McFadden2621e402013-02-19 07:29:21 -0800484status_t JMediaCodec::signalEndOfInputStream() {
485 return mCodec->signalEndOfInputStream();
486}
487
Lajos Molnard4023112014-07-11 15:12:59 -0700488status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800489 sp<AMessage> msg;
490 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700491 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
492 if (err != OK) {
493 return err;
494 }
495
496 return ConvertMessageToMap(env, msg, format);
497}
498
499status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
500 sp<AMessage> msg;
501 status_t err;
502 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800503 return err;
504 }
505
506 return ConvertMessageToMap(env, msg, format);
507}
508
509status_t JMediaCodec::getBuffers(
510 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900511 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800512
513 status_t err =
514 input
515 ? mCodec->getInputBuffers(&buffers)
516 : mCodec->getOutputBuffers(&buffers);
517
518 if (err != OK) {
519 return err;
520 }
521
Andreas Huber88572f72012-02-21 11:47:18 -0800522 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800523 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800524 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800525 return NO_MEMORY;
526 }
Andreas Huber88572f72012-02-21 11:47:18 -0800527
528 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900529 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800530
Lajos Molnar7de28d32014-07-25 07:51:02 -0700531 jobject byteBuffer = NULL;
532 err = createByteBufferFromABuffer(
533 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
534 if (err != OK) {
535 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800536 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700537 if (byteBuffer != NULL) {
538 env->SetObjectArrayElement(
539 *bufArray, i, byteBuffer);
540
Lajos Molnard4023112014-07-11 15:12:59 -0700541 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700542 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700543 }
Andreas Huber88572f72012-02-21 11:47:18 -0800544 }
545
Lajos Molnar7de28d32014-07-25 07:51:02 -0700546 return OK;
547}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700548
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800549template <typename T>
550static jobject CreateByteBuffer(
551 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
552 bool readOnly, bool clearBuffer) {
553 jobject byteBuffer =
554 env->NewDirectByteBuffer(
555 const_cast<typename std::remove_const<T>::type *>(base),
556 capacity);
557 if (readOnly && byteBuffer != NULL) {
558 jobject readOnlyBuffer = env->CallObjectMethod(
559 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
560 env->DeleteLocalRef(byteBuffer);
561 byteBuffer = readOnlyBuffer;
562 }
563 if (byteBuffer == NULL) {
564 return nullptr;
565 }
566 jobject me = env->CallObjectMethod(
567 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
568 env->DeleteLocalRef(me);
569 me = env->CallObjectMethod(
570 byteBuffer, gByteBufferInfo.limitId,
571 clearBuffer ? capacity : offset + size);
572 env->DeleteLocalRef(me);
573 me = env->CallObjectMethod(
574 byteBuffer, gByteBufferInfo.positionId,
575 clearBuffer ? 0 : offset);
576 env->DeleteLocalRef(me);
577 me = NULL;
578 return byteBuffer;
579}
580
581
Lajos Molnar7de28d32014-07-25 07:51:02 -0700582// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900583template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700584status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900585 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700586 jobject *buf) const {
587 // if this is an ABuffer that doesn't actually hold any accessible memory,
588 // use a null ByteBuffer
589 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700590
591 if (buffer == NULL) {
592 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
593 return OK;
594 }
595
Lajos Molnar7de28d32014-07-25 07:51:02 -0700596 if (buffer->base() == NULL) {
597 return OK;
598 }
599
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800600 jobject byteBuffer = CreateByteBuffer(
601 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
602 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700603
604 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800605 return OK;
606}
607
Lajos Molnard4023112014-07-11 15:12:59 -0700608status_t JMediaCodec::getBuffer(
609 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900610 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700611
612 status_t err =
613 input
614 ? mCodec->getInputBuffer(index, &buffer)
615 : mCodec->getOutputBuffer(index, &buffer);
616
617 if (err != OK) {
618 return err;
619 }
620
Lajos Molnar7de28d32014-07-25 07:51:02 -0700621 return createByteBufferFromABuffer(
622 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700623}
624
625status_t JMediaCodec::getImage(
626 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900627 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700628
629 status_t err =
630 input
631 ? mCodec->getInputBuffer(index, &buffer)
632 : mCodec->getOutputBuffer(index, &buffer);
633
634 if (err != OK) {
635 return err;
636 }
637
638 // if this is an ABuffer that doesn't actually hold any accessible memory,
639 // use a null ByteBuffer
640 *buf = NULL;
641 if (buffer->base() == NULL) {
642 return OK;
643 }
644
645 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700646 sp<ABuffer> imageData;
647 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700648 return OK;
649 }
650
Lajos Molnar7de28d32014-07-25 07:51:02 -0700651 int64_t timestamp = 0;
652 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
653 timestamp *= 1000; // adjust to ns
654 }
655
656 jobject byteBuffer = NULL;
657 err = createByteBufferFromABuffer(
658 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
659 if (err != OK) {
660 return OK;
661 }
662
663 jobject infoBuffer = NULL;
664 err = createByteBufferFromABuffer(
665 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
666 if (err != OK) {
667 env->DeleteLocalRef(byteBuffer);
668 byteBuffer = NULL;
669 return OK;
670 }
671
672 jobject cropRect = NULL;
673 int32_t left, top, right, bottom;
674 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
675 ScopedLocalRef<jclass> rectClazz(
676 env, env->FindClass("android/graphics/Rect"));
677 CHECK(rectClazz.get() != NULL);
678
679 jmethodID rectConstructID = env->GetMethodID(
680 rectClazz.get(), "<init>", "(IIII)V");
681
682 cropRect = env->NewObject(
683 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
684 }
685
686 ScopedLocalRef<jclass> imageClazz(
687 env, env->FindClass("android/media/MediaCodec$MediaImage"));
688 CHECK(imageClazz.get() != NULL);
689
690 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
691 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
692
693 *buf = env->NewObject(imageClazz.get(), imageConstructID,
694 byteBuffer, infoBuffer,
695 (jboolean)!input /* readOnly */,
696 (jlong)timestamp,
697 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
698
699 // if MediaImage creation fails, return null
700 if (env->ExceptionCheck()) {
701 env->ExceptionDescribe();
702 env->ExceptionClear();
703 *buf = NULL;
704 }
705
706 if (cropRect != NULL) {
707 env->DeleteLocalRef(cropRect);
708 cropRect = NULL;
709 }
710
711 env->DeleteLocalRef(byteBuffer);
712 byteBuffer = NULL;
713
714 env->DeleteLocalRef(infoBuffer);
715 infoBuffer = NULL;
716
Lajos Molnard4023112014-07-11 15:12:59 -0700717 return OK;
718}
719
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800720status_t JMediaCodec::getOutputFrame(
721 JNIEnv *env, jobject frame, size_t index) const {
722 sp<MediaCodecBuffer> buffer;
723
724 status_t err = mCodec->getOutputBuffer(index, &buffer);
725 if (err != OK) {
726 return err;
727 }
728
729 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800730 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800731 if (c2Buffer) {
732 switch (c2Buffer->data().type()) {
733 case C2BufferData::LINEAR: {
734 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700735 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800736 context->mBuffer = c2Buffer;
737 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
738 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800739 env->CallVoidMethod(
740 linearBlock.get(),
741 gLinearBlockInfo.setInternalStateId,
742 (jlong)context.release(),
743 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800744 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
745 break;
746 }
747 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800748 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
749 uint32_t width, height, format, stride, igbp_slot, generation;
750 uint64_t usage, igbp_id;
751 _UnwrapNativeCodec2GrallocMetadata(
752 c2Handle, &width, &height, &format, &usage, &stride, &generation,
753 &igbp_id, &igbp_slot);
754 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
755 GraphicBuffer* graphicBuffer = new GraphicBuffer(
756 grallocHandle, GraphicBuffer::CLONE_HANDLE,
757 width, height, format, 1, usage, stride);
758 ScopedLocalRef<jobject> hardwareBuffer{
759 env,
760 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
761 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
762 env->SetObjectField(
763 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800764 break;
765 }
766 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
767 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
768 case C2BufferData::INVALID: [[fallthrough]];
769 default:
770 return INVALID_OPERATION;
771 }
772 } else {
773 if (!mGraphicOutput) {
774 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700775 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800776 context->mLegacyBuffer = buffer;
777 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
778 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800779 env->CallVoidMethod(
780 linearBlock.get(),
781 gLinearBlockInfo.setInternalStateId,
782 (jlong)context.release(),
783 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800784 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
785 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800786 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800787 }
788 }
789 }
790
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700791 jobject formatMap;
792 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800793 if (err != OK) {
794 return err;
795 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700796 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
797 ScopedLocalRef<jobject> format{env, env->NewObject(
798 mediaFormatClass.get(),
799 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
800 formatMap)};
801 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
802 env->DeleteLocalRef(formatMap);
803 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800804
805 sp<RefBase> obj;
806 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
807 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
808 (decltype(changedKeys.get()))obj.get()};
809 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
810 frame, gFields.outputFrameChangedKeysID)};
811 for (const std::string &key : changedKeys->value) {
812 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
813 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
814 }
815 }
816 return OK;
817}
818
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300819status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
820 AString name;
821
822 status_t err = mCodec->getName(&name);
823
824 if (err != OK) {
825 return err;
826 }
827
828 *nameStr = env->NewStringUTF(name.c_str());
829
830 return OK;
831}
832
Chong Zhanga0b72a62018-02-28 18:46:26 -0800833static jobject getCodecCapabilitiesObject(
834 JNIEnv *env, const char *mime, bool isEncoder,
835 const sp<MediaCodecInfo::Capabilities> &capabilities) {
836 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
837 Vector<uint32_t> colorFormats;
838
839 sp<AMessage> defaultFormat = new AMessage();
840 defaultFormat->setString("mime", mime);
841
842 capabilities->getSupportedColorFormats(&colorFormats);
843 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800844 sp<AMessage> details = capabilities->getDetails();
845
846 jobject defaultFormatObj = NULL;
847 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
848 return NULL;
849 }
850 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
851
852 jobject detailsObj = NULL;
853 if (ConvertMessageToMap(env, details, &detailsObj)) {
854 return NULL;
855 }
856 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
857
858 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
859 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
860
861 for (size_t i = 0; i < profileLevels.size(); ++i) {
862 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
863
864 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
865 gCodecInfo.profileLevelClazz));
866
867 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
868 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
869
870 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
871 }
872
873 ScopedLocalRef<jintArray> colorFormatsArray(
874 env, env->NewIntArray(colorFormats.size()));
875 for (size_t i = 0; i < colorFormats.size(); ++i) {
876 jint val = colorFormats.itemAt(i);
877 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
878 }
879
880 return env->NewObject(
881 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800882 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800883 defaultFormatRef.get(), detailsRef.get());
884}
885
886status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
887 sp<MediaCodecInfo> codecInfo;
888
889 status_t err = mCodec->getCodecInfo(&codecInfo);
890
891 if (err != OK) {
892 return err;
893 }
894
895 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800896 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800897
Lajos Molnard2a7f472018-11-15 12:49:20 -0800898 ScopedLocalRef<jstring> canonicalNameObject(env,
899 env->NewStringUTF(codecInfo->getCodecName()));
900
901 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800902 bool isEncoder = codecInfo->isEncoder();
903
Lajos Molnard2a7f472018-11-15 12:49:20 -0800904 Vector<AString> mediaTypes;
905 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800906
907 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800908 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800909
Lajos Molnard2a7f472018-11-15 12:49:20 -0800910 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800911 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800912 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800913
914 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800915 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800916
917 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
918 }
919
920 ScopedLocalRef<jclass> codecInfoClazz(env,
921 env->FindClass("android/media/MediaCodecInfo"));
922 CHECK(codecInfoClazz.get() != NULL);
923
924 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800925 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800926
927 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800928 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800929
930 return OK;
931}
932
Ray Essick81fbc5b2019-12-07 06:24:59 -0800933status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
934 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700935 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700936 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800937 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800938 return status;
939}
940
Andreas Huber226065b2013-08-12 10:14:11 -0700941status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
942 return mCodec->setParameters(msg);
943}
944
Andreas Huberb12a5392012-04-30 14:18:33 -0700945void JMediaCodec::setVideoScalingMode(int mode) {
946 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700947 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700948 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700949 // also signal via param for components that queue to IGBP
950 sp<AMessage> msg = new AMessage;
951 msg->setInt32("android._video-scaling", mode);
952 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700953 }
954}
955
ybai5e053202018-11-01 13:02:15 +0800956void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
957 sp<AMessage> msg = new AMessage;
958 msg->setInt32("audio-presentation-presentation-id", presentationId);
959 msg->setInt32("audio-presentation-program-id", programId);
960 (void)mCodec->setParameters(msg);
961}
962
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700963status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
964 std::vector<std::string> names;
965 status_t status = mCodec->querySupportedVendorParameters(&names);
966 if (status != OK) {
967 return status;
968 }
969 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
970 for (const std::string &name : names) {
971 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
972 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
973 }
974 return OK;
975}
976
977status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
978 const char *tmp = env->GetStringUTFChars(name, nullptr);
979 CodecParameterDescriptor desc;
980 status_t status = mCodec->describeParameter(tmp, &desc);
981 env->ReleaseStringUTFChars(name, tmp);
982 if (status != OK) {
983 return status;
984 }
985 jint type = TYPE_NULL;
986 switch (desc.type) {
987 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
988 case AMessage::kTypeSize:
989 case AMessage::kTypeInt64: type = TYPE_LONG; break;
990 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
991 case AMessage::kTypeString: type = TYPE_STRING; break;
992 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
993 default: type = TYPE_NULL; break;
994 }
995 if (type == TYPE_NULL) {
996 return BAD_VALUE;
997 }
998 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
999 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1000 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1001 return OK;
1002}
1003
1004static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1005 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1006 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1007 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1008 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1009 jobject it = env->CallObjectMethod(
1010 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1011 while (env->CallBooleanMethod(it, hasNextID)) {
1012 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1013 const char *tmp = env->GetStringUTFChars(name, nullptr);
1014 vec->push_back(tmp);
1015 env->ReleaseStringUTFChars(name, tmp);
1016 }
1017}
1018
1019status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1020 std::vector<std::string> names;
1021 BuildVectorFromList(env, namesObj, &names);
1022 return mCodec->subscribeToVendorParameters(names);
1023}
1024
1025status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1026 std::vector<std::string> names;
1027 BuildVectorFromList(env, namesObj, &names);
1028 return mCodec->unsubscribeFromVendorParameters(names);
1029}
1030
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001031static jthrowable createCodecException(
1032 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1033 ScopedLocalRef<jclass> clazz(
1034 env, env->FindClass("android/media/MediaCodec$CodecException"));
1035 CHECK(clazz.get() != NULL);
1036
Ronghua Wuc53ad692015-05-08 14:40:49 -07001037 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001038 CHECK(ctor != NULL);
1039
1040 ScopedLocalRef<jstring> msgObj(
1041 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
1042
1043 // translate action code to Java equivalent
1044 switch (actionCode) {
1045 case ACTION_CODE_TRANSIENT:
1046 actionCode = gCodecActionCodes.codecActionTransient;
1047 break;
1048 case ACTION_CODE_RECOVERABLE:
1049 actionCode = gCodecActionCodes.codecActionRecoverable;
1050 break;
1051 default:
1052 actionCode = 0; // everything else is fatal
1053 break;
1054 }
1055
Ronghua Wuc53ad692015-05-08 14:40:49 -07001056 /* translate OS errors to Java API CodecException errorCodes */
1057 switch (err) {
1058 case NO_MEMORY:
1059 err = gCodecErrorCodes.errorInsufficientResource;
1060 break;
1061 case DEAD_OBJECT:
1062 err = gCodecErrorCodes.errorReclaimed;
1063 break;
1064 default: /* Other error codes go out as is. */
1065 break;
1066 }
1067
1068 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001069}
1070
Chong Zhang8d5e5562014-07-08 18:49:21 -07001071void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1072 int32_t arg1, arg2 = 0;
1073 jobject obj = NULL;
1074 CHECK(msg->findInt32("callbackID", &arg1));
1075 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001076
Chong Zhang8d5e5562014-07-08 18:49:21 -07001077 switch (arg1) {
1078 case MediaCodec::CB_INPUT_AVAILABLE:
1079 {
1080 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001081 break;
1082 }
1083
Chong Zhang8d5e5562014-07-08 18:49:21 -07001084 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001085 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001086 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001087
Chong Zhang8d5e5562014-07-08 18:49:21 -07001088 size_t size, offset;
1089 int64_t timeUs;
1090 uint32_t flags;
1091 CHECK(msg->findSize("size", &size));
1092 CHECK(msg->findSize("offset", &offset));
1093 CHECK(msg->findInt64("timeUs", &timeUs));
1094 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1095
Pavel Laboviche53421b2022-11-01 03:53:27 +00001096 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001097 if (obj == NULL) {
1098 if (env->ExceptionCheck()) {
1099 ALOGE("Could not create MediaCodec.BufferInfo.");
1100 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001101 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001102 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1103 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001104 }
1105
Pavel Laboviche53421b2022-11-01 03:53:27 +00001106 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001107 break;
1108 }
1109
1110 case MediaCodec::CB_ERROR:
1111 {
Chong Zhang94686d12014-07-11 15:53:58 -07001112 int32_t err, actionCode;
1113 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001114 CHECK(msg->findInt32("actionCode", &actionCode));
1115
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001116 // note that DRM errors could conceivably alias into a CodecException
1117 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001118
1119 if (obj == NULL) {
1120 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001121 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001122 env->ExceptionClear();
1123 }
1124 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1125 return;
1126 }
Andreas Huberaba67132013-10-22 12:40:01 -07001127
1128 break;
1129 }
1130
Chong Zhang8d5e5562014-07-08 18:49:21 -07001131 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001132 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001133 sp<AMessage> format;
1134 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001135
Chong Zhang8d5e5562014-07-08 18:49:21 -07001136 if (OK != ConvertMessageToMap(env, format, &obj)) {
1137 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1138 return;
1139 }
Andreas Huberaba67132013-10-22 12:40:01 -07001140
Andreas Huberaba67132013-10-22 12:40:01 -07001141 break;
1142 }
1143
1144 default:
1145 TRESPASS();
1146 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001147
1148 env->CallVoidMethod(
1149 mObject,
1150 gFields.postEventFromNativeID,
1151 EVENT_CALLBACK,
1152 arg1,
1153 arg2,
1154 obj);
1155
1156 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001157}
1158
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001159void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1160 int32_t arg1 = 0, arg2 = 0;
1161 jobject obj = NULL;
1162 JNIEnv *env = AndroidRuntime::getJNIEnv();
1163
1164 sp<AMessage> data;
1165 CHECK(msg->findMessage("data", &data));
1166
1167 status_t err = ConvertMessageToMap(env, data, &obj);
1168 if (err != OK) {
1169 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1170 return;
1171 }
1172
1173 env->CallVoidMethod(
1174 mObject, gFields.postEventFromNativeID,
1175 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1176
1177 env->DeleteLocalRef(obj);
1178}
1179
Lajos Molnard8578572015-06-05 20:17:33 -07001180void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1181 int32_t arg1 = 0, arg2 = 0;
1182 jobject obj = NULL;
1183 JNIEnv *env = AndroidRuntime::getJNIEnv();
1184
1185 sp<AMessage> data;
1186 CHECK(msg->findMessage("data", &data));
1187
1188 status_t err = ConvertMessageToMap(env, data, &obj);
1189 if (err != OK) {
1190 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1191 return;
1192 }
1193
1194 env->CallVoidMethod(
1195 mObject, gFields.postEventFromNativeID,
1196 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1197
1198 env->DeleteLocalRef(obj);
1199}
1200
Chong Zhang8d5e5562014-07-08 18:49:21 -07001201void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1202 switch (msg->what()) {
1203 case kWhatCallbackNotify:
1204 {
1205 handleCallback(msg);
1206 break;
1207 }
Lajos Molnard8578572015-06-05 20:17:33 -07001208 case kWhatFrameRendered:
1209 {
1210 handleFrameRenderedNotification(msg);
1211 break;
1212 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001213 case kWhatAsyncReleaseComplete:
1214 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001215 if (mLooper != NULL) {
1216 mLooper->unregisterHandler(id());
1217 mLooper->stop();
1218 mLooper.clear();
1219 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001220 break;
1221 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001222 case kWhatFirstTunnelFrameReady:
1223 {
1224 handleFirstTunnelFrameReadyNotification(msg);
1225 break;
1226 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001227 default:
1228 TRESPASS();
1229 }
Andreas Huberaba67132013-10-22 12:40:01 -07001230}
1231
Robert Shih631a80d2021-02-14 02:23:55 -08001232jint MediaErrorToJavaError(status_t err);
1233
Andreas Huber88572f72012-02-21 11:47:18 -08001234} // namespace android
1235
1236////////////////////////////////////////////////////////////////////////////////
1237
1238using namespace android;
1239
1240static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001241 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001242 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001243 if (codec != NULL) {
1244 codec->incStrong(thiz);
1245 }
1246 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001247 /* release MediaCodec and stop the looper now before decStrong.
1248 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1249 * its message handler, doing release() from there will deadlock
1250 * (as MediaCodec::release() post synchronous message to the same looper)
1251 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001252 if (release) {
1253 old->release();
1254 }
Andreas Huber88572f72012-02-21 11:47:18 -08001255 old->decStrong(thiz);
1256 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001257 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001258
1259 return old;
1260}
1261
1262static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001263 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1264 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1265 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001266}
1267
1268static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001269 // Clear Java native reference.
1270 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001271 if (codec != NULL) {
1272 codec->releaseAsync();
1273 }
Andreas Huber88572f72012-02-21 11:47:18 -08001274}
1275
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001276static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1277 jthrowable exception = createCodecException(env, err, actionCode, msg);
1278 env->Throw(exception);
1279}
1280
Robert Shih631a80d2021-02-14 02:23:55 -08001281static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1282 const sp<ICrypto> &crypto) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001283 ScopedLocalRef<jclass> clazz(
1284 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1285 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001286
1287 jmethodID constructID =
Robert Shih57f369a2022-12-16 12:47:27 -08001288 env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;IIII)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -07001289 CHECK(constructID != NULL);
1290
Robert Shih631a80d2021-02-14 02:23:55 -08001291 std::string defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -07001292
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001293 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Robert Shih390b6152022-05-10 10:42:29 -07001294 jint jerr = 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001295 switch (err) {
1296 case ERROR_DRM_NO_LICENSE:
Robert Shih390b6152022-05-10 10:42:29 -07001297 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001298 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001299 break;
1300 case ERROR_DRM_LICENSE_EXPIRED:
Robert Shih390b6152022-05-10 10:42:29 -07001301 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001302 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001303 break;
1304 case ERROR_DRM_RESOURCE_BUSY:
Robert Shih390b6152022-05-10 10:42:29 -07001305 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001306 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001307 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001308 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
Robert Shih390b6152022-05-10 10:42:29 -07001309 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001310 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001311 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001312 case ERROR_DRM_SESSION_NOT_OPENED:
Robert Shih390b6152022-05-10 10:42:29 -07001313 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001314 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001315 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001316 case ERROR_DRM_INSUFFICIENT_SECURITY:
Robert Shih390b6152022-05-10 10:42:29 -07001317 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
Jeff Tinker20594d82018-12-12 08:31:22 -08001318 defaultMsg = "Required security level is not met";
1319 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001320 case ERROR_DRM_CANNOT_HANDLE:
Robert Shih390b6152022-05-10 10:42:29 -07001321 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001322 defaultMsg = "Operation not supported in this configuration";
1323 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001324 case ERROR_DRM_FRAME_TOO_LARGE:
Robert Shih390b6152022-05-10 10:42:29 -07001325 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
Jeff Tinker20594d82018-12-12 08:31:22 -08001326 defaultMsg = "Decrytped frame exceeds size of output buffer";
1327 break;
1328 case ERROR_DRM_SESSION_LOST_STATE:
Robert Shih390b6152022-05-10 10:42:29 -07001329 jerr = gCryptoErrorCodes.cryptoErrorLostState;
Jeff Tinker20594d82018-12-12 08:31:22 -08001330 defaultMsg = "Session state was lost, open a new session and retry";
1331 break;
Robert Shih631a80d2021-02-14 02:23:55 -08001332 default: /* Other negative DRM error codes go out best-effort. */
Robert Shih390b6152022-05-10 10:42:29 -07001333 jerr = MediaErrorToJavaError(err);
Robert Shih631a80d2021-02-14 02:23:55 -08001334 defaultMsg = StrCryptoError(err);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001335 break;
1336 }
1337
Robert Shih57f369a2022-12-16 12:47:27 -08001338 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1339 DrmStatus dStatus(err, originalMsg.c_str());
1340 std::string detailedMsg(DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1341 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001342
Andreas Huberbfc56f42012-04-19 12:47:07 -07001343 jthrowable exception =
Robert Shih57f369a2022-12-16 12:47:27 -08001344 (jthrowable)env->NewObject(clazz.get(), constructID, msgObj, jerr,
1345 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext());
Andreas Huberbfc56f42012-04-19 12:47:07 -07001346
1347 env->Throw(exception);
1348}
1349
1350static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001351 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Robert Shih631a80d2021-02-14 02:23:55 -08001352 const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001353 switch (err) {
1354 case OK:
1355 return 0;
1356
1357 case -EAGAIN:
1358 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1359
1360 case INFO_FORMAT_CHANGED:
1361 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1362
1363 case INFO_OUTPUT_BUFFERS_CHANGED:
1364 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1365
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001366 case INVALID_OPERATION:
1367 jniThrowException(env, "java/lang/IllegalStateException", msg);
1368 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001369
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001370 case BAD_VALUE:
1371 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1372 return 0;
1373
Andreas Huber88572f72012-02-21 11:47:18 -08001374 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001375 if (isCryptoError(err)) {
Robert Shih631a80d2021-02-14 02:23:55 -08001376 throwCryptoException(env, err, msg, crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001377 return 0;
1378 }
1379 throwCodecException(env, err, actionCode, msg);
1380 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001381 }
Andreas Huber88572f72012-02-21 11:47:18 -08001382}
1383
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001384static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1385 JNIEnv *env,
1386 jobject thiz,
1387 jboolean enabled) {
1388 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1389
1390 if (codec == NULL || codec->initCheck() != OK) {
1391 throwExceptionAsNecessary(env, INVALID_OPERATION);
1392 return;
1393 }
1394
1395 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1396
1397 throwExceptionAsNecessary(env, err);
1398}
1399
Lajos Molnard8578572015-06-05 20:17:33 -07001400static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1401 JNIEnv *env,
1402 jobject thiz,
1403 jboolean enabled) {
1404 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1405
Wonsik Kim24e53802020-05-08 20:04:26 -07001406 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnard8578572015-06-05 20:17:33 -07001407 throwExceptionAsNecessary(env, INVALID_OPERATION);
1408 return;
1409 }
1410
1411 status_t err = codec->enableOnFrameRenderedListener(enabled);
1412
1413 throwExceptionAsNecessary(env, err);
1414}
1415
Chong Zhang8d5e5562014-07-08 18:49:21 -07001416static void android_media_MediaCodec_native_setCallback(
1417 JNIEnv *env,
1418 jobject thiz,
1419 jobject cb) {
1420 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1421
Wonsik Kim24e53802020-05-08 20:04:26 -07001422 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001423 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001424 return;
1425 }
1426
1427 status_t err = codec->setCallback(cb);
1428
1429 throwExceptionAsNecessary(env, err);
1430}
1431
Andreas Huber88572f72012-02-21 11:47:18 -08001432static void android_media_MediaCodec_native_configure(
1433 JNIEnv *env,
1434 jobject thiz,
1435 jobjectArray keys, jobjectArray values,
1436 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001437 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001438 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001439 jint flags) {
1440 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1441
Wonsik Kim24e53802020-05-08 20:04:26 -07001442 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001443 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001444 return;
1445 }
1446
1447 sp<AMessage> format;
1448 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1449
1450 if (err != OK) {
1451 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1452 return;
1453 }
1454
Andy McFaddend47f7d82012-12-18 09:48:38 -08001455 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001456 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001457 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001458 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001459 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001460 } else {
1461 jniThrowException(
1462 env,
1463 "java/lang/IllegalArgumentException",
1464 "The surface has been released");
1465 return;
1466 }
1467 }
1468
Andreas Huber8240d922012-04-04 14:06:32 -07001469 sp<ICrypto> crypto;
1470 if (jcrypto != NULL) {
1471 crypto = JCrypto::GetCrypto(env, jcrypto);
1472 }
1473
Chong Zhangd5927ae2017-01-03 11:07:18 -08001474 sp<IDescrambler> descrambler;
1475 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001476 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001477 }
1478
1479 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001480
1481 throwExceptionAsNecessary(env, err);
1482}
1483
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001484static void android_media_MediaCodec_native_setSurface(
1485 JNIEnv *env,
1486 jobject thiz,
1487 jobject jsurface) {
1488 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1489
Wonsik Kim24e53802020-05-08 20:04:26 -07001490 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001491 throwExceptionAsNecessary(env, INVALID_OPERATION);
1492 return;
1493 }
1494
1495 sp<IGraphicBufferProducer> bufferProducer;
1496 if (jsurface != NULL) {
1497 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1498 if (surface != NULL) {
1499 bufferProducer = surface->getIGraphicBufferProducer();
1500 } else {
1501 jniThrowException(
1502 env,
1503 "java/lang/IllegalArgumentException",
1504 "The surface has been released");
1505 return;
1506 }
1507 }
1508
1509 status_t err = codec->setSurface(bufferProducer);
1510 throwExceptionAsNecessary(env, err);
1511}
1512
Chong Zhang8034d602015-04-28 13:38:48 -07001513sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1514 JNIEnv* env, jobject object) {
1515 sp<PersistentSurface> persistentSurface;
1516
1517 jobject lock = env->GetObjectField(
1518 object, gPersistentSurfaceClassInfo.mLock);
1519 if (env->MonitorEnter(lock) == JNI_OK) {
1520 persistentSurface = reinterpret_cast<PersistentSurface *>(
1521 env->GetLongField(object,
1522 gPersistentSurfaceClassInfo.mPersistentObject));
1523 env->MonitorExit(lock);
1524 }
1525 env->DeleteLocalRef(lock);
1526
1527 return persistentSurface;
1528}
1529
1530static jobject android_media_MediaCodec_createPersistentInputSurface(
1531 JNIEnv* env, jclass /* clazz */) {
1532 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1533 sp<PersistentSurface> persistentSurface =
1534 MediaCodec::CreatePersistentInputSurface();
1535
1536 if (persistentSurface == NULL) {
1537 return NULL;
1538 }
1539
1540 sp<Surface> surface = new Surface(
1541 persistentSurface->getBufferProducer(), true);
1542 if (surface == NULL) {
1543 return NULL;
1544 }
1545
1546 jobject object = env->NewObject(
1547 gPersistentSurfaceClassInfo.clazz,
1548 gPersistentSurfaceClassInfo.ctor);
1549
1550 if (object == NULL) {
1551 if (env->ExceptionCheck()) {
1552 ALOGE("Could not create PersistentSurface.");
1553 env->ExceptionClear();
1554 }
1555 return NULL;
1556 }
1557
1558 jobject lock = env->GetObjectField(
1559 object, gPersistentSurfaceClassInfo.mLock);
1560 if (env->MonitorEnter(lock) == JNI_OK) {
1561 env->CallVoidMethod(
1562 object,
1563 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1564 (jlong)surface.get());
1565 env->SetLongField(
1566 object,
1567 gPersistentSurfaceClassInfo.mPersistentObject,
1568 (jlong)persistentSurface.get());
1569 env->MonitorExit(lock);
1570 } else {
1571 env->DeleteLocalRef(object);
1572 object = NULL;
1573 }
1574 env->DeleteLocalRef(lock);
1575
1576 if (object != NULL) {
1577 surface->incStrong(&sRefBaseOwner);
1578 persistentSurface->incStrong(&sRefBaseOwner);
1579 }
1580
1581 return object;
1582}
1583
1584static void android_media_MediaCodec_releasePersistentInputSurface(
1585 JNIEnv* env, jclass /* clazz */, jobject object) {
1586 sp<PersistentSurface> persistentSurface;
1587
1588 jobject lock = env->GetObjectField(
1589 object, gPersistentSurfaceClassInfo.mLock);
1590 if (env->MonitorEnter(lock) == JNI_OK) {
1591 persistentSurface = reinterpret_cast<PersistentSurface *>(
1592 env->GetLongField(
1593 object, gPersistentSurfaceClassInfo.mPersistentObject));
1594 env->SetLongField(
1595 object,
1596 gPersistentSurfaceClassInfo.mPersistentObject,
1597 (jlong)0);
1598 env->MonitorExit(lock);
1599 }
1600 env->DeleteLocalRef(lock);
1601
1602 if (persistentSurface != NULL) {
1603 persistentSurface->decStrong(&sRefBaseOwner);
1604 }
1605 // no need to release surface as it will be released by Surface's jni
1606}
1607
Chong Zhang9560ddb2015-05-13 10:25:29 -07001608static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001609 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001610 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001611
1612 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001613 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhang8034d602015-04-28 13:38:48 -07001614 throwExceptionAsNecessary(env, INVALID_OPERATION);
1615 return;
1616 }
1617
1618 sp<PersistentSurface> persistentSurface =
1619 android_media_MediaCodec_getPersistentInputSurface(env, object);
1620
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001621 if (persistentSurface == NULL) {
1622 throwExceptionAsNecessary(
1623 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1624 return;
1625 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001626 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001627 if (err != NO_ERROR) {
1628 throwExceptionAsNecessary(env, err);
1629 }
1630}
1631
Andy McFadden2621e402013-02-19 07:29:21 -08001632static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1633 jobject thiz) {
1634 ALOGV("android_media_MediaCodec_createInputSurface");
1635
1636 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001637 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001638 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001639 return NULL;
1640 }
1641
1642 // Tell the MediaCodec that we want to use a Surface as input.
1643 sp<IGraphicBufferProducer> bufferProducer;
1644 status_t err = codec->createInputSurface(&bufferProducer);
1645 if (err != NO_ERROR) {
1646 throwExceptionAsNecessary(env, err);
1647 return NULL;
1648 }
1649
1650 // Wrap the IGBP in a Java-language Surface.
1651 return android_view_Surface_createFromIGraphicBufferProducer(env,
1652 bufferProducer);
1653}
1654
Andreas Huber88572f72012-02-21 11:47:18 -08001655static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1656 ALOGV("android_media_MediaCodec_start");
1657
1658 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1659
Wonsik Kim24e53802020-05-08 20:04:26 -07001660 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001661 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001662 return;
1663 }
1664
1665 status_t err = codec->start();
1666
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001667 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001668}
1669
1670static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1671 ALOGV("android_media_MediaCodec_stop");
1672
1673 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1674
Wonsik Kim24e53802020-05-08 20:04:26 -07001675 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001676 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001677 return;
1678 }
1679
1680 status_t err = codec->stop();
1681
1682 throwExceptionAsNecessary(env, err);
1683}
1684
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001685static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1686 ALOGV("android_media_MediaCodec_reset");
1687
1688 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1689
Wonsik Kim24e53802020-05-08 20:04:26 -07001690 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001691 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001692 return;
1693 }
1694
1695 status_t err = codec->reset();
1696 if (err != OK) {
1697 // treat all errors as fatal for now, though resource not available
1698 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001699 // we also should avoid sending INVALID_OPERATION here due to
1700 // the transitory nature of reset(), it should not inadvertently
1701 // trigger an IllegalStateException.
1702 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001703 }
1704 throwExceptionAsNecessary(env, err);
1705}
1706
Andreas Huber88572f72012-02-21 11:47:18 -08001707static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1708 ALOGV("android_media_MediaCodec_flush");
1709
1710 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1711
Wonsik Kim24e53802020-05-08 20:04:26 -07001712 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001713 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001714 return;
1715 }
1716
1717 status_t err = codec->flush();
1718
1719 throwExceptionAsNecessary(env, err);
1720}
1721
1722static void android_media_MediaCodec_queueInputBuffer(
1723 JNIEnv *env,
1724 jobject thiz,
1725 jint index,
1726 jint offset,
1727 jint size,
1728 jlong timestampUs,
1729 jint flags) {
1730 ALOGV("android_media_MediaCodec_queueInputBuffer");
1731
1732 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1733
Wonsik Kim24e53802020-05-08 20:04:26 -07001734 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001735 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001736 return;
1737 }
1738
Andreas Huberbfc56f42012-04-19 12:47:07 -07001739 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001740
Andreas Huberbfc56f42012-04-19 12:47:07 -07001741 status_t err = codec->queueInputBuffer(
1742 index, offset, size, timestampUs, flags, &errorDetailMsg);
1743
1744 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001745 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001746}
1747
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001748struct NativeCryptoInfo {
1749 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1750 : mEnv{env},
1751 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1752 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1753 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1754
1755 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1756 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1757
1758 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1759 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1760
1761 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1762 if (jmode == gCryptoModes.Unencrypted) {
1763 mMode = CryptoPlugin::kMode_Unencrypted;
1764 } else if (jmode == gCryptoModes.AesCtr) {
1765 mMode = CryptoPlugin::kMode_AES_CTR;
1766 } else if (jmode == gCryptoModes.AesCbc) {
1767 mMode = CryptoPlugin::kMode_AES_CBC;
1768 } else {
1769 throwExceptionAsNecessary(env, INVALID_OPERATION);
1770 return;
1771 }
1772
1773 ScopedLocalRef<jobject> patternObj{
1774 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1775
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001776 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001777 mPattern.mEncryptBlocks = 0;
1778 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001779 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001780 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001781 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001782 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001783 patternObj.get(), gFields.patternSkipBlocksID);
1784 }
1785
1786 mErr = OK;
1787 if (mNumSubSamples <= 0) {
1788 mErr = -EINVAL;
1789 } else if (numBytesOfClearDataObj == nullptr
1790 && numBytesOfEncryptedDataObj == nullptr) {
1791 mErr = -EINVAL;
1792 } else if (numBytesOfEncryptedDataObj != nullptr
1793 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1794 mErr = -ERANGE;
1795 } else if (numBytesOfClearDataObj != nullptr
1796 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1797 mErr = -ERANGE;
1798 // subSamples array may silently overflow if number of samples are too large. Use
1799 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1800 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1801 mErr = -EINVAL;
1802 } else {
1803 jint *numBytesOfClearData =
1804 (numBytesOfClearDataObj == nullptr)
1805 ? nullptr
1806 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1807
1808 jint *numBytesOfEncryptedData =
1809 (numBytesOfEncryptedDataObj == nullptr)
1810 ? nullptr
1811 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1812
1813 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1814
1815 for (jint i = 0; i < mNumSubSamples; ++i) {
1816 mSubSamples[i].mNumBytesOfClearData =
1817 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1818
1819 mSubSamples[i].mNumBytesOfEncryptedData =
1820 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1821 }
1822
1823 if (numBytesOfEncryptedData != nullptr) {
1824 env->ReleaseIntArrayElements(
1825 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1826 numBytesOfEncryptedData = nullptr;
1827 }
1828
1829 if (numBytesOfClearData != nullptr) {
1830 env->ReleaseIntArrayElements(
1831 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1832 numBytesOfClearData = nullptr;
1833 }
1834 }
1835
1836 if (mErr == OK && mKeyObj.get() != nullptr) {
1837 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1838 mErr = -EINVAL;
1839 } else {
1840 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1841 }
1842 }
1843
1844 if (mErr == OK && mIvObj.get() != nullptr) {
1845 if (env->GetArrayLength(mIvObj.get()) != 16) {
1846 mErr = -EINVAL;
1847 } else {
1848 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1849 }
1850 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001851
1852 }
1853
1854 explicit NativeCryptoInfo(jint size)
1855 : mIvObj{nullptr, nullptr},
1856 mKeyObj{nullptr, nullptr},
1857 mMode{CryptoPlugin::kMode_Unencrypted},
1858 mPattern{0, 0} {
1859 mSubSamples = new CryptoPlugin::SubSample[1];
1860 mNumSubSamples = 1;
1861 mSubSamples[0].mNumBytesOfClearData = size;
1862 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001863 }
1864
1865 ~NativeCryptoInfo() {
1866 if (mIv != nullptr) {
1867 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1868 }
1869
1870 if (mKey != nullptr) {
1871 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1872 }
1873
1874 if (mSubSamples != nullptr) {
1875 delete[] mSubSamples;
1876 }
1877 }
1878
1879 JNIEnv *mEnv{nullptr};
1880 ScopedLocalRef<jbyteArray> mIvObj;
1881 ScopedLocalRef<jbyteArray> mKeyObj;
1882 status_t mErr{OK};
1883
1884 CryptoPlugin::SubSample *mSubSamples{nullptr};
1885 int32_t mNumSubSamples{0};
1886 jbyte *mIv{nullptr};
1887 jbyte *mKey{nullptr};
1888 enum CryptoPlugin::Mode mMode;
1889 CryptoPlugin::Pattern mPattern;
1890};
1891
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001892static void android_media_MediaCodec_queueSecureInputBuffer(
1893 JNIEnv *env,
1894 jobject thiz,
1895 jint index,
1896 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001897 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001898 jlong timestampUs,
1899 jint flags) {
1900 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1901
1902 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1903
Wonsik Kim24e53802020-05-08 20:04:26 -07001904 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001905 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001906 return;
1907 }
1908
Wonsik Kim1cac4252020-01-24 11:45:37 -08001909 jint numSubSamples =
1910 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1911
1912 jintArray numBytesOfClearDataObj =
1913 (jintArray)env->GetObjectField(
1914 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1915
1916 jintArray numBytesOfEncryptedDataObj =
1917 (jintArray)env->GetObjectField(
1918 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1919
1920 jbyteArray keyObj =
1921 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1922
1923 jbyteArray ivObj =
1924 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1925
1926 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1927 enum CryptoPlugin::Mode mode;
1928 if (jmode == gCryptoModes.Unencrypted) {
1929 mode = CryptoPlugin::kMode_Unencrypted;
1930 } else if (jmode == gCryptoModes.AesCtr) {
1931 mode = CryptoPlugin::kMode_AES_CTR;
1932 } else if (jmode == gCryptoModes.AesCbc) {
1933 mode = CryptoPlugin::kMode_AES_CBC;
1934 } else {
1935 throwExceptionAsNecessary(env, INVALID_OPERATION);
1936 return;
1937 }
1938
1939 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1940
1941 CryptoPlugin::Pattern pattern;
1942 if (patternObj == NULL) {
1943 pattern.mEncryptBlocks = 0;
1944 pattern.mSkipBlocks = 0;
1945 } else {
1946 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1947 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1948 }
1949
1950 status_t err = OK;
1951
1952 CryptoPlugin::SubSample *subSamples = NULL;
1953 jbyte *key = NULL;
1954 jbyte *iv = NULL;
1955
1956 if (numSubSamples <= 0) {
1957 err = -EINVAL;
1958 } else if (numBytesOfClearDataObj == NULL
1959 && numBytesOfEncryptedDataObj == NULL) {
1960 err = -EINVAL;
1961 } else if (numBytesOfEncryptedDataObj != NULL
1962 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1963 err = -ERANGE;
1964 } else if (numBytesOfClearDataObj != NULL
1965 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1966 err = -ERANGE;
1967 // subSamples array may silently overflow if number of samples are too large. Use
1968 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1969 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1970 err = -EINVAL;
1971 } else {
1972 jboolean isCopy;
1973
1974 jint *numBytesOfClearData =
1975 (numBytesOfClearDataObj == NULL)
1976 ? NULL
1977 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1978
1979 jint *numBytesOfEncryptedData =
1980 (numBytesOfEncryptedDataObj == NULL)
1981 ? NULL
1982 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1983
1984 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1985
1986 for (jint i = 0; i < numSubSamples; ++i) {
1987 subSamples[i].mNumBytesOfClearData =
1988 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1989
1990 subSamples[i].mNumBytesOfEncryptedData =
1991 (numBytesOfEncryptedData == NULL)
1992 ? 0 : numBytesOfEncryptedData[i];
1993 }
1994
1995 if (numBytesOfEncryptedData != NULL) {
1996 env->ReleaseIntArrayElements(
1997 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1998 numBytesOfEncryptedData = NULL;
1999 }
2000
2001 if (numBytesOfClearData != NULL) {
2002 env->ReleaseIntArrayElements(
2003 numBytesOfClearDataObj, numBytesOfClearData, 0);
2004 numBytesOfClearData = NULL;
2005 }
2006 }
2007
2008 if (err == OK && keyObj != NULL) {
2009 if (env->GetArrayLength(keyObj) != 16) {
2010 err = -EINVAL;
2011 } else {
2012 jboolean isCopy;
2013 key = env->GetByteArrayElements(keyObj, &isCopy);
2014 }
2015 }
2016
2017 if (err == OK && ivObj != NULL) {
2018 if (env->GetArrayLength(ivObj) != 16) {
2019 err = -EINVAL;
2020 } else {
2021 jboolean isCopy;
2022 iv = env->GetByteArrayElements(ivObj, &isCopy);
2023 }
2024 }
2025
Andreas Huberbfc56f42012-04-19 12:47:07 -07002026 AString errorDetailMsg;
2027
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002028 if (err == OK) {
2029 err = codec->queueSecureInputBuffer(
2030 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002031 subSamples, numSubSamples,
2032 (const uint8_t *)key, (const uint8_t *)iv,
2033 mode,
2034 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002035 timestampUs,
2036 flags,
2037 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002038 }
2039
Wonsik Kim1cac4252020-01-24 11:45:37 -08002040 if (iv != NULL) {
2041 env->ReleaseByteArrayElements(ivObj, iv, 0);
2042 iv = NULL;
2043 }
2044
2045 if (key != NULL) {
2046 env->ReleaseByteArrayElements(keyObj, key, 0);
2047 key = NULL;
2048 }
2049
2050 delete[] subSamples;
2051 subSamples = NULL;
2052
Andreas Huberbfc56f42012-04-19 12:47:07 -07002053 throwExceptionAsNecessary(
Robert Shih631a80d2021-02-14 02:23:55 -08002054 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
2055 codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002056}
2057
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002058static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002059 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2060 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2061 env, bufferObj);
2062 AHardwareBuffer_Desc desc;
2063 AHardwareBuffer_describe(hardwareBuffer, &desc);
2064 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2065 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2066 return nullptr;
2067 }
2068 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2069 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2070 return nullptr;
2071 }
2072 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2073
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002074 uint64_t cpuUsage = 0;
2075 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2076 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002077
2078 AHardwareBuffer_Planes planes;
2079 int err = AHardwareBuffer_lockPlanes(
2080 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2081 if (err != 0) {
2082 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2083 return nullptr;
2084 }
2085
2086 if (planes.planeCount != 3) {
2087 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2088 return nullptr;
2089 }
2090
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002091 ScopedLocalRef<jobjectArray> buffersArray{
2092 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2093 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2094 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002095
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002096 jboolean isCopy = JNI_FALSE;
2097 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2098 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2099
2100 // For Y plane
2101 int rowSampling = 1;
2102 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002103 // plane indices are Y-U-V.
2104 for (uint32_t i = 0; i < 3; ++i) {
2105 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002106 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2107 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2108 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002109 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2110 env,
2111 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002112 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002113 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002114 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002115 readOnly,
2116 true)};
2117
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002118 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2119 rowStrides[i] = plane.rowStride;
2120 pixelStrides[i] = plane.pixelStride;
2121 // For U-V planes
2122 rowSampling = 2;
2123 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002124 }
2125
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002126 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2127 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2128 rowStrides = pixelStrides = nullptr;
2129
Wonsik Kim637afb22020-02-25 14:27:29 -08002130 ScopedLocalRef<jclass> imageClazz(
2131 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2132 CHECK(imageClazz.get() != NULL);
2133
2134 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002135 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002136
2137 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002138 buffersArray.get(),
2139 rowStridesArray.get(),
2140 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002141 desc.width,
2142 desc.height,
2143 desc.format, // ???
2144 (jboolean)readOnly /* readOnly */,
2145 (jlong)0 /* timestamp */,
2146 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2147 (jlong)hardwareBuffer);
2148
2149 // if MediaImage creation fails, return null
2150 if (env->ExceptionCheck()) {
2151 env->ExceptionDescribe();
2152 env->ExceptionClear();
2153 return nullptr;
2154 }
2155
2156 AHardwareBuffer_acquire(hardwareBuffer);
2157
2158 return img;
2159}
2160
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002161static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2162 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002163 if (context == 0) {
2164 return;
2165 }
2166 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2167
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002168 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2169 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002170 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2171 // Continue to release the hardwareBuffer
2172 }
2173
2174 AHardwareBuffer_release(hardwareBuffer);
2175}
2176
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002177static status_t ConvertKeyValueListsToAMessage(
2178 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2179 static struct Fields {
2180 explicit Fields(JNIEnv *env) {
2181 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2182 CHECK(clazz.get() != NULL);
2183 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2184
2185 clazz.reset(env->FindClass("java/lang/Integer"));
2186 CHECK(clazz.get() != NULL);
2187 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2188
2189 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2190 CHECK(mIntegerValueId != NULL);
2191
2192 clazz.reset(env->FindClass("java/lang/Long"));
2193 CHECK(clazz.get() != NULL);
2194 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2195
2196 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2197 CHECK(mLongValueId != NULL);
2198
2199 clazz.reset(env->FindClass("java/lang/Float"));
2200 CHECK(clazz.get() != NULL);
2201 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2202
2203 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2204 CHECK(mFloatValueId != NULL);
2205
2206 clazz.reset(env->FindClass("java/util/ArrayList"));
2207 CHECK(clazz.get() != NULL);
2208
2209 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2210 CHECK(mByteBufferArrayId != NULL);
2211 }
2212
2213 jclass mStringClass;
2214 jclass mIntegerClass;
2215 jmethodID mIntegerValueId;
2216 jclass mLongClass;
2217 jmethodID mLongValueId;
2218 jclass mFloatClass;
2219 jmethodID mFloatValueId;
2220 jmethodID mByteBufferArrayId;
2221 } sFields{env};
2222
2223 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2224 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2225 return BAD_VALUE;
2226 }
2227
2228 sp<AMessage> result{new AMessage};
2229 for (jint i = 0; i < size; ++i) {
2230 ScopedLocalRef<jstring> jkey{
2231 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2232 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2233 AString key;
2234 if (tmp) {
2235 key.setTo(tmp);
2236 }
2237 env->ReleaseStringUTFChars(jkey.get(), tmp);
2238 if (key.empty()) {
2239 return NO_MEMORY;
2240 }
2241
2242 ScopedLocalRef<jobject> jvalue{
2243 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2244
2245 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2246 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2247 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002248 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002249 return NO_MEMORY;
2250 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002251 value.setTo(tmp);
2252 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002253 result->setString(key.c_str(), value);
2254 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2255 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2256 result->setInt32(key.c_str(), value);
2257 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2258 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2259 result->setInt64(key.c_str(), value);
2260 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2261 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2262 result->setFloat(key.c_str(), value);
2263 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002264 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2265 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002266 sp<ABuffer> buffer{new ABuffer(limit - position)};
2267 void *data = env->GetDirectBufferAddress(jvalue.get());
2268 if (data != nullptr) {
2269 memcpy(buffer->data(),
2270 static_cast<const uint8_t *>(data) + position,
2271 buffer->size());
2272 } else {
2273 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2274 jvalue.get(), sFields.mByteBufferArrayId)};
2275 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2276 reinterpret_cast<jbyte *>(buffer->data()));
2277 }
2278 result->setBuffer(key.c_str(), buffer);
2279 }
2280 }
2281
2282 *msg = result;
2283 return OK;
2284}
2285
Wonsik Kim8569a662022-05-24 14:16:44 -07002286static bool obtain(
2287 JMediaCodecLinearBlock *context,
2288 int capacity,
2289 const std::vector<std::string> &names,
2290 bool secure) {
2291 if (secure) {
2292 // Start at 1MB, which is an arbitrary starting point that can
2293 // increase when needed.
2294 constexpr size_t kInitialDealerCapacity = 1048576;
2295 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2296 kInitialDealerCapacity, "JNI(1MB)");
2297 context->mMemory = sDealer->allocate(capacity);
2298 if (context->mMemory == nullptr) {
2299 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2300 while (capacity * 2 > newDealerCapacity) {
2301 newDealerCapacity *= 2;
2302 }
2303 ALOGI("LinearBlock.native_obtain: "
2304 "Dealer capacity increasing from %zuMB to %zuMB",
2305 sDealer->getMemoryHeap()->getSize() / 1048576,
2306 newDealerCapacity / 1048576);
2307 sDealer = new MemoryDealer(
2308 newDealerCapacity,
2309 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2310 context->mMemory = sDealer->allocate(capacity);
2311 }
2312 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2313 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2314 } else {
2315 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2316 if (!context->mBlock) {
2317 return false;
2318 }
2319 }
2320 context->mCodecNames = names;
2321 return true;
2322}
2323
2324static void extractMemoryFromContext(
2325 JMediaCodecLinearBlock *context,
2326 jint offset,
2327 jint size,
2328 sp<hardware::HidlMemory> *memory) {
2329 *memory = context->toHidlMemory();
2330 if (*memory == nullptr) {
2331 if (!context->mBlock) {
2332 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2333 return;
2334 }
2335 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2336 context->capacity());
2337 if (!obtain(context, context->capacity(),
2338 context->mCodecNames, true /* secure */)) {
2339 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2340 return;
2341 }
2342 C2WriteView view = context->mBlock->map().get();
2343 if (view.error() != C2_OK) {
2344 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2345 return;
2346 }
2347 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2348 memcpy(memoryPtr + offset, view.base() + offset, size);
2349 context->mBlock.reset();
2350 context->mReadWriteMapping.reset();
2351 *memory = context->toHidlMemory();
2352 }
2353}
2354
2355static void extractBufferFromContext(
2356 JMediaCodecLinearBlock *context,
2357 jint offset,
2358 jint size,
2359 std::shared_ptr<C2Buffer> *buffer) {
2360 *buffer = context->toC2Buffer(offset, size);
2361 if (*buffer == nullptr) {
2362 if (!context->mMemory) {
2363 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2364 return;
2365 }
2366 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2367 context->capacity());
2368 if (obtain(context, context->capacity(),
2369 context->mCodecNames, false /* secure */)) {
2370 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2371 return;
2372 }
2373 C2WriteView view = context->mBlock->map().get();
2374 if (view.error() != C2_OK) {
2375 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2376 return;
2377 }
2378 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2379 memcpy(view.base() + offset, memoryPtr + offset, size);
2380 context->mMemory.clear();
2381 context->mHidlMemory.clear();
2382 context->mHidlMemorySize = 0;
2383 context->mHidlMemoryOffset = 0;
2384 *buffer = context->toC2Buffer(offset, size);
2385 }
2386}
2387
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002388static void android_media_MediaCodec_native_queueLinearBlock(
2389 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2390 jint offset, jint size, jobject cryptoInfoObj,
2391 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2392 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2393
2394 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2395
Wonsik Kim24e53802020-05-08 20:04:26 -07002396 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002397 throwExceptionAsNecessary(env, INVALID_OPERATION);
2398 return;
2399 }
2400
2401 sp<AMessage> tunings;
2402 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2403 if (err != OK) {
2404 throwExceptionAsNecessary(env, err);
2405 return;
2406 }
2407
2408 std::shared_ptr<C2Buffer> buffer;
2409 sp<hardware::HidlMemory> memory;
2410 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2411 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2412 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2413 JMediaCodecLinearBlock *context =
2414 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002415 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kim8569a662022-05-24 14:16:44 -07002416 extractMemoryFromContext(context, offset, size, &memory);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002417 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002418 } else {
Wonsik Kim8569a662022-05-24 14:16:44 -07002419 extractBufferFromContext(context, offset, size, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002420 }
2421 }
2422 env->MonitorExit(lock.get());
2423 } else {
2424 throwExceptionAsNecessary(env, INVALID_OPERATION);
2425 return;
2426 }
2427
2428 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002429 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002430 if (!memory) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002431 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002432 throwExceptionAsNecessary(env, BAD_VALUE);
2433 return;
2434 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002435 NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
2436 if (cryptoInfoObj == nullptr) {
2437 return NativeCryptoInfo{size};
2438 } else {
2439 return NativeCryptoInfo{env, cryptoInfoObj};
2440 }
2441 }();
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002442 err = codec->queueEncryptedLinearBlock(
2443 index,
2444 memory,
2445 offset,
2446 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2447 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2448 cryptoInfo.mMode,
2449 cryptoInfo.mPattern,
2450 presentationTimeUs,
2451 flags,
2452 tunings,
2453 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002454 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002455 } else {
2456 if (!buffer) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002457 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002458 throwExceptionAsNecessary(env, BAD_VALUE);
2459 return;
2460 }
2461 err = codec->queueBuffer(
2462 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2463 }
2464 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2465}
2466
Wonsik Kim637afb22020-02-25 14:27:29 -08002467static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002468 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2469 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002470 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002471
2472 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2473
Wonsik Kim24e53802020-05-08 20:04:26 -07002474 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002475 throwExceptionAsNecessary(env, INVALID_OPERATION);
2476 return;
2477 }
2478
2479 sp<AMessage> tunings;
2480 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2481 if (err != OK) {
2482 throwExceptionAsNecessary(env, err);
2483 return;
2484 }
2485
Wonsik Kim637afb22020-02-25 14:27:29 -08002486 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2487 env, bufferObj);
2488 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2489 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002490 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2491 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2492 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2493 std::shared_ptr<C2Allocator> alloc;
2494 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2495 C2PlatformAllocatorStore::GRALLOC, &alloc);
2496 if (err == C2_OK) {
2497 return alloc;
2498 }
2499 return nullptr;
2500 }();
2501 std::shared_ptr<C2GraphicAllocation> alloc;
2502 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2503 if (c2err != C2_OK) {
2504 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002505 native_handle_close(handle);
2506 native_handle_delete(handle);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002507 throwExceptionAsNecessary(env, BAD_VALUE);
2508 return;
2509 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002510 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002511 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2512 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002513 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002514 err = codec->queueBuffer(
2515 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002516 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2517}
2518
2519static void android_media_MediaCodec_native_getOutputFrame(
2520 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2521 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2522
2523 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2524
Wonsik Kim24e53802020-05-08 20:04:26 -07002525 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002526 throwExceptionAsNecessary(env, INVALID_OPERATION);
2527 return;
2528 }
2529
2530 status_t err = codec->getOutputFrame(env, frame, index);
2531 if (err != OK) {
2532 throwExceptionAsNecessary(env, err);
2533 }
2534}
2535
Andreas Huber88572f72012-02-21 11:47:18 -08002536static jint android_media_MediaCodec_dequeueInputBuffer(
2537 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2538 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2539
2540 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2541
Wonsik Kim24e53802020-05-08 20:04:26 -07002542 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002543 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002544 return -1;
2545 }
2546
2547 size_t index;
2548 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2549
2550 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002551 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002552 }
2553
2554 return throwExceptionAsNecessary(env, err);
2555}
2556
2557static jint android_media_MediaCodec_dequeueOutputBuffer(
2558 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2559 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2560
2561 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2562
Wonsik Kim24e53802020-05-08 20:04:26 -07002563 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002564 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002565 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002566 }
2567
2568 size_t index;
2569 status_t err = codec->dequeueOutputBuffer(
2570 env, bufferInfo, &index, timeoutUs);
2571
2572 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002573 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002574 }
2575
2576 return throwExceptionAsNecessary(env, err);
2577}
2578
2579static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002580 JNIEnv *env, jobject thiz,
2581 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002582 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2583
2584 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2585
Wonsik Kim24e53802020-05-08 20:04:26 -07002586 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002587 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002588 return;
2589 }
2590
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002591 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002592
2593 throwExceptionAsNecessary(env, err);
2594}
2595
Andy McFadden2621e402013-02-19 07:29:21 -08002596static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2597 jobject thiz) {
2598 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2599
2600 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002601 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002602 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08002603 return;
2604 }
2605
2606 status_t err = codec->signalEndOfInputStream();
2607
2608 throwExceptionAsNecessary(env, err);
2609}
2610
Lajos Molnard4023112014-07-11 15:12:59 -07002611static jobject android_media_MediaCodec_getFormatNative(
2612 JNIEnv *env, jobject thiz, jboolean input) {
2613 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002614
2615 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2616
Wonsik Kim24e53802020-05-08 20:04:26 -07002617 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002618 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002619 return NULL;
2620 }
2621
2622 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002623 status_t err = codec->getFormat(env, input, &format);
2624
2625 if (err == OK) {
2626 return format;
2627 }
2628
2629 throwExceptionAsNecessary(env, err);
2630
2631 return NULL;
2632}
2633
2634static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2635 JNIEnv *env, jobject thiz, jint index) {
2636 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2637
2638 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2639
Wonsik Kim24e53802020-05-08 20:04:26 -07002640 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002641 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002642 return NULL;
2643 }
2644
2645 jobject format;
2646 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002647
2648 if (err == OK) {
2649 return format;
2650 }
2651
2652 throwExceptionAsNecessary(env, err);
2653
2654 return NULL;
2655}
2656
2657static jobjectArray android_media_MediaCodec_getBuffers(
2658 JNIEnv *env, jobject thiz, jboolean input) {
2659 ALOGV("android_media_MediaCodec_getBuffers");
2660
2661 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2662
Wonsik Kim24e53802020-05-08 20:04:26 -07002663 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002664 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002665 return NULL;
2666 }
2667
2668 jobjectArray buffers;
2669 status_t err = codec->getBuffers(env, input, &buffers);
2670
2671 if (err == OK) {
2672 return buffers;
2673 }
2674
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002675 // if we're out of memory, an exception was already thrown
2676 if (err != NO_MEMORY) {
2677 throwExceptionAsNecessary(env, err);
2678 }
Andreas Huber88572f72012-02-21 11:47:18 -08002679
2680 return NULL;
2681}
2682
Lajos Molnard4023112014-07-11 15:12:59 -07002683static jobject android_media_MediaCodec_getBuffer(
2684 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2685 ALOGV("android_media_MediaCodec_getBuffer");
2686
2687 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2688
Wonsik Kim24e53802020-05-08 20:04:26 -07002689 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002690 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002691 return NULL;
2692 }
2693
2694 jobject buffer;
2695 status_t err = codec->getBuffer(env, input, index, &buffer);
2696
2697 if (err == OK) {
2698 return buffer;
2699 }
2700
2701 // if we're out of memory, an exception was already thrown
2702 if (err != NO_MEMORY) {
2703 throwExceptionAsNecessary(env, err);
2704 }
2705
2706 return NULL;
2707}
2708
2709static jobject android_media_MediaCodec_getImage(
2710 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2711 ALOGV("android_media_MediaCodec_getImage");
2712
2713 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2714
Wonsik Kim24e53802020-05-08 20:04:26 -07002715 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002716 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002717 return NULL;
2718 }
2719
2720 jobject image;
2721 status_t err = codec->getImage(env, input, index, &image);
2722
2723 if (err == OK) {
2724 return image;
2725 }
2726
2727 // if we're out of memory, an exception was already thrown
2728 if (err != NO_MEMORY) {
2729 throwExceptionAsNecessary(env, err);
2730 }
2731
2732 return NULL;
2733}
2734
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002735static jobject android_media_MediaCodec_getName(
2736 JNIEnv *env, jobject thiz) {
2737 ALOGV("android_media_MediaCodec_getName");
2738
2739 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2740
Wonsik Kim24e53802020-05-08 20:04:26 -07002741 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002742 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002743 return NULL;
2744 }
2745
2746 jstring name;
2747 status_t err = codec->getName(env, &name);
2748
2749 if (err == OK) {
2750 return name;
2751 }
2752
2753 throwExceptionAsNecessary(env, err);
2754
2755 return NULL;
2756}
2757
Chong Zhanga0b72a62018-02-28 18:46:26 -08002758static jobject android_media_MediaCodec_getOwnCodecInfo(
2759 JNIEnv *env, jobject thiz) {
2760 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2761
2762 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2763
Wonsik Kim24e53802020-05-08 20:04:26 -07002764 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhanga0b72a62018-02-28 18:46:26 -08002765 throwExceptionAsNecessary(env, INVALID_OPERATION);
2766 return NULL;
2767 }
2768
2769 jobject codecInfoObj;
2770 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2771
2772 if (err == OK) {
2773 return codecInfoObj;
2774 }
2775
2776 throwExceptionAsNecessary(env, err);
2777
2778 return NULL;
2779}
2780
Ray Essick0e0fee12017-01-25 18:01:56 -08002781static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002782android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002783{
Ray Essickf2d0e402017-03-09 10:17:51 -08002784 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002785
2786 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002787 if (codec == NULL || codec->initCheck() != OK) {
Ray Essick0e0fee12017-01-25 18:01:56 -08002788 jniThrowException(env, "java/lang/IllegalStateException", NULL);
2789 return 0;
2790 }
2791
2792 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002793 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002794
2795 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002796 if (err != OK) {
2797 ALOGE("getMetrics failed");
2798 return (jobject) NULL;
2799 }
2800
Ray Essick0e0fee12017-01-25 18:01:56 -08002801 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2802
2803 // housekeeping
2804 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002805 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002806
2807 return mybundle;
2808}
2809
Andreas Huber226065b2013-08-12 10:14:11 -07002810static void android_media_MediaCodec_setParameters(
2811 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2812 ALOGV("android_media_MediaCodec_setParameters");
2813
2814 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2815
Wonsik Kim24e53802020-05-08 20:04:26 -07002816 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002817 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07002818 return;
2819 }
2820
2821 sp<AMessage> params;
2822 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2823
2824 if (err == OK) {
2825 err = codec->setParameters(params);
2826 }
2827
2828 throwExceptionAsNecessary(env, err);
2829}
2830
Andreas Huberb12a5392012-04-30 14:18:33 -07002831static void android_media_MediaCodec_setVideoScalingMode(
2832 JNIEnv *env, jobject thiz, jint mode) {
2833 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2834
Wonsik Kim24e53802020-05-08 20:04:26 -07002835 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002836 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07002837 return;
2838 }
2839
2840 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2841 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07002842 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07002843 return;
2844 }
2845
2846 codec->setVideoScalingMode(mode);
2847}
2848
ybai5e053202018-11-01 13:02:15 +08002849static void android_media_MediaCodec_setAudioPresentation(
2850 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2851 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2852
Wonsik Kim24e53802020-05-08 20:04:26 -07002853 if (codec == NULL || codec->initCheck() != OK) {
ybai5e053202018-11-01 13:02:15 +08002854 throwExceptionAsNecessary(env, INVALID_OPERATION);
2855 return;
2856 }
2857
2858 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2859}
2860
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002861static jobject android_media_MediaCodec_getSupportedVendorParameters(
2862 JNIEnv *env, jobject thiz) {
2863 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2864
2865 if (codec == NULL || codec->initCheck() != OK) {
2866 throwExceptionAsNecessary(env, INVALID_OPERATION);
2867 return NULL;
2868 }
2869
2870 jobject ret = NULL;
2871 status_t status = codec->querySupportedVendorParameters(env, &ret);
2872 if (status != OK) {
2873 throwExceptionAsNecessary(env, status);
2874 }
2875
2876 return ret;
2877}
2878
2879static jobject android_media_MediaCodec_getParameterDescriptor(
2880 JNIEnv *env, jobject thiz, jstring name) {
2881 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2882
2883 if (codec == NULL || codec->initCheck() != OK) {
2884 throwExceptionAsNecessary(env, INVALID_OPERATION);
2885 return NULL;
2886 }
2887
2888 jobject ret = NULL;
2889 status_t status = codec->describeParameter(env, name, &ret);
2890 if (status != OK) {
2891 ret = NULL;
2892 }
2893 return ret;
2894}
2895
2896static void android_media_MediaCodec_subscribeToVendorParameters(
2897 JNIEnv *env, jobject thiz, jobject names) {
2898 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2899
2900 if (codec == NULL || codec->initCheck() != OK) {
2901 throwExceptionAsNecessary(env, INVALID_OPERATION);
2902 return;
2903 }
2904
2905 status_t status = codec->subscribeToVendorParameters(env, names);
2906 if (status != OK) {
2907 throwExceptionAsNecessary(env, status);
2908 }
2909 return;
2910}
2911
2912static void android_media_MediaCodec_unsubscribeFromVendorParameters(
2913 JNIEnv *env, jobject thiz, jobject names) {
2914 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2915
2916 if (codec == NULL || codec->initCheck() != OK) {
2917 throwExceptionAsNecessary(env, INVALID_OPERATION);
2918 return;
2919 }
2920
2921 status_t status = codec->unsubscribeFromVendorParameters(env, names);
2922 if (status != OK) {
2923 throwExceptionAsNecessary(env, status);
2924 }
2925 return;
2926}
2927
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07002928static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002929 ScopedLocalRef<jclass> clazz(
2930 env, env->FindClass("android/media/MediaCodec"));
2931 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002932
Andreas Huberaba67132013-10-22 12:40:01 -07002933 gFields.postEventFromNativeID =
2934 env->GetMethodID(
2935 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07002936 CHECK(gFields.postEventFromNativeID != NULL);
2937
Wonsik Kim61796fd2018-09-13 13:15:59 -07002938 gFields.lockAndGetContextID =
2939 env->GetMethodID(
2940 clazz.get(), "lockAndGetContext", "()J");
2941 CHECK(gFields.lockAndGetContextID != NULL);
2942
2943 gFields.setAndUnlockContextID =
2944 env->GetMethodID(
2945 clazz.get(), "setAndUnlockContext", "(J)V");
2946 CHECK(gFields.setAndUnlockContextID != NULL);
2947
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002948 jfieldID field;
2949 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
2950 CHECK(field != NULL);
2951 gCryptoModes.Unencrypted =
2952 env->GetStaticIntField(clazz.get(), field);
2953
2954 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
2955 CHECK(field != NULL);
2956 gCryptoModes.AesCtr =
2957 env->GetStaticIntField(clazz.get(), field);
2958
2959 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
2960 CHECK(field != NULL);
2961 gCryptoModes.AesCbc =
2962 env->GetStaticIntField(clazz.get(), field);
2963
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002964 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
2965 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07002966
2967 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002968 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002969 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
2970
2971 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002972 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002973 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
2974
2975 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002976 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002977 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
2978
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002979 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002980 CHECK(gFields.cryptoInfoKeyID != NULL);
2981
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002982 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002983 CHECK(gFields.cryptoInfoIVID != NULL);
2984
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002985 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002986 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002987
Santiago Seifert09ae5f62020-09-18 16:51:04 +01002988 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002989 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
2990 CHECK(gFields.cryptoInfoPatternID != NULL);
2991
2992 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
2993 CHECK(clazz.get() != NULL);
2994
2995 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
2996 CHECK(gFields.patternEncryptBlocksID != NULL);
2997
2998 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
2999 CHECK(gFields.patternSkipBlocksID != NULL);
3000
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003001 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3002 CHECK(clazz.get() != NULL);
3003
3004 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3005 CHECK(gFields.queueRequestIndexID != NULL);
3006
3007 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3008 CHECK(clazz.get() != NULL);
3009
3010 gFields.outputFrameLinearBlockID =
3011 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3012 CHECK(gFields.outputFrameLinearBlockID != NULL);
3013
Wonsik Kim637afb22020-02-25 14:27:29 -08003014 gFields.outputFrameHardwareBufferID =
3015 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3016 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003017
3018 gFields.outputFrameChangedKeysID =
3019 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3020 CHECK(gFields.outputFrameChangedKeysID != NULL);
3021
3022 gFields.outputFrameFormatID =
3023 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3024 CHECK(gFields.outputFrameFormatID != NULL);
3025
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003026 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3027 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003028
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003029 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003030 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003031 gCryptoErrorCodes.cryptoErrorNoKey =
3032 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003033
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003034 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003035 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003036 gCryptoErrorCodes.cryptoErrorKeyExpired =
3037 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003038
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003039 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003040 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003041 gCryptoErrorCodes.cryptoErrorResourceBusy =
3042 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003043
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003044 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3045 CHECK(field != NULL);
3046 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3047 env->GetStaticIntField(clazz.get(), field);
3048
Jeff Tinker96a2a952015-07-01 17:35:18 -07003049 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3050 CHECK(field != NULL);
3051 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3052 env->GetStaticIntField(clazz.get(), field);
3053
Jeff Tinker20594d82018-12-12 08:31:22 -08003054 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3055 CHECK(field != NULL);
3056 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3057 env->GetStaticIntField(clazz.get(), field);
3058
Jeff Tinkerd3932162016-03-05 11:35:20 -08003059 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3060 CHECK(field != NULL);
3061 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3062 env->GetStaticIntField(clazz.get(), field);
3063
Jeff Tinker20594d82018-12-12 08:31:22 -08003064 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3065 CHECK(field != NULL);
3066 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3067 env->GetStaticIntField(clazz.get(), field);
3068
3069 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3070 CHECK(field != NULL);
3071 gCryptoErrorCodes.cryptoErrorLostState =
3072 env->GetStaticIntField(clazz.get(), field);
3073
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003074 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3075 CHECK(clazz.get() != NULL);
3076 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3077 CHECK(field != NULL);
3078 gCodecActionCodes.codecActionTransient =
3079 env->GetStaticIntField(clazz.get(), field);
3080
3081 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3082 CHECK(field != NULL);
3083 gCodecActionCodes.codecActionRecoverable =
3084 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003085
Ronghua Wuc53ad692015-05-08 14:40:49 -07003086 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003087 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003088 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003089 env->GetStaticIntField(clazz.get(), field);
3090
Ronghua Wuc53ad692015-05-08 14:40:49 -07003091 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003092 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003093 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003094 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003095
3096 clazz.reset(env->FindClass("android/view/Surface"));
3097 CHECK(clazz.get() != NULL);
3098
3099 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3100 CHECK(field != NULL);
3101 gPersistentSurfaceClassInfo.mLock = field;
3102
3103 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3104 CHECK(method != NULL);
3105 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3106
3107 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3108 CHECK(clazz.get() != NULL);
3109 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3110
3111 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3112 CHECK(method != NULL);
3113 gPersistentSurfaceClassInfo.ctor = method;
3114
3115 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3116 CHECK(field != NULL);
3117 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003118
3119 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3120 CHECK(clazz.get() != NULL);
3121 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3122
3123 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003124 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003125 "Ljava/util/Map;Ljava/util/Map;)V");
3126 CHECK(method != NULL);
3127 gCodecInfo.capsCtorId = method;
3128
3129 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3130 CHECK(clazz.get() != NULL);
3131 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3132
3133 field = env->GetFieldID(clazz.get(), "profile", "I");
3134 CHECK(field != NULL);
3135 gCodecInfo.profileField = field;
3136
3137 field = env->GetFieldID(clazz.get(), "level", "I");
3138 CHECK(field != NULL);
3139 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003140
3141 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3142 CHECK(clazz.get() != NULL);
3143 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3144
3145 ScopedLocalRef<jclass> byteOrderClass(
3146 env, env->FindClass("java/nio/ByteOrder"));
3147 CHECK(byteOrderClass.get() != NULL);
3148
3149 jmethodID nativeOrderID = env->GetStaticMethodID(
3150 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3151 CHECK(nativeOrderID != NULL);
3152
3153 ScopedLocalRef<jobject> nativeByteOrderObj{
3154 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3155 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3156 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3157 nativeByteOrderObj.reset();
3158
3159 gByteBufferInfo.orderId = env->GetMethodID(
3160 clazz.get(),
3161 "order",
3162 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3163 CHECK(gByteBufferInfo.orderId != NULL);
3164
3165 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3166 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3167 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3168
3169 gByteBufferInfo.positionId = env->GetMethodID(
3170 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3171 CHECK(gByteBufferInfo.positionId != NULL);
3172
3173 gByteBufferInfo.limitId = env->GetMethodID(
3174 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3175 CHECK(gByteBufferInfo.limitId != NULL);
3176
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003177 gByteBufferInfo.getPositionId = env->GetMethodID(
3178 clazz.get(), "position", "()I");
3179 CHECK(gByteBufferInfo.getPositionId != NULL);
3180
3181 gByteBufferInfo.getLimitId = env->GetMethodID(
3182 clazz.get(), "limit", "()I");
3183 CHECK(gByteBufferInfo.getLimitId != NULL);
3184
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003185 clazz.reset(env->FindClass("java/util/ArrayList"));
3186 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003187 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3188
3189 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3190 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003191
3192 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3193 CHECK(gArrayListInfo.sizeId != NULL);
3194
3195 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3196 CHECK(gArrayListInfo.getId != NULL);
3197
3198 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3199 CHECK(gArrayListInfo.addId != NULL);
3200
3201 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3202 CHECK(clazz.get() != NULL);
3203
3204 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3205
3206 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3207 CHECK(gLinearBlockInfo.ctorId != NULL);
3208
3209 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3210 clazz.get(), "setInternalStateLocked", "(JZ)V");
3211 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3212
3213 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3214 CHECK(gLinearBlockInfo.contextId != NULL);
3215
3216 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3217 CHECK(gLinearBlockInfo.validId != NULL);
3218
3219 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3220 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003221
3222 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3223 CHECK(clazz.get() != NULL);
3224 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3225
3226 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3227 CHECK(gDescriptorInfo.ctorId != NULL);
3228
3229 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3230 CHECK(gDescriptorInfo.nameId != NULL);
3231
3232 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3233 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003234
3235 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3236 CHECK(clazz.get() != NULL);
3237 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3238
3239 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3240 CHECK(gBufferInfo.ctorId != NULL);
3241
3242 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3243 CHECK(gBufferInfo.setId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003244}
3245
3246static void android_media_MediaCodec_native_setup(
3247 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003248 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003249 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003250 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003251 return;
3252 }
3253
3254 const char *tmp = env->GetStringUTFChars(name, NULL);
3255
3256 if (tmp == NULL) {
3257 return;
3258 }
3259
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003260 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003261
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003262 const status_t err = codec->initCheck();
3263 if (err == NAME_NOT_FOUND) {
3264 // fail and do not try again.
3265 jniThrowException(env, "java/lang/IllegalArgumentException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003266 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003267 env->ReleaseStringUTFChars(name, tmp);
3268 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003269 }
3270 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003271 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003272 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err));
Ronghua Wuc53ad692015-05-08 14:40:49 -07003273 env->ReleaseStringUTFChars(name, tmp);
3274 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003275 }
3276 if (err == PERMISSION_DENIED) {
3277 jniThrowException(env, "java/lang/SecurityException",
3278 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
3279 err));
3280 env->ReleaseStringUTFChars(name, tmp);
3281 return;
3282 }
3283 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003284 // believed possible to try again
3285 jniThrowException(env, "java/io/IOException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003286 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003287 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003288 return;
3289 }
3290
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003291 env->ReleaseStringUTFChars(name, tmp);
3292
Andreas Huberaba67132013-10-22 12:40:01 -07003293 codec->registerSelf();
3294
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003295 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003296}
3297
3298static void android_media_MediaCodec_native_finalize(
3299 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003300 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003301}
3302
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003303// MediaCodec.LinearBlock
3304
3305static jobject android_media_MediaCodec_LinearBlock_native_map(
3306 JNIEnv *env, jobject thiz) {
3307 JMediaCodecLinearBlock *context =
3308 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3309 if (context->mBuffer) {
3310 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3311 if (!context->mReadonlyMapping) {
3312 const C2BufferData data = buffer->data();
3313 if (data.type() != C2BufferData::LINEAR) {
3314 throwExceptionAsNecessary(env, INVALID_OPERATION);
3315 return nullptr;
3316 }
3317 if (data.linearBlocks().size() != 1u) {
3318 throwExceptionAsNecessary(env, INVALID_OPERATION);
3319 return nullptr;
3320 }
3321 C2ConstLinearBlock block = data.linearBlocks().front();
3322 context->mReadonlyMapping =
3323 std::make_shared<C2ReadView>(block.map().get());
3324 }
3325 return CreateByteBuffer(
3326 env,
3327 context->mReadonlyMapping->data(), // base
3328 context->mReadonlyMapping->capacity(), // capacity
3329 0u, // offset
3330 context->mReadonlyMapping->capacity(), // size
3331 true, // readOnly
3332 true /* clearBuffer */);
3333 } else if (context->mBlock) {
3334 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3335 if (!context->mReadWriteMapping) {
3336 context->mReadWriteMapping =
3337 std::make_shared<C2WriteView>(block->map().get());
3338 }
3339 return CreateByteBuffer(
3340 env,
3341 context->mReadWriteMapping->base(),
3342 context->mReadWriteMapping->capacity(),
3343 context->mReadWriteMapping->offset(),
3344 context->mReadWriteMapping->size(),
3345 false, // readOnly
3346 true /* clearBuffer */);
3347 } else if (context->mLegacyBuffer) {
3348 return CreateByteBuffer(
3349 env,
3350 context->mLegacyBuffer->base(),
3351 context->mLegacyBuffer->capacity(),
3352 context->mLegacyBuffer->offset(),
3353 context->mLegacyBuffer->size(),
3354 true, // readOnly
3355 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003356 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003357 return CreateByteBuffer(
3358 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003359 context->mMemory->unsecurePointer(),
3360 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003361 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003362 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003363 false, // readOnly
3364 true /* clearBuffer */);
3365 }
3366 throwExceptionAsNecessary(env, INVALID_OPERATION);
3367 return nullptr;
3368}
3369
3370static void android_media_MediaCodec_LinearBlock_native_recycle(
3371 JNIEnv *env, jobject thiz) {
3372 JMediaCodecLinearBlock *context =
3373 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003374 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003375 delete context;
3376}
3377
3378static void PopulateNamesVector(
3379 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3380 jsize length = env->GetArrayLength(codecNames);
3381 for (jsize i = 0; i < length; ++i) {
3382 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3383 if (jstr == nullptr) {
3384 // null entries are ignored
3385 continue;
3386 }
3387 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3388 if (cstr == nullptr) {
3389 throwExceptionAsNecessary(env, BAD_VALUE);
3390 return;
3391 }
3392 names->emplace_back(cstr);
3393 env->ReleaseStringUTFChars(jstr, cstr);
3394 }
3395}
3396
3397static void android_media_MediaCodec_LinearBlock_native_obtain(
3398 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3399 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3400 std::vector<std::string> names;
3401 PopulateNamesVector(env, codecNames, &names);
3402 bool hasSecure = false;
3403 bool hasNonSecure = false;
3404 for (const std::string &name : names) {
3405 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3406 hasSecure = true;
3407 } else {
3408 hasNonSecure = true;
3409 }
3410 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003411 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3412 jniThrowException(env, "java/io/IOException", nullptr);
3413 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003414 }
3415 env->CallVoidMethod(
3416 thiz,
3417 gLinearBlockInfo.setInternalStateId,
3418 (jlong)context.release(),
3419 true /* isMappable */);
3420}
3421
3422static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003423 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003424 std::vector<std::string> names;
3425 PopulateNamesVector(env, codecNames, &names);
3426 bool isCompatible = false;
3427 bool hasSecure = false;
3428 bool hasNonSecure = false;
3429 for (const std::string &name : names) {
3430 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3431 hasSecure = true;
3432 } else {
3433 hasNonSecure = true;
3434 }
3435 }
3436 if (hasSecure && hasNonSecure) {
3437 return false;
3438 }
3439 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3440 if (err != OK) {
3441 throwExceptionAsNecessary(env, err);
3442 }
3443 return isCompatible;
3444}
3445
Daniel Micay76f6a862015-09-19 17:31:01 -04003446static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003447 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003448
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003449 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3450
Chong Zhang8034d602015-04-28 13:38:48 -07003451 { "native_releasePersistentInputSurface",
3452 "(Landroid/view/Surface;)V",
3453 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3454
3455 { "native_createPersistentInputSurface",
3456 "()Landroid/media/MediaCodec$PersistentSurface;",
3457 (void *)android_media_MediaCodec_createPersistentInputSurface },
3458
Chong Zhang9560ddb2015-05-13 10:25:29 -07003459 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3460 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003461
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003462 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3463 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3464
Lajos Molnard8578572015-06-05 20:17:33 -07003465 { "native_enableOnFrameRenderedListener", "(Z)V",
3466 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3467
Chong Zhang8d5e5562014-07-08 18:49:21 -07003468 { "native_setCallback",
3469 "(Landroid/media/MediaCodec$Callback;)V",
3470 (void *)android_media_MediaCodec_native_setCallback },
3471
Andreas Huber88572f72012-02-21 11:47:18 -08003472 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003473 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003474 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003475 (void *)android_media_MediaCodec_native_configure },
3476
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003477 { "native_setSurface",
3478 "(Landroid/view/Surface;)V",
3479 (void *)android_media_MediaCodec_native_setSurface },
3480
Andy McFadden2621e402013-02-19 07:29:21 -08003481 { "createInputSurface", "()Landroid/view/Surface;",
3482 (void *)android_media_MediaCodec_createInputSurface },
3483
Lajos Molnard4023112014-07-11 15:12:59 -07003484 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003485 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003486 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003487
Lajos Molnard4023112014-07-11 15:12:59 -07003488 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003489 (void *)android_media_MediaCodec_queueInputBuffer },
3490
Lajos Molnard4023112014-07-11 15:12:59 -07003491 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003492 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3493
Wonsik Kim637afb22020-02-25 14:27:29 -08003494 { "native_mapHardwareBuffer",
3495 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3496 (void *)android_media_MediaCodec_mapHardwareBuffer },
3497
3498 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3499
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003500 { "native_queueLinearBlock",
3501 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3502 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3503 (void *)android_media_MediaCodec_native_queueLinearBlock },
3504
Wonsik Kim637afb22020-02-25 14:27:29 -08003505 { "native_queueHardwareBuffer",
3506 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3507 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003508
3509 { "native_getOutputFrame",
3510 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3511 (void *)android_media_MediaCodec_native_getOutputFrame },
3512
Lajos Molnard4023112014-07-11 15:12:59 -07003513 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003514 (void *)android_media_MediaCodec_dequeueInputBuffer },
3515
Lajos Molnard4023112014-07-11 15:12:59 -07003516 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003517 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3518
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003519 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003520 (void *)android_media_MediaCodec_releaseOutputBuffer },
3521
Andy McFadden2621e402013-02-19 07:29:21 -08003522 { "signalEndOfInputStream", "()V",
3523 (void *)android_media_MediaCodec_signalEndOfInputStream },
3524
Lajos Molnard4023112014-07-11 15:12:59 -07003525 { "getFormatNative", "(Z)Ljava/util/Map;",
3526 (void *)android_media_MediaCodec_getFormatNative },
3527
3528 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3529 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003530
3531 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3532 (void *)android_media_MediaCodec_getBuffers },
3533
Lajos Molnard4023112014-07-11 15:12:59 -07003534 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3535 (void *)android_media_MediaCodec_getBuffer },
3536
3537 { "getImage", "(ZI)Landroid/media/Image;",
3538 (void *)android_media_MediaCodec_getImage },
3539
Lajos Molnard2a7f472018-11-15 12:49:20 -08003540 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003541 (void *)android_media_MediaCodec_getName },
3542
Chong Zhanga0b72a62018-02-28 18:46:26 -08003543 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3544 (void *)android_media_MediaCodec_getOwnCodecInfo },
3545
Ray Essick10353e32017-04-14 10:22:55 -07003546 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003547 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003548
Andreas Huber226065b2013-08-12 10:14:11 -07003549 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3550 (void *)android_media_MediaCodec_setParameters },
3551
Andreas Huberb12a5392012-04-30 14:18:33 -07003552 { "setVideoScalingMode", "(I)V",
3553 (void *)android_media_MediaCodec_setVideoScalingMode },
3554
ybai5e053202018-11-01 13:02:15 +08003555 { "native_setAudioPresentation", "(II)V",
3556 (void *)android_media_MediaCodec_setAudioPresentation },
3557
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003558 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
3559 (void *)android_media_MediaCodec_getSupportedVendorParameters },
3560
3561 { "native_getParameterDescriptor",
3562 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
3563 (void *)android_media_MediaCodec_getParameterDescriptor },
3564
3565 { "native_subscribeToVendorParameters",
3566 "(Ljava/util/List;)V",
3567 (void *)android_media_MediaCodec_subscribeToVendorParameters},
3568
3569 { "native_unsubscribeFromVendorParameters",
3570 "(Ljava/util/List;)V",
3571 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
3572
Andreas Huber88572f72012-02-21 11:47:18 -08003573 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3574
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003575 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003576 (void *)android_media_MediaCodec_native_setup },
3577
3578 { "native_finalize", "()V",
3579 (void *)android_media_MediaCodec_native_finalize },
3580};
3581
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003582static const JNINativeMethod gLinearBlockMethods[] = {
3583 { "native_map", "()Ljava/nio/ByteBuffer;",
3584 (void *)android_media_MediaCodec_LinearBlock_native_map },
3585
3586 { "native_recycle", "()V",
3587 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3588
3589 { "native_obtain", "(I[Ljava/lang/String;)V",
3590 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3591
3592 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3593 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3594};
3595
Andreas Huber88572f72012-02-21 11:47:18 -08003596int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003597 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003598 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003599 if (result != JNI_OK) {
3600 return result;
3601 }
3602 result = AndroidRuntime::registerNativeMethods(env,
3603 "android/media/MediaCodec$LinearBlock",
3604 gLinearBlockMethods,
3605 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003606 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003607}