blob: 53c02663636a24a32c37e4e4c5635a7a71a7bece [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec-JNI"
19#include <utils/Log.h>
20
Wonsik Kimccb7ac62019-12-27 17:12:40 -080021#include <type_traits>
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include "android_media_MediaCodec.h"
24
shubangd49681e2020-02-17 21:32:30 -080025#include "android_media_MediaCodecLinearBlock.h"
Andreas Huber07ea4262012-04-11 12:21:20 -070026#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070027#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080028#include "android_media_MediaMetricsJNI.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090029#include "android_media_Streams.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "android_runtime/AndroidRuntime.h"
31#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080032#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080033#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080035#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080036
Wonsik Kim637afb22020-02-25 14:27:29 -080037#include <C2AllocatorGralloc.h>
38#include <C2BlockInternal.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080039#include <C2Buffer.h>
Wonsik Kimb8ebdb32020-04-21 17:00:13 -070040#include <C2PlatformSupport.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080041
Chong Zhang2659c2f2017-04-27 13:18:20 -070042#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080043
Wonsik Kim637afb22020-02-25 14:27:29 -080044#include <android_runtime/android_hardware_HardwareBuffer.h>
45
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -080046#include <android-base/stringprintf.h>
47
Wonsik Kimf7069ce2020-05-13 17:15:47 -070048#include <binder/MemoryDealer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080049
Lajos Molnar7ac4f562014-03-24 15:57:51 -070050#include <cutils/compiler.h>
51
Mathias Agopian8335f1c2012-02-25 18:48:35 -080052#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080053
Wonsik Kimccb7ac62019-12-27 17:12:40 -080054#include <hidlmemory/FrameworkUtils.h>
55
Wonsik Kim4273dd02016-09-27 15:23:35 +090056#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080057#include <media/hardware/VideoAPI.h>
Wonsik Kim8798c8c2021-03-18 21:38:57 -070058#include <media/stagefright/CodecBase.h>
Andreas Huber88572f72012-02-21 11:47:18 -080059#include <media/stagefright/MediaCodec.h>
60#include <media/stagefright/foundation/ABuffer.h>
61#include <media/stagefright/foundation/ADebug.h>
62#include <media/stagefright/foundation/ALooper.h>
63#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070064#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080065#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070066#include <media/stagefright/PersistentSurface.h>
Robert Shih631a80d2021-02-14 02:23:55 -080067#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080068#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070069
Wonsik Kim637afb22020-02-25 14:27:29 -080070#include <private/android/AHardwareBufferHelpers.h>
71
Andreas Huberb12a5392012-04-30 14:18:33 -070072#include <system/window.h>
73
Andreas Huber88572f72012-02-21 11:47:18 -080074namespace android {
75
76// Keep these in sync with their equivalents in MediaCodec.java !!!
77enum {
78 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
79 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
80 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
81};
82
Andreas Huberaba67132013-10-22 12:40:01 -070083enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070084 EVENT_CALLBACK = 1,
85 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070086 EVENT_FRAME_RENDERED = 3,
Guillaume Chelfic072caf2021-02-03 16:18:26 +010087 EVENT_FIRST_TUNNEL_FRAME_READY = 4,
Andreas Huberaba67132013-10-22 12:40:01 -070088};
89
Wonsik Kim8798c8c2021-03-18 21:38:57 -070090// From MediaFormat.java
91enum {
92 TYPE_NULL = 0,
93 TYPE_INTEGER = 1,
94 TYPE_LONG = 2,
95 TYPE_FLOAT = 3,
96 TYPE_STRING = 4,
97 TYPE_BYTE_BUFFER = 5,
98};
99
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700100static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -0700101 jint cryptoErrorNoKey;
102 jint cryptoErrorKeyExpired;
103 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700104 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700105 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -0800106 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800107 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -0800108 jint cryptoErrorFrameTooLarge;
109 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700110} gCryptoErrorCodes;
111
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700112static struct CodecActionCodes {
113 jint codecActionTransient;
114 jint codecActionRecoverable;
115} gCodecActionCodes;
116
Ronghua Wuc53ad692015-05-08 14:40:49 -0700117static struct CodecErrorCodes {
118 jint errorInsufficientResource;
119 jint errorReclaimed;
120} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700121
Chong Zhang8034d602015-04-28 13:38:48 -0700122static struct {
123 jclass clazz;
124 jfieldID mLock;
125 jfieldID mPersistentObject;
126 jmethodID ctor;
127 jmethodID setNativeObjectLocked;
128} gPersistentSurfaceClassInfo;
129
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800130static struct {
131 jint Unencrypted;
132 jint AesCtr;
133 jint AesCbc;
134} gCryptoModes;
135
Chong Zhanga0b72a62018-02-28 18:46:26 -0800136static struct {
137 jclass capsClazz;
138 jmethodID capsCtorId;
139 jclass profileLevelClazz;
140 jfieldID profileField;
141 jfieldID levelField;
142} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800143
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800144static struct {
145 jclass clazz;
146 jobject nativeByteOrder;
147 jmethodID orderId;
148 jmethodID asReadOnlyBufferId;
149 jmethodID positionId;
150 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700151 jmethodID getPositionId;
152 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800153} gByteBufferInfo;
154
155static struct {
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700156 jclass clazz;
157 jmethodID ctorId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800158 jmethodID sizeId;
159 jmethodID getId;
160 jmethodID addId;
161} gArrayListInfo;
162
163static struct {
164 jclass clazz;
165 jmethodID ctorId;
166 jmethodID setInternalStateId;
167 jfieldID contextId;
168 jfieldID validId;
169 jfieldID lockId;
170} gLinearBlockInfo;
171
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700172static struct {
173 jclass clazz;
174 jmethodID ctorId;
175 jfieldID nameId;
176 jfieldID typeId;
177} gDescriptorInfo;
178
Pavel Laboviche53421b2022-11-01 03:53:27 +0000179static struct {
180 jclass clazz;
181 jmethodID ctorId;
182 jmethodID setId;
183} gBufferInfo;
184
Andreas Huber88572f72012-02-21 11:47:18 -0800185struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700186 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700187 jmethodID lockAndGetContextID;
188 jmethodID setAndUnlockContextID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700189 jfieldID cryptoInfoNumSubSamplesID;
190 jfieldID cryptoInfoNumBytesOfClearDataID;
191 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
192 jfieldID cryptoInfoKeyID;
193 jfieldID cryptoInfoIVID;
194 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800195 jfieldID cryptoInfoPatternID;
196 jfieldID patternEncryptBlocksID;
197 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800198 jfieldID queueRequestIndexID;
199 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800200 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800201 jfieldID outputFrameChangedKeysID;
202 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800203};
204
205static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700206static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800207
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800208
Andreas Huber88572f72012-02-21 11:47:18 -0800209////////////////////////////////////////////////////////////////////////////////
210
211JMediaCodec::JMediaCodec(
212 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100213 const char *name, bool nameIsType, bool encoder, int pid, int uid)
Andreas Huber88572f72012-02-21 11:47:18 -0800214 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700215 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800216 jclass clazz = env->GetObjectClass(thiz);
217 CHECK(clazz != NULL);
218
219 mClass = (jclass)env->NewGlobalRef(clazz);
220 mObject = env->NewWeakGlobalRef(thiz);
221
222 mLooper = new ALooper;
223 mLooper->setName("MediaCodec_looper");
224
225 mLooper->start(
226 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700227 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700228 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800229
230 if (nameIsType) {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100231 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800232 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
233 mNameAtCreation = "(null)";
234 }
Andreas Huber88572f72012-02-21 11:47:18 -0800235 } else {
Brian Lindahl6ceeed42022-02-01 11:10:30 +0100236 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
Lajos Molnare7473872019-02-05 18:54:27 -0800237 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800238 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700239 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800240}
241
242status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700243 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800244}
245
Andreas Huberaba67132013-10-22 12:40:01 -0700246void JMediaCodec::registerSelf() {
247 mLooper->registerHandler(this);
248}
249
Chong Zhang128b0122014-03-01 18:04:13 -0800250void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700251 std::call_once(mReleaseFlag, [this] {
252 if (mCodec != NULL) {
253 mCodec->release();
254 mInitStatus = NO_INIT;
255 }
Andreas Huber88572f72012-02-21 11:47:18 -0800256
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700257 if (mLooper != NULL) {
258 mLooper->unregisterHandler(id());
259 mLooper->stop();
260 mLooper.clear();
261 }
262 });
Chong Zhang128b0122014-03-01 18:04:13 -0800263}
264
Wonsik Kim89666622020-04-28 10:43:47 -0700265void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700266 std::call_once(mAsyncReleaseFlag, [this] {
267 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700268 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
269 // Hold strong reference to this until async release is complete
270 notify->setObject("this", this);
271 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700272 }
273 mInitStatus = NO_INIT;
274 });
Wonsik Kim89666622020-04-28 10:43:47 -0700275}
276
Chong Zhang128b0122014-03-01 18:04:13 -0800277JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700278 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800279 /* MediaCodec and looper should have been released explicitly already
280 * in setMediaCodec() (see comments in setMediaCodec()).
281 *
282 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
283 * message handler, doing release() there risks deadlock as MediaCodec::
284 * release() post synchronous message to the same looper.
285 *
286 * Print a warning and try to proceed with releasing.
287 */
288 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
289 release();
290 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
291 }
292
Andreas Huber88572f72012-02-21 11:47:18 -0800293 JNIEnv *env = AndroidRuntime::getJNIEnv();
294
295 env->DeleteWeakGlobalRef(mObject);
296 mObject = NULL;
297 env->DeleteGlobalRef(mClass);
298 mClass = NULL;
299}
300
Guillaume Chelfic072caf2021-02-03 16:18:26 +0100301status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
302 if (enable) {
303 if (mOnFirstTunnelFrameReadyNotification == NULL) {
304 mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
305 }
306 } else {
307 mOnFirstTunnelFrameReadyNotification.clear();
308 }
309
310 return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
311}
312
Lajos Molnard8578572015-06-05 20:17:33 -0700313status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
314 if (enable) {
315 if (mOnFrameRenderedNotification == NULL) {
316 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
317 }
318 } else {
319 mOnFrameRenderedNotification.clear();
320 }
321
322 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
323}
324
Chong Zhang8d5e5562014-07-08 18:49:21 -0700325status_t JMediaCodec::setCallback(jobject cb) {
326 if (cb != NULL) {
327 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800328 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700329 }
330 } else {
331 mCallbackNotification.clear();
332 }
333
334 return mCodec->setCallback(mCallbackNotification);
335}
336
Andreas Huber88572f72012-02-21 11:47:18 -0800337status_t JMediaCodec::configure(
338 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800339 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700340 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800341 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800342 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800343 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800344 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700345 mSurfaceTextureClient =
346 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700347 } else {
348 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800349 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700350
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800351 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
352 AString mime;
353 CHECK(format->findString("mime", &mime));
354 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
355 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700356 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800357 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800358
Chong Zhangd5927ae2017-01-03 11:07:18 -0800359 return mCodec->configure(
360 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800361}
362
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700363status_t JMediaCodec::setSurface(
364 const sp<IGraphicBufferProducer> &bufferProducer) {
365 sp<Surface> client;
366 if (bufferProducer != NULL) {
367 client = new Surface(bufferProducer, true /* controlledByApp */);
368 }
369 status_t err = mCodec->setSurface(client);
370 if (err == OK) {
371 mSurfaceTextureClient = client;
372 }
373 return err;
374}
375
Andy McFadden2621e402013-02-19 07:29:21 -0800376status_t JMediaCodec::createInputSurface(
377 sp<IGraphicBufferProducer>* bufferProducer) {
378 return mCodec->createInputSurface(bufferProducer);
379}
380
Chong Zhang9560ddb2015-05-13 10:25:29 -0700381status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700382 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700383 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700384}
385
Andreas Huber88572f72012-02-21 11:47:18 -0800386status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700387 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800388}
389
390status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700391 mSurfaceTextureClient.clear();
392
Chong Zhang8d5e5562014-07-08 18:49:21 -0700393 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800394}
395
396status_t JMediaCodec::flush() {
397 return mCodec->flush();
398}
399
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700400status_t JMediaCodec::reset() {
401 return mCodec->reset();
402}
403
Andreas Huber88572f72012-02-21 11:47:18 -0800404status_t JMediaCodec::queueInputBuffer(
405 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700406 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
407 AString *errorDetailMsg) {
408 return mCodec->queueInputBuffer(
409 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800410}
411
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700412status_t JMediaCodec::queueSecureInputBuffer(
413 size_t index,
414 size_t offset,
415 const CryptoPlugin::SubSample *subSamples,
416 size_t numSubSamples,
417 const uint8_t key[16],
418 const uint8_t iv[16],
419 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800420 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700421 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700422 uint32_t flags,
423 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700424 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800425 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700426 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700427}
428
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800429status_t JMediaCodec::queueBuffer(
430 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
431 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
432 return mCodec->queueBuffer(
433 index, buffer, timeUs, flags, tunings, errorDetailMsg);
434}
435
436status_t JMediaCodec::queueEncryptedLinearBlock(
437 size_t index,
438 const sp<hardware::HidlMemory> &buffer,
439 size_t offset,
440 const CryptoPlugin::SubSample *subSamples,
441 size_t numSubSamples,
442 const uint8_t key[16],
443 const uint8_t iv[16],
444 CryptoPlugin::Mode mode,
445 const CryptoPlugin::Pattern &pattern,
446 int64_t presentationTimeUs,
447 uint32_t flags,
448 const sp<AMessage> &tunings,
449 AString *errorDetailMsg) {
450 return mCodec->queueEncryptedBuffer(
451 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
452 presentationTimeUs, flags, tunings, errorDetailMsg);
453}
454
Andreas Huber88572f72012-02-21 11:47:18 -0800455status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700456 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800457}
458
459status_t JMediaCodec::dequeueOutputBuffer(
460 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
461 size_t size, offset;
462 int64_t timeUs;
463 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700464 status_t err = mCodec->dequeueOutputBuffer(
465 index, &offset, &size, &timeUs, &flags, timeoutUs);
466
Andreas Huberaba67132013-10-22 12:40:01 -0700467 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800468 return err;
469 }
470
Pavel Laboviche53421b2022-11-01 03:53:27 +0000471 env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800472
473 return OK;
474}
475
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700476status_t JMediaCodec::releaseOutputBuffer(
477 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
478 if (updatePTS) {
479 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
480 }
Andreas Huber88572f72012-02-21 11:47:18 -0800481 return render
482 ? mCodec->renderOutputBufferAndRelease(index)
483 : mCodec->releaseOutputBuffer(index);
484}
485
Andy McFadden2621e402013-02-19 07:29:21 -0800486status_t JMediaCodec::signalEndOfInputStream() {
487 return mCodec->signalEndOfInputStream();
488}
489
Lajos Molnard4023112014-07-11 15:12:59 -0700490status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800491 sp<AMessage> msg;
492 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700493 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
494 if (err != OK) {
495 return err;
496 }
497
498 return ConvertMessageToMap(env, msg, format);
499}
500
501status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
502 sp<AMessage> msg;
503 status_t err;
504 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800505 return err;
506 }
507
508 return ConvertMessageToMap(env, msg, format);
509}
510
511status_t JMediaCodec::getBuffers(
512 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900513 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800514
515 status_t err =
516 input
517 ? mCodec->getInputBuffers(&buffers)
518 : mCodec->getOutputBuffers(&buffers);
519
520 if (err != OK) {
521 return err;
522 }
523
Andreas Huber88572f72012-02-21 11:47:18 -0800524 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800525 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800526 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800527 return NO_MEMORY;
528 }
Andreas Huber88572f72012-02-21 11:47:18 -0800529
530 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900531 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800532
Lajos Molnar7de28d32014-07-25 07:51:02 -0700533 jobject byteBuffer = NULL;
534 err = createByteBufferFromABuffer(
535 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
536 if (err != OK) {
537 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800538 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700539 if (byteBuffer != NULL) {
540 env->SetObjectArrayElement(
541 *bufArray, i, byteBuffer);
542
Lajos Molnard4023112014-07-11 15:12:59 -0700543 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700544 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700545 }
Andreas Huber88572f72012-02-21 11:47:18 -0800546 }
547
Lajos Molnar7de28d32014-07-25 07:51:02 -0700548 return OK;
549}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700550
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800551template <typename T>
552static jobject CreateByteBuffer(
553 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
554 bool readOnly, bool clearBuffer) {
555 jobject byteBuffer =
556 env->NewDirectByteBuffer(
557 const_cast<typename std::remove_const<T>::type *>(base),
558 capacity);
559 if (readOnly && byteBuffer != NULL) {
560 jobject readOnlyBuffer = env->CallObjectMethod(
561 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
562 env->DeleteLocalRef(byteBuffer);
563 byteBuffer = readOnlyBuffer;
564 }
565 if (byteBuffer == NULL) {
566 return nullptr;
567 }
568 jobject me = env->CallObjectMethod(
569 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
570 env->DeleteLocalRef(me);
571 me = env->CallObjectMethod(
572 byteBuffer, gByteBufferInfo.limitId,
573 clearBuffer ? capacity : offset + size);
574 env->DeleteLocalRef(me);
575 me = env->CallObjectMethod(
576 byteBuffer, gByteBufferInfo.positionId,
577 clearBuffer ? 0 : offset);
578 env->DeleteLocalRef(me);
579 me = NULL;
580 return byteBuffer;
581}
582
583
Lajos Molnar7de28d32014-07-25 07:51:02 -0700584// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900585template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700586status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900587 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700588 jobject *buf) const {
589 // if this is an ABuffer that doesn't actually hold any accessible memory,
590 // use a null ByteBuffer
591 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700592
593 if (buffer == NULL) {
594 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
595 return OK;
596 }
597
Lajos Molnar7de28d32014-07-25 07:51:02 -0700598 if (buffer->base() == NULL) {
599 return OK;
600 }
601
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800602 jobject byteBuffer = CreateByteBuffer(
603 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
604 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700605
606 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800607 return OK;
608}
609
Lajos Molnard4023112014-07-11 15:12:59 -0700610status_t JMediaCodec::getBuffer(
611 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900612 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700613
614 status_t err =
615 input
616 ? mCodec->getInputBuffer(index, &buffer)
617 : mCodec->getOutputBuffer(index, &buffer);
618
619 if (err != OK) {
620 return err;
621 }
622
Lajos Molnar7de28d32014-07-25 07:51:02 -0700623 return createByteBufferFromABuffer(
624 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700625}
626
627status_t JMediaCodec::getImage(
628 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900629 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700630
631 status_t err =
632 input
633 ? mCodec->getInputBuffer(index, &buffer)
634 : mCodec->getOutputBuffer(index, &buffer);
635
636 if (err != OK) {
637 return err;
638 }
639
640 // if this is an ABuffer that doesn't actually hold any accessible memory,
641 // use a null ByteBuffer
642 *buf = NULL;
643 if (buffer->base() == NULL) {
644 return OK;
645 }
646
647 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700648 sp<ABuffer> imageData;
649 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700650 return OK;
651 }
652
Lajos Molnar7de28d32014-07-25 07:51:02 -0700653 int64_t timestamp = 0;
654 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
655 timestamp *= 1000; // adjust to ns
656 }
657
658 jobject byteBuffer = NULL;
659 err = createByteBufferFromABuffer(
660 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
661 if (err != OK) {
662 return OK;
663 }
664
665 jobject infoBuffer = NULL;
666 err = createByteBufferFromABuffer(
667 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
668 if (err != OK) {
669 env->DeleteLocalRef(byteBuffer);
670 byteBuffer = NULL;
671 return OK;
672 }
673
674 jobject cropRect = NULL;
675 int32_t left, top, right, bottom;
676 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
677 ScopedLocalRef<jclass> rectClazz(
678 env, env->FindClass("android/graphics/Rect"));
679 CHECK(rectClazz.get() != NULL);
680
681 jmethodID rectConstructID = env->GetMethodID(
682 rectClazz.get(), "<init>", "(IIII)V");
683
684 cropRect = env->NewObject(
685 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
686 }
687
688 ScopedLocalRef<jclass> imageClazz(
689 env, env->FindClass("android/media/MediaCodec$MediaImage"));
690 CHECK(imageClazz.get() != NULL);
691
692 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
693 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
694
695 *buf = env->NewObject(imageClazz.get(), imageConstructID,
696 byteBuffer, infoBuffer,
697 (jboolean)!input /* readOnly */,
698 (jlong)timestamp,
699 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
700
701 // if MediaImage creation fails, return null
702 if (env->ExceptionCheck()) {
703 env->ExceptionDescribe();
704 env->ExceptionClear();
705 *buf = NULL;
706 }
707
708 if (cropRect != NULL) {
709 env->DeleteLocalRef(cropRect);
710 cropRect = NULL;
711 }
712
713 env->DeleteLocalRef(byteBuffer);
714 byteBuffer = NULL;
715
716 env->DeleteLocalRef(infoBuffer);
717 infoBuffer = NULL;
718
Lajos Molnard4023112014-07-11 15:12:59 -0700719 return OK;
720}
721
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800722status_t JMediaCodec::getOutputFrame(
723 JNIEnv *env, jobject frame, size_t index) const {
724 sp<MediaCodecBuffer> buffer;
725
726 status_t err = mCodec->getOutputBuffer(index, &buffer);
727 if (err != OK) {
728 return err;
729 }
730
731 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800732 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800733 if (c2Buffer) {
734 switch (c2Buffer->data().type()) {
735 case C2BufferData::LINEAR: {
736 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700737 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800738 context->mBuffer = c2Buffer;
739 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
740 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800741 env->CallVoidMethod(
742 linearBlock.get(),
743 gLinearBlockInfo.setInternalStateId,
744 (jlong)context.release(),
745 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800746 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
747 break;
748 }
749 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800750 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
751 uint32_t width, height, format, stride, igbp_slot, generation;
752 uint64_t usage, igbp_id;
753 _UnwrapNativeCodec2GrallocMetadata(
754 c2Handle, &width, &height, &format, &usage, &stride, &generation,
755 &igbp_id, &igbp_slot);
756 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
757 GraphicBuffer* graphicBuffer = new GraphicBuffer(
758 grallocHandle, GraphicBuffer::CLONE_HANDLE,
759 width, height, format, 1, usage, stride);
760 ScopedLocalRef<jobject> hardwareBuffer{
761 env,
762 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
763 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
764 env->SetObjectField(
765 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800766 break;
767 }
768 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
769 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
770 case C2BufferData::INVALID: [[fallthrough]];
771 default:
772 return INVALID_OPERATION;
773 }
774 } else {
775 if (!mGraphicOutput) {
776 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
Wonsik Kim8569a662022-05-24 14:16:44 -0700777 context->mCodecNames.push_back(mNameAtCreation.c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800778 context->mLegacyBuffer = buffer;
779 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
780 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800781 env->CallVoidMethod(
782 linearBlock.get(),
783 gLinearBlockInfo.setInternalStateId,
784 (jlong)context.release(),
785 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800786 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
787 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800788 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800789 }
790 }
791 }
792
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700793 jobject formatMap;
794 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800795 if (err != OK) {
796 return err;
797 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700798 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
799 ScopedLocalRef<jobject> format{env, env->NewObject(
800 mediaFormatClass.get(),
801 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
802 formatMap)};
803 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
804 env->DeleteLocalRef(formatMap);
805 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800806
807 sp<RefBase> obj;
808 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
809 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
810 (decltype(changedKeys.get()))obj.get()};
811 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
812 frame, gFields.outputFrameChangedKeysID)};
813 for (const std::string &key : changedKeys->value) {
814 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
815 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
816 }
817 }
818 return OK;
819}
820
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300821status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
822 AString name;
823
824 status_t err = mCodec->getName(&name);
825
826 if (err != OK) {
827 return err;
828 }
829
830 *nameStr = env->NewStringUTF(name.c_str());
831
832 return OK;
833}
834
Chong Zhanga0b72a62018-02-28 18:46:26 -0800835static jobject getCodecCapabilitiesObject(
836 JNIEnv *env, const char *mime, bool isEncoder,
837 const sp<MediaCodecInfo::Capabilities> &capabilities) {
838 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
839 Vector<uint32_t> colorFormats;
840
841 sp<AMessage> defaultFormat = new AMessage();
842 defaultFormat->setString("mime", mime);
843
844 capabilities->getSupportedColorFormats(&colorFormats);
845 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800846 sp<AMessage> details = capabilities->getDetails();
847
848 jobject defaultFormatObj = NULL;
849 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
850 return NULL;
851 }
852 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
853
854 jobject detailsObj = NULL;
855 if (ConvertMessageToMap(env, details, &detailsObj)) {
856 return NULL;
857 }
858 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
859
860 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
861 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
862
863 for (size_t i = 0; i < profileLevels.size(); ++i) {
864 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
865
866 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
867 gCodecInfo.profileLevelClazz));
868
869 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
870 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
871
872 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
873 }
874
875 ScopedLocalRef<jintArray> colorFormatsArray(
876 env, env->NewIntArray(colorFormats.size()));
877 for (size_t i = 0; i < colorFormats.size(); ++i) {
878 jint val = colorFormats.itemAt(i);
879 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
880 }
881
882 return env->NewObject(
883 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800884 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800885 defaultFormatRef.get(), detailsRef.get());
886}
887
888status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
889 sp<MediaCodecInfo> codecInfo;
890
891 status_t err = mCodec->getCodecInfo(&codecInfo);
892
893 if (err != OK) {
894 return err;
895 }
896
897 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800898 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800899
Lajos Molnard2a7f472018-11-15 12:49:20 -0800900 ScopedLocalRef<jstring> canonicalNameObject(env,
901 env->NewStringUTF(codecInfo->getCodecName()));
902
903 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800904 bool isEncoder = codecInfo->isEncoder();
905
Lajos Molnard2a7f472018-11-15 12:49:20 -0800906 Vector<AString> mediaTypes;
907 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800908
909 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800910 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800911
Lajos Molnard2a7f472018-11-15 12:49:20 -0800912 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800913 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800914 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800915
916 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800917 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800918
919 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
920 }
921
922 ScopedLocalRef<jclass> codecInfoClazz(env,
923 env->FindClass("android/media/MediaCodecInfo"));
924 CHECK(codecInfoClazz.get() != NULL);
925
926 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800927 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800928
929 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800930 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800931
932 return OK;
933}
934
Ray Essick81fbc5b2019-12-07 06:24:59 -0800935status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
936 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700937 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700938 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800939 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800940 return status;
941}
942
Andreas Huber226065b2013-08-12 10:14:11 -0700943status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
944 return mCodec->setParameters(msg);
945}
946
Andreas Huberb12a5392012-04-30 14:18:33 -0700947void JMediaCodec::setVideoScalingMode(int mode) {
948 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700949 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700950 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700951 // also signal via param for components that queue to IGBP
952 sp<AMessage> msg = new AMessage;
953 msg->setInt32("android._video-scaling", mode);
954 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700955 }
956}
957
ybai5e053202018-11-01 13:02:15 +0800958void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
959 sp<AMessage> msg = new AMessage;
960 msg->setInt32("audio-presentation-presentation-id", presentationId);
961 msg->setInt32("audio-presentation-program-id", programId);
962 (void)mCodec->setParameters(msg);
963}
964
Wonsik Kim8798c8c2021-03-18 21:38:57 -0700965status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
966 std::vector<std::string> names;
967 status_t status = mCodec->querySupportedVendorParameters(&names);
968 if (status != OK) {
969 return status;
970 }
971 *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
972 for (const std::string &name : names) {
973 ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
974 (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
975 }
976 return OK;
977}
978
979status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
980 const char *tmp = env->GetStringUTFChars(name, nullptr);
981 CodecParameterDescriptor desc;
982 status_t status = mCodec->describeParameter(tmp, &desc);
983 env->ReleaseStringUTFChars(name, tmp);
984 if (status != OK) {
985 return status;
986 }
987 jint type = TYPE_NULL;
988 switch (desc.type) {
989 case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
990 case AMessage::kTypeSize:
991 case AMessage::kTypeInt64: type = TYPE_LONG; break;
992 case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
993 case AMessage::kTypeString: type = TYPE_STRING; break;
994 case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
995 default: type = TYPE_NULL; break;
996 }
997 if (type == TYPE_NULL) {
998 return BAD_VALUE;
999 }
1000 *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
1001 env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
1002 env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
1003 return OK;
1004}
1005
1006static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
1007 ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
1008 ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
1009 jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
1010 jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
1011 jobject it = env->CallObjectMethod(
1012 list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
1013 while (env->CallBooleanMethod(it, hasNextID)) {
1014 jstring name = (jstring)env->CallObjectMethod(it, nextID);
1015 const char *tmp = env->GetStringUTFChars(name, nullptr);
1016 vec->push_back(tmp);
1017 env->ReleaseStringUTFChars(name, tmp);
1018 }
1019}
1020
1021status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
1022 std::vector<std::string> names;
1023 BuildVectorFromList(env, namesObj, &names);
1024 return mCodec->subscribeToVendorParameters(names);
1025}
1026
1027status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
1028 std::vector<std::string> names;
1029 BuildVectorFromList(env, namesObj, &names);
1030 return mCodec->unsubscribeFromVendorParameters(names);
1031}
1032
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001033static jthrowable createCodecException(
1034 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
1035 ScopedLocalRef<jclass> clazz(
1036 env, env->FindClass("android/media/MediaCodec$CodecException"));
1037 CHECK(clazz.get() != NULL);
1038
Ronghua Wuc53ad692015-05-08 14:40:49 -07001039 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001040 CHECK(ctor != NULL);
1041
1042 ScopedLocalRef<jstring> msgObj(
1043 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
1044
1045 // translate action code to Java equivalent
1046 switch (actionCode) {
1047 case ACTION_CODE_TRANSIENT:
1048 actionCode = gCodecActionCodes.codecActionTransient;
1049 break;
1050 case ACTION_CODE_RECOVERABLE:
1051 actionCode = gCodecActionCodes.codecActionRecoverable;
1052 break;
1053 default:
1054 actionCode = 0; // everything else is fatal
1055 break;
1056 }
1057
Ronghua Wuc53ad692015-05-08 14:40:49 -07001058 /* translate OS errors to Java API CodecException errorCodes */
1059 switch (err) {
1060 case NO_MEMORY:
1061 err = gCodecErrorCodes.errorInsufficientResource;
1062 break;
1063 case DEAD_OBJECT:
1064 err = gCodecErrorCodes.errorReclaimed;
1065 break;
1066 default: /* Other error codes go out as is. */
1067 break;
1068 }
1069
1070 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001071}
1072
Chong Zhang8d5e5562014-07-08 18:49:21 -07001073void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
1074 int32_t arg1, arg2 = 0;
1075 jobject obj = NULL;
1076 CHECK(msg->findInt32("callbackID", &arg1));
1077 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -07001078
Chong Zhang8d5e5562014-07-08 18:49:21 -07001079 switch (arg1) {
1080 case MediaCodec::CB_INPUT_AVAILABLE:
1081 {
1082 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001083 break;
1084 }
1085
Chong Zhang8d5e5562014-07-08 18:49:21 -07001086 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -07001087 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001088 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -07001089
Chong Zhang8d5e5562014-07-08 18:49:21 -07001090 size_t size, offset;
1091 int64_t timeUs;
1092 uint32_t flags;
1093 CHECK(msg->findSize("size", &size));
1094 CHECK(msg->findSize("offset", &offset));
1095 CHECK(msg->findInt64("timeUs", &timeUs));
1096 CHECK(msg->findInt32("flags", (int32_t *)&flags));
1097
Pavel Laboviche53421b2022-11-01 03:53:27 +00001098 obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001099 if (obj == NULL) {
1100 if (env->ExceptionCheck()) {
1101 ALOGE("Could not create MediaCodec.BufferInfo.");
1102 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001103 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001104 jniThrowException(env, "java/lang/IllegalStateException",
1105 "Fatal error: could not create MediaCodec.BufferInfo object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001106 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001107 }
1108
Pavel Laboviche53421b2022-11-01 03:53:27 +00001109 env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001110 break;
1111 }
1112
1113 case MediaCodec::CB_ERROR:
1114 {
Chong Zhang94686d12014-07-11 15:53:58 -07001115 int32_t err, actionCode;
1116 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001117 CHECK(msg->findInt32("actionCode", &actionCode));
1118
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001119 // note that DRM errors could conceivably alias into a CodecException
1120 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001121
1122 if (obj == NULL) {
1123 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001124 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001125 env->ExceptionClear();
1126 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001127 jniThrowException(env, "java/lang/IllegalStateException",
1128 "Fatal error: could not create CodecException object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001129 return;
1130 }
Andreas Huberaba67132013-10-22 12:40:01 -07001131
1132 break;
1133 }
1134
Chong Zhang8d5e5562014-07-08 18:49:21 -07001135 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001136 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001137 sp<AMessage> format;
1138 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001139
Chong Zhang8d5e5562014-07-08 18:49:21 -07001140 if (OK != ConvertMessageToMap(env, format, &obj)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001141 jniThrowException(env, "java/lang/IllegalStateException",
1142 "Fatal error: failed to convert format "
1143 "from native to Java object");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001144 return;
1145 }
Andreas Huberaba67132013-10-22 12:40:01 -07001146
Andreas Huberaba67132013-10-22 12:40:01 -07001147 break;
1148 }
1149
1150 default:
1151 TRESPASS();
1152 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001153
1154 env->CallVoidMethod(
1155 mObject,
1156 gFields.postEventFromNativeID,
1157 EVENT_CALLBACK,
1158 arg1,
1159 arg2,
1160 obj);
1161
1162 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001163}
1164
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001165void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
1166 int32_t arg1 = 0, arg2 = 0;
1167 jobject obj = NULL;
1168 JNIEnv *env = AndroidRuntime::getJNIEnv();
1169
1170 sp<AMessage> data;
1171 CHECK(msg->findMessage("data", &data));
1172
1173 status_t err = ConvertMessageToMap(env, data, &obj);
1174 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001175 jniThrowException(env, "java/lang/IllegalStateException",
1176 "Fatal error: failed to convert format from native to Java object");
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001177 return;
1178 }
1179
1180 env->CallVoidMethod(
1181 mObject, gFields.postEventFromNativeID,
1182 EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);
1183
1184 env->DeleteLocalRef(obj);
1185}
1186
Lajos Molnard8578572015-06-05 20:17:33 -07001187void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1188 int32_t arg1 = 0, arg2 = 0;
1189 jobject obj = NULL;
1190 JNIEnv *env = AndroidRuntime::getJNIEnv();
1191
1192 sp<AMessage> data;
1193 CHECK(msg->findMessage("data", &data));
1194
1195 status_t err = ConvertMessageToMap(env, data, &obj);
1196 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001197 jniThrowException(env, "java/lang/IllegalStateException",
1198 "Fatal error: failed to convert format from native to Java object");
Lajos Molnard8578572015-06-05 20:17:33 -07001199 return;
1200 }
1201
1202 env->CallVoidMethod(
1203 mObject, gFields.postEventFromNativeID,
1204 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1205
1206 env->DeleteLocalRef(obj);
1207}
1208
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001209std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
1210 if (mCodec == nullptr) {
1211 return msg ?: "";
1212 }
1213 std::string prefix = "";
1214 if (msg && msg[0] != '\0') {
1215 prefix.append(msg);
1216 prefix.append("\n");
1217 }
1218 return prefix + mCodec->getErrorLog().extract();
1219}
1220
Chong Zhang8d5e5562014-07-08 18:49:21 -07001221void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1222 switch (msg->what()) {
1223 case kWhatCallbackNotify:
1224 {
1225 handleCallback(msg);
1226 break;
1227 }
Lajos Molnard8578572015-06-05 20:17:33 -07001228 case kWhatFrameRendered:
1229 {
1230 handleFrameRenderedNotification(msg);
1231 break;
1232 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001233 case kWhatAsyncReleaseComplete:
1234 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001235 if (mLooper != NULL) {
1236 mLooper->unregisterHandler(id());
1237 mLooper->stop();
1238 mLooper.clear();
1239 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001240 break;
1241 }
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001242 case kWhatFirstTunnelFrameReady:
1243 {
1244 handleFirstTunnelFrameReadyNotification(msg);
1245 break;
1246 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001247 default:
1248 TRESPASS();
1249 }
Andreas Huberaba67132013-10-22 12:40:01 -07001250}
1251
Robert Shih631a80d2021-02-14 02:23:55 -08001252jint MediaErrorToJavaError(status_t err);
1253
Andreas Huber88572f72012-02-21 11:47:18 -08001254} // namespace android
1255
1256////////////////////////////////////////////////////////////////////////////////
1257
1258using namespace android;
1259
1260static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001261 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001262 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001263 if (codec != NULL) {
1264 codec->incStrong(thiz);
1265 }
1266 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001267 /* release MediaCodec and stop the looper now before decStrong.
1268 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1269 * its message handler, doing release() from there will deadlock
1270 * (as MediaCodec::release() post synchronous message to the same looper)
1271 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001272 if (release) {
1273 old->release();
1274 }
Andreas Huber88572f72012-02-21 11:47:18 -08001275 old->decStrong(thiz);
1276 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001277 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001278
1279 return old;
1280}
1281
1282static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001283 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1284 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1285 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001286}
1287
1288static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001289 // Clear Java native reference.
1290 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001291 if (codec != NULL) {
1292 codec->releaseAsync();
1293 }
Andreas Huber88572f72012-02-21 11:47:18 -08001294}
1295
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001296static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1297 jthrowable exception = createCodecException(env, err, actionCode, msg);
1298 env->Throw(exception);
1299}
1300
Robert Shih631a80d2021-02-14 02:23:55 -08001301static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1302 const sp<ICrypto> &crypto) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001303 ScopedLocalRef<jclass> clazz(
1304 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1305 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001306
1307 jmethodID constructID =
Robert Shih57f369a2022-12-16 12:47:27 -08001308 env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;IIII)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -07001309 CHECK(constructID != NULL);
1310
Robert Shih631a80d2021-02-14 02:23:55 -08001311 std::string defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -07001312
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001313 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Robert Shih390b6152022-05-10 10:42:29 -07001314 jint jerr = 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001315 switch (err) {
1316 case ERROR_DRM_NO_LICENSE:
Robert Shih390b6152022-05-10 10:42:29 -07001317 jerr = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001318 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001319 break;
1320 case ERROR_DRM_LICENSE_EXPIRED:
Robert Shih390b6152022-05-10 10:42:29 -07001321 jerr = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001322 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001323 break;
1324 case ERROR_DRM_RESOURCE_BUSY:
Robert Shih390b6152022-05-10 10:42:29 -07001325 jerr = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001326 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001327 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001328 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
Robert Shih390b6152022-05-10 10:42:29 -07001329 jerr = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001330 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001331 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001332 case ERROR_DRM_SESSION_NOT_OPENED:
Robert Shih390b6152022-05-10 10:42:29 -07001333 jerr = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001334 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001335 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001336 case ERROR_DRM_INSUFFICIENT_SECURITY:
Robert Shih390b6152022-05-10 10:42:29 -07001337 jerr = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
Jeff Tinker20594d82018-12-12 08:31:22 -08001338 defaultMsg = "Required security level is not met";
1339 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001340 case ERROR_DRM_CANNOT_HANDLE:
Robert Shih390b6152022-05-10 10:42:29 -07001341 jerr = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001342 defaultMsg = "Operation not supported in this configuration";
1343 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001344 case ERROR_DRM_FRAME_TOO_LARGE:
Robert Shih390b6152022-05-10 10:42:29 -07001345 jerr = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
Jeff Tinker20594d82018-12-12 08:31:22 -08001346 defaultMsg = "Decrytped frame exceeds size of output buffer";
1347 break;
1348 case ERROR_DRM_SESSION_LOST_STATE:
Robert Shih390b6152022-05-10 10:42:29 -07001349 jerr = gCryptoErrorCodes.cryptoErrorLostState;
Jeff Tinker20594d82018-12-12 08:31:22 -08001350 defaultMsg = "Session state was lost, open a new session and retry";
1351 break;
Robert Shih631a80d2021-02-14 02:23:55 -08001352 default: /* Other negative DRM error codes go out best-effort. */
Robert Shih390b6152022-05-10 10:42:29 -07001353 jerr = MediaErrorToJavaError(err);
Robert Shih631a80d2021-02-14 02:23:55 -08001354 defaultMsg = StrCryptoError(err);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001355 break;
1356 }
1357
Robert Shih57f369a2022-12-16 12:47:27 -08001358 std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
1359 DrmStatus dStatus(err, originalMsg.c_str());
1360 std::string detailedMsg(DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
1361 jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001362
Andreas Huberbfc56f42012-04-19 12:47:07 -07001363 jthrowable exception =
Robert Shih57f369a2022-12-16 12:47:27 -08001364 (jthrowable)env->NewObject(clazz.get(), constructID, msgObj, jerr,
1365 dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext());
Andreas Huberbfc56f42012-04-19 12:47:07 -07001366
1367 env->Throw(exception);
1368}
1369
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001370static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
1371 if (codec == NULL) {
1372 return msg ?: "codec is released already";
1373 }
1374 return codec->getExceptionMessage(msg);
1375}
1376
Andreas Huberbfc56f42012-04-19 12:47:07 -07001377static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001378 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001379 const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
1380 const sp<JMediaCodec> &codec = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001381 switch (err) {
1382 case OK:
1383 return 0;
1384
1385 case -EAGAIN:
1386 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1387
1388 case INFO_FORMAT_CHANGED:
1389 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1390
1391 case INFO_OUTPUT_BUFFERS_CHANGED:
1392 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1393
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001394 case INVALID_OPERATION:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001395 jniThrowException(
1396 env, "java/lang/IllegalStateException",
1397 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001398 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001399
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001400 case BAD_VALUE:
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001401 jniThrowException(
1402 env, "java/lang/IllegalArgumentException",
1403 GetExceptionMessage(codec, msg).c_str());
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001404 return 0;
1405
Andreas Huber88572f72012-02-21 11:47:18 -08001406 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001407 if (isCryptoError(err)) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001408 throwCryptoException(
1409 env, err,
1410 GetExceptionMessage(codec, msg).c_str(),
1411 crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001412 return 0;
1413 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001414 throwCodecException(
1415 env, err, actionCode,
1416 GetExceptionMessage(codec, msg).c_str());
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001417 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001418 }
Andreas Huber88572f72012-02-21 11:47:18 -08001419}
1420
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001421static jint throwExceptionAsNecessary(
1422 JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
1423 int32_t actionCode = ACTION_CODE_FATAL) {
1424 return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
1425}
1426
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001427static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
1428 JNIEnv *env,
1429 jobject thiz,
1430 jboolean enabled) {
1431 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1432
1433 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001434 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001435 return;
1436 }
1437
1438 status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
1439
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001440 throwExceptionAsNecessary(env, err, codec);
Guillaume Chelfic072caf2021-02-03 16:18:26 +01001441}
1442
Lajos Molnard8578572015-06-05 20:17:33 -07001443static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1444 JNIEnv *env,
1445 jobject thiz,
1446 jboolean enabled) {
1447 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1448
Wonsik Kim24e53802020-05-08 20:04:26 -07001449 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001450 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001451 return;
1452 }
1453
1454 status_t err = codec->enableOnFrameRenderedListener(enabled);
1455
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001456 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard8578572015-06-05 20:17:33 -07001457}
1458
Chong Zhang8d5e5562014-07-08 18:49:21 -07001459static void android_media_MediaCodec_native_setCallback(
1460 JNIEnv *env,
1461 jobject thiz,
1462 jobject cb) {
1463 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1464
Wonsik Kim24e53802020-05-08 20:04:26 -07001465 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001466 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001467 return;
1468 }
1469
1470 status_t err = codec->setCallback(cb);
1471
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001472 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001473}
1474
Andreas Huber88572f72012-02-21 11:47:18 -08001475static void android_media_MediaCodec_native_configure(
1476 JNIEnv *env,
1477 jobject thiz,
1478 jobjectArray keys, jobjectArray values,
1479 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001480 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001481 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001482 jint flags) {
1483 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1484
Wonsik Kim24e53802020-05-08 20:04:26 -07001485 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001486 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001487 return;
1488 }
1489
1490 sp<AMessage> format;
1491 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1492
1493 if (err != OK) {
1494 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1495 return;
1496 }
1497
Andy McFaddend47f7d82012-12-18 09:48:38 -08001498 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001499 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001500 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001501 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001502 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001503 } else {
1504 jniThrowException(
1505 env,
1506 "java/lang/IllegalArgumentException",
1507 "The surface has been released");
1508 return;
1509 }
1510 }
1511
Andreas Huber8240d922012-04-04 14:06:32 -07001512 sp<ICrypto> crypto;
1513 if (jcrypto != NULL) {
1514 crypto = JCrypto::GetCrypto(env, jcrypto);
1515 }
1516
Chong Zhangd5927ae2017-01-03 11:07:18 -08001517 sp<IDescrambler> descrambler;
1518 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001519 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001520 }
1521
1522 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001523
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001524 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001525}
1526
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001527static void android_media_MediaCodec_native_setSurface(
1528 JNIEnv *env,
1529 jobject thiz,
1530 jobject jsurface) {
1531 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1532
Wonsik Kim24e53802020-05-08 20:04:26 -07001533 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001534 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001535 return;
1536 }
1537
1538 sp<IGraphicBufferProducer> bufferProducer;
1539 if (jsurface != NULL) {
1540 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1541 if (surface != NULL) {
1542 bufferProducer = surface->getIGraphicBufferProducer();
1543 } else {
1544 jniThrowException(
1545 env,
1546 "java/lang/IllegalArgumentException",
1547 "The surface has been released");
1548 return;
1549 }
1550 }
1551
1552 status_t err = codec->setSurface(bufferProducer);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001553 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001554}
1555
Chong Zhang8034d602015-04-28 13:38:48 -07001556sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1557 JNIEnv* env, jobject object) {
1558 sp<PersistentSurface> persistentSurface;
1559
1560 jobject lock = env->GetObjectField(
1561 object, gPersistentSurfaceClassInfo.mLock);
1562 if (env->MonitorEnter(lock) == JNI_OK) {
1563 persistentSurface = reinterpret_cast<PersistentSurface *>(
1564 env->GetLongField(object,
1565 gPersistentSurfaceClassInfo.mPersistentObject));
1566 env->MonitorExit(lock);
1567 }
1568 env->DeleteLocalRef(lock);
1569
1570 return persistentSurface;
1571}
1572
1573static jobject android_media_MediaCodec_createPersistentInputSurface(
1574 JNIEnv* env, jclass /* clazz */) {
1575 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1576 sp<PersistentSurface> persistentSurface =
1577 MediaCodec::CreatePersistentInputSurface();
1578
1579 if (persistentSurface == NULL) {
1580 return NULL;
1581 }
1582
1583 sp<Surface> surface = new Surface(
1584 persistentSurface->getBufferProducer(), true);
1585 if (surface == NULL) {
1586 return NULL;
1587 }
1588
1589 jobject object = env->NewObject(
1590 gPersistentSurfaceClassInfo.clazz,
1591 gPersistentSurfaceClassInfo.ctor);
1592
1593 if (object == NULL) {
1594 if (env->ExceptionCheck()) {
1595 ALOGE("Could not create PersistentSurface.");
1596 env->ExceptionClear();
1597 }
1598 return NULL;
1599 }
1600
1601 jobject lock = env->GetObjectField(
1602 object, gPersistentSurfaceClassInfo.mLock);
1603 if (env->MonitorEnter(lock) == JNI_OK) {
1604 env->CallVoidMethod(
1605 object,
1606 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1607 (jlong)surface.get());
1608 env->SetLongField(
1609 object,
1610 gPersistentSurfaceClassInfo.mPersistentObject,
1611 (jlong)persistentSurface.get());
1612 env->MonitorExit(lock);
1613 } else {
1614 env->DeleteLocalRef(object);
1615 object = NULL;
1616 }
1617 env->DeleteLocalRef(lock);
1618
1619 if (object != NULL) {
1620 surface->incStrong(&sRefBaseOwner);
1621 persistentSurface->incStrong(&sRefBaseOwner);
1622 }
1623
1624 return object;
1625}
1626
1627static void android_media_MediaCodec_releasePersistentInputSurface(
1628 JNIEnv* env, jclass /* clazz */, jobject object) {
1629 sp<PersistentSurface> persistentSurface;
1630
1631 jobject lock = env->GetObjectField(
1632 object, gPersistentSurfaceClassInfo.mLock);
1633 if (env->MonitorEnter(lock) == JNI_OK) {
1634 persistentSurface = reinterpret_cast<PersistentSurface *>(
1635 env->GetLongField(
1636 object, gPersistentSurfaceClassInfo.mPersistentObject));
1637 env->SetLongField(
1638 object,
1639 gPersistentSurfaceClassInfo.mPersistentObject,
1640 (jlong)0);
1641 env->MonitorExit(lock);
1642 }
1643 env->DeleteLocalRef(lock);
1644
1645 if (persistentSurface != NULL) {
1646 persistentSurface->decStrong(&sRefBaseOwner);
1647 }
1648 // no need to release surface as it will be released by Surface's jni
1649}
1650
Chong Zhang9560ddb2015-05-13 10:25:29 -07001651static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001652 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001653 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001654
1655 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001656 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001657 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001658 return;
1659 }
1660
1661 sp<PersistentSurface> persistentSurface =
1662 android_media_MediaCodec_getPersistentInputSurface(env, object);
1663
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001664 if (persistentSurface == NULL) {
1665 throwExceptionAsNecessary(
1666 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1667 return;
1668 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001669 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001670 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001671 throwExceptionAsNecessary(env, err, codec);
Chong Zhang8034d602015-04-28 13:38:48 -07001672 }
1673}
1674
Andy McFadden2621e402013-02-19 07:29:21 -08001675static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1676 jobject thiz) {
1677 ALOGV("android_media_MediaCodec_createInputSurface");
1678
1679 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001680 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001681 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001682 return NULL;
1683 }
1684
1685 // Tell the MediaCodec that we want to use a Surface as input.
1686 sp<IGraphicBufferProducer> bufferProducer;
1687 status_t err = codec->createInputSurface(&bufferProducer);
1688 if (err != NO_ERROR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001689 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08001690 return NULL;
1691 }
1692
1693 // Wrap the IGBP in a Java-language Surface.
1694 return android_view_Surface_createFromIGraphicBufferProducer(env,
1695 bufferProducer);
1696}
1697
Andreas Huber88572f72012-02-21 11:47:18 -08001698static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1699 ALOGV("android_media_MediaCodec_start");
1700
1701 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1702
Wonsik Kim24e53802020-05-08 20:04:26 -07001703 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001704 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001705 return;
1706 }
1707
1708 status_t err = codec->start();
1709
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001710 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001711}
1712
1713static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1714 ALOGV("android_media_MediaCodec_stop");
1715
1716 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1717
Wonsik Kim24e53802020-05-08 20:04:26 -07001718 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001719 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001720 return;
1721 }
1722
1723 status_t err = codec->stop();
1724
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001725 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001726}
1727
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001728static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1729 ALOGV("android_media_MediaCodec_reset");
1730
1731 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1732
Wonsik Kim24e53802020-05-08 20:04:26 -07001733 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001734 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001735 return;
1736 }
1737
1738 status_t err = codec->reset();
1739 if (err != OK) {
1740 // treat all errors as fatal for now, though resource not available
1741 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001742 // we also should avoid sending INVALID_OPERATION here due to
1743 // the transitory nature of reset(), it should not inadvertently
1744 // trigger an IllegalStateException.
1745 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001746 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001747 throwExceptionAsNecessary(env, err, codec);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001748}
1749
Andreas Huber88572f72012-02-21 11:47:18 -08001750static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1751 ALOGV("android_media_MediaCodec_flush");
1752
1753 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1754
Wonsik Kim24e53802020-05-08 20:04:26 -07001755 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001756 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001757 return;
1758 }
1759
1760 status_t err = codec->flush();
1761
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001762 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001763}
1764
1765static void android_media_MediaCodec_queueInputBuffer(
1766 JNIEnv *env,
1767 jobject thiz,
1768 jint index,
1769 jint offset,
1770 jint size,
1771 jlong timestampUs,
1772 jint flags) {
1773 ALOGV("android_media_MediaCodec_queueInputBuffer");
1774
1775 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1776
Wonsik Kim24e53802020-05-08 20:04:26 -07001777 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001778 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08001779 return;
1780 }
1781
Andreas Huberbfc56f42012-04-19 12:47:07 -07001782 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001783
Andreas Huberbfc56f42012-04-19 12:47:07 -07001784 status_t err = codec->queueInputBuffer(
1785 index, offset, size, timestampUs, flags, &errorDetailMsg);
1786
1787 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001788 env, err, ACTION_CODE_FATAL,
1789 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001790}
1791
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001792struct NativeCryptoInfo {
1793 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1794 : mEnv{env},
1795 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1796 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1797 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1798
1799 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1800 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1801
1802 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1803 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1804
1805 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1806 if (jmode == gCryptoModes.Unencrypted) {
1807 mMode = CryptoPlugin::kMode_Unencrypted;
1808 } else if (jmode == gCryptoModes.AesCtr) {
1809 mMode = CryptoPlugin::kMode_AES_CTR;
1810 } else if (jmode == gCryptoModes.AesCbc) {
1811 mMode = CryptoPlugin::kMode_AES_CBC;
1812 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001813 throwExceptionAsNecessary(
1814 env, INVALID_OPERATION, ACTION_CODE_FATAL,
1815 base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001816 return;
1817 }
1818
1819 ScopedLocalRef<jobject> patternObj{
1820 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1821
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001822 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001823 mPattern.mEncryptBlocks = 0;
1824 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001825 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001826 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001827 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001828 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001829 patternObj.get(), gFields.patternSkipBlocksID);
1830 }
1831
1832 mErr = OK;
1833 if (mNumSubSamples <= 0) {
1834 mErr = -EINVAL;
1835 } else if (numBytesOfClearDataObj == nullptr
1836 && numBytesOfEncryptedDataObj == nullptr) {
1837 mErr = -EINVAL;
1838 } else if (numBytesOfEncryptedDataObj != nullptr
1839 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1840 mErr = -ERANGE;
1841 } else if (numBytesOfClearDataObj != nullptr
1842 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1843 mErr = -ERANGE;
1844 // subSamples array may silently overflow if number of samples are too large. Use
1845 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1846 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1847 mErr = -EINVAL;
1848 } else {
1849 jint *numBytesOfClearData =
1850 (numBytesOfClearDataObj == nullptr)
1851 ? nullptr
1852 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1853
1854 jint *numBytesOfEncryptedData =
1855 (numBytesOfEncryptedDataObj == nullptr)
1856 ? nullptr
1857 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1858
1859 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1860
1861 for (jint i = 0; i < mNumSubSamples; ++i) {
1862 mSubSamples[i].mNumBytesOfClearData =
1863 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1864
1865 mSubSamples[i].mNumBytesOfEncryptedData =
1866 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1867 }
1868
1869 if (numBytesOfEncryptedData != nullptr) {
1870 env->ReleaseIntArrayElements(
1871 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1872 numBytesOfEncryptedData = nullptr;
1873 }
1874
1875 if (numBytesOfClearData != nullptr) {
1876 env->ReleaseIntArrayElements(
1877 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1878 numBytesOfClearData = nullptr;
1879 }
1880 }
1881
1882 if (mErr == OK && mKeyObj.get() != nullptr) {
1883 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1884 mErr = -EINVAL;
1885 } else {
1886 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1887 }
1888 }
1889
1890 if (mErr == OK && mIvObj.get() != nullptr) {
1891 if (env->GetArrayLength(mIvObj.get()) != 16) {
1892 mErr = -EINVAL;
1893 } else {
1894 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1895 }
1896 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001897
1898 }
1899
1900 explicit NativeCryptoInfo(jint size)
1901 : mIvObj{nullptr, nullptr},
1902 mKeyObj{nullptr, nullptr},
1903 mMode{CryptoPlugin::kMode_Unencrypted},
1904 mPattern{0, 0} {
1905 mSubSamples = new CryptoPlugin::SubSample[1];
1906 mNumSubSamples = 1;
1907 mSubSamples[0].mNumBytesOfClearData = size;
1908 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001909 }
1910
1911 ~NativeCryptoInfo() {
1912 if (mIv != nullptr) {
1913 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1914 }
1915
1916 if (mKey != nullptr) {
1917 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1918 }
1919
1920 if (mSubSamples != nullptr) {
1921 delete[] mSubSamples;
1922 }
1923 }
1924
1925 JNIEnv *mEnv{nullptr};
1926 ScopedLocalRef<jbyteArray> mIvObj;
1927 ScopedLocalRef<jbyteArray> mKeyObj;
1928 status_t mErr{OK};
1929
1930 CryptoPlugin::SubSample *mSubSamples{nullptr};
1931 int32_t mNumSubSamples{0};
1932 jbyte *mIv{nullptr};
1933 jbyte *mKey{nullptr};
1934 enum CryptoPlugin::Mode mMode;
1935 CryptoPlugin::Pattern mPattern;
1936};
1937
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001938static void android_media_MediaCodec_queueSecureInputBuffer(
1939 JNIEnv *env,
1940 jobject thiz,
1941 jint index,
1942 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001943 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001944 jlong timestampUs,
1945 jint flags) {
1946 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1947
1948 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1949
Wonsik Kim24e53802020-05-08 20:04:26 -07001950 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001951 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001952 return;
1953 }
1954
Wonsik Kim1cac4252020-01-24 11:45:37 -08001955 jint numSubSamples =
1956 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1957
1958 jintArray numBytesOfClearDataObj =
1959 (jintArray)env->GetObjectField(
1960 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1961
1962 jintArray numBytesOfEncryptedDataObj =
1963 (jintArray)env->GetObjectField(
1964 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1965
1966 jbyteArray keyObj =
1967 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1968
1969 jbyteArray ivObj =
1970 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1971
1972 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1973 enum CryptoPlugin::Mode mode;
1974 if (jmode == gCryptoModes.Unencrypted) {
1975 mode = CryptoPlugin::kMode_Unencrypted;
1976 } else if (jmode == gCryptoModes.AesCtr) {
1977 mode = CryptoPlugin::kMode_AES_CTR;
1978 } else if (jmode == gCryptoModes.AesCbc) {
1979 mode = CryptoPlugin::kMode_AES_CBC;
1980 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08001981 throwExceptionAsNecessary(
1982 env, INVALID_OPERATION, ACTION_CODE_FATAL,
1983 base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
Wonsik Kim1cac4252020-01-24 11:45:37 -08001984 return;
1985 }
1986
1987 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1988
1989 CryptoPlugin::Pattern pattern;
1990 if (patternObj == NULL) {
1991 pattern.mEncryptBlocks = 0;
1992 pattern.mSkipBlocks = 0;
1993 } else {
1994 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1995 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1996 }
1997
1998 status_t err = OK;
1999
2000 CryptoPlugin::SubSample *subSamples = NULL;
2001 jbyte *key = NULL;
2002 jbyte *iv = NULL;
2003
2004 if (numSubSamples <= 0) {
2005 err = -EINVAL;
2006 } else if (numBytesOfClearDataObj == NULL
2007 && numBytesOfEncryptedDataObj == NULL) {
2008 err = -EINVAL;
2009 } else if (numBytesOfEncryptedDataObj != NULL
2010 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
2011 err = -ERANGE;
2012 } else if (numBytesOfClearDataObj != NULL
2013 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
2014 err = -ERANGE;
2015 // subSamples array may silently overflow if number of samples are too large. Use
2016 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
2017 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
2018 err = -EINVAL;
2019 } else {
2020 jboolean isCopy;
2021
2022 jint *numBytesOfClearData =
2023 (numBytesOfClearDataObj == NULL)
2024 ? NULL
2025 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
2026
2027 jint *numBytesOfEncryptedData =
2028 (numBytesOfEncryptedDataObj == NULL)
2029 ? NULL
2030 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
2031
2032 subSamples = new CryptoPlugin::SubSample[numSubSamples];
2033
2034 for (jint i = 0; i < numSubSamples; ++i) {
2035 subSamples[i].mNumBytesOfClearData =
2036 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
2037
2038 subSamples[i].mNumBytesOfEncryptedData =
2039 (numBytesOfEncryptedData == NULL)
2040 ? 0 : numBytesOfEncryptedData[i];
2041 }
2042
2043 if (numBytesOfEncryptedData != NULL) {
2044 env->ReleaseIntArrayElements(
2045 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
2046 numBytesOfEncryptedData = NULL;
2047 }
2048
2049 if (numBytesOfClearData != NULL) {
2050 env->ReleaseIntArrayElements(
2051 numBytesOfClearDataObj, numBytesOfClearData, 0);
2052 numBytesOfClearData = NULL;
2053 }
2054 }
2055
2056 if (err == OK && keyObj != NULL) {
2057 if (env->GetArrayLength(keyObj) != 16) {
2058 err = -EINVAL;
2059 } else {
2060 jboolean isCopy;
2061 key = env->GetByteArrayElements(keyObj, &isCopy);
2062 }
2063 }
2064
2065 if (err == OK && ivObj != NULL) {
2066 if (env->GetArrayLength(ivObj) != 16) {
2067 err = -EINVAL;
2068 } else {
2069 jboolean isCopy;
2070 iv = env->GetByteArrayElements(ivObj, &isCopy);
2071 }
2072 }
2073
Andreas Huberbfc56f42012-04-19 12:47:07 -07002074 AString errorDetailMsg;
2075
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002076 if (err == OK) {
2077 err = codec->queueSecureInputBuffer(
2078 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08002079 subSamples, numSubSamples,
2080 (const uint8_t *)key, (const uint8_t *)iv,
2081 mode,
2082 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07002083 timestampUs,
2084 flags,
2085 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002086 }
2087
Wonsik Kim1cac4252020-01-24 11:45:37 -08002088 if (iv != NULL) {
2089 env->ReleaseByteArrayElements(ivObj, iv, 0);
2090 iv = NULL;
2091 }
2092
2093 if (key != NULL) {
2094 env->ReleaseByteArrayElements(keyObj, key, 0);
2095 key = NULL;
2096 }
2097
2098 delete[] subSamples;
2099 subSamples = NULL;
2100
Andreas Huberbfc56f42012-04-19 12:47:07 -07002101 throwExceptionAsNecessary(
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002102 env, err, ACTION_CODE_FATAL,
2103 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002104}
2105
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002106static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002107 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
2108 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2109 env, bufferObj);
2110 AHardwareBuffer_Desc desc;
2111 AHardwareBuffer_describe(hardwareBuffer, &desc);
2112 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
2113 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
2114 return nullptr;
2115 }
2116 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
2117 ALOGI("mapHardwareBuffer: buffer not CPU readable");
2118 return nullptr;
2119 }
2120 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
2121
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002122 uint64_t cpuUsage = 0;
2123 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
2124 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08002125
2126 AHardwareBuffer_Planes planes;
2127 int err = AHardwareBuffer_lockPlanes(
2128 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
2129 if (err != 0) {
2130 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
2131 return nullptr;
2132 }
2133
2134 if (planes.planeCount != 3) {
2135 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
2136 return nullptr;
2137 }
2138
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002139 ScopedLocalRef<jobjectArray> buffersArray{
2140 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
2141 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
2142 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08002143
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002144 jboolean isCopy = JNI_FALSE;
2145 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2146 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
2147
2148 // For Y plane
2149 int rowSampling = 1;
2150 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08002151 // plane indices are Y-U-V.
2152 for (uint32_t i = 0; i < 3; ++i) {
2153 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002154 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
2155 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
2156 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08002157 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
2158 env,
2159 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002160 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002161 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002162 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08002163 readOnly,
2164 true)};
2165
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002166 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
2167 rowStrides[i] = plane.rowStride;
2168 pixelStrides[i] = plane.pixelStride;
2169 // For U-V planes
2170 rowSampling = 2;
2171 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08002172 }
2173
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002174 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
2175 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
2176 rowStrides = pixelStrides = nullptr;
2177
Wonsik Kim637afb22020-02-25 14:27:29 -08002178 ScopedLocalRef<jclass> imageClazz(
2179 env, env->FindClass("android/media/MediaCodec$MediaImage"));
2180 CHECK(imageClazz.get() != NULL);
2181
2182 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002183 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08002184
2185 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002186 buffersArray.get(),
2187 rowStridesArray.get(),
2188 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002189 desc.width,
2190 desc.height,
2191 desc.format, // ???
2192 (jboolean)readOnly /* readOnly */,
2193 (jlong)0 /* timestamp */,
2194 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2195 (jlong)hardwareBuffer);
2196
2197 // if MediaImage creation fails, return null
2198 if (env->ExceptionCheck()) {
2199 env->ExceptionDescribe();
2200 env->ExceptionClear();
2201 return nullptr;
2202 }
2203
2204 AHardwareBuffer_acquire(hardwareBuffer);
2205
2206 return img;
2207}
2208
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002209static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2210 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002211 if (context == 0) {
2212 return;
2213 }
2214 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2215
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002216 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2217 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002218 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2219 // Continue to release the hardwareBuffer
2220 }
2221
2222 AHardwareBuffer_release(hardwareBuffer);
2223}
2224
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002225static status_t ConvertKeyValueListsToAMessage(
2226 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2227 static struct Fields {
2228 explicit Fields(JNIEnv *env) {
2229 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2230 CHECK(clazz.get() != NULL);
2231 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2232
2233 clazz.reset(env->FindClass("java/lang/Integer"));
2234 CHECK(clazz.get() != NULL);
2235 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2236
2237 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2238 CHECK(mIntegerValueId != NULL);
2239
2240 clazz.reset(env->FindClass("java/lang/Long"));
2241 CHECK(clazz.get() != NULL);
2242 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2243
2244 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2245 CHECK(mLongValueId != NULL);
2246
2247 clazz.reset(env->FindClass("java/lang/Float"));
2248 CHECK(clazz.get() != NULL);
2249 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2250
2251 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2252 CHECK(mFloatValueId != NULL);
2253
2254 clazz.reset(env->FindClass("java/util/ArrayList"));
2255 CHECK(clazz.get() != NULL);
2256
2257 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2258 CHECK(mByteBufferArrayId != NULL);
2259 }
2260
2261 jclass mStringClass;
2262 jclass mIntegerClass;
2263 jmethodID mIntegerValueId;
2264 jclass mLongClass;
2265 jmethodID mLongValueId;
2266 jclass mFloatClass;
2267 jmethodID mFloatValueId;
2268 jmethodID mByteBufferArrayId;
2269 } sFields{env};
2270
2271 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2272 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2273 return BAD_VALUE;
2274 }
2275
2276 sp<AMessage> result{new AMessage};
2277 for (jint i = 0; i < size; ++i) {
2278 ScopedLocalRef<jstring> jkey{
2279 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2280 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2281 AString key;
2282 if (tmp) {
2283 key.setTo(tmp);
2284 }
2285 env->ReleaseStringUTFChars(jkey.get(), tmp);
2286 if (key.empty()) {
2287 return NO_MEMORY;
2288 }
2289
2290 ScopedLocalRef<jobject> jvalue{
2291 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2292
2293 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2294 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2295 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002296 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002297 return NO_MEMORY;
2298 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002299 value.setTo(tmp);
2300 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002301 result->setString(key.c_str(), value);
2302 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2303 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2304 result->setInt32(key.c_str(), value);
2305 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2306 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2307 result->setInt64(key.c_str(), value);
2308 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2309 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2310 result->setFloat(key.c_str(), value);
2311 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002312 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2313 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002314 sp<ABuffer> buffer{new ABuffer(limit - position)};
2315 void *data = env->GetDirectBufferAddress(jvalue.get());
2316 if (data != nullptr) {
2317 memcpy(buffer->data(),
2318 static_cast<const uint8_t *>(data) + position,
2319 buffer->size());
2320 } else {
2321 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2322 jvalue.get(), sFields.mByteBufferArrayId)};
2323 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2324 reinterpret_cast<jbyte *>(buffer->data()));
2325 }
2326 result->setBuffer(key.c_str(), buffer);
2327 }
2328 }
2329
2330 *msg = result;
2331 return OK;
2332}
2333
Wonsik Kim8569a662022-05-24 14:16:44 -07002334static bool obtain(
2335 JMediaCodecLinearBlock *context,
2336 int capacity,
2337 const std::vector<std::string> &names,
2338 bool secure) {
2339 if (secure) {
2340 // Start at 1MB, which is an arbitrary starting point that can
2341 // increase when needed.
2342 constexpr size_t kInitialDealerCapacity = 1048576;
2343 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
2344 kInitialDealerCapacity, "JNI(1MB)");
2345 context->mMemory = sDealer->allocate(capacity);
2346 if (context->mMemory == nullptr) {
2347 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
2348 while (capacity * 2 > newDealerCapacity) {
2349 newDealerCapacity *= 2;
2350 }
2351 ALOGI("LinearBlock.native_obtain: "
2352 "Dealer capacity increasing from %zuMB to %zuMB",
2353 sDealer->getMemoryHeap()->getSize() / 1048576,
2354 newDealerCapacity / 1048576);
2355 sDealer = new MemoryDealer(
2356 newDealerCapacity,
2357 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
2358 context->mMemory = sDealer->allocate(capacity);
2359 }
2360 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
2361 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
2362 } else {
2363 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2364 if (!context->mBlock) {
2365 return false;
2366 }
2367 }
2368 context->mCodecNames = names;
2369 return true;
2370}
2371
2372static void extractMemoryFromContext(
2373 JMediaCodecLinearBlock *context,
2374 jint offset,
2375 jint size,
2376 sp<hardware::HidlMemory> *memory) {
2377 *memory = context->toHidlMemory();
2378 if (*memory == nullptr) {
2379 if (!context->mBlock) {
2380 ALOGW("extractMemoryFromContext: the buffer is missing both IMemory and C2Block");
2381 return;
2382 }
2383 ALOGD("extractMemoryFromContext: realloc & copying from C2Block to IMemory (cap=%zu)",
2384 context->capacity());
2385 if (!obtain(context, context->capacity(),
2386 context->mCodecNames, true /* secure */)) {
2387 ALOGW("extractMemoryFromContext: failed to obtain secure block");
2388 return;
2389 }
2390 C2WriteView view = context->mBlock->map().get();
2391 if (view.error() != C2_OK) {
2392 ALOGW("extractMemoryFromContext: failed to map C2Block (%d)", view.error());
2393 return;
2394 }
2395 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2396 memcpy(memoryPtr + offset, view.base() + offset, size);
2397 context->mBlock.reset();
2398 context->mReadWriteMapping.reset();
2399 *memory = context->toHidlMemory();
2400 }
2401}
2402
2403static void extractBufferFromContext(
2404 JMediaCodecLinearBlock *context,
2405 jint offset,
2406 jint size,
2407 std::shared_ptr<C2Buffer> *buffer) {
2408 *buffer = context->toC2Buffer(offset, size);
2409 if (*buffer == nullptr) {
2410 if (!context->mMemory) {
2411 ALOGW("extractBufferFromContext: the buffer is missing both IMemory and C2Block");
2412 return;
2413 }
2414 ALOGD("extractBufferFromContext: realloc & copying from IMemory to C2Block (cap=%zu)",
2415 context->capacity());
2416 if (obtain(context, context->capacity(),
2417 context->mCodecNames, false /* secure */)) {
2418 ALOGW("extractBufferFromContext: failed to obtain non-secure block");
2419 return;
2420 }
2421 C2WriteView view = context->mBlock->map().get();
2422 if (view.error() != C2_OK) {
2423 ALOGW("extractBufferFromContext: failed to map C2Block (%d)", view.error());
2424 return;
2425 }
2426 uint8_t *memoryPtr = static_cast<uint8_t *>(context->mMemory->unsecurePointer());
2427 memcpy(view.base() + offset, memoryPtr + offset, size);
2428 context->mMemory.clear();
2429 context->mHidlMemory.clear();
2430 context->mHidlMemorySize = 0;
2431 context->mHidlMemoryOffset = 0;
2432 *buffer = context->toC2Buffer(offset, size);
2433 }
2434}
2435
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002436static void android_media_MediaCodec_native_queueLinearBlock(
2437 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2438 jint offset, jint size, jobject cryptoInfoObj,
2439 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2440 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2441
2442 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2443
Wonsik Kim24e53802020-05-08 20:04:26 -07002444 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002445 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002446 return;
2447 }
2448
2449 sp<AMessage> tunings;
2450 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2451 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002452 throwExceptionAsNecessary(
2453 env, err, ACTION_CODE_FATAL,
2454 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002455 return;
2456 }
2457
2458 std::shared_ptr<C2Buffer> buffer;
2459 sp<hardware::HidlMemory> memory;
2460 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2461 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2462 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2463 JMediaCodecLinearBlock *context =
2464 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002465 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kim8569a662022-05-24 14:16:44 -07002466 extractMemoryFromContext(context, offset, size, &memory);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002467 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002468 } else {
Wonsik Kim8569a662022-05-24 14:16:44 -07002469 extractBufferFromContext(context, offset, size, &buffer);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002470 }
2471 }
2472 env->MonitorExit(lock.get());
2473 } else {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002474 throwExceptionAsNecessary(
2475 env, INVALID_OPERATION, ACTION_CODE_FATAL,
2476 "Failed to grab lock for a LinearBlock object");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002477 return;
2478 }
2479
2480 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002481 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002482 if (!memory) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002483 // It means there was an unexpected failure in extractMemoryFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002484 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002485 throwExceptionAsNecessary(
2486 env, BAD_VALUE, ACTION_CODE_FATAL,
2487 "Unexpected error: the input buffer is not compatible with "
2488 "the secure codec, and a fallback logic failed.\n"
2489 "Suggestion: please try including the secure codec when calling "
2490 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002491 return;
2492 }
George Burgess IV436998b2022-11-02 11:42:33 -06002493 auto cryptoInfo =
Robert Shihfe3785c2023-07-11 07:27:02 +00002494 cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{size};
George Burgess IV436998b2022-11-02 11:42:33 -06002495 if (env->ExceptionCheck()) {
2496 // Creation of cryptoInfo failed. Let the exception bubble up.
2497 return;
2498 }
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002499 err = codec->queueEncryptedLinearBlock(
2500 index,
2501 memory,
2502 offset,
2503 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2504 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2505 cryptoInfo.mMode,
2506 cryptoInfo.mPattern,
2507 presentationTimeUs,
2508 flags,
2509 tunings,
2510 &errorDetailMsg);
Wonsik Kim8569a662022-05-24 14:16:44 -07002511 ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002512 } else {
2513 if (!buffer) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002514 // It means there was an unexpected failure in extractBufferFromContext above
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002515 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002516 throwExceptionAsNecessary(
2517 env, BAD_VALUE, ACTION_CODE_FATAL,
2518 "Unexpected error: the input buffer is not compatible with "
2519 "the non-secure codec, and a fallback logic failed.\n"
2520 "Suggestion: please do not include the secure codec when calling "
2521 "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002522 return;
2523 }
2524 err = codec->queueBuffer(
2525 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2526 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002527 throwExceptionAsNecessary(
2528 env, err, ACTION_CODE_FATAL,
2529 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002530}
2531
Wonsik Kim637afb22020-02-25 14:27:29 -08002532static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002533 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2534 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002535 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002536
2537 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2538
Wonsik Kim24e53802020-05-08 20:04:26 -07002539 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002540 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002541 return;
2542 }
2543
2544 sp<AMessage> tunings;
2545 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2546 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002547 throwExceptionAsNecessary(
2548 env, err, ACTION_CODE_FATAL,
2549 "error occurred while converting tunings from Java to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002550 return;
2551 }
2552
Wonsik Kim637afb22020-02-25 14:27:29 -08002553 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2554 env, bufferObj);
2555 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2556 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002557 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2558 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2559 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2560 std::shared_ptr<C2Allocator> alloc;
2561 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2562 C2PlatformAllocatorStore::GRALLOC, &alloc);
2563 if (err == C2_OK) {
2564 return alloc;
2565 }
2566 return nullptr;
2567 }();
2568 std::shared_ptr<C2GraphicAllocation> alloc;
2569 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2570 if (c2err != C2_OK) {
2571 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Chih-Yu Huangef546db2021-03-11 14:37:21 +09002572 native_handle_close(handle);
2573 native_handle_delete(handle);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002574 throwExceptionAsNecessary(
2575 env, BAD_VALUE, ACTION_CODE_FATAL,
2576 "HardwareBuffer not recognized");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002577 return;
2578 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002579 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002580 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2581 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002582 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002583 err = codec->queueBuffer(
2584 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002585 throwExceptionAsNecessary(
2586 env, err, ACTION_CODE_FATAL,
2587 codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002588}
2589
2590static void android_media_MediaCodec_native_getOutputFrame(
2591 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2592 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2593
2594 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2595
Wonsik Kim24e53802020-05-08 20:04:26 -07002596 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002597 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002598 return;
2599 }
2600
2601 status_t err = codec->getOutputFrame(env, frame, index);
2602 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002603 throwExceptionAsNecessary(env, err, codec);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002604 }
2605}
2606
Andreas Huber88572f72012-02-21 11:47:18 -08002607static jint android_media_MediaCodec_dequeueInputBuffer(
2608 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2609 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2610
2611 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2612
Wonsik Kim24e53802020-05-08 20:04:26 -07002613 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002614 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002615 return -1;
2616 }
2617
2618 size_t index;
2619 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2620
2621 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002622 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002623 }
2624
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002625 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002626}
2627
2628static jint android_media_MediaCodec_dequeueOutputBuffer(
2629 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2630 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2631
2632 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2633
Wonsik Kim24e53802020-05-08 20:04:26 -07002634 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002635 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002636 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002637 }
2638
2639 size_t index;
2640 status_t err = codec->dequeueOutputBuffer(
2641 env, bufferInfo, &index, timeoutUs);
2642
2643 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002644 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002645 }
2646
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002647 return throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002648}
2649
2650static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002651 JNIEnv *env, jobject thiz,
2652 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002653 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2654
2655 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2656
Wonsik Kim24e53802020-05-08 20:04:26 -07002657 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002658 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002659 return;
2660 }
2661
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002662 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002663
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002664 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002665}
2666
Andy McFadden2621e402013-02-19 07:29:21 -08002667static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2668 jobject thiz) {
2669 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2670
2671 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002672 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002673 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002674 return;
2675 }
2676
2677 status_t err = codec->signalEndOfInputStream();
2678
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002679 throwExceptionAsNecessary(env, err, codec);
Andy McFadden2621e402013-02-19 07:29:21 -08002680}
2681
Lajos Molnard4023112014-07-11 15:12:59 -07002682static jobject android_media_MediaCodec_getFormatNative(
2683 JNIEnv *env, jobject thiz, jboolean input) {
2684 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002685
2686 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2687
Wonsik Kim24e53802020-05-08 20:04:26 -07002688 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002689 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002690 return NULL;
2691 }
2692
2693 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002694 status_t err = codec->getFormat(env, input, &format);
2695
2696 if (err == OK) {
2697 return format;
2698 }
2699
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002700 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002701
2702 return NULL;
2703}
2704
2705static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2706 JNIEnv *env, jobject thiz, jint index) {
2707 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2708
2709 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2710
Wonsik Kim24e53802020-05-08 20:04:26 -07002711 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002712 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002713 return NULL;
2714 }
2715
2716 jobject format;
2717 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002718
2719 if (err == OK) {
2720 return format;
2721 }
2722
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002723 throwExceptionAsNecessary(env, err, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002724
2725 return NULL;
2726}
2727
2728static jobjectArray android_media_MediaCodec_getBuffers(
2729 JNIEnv *env, jobject thiz, jboolean input) {
2730 ALOGV("android_media_MediaCodec_getBuffers");
2731
2732 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2733
Wonsik Kim24e53802020-05-08 20:04:26 -07002734 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002735 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08002736 return NULL;
2737 }
2738
2739 jobjectArray buffers;
2740 status_t err = codec->getBuffers(env, input, &buffers);
2741
2742 if (err == OK) {
2743 return buffers;
2744 }
2745
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002746 // if we're out of memory, an exception was already thrown
2747 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002748 throwExceptionAsNecessary(env, err, codec);
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002749 }
Andreas Huber88572f72012-02-21 11:47:18 -08002750
2751 return NULL;
2752}
2753
Lajos Molnard4023112014-07-11 15:12:59 -07002754static jobject android_media_MediaCodec_getBuffer(
2755 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2756 ALOGV("android_media_MediaCodec_getBuffer");
2757
2758 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2759
Wonsik Kim24e53802020-05-08 20:04:26 -07002760 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002761 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002762 return NULL;
2763 }
2764
2765 jobject buffer;
2766 status_t err = codec->getBuffer(env, input, index, &buffer);
2767
2768 if (err == OK) {
2769 return buffer;
2770 }
2771
2772 // if we're out of memory, an exception was already thrown
2773 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002774 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002775 }
2776
2777 return NULL;
2778}
2779
2780static jobject android_media_MediaCodec_getImage(
2781 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2782 ALOGV("android_media_MediaCodec_getImage");
2783
2784 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2785
Wonsik Kim24e53802020-05-08 20:04:26 -07002786 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002787 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002788 return NULL;
2789 }
2790
2791 jobject image;
2792 status_t err = codec->getImage(env, input, index, &image);
2793
2794 if (err == OK) {
2795 return image;
2796 }
2797
2798 // if we're out of memory, an exception was already thrown
2799 if (err != NO_MEMORY) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002800 throwExceptionAsNecessary(env, err, codec);
Lajos Molnard4023112014-07-11 15:12:59 -07002801 }
2802
2803 return NULL;
2804}
2805
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002806static jobject android_media_MediaCodec_getName(
2807 JNIEnv *env, jobject thiz) {
2808 ALOGV("android_media_MediaCodec_getName");
2809
2810 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2811
Wonsik Kim24e53802020-05-08 20:04:26 -07002812 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002813 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002814 return NULL;
2815 }
2816
2817 jstring name;
2818 status_t err = codec->getName(env, &name);
2819
2820 if (err == OK) {
2821 return name;
2822 }
2823
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002824 throwExceptionAsNecessary(env, err, codec);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002825
2826 return NULL;
2827}
2828
Chong Zhanga0b72a62018-02-28 18:46:26 -08002829static jobject android_media_MediaCodec_getOwnCodecInfo(
2830 JNIEnv *env, jobject thiz) {
2831 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2832
2833 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2834
Wonsik Kim24e53802020-05-08 20:04:26 -07002835 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002836 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08002837 return NULL;
2838 }
2839
2840 jobject codecInfoObj;
2841 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2842
2843 if (err == OK) {
2844 return codecInfoObj;
2845 }
2846
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002847 throwExceptionAsNecessary(env, err, codec);
Chong Zhanga0b72a62018-02-28 18:46:26 -08002848
2849 return NULL;
2850}
2851
Ray Essick0e0fee12017-01-25 18:01:56 -08002852static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002853android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002854{
Ray Essickf2d0e402017-03-09 10:17:51 -08002855 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002856
2857 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002858 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002859 jniThrowException(env, "java/lang/IllegalStateException",
2860 GetExceptionMessage(codec, NULL).c_str());
Ray Essick0e0fee12017-01-25 18:01:56 -08002861 return 0;
2862 }
2863
2864 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002865 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002866
2867 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002868 if (err != OK) {
2869 ALOGE("getMetrics failed");
2870 return (jobject) NULL;
2871 }
2872
Ray Essick0e0fee12017-01-25 18:01:56 -08002873 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2874
2875 // housekeeping
2876 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002877 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002878
2879 return mybundle;
2880}
2881
Andreas Huber226065b2013-08-12 10:14:11 -07002882static void android_media_MediaCodec_setParameters(
2883 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2884 ALOGV("android_media_MediaCodec_setParameters");
2885
2886 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2887
Wonsik Kim24e53802020-05-08 20:04:26 -07002888 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002889 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07002890 return;
2891 }
2892
2893 sp<AMessage> params;
2894 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2895
2896 if (err == OK) {
2897 err = codec->setParameters(params);
2898 }
2899
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002900 throwExceptionAsNecessary(env, err, codec);
Andreas Huber226065b2013-08-12 10:14:11 -07002901}
2902
Andreas Huberb12a5392012-04-30 14:18:33 -07002903static void android_media_MediaCodec_setVideoScalingMode(
2904 JNIEnv *env, jobject thiz, jint mode) {
2905 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2906
Wonsik Kim24e53802020-05-08 20:04:26 -07002907 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002908 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Andreas Huberb12a5392012-04-30 14:18:33 -07002909 return;
2910 }
2911
2912 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2913 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002914 jniThrowException(env, "java/lang/IllegalArgumentException",
2915 String8::format("Unrecognized mode: %d", mode));
Andreas Huberb12a5392012-04-30 14:18:33 -07002916 return;
2917 }
2918
2919 codec->setVideoScalingMode(mode);
2920}
2921
ybai5e053202018-11-01 13:02:15 +08002922static void android_media_MediaCodec_setAudioPresentation(
2923 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2924 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2925
Wonsik Kim24e53802020-05-08 20:04:26 -07002926 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002927 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
ybai5e053202018-11-01 13:02:15 +08002928 return;
2929 }
2930
2931 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2932}
2933
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002934static jobject android_media_MediaCodec_getSupportedVendorParameters(
2935 JNIEnv *env, jobject thiz) {
2936 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2937
2938 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002939 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002940 return NULL;
2941 }
2942
2943 jobject ret = NULL;
2944 status_t status = codec->querySupportedVendorParameters(env, &ret);
2945 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002946 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002947 }
2948
2949 return ret;
2950}
2951
2952static jobject android_media_MediaCodec_getParameterDescriptor(
2953 JNIEnv *env, jobject thiz, jstring name) {
2954 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2955
2956 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002957 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002958 return NULL;
2959 }
2960
2961 jobject ret = NULL;
2962 status_t status = codec->describeParameter(env, name, &ret);
2963 if (status != OK) {
2964 ret = NULL;
2965 }
2966 return ret;
2967}
2968
2969static void android_media_MediaCodec_subscribeToVendorParameters(
2970 JNIEnv *env, jobject thiz, jobject names) {
2971 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2972
2973 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002974 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002975 return;
2976 }
2977
2978 status_t status = codec->subscribeToVendorParameters(env, names);
2979 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002980 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002981 }
2982 return;
2983}
2984
2985static void android_media_MediaCodec_unsubscribeFromVendorParameters(
2986 JNIEnv *env, jobject thiz, jobject names) {
2987 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2988
2989 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002990 throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002991 return;
2992 }
2993
2994 status_t status = codec->unsubscribeFromVendorParameters(env, names);
2995 if (status != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08002996 throwExceptionAsNecessary(env, status, codec);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07002997 }
2998 return;
2999}
3000
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003001static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003002 ScopedLocalRef<jclass> clazz(
3003 env, env->FindClass("android/media/MediaCodec"));
3004 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003005
Andreas Huberaba67132013-10-22 12:40:01 -07003006 gFields.postEventFromNativeID =
3007 env->GetMethodID(
3008 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07003009 CHECK(gFields.postEventFromNativeID != NULL);
3010
Wonsik Kim61796fd2018-09-13 13:15:59 -07003011 gFields.lockAndGetContextID =
3012 env->GetMethodID(
3013 clazz.get(), "lockAndGetContext", "()J");
3014 CHECK(gFields.lockAndGetContextID != NULL);
3015
3016 gFields.setAndUnlockContextID =
3017 env->GetMethodID(
3018 clazz.get(), "setAndUnlockContext", "(J)V");
3019 CHECK(gFields.setAndUnlockContextID != NULL);
3020
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003021 jfieldID field;
3022 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
3023 CHECK(field != NULL);
3024 gCryptoModes.Unencrypted =
3025 env->GetStaticIntField(clazz.get(), field);
3026
3027 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
3028 CHECK(field != NULL);
3029 gCryptoModes.AesCtr =
3030 env->GetStaticIntField(clazz.get(), field);
3031
3032 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
3033 CHECK(field != NULL);
3034 gCryptoModes.AesCbc =
3035 env->GetStaticIntField(clazz.get(), field);
3036
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003037 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
3038 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07003039
3040 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003041 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003042 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
3043
3044 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003045 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003046 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
3047
3048 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003049 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003050 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
3051
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003052 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003053 CHECK(gFields.cryptoInfoKeyID != NULL);
3054
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003055 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07003056 CHECK(gFields.cryptoInfoIVID != NULL);
3057
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003058 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07003059 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003060
Santiago Seifert09ae5f62020-09-18 16:51:04 +01003061 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08003062 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
3063 CHECK(gFields.cryptoInfoPatternID != NULL);
3064
3065 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
3066 CHECK(clazz.get() != NULL);
3067
3068 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
3069 CHECK(gFields.patternEncryptBlocksID != NULL);
3070
3071 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
3072 CHECK(gFields.patternSkipBlocksID != NULL);
3073
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003074 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
3075 CHECK(clazz.get() != NULL);
3076
3077 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
3078 CHECK(gFields.queueRequestIndexID != NULL);
3079
3080 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
3081 CHECK(clazz.get() != NULL);
3082
3083 gFields.outputFrameLinearBlockID =
3084 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
3085 CHECK(gFields.outputFrameLinearBlockID != NULL);
3086
Wonsik Kim637afb22020-02-25 14:27:29 -08003087 gFields.outputFrameHardwareBufferID =
3088 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
3089 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003090
3091 gFields.outputFrameChangedKeysID =
3092 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
3093 CHECK(gFields.outputFrameChangedKeysID != NULL);
3094
3095 gFields.outputFrameFormatID =
3096 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
3097 CHECK(gFields.outputFrameFormatID != NULL);
3098
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003099 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
3100 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003101
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003102 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003103 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003104 gCryptoErrorCodes.cryptoErrorNoKey =
3105 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003106
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003107 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003108 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003109 gCryptoErrorCodes.cryptoErrorKeyExpired =
3110 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07003111
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003112 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07003113 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07003114 gCryptoErrorCodes.cryptoErrorResourceBusy =
3115 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003116
Jeff Tinker336d3ea2014-08-28 17:57:36 -07003117 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
3118 CHECK(field != NULL);
3119 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
3120 env->GetStaticIntField(clazz.get(), field);
3121
Jeff Tinker96a2a952015-07-01 17:35:18 -07003122 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
3123 CHECK(field != NULL);
3124 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
3125 env->GetStaticIntField(clazz.get(), field);
3126
Jeff Tinker20594d82018-12-12 08:31:22 -08003127 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
3128 CHECK(field != NULL);
3129 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
3130 env->GetStaticIntField(clazz.get(), field);
3131
Jeff Tinkerd3932162016-03-05 11:35:20 -08003132 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
3133 CHECK(field != NULL);
3134 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
3135 env->GetStaticIntField(clazz.get(), field);
3136
Jeff Tinker20594d82018-12-12 08:31:22 -08003137 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
3138 CHECK(field != NULL);
3139 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
3140 env->GetStaticIntField(clazz.get(), field);
3141
3142 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
3143 CHECK(field != NULL);
3144 gCryptoErrorCodes.cryptoErrorLostState =
3145 env->GetStaticIntField(clazz.get(), field);
3146
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003147 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
3148 CHECK(clazz.get() != NULL);
3149 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
3150 CHECK(field != NULL);
3151 gCodecActionCodes.codecActionTransient =
3152 env->GetStaticIntField(clazz.get(), field);
3153
3154 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
3155 CHECK(field != NULL);
3156 gCodecActionCodes.codecActionRecoverable =
3157 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003158
Ronghua Wuc53ad692015-05-08 14:40:49 -07003159 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003160 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003161 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003162 env->GetStaticIntField(clazz.get(), field);
3163
Ronghua Wuc53ad692015-05-08 14:40:49 -07003164 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003165 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07003166 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07003167 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07003168
3169 clazz.reset(env->FindClass("android/view/Surface"));
3170 CHECK(clazz.get() != NULL);
3171
3172 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3173 CHECK(field != NULL);
3174 gPersistentSurfaceClassInfo.mLock = field;
3175
3176 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
3177 CHECK(method != NULL);
3178 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
3179
3180 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
3181 CHECK(clazz.get() != NULL);
3182 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3183
3184 method = env->GetMethodID(clazz.get(), "<init>", "()V");
3185 CHECK(method != NULL);
3186 gPersistentSurfaceClassInfo.ctor = method;
3187
3188 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
3189 CHECK(field != NULL);
3190 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08003191
3192 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
3193 CHECK(clazz.get() != NULL);
3194 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
3195
3196 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08003197 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08003198 "Ljava/util/Map;Ljava/util/Map;)V");
3199 CHECK(method != NULL);
3200 gCodecInfo.capsCtorId = method;
3201
3202 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
3203 CHECK(clazz.get() != NULL);
3204 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
3205
3206 field = env->GetFieldID(clazz.get(), "profile", "I");
3207 CHECK(field != NULL);
3208 gCodecInfo.profileField = field;
3209
3210 field = env->GetFieldID(clazz.get(), "level", "I");
3211 CHECK(field != NULL);
3212 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003213
3214 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
3215 CHECK(clazz.get() != NULL);
3216 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3217
3218 ScopedLocalRef<jclass> byteOrderClass(
3219 env, env->FindClass("java/nio/ByteOrder"));
3220 CHECK(byteOrderClass.get() != NULL);
3221
3222 jmethodID nativeOrderID = env->GetStaticMethodID(
3223 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
3224 CHECK(nativeOrderID != NULL);
3225
3226 ScopedLocalRef<jobject> nativeByteOrderObj{
3227 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
3228 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
3229 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
3230 nativeByteOrderObj.reset();
3231
3232 gByteBufferInfo.orderId = env->GetMethodID(
3233 clazz.get(),
3234 "order",
3235 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
3236 CHECK(gByteBufferInfo.orderId != NULL);
3237
3238 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
3239 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
3240 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
3241
3242 gByteBufferInfo.positionId = env->GetMethodID(
3243 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
3244 CHECK(gByteBufferInfo.positionId != NULL);
3245
3246 gByteBufferInfo.limitId = env->GetMethodID(
3247 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
3248 CHECK(gByteBufferInfo.limitId != NULL);
3249
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07003250 gByteBufferInfo.getPositionId = env->GetMethodID(
3251 clazz.get(), "position", "()I");
3252 CHECK(gByteBufferInfo.getPositionId != NULL);
3253
3254 gByteBufferInfo.getLimitId = env->GetMethodID(
3255 clazz.get(), "limit", "()I");
3256 CHECK(gByteBufferInfo.getLimitId != NULL);
3257
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003258 clazz.reset(env->FindClass("java/util/ArrayList"));
3259 CHECK(clazz.get() != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003260 gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3261
3262 gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3263 CHECK(gArrayListInfo.ctorId != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003264
3265 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
3266 CHECK(gArrayListInfo.sizeId != NULL);
3267
3268 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
3269 CHECK(gArrayListInfo.getId != NULL);
3270
3271 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
3272 CHECK(gArrayListInfo.addId != NULL);
3273
3274 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
3275 CHECK(clazz.get() != NULL);
3276
3277 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3278
3279 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3280 CHECK(gLinearBlockInfo.ctorId != NULL);
3281
3282 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
3283 clazz.get(), "setInternalStateLocked", "(JZ)V");
3284 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
3285
3286 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
3287 CHECK(gLinearBlockInfo.contextId != NULL);
3288
3289 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
3290 CHECK(gLinearBlockInfo.validId != NULL);
3291
3292 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
3293 CHECK(gLinearBlockInfo.lockId != NULL);
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003294
3295 clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
3296 CHECK(clazz.get() != NULL);
3297 gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3298
3299 gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3300 CHECK(gDescriptorInfo.ctorId != NULL);
3301
3302 gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
3303 CHECK(gDescriptorInfo.nameId != NULL);
3304
3305 gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
3306 CHECK(gDescriptorInfo.typeId != NULL);
Pavel Laboviche53421b2022-11-01 03:53:27 +00003307
3308 clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
3309 CHECK(clazz.get() != NULL);
3310 gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
3311
3312 gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
3313 CHECK(gBufferInfo.ctorId != NULL);
3314
3315 gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
3316 CHECK(gBufferInfo.setId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003317}
3318
3319static void android_media_MediaCodec_native_setup(
3320 JNIEnv *env, jobject thiz,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003321 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
Andreas Huber88572f72012-02-21 11:47:18 -08003322 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003323 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003324 return;
3325 }
3326
3327 const char *tmp = env->GetStringUTFChars(name, NULL);
3328
3329 if (tmp == NULL) {
3330 return;
3331 }
3332
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003333 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
Andreas Huber88572f72012-02-21 11:47:18 -08003334
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003335 const status_t err = codec->initCheck();
3336 if (err == NAME_NOT_FOUND) {
3337 // fail and do not try again.
3338 jniThrowException(env, "java/lang/IllegalArgumentException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003339 String8::format("Failed to initialize %s, error %#x (NAME_NOT_FOUND)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003340 env->ReleaseStringUTFChars(name, tmp);
3341 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003342 }
3343 if (err == NO_MEMORY) {
Ronghua Wuc53ad692015-05-08 14:40:49 -07003344 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003345 String8::format("Failed to initialize %s, error %#x (NO_MEMORY)", tmp, err));
Ronghua Wuc53ad692015-05-08 14:40:49 -07003346 env->ReleaseStringUTFChars(name, tmp);
3347 return;
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003348 }
3349 if (err == PERMISSION_DENIED) {
3350 jniThrowException(env, "java/lang/SecurityException",
3351 String8::format("Failed to initialize %s, error %#x (PERMISSION_DENIED)", tmp,
3352 err));
3353 env->ReleaseStringUTFChars(name, tmp);
3354 return;
3355 }
3356 if (err != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003357 // believed possible to try again
3358 jniThrowException(env, "java/io/IOException",
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003359 String8::format("Failed to find matching codec %s, error %#x (?)", tmp, err));
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003360 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08003361 return;
3362 }
3363
Andy Hung5f9aa0b2014-07-30 15:48:21 -07003364 env->ReleaseStringUTFChars(name, tmp);
3365
Andreas Huberaba67132013-10-22 12:40:01 -07003366 codec->registerSelf();
3367
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003368 setMediaCodec(env, thiz, codec);
Andreas Huber88572f72012-02-21 11:47:18 -08003369}
3370
3371static void android_media_MediaCodec_native_finalize(
3372 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07003373 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08003374}
3375
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003376// MediaCodec.LinearBlock
3377
3378static jobject android_media_MediaCodec_LinearBlock_native_map(
3379 JNIEnv *env, jobject thiz) {
3380 JMediaCodecLinearBlock *context =
3381 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
3382 if (context->mBuffer) {
3383 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
3384 if (!context->mReadonlyMapping) {
3385 const C2BufferData data = buffer->data();
3386 if (data.type() != C2BufferData::LINEAR) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003387 throwExceptionAsNecessary(
3388 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3389 "Underlying buffer is not a linear buffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003390 return nullptr;
3391 }
3392 if (data.linearBlocks().size() != 1u) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003393 throwExceptionAsNecessary(
3394 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3395 "Underlying buffer contains more than one block");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003396 return nullptr;
3397 }
3398 C2ConstLinearBlock block = data.linearBlocks().front();
3399 context->mReadonlyMapping =
3400 std::make_shared<C2ReadView>(block.map().get());
3401 }
3402 return CreateByteBuffer(
3403 env,
3404 context->mReadonlyMapping->data(), // base
3405 context->mReadonlyMapping->capacity(), // capacity
3406 0u, // offset
3407 context->mReadonlyMapping->capacity(), // size
3408 true, // readOnly
3409 true /* clearBuffer */);
3410 } else if (context->mBlock) {
3411 std::shared_ptr<C2LinearBlock> block = context->mBlock;
3412 if (!context->mReadWriteMapping) {
3413 context->mReadWriteMapping =
3414 std::make_shared<C2WriteView>(block->map().get());
3415 }
3416 return CreateByteBuffer(
3417 env,
3418 context->mReadWriteMapping->base(),
3419 context->mReadWriteMapping->capacity(),
3420 context->mReadWriteMapping->offset(),
3421 context->mReadWriteMapping->size(),
3422 false, // readOnly
3423 true /* clearBuffer */);
3424 } else if (context->mLegacyBuffer) {
3425 return CreateByteBuffer(
3426 env,
3427 context->mLegacyBuffer->base(),
3428 context->mLegacyBuffer->capacity(),
3429 context->mLegacyBuffer->offset(),
3430 context->mLegacyBuffer->size(),
3431 true, // readOnly
3432 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003433 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003434 return CreateByteBuffer(
3435 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003436 context->mMemory->unsecurePointer(),
3437 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003438 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003439 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003440 false, // readOnly
3441 true /* clearBuffer */);
3442 }
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003443 throwExceptionAsNecessary(
3444 env, INVALID_OPERATION, ACTION_CODE_FATAL,
3445 "Underlying buffer is empty");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003446 return nullptr;
3447}
3448
3449static void android_media_MediaCodec_LinearBlock_native_recycle(
3450 JNIEnv *env, jobject thiz) {
3451 JMediaCodecLinearBlock *context =
3452 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003453 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003454 delete context;
3455}
3456
3457static void PopulateNamesVector(
3458 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3459 jsize length = env->GetArrayLength(codecNames);
3460 for (jsize i = 0; i < length; ++i) {
3461 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3462 if (jstr == nullptr) {
3463 // null entries are ignored
3464 continue;
3465 }
3466 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3467 if (cstr == nullptr) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003468 throwExceptionAsNecessary(
3469 env, BAD_VALUE, ACTION_CODE_FATAL,
3470 "Error converting Java string to native");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003471 return;
3472 }
3473 names->emplace_back(cstr);
3474 env->ReleaseStringUTFChars(jstr, cstr);
3475 }
3476}
3477
3478static void android_media_MediaCodec_LinearBlock_native_obtain(
3479 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3480 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3481 std::vector<std::string> names;
3482 PopulateNamesVector(env, codecNames, &names);
3483 bool hasSecure = false;
3484 bool hasNonSecure = false;
3485 for (const std::string &name : names) {
3486 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3487 hasSecure = true;
3488 } else {
3489 hasNonSecure = true;
3490 }
3491 }
Wonsik Kim8569a662022-05-24 14:16:44 -07003492 if (!obtain(context.get(), capacity, names, (hasSecure && !hasNonSecure) /* secure */)) {
3493 jniThrowException(env, "java/io/IOException", nullptr);
3494 return;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003495 }
3496 env->CallVoidMethod(
3497 thiz,
3498 gLinearBlockInfo.setInternalStateId,
3499 (jlong)context.release(),
3500 true /* isMappable */);
3501}
3502
3503static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003504 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003505 std::vector<std::string> names;
3506 PopulateNamesVector(env, codecNames, &names);
3507 bool isCompatible = false;
3508 bool hasSecure = false;
3509 bool hasNonSecure = false;
3510 for (const std::string &name : names) {
3511 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3512 hasSecure = true;
3513 } else {
3514 hasNonSecure = true;
3515 }
3516 }
3517 if (hasSecure && hasNonSecure) {
3518 return false;
3519 }
3520 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3521 if (err != OK) {
Wonsik Kimd1a1b4e2023-01-30 10:26:08 -08003522 // TODO: CodecErrorLog
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003523 throwExceptionAsNecessary(env, err);
3524 }
3525 return isCompatible;
3526}
3527
Daniel Micay76f6a862015-09-19 17:31:01 -04003528static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003529 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003530
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003531 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3532
Chong Zhang8034d602015-04-28 13:38:48 -07003533 { "native_releasePersistentInputSurface",
3534 "(Landroid/view/Surface;)V",
3535 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3536
3537 { "native_createPersistentInputSurface",
3538 "()Landroid/media/MediaCodec$PersistentSurface;",
3539 (void *)android_media_MediaCodec_createPersistentInputSurface },
3540
Chong Zhang9560ddb2015-05-13 10:25:29 -07003541 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3542 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003543
Guillaume Chelfic072caf2021-02-03 16:18:26 +01003544 { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
3545 (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },
3546
Lajos Molnard8578572015-06-05 20:17:33 -07003547 { "native_enableOnFrameRenderedListener", "(Z)V",
3548 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3549
Chong Zhang8d5e5562014-07-08 18:49:21 -07003550 { "native_setCallback",
3551 "(Landroid/media/MediaCodec$Callback;)V",
3552 (void *)android_media_MediaCodec_native_setCallback },
3553
Andreas Huber88572f72012-02-21 11:47:18 -08003554 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003555 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003556 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003557 (void *)android_media_MediaCodec_native_configure },
3558
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003559 { "native_setSurface",
3560 "(Landroid/view/Surface;)V",
3561 (void *)android_media_MediaCodec_native_setSurface },
3562
Andy McFadden2621e402013-02-19 07:29:21 -08003563 { "createInputSurface", "()Landroid/view/Surface;",
3564 (void *)android_media_MediaCodec_createInputSurface },
3565
Lajos Molnard4023112014-07-11 15:12:59 -07003566 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003567 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003568 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003569
Lajos Molnard4023112014-07-11 15:12:59 -07003570 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003571 (void *)android_media_MediaCodec_queueInputBuffer },
3572
Lajos Molnard4023112014-07-11 15:12:59 -07003573 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003574 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3575
Wonsik Kim637afb22020-02-25 14:27:29 -08003576 { "native_mapHardwareBuffer",
3577 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3578 (void *)android_media_MediaCodec_mapHardwareBuffer },
3579
3580 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3581
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003582 { "native_queueLinearBlock",
3583 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3584 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3585 (void *)android_media_MediaCodec_native_queueLinearBlock },
3586
Wonsik Kim637afb22020-02-25 14:27:29 -08003587 { "native_queueHardwareBuffer",
3588 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3589 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003590
3591 { "native_getOutputFrame",
3592 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3593 (void *)android_media_MediaCodec_native_getOutputFrame },
3594
Lajos Molnard4023112014-07-11 15:12:59 -07003595 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003596 (void *)android_media_MediaCodec_dequeueInputBuffer },
3597
Lajos Molnard4023112014-07-11 15:12:59 -07003598 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003599 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3600
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003601 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003602 (void *)android_media_MediaCodec_releaseOutputBuffer },
3603
Andy McFadden2621e402013-02-19 07:29:21 -08003604 { "signalEndOfInputStream", "()V",
3605 (void *)android_media_MediaCodec_signalEndOfInputStream },
3606
Lajos Molnard4023112014-07-11 15:12:59 -07003607 { "getFormatNative", "(Z)Ljava/util/Map;",
3608 (void *)android_media_MediaCodec_getFormatNative },
3609
3610 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3611 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003612
3613 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3614 (void *)android_media_MediaCodec_getBuffers },
3615
Lajos Molnard4023112014-07-11 15:12:59 -07003616 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3617 (void *)android_media_MediaCodec_getBuffer },
3618
3619 { "getImage", "(ZI)Landroid/media/Image;",
3620 (void *)android_media_MediaCodec_getImage },
3621
Lajos Molnard2a7f472018-11-15 12:49:20 -08003622 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003623 (void *)android_media_MediaCodec_getName },
3624
Chong Zhanga0b72a62018-02-28 18:46:26 -08003625 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3626 (void *)android_media_MediaCodec_getOwnCodecInfo },
3627
Ray Essick10353e32017-04-14 10:22:55 -07003628 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003629 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003630
Andreas Huber226065b2013-08-12 10:14:11 -07003631 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3632 (void *)android_media_MediaCodec_setParameters },
3633
Andreas Huberb12a5392012-04-30 14:18:33 -07003634 { "setVideoScalingMode", "(I)V",
3635 (void *)android_media_MediaCodec_setVideoScalingMode },
3636
ybai5e053202018-11-01 13:02:15 +08003637 { "native_setAudioPresentation", "(II)V",
3638 (void *)android_media_MediaCodec_setAudioPresentation },
3639
Wonsik Kim8798c8c2021-03-18 21:38:57 -07003640 { "native_getSupportedVendorParameters", "()Ljava/util/List;",
3641 (void *)android_media_MediaCodec_getSupportedVendorParameters },
3642
3643 { "native_getParameterDescriptor",
3644 "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
3645 (void *)android_media_MediaCodec_getParameterDescriptor },
3646
3647 { "native_subscribeToVendorParameters",
3648 "(Ljava/util/List;)V",
3649 (void *)android_media_MediaCodec_subscribeToVendorParameters},
3650
3651 { "native_unsubscribeFromVendorParameters",
3652 "(Ljava/util/List;)V",
3653 (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
3654
Andreas Huber88572f72012-02-21 11:47:18 -08003655 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3656
Brian Lindahl6ceeed42022-02-01 11:10:30 +01003657 { "native_setup", "(Ljava/lang/String;ZZII)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003658 (void *)android_media_MediaCodec_native_setup },
3659
3660 { "native_finalize", "()V",
3661 (void *)android_media_MediaCodec_native_finalize },
3662};
3663
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003664static const JNINativeMethod gLinearBlockMethods[] = {
3665 { "native_map", "()Ljava/nio/ByteBuffer;",
3666 (void *)android_media_MediaCodec_LinearBlock_native_map },
3667
3668 { "native_recycle", "()V",
3669 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3670
3671 { "native_obtain", "(I[Ljava/lang/String;)V",
3672 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3673
3674 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3675 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3676};
3677
Andreas Huber88572f72012-02-21 11:47:18 -08003678int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003679 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003680 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003681 if (result != JNI_OK) {
3682 return result;
3683 }
3684 result = AndroidRuntime::registerNativeMethods(env,
3685 "android/media/MediaCodec$LinearBlock",
3686 gLinearBlockMethods,
3687 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003688 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003689}