blob: 1870a939f0dc637c785ebbc6b68e006b5e2688ec [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec-JNI"
19#include <utils/Log.h>
20
Wonsik Kimccb7ac62019-12-27 17:12:40 -080021#include <type_traits>
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include "android_media_MediaCodec.h"
24
shubangd49681e2020-02-17 21:32:30 -080025#include "android_media_MediaCodecLinearBlock.h"
Andreas Huber07ea4262012-04-11 12:21:20 -070026#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070027#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080028#include "android_media_MediaMetricsJNI.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090029#include "android_media_Streams.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "android_runtime/AndroidRuntime.h"
31#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080032#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080033#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080035#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080036
Wonsik Kim637afb22020-02-25 14:27:29 -080037#include <C2AllocatorGralloc.h>
38#include <C2BlockInternal.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080039#include <C2Buffer.h>
Wonsik Kimb8ebdb32020-04-21 17:00:13 -070040#include <C2PlatformSupport.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080041
Chong Zhang2659c2f2017-04-27 13:18:20 -070042#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080043
Wonsik Kim637afb22020-02-25 14:27:29 -080044#include <android_runtime/android_hardware_HardwareBuffer.h>
45
Wonsik Kimf7069ce2020-05-13 17:15:47 -070046#include <binder/MemoryDealer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080047
Lajos Molnar7ac4f562014-03-24 15:57:51 -070048#include <cutils/compiler.h>
49
Mathias Agopian8335f1c2012-02-25 18:48:35 -080050#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080051
Wonsik Kimccb7ac62019-12-27 17:12:40 -080052#include <hidlmemory/FrameworkUtils.h>
53
Wonsik Kim4273dd02016-09-27 15:23:35 +090054#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080055#include <media/hardware/VideoAPI.h>
Andreas Huber88572f72012-02-21 11:47:18 -080056#include <media/stagefright/MediaCodec.h>
57#include <media/stagefright/foundation/ABuffer.h>
58#include <media/stagefright/foundation/ADebug.h>
59#include <media/stagefright/foundation/ALooper.h>
60#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070061#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080062#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070063#include <media/stagefright/PersistentSurface.h>
Robert Shih631a80d2021-02-14 02:23:55 -080064#include <mediadrm/DrmUtils.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080065#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070066
Wonsik Kim637afb22020-02-25 14:27:29 -080067#include <private/android/AHardwareBufferHelpers.h>
68
Andreas Huberb12a5392012-04-30 14:18:33 -070069#include <system/window.h>
70
Andreas Huber88572f72012-02-21 11:47:18 -080071namespace android {
72
73// Keep these in sync with their equivalents in MediaCodec.java !!!
74enum {
75 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
76 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
77 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
78};
79
Andreas Huberaba67132013-10-22 12:40:01 -070080enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070081 EVENT_CALLBACK = 1,
82 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070083 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070084};
85
Andy Hung5f9aa0b2014-07-30 15:48:21 -070086static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070087 jint cryptoErrorNoKey;
88 jint cryptoErrorKeyExpired;
89 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070090 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070091 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -080092 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -080093 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -080094 jint cryptoErrorFrameTooLarge;
95 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -070096} gCryptoErrorCodes;
97
Andy Hung5f9aa0b2014-07-30 15:48:21 -070098static struct CodecActionCodes {
99 jint codecActionTransient;
100 jint codecActionRecoverable;
101} gCodecActionCodes;
102
Ronghua Wuc53ad692015-05-08 14:40:49 -0700103static struct CodecErrorCodes {
104 jint errorInsufficientResource;
105 jint errorReclaimed;
106} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700107
Chong Zhang8034d602015-04-28 13:38:48 -0700108static struct {
109 jclass clazz;
110 jfieldID mLock;
111 jfieldID mPersistentObject;
112 jmethodID ctor;
113 jmethodID setNativeObjectLocked;
114} gPersistentSurfaceClassInfo;
115
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800116static struct {
117 jint Unencrypted;
118 jint AesCtr;
119 jint AesCbc;
120} gCryptoModes;
121
Chong Zhanga0b72a62018-02-28 18:46:26 -0800122static struct {
123 jclass capsClazz;
124 jmethodID capsCtorId;
125 jclass profileLevelClazz;
126 jfieldID profileField;
127 jfieldID levelField;
128} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800129
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800130static struct {
131 jclass clazz;
132 jobject nativeByteOrder;
133 jmethodID orderId;
134 jmethodID asReadOnlyBufferId;
135 jmethodID positionId;
136 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700137 jmethodID getPositionId;
138 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800139} gByteBufferInfo;
140
141static struct {
142 jmethodID sizeId;
143 jmethodID getId;
144 jmethodID addId;
145} gArrayListInfo;
146
147static struct {
148 jclass clazz;
149 jmethodID ctorId;
150 jmethodID setInternalStateId;
151 jfieldID contextId;
152 jfieldID validId;
153 jfieldID lockId;
154} gLinearBlockInfo;
155
Andreas Huber88572f72012-02-21 11:47:18 -0800156struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700157 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700158 jmethodID lockAndGetContextID;
159 jmethodID setAndUnlockContextID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700160 jfieldID cryptoInfoNumSubSamplesID;
161 jfieldID cryptoInfoNumBytesOfClearDataID;
162 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
163 jfieldID cryptoInfoKeyID;
164 jfieldID cryptoInfoIVID;
165 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800166 jfieldID cryptoInfoPatternID;
167 jfieldID patternEncryptBlocksID;
168 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800169 jfieldID queueRequestIndexID;
170 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800171 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800172 jfieldID outputFrameChangedKeysID;
173 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800174};
175
176static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700177static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800178
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800179
Andreas Huber88572f72012-02-21 11:47:18 -0800180////////////////////////////////////////////////////////////////////////////////
181
182JMediaCodec::JMediaCodec(
183 JNIEnv *env, jobject thiz,
184 const char *name, bool nameIsType, bool encoder)
185 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700186 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800187 jclass clazz = env->GetObjectClass(thiz);
188 CHECK(clazz != NULL);
189
190 mClass = (jclass)env->NewGlobalRef(clazz);
191 mObject = env->NewWeakGlobalRef(thiz);
192
193 mLooper = new ALooper;
194 mLooper->setName("MediaCodec_looper");
195
196 mLooper->start(
197 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700198 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700199 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800200
201 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700202 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800203 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
204 mNameAtCreation = "(null)";
205 }
Andreas Huber88572f72012-02-21 11:47:18 -0800206 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700207 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800208 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800209 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700210 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800211}
212
213status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700214 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800215}
216
Andreas Huberaba67132013-10-22 12:40:01 -0700217void JMediaCodec::registerSelf() {
218 mLooper->registerHandler(this);
219}
220
Chong Zhang128b0122014-03-01 18:04:13 -0800221void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700222 std::call_once(mReleaseFlag, [this] {
223 if (mCodec != NULL) {
224 mCodec->release();
225 mInitStatus = NO_INIT;
226 }
Andreas Huber88572f72012-02-21 11:47:18 -0800227
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700228 if (mLooper != NULL) {
229 mLooper->unregisterHandler(id());
230 mLooper->stop();
231 mLooper.clear();
232 }
233 });
Chong Zhang128b0122014-03-01 18:04:13 -0800234}
235
Wonsik Kim89666622020-04-28 10:43:47 -0700236void JMediaCodec::releaseAsync() {
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700237 std::call_once(mAsyncReleaseFlag, [this] {
238 if (mCodec != NULL) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -0700239 sp<AMessage> notify = new AMessage(kWhatAsyncReleaseComplete, this);
240 // Hold strong reference to this until async release is complete
241 notify->setObject("this", this);
242 mCodec->releaseAsync(notify);
Wonsik Kimd4ce4e32020-06-08 10:59:48 -0700243 }
244 mInitStatus = NO_INIT;
245 });
Wonsik Kim89666622020-04-28 10:43:47 -0700246}
247
Chong Zhang128b0122014-03-01 18:04:13 -0800248JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700249 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800250 /* MediaCodec and looper should have been released explicitly already
251 * in setMediaCodec() (see comments in setMediaCodec()).
252 *
253 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
254 * message handler, doing release() there risks deadlock as MediaCodec::
255 * release() post synchronous message to the same looper.
256 *
257 * Print a warning and try to proceed with releasing.
258 */
259 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
260 release();
261 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
262 }
263
Andreas Huber88572f72012-02-21 11:47:18 -0800264 JNIEnv *env = AndroidRuntime::getJNIEnv();
265
266 env->DeleteWeakGlobalRef(mObject);
267 mObject = NULL;
268 env->DeleteGlobalRef(mClass);
269 mClass = NULL;
270}
271
Lajos Molnard8578572015-06-05 20:17:33 -0700272status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
273 if (enable) {
274 if (mOnFrameRenderedNotification == NULL) {
275 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
276 }
277 } else {
278 mOnFrameRenderedNotification.clear();
279 }
280
281 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
282}
283
Chong Zhang8d5e5562014-07-08 18:49:21 -0700284status_t JMediaCodec::setCallback(jobject cb) {
285 if (cb != NULL) {
286 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800287 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700288 }
289 } else {
290 mCallbackNotification.clear();
291 }
292
293 return mCodec->setCallback(mCallbackNotification);
294}
295
Andreas Huber88572f72012-02-21 11:47:18 -0800296status_t JMediaCodec::configure(
297 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800298 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700299 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800300 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800301 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800302 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800303 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700304 mSurfaceTextureClient =
305 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700306 } else {
307 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800308 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700309
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800310 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
311 AString mime;
312 CHECK(format->findString("mime", &mime));
313 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
314 && !(flags & CONFIGURE_FLAG_ENCODE);
Wonsik Kimf7069ce2020-05-13 17:15:47 -0700315 mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
Robert Shih631a80d2021-02-14 02:23:55 -0800316 mCrypto = crypto;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800317
Chong Zhangd5927ae2017-01-03 11:07:18 -0800318 return mCodec->configure(
319 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800320}
321
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700322status_t JMediaCodec::setSurface(
323 const sp<IGraphicBufferProducer> &bufferProducer) {
324 sp<Surface> client;
325 if (bufferProducer != NULL) {
326 client = new Surface(bufferProducer, true /* controlledByApp */);
327 }
328 status_t err = mCodec->setSurface(client);
329 if (err == OK) {
330 mSurfaceTextureClient = client;
331 }
332 return err;
333}
334
Andy McFadden2621e402013-02-19 07:29:21 -0800335status_t JMediaCodec::createInputSurface(
336 sp<IGraphicBufferProducer>* bufferProducer) {
337 return mCodec->createInputSurface(bufferProducer);
338}
339
Chong Zhang9560ddb2015-05-13 10:25:29 -0700340status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700341 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700342 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700343}
344
Andreas Huber88572f72012-02-21 11:47:18 -0800345status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700346 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800347}
348
349status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700350 mSurfaceTextureClient.clear();
351
Chong Zhang8d5e5562014-07-08 18:49:21 -0700352 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800353}
354
355status_t JMediaCodec::flush() {
356 return mCodec->flush();
357}
358
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700359status_t JMediaCodec::reset() {
360 return mCodec->reset();
361}
362
Andreas Huber88572f72012-02-21 11:47:18 -0800363status_t JMediaCodec::queueInputBuffer(
364 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700365 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
366 AString *errorDetailMsg) {
367 return mCodec->queueInputBuffer(
368 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800369}
370
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700371status_t JMediaCodec::queueSecureInputBuffer(
372 size_t index,
373 size_t offset,
374 const CryptoPlugin::SubSample *subSamples,
375 size_t numSubSamples,
376 const uint8_t key[16],
377 const uint8_t iv[16],
378 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800379 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700380 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700381 uint32_t flags,
382 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700383 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800384 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700385 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700386}
387
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800388status_t JMediaCodec::queueBuffer(
389 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
390 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
391 return mCodec->queueBuffer(
392 index, buffer, timeUs, flags, tunings, errorDetailMsg);
393}
394
395status_t JMediaCodec::queueEncryptedLinearBlock(
396 size_t index,
397 const sp<hardware::HidlMemory> &buffer,
398 size_t offset,
399 const CryptoPlugin::SubSample *subSamples,
400 size_t numSubSamples,
401 const uint8_t key[16],
402 const uint8_t iv[16],
403 CryptoPlugin::Mode mode,
404 const CryptoPlugin::Pattern &pattern,
405 int64_t presentationTimeUs,
406 uint32_t flags,
407 const sp<AMessage> &tunings,
408 AString *errorDetailMsg) {
409 return mCodec->queueEncryptedBuffer(
410 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
411 presentationTimeUs, flags, tunings, errorDetailMsg);
412}
413
Andreas Huber88572f72012-02-21 11:47:18 -0800414status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700415 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800416}
417
418status_t JMediaCodec::dequeueOutputBuffer(
419 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
420 size_t size, offset;
421 int64_t timeUs;
422 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700423 status_t err = mCodec->dequeueOutputBuffer(
424 index, &offset, &size, &timeUs, &flags, timeoutUs);
425
Andreas Huberaba67132013-10-22 12:40:01 -0700426 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800427 return err;
428 }
429
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700430 ScopedLocalRef<jclass> clazz(
431 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800432
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700433 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000434 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800435
436 return OK;
437}
438
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700439status_t JMediaCodec::releaseOutputBuffer(
440 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
441 if (updatePTS) {
442 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
443 }
Andreas Huber88572f72012-02-21 11:47:18 -0800444 return render
445 ? mCodec->renderOutputBufferAndRelease(index)
446 : mCodec->releaseOutputBuffer(index);
447}
448
Andy McFadden2621e402013-02-19 07:29:21 -0800449status_t JMediaCodec::signalEndOfInputStream() {
450 return mCodec->signalEndOfInputStream();
451}
452
Lajos Molnard4023112014-07-11 15:12:59 -0700453status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800454 sp<AMessage> msg;
455 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700456 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
457 if (err != OK) {
458 return err;
459 }
460
461 return ConvertMessageToMap(env, msg, format);
462}
463
464status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
465 sp<AMessage> msg;
466 status_t err;
467 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800468 return err;
469 }
470
471 return ConvertMessageToMap(env, msg, format);
472}
473
474status_t JMediaCodec::getBuffers(
475 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900476 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800477
478 status_t err =
479 input
480 ? mCodec->getInputBuffers(&buffers)
481 : mCodec->getOutputBuffers(&buffers);
482
483 if (err != OK) {
484 return err;
485 }
486
Andreas Huber88572f72012-02-21 11:47:18 -0800487 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800488 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800489 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800490 return NO_MEMORY;
491 }
Andreas Huber88572f72012-02-21 11:47:18 -0800492
493 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900494 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800495
Lajos Molnar7de28d32014-07-25 07:51:02 -0700496 jobject byteBuffer = NULL;
497 err = createByteBufferFromABuffer(
498 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
499 if (err != OK) {
500 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800501 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700502 if (byteBuffer != NULL) {
503 env->SetObjectArrayElement(
504 *bufArray, i, byteBuffer);
505
Lajos Molnard4023112014-07-11 15:12:59 -0700506 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700507 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700508 }
Andreas Huber88572f72012-02-21 11:47:18 -0800509 }
510
Lajos Molnar7de28d32014-07-25 07:51:02 -0700511 return OK;
512}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700513
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800514template <typename T>
515static jobject CreateByteBuffer(
516 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
517 bool readOnly, bool clearBuffer) {
518 jobject byteBuffer =
519 env->NewDirectByteBuffer(
520 const_cast<typename std::remove_const<T>::type *>(base),
521 capacity);
522 if (readOnly && byteBuffer != NULL) {
523 jobject readOnlyBuffer = env->CallObjectMethod(
524 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
525 env->DeleteLocalRef(byteBuffer);
526 byteBuffer = readOnlyBuffer;
527 }
528 if (byteBuffer == NULL) {
529 return nullptr;
530 }
531 jobject me = env->CallObjectMethod(
532 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
533 env->DeleteLocalRef(me);
534 me = env->CallObjectMethod(
535 byteBuffer, gByteBufferInfo.limitId,
536 clearBuffer ? capacity : offset + size);
537 env->DeleteLocalRef(me);
538 me = env->CallObjectMethod(
539 byteBuffer, gByteBufferInfo.positionId,
540 clearBuffer ? 0 : offset);
541 env->DeleteLocalRef(me);
542 me = NULL;
543 return byteBuffer;
544}
545
546
Lajos Molnar7de28d32014-07-25 07:51:02 -0700547// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900548template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700549status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900550 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700551 jobject *buf) const {
552 // if this is an ABuffer that doesn't actually hold any accessible memory,
553 // use a null ByteBuffer
554 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700555
556 if (buffer == NULL) {
557 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
558 return OK;
559 }
560
Lajos Molnar7de28d32014-07-25 07:51:02 -0700561 if (buffer->base() == NULL) {
562 return OK;
563 }
564
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800565 jobject byteBuffer = CreateByteBuffer(
566 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
567 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700568
569 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800570 return OK;
571}
572
Lajos Molnard4023112014-07-11 15:12:59 -0700573status_t JMediaCodec::getBuffer(
574 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900575 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700576
577 status_t err =
578 input
579 ? mCodec->getInputBuffer(index, &buffer)
580 : mCodec->getOutputBuffer(index, &buffer);
581
582 if (err != OK) {
583 return err;
584 }
585
Lajos Molnar7de28d32014-07-25 07:51:02 -0700586 return createByteBufferFromABuffer(
587 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700588}
589
590status_t JMediaCodec::getImage(
591 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900592 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700593
594 status_t err =
595 input
596 ? mCodec->getInputBuffer(index, &buffer)
597 : mCodec->getOutputBuffer(index, &buffer);
598
599 if (err != OK) {
600 return err;
601 }
602
603 // if this is an ABuffer that doesn't actually hold any accessible memory,
604 // use a null ByteBuffer
605 *buf = NULL;
606 if (buffer->base() == NULL) {
607 return OK;
608 }
609
610 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700611 sp<ABuffer> imageData;
612 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700613 return OK;
614 }
615
Lajos Molnar7de28d32014-07-25 07:51:02 -0700616 int64_t timestamp = 0;
617 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
618 timestamp *= 1000; // adjust to ns
619 }
620
621 jobject byteBuffer = NULL;
622 err = createByteBufferFromABuffer(
623 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
624 if (err != OK) {
625 return OK;
626 }
627
628 jobject infoBuffer = NULL;
629 err = createByteBufferFromABuffer(
630 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
631 if (err != OK) {
632 env->DeleteLocalRef(byteBuffer);
633 byteBuffer = NULL;
634 return OK;
635 }
636
637 jobject cropRect = NULL;
638 int32_t left, top, right, bottom;
639 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
640 ScopedLocalRef<jclass> rectClazz(
641 env, env->FindClass("android/graphics/Rect"));
642 CHECK(rectClazz.get() != NULL);
643
644 jmethodID rectConstructID = env->GetMethodID(
645 rectClazz.get(), "<init>", "(IIII)V");
646
647 cropRect = env->NewObject(
648 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
649 }
650
651 ScopedLocalRef<jclass> imageClazz(
652 env, env->FindClass("android/media/MediaCodec$MediaImage"));
653 CHECK(imageClazz.get() != NULL);
654
655 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
656 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
657
658 *buf = env->NewObject(imageClazz.get(), imageConstructID,
659 byteBuffer, infoBuffer,
660 (jboolean)!input /* readOnly */,
661 (jlong)timestamp,
662 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
663
664 // if MediaImage creation fails, return null
665 if (env->ExceptionCheck()) {
666 env->ExceptionDescribe();
667 env->ExceptionClear();
668 *buf = NULL;
669 }
670
671 if (cropRect != NULL) {
672 env->DeleteLocalRef(cropRect);
673 cropRect = NULL;
674 }
675
676 env->DeleteLocalRef(byteBuffer);
677 byteBuffer = NULL;
678
679 env->DeleteLocalRef(infoBuffer);
680 infoBuffer = NULL;
681
Lajos Molnard4023112014-07-11 15:12:59 -0700682 return OK;
683}
684
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800685status_t JMediaCodec::getOutputFrame(
686 JNIEnv *env, jobject frame, size_t index) const {
687 sp<MediaCodecBuffer> buffer;
688
689 status_t err = mCodec->getOutputBuffer(index, &buffer);
690 if (err != OK) {
691 return err;
692 }
693
694 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800695 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800696 if (c2Buffer) {
697 switch (c2Buffer->data().type()) {
698 case C2BufferData::LINEAR: {
699 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
700 context->mBuffer = c2Buffer;
701 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
702 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800703 env->CallVoidMethod(
704 linearBlock.get(),
705 gLinearBlockInfo.setInternalStateId,
706 (jlong)context.release(),
707 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800708 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
709 break;
710 }
711 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800712 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
713 uint32_t width, height, format, stride, igbp_slot, generation;
714 uint64_t usage, igbp_id;
715 _UnwrapNativeCodec2GrallocMetadata(
716 c2Handle, &width, &height, &format, &usage, &stride, &generation,
717 &igbp_id, &igbp_slot);
718 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
719 GraphicBuffer* graphicBuffer = new GraphicBuffer(
720 grallocHandle, GraphicBuffer::CLONE_HANDLE,
721 width, height, format, 1, usage, stride);
722 ScopedLocalRef<jobject> hardwareBuffer{
723 env,
724 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
725 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
726 env->SetObjectField(
727 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800728 break;
729 }
730 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
731 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
732 case C2BufferData::INVALID: [[fallthrough]];
733 default:
734 return INVALID_OPERATION;
735 }
736 } else {
737 if (!mGraphicOutput) {
738 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
739 context->mLegacyBuffer = buffer;
740 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
741 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800742 env->CallVoidMethod(
743 linearBlock.get(),
744 gLinearBlockInfo.setInternalStateId,
745 (jlong)context.release(),
746 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800747 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
748 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800749 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800750 }
751 }
752 }
753
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700754 jobject formatMap;
755 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800756 if (err != OK) {
757 return err;
758 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700759 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
760 ScopedLocalRef<jobject> format{env, env->NewObject(
761 mediaFormatClass.get(),
762 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
763 formatMap)};
764 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
765 env->DeleteLocalRef(formatMap);
766 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800767
768 sp<RefBase> obj;
769 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
770 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
771 (decltype(changedKeys.get()))obj.get()};
772 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
773 frame, gFields.outputFrameChangedKeysID)};
774 for (const std::string &key : changedKeys->value) {
775 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
776 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
777 }
778 }
779 return OK;
780}
781
782
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300783status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
784 AString name;
785
786 status_t err = mCodec->getName(&name);
787
788 if (err != OK) {
789 return err;
790 }
791
792 *nameStr = env->NewStringUTF(name.c_str());
793
794 return OK;
795}
796
Chong Zhanga0b72a62018-02-28 18:46:26 -0800797static jobject getCodecCapabilitiesObject(
798 JNIEnv *env, const char *mime, bool isEncoder,
799 const sp<MediaCodecInfo::Capabilities> &capabilities) {
800 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
801 Vector<uint32_t> colorFormats;
802
803 sp<AMessage> defaultFormat = new AMessage();
804 defaultFormat->setString("mime", mime);
805
806 capabilities->getSupportedColorFormats(&colorFormats);
807 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800808 sp<AMessage> details = capabilities->getDetails();
809
810 jobject defaultFormatObj = NULL;
811 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
812 return NULL;
813 }
814 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
815
816 jobject detailsObj = NULL;
817 if (ConvertMessageToMap(env, details, &detailsObj)) {
818 return NULL;
819 }
820 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
821
822 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
823 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
824
825 for (size_t i = 0; i < profileLevels.size(); ++i) {
826 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
827
828 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
829 gCodecInfo.profileLevelClazz));
830
831 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
832 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
833
834 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
835 }
836
837 ScopedLocalRef<jintArray> colorFormatsArray(
838 env, env->NewIntArray(colorFormats.size()));
839 for (size_t i = 0; i < colorFormats.size(); ++i) {
840 jint val = colorFormats.itemAt(i);
841 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
842 }
843
844 return env->NewObject(
845 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800846 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800847 defaultFormatRef.get(), detailsRef.get());
848}
849
850status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
851 sp<MediaCodecInfo> codecInfo;
852
853 status_t err = mCodec->getCodecInfo(&codecInfo);
854
855 if (err != OK) {
856 return err;
857 }
858
859 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800860 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800861
Lajos Molnard2a7f472018-11-15 12:49:20 -0800862 ScopedLocalRef<jstring> canonicalNameObject(env,
863 env->NewStringUTF(codecInfo->getCodecName()));
864
865 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800866 bool isEncoder = codecInfo->isEncoder();
867
Lajos Molnard2a7f472018-11-15 12:49:20 -0800868 Vector<AString> mediaTypes;
869 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800870
871 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800872 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800873
Lajos Molnard2a7f472018-11-15 12:49:20 -0800874 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800875 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800876 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800877
878 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800879 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800880
881 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
882 }
883
884 ScopedLocalRef<jclass> codecInfoClazz(env,
885 env->FindClass("android/media/MediaCodecInfo"));
886 CHECK(codecInfoClazz.get() != NULL);
887
888 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800889 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800890
891 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800892 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800893
894 return OK;
895}
896
Ray Essick81fbc5b2019-12-07 06:24:59 -0800897status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
898 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700899 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700900 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800901 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800902 return status;
903}
904
Andreas Huber226065b2013-08-12 10:14:11 -0700905status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
906 return mCodec->setParameters(msg);
907}
908
Andreas Huberb12a5392012-04-30 14:18:33 -0700909void JMediaCodec::setVideoScalingMode(int mode) {
910 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700911 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700912 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700913 // also signal via param for components that queue to IGBP
914 sp<AMessage> msg = new AMessage;
915 msg->setInt32("android._video-scaling", mode);
916 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700917 }
918}
919
ybai5e053202018-11-01 13:02:15 +0800920void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
921 sp<AMessage> msg = new AMessage;
922 msg->setInt32("audio-presentation-presentation-id", presentationId);
923 msg->setInt32("audio-presentation-program-id", programId);
924 (void)mCodec->setParameters(msg);
925}
926
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700927static jthrowable createCodecException(
928 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
929 ScopedLocalRef<jclass> clazz(
930 env, env->FindClass("android/media/MediaCodec$CodecException"));
931 CHECK(clazz.get() != NULL);
932
Ronghua Wuc53ad692015-05-08 14:40:49 -0700933 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700934 CHECK(ctor != NULL);
935
936 ScopedLocalRef<jstring> msgObj(
937 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
938
939 // translate action code to Java equivalent
940 switch (actionCode) {
941 case ACTION_CODE_TRANSIENT:
942 actionCode = gCodecActionCodes.codecActionTransient;
943 break;
944 case ACTION_CODE_RECOVERABLE:
945 actionCode = gCodecActionCodes.codecActionRecoverable;
946 break;
947 default:
948 actionCode = 0; // everything else is fatal
949 break;
950 }
951
Ronghua Wuc53ad692015-05-08 14:40:49 -0700952 /* translate OS errors to Java API CodecException errorCodes */
953 switch (err) {
954 case NO_MEMORY:
955 err = gCodecErrorCodes.errorInsufficientResource;
956 break;
957 case DEAD_OBJECT:
958 err = gCodecErrorCodes.errorReclaimed;
959 break;
960 default: /* Other error codes go out as is. */
961 break;
962 }
963
964 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700965}
966
Chong Zhang8d5e5562014-07-08 18:49:21 -0700967void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
968 int32_t arg1, arg2 = 0;
969 jobject obj = NULL;
970 CHECK(msg->findInt32("callbackID", &arg1));
971 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700972
Chong Zhang8d5e5562014-07-08 18:49:21 -0700973 switch (arg1) {
974 case MediaCodec::CB_INPUT_AVAILABLE:
975 {
976 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700977 break;
978 }
979
Chong Zhang8d5e5562014-07-08 18:49:21 -0700980 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700981 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700982 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700983
Chong Zhang8d5e5562014-07-08 18:49:21 -0700984 size_t size, offset;
985 int64_t timeUs;
986 uint32_t flags;
987 CHECK(msg->findSize("size", &size));
988 CHECK(msg->findSize("offset", &offset));
989 CHECK(msg->findInt64("timeUs", &timeUs));
990 CHECK(msg->findInt32("flags", (int32_t *)&flags));
991
992 ScopedLocalRef<jclass> clazz(
993 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
994 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
995 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
996
997 obj = env->NewObject(clazz.get(), ctor);
998
999 if (obj == NULL) {
1000 if (env->ExceptionCheck()) {
1001 ALOGE("Could not create MediaCodec.BufferInfo.");
1002 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -07001003 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001004 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1005 return;
Andreas Huberaba67132013-10-22 12:40:01 -07001006 }
1007
Chong Zhang8d5e5562014-07-08 18:49:21 -07001008 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
1009 break;
1010 }
1011
1012 case MediaCodec::CB_ERROR:
1013 {
Chong Zhang94686d12014-07-11 15:53:58 -07001014 int32_t err, actionCode;
1015 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001016 CHECK(msg->findInt32("actionCode", &actionCode));
1017
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001018 // note that DRM errors could conceivably alias into a CodecException
1019 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001020
1021 if (obj == NULL) {
1022 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001023 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001024 env->ExceptionClear();
1025 }
1026 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1027 return;
1028 }
Andreas Huberaba67132013-10-22 12:40:01 -07001029
1030 break;
1031 }
1032
Chong Zhang8d5e5562014-07-08 18:49:21 -07001033 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001034 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001035 sp<AMessage> format;
1036 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001037
Chong Zhang8d5e5562014-07-08 18:49:21 -07001038 if (OK != ConvertMessageToMap(env, format, &obj)) {
1039 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1040 return;
1041 }
Andreas Huberaba67132013-10-22 12:40:01 -07001042
Andreas Huberaba67132013-10-22 12:40:01 -07001043 break;
1044 }
1045
1046 default:
1047 TRESPASS();
1048 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001049
1050 env->CallVoidMethod(
1051 mObject,
1052 gFields.postEventFromNativeID,
1053 EVENT_CALLBACK,
1054 arg1,
1055 arg2,
1056 obj);
1057
1058 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001059}
1060
Lajos Molnard8578572015-06-05 20:17:33 -07001061void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1062 int32_t arg1 = 0, arg2 = 0;
1063 jobject obj = NULL;
1064 JNIEnv *env = AndroidRuntime::getJNIEnv();
1065
1066 sp<AMessage> data;
1067 CHECK(msg->findMessage("data", &data));
1068
1069 status_t err = ConvertMessageToMap(env, data, &obj);
1070 if (err != OK) {
1071 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1072 return;
1073 }
1074
1075 env->CallVoidMethod(
1076 mObject, gFields.postEventFromNativeID,
1077 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1078
1079 env->DeleteLocalRef(obj);
1080}
1081
Chong Zhang8d5e5562014-07-08 18:49:21 -07001082void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1083 switch (msg->what()) {
1084 case kWhatCallbackNotify:
1085 {
1086 handleCallback(msg);
1087 break;
1088 }
Lajos Molnard8578572015-06-05 20:17:33 -07001089 case kWhatFrameRendered:
1090 {
1091 handleFrameRenderedNotification(msg);
1092 break;
1093 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001094 case kWhatAsyncReleaseComplete:
1095 {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001096 if (mLooper != NULL) {
1097 mLooper->unregisterHandler(id());
1098 mLooper->stop();
1099 mLooper.clear();
1100 }
Wonsik Kimd4ce4e32020-06-08 10:59:48 -07001101 break;
1102 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001103 default:
1104 TRESPASS();
1105 }
Andreas Huberaba67132013-10-22 12:40:01 -07001106}
1107
Robert Shih631a80d2021-02-14 02:23:55 -08001108jint MediaErrorToJavaError(status_t err);
1109
Andreas Huber88572f72012-02-21 11:47:18 -08001110} // namespace android
1111
1112////////////////////////////////////////////////////////////////////////////////
1113
1114using namespace android;
1115
1116static sp<JMediaCodec> setMediaCodec(
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001117 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec, bool release = true) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001118 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001119 if (codec != NULL) {
1120 codec->incStrong(thiz);
1121 }
1122 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001123 /* release MediaCodec and stop the looper now before decStrong.
1124 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1125 * its message handler, doing release() from there will deadlock
1126 * (as MediaCodec::release() post synchronous message to the same looper)
1127 */
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001128 if (release) {
1129 old->release();
1130 }
Andreas Huber88572f72012-02-21 11:47:18 -08001131 old->decStrong(thiz);
1132 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001133 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001134
1135 return old;
1136}
1137
1138static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001139 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1140 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1141 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001142}
1143
1144static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kime37ef4b2020-06-18 23:52:03 -07001145 // Clear Java native reference.
1146 sp<JMediaCodec> codec = setMediaCodec(env, thiz, nullptr, false /* release */);
Wonsik Kim89666622020-04-28 10:43:47 -07001147 if (codec != NULL) {
1148 codec->releaseAsync();
1149 }
Andreas Huber88572f72012-02-21 11:47:18 -08001150}
1151
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001152static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1153 jthrowable exception = createCodecException(env, err, actionCode, msg);
1154 env->Throw(exception);
1155}
1156
Robert Shih631a80d2021-02-14 02:23:55 -08001157static void throwCryptoException(JNIEnv *env, status_t err, const char *msg,
1158 const sp<ICrypto> &crypto) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001159 ScopedLocalRef<jclass> clazz(
1160 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1161 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001162
1163 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001164 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -07001165 CHECK(constructID != NULL);
1166
Robert Shih631a80d2021-02-14 02:23:55 -08001167 std::string defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -07001168
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001169 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001170 switch (err) {
1171 case ERROR_DRM_NO_LICENSE:
1172 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001173 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001174 break;
1175 case ERROR_DRM_LICENSE_EXPIRED:
1176 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001177 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001178 break;
1179 case ERROR_DRM_RESOURCE_BUSY:
1180 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001181 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001182 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001183 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1184 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001185 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001186 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001187 case ERROR_DRM_SESSION_NOT_OPENED:
1188 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001189 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001190 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001191 case ERROR_DRM_INSUFFICIENT_SECURITY:
1192 err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1193 defaultMsg = "Required security level is not met";
1194 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001195 case ERROR_DRM_CANNOT_HANDLE:
1196 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1197 defaultMsg = "Operation not supported in this configuration";
1198 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001199 case ERROR_DRM_FRAME_TOO_LARGE:
1200 err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1201 defaultMsg = "Decrytped frame exceeds size of output buffer";
1202 break;
1203 case ERROR_DRM_SESSION_LOST_STATE:
1204 err = gCryptoErrorCodes.cryptoErrorLostState;
1205 defaultMsg = "Session state was lost, open a new session and retry";
1206 break;
Robert Shih631a80d2021-02-14 02:23:55 -08001207 default: /* Other negative DRM error codes go out best-effort. */
1208 err = MediaErrorToJavaError(err);
1209 defaultMsg = StrCryptoError(err);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001210 break;
1211 }
1212
Robert Shih631a80d2021-02-14 02:23:55 -08001213 std::string msgStr(msg != NULL ? msg : defaultMsg.c_str());
1214 if (crypto != NULL) {
1215 msgStr = DrmUtils::GetExceptionMessage(err, msgStr.c_str(), crypto);
1216 }
1217 jstring msgObj = env->NewStringUTF(msgStr.c_str());
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001218
Andreas Huberbfc56f42012-04-19 12:47:07 -07001219 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001220 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001221
1222 env->Throw(exception);
1223}
1224
1225static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001226 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
Robert Shih631a80d2021-02-14 02:23:55 -08001227 const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001228 switch (err) {
1229 case OK:
1230 return 0;
1231
1232 case -EAGAIN:
1233 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1234
1235 case INFO_FORMAT_CHANGED:
1236 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1237
1238 case INFO_OUTPUT_BUFFERS_CHANGED:
1239 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1240
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001241 case INVALID_OPERATION:
1242 jniThrowException(env, "java/lang/IllegalStateException", msg);
1243 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001244
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001245 case BAD_VALUE:
1246 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1247 return 0;
1248
Andreas Huber88572f72012-02-21 11:47:18 -08001249 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001250 if (isCryptoError(err)) {
Robert Shih631a80d2021-02-14 02:23:55 -08001251 throwCryptoException(env, err, msg, crypto);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001252 return 0;
1253 }
1254 throwCodecException(env, err, actionCode, msg);
1255 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001256 }
Andreas Huber88572f72012-02-21 11:47:18 -08001257}
1258
Lajos Molnard8578572015-06-05 20:17:33 -07001259static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1260 JNIEnv *env,
1261 jobject thiz,
1262 jboolean enabled) {
1263 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1264
Wonsik Kim24e53802020-05-08 20:04:26 -07001265 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnard8578572015-06-05 20:17:33 -07001266 throwExceptionAsNecessary(env, INVALID_OPERATION);
1267 return;
1268 }
1269
1270 status_t err = codec->enableOnFrameRenderedListener(enabled);
1271
1272 throwExceptionAsNecessary(env, err);
1273}
1274
Chong Zhang8d5e5562014-07-08 18:49:21 -07001275static void android_media_MediaCodec_native_setCallback(
1276 JNIEnv *env,
1277 jobject thiz,
1278 jobject cb) {
1279 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1280
Wonsik Kim24e53802020-05-08 20:04:26 -07001281 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001282 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001283 return;
1284 }
1285
1286 status_t err = codec->setCallback(cb);
1287
1288 throwExceptionAsNecessary(env, err);
1289}
1290
Andreas Huber88572f72012-02-21 11:47:18 -08001291static void android_media_MediaCodec_native_configure(
1292 JNIEnv *env,
1293 jobject thiz,
1294 jobjectArray keys, jobjectArray values,
1295 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001296 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001297 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001298 jint flags) {
1299 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1300
Wonsik Kim24e53802020-05-08 20:04:26 -07001301 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001302 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001303 return;
1304 }
1305
1306 sp<AMessage> format;
1307 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1308
1309 if (err != OK) {
1310 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1311 return;
1312 }
1313
Andy McFaddend47f7d82012-12-18 09:48:38 -08001314 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001315 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001316 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001317 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001318 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001319 } else {
1320 jniThrowException(
1321 env,
1322 "java/lang/IllegalArgumentException",
1323 "The surface has been released");
1324 return;
1325 }
1326 }
1327
Andreas Huber8240d922012-04-04 14:06:32 -07001328 sp<ICrypto> crypto;
1329 if (jcrypto != NULL) {
1330 crypto = JCrypto::GetCrypto(env, jcrypto);
1331 }
1332
Chong Zhangd5927ae2017-01-03 11:07:18 -08001333 sp<IDescrambler> descrambler;
1334 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001335 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001336 }
1337
1338 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001339
1340 throwExceptionAsNecessary(env, err);
1341}
1342
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001343static void android_media_MediaCodec_native_setSurface(
1344 JNIEnv *env,
1345 jobject thiz,
1346 jobject jsurface) {
1347 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1348
Wonsik Kim24e53802020-05-08 20:04:26 -07001349 if (codec == NULL || codec->initCheck() != OK) {
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001350 throwExceptionAsNecessary(env, INVALID_OPERATION);
1351 return;
1352 }
1353
1354 sp<IGraphicBufferProducer> bufferProducer;
1355 if (jsurface != NULL) {
1356 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1357 if (surface != NULL) {
1358 bufferProducer = surface->getIGraphicBufferProducer();
1359 } else {
1360 jniThrowException(
1361 env,
1362 "java/lang/IllegalArgumentException",
1363 "The surface has been released");
1364 return;
1365 }
1366 }
1367
1368 status_t err = codec->setSurface(bufferProducer);
1369 throwExceptionAsNecessary(env, err);
1370}
1371
Chong Zhang8034d602015-04-28 13:38:48 -07001372sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1373 JNIEnv* env, jobject object) {
1374 sp<PersistentSurface> persistentSurface;
1375
1376 jobject lock = env->GetObjectField(
1377 object, gPersistentSurfaceClassInfo.mLock);
1378 if (env->MonitorEnter(lock) == JNI_OK) {
1379 persistentSurface = reinterpret_cast<PersistentSurface *>(
1380 env->GetLongField(object,
1381 gPersistentSurfaceClassInfo.mPersistentObject));
1382 env->MonitorExit(lock);
1383 }
1384 env->DeleteLocalRef(lock);
1385
1386 return persistentSurface;
1387}
1388
1389static jobject android_media_MediaCodec_createPersistentInputSurface(
1390 JNIEnv* env, jclass /* clazz */) {
1391 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1392 sp<PersistentSurface> persistentSurface =
1393 MediaCodec::CreatePersistentInputSurface();
1394
1395 if (persistentSurface == NULL) {
1396 return NULL;
1397 }
1398
1399 sp<Surface> surface = new Surface(
1400 persistentSurface->getBufferProducer(), true);
1401 if (surface == NULL) {
1402 return NULL;
1403 }
1404
1405 jobject object = env->NewObject(
1406 gPersistentSurfaceClassInfo.clazz,
1407 gPersistentSurfaceClassInfo.ctor);
1408
1409 if (object == NULL) {
1410 if (env->ExceptionCheck()) {
1411 ALOGE("Could not create PersistentSurface.");
1412 env->ExceptionClear();
1413 }
1414 return NULL;
1415 }
1416
1417 jobject lock = env->GetObjectField(
1418 object, gPersistentSurfaceClassInfo.mLock);
1419 if (env->MonitorEnter(lock) == JNI_OK) {
1420 env->CallVoidMethod(
1421 object,
1422 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1423 (jlong)surface.get());
1424 env->SetLongField(
1425 object,
1426 gPersistentSurfaceClassInfo.mPersistentObject,
1427 (jlong)persistentSurface.get());
1428 env->MonitorExit(lock);
1429 } else {
1430 env->DeleteLocalRef(object);
1431 object = NULL;
1432 }
1433 env->DeleteLocalRef(lock);
1434
1435 if (object != NULL) {
1436 surface->incStrong(&sRefBaseOwner);
1437 persistentSurface->incStrong(&sRefBaseOwner);
1438 }
1439
1440 return object;
1441}
1442
1443static void android_media_MediaCodec_releasePersistentInputSurface(
1444 JNIEnv* env, jclass /* clazz */, jobject object) {
1445 sp<PersistentSurface> persistentSurface;
1446
1447 jobject lock = env->GetObjectField(
1448 object, gPersistentSurfaceClassInfo.mLock);
1449 if (env->MonitorEnter(lock) == JNI_OK) {
1450 persistentSurface = reinterpret_cast<PersistentSurface *>(
1451 env->GetLongField(
1452 object, gPersistentSurfaceClassInfo.mPersistentObject));
1453 env->SetLongField(
1454 object,
1455 gPersistentSurfaceClassInfo.mPersistentObject,
1456 (jlong)0);
1457 env->MonitorExit(lock);
1458 }
1459 env->DeleteLocalRef(lock);
1460
1461 if (persistentSurface != NULL) {
1462 persistentSurface->decStrong(&sRefBaseOwner);
1463 }
1464 // no need to release surface as it will be released by Surface's jni
1465}
1466
Chong Zhang9560ddb2015-05-13 10:25:29 -07001467static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001468 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001469 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001470
1471 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001472 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhang8034d602015-04-28 13:38:48 -07001473 throwExceptionAsNecessary(env, INVALID_OPERATION);
1474 return;
1475 }
1476
1477 sp<PersistentSurface> persistentSurface =
1478 android_media_MediaCodec_getPersistentInputSurface(env, object);
1479
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001480 if (persistentSurface == NULL) {
1481 throwExceptionAsNecessary(
1482 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1483 return;
1484 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001485 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001486 if (err != NO_ERROR) {
1487 throwExceptionAsNecessary(env, err);
1488 }
1489}
1490
Andy McFadden2621e402013-02-19 07:29:21 -08001491static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1492 jobject thiz) {
1493 ALOGV("android_media_MediaCodec_createInputSurface");
1494
1495 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07001496 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001497 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001498 return NULL;
1499 }
1500
1501 // Tell the MediaCodec that we want to use a Surface as input.
1502 sp<IGraphicBufferProducer> bufferProducer;
1503 status_t err = codec->createInputSurface(&bufferProducer);
1504 if (err != NO_ERROR) {
1505 throwExceptionAsNecessary(env, err);
1506 return NULL;
1507 }
1508
1509 // Wrap the IGBP in a Java-language Surface.
1510 return android_view_Surface_createFromIGraphicBufferProducer(env,
1511 bufferProducer);
1512}
1513
Andreas Huber88572f72012-02-21 11:47:18 -08001514static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1515 ALOGV("android_media_MediaCodec_start");
1516
1517 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1518
Wonsik Kim24e53802020-05-08 20:04:26 -07001519 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001520 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001521 return;
1522 }
1523
1524 status_t err = codec->start();
1525
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001526 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001527}
1528
1529static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1530 ALOGV("android_media_MediaCodec_stop");
1531
1532 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1533
Wonsik Kim24e53802020-05-08 20:04:26 -07001534 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001535 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001536 return;
1537 }
1538
1539 status_t err = codec->stop();
1540
1541 throwExceptionAsNecessary(env, err);
1542}
1543
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001544static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1545 ALOGV("android_media_MediaCodec_reset");
1546
1547 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1548
Wonsik Kim24e53802020-05-08 20:04:26 -07001549 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001550 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001551 return;
1552 }
1553
1554 status_t err = codec->reset();
1555 if (err != OK) {
1556 // treat all errors as fatal for now, though resource not available
1557 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001558 // we also should avoid sending INVALID_OPERATION here due to
1559 // the transitory nature of reset(), it should not inadvertently
1560 // trigger an IllegalStateException.
1561 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001562 }
1563 throwExceptionAsNecessary(env, err);
1564}
1565
Andreas Huber88572f72012-02-21 11:47:18 -08001566static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1567 ALOGV("android_media_MediaCodec_flush");
1568
1569 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1570
Wonsik Kim24e53802020-05-08 20:04:26 -07001571 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001572 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001573 return;
1574 }
1575
1576 status_t err = codec->flush();
1577
1578 throwExceptionAsNecessary(env, err);
1579}
1580
1581static void android_media_MediaCodec_queueInputBuffer(
1582 JNIEnv *env,
1583 jobject thiz,
1584 jint index,
1585 jint offset,
1586 jint size,
1587 jlong timestampUs,
1588 jint flags) {
1589 ALOGV("android_media_MediaCodec_queueInputBuffer");
1590
1591 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1592
Wonsik Kim24e53802020-05-08 20:04:26 -07001593 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001594 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001595 return;
1596 }
1597
Andreas Huberbfc56f42012-04-19 12:47:07 -07001598 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001599
Andreas Huberbfc56f42012-04-19 12:47:07 -07001600 status_t err = codec->queueInputBuffer(
1601 index, offset, size, timestampUs, flags, &errorDetailMsg);
1602
1603 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001604 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001605}
1606
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001607struct NativeCryptoInfo {
1608 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1609 : mEnv{env},
1610 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1611 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1612 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1613
1614 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1615 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1616
1617 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1618 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1619
1620 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1621 if (jmode == gCryptoModes.Unencrypted) {
1622 mMode = CryptoPlugin::kMode_Unencrypted;
1623 } else if (jmode == gCryptoModes.AesCtr) {
1624 mMode = CryptoPlugin::kMode_AES_CTR;
1625 } else if (jmode == gCryptoModes.AesCbc) {
1626 mMode = CryptoPlugin::kMode_AES_CBC;
1627 } else {
1628 throwExceptionAsNecessary(env, INVALID_OPERATION);
1629 return;
1630 }
1631
1632 ScopedLocalRef<jobject> patternObj{
1633 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1634
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001635 if (patternObj.get() == nullptr) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001636 mPattern.mEncryptBlocks = 0;
1637 mPattern.mSkipBlocks = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001638 } else {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001639 mPattern.mEncryptBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001640 patternObj.get(), gFields.patternEncryptBlocksID);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001641 mPattern.mSkipBlocks = env->GetIntField(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001642 patternObj.get(), gFields.patternSkipBlocksID);
1643 }
1644
1645 mErr = OK;
1646 if (mNumSubSamples <= 0) {
1647 mErr = -EINVAL;
1648 } else if (numBytesOfClearDataObj == nullptr
1649 && numBytesOfEncryptedDataObj == nullptr) {
1650 mErr = -EINVAL;
1651 } else if (numBytesOfEncryptedDataObj != nullptr
1652 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1653 mErr = -ERANGE;
1654 } else if (numBytesOfClearDataObj != nullptr
1655 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1656 mErr = -ERANGE;
1657 // subSamples array may silently overflow if number of samples are too large. Use
1658 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1659 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1660 mErr = -EINVAL;
1661 } else {
1662 jint *numBytesOfClearData =
1663 (numBytesOfClearDataObj == nullptr)
1664 ? nullptr
1665 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1666
1667 jint *numBytesOfEncryptedData =
1668 (numBytesOfEncryptedDataObj == nullptr)
1669 ? nullptr
1670 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1671
1672 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1673
1674 for (jint i = 0; i < mNumSubSamples; ++i) {
1675 mSubSamples[i].mNumBytesOfClearData =
1676 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1677
1678 mSubSamples[i].mNumBytesOfEncryptedData =
1679 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1680 }
1681
1682 if (numBytesOfEncryptedData != nullptr) {
1683 env->ReleaseIntArrayElements(
1684 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1685 numBytesOfEncryptedData = nullptr;
1686 }
1687
1688 if (numBytesOfClearData != nullptr) {
1689 env->ReleaseIntArrayElements(
1690 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1691 numBytesOfClearData = nullptr;
1692 }
1693 }
1694
1695 if (mErr == OK && mKeyObj.get() != nullptr) {
1696 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1697 mErr = -EINVAL;
1698 } else {
1699 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1700 }
1701 }
1702
1703 if (mErr == OK && mIvObj.get() != nullptr) {
1704 if (env->GetArrayLength(mIvObj.get()) != 16) {
1705 mErr = -EINVAL;
1706 } else {
1707 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1708 }
1709 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07001710
1711 }
1712
1713 explicit NativeCryptoInfo(jint size)
1714 : mIvObj{nullptr, nullptr},
1715 mKeyObj{nullptr, nullptr},
1716 mMode{CryptoPlugin::kMode_Unencrypted},
1717 mPattern{0, 0} {
1718 mSubSamples = new CryptoPlugin::SubSample[1];
1719 mNumSubSamples = 1;
1720 mSubSamples[0].mNumBytesOfClearData = size;
1721 mSubSamples[0].mNumBytesOfEncryptedData = 0;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001722 }
1723
1724 ~NativeCryptoInfo() {
1725 if (mIv != nullptr) {
1726 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1727 }
1728
1729 if (mKey != nullptr) {
1730 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1731 }
1732
1733 if (mSubSamples != nullptr) {
1734 delete[] mSubSamples;
1735 }
1736 }
1737
1738 JNIEnv *mEnv{nullptr};
1739 ScopedLocalRef<jbyteArray> mIvObj;
1740 ScopedLocalRef<jbyteArray> mKeyObj;
1741 status_t mErr{OK};
1742
1743 CryptoPlugin::SubSample *mSubSamples{nullptr};
1744 int32_t mNumSubSamples{0};
1745 jbyte *mIv{nullptr};
1746 jbyte *mKey{nullptr};
1747 enum CryptoPlugin::Mode mMode;
1748 CryptoPlugin::Pattern mPattern;
1749};
1750
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001751static void android_media_MediaCodec_queueSecureInputBuffer(
1752 JNIEnv *env,
1753 jobject thiz,
1754 jint index,
1755 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001756 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001757 jlong timestampUs,
1758 jint flags) {
1759 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1760
1761 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1762
Wonsik Kim24e53802020-05-08 20:04:26 -07001763 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001764 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001765 return;
1766 }
1767
Wonsik Kim1cac4252020-01-24 11:45:37 -08001768 jint numSubSamples =
1769 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1770
1771 jintArray numBytesOfClearDataObj =
1772 (jintArray)env->GetObjectField(
1773 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1774
1775 jintArray numBytesOfEncryptedDataObj =
1776 (jintArray)env->GetObjectField(
1777 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1778
1779 jbyteArray keyObj =
1780 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1781
1782 jbyteArray ivObj =
1783 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1784
1785 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1786 enum CryptoPlugin::Mode mode;
1787 if (jmode == gCryptoModes.Unencrypted) {
1788 mode = CryptoPlugin::kMode_Unencrypted;
1789 } else if (jmode == gCryptoModes.AesCtr) {
1790 mode = CryptoPlugin::kMode_AES_CTR;
1791 } else if (jmode == gCryptoModes.AesCbc) {
1792 mode = CryptoPlugin::kMode_AES_CBC;
1793 } else {
1794 throwExceptionAsNecessary(env, INVALID_OPERATION);
1795 return;
1796 }
1797
1798 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1799
1800 CryptoPlugin::Pattern pattern;
1801 if (patternObj == NULL) {
1802 pattern.mEncryptBlocks = 0;
1803 pattern.mSkipBlocks = 0;
1804 } else {
1805 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1806 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1807 }
1808
1809 status_t err = OK;
1810
1811 CryptoPlugin::SubSample *subSamples = NULL;
1812 jbyte *key = NULL;
1813 jbyte *iv = NULL;
1814
1815 if (numSubSamples <= 0) {
1816 err = -EINVAL;
1817 } else if (numBytesOfClearDataObj == NULL
1818 && numBytesOfEncryptedDataObj == NULL) {
1819 err = -EINVAL;
1820 } else if (numBytesOfEncryptedDataObj != NULL
1821 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1822 err = -ERANGE;
1823 } else if (numBytesOfClearDataObj != NULL
1824 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1825 err = -ERANGE;
1826 // subSamples array may silently overflow if number of samples are too large. Use
1827 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1828 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1829 err = -EINVAL;
1830 } else {
1831 jboolean isCopy;
1832
1833 jint *numBytesOfClearData =
1834 (numBytesOfClearDataObj == NULL)
1835 ? NULL
1836 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1837
1838 jint *numBytesOfEncryptedData =
1839 (numBytesOfEncryptedDataObj == NULL)
1840 ? NULL
1841 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1842
1843 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1844
1845 for (jint i = 0; i < numSubSamples; ++i) {
1846 subSamples[i].mNumBytesOfClearData =
1847 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1848
1849 subSamples[i].mNumBytesOfEncryptedData =
1850 (numBytesOfEncryptedData == NULL)
1851 ? 0 : numBytesOfEncryptedData[i];
1852 }
1853
1854 if (numBytesOfEncryptedData != NULL) {
1855 env->ReleaseIntArrayElements(
1856 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1857 numBytesOfEncryptedData = NULL;
1858 }
1859
1860 if (numBytesOfClearData != NULL) {
1861 env->ReleaseIntArrayElements(
1862 numBytesOfClearDataObj, numBytesOfClearData, 0);
1863 numBytesOfClearData = NULL;
1864 }
1865 }
1866
1867 if (err == OK && keyObj != NULL) {
1868 if (env->GetArrayLength(keyObj) != 16) {
1869 err = -EINVAL;
1870 } else {
1871 jboolean isCopy;
1872 key = env->GetByteArrayElements(keyObj, &isCopy);
1873 }
1874 }
1875
1876 if (err == OK && ivObj != NULL) {
1877 if (env->GetArrayLength(ivObj) != 16) {
1878 err = -EINVAL;
1879 } else {
1880 jboolean isCopy;
1881 iv = env->GetByteArrayElements(ivObj, &isCopy);
1882 }
1883 }
1884
Andreas Huberbfc56f42012-04-19 12:47:07 -07001885 AString errorDetailMsg;
1886
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001887 if (err == OK) {
1888 err = codec->queueSecureInputBuffer(
1889 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08001890 subSamples, numSubSamples,
1891 (const uint8_t *)key, (const uint8_t *)iv,
1892 mode,
1893 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001894 timestampUs,
1895 flags,
1896 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001897 }
1898
Wonsik Kim1cac4252020-01-24 11:45:37 -08001899 if (iv != NULL) {
1900 env->ReleaseByteArrayElements(ivObj, iv, 0);
1901 iv = NULL;
1902 }
1903
1904 if (key != NULL) {
1905 env->ReleaseByteArrayElements(keyObj, key, 0);
1906 key = NULL;
1907 }
1908
1909 delete[] subSamples;
1910 subSamples = NULL;
1911
Andreas Huberbfc56f42012-04-19 12:47:07 -07001912 throwExceptionAsNecessary(
Robert Shih631a80d2021-02-14 02:23:55 -08001913 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
1914 codec->getCrypto());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001915}
1916
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001917static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08001918 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
1919 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
1920 env, bufferObj);
1921 AHardwareBuffer_Desc desc;
1922 AHardwareBuffer_describe(hardwareBuffer, &desc);
1923 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
1924 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
1925 return nullptr;
1926 }
1927 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
1928 ALOGI("mapHardwareBuffer: buffer not CPU readable");
1929 return nullptr;
1930 }
1931 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
1932
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001933 uint64_t cpuUsage = 0;
1934 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
1935 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08001936
1937 AHardwareBuffer_Planes planes;
1938 int err = AHardwareBuffer_lockPlanes(
1939 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
1940 if (err != 0) {
1941 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
1942 return nullptr;
1943 }
1944
1945 if (planes.planeCount != 3) {
1946 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
1947 return nullptr;
1948 }
1949
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001950 ScopedLocalRef<jobjectArray> buffersArray{
1951 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
1952 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
1953 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08001954
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001955 jboolean isCopy = JNI_FALSE;
1956 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1957 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1958
1959 // For Y plane
1960 int rowSampling = 1;
1961 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08001962 // plane indices are Y-U-V.
1963 for (uint32_t i = 0; i < 3; ++i) {
1964 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001965 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
1966 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
1967 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08001968 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
1969 env,
1970 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001971 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08001972 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001973 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08001974 readOnly,
1975 true)};
1976
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001977 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
1978 rowStrides[i] = plane.rowStride;
1979 pixelStrides[i] = plane.pixelStride;
1980 // For U-V planes
1981 rowSampling = 2;
1982 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08001983 }
1984
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001985 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
1986 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
1987 rowStrides = pixelStrides = nullptr;
1988
Wonsik Kim637afb22020-02-25 14:27:29 -08001989 ScopedLocalRef<jclass> imageClazz(
1990 env, env->FindClass("android/media/MediaCodec$MediaImage"));
1991 CHECK(imageClazz.get() != NULL);
1992
1993 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001994 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08001995
1996 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001997 buffersArray.get(),
1998 rowStridesArray.get(),
1999 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08002000 desc.width,
2001 desc.height,
2002 desc.format, // ???
2003 (jboolean)readOnly /* readOnly */,
2004 (jlong)0 /* timestamp */,
2005 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
2006 (jlong)hardwareBuffer);
2007
2008 // if MediaImage creation fails, return null
2009 if (env->ExceptionCheck()) {
2010 env->ExceptionDescribe();
2011 env->ExceptionClear();
2012 return nullptr;
2013 }
2014
2015 AHardwareBuffer_acquire(hardwareBuffer);
2016
2017 return img;
2018}
2019
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002020static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
2021 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08002022 if (context == 0) {
2023 return;
2024 }
2025 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
2026
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002027 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
2028 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002029 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
2030 // Continue to release the hardwareBuffer
2031 }
2032
2033 AHardwareBuffer_release(hardwareBuffer);
2034}
2035
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002036static status_t ConvertKeyValueListsToAMessage(
2037 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
2038 static struct Fields {
2039 explicit Fields(JNIEnv *env) {
2040 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2041 CHECK(clazz.get() != NULL);
2042 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2043
2044 clazz.reset(env->FindClass("java/lang/Integer"));
2045 CHECK(clazz.get() != NULL);
2046 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2047
2048 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2049 CHECK(mIntegerValueId != NULL);
2050
2051 clazz.reset(env->FindClass("java/lang/Long"));
2052 CHECK(clazz.get() != NULL);
2053 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2054
2055 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2056 CHECK(mLongValueId != NULL);
2057
2058 clazz.reset(env->FindClass("java/lang/Float"));
2059 CHECK(clazz.get() != NULL);
2060 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2061
2062 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2063 CHECK(mFloatValueId != NULL);
2064
2065 clazz.reset(env->FindClass("java/util/ArrayList"));
2066 CHECK(clazz.get() != NULL);
2067
2068 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2069 CHECK(mByteBufferArrayId != NULL);
2070 }
2071
2072 jclass mStringClass;
2073 jclass mIntegerClass;
2074 jmethodID mIntegerValueId;
2075 jclass mLongClass;
2076 jmethodID mLongValueId;
2077 jclass mFloatClass;
2078 jmethodID mFloatValueId;
2079 jmethodID mByteBufferArrayId;
2080 } sFields{env};
2081
2082 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2083 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2084 return BAD_VALUE;
2085 }
2086
2087 sp<AMessage> result{new AMessage};
2088 for (jint i = 0; i < size; ++i) {
2089 ScopedLocalRef<jstring> jkey{
2090 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2091 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2092 AString key;
2093 if (tmp) {
2094 key.setTo(tmp);
2095 }
2096 env->ReleaseStringUTFChars(jkey.get(), tmp);
2097 if (key.empty()) {
2098 return NO_MEMORY;
2099 }
2100
2101 ScopedLocalRef<jobject> jvalue{
2102 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2103
2104 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2105 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2106 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002107 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002108 return NO_MEMORY;
2109 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002110 value.setTo(tmp);
2111 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002112 result->setString(key.c_str(), value);
2113 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2114 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2115 result->setInt32(key.c_str(), value);
2116 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2117 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2118 result->setInt64(key.c_str(), value);
2119 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2120 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2121 result->setFloat(key.c_str(), value);
2122 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002123 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2124 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002125 sp<ABuffer> buffer{new ABuffer(limit - position)};
2126 void *data = env->GetDirectBufferAddress(jvalue.get());
2127 if (data != nullptr) {
2128 memcpy(buffer->data(),
2129 static_cast<const uint8_t *>(data) + position,
2130 buffer->size());
2131 } else {
2132 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2133 jvalue.get(), sFields.mByteBufferArrayId)};
2134 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2135 reinterpret_cast<jbyte *>(buffer->data()));
2136 }
2137 result->setBuffer(key.c_str(), buffer);
2138 }
2139 }
2140
2141 *msg = result;
2142 return OK;
2143}
2144
2145static void android_media_MediaCodec_native_queueLinearBlock(
2146 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2147 jint offset, jint size, jobject cryptoInfoObj,
2148 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2149 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2150
2151 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2152
Wonsik Kim24e53802020-05-08 20:04:26 -07002153 if (codec == nullptr || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002154 throwExceptionAsNecessary(env, INVALID_OPERATION);
2155 return;
2156 }
2157
2158 sp<AMessage> tunings;
2159 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2160 if (err != OK) {
2161 throwExceptionAsNecessary(env, err);
2162 return;
2163 }
2164
2165 std::shared_ptr<C2Buffer> buffer;
2166 sp<hardware::HidlMemory> memory;
2167 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2168 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2169 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2170 JMediaCodecLinearBlock *context =
2171 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002172 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002173 memory = context->toHidlMemory();
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002174 // TODO: copy if memory is null
2175 offset += context->mHidlMemoryOffset;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002176 } else {
2177 buffer = context->toC2Buffer(offset, size);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002178 // TODO: copy if buffer is null
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002179 }
2180 }
2181 env->MonitorExit(lock.get());
2182 } else {
2183 throwExceptionAsNecessary(env, INVALID_OPERATION);
2184 return;
2185 }
2186
2187 AString errorDetailMsg;
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002188 if (codec->hasCryptoOrDescrambler()) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002189 if (!memory) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002190 ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002191 throwExceptionAsNecessary(env, BAD_VALUE);
2192 return;
2193 }
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002194 NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
2195 if (cryptoInfoObj == nullptr) {
2196 return NativeCryptoInfo{size};
2197 } else {
2198 return NativeCryptoInfo{env, cryptoInfoObj};
2199 }
2200 }();
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002201 err = codec->queueEncryptedLinearBlock(
2202 index,
2203 memory,
2204 offset,
2205 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2206 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2207 cryptoInfo.mMode,
2208 cryptoInfo.mPattern,
2209 presentationTimeUs,
2210 flags,
2211 tunings,
2212 &errorDetailMsg);
2213 } else {
2214 if (!buffer) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07002215 ALOGI("queueLinearBlock: no C2Buffer found");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002216 throwExceptionAsNecessary(env, BAD_VALUE);
2217 return;
2218 }
2219 err = codec->queueBuffer(
2220 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2221 }
2222 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2223}
2224
Wonsik Kim637afb22020-02-25 14:27:29 -08002225static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002226 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2227 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002228 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002229
2230 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2231
Wonsik Kim24e53802020-05-08 20:04:26 -07002232 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002233 throwExceptionAsNecessary(env, INVALID_OPERATION);
2234 return;
2235 }
2236
2237 sp<AMessage> tunings;
2238 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2239 if (err != OK) {
2240 throwExceptionAsNecessary(env, err);
2241 return;
2242 }
2243
Wonsik Kim637afb22020-02-25 14:27:29 -08002244 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2245 env, bufferObj);
2246 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2247 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002248 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2249 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2250 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2251 std::shared_ptr<C2Allocator> alloc;
2252 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2253 C2PlatformAllocatorStore::GRALLOC, &alloc);
2254 if (err == C2_OK) {
2255 return alloc;
2256 }
2257 return nullptr;
2258 }();
2259 std::shared_ptr<C2GraphicAllocation> alloc;
2260 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2261 if (c2err != C2_OK) {
2262 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002263 throwExceptionAsNecessary(env, BAD_VALUE);
2264 return;
2265 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002266 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002267 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2268 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002269 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002270 err = codec->queueBuffer(
2271 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002272 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2273}
2274
2275static void android_media_MediaCodec_native_getOutputFrame(
2276 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2277 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2278
2279 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2280
Wonsik Kim24e53802020-05-08 20:04:26 -07002281 if (codec == NULL || codec->initCheck() != OK) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002282 throwExceptionAsNecessary(env, INVALID_OPERATION);
2283 return;
2284 }
2285
2286 status_t err = codec->getOutputFrame(env, frame, index);
2287 if (err != OK) {
2288 throwExceptionAsNecessary(env, err);
2289 }
2290}
2291
Andreas Huber88572f72012-02-21 11:47:18 -08002292static jint android_media_MediaCodec_dequeueInputBuffer(
2293 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2294 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2295
2296 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2297
Wonsik Kim24e53802020-05-08 20:04:26 -07002298 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002299 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002300 return -1;
2301 }
2302
2303 size_t index;
2304 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2305
2306 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002307 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002308 }
2309
2310 return throwExceptionAsNecessary(env, err);
2311}
2312
2313static jint android_media_MediaCodec_dequeueOutputBuffer(
2314 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2315 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2316
2317 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2318
Wonsik Kim24e53802020-05-08 20:04:26 -07002319 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002320 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002321 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002322 }
2323
2324 size_t index;
2325 status_t err = codec->dequeueOutputBuffer(
2326 env, bufferInfo, &index, timeoutUs);
2327
2328 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002329 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002330 }
2331
2332 return throwExceptionAsNecessary(env, err);
2333}
2334
2335static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002336 JNIEnv *env, jobject thiz,
2337 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002338 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2339
2340 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2341
Wonsik Kim24e53802020-05-08 20:04:26 -07002342 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002343 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002344 return;
2345 }
2346
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002347 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002348
2349 throwExceptionAsNecessary(env, err);
2350}
2351
Andy McFadden2621e402013-02-19 07:29:21 -08002352static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2353 jobject thiz) {
2354 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2355
2356 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002357 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002358 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08002359 return;
2360 }
2361
2362 status_t err = codec->signalEndOfInputStream();
2363
2364 throwExceptionAsNecessary(env, err);
2365}
2366
Lajos Molnard4023112014-07-11 15:12:59 -07002367static jobject android_media_MediaCodec_getFormatNative(
2368 JNIEnv *env, jobject thiz, jboolean input) {
2369 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002370
2371 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2372
Wonsik Kim24e53802020-05-08 20:04:26 -07002373 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002374 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002375 return NULL;
2376 }
2377
2378 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002379 status_t err = codec->getFormat(env, input, &format);
2380
2381 if (err == OK) {
2382 return format;
2383 }
2384
2385 throwExceptionAsNecessary(env, err);
2386
2387 return NULL;
2388}
2389
2390static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2391 JNIEnv *env, jobject thiz, jint index) {
2392 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2393
2394 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2395
Wonsik Kim24e53802020-05-08 20:04:26 -07002396 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002397 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002398 return NULL;
2399 }
2400
2401 jobject format;
2402 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002403
2404 if (err == OK) {
2405 return format;
2406 }
2407
2408 throwExceptionAsNecessary(env, err);
2409
2410 return NULL;
2411}
2412
2413static jobjectArray android_media_MediaCodec_getBuffers(
2414 JNIEnv *env, jobject thiz, jboolean input) {
2415 ALOGV("android_media_MediaCodec_getBuffers");
2416
2417 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2418
Wonsik Kim24e53802020-05-08 20:04:26 -07002419 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002420 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002421 return NULL;
2422 }
2423
2424 jobjectArray buffers;
2425 status_t err = codec->getBuffers(env, input, &buffers);
2426
2427 if (err == OK) {
2428 return buffers;
2429 }
2430
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002431 // if we're out of memory, an exception was already thrown
2432 if (err != NO_MEMORY) {
2433 throwExceptionAsNecessary(env, err);
2434 }
Andreas Huber88572f72012-02-21 11:47:18 -08002435
2436 return NULL;
2437}
2438
Lajos Molnard4023112014-07-11 15:12:59 -07002439static jobject android_media_MediaCodec_getBuffer(
2440 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2441 ALOGV("android_media_MediaCodec_getBuffer");
2442
2443 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2444
Wonsik Kim24e53802020-05-08 20:04:26 -07002445 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002446 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002447 return NULL;
2448 }
2449
2450 jobject buffer;
2451 status_t err = codec->getBuffer(env, input, index, &buffer);
2452
2453 if (err == OK) {
2454 return buffer;
2455 }
2456
2457 // if we're out of memory, an exception was already thrown
2458 if (err != NO_MEMORY) {
2459 throwExceptionAsNecessary(env, err);
2460 }
2461
2462 return NULL;
2463}
2464
2465static jobject android_media_MediaCodec_getImage(
2466 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2467 ALOGV("android_media_MediaCodec_getImage");
2468
2469 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2470
Wonsik Kim24e53802020-05-08 20:04:26 -07002471 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002472 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002473 return NULL;
2474 }
2475
2476 jobject image;
2477 status_t err = codec->getImage(env, input, index, &image);
2478
2479 if (err == OK) {
2480 return image;
2481 }
2482
2483 // if we're out of memory, an exception was already thrown
2484 if (err != NO_MEMORY) {
2485 throwExceptionAsNecessary(env, err);
2486 }
2487
2488 return NULL;
2489}
2490
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002491static jobject android_media_MediaCodec_getName(
2492 JNIEnv *env, jobject thiz) {
2493 ALOGV("android_media_MediaCodec_getName");
2494
2495 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2496
Wonsik Kim24e53802020-05-08 20:04:26 -07002497 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002498 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002499 return NULL;
2500 }
2501
2502 jstring name;
2503 status_t err = codec->getName(env, &name);
2504
2505 if (err == OK) {
2506 return name;
2507 }
2508
2509 throwExceptionAsNecessary(env, err);
2510
2511 return NULL;
2512}
2513
Chong Zhanga0b72a62018-02-28 18:46:26 -08002514static jobject android_media_MediaCodec_getOwnCodecInfo(
2515 JNIEnv *env, jobject thiz) {
2516 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2517
2518 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2519
Wonsik Kim24e53802020-05-08 20:04:26 -07002520 if (codec == NULL || codec->initCheck() != OK) {
Chong Zhanga0b72a62018-02-28 18:46:26 -08002521 throwExceptionAsNecessary(env, INVALID_OPERATION);
2522 return NULL;
2523 }
2524
2525 jobject codecInfoObj;
2526 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2527
2528 if (err == OK) {
2529 return codecInfoObj;
2530 }
2531
2532 throwExceptionAsNecessary(env, err);
2533
2534 return NULL;
2535}
2536
Ray Essick0e0fee12017-01-25 18:01:56 -08002537static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002538android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002539{
Ray Essickf2d0e402017-03-09 10:17:51 -08002540 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002541
2542 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
Wonsik Kim24e53802020-05-08 20:04:26 -07002543 if (codec == NULL || codec->initCheck() != OK) {
Ray Essick0e0fee12017-01-25 18:01:56 -08002544 jniThrowException(env, "java/lang/IllegalStateException", NULL);
2545 return 0;
2546 }
2547
2548 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002549 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002550
2551 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002552 if (err != OK) {
2553 ALOGE("getMetrics failed");
2554 return (jobject) NULL;
2555 }
2556
Ray Essick0e0fee12017-01-25 18:01:56 -08002557 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2558
2559 // housekeeping
2560 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002561 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002562
2563 return mybundle;
2564}
2565
Andreas Huber226065b2013-08-12 10:14:11 -07002566static void android_media_MediaCodec_setParameters(
2567 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2568 ALOGV("android_media_MediaCodec_setParameters");
2569
2570 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2571
Wonsik Kim24e53802020-05-08 20:04:26 -07002572 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002573 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07002574 return;
2575 }
2576
2577 sp<AMessage> params;
2578 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2579
2580 if (err == OK) {
2581 err = codec->setParameters(params);
2582 }
2583
2584 throwExceptionAsNecessary(env, err);
2585}
2586
Andreas Huberb12a5392012-04-30 14:18:33 -07002587static void android_media_MediaCodec_setVideoScalingMode(
2588 JNIEnv *env, jobject thiz, jint mode) {
2589 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2590
Wonsik Kim24e53802020-05-08 20:04:26 -07002591 if (codec == NULL || codec->initCheck() != OK) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002592 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07002593 return;
2594 }
2595
2596 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2597 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07002598 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07002599 return;
2600 }
2601
2602 codec->setVideoScalingMode(mode);
2603}
2604
ybai5e053202018-11-01 13:02:15 +08002605static void android_media_MediaCodec_setAudioPresentation(
2606 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2607 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2608
Wonsik Kim24e53802020-05-08 20:04:26 -07002609 if (codec == NULL || codec->initCheck() != OK) {
ybai5e053202018-11-01 13:02:15 +08002610 throwExceptionAsNecessary(env, INVALID_OPERATION);
2611 return;
2612 }
2613
2614 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2615}
2616
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07002617static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002618 ScopedLocalRef<jclass> clazz(
2619 env, env->FindClass("android/media/MediaCodec"));
2620 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002621
Andreas Huberaba67132013-10-22 12:40:01 -07002622 gFields.postEventFromNativeID =
2623 env->GetMethodID(
2624 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07002625 CHECK(gFields.postEventFromNativeID != NULL);
2626
Wonsik Kim61796fd2018-09-13 13:15:59 -07002627 gFields.lockAndGetContextID =
2628 env->GetMethodID(
2629 clazz.get(), "lockAndGetContext", "()J");
2630 CHECK(gFields.lockAndGetContextID != NULL);
2631
2632 gFields.setAndUnlockContextID =
2633 env->GetMethodID(
2634 clazz.get(), "setAndUnlockContext", "(J)V");
2635 CHECK(gFields.setAndUnlockContextID != NULL);
2636
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002637 jfieldID field;
2638 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
2639 CHECK(field != NULL);
2640 gCryptoModes.Unencrypted =
2641 env->GetStaticIntField(clazz.get(), field);
2642
2643 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
2644 CHECK(field != NULL);
2645 gCryptoModes.AesCtr =
2646 env->GetStaticIntField(clazz.get(), field);
2647
2648 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
2649 CHECK(field != NULL);
2650 gCryptoModes.AesCbc =
2651 env->GetStaticIntField(clazz.get(), field);
2652
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002653 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
2654 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07002655
2656 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002657 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002658 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
2659
2660 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002661 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002662 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
2663
2664 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002665 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002666 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
2667
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002668 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002669 CHECK(gFields.cryptoInfoKeyID != NULL);
2670
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002671 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002672 CHECK(gFields.cryptoInfoIVID != NULL);
2673
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002674 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002675 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002676
Santiago Seifert09ae5f62020-09-18 16:51:04 +01002677 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "mPattern",
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002678 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
2679 CHECK(gFields.cryptoInfoPatternID != NULL);
2680
2681 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
2682 CHECK(clazz.get() != NULL);
2683
2684 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
2685 CHECK(gFields.patternEncryptBlocksID != NULL);
2686
2687 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
2688 CHECK(gFields.patternSkipBlocksID != NULL);
2689
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002690 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
2691 CHECK(clazz.get() != NULL);
2692
2693 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
2694 CHECK(gFields.queueRequestIndexID != NULL);
2695
2696 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
2697 CHECK(clazz.get() != NULL);
2698
2699 gFields.outputFrameLinearBlockID =
2700 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
2701 CHECK(gFields.outputFrameLinearBlockID != NULL);
2702
Wonsik Kim637afb22020-02-25 14:27:29 -08002703 gFields.outputFrameHardwareBufferID =
2704 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
2705 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002706
2707 gFields.outputFrameChangedKeysID =
2708 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
2709 CHECK(gFields.outputFrameChangedKeysID != NULL);
2710
2711 gFields.outputFrameFormatID =
2712 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
2713 CHECK(gFields.outputFrameFormatID != NULL);
2714
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002715 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
2716 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002717
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002718 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002719 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002720 gCryptoErrorCodes.cryptoErrorNoKey =
2721 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002722
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002723 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002724 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002725 gCryptoErrorCodes.cryptoErrorKeyExpired =
2726 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002727
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002728 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002729 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002730 gCryptoErrorCodes.cryptoErrorResourceBusy =
2731 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002732
Jeff Tinker336d3ea2014-08-28 17:57:36 -07002733 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
2734 CHECK(field != NULL);
2735 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
2736 env->GetStaticIntField(clazz.get(), field);
2737
Jeff Tinker96a2a952015-07-01 17:35:18 -07002738 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
2739 CHECK(field != NULL);
2740 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
2741 env->GetStaticIntField(clazz.get(), field);
2742
Jeff Tinker20594d82018-12-12 08:31:22 -08002743 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
2744 CHECK(field != NULL);
2745 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
2746 env->GetStaticIntField(clazz.get(), field);
2747
Jeff Tinkerd3932162016-03-05 11:35:20 -08002748 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
2749 CHECK(field != NULL);
2750 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
2751 env->GetStaticIntField(clazz.get(), field);
2752
Jeff Tinker20594d82018-12-12 08:31:22 -08002753 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
2754 CHECK(field != NULL);
2755 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
2756 env->GetStaticIntField(clazz.get(), field);
2757
2758 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
2759 CHECK(field != NULL);
2760 gCryptoErrorCodes.cryptoErrorLostState =
2761 env->GetStaticIntField(clazz.get(), field);
2762
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002763 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
2764 CHECK(clazz.get() != NULL);
2765 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
2766 CHECK(field != NULL);
2767 gCodecActionCodes.codecActionTransient =
2768 env->GetStaticIntField(clazz.get(), field);
2769
2770 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
2771 CHECK(field != NULL);
2772 gCodecActionCodes.codecActionRecoverable =
2773 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002774
Ronghua Wuc53ad692015-05-08 14:40:49 -07002775 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002776 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002777 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002778 env->GetStaticIntField(clazz.get(), field);
2779
Ronghua Wuc53ad692015-05-08 14:40:49 -07002780 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002781 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002782 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002783 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07002784
2785 clazz.reset(env->FindClass("android/view/Surface"));
2786 CHECK(clazz.get() != NULL);
2787
2788 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2789 CHECK(field != NULL);
2790 gPersistentSurfaceClassInfo.mLock = field;
2791
2792 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
2793 CHECK(method != NULL);
2794 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2795
2796 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2797 CHECK(clazz.get() != NULL);
2798 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2799
2800 method = env->GetMethodID(clazz.get(), "<init>", "()V");
2801 CHECK(method != NULL);
2802 gPersistentSurfaceClassInfo.ctor = method;
2803
2804 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2805 CHECK(field != NULL);
2806 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08002807
2808 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2809 CHECK(clazz.get() != NULL);
2810 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2811
2812 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08002813 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08002814 "Ljava/util/Map;Ljava/util/Map;)V");
2815 CHECK(method != NULL);
2816 gCodecInfo.capsCtorId = method;
2817
2818 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2819 CHECK(clazz.get() != NULL);
2820 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2821
2822 field = env->GetFieldID(clazz.get(), "profile", "I");
2823 CHECK(field != NULL);
2824 gCodecInfo.profileField = field;
2825
2826 field = env->GetFieldID(clazz.get(), "level", "I");
2827 CHECK(field != NULL);
2828 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002829
2830 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
2831 CHECK(clazz.get() != NULL);
2832 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2833
2834 ScopedLocalRef<jclass> byteOrderClass(
2835 env, env->FindClass("java/nio/ByteOrder"));
2836 CHECK(byteOrderClass.get() != NULL);
2837
2838 jmethodID nativeOrderID = env->GetStaticMethodID(
2839 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
2840 CHECK(nativeOrderID != NULL);
2841
2842 ScopedLocalRef<jobject> nativeByteOrderObj{
2843 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
2844 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
2845 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
2846 nativeByteOrderObj.reset();
2847
2848 gByteBufferInfo.orderId = env->GetMethodID(
2849 clazz.get(),
2850 "order",
2851 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
2852 CHECK(gByteBufferInfo.orderId != NULL);
2853
2854 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
2855 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
2856 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
2857
2858 gByteBufferInfo.positionId = env->GetMethodID(
2859 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
2860 CHECK(gByteBufferInfo.positionId != NULL);
2861
2862 gByteBufferInfo.limitId = env->GetMethodID(
2863 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
2864 CHECK(gByteBufferInfo.limitId != NULL);
2865
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002866 gByteBufferInfo.getPositionId = env->GetMethodID(
2867 clazz.get(), "position", "()I");
2868 CHECK(gByteBufferInfo.getPositionId != NULL);
2869
2870 gByteBufferInfo.getLimitId = env->GetMethodID(
2871 clazz.get(), "limit", "()I");
2872 CHECK(gByteBufferInfo.getLimitId != NULL);
2873
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002874 clazz.reset(env->FindClass("java/util/ArrayList"));
2875 CHECK(clazz.get() != NULL);
2876
2877 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
2878 CHECK(gArrayListInfo.sizeId != NULL);
2879
2880 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
2881 CHECK(gArrayListInfo.getId != NULL);
2882
2883 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
2884 CHECK(gArrayListInfo.addId != NULL);
2885
2886 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
2887 CHECK(clazz.get() != NULL);
2888
2889 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2890
2891 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
2892 CHECK(gLinearBlockInfo.ctorId != NULL);
2893
2894 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
2895 clazz.get(), "setInternalStateLocked", "(JZ)V");
2896 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
2897
2898 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
2899 CHECK(gLinearBlockInfo.contextId != NULL);
2900
2901 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
2902 CHECK(gLinearBlockInfo.validId != NULL);
2903
2904 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2905 CHECK(gLinearBlockInfo.lockId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002906}
2907
2908static void android_media_MediaCodec_native_setup(
2909 JNIEnv *env, jobject thiz,
2910 jstring name, jboolean nameIsType, jboolean encoder) {
2911 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002912 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002913 return;
2914 }
2915
2916 const char *tmp = env->GetStringUTFChars(name, NULL);
2917
2918 if (tmp == NULL) {
2919 return;
2920 }
2921
2922 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2923
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002924 const status_t err = codec->initCheck();
2925 if (err == NAME_NOT_FOUND) {
2926 // fail and do not try again.
2927 jniThrowException(env, "java/lang/IllegalArgumentException",
2928 String8::format("Failed to initialize %s, error %#x", tmp, err));
2929 env->ReleaseStringUTFChars(name, tmp);
2930 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07002931 } if (err == NO_MEMORY) {
2932 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2933 String8::format("Failed to initialize %s, error %#x", tmp, err));
2934 env->ReleaseStringUTFChars(name, tmp);
2935 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002936 } else if (err != OK) {
2937 // believed possible to try again
2938 jniThrowException(env, "java/io/IOException",
2939 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2940 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08002941 return;
2942 }
2943
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002944 env->ReleaseStringUTFChars(name, tmp);
2945
Andreas Huberaba67132013-10-22 12:40:01 -07002946 codec->registerSelf();
2947
Andreas Huber88572f72012-02-21 11:47:18 -08002948 setMediaCodec(env,thiz, codec);
2949}
2950
2951static void android_media_MediaCodec_native_finalize(
2952 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07002953 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002954}
2955
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002956// MediaCodec.LinearBlock
2957
2958static jobject android_media_MediaCodec_LinearBlock_native_map(
2959 JNIEnv *env, jobject thiz) {
2960 JMediaCodecLinearBlock *context =
2961 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2962 if (context->mBuffer) {
2963 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
2964 if (!context->mReadonlyMapping) {
2965 const C2BufferData data = buffer->data();
2966 if (data.type() != C2BufferData::LINEAR) {
2967 throwExceptionAsNecessary(env, INVALID_OPERATION);
2968 return nullptr;
2969 }
2970 if (data.linearBlocks().size() != 1u) {
2971 throwExceptionAsNecessary(env, INVALID_OPERATION);
2972 return nullptr;
2973 }
2974 C2ConstLinearBlock block = data.linearBlocks().front();
2975 context->mReadonlyMapping =
2976 std::make_shared<C2ReadView>(block.map().get());
2977 }
2978 return CreateByteBuffer(
2979 env,
2980 context->mReadonlyMapping->data(), // base
2981 context->mReadonlyMapping->capacity(), // capacity
2982 0u, // offset
2983 context->mReadonlyMapping->capacity(), // size
2984 true, // readOnly
2985 true /* clearBuffer */);
2986 } else if (context->mBlock) {
2987 std::shared_ptr<C2LinearBlock> block = context->mBlock;
2988 if (!context->mReadWriteMapping) {
2989 context->mReadWriteMapping =
2990 std::make_shared<C2WriteView>(block->map().get());
2991 }
2992 return CreateByteBuffer(
2993 env,
2994 context->mReadWriteMapping->base(),
2995 context->mReadWriteMapping->capacity(),
2996 context->mReadWriteMapping->offset(),
2997 context->mReadWriteMapping->size(),
2998 false, // readOnly
2999 true /* clearBuffer */);
3000 } else if (context->mLegacyBuffer) {
3001 return CreateByteBuffer(
3002 env,
3003 context->mLegacyBuffer->base(),
3004 context->mLegacyBuffer->capacity(),
3005 context->mLegacyBuffer->offset(),
3006 context->mLegacyBuffer->size(),
3007 true, // readOnly
3008 true /* clearBuffer */);
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003009 } else if (context->mMemory) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003010 return CreateByteBuffer(
3011 env,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003012 context->mMemory->unsecurePointer(),
3013 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003014 0,
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003015 context->mMemory->size(),
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003016 false, // readOnly
3017 true /* clearBuffer */);
3018 }
3019 throwExceptionAsNecessary(env, INVALID_OPERATION);
3020 return nullptr;
3021}
3022
3023static void android_media_MediaCodec_LinearBlock_native_recycle(
3024 JNIEnv *env, jobject thiz) {
3025 JMediaCodecLinearBlock *context =
3026 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
Wonsik Kimd319a442020-05-28 17:54:06 -07003027 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, jlong(0), false);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003028 delete context;
3029}
3030
3031static void PopulateNamesVector(
3032 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
3033 jsize length = env->GetArrayLength(codecNames);
3034 for (jsize i = 0; i < length; ++i) {
3035 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
3036 if (jstr == nullptr) {
3037 // null entries are ignored
3038 continue;
3039 }
3040 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
3041 if (cstr == nullptr) {
3042 throwExceptionAsNecessary(env, BAD_VALUE);
3043 return;
3044 }
3045 names->emplace_back(cstr);
3046 env->ReleaseStringUTFChars(jstr, cstr);
3047 }
3048}
3049
3050static void android_media_MediaCodec_LinearBlock_native_obtain(
3051 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3052 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3053 std::vector<std::string> names;
3054 PopulateNamesVector(env, codecNames, &names);
3055 bool hasSecure = false;
3056 bool hasNonSecure = false;
3057 for (const std::string &name : names) {
3058 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3059 hasSecure = true;
3060 } else {
3061 hasNonSecure = true;
3062 }
3063 }
3064 if (hasSecure && !hasNonSecure) {
Wonsik Kimf7069ce2020-05-13 17:15:47 -07003065 constexpr size_t kInitialDealerCapacity = 1048576; // 1MB
3066 thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
3067 kInitialDealerCapacity, "JNI(1MB)");
3068 context->mMemory = sDealer->allocate(capacity);
3069 if (context->mMemory == nullptr) {
3070 size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
3071 while (capacity * 2 > newDealerCapacity) {
3072 newDealerCapacity *= 2;
3073 }
3074 ALOGI("LinearBlock.native_obtain: "
3075 "Dealer capacity increasing from %zuMB to %zuMB",
3076 sDealer->getMemoryHeap()->getSize() / 1048576,
3077 newDealerCapacity / 1048576);
3078 sDealer = new MemoryDealer(
3079 newDealerCapacity,
3080 AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
3081 context->mMemory = sDealer->allocate(capacity);
3082 }
3083 context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
3084 &context->mHidlMemoryOffset, &context->mHidlMemorySize));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003085 } else {
3086 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
3087 if (!context->mBlock) {
3088 jniThrowException(env, "java/io/IOException", nullptr);
3089 return;
3090 }
3091 }
3092 env->CallVoidMethod(
3093 thiz,
3094 gLinearBlockInfo.setInternalStateId,
3095 (jlong)context.release(),
3096 true /* isMappable */);
3097}
3098
3099static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003100 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003101 std::vector<std::string> names;
3102 PopulateNamesVector(env, codecNames, &names);
3103 bool isCompatible = false;
3104 bool hasSecure = false;
3105 bool hasNonSecure = false;
3106 for (const std::string &name : names) {
3107 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3108 hasSecure = true;
3109 } else {
3110 hasNonSecure = true;
3111 }
3112 }
3113 if (hasSecure && hasNonSecure) {
3114 return false;
3115 }
3116 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3117 if (err != OK) {
3118 throwExceptionAsNecessary(env, err);
3119 }
3120 return isCompatible;
3121}
3122
Daniel Micay76f6a862015-09-19 17:31:01 -04003123static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003124 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003125
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003126 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3127
Chong Zhang8034d602015-04-28 13:38:48 -07003128 { "native_releasePersistentInputSurface",
3129 "(Landroid/view/Surface;)V",
3130 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3131
3132 { "native_createPersistentInputSurface",
3133 "()Landroid/media/MediaCodec$PersistentSurface;",
3134 (void *)android_media_MediaCodec_createPersistentInputSurface },
3135
Chong Zhang9560ddb2015-05-13 10:25:29 -07003136 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3137 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003138
Lajos Molnard8578572015-06-05 20:17:33 -07003139 { "native_enableOnFrameRenderedListener", "(Z)V",
3140 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3141
Chong Zhang8d5e5562014-07-08 18:49:21 -07003142 { "native_setCallback",
3143 "(Landroid/media/MediaCodec$Callback;)V",
3144 (void *)android_media_MediaCodec_native_setCallback },
3145
Andreas Huber88572f72012-02-21 11:47:18 -08003146 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003147 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003148 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003149 (void *)android_media_MediaCodec_native_configure },
3150
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003151 { "native_setSurface",
3152 "(Landroid/view/Surface;)V",
3153 (void *)android_media_MediaCodec_native_setSurface },
3154
Andy McFadden2621e402013-02-19 07:29:21 -08003155 { "createInputSurface", "()Landroid/view/Surface;",
3156 (void *)android_media_MediaCodec_createInputSurface },
3157
Lajos Molnard4023112014-07-11 15:12:59 -07003158 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003159 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003160 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003161
Lajos Molnard4023112014-07-11 15:12:59 -07003162 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003163 (void *)android_media_MediaCodec_queueInputBuffer },
3164
Lajos Molnard4023112014-07-11 15:12:59 -07003165 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003166 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3167
Wonsik Kim637afb22020-02-25 14:27:29 -08003168 { "native_mapHardwareBuffer",
3169 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3170 (void *)android_media_MediaCodec_mapHardwareBuffer },
3171
3172 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3173
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003174 { "native_queueLinearBlock",
3175 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3176 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3177 (void *)android_media_MediaCodec_native_queueLinearBlock },
3178
Wonsik Kim637afb22020-02-25 14:27:29 -08003179 { "native_queueHardwareBuffer",
3180 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3181 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003182
3183 { "native_getOutputFrame",
3184 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3185 (void *)android_media_MediaCodec_native_getOutputFrame },
3186
Lajos Molnard4023112014-07-11 15:12:59 -07003187 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003188 (void *)android_media_MediaCodec_dequeueInputBuffer },
3189
Lajos Molnard4023112014-07-11 15:12:59 -07003190 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003191 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3192
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003193 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003194 (void *)android_media_MediaCodec_releaseOutputBuffer },
3195
Andy McFadden2621e402013-02-19 07:29:21 -08003196 { "signalEndOfInputStream", "()V",
3197 (void *)android_media_MediaCodec_signalEndOfInputStream },
3198
Lajos Molnard4023112014-07-11 15:12:59 -07003199 { "getFormatNative", "(Z)Ljava/util/Map;",
3200 (void *)android_media_MediaCodec_getFormatNative },
3201
3202 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3203 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003204
3205 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3206 (void *)android_media_MediaCodec_getBuffers },
3207
Lajos Molnard4023112014-07-11 15:12:59 -07003208 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3209 (void *)android_media_MediaCodec_getBuffer },
3210
3211 { "getImage", "(ZI)Landroid/media/Image;",
3212 (void *)android_media_MediaCodec_getImage },
3213
Lajos Molnard2a7f472018-11-15 12:49:20 -08003214 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003215 (void *)android_media_MediaCodec_getName },
3216
Chong Zhanga0b72a62018-02-28 18:46:26 -08003217 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3218 (void *)android_media_MediaCodec_getOwnCodecInfo },
3219
Ray Essick10353e32017-04-14 10:22:55 -07003220 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003221 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003222
Andreas Huber226065b2013-08-12 10:14:11 -07003223 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3224 (void *)android_media_MediaCodec_setParameters },
3225
Andreas Huberb12a5392012-04-30 14:18:33 -07003226 { "setVideoScalingMode", "(I)V",
3227 (void *)android_media_MediaCodec_setVideoScalingMode },
3228
ybai5e053202018-11-01 13:02:15 +08003229 { "native_setAudioPresentation", "(II)V",
3230 (void *)android_media_MediaCodec_setAudioPresentation },
3231
Andreas Huber88572f72012-02-21 11:47:18 -08003232 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3233
3234 { "native_setup", "(Ljava/lang/String;ZZ)V",
3235 (void *)android_media_MediaCodec_native_setup },
3236
3237 { "native_finalize", "()V",
3238 (void *)android_media_MediaCodec_native_finalize },
3239};
3240
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003241static const JNINativeMethod gLinearBlockMethods[] = {
3242 { "native_map", "()Ljava/nio/ByteBuffer;",
3243 (void *)android_media_MediaCodec_LinearBlock_native_map },
3244
3245 { "native_recycle", "()V",
3246 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3247
3248 { "native_obtain", "(I[Ljava/lang/String;)V",
3249 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3250
3251 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3252 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3253};
3254
Andreas Huber88572f72012-02-21 11:47:18 -08003255int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003256 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003257 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003258 if (result != JNI_OK) {
3259 return result;
3260 }
3261 result = AndroidRuntime::registerNativeMethods(env,
3262 "android/media/MediaCodec$LinearBlock",
3263 gLinearBlockMethods,
3264 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003265 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003266}