blob: cde7df22006ef311ffcfae0d528c2feae25de38d [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>
40
Chong Zhang2659c2f2017-04-27 13:18:20 -070041#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080042
Wonsik Kim637afb22020-02-25 14:27:29 -080043#include <android_runtime/android_hardware_HardwareBuffer.h>
44
Wonsik Kimccb7ac62019-12-27 17:12:40 -080045#include <binder/MemoryHeapBase.h>
46
Lajos Molnar7ac4f562014-03-24 15:57:51 -070047#include <cutils/compiler.h>
48
Mathias Agopian8335f1c2012-02-25 18:48:35 -080049#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080050
Wonsik Kimccb7ac62019-12-27 17:12:40 -080051#include <hidlmemory/FrameworkUtils.h>
52
Wonsik Kim4273dd02016-09-27 15:23:35 +090053#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080054#include <media/hardware/VideoAPI.h>
Andreas Huber88572f72012-02-21 11:47:18 -080055#include <media/stagefright/MediaCodec.h>
56#include <media/stagefright/foundation/ABuffer.h>
57#include <media/stagefright/foundation/ADebug.h>
58#include <media/stagefright/foundation/ALooper.h>
59#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070060#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080061#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070062#include <media/stagefright/PersistentSurface.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080063#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070064
Wonsik Kim637afb22020-02-25 14:27:29 -080065#include <private/android/AHardwareBufferHelpers.h>
66
Andreas Huberb12a5392012-04-30 14:18:33 -070067#include <system/window.h>
68
Andreas Huber88572f72012-02-21 11:47:18 -080069namespace android {
70
71// Keep these in sync with their equivalents in MediaCodec.java !!!
72enum {
73 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
74 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
75 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
76};
77
Andreas Huberaba67132013-10-22 12:40:01 -070078enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070079 EVENT_CALLBACK = 1,
80 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070081 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070082};
83
Andy Hung5f9aa0b2014-07-30 15:48:21 -070084static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070085 jint cryptoErrorNoKey;
86 jint cryptoErrorKeyExpired;
87 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070088 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070089 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -080090 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -080091 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -080092 jint cryptoErrorFrameTooLarge;
93 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -070094} gCryptoErrorCodes;
95
Andy Hung5f9aa0b2014-07-30 15:48:21 -070096static struct CodecActionCodes {
97 jint codecActionTransient;
98 jint codecActionRecoverable;
99} gCodecActionCodes;
100
Ronghua Wuc53ad692015-05-08 14:40:49 -0700101static struct CodecErrorCodes {
102 jint errorInsufficientResource;
103 jint errorReclaimed;
104} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700105
Chong Zhang8034d602015-04-28 13:38:48 -0700106static struct {
107 jclass clazz;
108 jfieldID mLock;
109 jfieldID mPersistentObject;
110 jmethodID ctor;
111 jmethodID setNativeObjectLocked;
112} gPersistentSurfaceClassInfo;
113
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800114static struct {
115 jint Unencrypted;
116 jint AesCtr;
117 jint AesCbc;
118} gCryptoModes;
119
Chong Zhanga0b72a62018-02-28 18:46:26 -0800120static struct {
121 jclass capsClazz;
122 jmethodID capsCtorId;
123 jclass profileLevelClazz;
124 jfieldID profileField;
125 jfieldID levelField;
126} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800127
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800128static struct {
129 jclass clazz;
130 jobject nativeByteOrder;
131 jmethodID orderId;
132 jmethodID asReadOnlyBufferId;
133 jmethodID positionId;
134 jmethodID limitId;
135} gByteBufferInfo;
136
137static struct {
138 jmethodID sizeId;
139 jmethodID getId;
140 jmethodID addId;
141} gArrayListInfo;
142
143static struct {
144 jclass clazz;
145 jmethodID ctorId;
146 jmethodID setInternalStateId;
147 jfieldID contextId;
148 jfieldID validId;
149 jfieldID lockId;
150} gLinearBlockInfo;
151
Andreas Huber88572f72012-02-21 11:47:18 -0800152struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700153 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700154 jmethodID lockAndGetContextID;
155 jmethodID setAndUnlockContextID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700156 jfieldID cryptoInfoNumSubSamplesID;
157 jfieldID cryptoInfoNumBytesOfClearDataID;
158 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
159 jfieldID cryptoInfoKeyID;
160 jfieldID cryptoInfoIVID;
161 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800162 jfieldID cryptoInfoPatternID;
163 jfieldID patternEncryptBlocksID;
164 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800165 jfieldID queueRequestIndexID;
166 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800167 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800168 jfieldID outputFrameChangedKeysID;
169 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800170};
171
172static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700173static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800174
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800175
Andreas Huber88572f72012-02-21 11:47:18 -0800176////////////////////////////////////////////////////////////////////////////////
177
178JMediaCodec::JMediaCodec(
179 JNIEnv *env, jobject thiz,
180 const char *name, bool nameIsType, bool encoder)
181 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700182 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800183 jclass clazz = env->GetObjectClass(thiz);
184 CHECK(clazz != NULL);
185
186 mClass = (jclass)env->NewGlobalRef(clazz);
187 mObject = env->NewWeakGlobalRef(thiz);
188
189 mLooper = new ALooper;
190 mLooper->setName("MediaCodec_looper");
191
192 mLooper->start(
193 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700194 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700195 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800196
197 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700198 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800199 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
200 mNameAtCreation = "(null)";
201 }
Andreas Huber88572f72012-02-21 11:47:18 -0800202 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700203 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800204 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800205 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700206 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800207}
208
209status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700210 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800211}
212
Andreas Huberaba67132013-10-22 12:40:01 -0700213void JMediaCodec::registerSelf() {
214 mLooper->registerHandler(this);
215}
216
Chong Zhang128b0122014-03-01 18:04:13 -0800217void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700218 std::call_once(mReleaseFlag, [this] {
219 if (mCodec != NULL) {
220 mCodec->release();
221 mInitStatus = NO_INIT;
222 }
Andreas Huber88572f72012-02-21 11:47:18 -0800223
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700224 if (mLooper != NULL) {
225 mLooper->unregisterHandler(id());
226 mLooper->stop();
227 mLooper.clear();
228 }
229 });
Chong Zhang128b0122014-03-01 18:04:13 -0800230}
231
232JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700233 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800234 /* MediaCodec and looper should have been released explicitly already
235 * in setMediaCodec() (see comments in setMediaCodec()).
236 *
237 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
238 * message handler, doing release() there risks deadlock as MediaCodec::
239 * release() post synchronous message to the same looper.
240 *
241 * Print a warning and try to proceed with releasing.
242 */
243 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
244 release();
245 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
246 }
247
Andreas Huber88572f72012-02-21 11:47:18 -0800248 JNIEnv *env = AndroidRuntime::getJNIEnv();
249
250 env->DeleteWeakGlobalRef(mObject);
251 mObject = NULL;
252 env->DeleteGlobalRef(mClass);
253 mClass = NULL;
254}
255
Lajos Molnard8578572015-06-05 20:17:33 -0700256status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
257 if (enable) {
258 if (mOnFrameRenderedNotification == NULL) {
259 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
260 }
261 } else {
262 mOnFrameRenderedNotification.clear();
263 }
264
265 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
266}
267
Chong Zhang8d5e5562014-07-08 18:49:21 -0700268status_t JMediaCodec::setCallback(jobject cb) {
269 if (cb != NULL) {
270 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800271 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700272 }
273 } else {
274 mCallbackNotification.clear();
275 }
276
277 return mCodec->setCallback(mCallbackNotification);
278}
279
Andreas Huber88572f72012-02-21 11:47:18 -0800280status_t JMediaCodec::configure(
281 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800282 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700283 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800284 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800285 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800286 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800287 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700288 mSurfaceTextureClient =
289 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700290 } else {
291 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800292 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700293
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800294 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
295 AString mime;
296 CHECK(format->findString("mime", &mime));
297 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
298 && !(flags & CONFIGURE_FLAG_ENCODE);
299
Chong Zhangd5927ae2017-01-03 11:07:18 -0800300 return mCodec->configure(
301 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800302}
303
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700304status_t JMediaCodec::setSurface(
305 const sp<IGraphicBufferProducer> &bufferProducer) {
306 sp<Surface> client;
307 if (bufferProducer != NULL) {
308 client = new Surface(bufferProducer, true /* controlledByApp */);
309 }
310 status_t err = mCodec->setSurface(client);
311 if (err == OK) {
312 mSurfaceTextureClient = client;
313 }
314 return err;
315}
316
Andy McFadden2621e402013-02-19 07:29:21 -0800317status_t JMediaCodec::createInputSurface(
318 sp<IGraphicBufferProducer>* bufferProducer) {
319 return mCodec->createInputSurface(bufferProducer);
320}
321
Chong Zhang9560ddb2015-05-13 10:25:29 -0700322status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700323 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700324 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700325}
326
Andreas Huber88572f72012-02-21 11:47:18 -0800327status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700328 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800329}
330
331status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700332 mSurfaceTextureClient.clear();
333
Chong Zhang8d5e5562014-07-08 18:49:21 -0700334 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800335}
336
337status_t JMediaCodec::flush() {
338 return mCodec->flush();
339}
340
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700341status_t JMediaCodec::reset() {
342 return mCodec->reset();
343}
344
Andreas Huber88572f72012-02-21 11:47:18 -0800345status_t JMediaCodec::queueInputBuffer(
346 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700347 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
348 AString *errorDetailMsg) {
349 return mCodec->queueInputBuffer(
350 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800351}
352
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700353status_t JMediaCodec::queueSecureInputBuffer(
354 size_t index,
355 size_t offset,
356 const CryptoPlugin::SubSample *subSamples,
357 size_t numSubSamples,
358 const uint8_t key[16],
359 const uint8_t iv[16],
360 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800361 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700362 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700363 uint32_t flags,
364 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700365 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800366 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700367 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700368}
369
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800370status_t JMediaCodec::queueBuffer(
371 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
372 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
373 return mCodec->queueBuffer(
374 index, buffer, timeUs, flags, tunings, errorDetailMsg);
375}
376
377status_t JMediaCodec::queueEncryptedLinearBlock(
378 size_t index,
379 const sp<hardware::HidlMemory> &buffer,
380 size_t offset,
381 const CryptoPlugin::SubSample *subSamples,
382 size_t numSubSamples,
383 const uint8_t key[16],
384 const uint8_t iv[16],
385 CryptoPlugin::Mode mode,
386 const CryptoPlugin::Pattern &pattern,
387 int64_t presentationTimeUs,
388 uint32_t flags,
389 const sp<AMessage> &tunings,
390 AString *errorDetailMsg) {
391 return mCodec->queueEncryptedBuffer(
392 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
393 presentationTimeUs, flags, tunings, errorDetailMsg);
394}
395
Andreas Huber88572f72012-02-21 11:47:18 -0800396status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700397 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800398}
399
400status_t JMediaCodec::dequeueOutputBuffer(
401 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
402 size_t size, offset;
403 int64_t timeUs;
404 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700405 status_t err = mCodec->dequeueOutputBuffer(
406 index, &offset, &size, &timeUs, &flags, timeoutUs);
407
Andreas Huberaba67132013-10-22 12:40:01 -0700408 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800409 return err;
410 }
411
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700412 ScopedLocalRef<jclass> clazz(
413 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800414
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700415 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000416 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800417
418 return OK;
419}
420
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700421status_t JMediaCodec::releaseOutputBuffer(
422 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
423 if (updatePTS) {
424 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
425 }
Andreas Huber88572f72012-02-21 11:47:18 -0800426 return render
427 ? mCodec->renderOutputBufferAndRelease(index)
428 : mCodec->releaseOutputBuffer(index);
429}
430
Andy McFadden2621e402013-02-19 07:29:21 -0800431status_t JMediaCodec::signalEndOfInputStream() {
432 return mCodec->signalEndOfInputStream();
433}
434
Lajos Molnard4023112014-07-11 15:12:59 -0700435status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800436 sp<AMessage> msg;
437 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700438 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
439 if (err != OK) {
440 return err;
441 }
442
443 return ConvertMessageToMap(env, msg, format);
444}
445
446status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
447 sp<AMessage> msg;
448 status_t err;
449 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800450 return err;
451 }
452
453 return ConvertMessageToMap(env, msg, format);
454}
455
456status_t JMediaCodec::getBuffers(
457 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900458 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800459
460 status_t err =
461 input
462 ? mCodec->getInputBuffers(&buffers)
463 : mCodec->getOutputBuffers(&buffers);
464
465 if (err != OK) {
466 return err;
467 }
468
Andreas Huber88572f72012-02-21 11:47:18 -0800469 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800470 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800471 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800472 return NO_MEMORY;
473 }
Andreas Huber88572f72012-02-21 11:47:18 -0800474
475 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900476 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800477
Lajos Molnar7de28d32014-07-25 07:51:02 -0700478 jobject byteBuffer = NULL;
479 err = createByteBufferFromABuffer(
480 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
481 if (err != OK) {
482 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800483 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700484 if (byteBuffer != NULL) {
485 env->SetObjectArrayElement(
486 *bufArray, i, byteBuffer);
487
Lajos Molnard4023112014-07-11 15:12:59 -0700488 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700489 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700490 }
Andreas Huber88572f72012-02-21 11:47:18 -0800491 }
492
Lajos Molnar7de28d32014-07-25 07:51:02 -0700493 return OK;
494}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700495
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800496template <typename T>
497static jobject CreateByteBuffer(
498 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
499 bool readOnly, bool clearBuffer) {
500 jobject byteBuffer =
501 env->NewDirectByteBuffer(
502 const_cast<typename std::remove_const<T>::type *>(base),
503 capacity);
504 if (readOnly && byteBuffer != NULL) {
505 jobject readOnlyBuffer = env->CallObjectMethod(
506 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
507 env->DeleteLocalRef(byteBuffer);
508 byteBuffer = readOnlyBuffer;
509 }
510 if (byteBuffer == NULL) {
511 return nullptr;
512 }
513 jobject me = env->CallObjectMethod(
514 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
515 env->DeleteLocalRef(me);
516 me = env->CallObjectMethod(
517 byteBuffer, gByteBufferInfo.limitId,
518 clearBuffer ? capacity : offset + size);
519 env->DeleteLocalRef(me);
520 me = env->CallObjectMethod(
521 byteBuffer, gByteBufferInfo.positionId,
522 clearBuffer ? 0 : offset);
523 env->DeleteLocalRef(me);
524 me = NULL;
525 return byteBuffer;
526}
527
528
Lajos Molnar7de28d32014-07-25 07:51:02 -0700529// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900530template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700531status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900532 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700533 jobject *buf) const {
534 // if this is an ABuffer that doesn't actually hold any accessible memory,
535 // use a null ByteBuffer
536 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700537
538 if (buffer == NULL) {
539 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
540 return OK;
541 }
542
Lajos Molnar7de28d32014-07-25 07:51:02 -0700543 if (buffer->base() == NULL) {
544 return OK;
545 }
546
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800547 jobject byteBuffer = CreateByteBuffer(
548 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
549 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700550
551 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800552 return OK;
553}
554
Lajos Molnard4023112014-07-11 15:12:59 -0700555status_t JMediaCodec::getBuffer(
556 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900557 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700558
559 status_t err =
560 input
561 ? mCodec->getInputBuffer(index, &buffer)
562 : mCodec->getOutputBuffer(index, &buffer);
563
564 if (err != OK) {
565 return err;
566 }
567
Lajos Molnar7de28d32014-07-25 07:51:02 -0700568 return createByteBufferFromABuffer(
569 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700570}
571
572status_t JMediaCodec::getImage(
573 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900574 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700575
576 status_t err =
577 input
578 ? mCodec->getInputBuffer(index, &buffer)
579 : mCodec->getOutputBuffer(index, &buffer);
580
581 if (err != OK) {
582 return err;
583 }
584
585 // if this is an ABuffer that doesn't actually hold any accessible memory,
586 // use a null ByteBuffer
587 *buf = NULL;
588 if (buffer->base() == NULL) {
589 return OK;
590 }
591
592 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700593 sp<ABuffer> imageData;
594 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700595 return OK;
596 }
597
Lajos Molnar7de28d32014-07-25 07:51:02 -0700598 int64_t timestamp = 0;
599 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
600 timestamp *= 1000; // adjust to ns
601 }
602
603 jobject byteBuffer = NULL;
604 err = createByteBufferFromABuffer(
605 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
606 if (err != OK) {
607 return OK;
608 }
609
610 jobject infoBuffer = NULL;
611 err = createByteBufferFromABuffer(
612 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
613 if (err != OK) {
614 env->DeleteLocalRef(byteBuffer);
615 byteBuffer = NULL;
616 return OK;
617 }
618
619 jobject cropRect = NULL;
620 int32_t left, top, right, bottom;
621 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
622 ScopedLocalRef<jclass> rectClazz(
623 env, env->FindClass("android/graphics/Rect"));
624 CHECK(rectClazz.get() != NULL);
625
626 jmethodID rectConstructID = env->GetMethodID(
627 rectClazz.get(), "<init>", "(IIII)V");
628
629 cropRect = env->NewObject(
630 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
631 }
632
633 ScopedLocalRef<jclass> imageClazz(
634 env, env->FindClass("android/media/MediaCodec$MediaImage"));
635 CHECK(imageClazz.get() != NULL);
636
637 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
638 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
639
640 *buf = env->NewObject(imageClazz.get(), imageConstructID,
641 byteBuffer, infoBuffer,
642 (jboolean)!input /* readOnly */,
643 (jlong)timestamp,
644 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
645
646 // if MediaImage creation fails, return null
647 if (env->ExceptionCheck()) {
648 env->ExceptionDescribe();
649 env->ExceptionClear();
650 *buf = NULL;
651 }
652
653 if (cropRect != NULL) {
654 env->DeleteLocalRef(cropRect);
655 cropRect = NULL;
656 }
657
658 env->DeleteLocalRef(byteBuffer);
659 byteBuffer = NULL;
660
661 env->DeleteLocalRef(infoBuffer);
662 infoBuffer = NULL;
663
Lajos Molnard4023112014-07-11 15:12:59 -0700664 return OK;
665}
666
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800667status_t JMediaCodec::getOutputFrame(
668 JNIEnv *env, jobject frame, size_t index) const {
669 sp<MediaCodecBuffer> buffer;
670
671 status_t err = mCodec->getOutputBuffer(index, &buffer);
672 if (err != OK) {
673 return err;
674 }
675
676 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800677 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800678 if (c2Buffer) {
679 switch (c2Buffer->data().type()) {
680 case C2BufferData::LINEAR: {
681 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
682 context->mBuffer = c2Buffer;
683 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
684 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800685 env->CallVoidMethod(
686 linearBlock.get(),
687 gLinearBlockInfo.setInternalStateId,
688 (jlong)context.release(),
689 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800690 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
691 break;
692 }
693 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800694 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
695 uint32_t width, height, format, stride, igbp_slot, generation;
696 uint64_t usage, igbp_id;
697 _UnwrapNativeCodec2GrallocMetadata(
698 c2Handle, &width, &height, &format, &usage, &stride, &generation,
699 &igbp_id, &igbp_slot);
700 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
701 GraphicBuffer* graphicBuffer = new GraphicBuffer(
702 grallocHandle, GraphicBuffer::CLONE_HANDLE,
703 width, height, format, 1, usage, stride);
704 ScopedLocalRef<jobject> hardwareBuffer{
705 env,
706 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
707 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
708 env->SetObjectField(
709 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800710 break;
711 }
712 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
713 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
714 case C2BufferData::INVALID: [[fallthrough]];
715 default:
716 return INVALID_OPERATION;
717 }
718 } else {
719 if (!mGraphicOutput) {
720 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
721 context->mLegacyBuffer = buffer;
722 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
723 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800724 env->CallVoidMethod(
725 linearBlock.get(),
726 gLinearBlockInfo.setInternalStateId,
727 (jlong)context.release(),
728 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800729 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
730 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800731 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800732 }
733 }
734 }
735
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700736 jobject formatMap;
737 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800738 if (err != OK) {
739 return err;
740 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700741 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
742 ScopedLocalRef<jobject> format{env, env->NewObject(
743 mediaFormatClass.get(),
744 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
745 formatMap)};
746 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
747 env->DeleteLocalRef(formatMap);
748 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800749
750 sp<RefBase> obj;
751 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
752 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
753 (decltype(changedKeys.get()))obj.get()};
754 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
755 frame, gFields.outputFrameChangedKeysID)};
756 for (const std::string &key : changedKeys->value) {
757 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
758 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
759 }
760 }
761 return OK;
762}
763
764
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300765status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
766 AString name;
767
768 status_t err = mCodec->getName(&name);
769
770 if (err != OK) {
771 return err;
772 }
773
774 *nameStr = env->NewStringUTF(name.c_str());
775
776 return OK;
777}
778
Chong Zhanga0b72a62018-02-28 18:46:26 -0800779static jobject getCodecCapabilitiesObject(
780 JNIEnv *env, const char *mime, bool isEncoder,
781 const sp<MediaCodecInfo::Capabilities> &capabilities) {
782 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
783 Vector<uint32_t> colorFormats;
784
785 sp<AMessage> defaultFormat = new AMessage();
786 defaultFormat->setString("mime", mime);
787
788 capabilities->getSupportedColorFormats(&colorFormats);
789 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800790 sp<AMessage> details = capabilities->getDetails();
791
792 jobject defaultFormatObj = NULL;
793 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
794 return NULL;
795 }
796 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
797
798 jobject detailsObj = NULL;
799 if (ConvertMessageToMap(env, details, &detailsObj)) {
800 return NULL;
801 }
802 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
803
804 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
805 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
806
807 for (size_t i = 0; i < profileLevels.size(); ++i) {
808 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
809
810 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
811 gCodecInfo.profileLevelClazz));
812
813 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
814 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
815
816 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
817 }
818
819 ScopedLocalRef<jintArray> colorFormatsArray(
820 env, env->NewIntArray(colorFormats.size()));
821 for (size_t i = 0; i < colorFormats.size(); ++i) {
822 jint val = colorFormats.itemAt(i);
823 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
824 }
825
826 return env->NewObject(
827 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800828 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800829 defaultFormatRef.get(), detailsRef.get());
830}
831
832status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
833 sp<MediaCodecInfo> codecInfo;
834
835 status_t err = mCodec->getCodecInfo(&codecInfo);
836
837 if (err != OK) {
838 return err;
839 }
840
841 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800842 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800843
Lajos Molnard2a7f472018-11-15 12:49:20 -0800844 ScopedLocalRef<jstring> canonicalNameObject(env,
845 env->NewStringUTF(codecInfo->getCodecName()));
846
847 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800848 bool isEncoder = codecInfo->isEncoder();
849
Lajos Molnard2a7f472018-11-15 12:49:20 -0800850 Vector<AString> mediaTypes;
851 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800852
853 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800854 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800855
Lajos Molnard2a7f472018-11-15 12:49:20 -0800856 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800857 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800858 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800859
860 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800861 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800862
863 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
864 }
865
866 ScopedLocalRef<jclass> codecInfoClazz(env,
867 env->FindClass("android/media/MediaCodecInfo"));
868 CHECK(codecInfoClazz.get() != NULL);
869
870 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800871 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800872
873 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800874 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800875
876 return OK;
877}
878
Ray Essick81fbc5b2019-12-07 06:24:59 -0800879status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
880 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700881 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700882 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800883 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800884 return status;
885}
886
Andreas Huber226065b2013-08-12 10:14:11 -0700887status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
888 return mCodec->setParameters(msg);
889}
890
Andreas Huberb12a5392012-04-30 14:18:33 -0700891void JMediaCodec::setVideoScalingMode(int mode) {
892 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700893 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700894 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700895 // also signal via param for components that queue to IGBP
896 sp<AMessage> msg = new AMessage;
897 msg->setInt32("android._video-scaling", mode);
898 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700899 }
900}
901
ybai5e053202018-11-01 13:02:15 +0800902void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
903 sp<AMessage> msg = new AMessage;
904 msg->setInt32("audio-presentation-presentation-id", presentationId);
905 msg->setInt32("audio-presentation-program-id", programId);
906 (void)mCodec->setParameters(msg);
907}
908
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700909static jthrowable createCodecException(
910 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
911 ScopedLocalRef<jclass> clazz(
912 env, env->FindClass("android/media/MediaCodec$CodecException"));
913 CHECK(clazz.get() != NULL);
914
Ronghua Wuc53ad692015-05-08 14:40:49 -0700915 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700916 CHECK(ctor != NULL);
917
918 ScopedLocalRef<jstring> msgObj(
919 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
920
921 // translate action code to Java equivalent
922 switch (actionCode) {
923 case ACTION_CODE_TRANSIENT:
924 actionCode = gCodecActionCodes.codecActionTransient;
925 break;
926 case ACTION_CODE_RECOVERABLE:
927 actionCode = gCodecActionCodes.codecActionRecoverable;
928 break;
929 default:
930 actionCode = 0; // everything else is fatal
931 break;
932 }
933
Ronghua Wuc53ad692015-05-08 14:40:49 -0700934 /* translate OS errors to Java API CodecException errorCodes */
935 switch (err) {
936 case NO_MEMORY:
937 err = gCodecErrorCodes.errorInsufficientResource;
938 break;
939 case DEAD_OBJECT:
940 err = gCodecErrorCodes.errorReclaimed;
941 break;
942 default: /* Other error codes go out as is. */
943 break;
944 }
945
946 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700947}
948
Chong Zhang8d5e5562014-07-08 18:49:21 -0700949void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
950 int32_t arg1, arg2 = 0;
951 jobject obj = NULL;
952 CHECK(msg->findInt32("callbackID", &arg1));
953 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700954
Chong Zhang8d5e5562014-07-08 18:49:21 -0700955 switch (arg1) {
956 case MediaCodec::CB_INPUT_AVAILABLE:
957 {
958 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700959 break;
960 }
961
Chong Zhang8d5e5562014-07-08 18:49:21 -0700962 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700963 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700964 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700965
Chong Zhang8d5e5562014-07-08 18:49:21 -0700966 size_t size, offset;
967 int64_t timeUs;
968 uint32_t flags;
969 CHECK(msg->findSize("size", &size));
970 CHECK(msg->findSize("offset", &offset));
971 CHECK(msg->findInt64("timeUs", &timeUs));
972 CHECK(msg->findInt32("flags", (int32_t *)&flags));
973
974 ScopedLocalRef<jclass> clazz(
975 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
976 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
977 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
978
979 obj = env->NewObject(clazz.get(), ctor);
980
981 if (obj == NULL) {
982 if (env->ExceptionCheck()) {
983 ALOGE("Could not create MediaCodec.BufferInfo.");
984 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700985 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700986 jniThrowException(env, "java/lang/IllegalStateException", NULL);
987 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700988 }
989
Chong Zhang8d5e5562014-07-08 18:49:21 -0700990 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
991 break;
992 }
993
994 case MediaCodec::CB_ERROR:
995 {
Chong Zhang94686d12014-07-11 15:53:58 -0700996 int32_t err, actionCode;
997 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -0700998 CHECK(msg->findInt32("actionCode", &actionCode));
999
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001000 // note that DRM errors could conceivably alias into a CodecException
1001 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001002
1003 if (obj == NULL) {
1004 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001005 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001006 env->ExceptionClear();
1007 }
1008 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1009 return;
1010 }
Andreas Huberaba67132013-10-22 12:40:01 -07001011
1012 break;
1013 }
1014
Chong Zhang8d5e5562014-07-08 18:49:21 -07001015 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001016 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001017 sp<AMessage> format;
1018 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001019
Chong Zhang8d5e5562014-07-08 18:49:21 -07001020 if (OK != ConvertMessageToMap(env, format, &obj)) {
1021 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1022 return;
1023 }
Andreas Huberaba67132013-10-22 12:40:01 -07001024
Andreas Huberaba67132013-10-22 12:40:01 -07001025 break;
1026 }
1027
1028 default:
1029 TRESPASS();
1030 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001031
1032 env->CallVoidMethod(
1033 mObject,
1034 gFields.postEventFromNativeID,
1035 EVENT_CALLBACK,
1036 arg1,
1037 arg2,
1038 obj);
1039
1040 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001041}
1042
Lajos Molnard8578572015-06-05 20:17:33 -07001043void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1044 int32_t arg1 = 0, arg2 = 0;
1045 jobject obj = NULL;
1046 JNIEnv *env = AndroidRuntime::getJNIEnv();
1047
1048 sp<AMessage> data;
1049 CHECK(msg->findMessage("data", &data));
1050
1051 status_t err = ConvertMessageToMap(env, data, &obj);
1052 if (err != OK) {
1053 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1054 return;
1055 }
1056
1057 env->CallVoidMethod(
1058 mObject, gFields.postEventFromNativeID,
1059 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1060
1061 env->DeleteLocalRef(obj);
1062}
1063
Chong Zhang8d5e5562014-07-08 18:49:21 -07001064void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1065 switch (msg->what()) {
1066 case kWhatCallbackNotify:
1067 {
1068 handleCallback(msg);
1069 break;
1070 }
Lajos Molnard8578572015-06-05 20:17:33 -07001071 case kWhatFrameRendered:
1072 {
1073 handleFrameRenderedNotification(msg);
1074 break;
1075 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001076 default:
1077 TRESPASS();
1078 }
Andreas Huberaba67132013-10-22 12:40:01 -07001079}
1080
Andreas Huber88572f72012-02-21 11:47:18 -08001081} // namespace android
1082
1083////////////////////////////////////////////////////////////////////////////////
1084
1085using namespace android;
1086
1087static sp<JMediaCodec> setMediaCodec(
1088 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001089 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001090 if (codec != NULL) {
1091 codec->incStrong(thiz);
1092 }
1093 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001094 /* release MediaCodec and stop the looper now before decStrong.
1095 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1096 * its message handler, doing release() from there will deadlock
1097 * (as MediaCodec::release() post synchronous message to the same looper)
1098 */
1099 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -08001100 old->decStrong(thiz);
1101 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001102 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001103
1104 return old;
1105}
1106
1107static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001108 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1109 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1110 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001111}
1112
1113static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Lajos Molnar5b610e22020-03-09 21:22:44 +00001114 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001115}
1116
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001117static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1118 jthrowable exception = createCodecException(env, err, actionCode, msg);
1119 env->Throw(exception);
1120}
1121
Andreas Huberbfc56f42012-04-19 12:47:07 -07001122static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001123 ScopedLocalRef<jclass> clazz(
1124 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1125 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001126
1127 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001128 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -07001129 CHECK(constructID != NULL);
1130
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001131 const char *defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -07001132
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001133 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001134 switch (err) {
1135 case ERROR_DRM_NO_LICENSE:
1136 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001137 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001138 break;
1139 case ERROR_DRM_LICENSE_EXPIRED:
1140 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001141 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001142 break;
1143 case ERROR_DRM_RESOURCE_BUSY:
1144 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001145 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001146 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001147 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1148 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001149 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001150 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001151 case ERROR_DRM_SESSION_NOT_OPENED:
1152 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001153 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001154 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001155 case ERROR_DRM_INSUFFICIENT_SECURITY:
1156 err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1157 defaultMsg = "Required security level is not met";
1158 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001159 case ERROR_DRM_CANNOT_HANDLE:
1160 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1161 defaultMsg = "Operation not supported in this configuration";
1162 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001163 case ERROR_DRM_FRAME_TOO_LARGE:
1164 err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1165 defaultMsg = "Decrytped frame exceeds size of output buffer";
1166 break;
1167 case ERROR_DRM_SESSION_LOST_STATE:
1168 err = gCryptoErrorCodes.cryptoErrorLostState;
1169 defaultMsg = "Session state was lost, open a new session and retry";
1170 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001171 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001172 break;
1173 }
1174
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001175 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
1176
Andreas Huberbfc56f42012-04-19 12:47:07 -07001177 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001178 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001179
1180 env->Throw(exception);
1181}
1182
1183static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001184 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1185 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001186 switch (err) {
1187 case OK:
1188 return 0;
1189
1190 case -EAGAIN:
1191 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1192
1193 case INFO_FORMAT_CHANGED:
1194 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1195
1196 case INFO_OUTPUT_BUFFERS_CHANGED:
1197 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1198
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001199 case INVALID_OPERATION:
1200 jniThrowException(env, "java/lang/IllegalStateException", msg);
1201 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001202
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001203 case BAD_VALUE:
1204 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1205 return 0;
1206
Andreas Huber88572f72012-02-21 11:47:18 -08001207 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001208 if (isCryptoError(err)) {
1209 throwCryptoException(env, err, msg);
1210 return 0;
1211 }
1212 throwCodecException(env, err, actionCode, msg);
1213 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001214 }
Andreas Huber88572f72012-02-21 11:47:18 -08001215}
1216
Lajos Molnard8578572015-06-05 20:17:33 -07001217static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1218 JNIEnv *env,
1219 jobject thiz,
1220 jboolean enabled) {
1221 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1222
1223 if (codec == NULL) {
1224 throwExceptionAsNecessary(env, INVALID_OPERATION);
1225 return;
1226 }
1227
1228 status_t err = codec->enableOnFrameRenderedListener(enabled);
1229
1230 throwExceptionAsNecessary(env, err);
1231}
1232
Chong Zhang8d5e5562014-07-08 18:49:21 -07001233static void android_media_MediaCodec_native_setCallback(
1234 JNIEnv *env,
1235 jobject thiz,
1236 jobject cb) {
1237 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1238
1239 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001240 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001241 return;
1242 }
1243
1244 status_t err = codec->setCallback(cb);
1245
1246 throwExceptionAsNecessary(env, err);
1247}
1248
Andreas Huber88572f72012-02-21 11:47:18 -08001249static void android_media_MediaCodec_native_configure(
1250 JNIEnv *env,
1251 jobject thiz,
1252 jobjectArray keys, jobjectArray values,
1253 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001254 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001255 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001256 jint flags) {
1257 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1258
1259 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001260 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001261 return;
1262 }
1263
1264 sp<AMessage> format;
1265 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1266
1267 if (err != OK) {
1268 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1269 return;
1270 }
1271
Andy McFaddend47f7d82012-12-18 09:48:38 -08001272 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001273 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001274 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001275 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001276 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001277 } else {
1278 jniThrowException(
1279 env,
1280 "java/lang/IllegalArgumentException",
1281 "The surface has been released");
1282 return;
1283 }
1284 }
1285
Andreas Huber8240d922012-04-04 14:06:32 -07001286 sp<ICrypto> crypto;
1287 if (jcrypto != NULL) {
1288 crypto = JCrypto::GetCrypto(env, jcrypto);
1289 }
1290
Chong Zhangd5927ae2017-01-03 11:07:18 -08001291 sp<IDescrambler> descrambler;
1292 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001293 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001294 }
1295
1296 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001297
1298 throwExceptionAsNecessary(env, err);
1299}
1300
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001301static void android_media_MediaCodec_native_setSurface(
1302 JNIEnv *env,
1303 jobject thiz,
1304 jobject jsurface) {
1305 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1306
1307 if (codec == NULL) {
1308 throwExceptionAsNecessary(env, INVALID_OPERATION);
1309 return;
1310 }
1311
1312 sp<IGraphicBufferProducer> bufferProducer;
1313 if (jsurface != NULL) {
1314 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1315 if (surface != NULL) {
1316 bufferProducer = surface->getIGraphicBufferProducer();
1317 } else {
1318 jniThrowException(
1319 env,
1320 "java/lang/IllegalArgumentException",
1321 "The surface has been released");
1322 return;
1323 }
1324 }
1325
1326 status_t err = codec->setSurface(bufferProducer);
1327 throwExceptionAsNecessary(env, err);
1328}
1329
Chong Zhang8034d602015-04-28 13:38:48 -07001330sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1331 JNIEnv* env, jobject object) {
1332 sp<PersistentSurface> persistentSurface;
1333
1334 jobject lock = env->GetObjectField(
1335 object, gPersistentSurfaceClassInfo.mLock);
1336 if (env->MonitorEnter(lock) == JNI_OK) {
1337 persistentSurface = reinterpret_cast<PersistentSurface *>(
1338 env->GetLongField(object,
1339 gPersistentSurfaceClassInfo.mPersistentObject));
1340 env->MonitorExit(lock);
1341 }
1342 env->DeleteLocalRef(lock);
1343
1344 return persistentSurface;
1345}
1346
1347static jobject android_media_MediaCodec_createPersistentInputSurface(
1348 JNIEnv* env, jclass /* clazz */) {
1349 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1350 sp<PersistentSurface> persistentSurface =
1351 MediaCodec::CreatePersistentInputSurface();
1352
1353 if (persistentSurface == NULL) {
1354 return NULL;
1355 }
1356
1357 sp<Surface> surface = new Surface(
1358 persistentSurface->getBufferProducer(), true);
1359 if (surface == NULL) {
1360 return NULL;
1361 }
1362
1363 jobject object = env->NewObject(
1364 gPersistentSurfaceClassInfo.clazz,
1365 gPersistentSurfaceClassInfo.ctor);
1366
1367 if (object == NULL) {
1368 if (env->ExceptionCheck()) {
1369 ALOGE("Could not create PersistentSurface.");
1370 env->ExceptionClear();
1371 }
1372 return NULL;
1373 }
1374
1375 jobject lock = env->GetObjectField(
1376 object, gPersistentSurfaceClassInfo.mLock);
1377 if (env->MonitorEnter(lock) == JNI_OK) {
1378 env->CallVoidMethod(
1379 object,
1380 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1381 (jlong)surface.get());
1382 env->SetLongField(
1383 object,
1384 gPersistentSurfaceClassInfo.mPersistentObject,
1385 (jlong)persistentSurface.get());
1386 env->MonitorExit(lock);
1387 } else {
1388 env->DeleteLocalRef(object);
1389 object = NULL;
1390 }
1391 env->DeleteLocalRef(lock);
1392
1393 if (object != NULL) {
1394 surface->incStrong(&sRefBaseOwner);
1395 persistentSurface->incStrong(&sRefBaseOwner);
1396 }
1397
1398 return object;
1399}
1400
1401static void android_media_MediaCodec_releasePersistentInputSurface(
1402 JNIEnv* env, jclass /* clazz */, jobject object) {
1403 sp<PersistentSurface> persistentSurface;
1404
1405 jobject lock = env->GetObjectField(
1406 object, gPersistentSurfaceClassInfo.mLock);
1407 if (env->MonitorEnter(lock) == JNI_OK) {
1408 persistentSurface = reinterpret_cast<PersistentSurface *>(
1409 env->GetLongField(
1410 object, gPersistentSurfaceClassInfo.mPersistentObject));
1411 env->SetLongField(
1412 object,
1413 gPersistentSurfaceClassInfo.mPersistentObject,
1414 (jlong)0);
1415 env->MonitorExit(lock);
1416 }
1417 env->DeleteLocalRef(lock);
1418
1419 if (persistentSurface != NULL) {
1420 persistentSurface->decStrong(&sRefBaseOwner);
1421 }
1422 // no need to release surface as it will be released by Surface's jni
1423}
1424
Chong Zhang9560ddb2015-05-13 10:25:29 -07001425static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001426 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001427 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001428
1429 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1430 if (codec == NULL) {
1431 throwExceptionAsNecessary(env, INVALID_OPERATION);
1432 return;
1433 }
1434
1435 sp<PersistentSurface> persistentSurface =
1436 android_media_MediaCodec_getPersistentInputSurface(env, object);
1437
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001438 if (persistentSurface == NULL) {
1439 throwExceptionAsNecessary(
1440 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1441 return;
1442 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001443 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001444 if (err != NO_ERROR) {
1445 throwExceptionAsNecessary(env, err);
1446 }
1447}
1448
Andy McFadden2621e402013-02-19 07:29:21 -08001449static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1450 jobject thiz) {
1451 ALOGV("android_media_MediaCodec_createInputSurface");
1452
1453 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1454 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001455 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001456 return NULL;
1457 }
1458
1459 // Tell the MediaCodec that we want to use a Surface as input.
1460 sp<IGraphicBufferProducer> bufferProducer;
1461 status_t err = codec->createInputSurface(&bufferProducer);
1462 if (err != NO_ERROR) {
1463 throwExceptionAsNecessary(env, err);
1464 return NULL;
1465 }
1466
1467 // Wrap the IGBP in a Java-language Surface.
1468 return android_view_Surface_createFromIGraphicBufferProducer(env,
1469 bufferProducer);
1470}
1471
Andreas Huber88572f72012-02-21 11:47:18 -08001472static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1473 ALOGV("android_media_MediaCodec_start");
1474
1475 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1476
1477 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001478 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001479 return;
1480 }
1481
1482 status_t err = codec->start();
1483
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001484 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001485}
1486
1487static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1488 ALOGV("android_media_MediaCodec_stop");
1489
1490 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1491
1492 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001493 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001494 return;
1495 }
1496
1497 status_t err = codec->stop();
1498
1499 throwExceptionAsNecessary(env, err);
1500}
1501
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001502static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1503 ALOGV("android_media_MediaCodec_reset");
1504
1505 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1506
1507 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001508 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001509 return;
1510 }
1511
1512 status_t err = codec->reset();
1513 if (err != OK) {
1514 // treat all errors as fatal for now, though resource not available
1515 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001516 // we also should avoid sending INVALID_OPERATION here due to
1517 // the transitory nature of reset(), it should not inadvertently
1518 // trigger an IllegalStateException.
1519 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001520 }
1521 throwExceptionAsNecessary(env, err);
1522}
1523
Andreas Huber88572f72012-02-21 11:47:18 -08001524static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1525 ALOGV("android_media_MediaCodec_flush");
1526
1527 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1528
1529 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001530 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001531 return;
1532 }
1533
1534 status_t err = codec->flush();
1535
1536 throwExceptionAsNecessary(env, err);
1537}
1538
1539static void android_media_MediaCodec_queueInputBuffer(
1540 JNIEnv *env,
1541 jobject thiz,
1542 jint index,
1543 jint offset,
1544 jint size,
1545 jlong timestampUs,
1546 jint flags) {
1547 ALOGV("android_media_MediaCodec_queueInputBuffer");
1548
1549 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1550
1551 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001552 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001553 return;
1554 }
1555
Andreas Huberbfc56f42012-04-19 12:47:07 -07001556 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001557
Andreas Huberbfc56f42012-04-19 12:47:07 -07001558 status_t err = codec->queueInputBuffer(
1559 index, offset, size, timestampUs, flags, &errorDetailMsg);
1560
1561 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001562 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001563}
1564
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001565struct NativeCryptoInfo {
1566 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1567 : mEnv{env},
1568 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1569 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1570 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1571
1572 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1573 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1574
1575 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1576 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1577
1578 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1579 if (jmode == gCryptoModes.Unencrypted) {
1580 mMode = CryptoPlugin::kMode_Unencrypted;
1581 } else if (jmode == gCryptoModes.AesCtr) {
1582 mMode = CryptoPlugin::kMode_AES_CTR;
1583 } else if (jmode == gCryptoModes.AesCbc) {
1584 mMode = CryptoPlugin::kMode_AES_CBC;
1585 } else {
1586 throwExceptionAsNecessary(env, INVALID_OPERATION);
1587 return;
1588 }
1589
1590 ScopedLocalRef<jobject> patternObj{
1591 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1592
1593 CryptoPlugin::Pattern pattern;
1594 if (patternObj.get() == nullptr) {
1595 pattern.mEncryptBlocks = 0;
1596 pattern.mSkipBlocks = 0;
1597 } else {
1598 pattern.mEncryptBlocks = env->GetIntField(
1599 patternObj.get(), gFields.patternEncryptBlocksID);
1600 pattern.mSkipBlocks = env->GetIntField(
1601 patternObj.get(), gFields.patternSkipBlocksID);
1602 }
1603
1604 mErr = OK;
1605 if (mNumSubSamples <= 0) {
1606 mErr = -EINVAL;
1607 } else if (numBytesOfClearDataObj == nullptr
1608 && numBytesOfEncryptedDataObj == nullptr) {
1609 mErr = -EINVAL;
1610 } else if (numBytesOfEncryptedDataObj != nullptr
1611 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1612 mErr = -ERANGE;
1613 } else if (numBytesOfClearDataObj != nullptr
1614 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1615 mErr = -ERANGE;
1616 // subSamples array may silently overflow if number of samples are too large. Use
1617 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1618 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1619 mErr = -EINVAL;
1620 } else {
1621 jint *numBytesOfClearData =
1622 (numBytesOfClearDataObj == nullptr)
1623 ? nullptr
1624 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1625
1626 jint *numBytesOfEncryptedData =
1627 (numBytesOfEncryptedDataObj == nullptr)
1628 ? nullptr
1629 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1630
1631 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1632
1633 for (jint i = 0; i < mNumSubSamples; ++i) {
1634 mSubSamples[i].mNumBytesOfClearData =
1635 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1636
1637 mSubSamples[i].mNumBytesOfEncryptedData =
1638 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1639 }
1640
1641 if (numBytesOfEncryptedData != nullptr) {
1642 env->ReleaseIntArrayElements(
1643 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1644 numBytesOfEncryptedData = nullptr;
1645 }
1646
1647 if (numBytesOfClearData != nullptr) {
1648 env->ReleaseIntArrayElements(
1649 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1650 numBytesOfClearData = nullptr;
1651 }
1652 }
1653
1654 if (mErr == OK && mKeyObj.get() != nullptr) {
1655 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1656 mErr = -EINVAL;
1657 } else {
1658 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1659 }
1660 }
1661
1662 if (mErr == OK && mIvObj.get() != nullptr) {
1663 if (env->GetArrayLength(mIvObj.get()) != 16) {
1664 mErr = -EINVAL;
1665 } else {
1666 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1667 }
1668 }
1669 }
1670
1671 ~NativeCryptoInfo() {
1672 if (mIv != nullptr) {
1673 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1674 }
1675
1676 if (mKey != nullptr) {
1677 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1678 }
1679
1680 if (mSubSamples != nullptr) {
1681 delete[] mSubSamples;
1682 }
1683 }
1684
1685 JNIEnv *mEnv{nullptr};
1686 ScopedLocalRef<jbyteArray> mIvObj;
1687 ScopedLocalRef<jbyteArray> mKeyObj;
1688 status_t mErr{OK};
1689
1690 CryptoPlugin::SubSample *mSubSamples{nullptr};
1691 int32_t mNumSubSamples{0};
1692 jbyte *mIv{nullptr};
1693 jbyte *mKey{nullptr};
1694 enum CryptoPlugin::Mode mMode;
1695 CryptoPlugin::Pattern mPattern;
1696};
1697
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001698static void android_media_MediaCodec_queueSecureInputBuffer(
1699 JNIEnv *env,
1700 jobject thiz,
1701 jint index,
1702 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001703 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001704 jlong timestampUs,
1705 jint flags) {
1706 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1707
1708 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1709
1710 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001711 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001712 return;
1713 }
1714
Wonsik Kim1cac4252020-01-24 11:45:37 -08001715 jint numSubSamples =
1716 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1717
1718 jintArray numBytesOfClearDataObj =
1719 (jintArray)env->GetObjectField(
1720 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1721
1722 jintArray numBytesOfEncryptedDataObj =
1723 (jintArray)env->GetObjectField(
1724 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1725
1726 jbyteArray keyObj =
1727 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1728
1729 jbyteArray ivObj =
1730 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1731
1732 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1733 enum CryptoPlugin::Mode mode;
1734 if (jmode == gCryptoModes.Unencrypted) {
1735 mode = CryptoPlugin::kMode_Unencrypted;
1736 } else if (jmode == gCryptoModes.AesCtr) {
1737 mode = CryptoPlugin::kMode_AES_CTR;
1738 } else if (jmode == gCryptoModes.AesCbc) {
1739 mode = CryptoPlugin::kMode_AES_CBC;
1740 } else {
1741 throwExceptionAsNecessary(env, INVALID_OPERATION);
1742 return;
1743 }
1744
1745 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1746
1747 CryptoPlugin::Pattern pattern;
1748 if (patternObj == NULL) {
1749 pattern.mEncryptBlocks = 0;
1750 pattern.mSkipBlocks = 0;
1751 } else {
1752 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1753 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1754 }
1755
1756 status_t err = OK;
1757
1758 CryptoPlugin::SubSample *subSamples = NULL;
1759 jbyte *key = NULL;
1760 jbyte *iv = NULL;
1761
1762 if (numSubSamples <= 0) {
1763 err = -EINVAL;
1764 } else if (numBytesOfClearDataObj == NULL
1765 && numBytesOfEncryptedDataObj == NULL) {
1766 err = -EINVAL;
1767 } else if (numBytesOfEncryptedDataObj != NULL
1768 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1769 err = -ERANGE;
1770 } else if (numBytesOfClearDataObj != NULL
1771 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1772 err = -ERANGE;
1773 // subSamples array may silently overflow if number of samples are too large. Use
1774 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1775 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1776 err = -EINVAL;
1777 } else {
1778 jboolean isCopy;
1779
1780 jint *numBytesOfClearData =
1781 (numBytesOfClearDataObj == NULL)
1782 ? NULL
1783 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1784
1785 jint *numBytesOfEncryptedData =
1786 (numBytesOfEncryptedDataObj == NULL)
1787 ? NULL
1788 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1789
1790 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1791
1792 for (jint i = 0; i < numSubSamples; ++i) {
1793 subSamples[i].mNumBytesOfClearData =
1794 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1795
1796 subSamples[i].mNumBytesOfEncryptedData =
1797 (numBytesOfEncryptedData == NULL)
1798 ? 0 : numBytesOfEncryptedData[i];
1799 }
1800
1801 if (numBytesOfEncryptedData != NULL) {
1802 env->ReleaseIntArrayElements(
1803 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1804 numBytesOfEncryptedData = NULL;
1805 }
1806
1807 if (numBytesOfClearData != NULL) {
1808 env->ReleaseIntArrayElements(
1809 numBytesOfClearDataObj, numBytesOfClearData, 0);
1810 numBytesOfClearData = NULL;
1811 }
1812 }
1813
1814 if (err == OK && keyObj != NULL) {
1815 if (env->GetArrayLength(keyObj) != 16) {
1816 err = -EINVAL;
1817 } else {
1818 jboolean isCopy;
1819 key = env->GetByteArrayElements(keyObj, &isCopy);
1820 }
1821 }
1822
1823 if (err == OK && ivObj != NULL) {
1824 if (env->GetArrayLength(ivObj) != 16) {
1825 err = -EINVAL;
1826 } else {
1827 jboolean isCopy;
1828 iv = env->GetByteArrayElements(ivObj, &isCopy);
1829 }
1830 }
1831
Andreas Huberbfc56f42012-04-19 12:47:07 -07001832 AString errorDetailMsg;
1833
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001834 if (err == OK) {
1835 err = codec->queueSecureInputBuffer(
1836 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08001837 subSamples, numSubSamples,
1838 (const uint8_t *)key, (const uint8_t *)iv,
1839 mode,
1840 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001841 timestampUs,
1842 flags,
1843 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001844 }
1845
Wonsik Kim1cac4252020-01-24 11:45:37 -08001846 if (iv != NULL) {
1847 env->ReleaseByteArrayElements(ivObj, iv, 0);
1848 iv = NULL;
1849 }
1850
1851 if (key != NULL) {
1852 env->ReleaseByteArrayElements(keyObj, key, 0);
1853 key = NULL;
1854 }
1855
1856 delete[] subSamples;
1857 subSamples = NULL;
1858
Andreas Huberbfc56f42012-04-19 12:47:07 -07001859 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001860 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001861}
1862
Wonsik Kim637afb22020-02-25 14:27:29 -08001863static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jobject bufferObj) {
1864 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
1865 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
1866 env, bufferObj);
1867 AHardwareBuffer_Desc desc;
1868 AHardwareBuffer_describe(hardwareBuffer, &desc);
1869 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
1870 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
1871 return nullptr;
1872 }
1873 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
1874 ALOGI("mapHardwareBuffer: buffer not CPU readable");
1875 return nullptr;
1876 }
1877 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
1878
1879 uint64_t cpuUsage = desc.usage;
1880 cpuUsage = (cpuUsage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
1881 cpuUsage = (cpuUsage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
1882
1883 AHardwareBuffer_Planes planes;
1884 int err = AHardwareBuffer_lockPlanes(
1885 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
1886 if (err != 0) {
1887 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
1888 return nullptr;
1889 }
1890
1891 if (planes.planeCount != 3) {
1892 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
1893 return nullptr;
1894 }
1895
1896 ScopedLocalRef<jclass> planeClazz(
1897 env, env->FindClass("android/media/MediaCodec$MediaImage$MediaPlane"));
1898 ScopedLocalRef<jobjectArray> planeArray{
1899 env, env->NewObjectArray(3, planeClazz.get(), NULL)};
1900 CHECK(planeClazz.get() != NULL);
1901 jmethodID planeConstructID = env->GetMethodID(planeClazz.get(), "<init>",
1902 "([Ljava/nio/ByteBuffer;IIIII)V");
1903
1904 // plane indices are Y-U-V.
1905 for (uint32_t i = 0; i < 3; ++i) {
1906 const AHardwareBuffer_Plane &plane = planes.planes[i];
1907 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
1908 env,
1909 plane.data,
1910 plane.rowStride * (desc.height - 1) + plane.pixelStride * (desc.width - 1) + 1,
1911 0,
1912 plane.rowStride * (desc.height - 1) + plane.pixelStride * (desc.width - 1) + 1,
1913 readOnly,
1914 true)};
1915
1916 ScopedLocalRef<jobject> planeObj{env, env->NewObject(
1917 planeClazz.get(), planeConstructID,
1918 byteBuffer.get(), plane.rowStride, plane.pixelStride)};
1919
1920 env->SetObjectArrayElement(planeArray.get(), i, planeObj.get());
1921 }
1922
1923 ScopedLocalRef<jclass> imageClazz(
1924 env, env->FindClass("android/media/MediaCodec$MediaImage"));
1925 CHECK(imageClazz.get() != NULL);
1926
1927 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
1928 "([Landroid/media/Image$Plane;IIIZJIILandroid/graphics/Rect;J)V");
1929
1930 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
1931 planeArray.get(),
1932 desc.width,
1933 desc.height,
1934 desc.format, // ???
1935 (jboolean)readOnly /* readOnly */,
1936 (jlong)0 /* timestamp */,
1937 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
1938 (jlong)hardwareBuffer);
1939
1940 // if MediaImage creation fails, return null
1941 if (env->ExceptionCheck()) {
1942 env->ExceptionDescribe();
1943 env->ExceptionClear();
1944 return nullptr;
1945 }
1946
1947 AHardwareBuffer_acquire(hardwareBuffer);
1948
1949 return img;
1950}
1951
1952static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jlong context) {
1953 if (context == 0) {
1954 return;
1955 }
1956 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
1957
1958 int32_t fenceFd = -1;
1959 int err = AHardwareBuffer_unlock(hardwareBuffer, &fenceFd);
1960 if (err == 0) {
1961 sp<Fence> fence{new Fence(fenceFd)};
1962 } else {
1963 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
1964 // Continue to release the hardwareBuffer
1965 }
1966
1967 AHardwareBuffer_release(hardwareBuffer);
1968}
1969
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001970static status_t ConvertKeyValueListsToAMessage(
1971 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
1972 static struct Fields {
1973 explicit Fields(JNIEnv *env) {
1974 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
1975 CHECK(clazz.get() != NULL);
1976 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
1977
1978 clazz.reset(env->FindClass("java/lang/Integer"));
1979 CHECK(clazz.get() != NULL);
1980 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
1981
1982 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
1983 CHECK(mIntegerValueId != NULL);
1984
1985 clazz.reset(env->FindClass("java/lang/Long"));
1986 CHECK(clazz.get() != NULL);
1987 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
1988
1989 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
1990 CHECK(mLongValueId != NULL);
1991
1992 clazz.reset(env->FindClass("java/lang/Float"));
1993 CHECK(clazz.get() != NULL);
1994 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
1995
1996 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
1997 CHECK(mFloatValueId != NULL);
1998
1999 clazz.reset(env->FindClass("java/util/ArrayList"));
2000 CHECK(clazz.get() != NULL);
2001
2002 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2003 CHECK(mByteBufferArrayId != NULL);
2004 }
2005
2006 jclass mStringClass;
2007 jclass mIntegerClass;
2008 jmethodID mIntegerValueId;
2009 jclass mLongClass;
2010 jmethodID mLongValueId;
2011 jclass mFloatClass;
2012 jmethodID mFloatValueId;
2013 jmethodID mByteBufferArrayId;
2014 } sFields{env};
2015
2016 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2017 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2018 return BAD_VALUE;
2019 }
2020
2021 sp<AMessage> result{new AMessage};
2022 for (jint i = 0; i < size; ++i) {
2023 ScopedLocalRef<jstring> jkey{
2024 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2025 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2026 AString key;
2027 if (tmp) {
2028 key.setTo(tmp);
2029 }
2030 env->ReleaseStringUTFChars(jkey.get(), tmp);
2031 if (key.empty()) {
2032 return NO_MEMORY;
2033 }
2034
2035 ScopedLocalRef<jobject> jvalue{
2036 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2037
2038 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2039 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2040 AString value;
2041 if (tmp) {
2042 value.setTo(tmp);
2043 }
2044 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
2045 if (value.empty()) {
2046 return NO_MEMORY;
2047 }
2048 result->setString(key.c_str(), value);
2049 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2050 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2051 result->setInt32(key.c_str(), value);
2052 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2053 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2054 result->setInt64(key.c_str(), value);
2055 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2056 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2057 result->setFloat(key.c_str(), value);
2058 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
2059 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.positionId);
2060 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.limitId);
2061 sp<ABuffer> buffer{new ABuffer(limit - position)};
2062 void *data = env->GetDirectBufferAddress(jvalue.get());
2063 if (data != nullptr) {
2064 memcpy(buffer->data(),
2065 static_cast<const uint8_t *>(data) + position,
2066 buffer->size());
2067 } else {
2068 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2069 jvalue.get(), sFields.mByteBufferArrayId)};
2070 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2071 reinterpret_cast<jbyte *>(buffer->data()));
2072 }
2073 result->setBuffer(key.c_str(), buffer);
2074 }
2075 }
2076
2077 *msg = result;
2078 return OK;
2079}
2080
2081static void android_media_MediaCodec_native_queueLinearBlock(
2082 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2083 jint offset, jint size, jobject cryptoInfoObj,
2084 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2085 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2086
2087 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2088
2089 if (codec == nullptr) {
2090 throwExceptionAsNecessary(env, INVALID_OPERATION);
2091 return;
2092 }
2093
2094 sp<AMessage> tunings;
2095 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2096 if (err != OK) {
2097 throwExceptionAsNecessary(env, err);
2098 return;
2099 }
2100
2101 std::shared_ptr<C2Buffer> buffer;
2102 sp<hardware::HidlMemory> memory;
2103 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2104 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2105 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2106 JMediaCodecLinearBlock *context =
2107 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
2108 if (cryptoInfoObj != nullptr) {
2109 memory = context->toHidlMemory();
2110 } else {
2111 buffer = context->toC2Buffer(offset, size);
2112 }
2113 }
2114 env->MonitorExit(lock.get());
2115 } else {
2116 throwExceptionAsNecessary(env, INVALID_OPERATION);
2117 return;
2118 }
2119
2120 AString errorDetailMsg;
2121 if (cryptoInfoObj != nullptr) {
2122 if (!memory) {
2123 throwExceptionAsNecessary(env, BAD_VALUE);
2124 return;
2125 }
2126
2127 NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002128 err = codec->queueEncryptedLinearBlock(
2129 index,
2130 memory,
2131 offset,
2132 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2133 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2134 cryptoInfo.mMode,
2135 cryptoInfo.mPattern,
2136 presentationTimeUs,
2137 flags,
2138 tunings,
2139 &errorDetailMsg);
2140 } else {
2141 if (!buffer) {
2142 throwExceptionAsNecessary(env, BAD_VALUE);
2143 return;
2144 }
2145 err = codec->queueBuffer(
2146 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2147 }
2148 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2149}
2150
Wonsik Kim637afb22020-02-25 14:27:29 -08002151static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002152 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2153 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002154 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002155
2156 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2157
2158 if (codec == NULL) {
2159 throwExceptionAsNecessary(env, INVALID_OPERATION);
2160 return;
2161 }
2162
2163 sp<AMessage> tunings;
2164 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2165 if (err != OK) {
2166 throwExceptionAsNecessary(env, err);
2167 return;
2168 }
2169
Wonsik Kim637afb22020-02-25 14:27:29 -08002170 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2171 env, bufferObj);
2172 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2173 C2Handle *handle = WrapNativeCodec2GrallocHandle(
2174 graphicBuffer->handle, graphicBuffer->format,
2175 graphicBuffer->width, graphicBuffer->height,
2176 graphicBuffer->usage, graphicBuffer->stride);
2177 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(handle);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002178
Wonsik Kim637afb22020-02-25 14:27:29 -08002179 if (!block) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002180 throwExceptionAsNecessary(env, BAD_VALUE);
2181 return;
2182 }
Wonsik Kim637afb22020-02-25 14:27:29 -08002183 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2184 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002185 AString errorDetailMsg;
2186 err = codec->queueBuffer(index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2187 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2188}
2189
2190static void android_media_MediaCodec_native_getOutputFrame(
2191 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2192 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2193
2194 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2195
2196 if (codec == NULL) {
2197 throwExceptionAsNecessary(env, INVALID_OPERATION);
2198 return;
2199 }
2200
2201 status_t err = codec->getOutputFrame(env, frame, index);
2202 if (err != OK) {
2203 throwExceptionAsNecessary(env, err);
2204 }
2205}
2206
Andreas Huber88572f72012-02-21 11:47:18 -08002207static jint android_media_MediaCodec_dequeueInputBuffer(
2208 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2209 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2210
2211 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2212
2213 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002214 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002215 return -1;
2216 }
2217
2218 size_t index;
2219 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2220
2221 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002222 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002223 }
2224
2225 return throwExceptionAsNecessary(env, err);
2226}
2227
2228static jint android_media_MediaCodec_dequeueOutputBuffer(
2229 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2230 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2231
2232 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2233
2234 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002235 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002236 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002237 }
2238
2239 size_t index;
2240 status_t err = codec->dequeueOutputBuffer(
2241 env, bufferInfo, &index, timeoutUs);
2242
2243 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002244 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002245 }
2246
2247 return throwExceptionAsNecessary(env, err);
2248}
2249
2250static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002251 JNIEnv *env, jobject thiz,
2252 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002253 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2254
2255 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2256
2257 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002258 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002259 return;
2260 }
2261
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002262 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002263
2264 throwExceptionAsNecessary(env, err);
2265}
2266
Andy McFadden2621e402013-02-19 07:29:21 -08002267static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2268 jobject thiz) {
2269 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2270
2271 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2272 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002273 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08002274 return;
2275 }
2276
2277 status_t err = codec->signalEndOfInputStream();
2278
2279 throwExceptionAsNecessary(env, err);
2280}
2281
Lajos Molnard4023112014-07-11 15:12:59 -07002282static jobject android_media_MediaCodec_getFormatNative(
2283 JNIEnv *env, jobject thiz, jboolean input) {
2284 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002285
2286 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2287
2288 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002289 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002290 return NULL;
2291 }
2292
2293 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002294 status_t err = codec->getFormat(env, input, &format);
2295
2296 if (err == OK) {
2297 return format;
2298 }
2299
2300 throwExceptionAsNecessary(env, err);
2301
2302 return NULL;
2303}
2304
2305static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2306 JNIEnv *env, jobject thiz, jint index) {
2307 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2308
2309 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2310
2311 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002312 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002313 return NULL;
2314 }
2315
2316 jobject format;
2317 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002318
2319 if (err == OK) {
2320 return format;
2321 }
2322
2323 throwExceptionAsNecessary(env, err);
2324
2325 return NULL;
2326}
2327
2328static jobjectArray android_media_MediaCodec_getBuffers(
2329 JNIEnv *env, jobject thiz, jboolean input) {
2330 ALOGV("android_media_MediaCodec_getBuffers");
2331
2332 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2333
2334 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002335 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002336 return NULL;
2337 }
2338
2339 jobjectArray buffers;
2340 status_t err = codec->getBuffers(env, input, &buffers);
2341
2342 if (err == OK) {
2343 return buffers;
2344 }
2345
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002346 // if we're out of memory, an exception was already thrown
2347 if (err != NO_MEMORY) {
2348 throwExceptionAsNecessary(env, err);
2349 }
Andreas Huber88572f72012-02-21 11:47:18 -08002350
2351 return NULL;
2352}
2353
Lajos Molnard4023112014-07-11 15:12:59 -07002354static jobject android_media_MediaCodec_getBuffer(
2355 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2356 ALOGV("android_media_MediaCodec_getBuffer");
2357
2358 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2359
2360 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002361 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002362 return NULL;
2363 }
2364
2365 jobject buffer;
2366 status_t err = codec->getBuffer(env, input, index, &buffer);
2367
2368 if (err == OK) {
2369 return buffer;
2370 }
2371
2372 // if we're out of memory, an exception was already thrown
2373 if (err != NO_MEMORY) {
2374 throwExceptionAsNecessary(env, err);
2375 }
2376
2377 return NULL;
2378}
2379
2380static jobject android_media_MediaCodec_getImage(
2381 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2382 ALOGV("android_media_MediaCodec_getImage");
2383
2384 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2385
2386 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002387 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002388 return NULL;
2389 }
2390
2391 jobject image;
2392 status_t err = codec->getImage(env, input, index, &image);
2393
2394 if (err == OK) {
2395 return image;
2396 }
2397
2398 // if we're out of memory, an exception was already thrown
2399 if (err != NO_MEMORY) {
2400 throwExceptionAsNecessary(env, err);
2401 }
2402
2403 return NULL;
2404}
2405
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002406static jobject android_media_MediaCodec_getName(
2407 JNIEnv *env, jobject thiz) {
2408 ALOGV("android_media_MediaCodec_getName");
2409
2410 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2411
2412 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002413 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002414 return NULL;
2415 }
2416
2417 jstring name;
2418 status_t err = codec->getName(env, &name);
2419
2420 if (err == OK) {
2421 return name;
2422 }
2423
2424 throwExceptionAsNecessary(env, err);
2425
2426 return NULL;
2427}
2428
Chong Zhanga0b72a62018-02-28 18:46:26 -08002429static jobject android_media_MediaCodec_getOwnCodecInfo(
2430 JNIEnv *env, jobject thiz) {
2431 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2432
2433 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2434
2435 if (codec == NULL) {
2436 throwExceptionAsNecessary(env, INVALID_OPERATION);
2437 return NULL;
2438 }
2439
2440 jobject codecInfoObj;
2441 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2442
2443 if (err == OK) {
2444 return codecInfoObj;
2445 }
2446
2447 throwExceptionAsNecessary(env, err);
2448
2449 return NULL;
2450}
2451
Ray Essick0e0fee12017-01-25 18:01:56 -08002452static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002453android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002454{
Ray Essickf2d0e402017-03-09 10:17:51 -08002455 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002456
2457 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2458 if (codec == NULL ) {
2459 jniThrowException(env, "java/lang/IllegalStateException", NULL);
2460 return 0;
2461 }
2462
2463 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002464 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002465
2466 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002467 if (err != OK) {
2468 ALOGE("getMetrics failed");
2469 return (jobject) NULL;
2470 }
2471
Ray Essick0e0fee12017-01-25 18:01:56 -08002472 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2473
2474 // housekeeping
2475 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002476 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002477
2478 return mybundle;
2479}
2480
Andreas Huber226065b2013-08-12 10:14:11 -07002481static void android_media_MediaCodec_setParameters(
2482 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2483 ALOGV("android_media_MediaCodec_setParameters");
2484
2485 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2486
2487 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002488 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07002489 return;
2490 }
2491
2492 sp<AMessage> params;
2493 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2494
2495 if (err == OK) {
2496 err = codec->setParameters(params);
2497 }
2498
2499 throwExceptionAsNecessary(env, err);
2500}
2501
Andreas Huberb12a5392012-04-30 14:18:33 -07002502static void android_media_MediaCodec_setVideoScalingMode(
2503 JNIEnv *env, jobject thiz, jint mode) {
2504 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2505
2506 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002507 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07002508 return;
2509 }
2510
2511 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2512 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07002513 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07002514 return;
2515 }
2516
2517 codec->setVideoScalingMode(mode);
2518}
2519
ybai5e053202018-11-01 13:02:15 +08002520static void android_media_MediaCodec_setAudioPresentation(
2521 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2522 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2523
2524 if (codec == NULL) {
2525 throwExceptionAsNecessary(env, INVALID_OPERATION);
2526 return;
2527 }
2528
2529 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2530}
2531
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07002532static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002533 ScopedLocalRef<jclass> clazz(
2534 env, env->FindClass("android/media/MediaCodec"));
2535 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002536
Andreas Huberaba67132013-10-22 12:40:01 -07002537 gFields.postEventFromNativeID =
2538 env->GetMethodID(
2539 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07002540 CHECK(gFields.postEventFromNativeID != NULL);
2541
Wonsik Kim61796fd2018-09-13 13:15:59 -07002542 gFields.lockAndGetContextID =
2543 env->GetMethodID(
2544 clazz.get(), "lockAndGetContext", "()J");
2545 CHECK(gFields.lockAndGetContextID != NULL);
2546
2547 gFields.setAndUnlockContextID =
2548 env->GetMethodID(
2549 clazz.get(), "setAndUnlockContext", "(J)V");
2550 CHECK(gFields.setAndUnlockContextID != NULL);
2551
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002552 jfieldID field;
2553 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
2554 CHECK(field != NULL);
2555 gCryptoModes.Unencrypted =
2556 env->GetStaticIntField(clazz.get(), field);
2557
2558 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
2559 CHECK(field != NULL);
2560 gCryptoModes.AesCtr =
2561 env->GetStaticIntField(clazz.get(), field);
2562
2563 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
2564 CHECK(field != NULL);
2565 gCryptoModes.AesCbc =
2566 env->GetStaticIntField(clazz.get(), field);
2567
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002568 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
2569 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07002570
2571 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002572 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002573 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
2574
2575 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002576 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002577 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
2578
2579 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002580 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002581 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
2582
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002583 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002584 CHECK(gFields.cryptoInfoKeyID != NULL);
2585
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002586 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002587 CHECK(gFields.cryptoInfoIVID != NULL);
2588
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002589 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002590 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002591
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002592 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
2593 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
2594 CHECK(gFields.cryptoInfoPatternID != NULL);
2595
2596 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
2597 CHECK(clazz.get() != NULL);
2598
2599 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
2600 CHECK(gFields.patternEncryptBlocksID != NULL);
2601
2602 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
2603 CHECK(gFields.patternSkipBlocksID != NULL);
2604
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002605 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
2606 CHECK(clazz.get() != NULL);
2607
2608 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
2609 CHECK(gFields.queueRequestIndexID != NULL);
2610
2611 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
2612 CHECK(clazz.get() != NULL);
2613
2614 gFields.outputFrameLinearBlockID =
2615 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
2616 CHECK(gFields.outputFrameLinearBlockID != NULL);
2617
Wonsik Kim637afb22020-02-25 14:27:29 -08002618 gFields.outputFrameHardwareBufferID =
2619 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
2620 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002621
2622 gFields.outputFrameChangedKeysID =
2623 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
2624 CHECK(gFields.outputFrameChangedKeysID != NULL);
2625
2626 gFields.outputFrameFormatID =
2627 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
2628 CHECK(gFields.outputFrameFormatID != NULL);
2629
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002630 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
2631 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002632
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002633 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002634 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002635 gCryptoErrorCodes.cryptoErrorNoKey =
2636 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002637
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002638 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002639 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002640 gCryptoErrorCodes.cryptoErrorKeyExpired =
2641 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002642
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002643 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002644 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002645 gCryptoErrorCodes.cryptoErrorResourceBusy =
2646 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002647
Jeff Tinker336d3ea2014-08-28 17:57:36 -07002648 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
2649 CHECK(field != NULL);
2650 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
2651 env->GetStaticIntField(clazz.get(), field);
2652
Jeff Tinker96a2a952015-07-01 17:35:18 -07002653 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
2654 CHECK(field != NULL);
2655 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
2656 env->GetStaticIntField(clazz.get(), field);
2657
Jeff Tinker20594d82018-12-12 08:31:22 -08002658 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
2659 CHECK(field != NULL);
2660 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
2661 env->GetStaticIntField(clazz.get(), field);
2662
Jeff Tinkerd3932162016-03-05 11:35:20 -08002663 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
2664 CHECK(field != NULL);
2665 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
2666 env->GetStaticIntField(clazz.get(), field);
2667
Jeff Tinker20594d82018-12-12 08:31:22 -08002668 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
2669 CHECK(field != NULL);
2670 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
2671 env->GetStaticIntField(clazz.get(), field);
2672
2673 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
2674 CHECK(field != NULL);
2675 gCryptoErrorCodes.cryptoErrorLostState =
2676 env->GetStaticIntField(clazz.get(), field);
2677
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002678 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
2679 CHECK(clazz.get() != NULL);
2680 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
2681 CHECK(field != NULL);
2682 gCodecActionCodes.codecActionTransient =
2683 env->GetStaticIntField(clazz.get(), field);
2684
2685 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
2686 CHECK(field != NULL);
2687 gCodecActionCodes.codecActionRecoverable =
2688 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002689
Ronghua Wuc53ad692015-05-08 14:40:49 -07002690 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002691 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002692 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002693 env->GetStaticIntField(clazz.get(), field);
2694
Ronghua Wuc53ad692015-05-08 14:40:49 -07002695 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002696 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002697 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002698 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07002699
2700 clazz.reset(env->FindClass("android/view/Surface"));
2701 CHECK(clazz.get() != NULL);
2702
2703 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2704 CHECK(field != NULL);
2705 gPersistentSurfaceClassInfo.mLock = field;
2706
2707 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
2708 CHECK(method != NULL);
2709 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2710
2711 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2712 CHECK(clazz.get() != NULL);
2713 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2714
2715 method = env->GetMethodID(clazz.get(), "<init>", "()V");
2716 CHECK(method != NULL);
2717 gPersistentSurfaceClassInfo.ctor = method;
2718
2719 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2720 CHECK(field != NULL);
2721 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08002722
2723 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2724 CHECK(clazz.get() != NULL);
2725 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2726
2727 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08002728 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08002729 "Ljava/util/Map;Ljava/util/Map;)V");
2730 CHECK(method != NULL);
2731 gCodecInfo.capsCtorId = method;
2732
2733 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2734 CHECK(clazz.get() != NULL);
2735 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2736
2737 field = env->GetFieldID(clazz.get(), "profile", "I");
2738 CHECK(field != NULL);
2739 gCodecInfo.profileField = field;
2740
2741 field = env->GetFieldID(clazz.get(), "level", "I");
2742 CHECK(field != NULL);
2743 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002744
2745 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
2746 CHECK(clazz.get() != NULL);
2747 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2748
2749 ScopedLocalRef<jclass> byteOrderClass(
2750 env, env->FindClass("java/nio/ByteOrder"));
2751 CHECK(byteOrderClass.get() != NULL);
2752
2753 jmethodID nativeOrderID = env->GetStaticMethodID(
2754 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
2755 CHECK(nativeOrderID != NULL);
2756
2757 ScopedLocalRef<jobject> nativeByteOrderObj{
2758 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
2759 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
2760 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
2761 nativeByteOrderObj.reset();
2762
2763 gByteBufferInfo.orderId = env->GetMethodID(
2764 clazz.get(),
2765 "order",
2766 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
2767 CHECK(gByteBufferInfo.orderId != NULL);
2768
2769 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
2770 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
2771 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
2772
2773 gByteBufferInfo.positionId = env->GetMethodID(
2774 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
2775 CHECK(gByteBufferInfo.positionId != NULL);
2776
2777 gByteBufferInfo.limitId = env->GetMethodID(
2778 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
2779 CHECK(gByteBufferInfo.limitId != NULL);
2780
2781 clazz.reset(env->FindClass("java/util/ArrayList"));
2782 CHECK(clazz.get() != NULL);
2783
2784 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
2785 CHECK(gArrayListInfo.sizeId != NULL);
2786
2787 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
2788 CHECK(gArrayListInfo.getId != NULL);
2789
2790 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
2791 CHECK(gArrayListInfo.addId != NULL);
2792
2793 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
2794 CHECK(clazz.get() != NULL);
2795
2796 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2797
2798 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
2799 CHECK(gLinearBlockInfo.ctorId != NULL);
2800
2801 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
2802 clazz.get(), "setInternalStateLocked", "(JZ)V");
2803 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
2804
2805 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
2806 CHECK(gLinearBlockInfo.contextId != NULL);
2807
2808 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
2809 CHECK(gLinearBlockInfo.validId != NULL);
2810
2811 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2812 CHECK(gLinearBlockInfo.lockId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002813}
2814
2815static void android_media_MediaCodec_native_setup(
2816 JNIEnv *env, jobject thiz,
2817 jstring name, jboolean nameIsType, jboolean encoder) {
2818 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002819 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002820 return;
2821 }
2822
2823 const char *tmp = env->GetStringUTFChars(name, NULL);
2824
2825 if (tmp == NULL) {
2826 return;
2827 }
2828
2829 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2830
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002831 const status_t err = codec->initCheck();
2832 if (err == NAME_NOT_FOUND) {
2833 // fail and do not try again.
2834 jniThrowException(env, "java/lang/IllegalArgumentException",
2835 String8::format("Failed to initialize %s, error %#x", tmp, err));
2836 env->ReleaseStringUTFChars(name, tmp);
2837 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07002838 } if (err == NO_MEMORY) {
2839 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2840 String8::format("Failed to initialize %s, error %#x", tmp, err));
2841 env->ReleaseStringUTFChars(name, tmp);
2842 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002843 } else if (err != OK) {
2844 // believed possible to try again
2845 jniThrowException(env, "java/io/IOException",
2846 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2847 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08002848 return;
2849 }
2850
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002851 env->ReleaseStringUTFChars(name, tmp);
2852
Andreas Huberaba67132013-10-22 12:40:01 -07002853 codec->registerSelf();
2854
Andreas Huber88572f72012-02-21 11:47:18 -08002855 setMediaCodec(env,thiz, codec);
2856}
2857
2858static void android_media_MediaCodec_native_finalize(
2859 JNIEnv *env, jobject thiz) {
Lajos Molnar5b610e22020-03-09 21:22:44 +00002860 android_media_MediaCodec_release(env, thiz);
Andreas Huber88572f72012-02-21 11:47:18 -08002861}
2862
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002863// MediaCodec.LinearBlock
2864
2865static jobject android_media_MediaCodec_LinearBlock_native_map(
2866 JNIEnv *env, jobject thiz) {
2867 JMediaCodecLinearBlock *context =
2868 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2869 if (context->mBuffer) {
2870 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
2871 if (!context->mReadonlyMapping) {
2872 const C2BufferData data = buffer->data();
2873 if (data.type() != C2BufferData::LINEAR) {
2874 throwExceptionAsNecessary(env, INVALID_OPERATION);
2875 return nullptr;
2876 }
2877 if (data.linearBlocks().size() != 1u) {
2878 throwExceptionAsNecessary(env, INVALID_OPERATION);
2879 return nullptr;
2880 }
2881 C2ConstLinearBlock block = data.linearBlocks().front();
2882 context->mReadonlyMapping =
2883 std::make_shared<C2ReadView>(block.map().get());
2884 }
2885 return CreateByteBuffer(
2886 env,
2887 context->mReadonlyMapping->data(), // base
2888 context->mReadonlyMapping->capacity(), // capacity
2889 0u, // offset
2890 context->mReadonlyMapping->capacity(), // size
2891 true, // readOnly
2892 true /* clearBuffer */);
2893 } else if (context->mBlock) {
2894 std::shared_ptr<C2LinearBlock> block = context->mBlock;
2895 if (!context->mReadWriteMapping) {
2896 context->mReadWriteMapping =
2897 std::make_shared<C2WriteView>(block->map().get());
2898 }
2899 return CreateByteBuffer(
2900 env,
2901 context->mReadWriteMapping->base(),
2902 context->mReadWriteMapping->capacity(),
2903 context->mReadWriteMapping->offset(),
2904 context->mReadWriteMapping->size(),
2905 false, // readOnly
2906 true /* clearBuffer */);
2907 } else if (context->mLegacyBuffer) {
2908 return CreateByteBuffer(
2909 env,
2910 context->mLegacyBuffer->base(),
2911 context->mLegacyBuffer->capacity(),
2912 context->mLegacyBuffer->offset(),
2913 context->mLegacyBuffer->size(),
2914 true, // readOnly
2915 true /* clearBuffer */);
2916 } else if (context->mHeap) {
2917 return CreateByteBuffer(
2918 env,
2919 static_cast<uint8_t *>(context->mHeap->getBase()) + context->mHeap->getOffset(),
2920 context->mHeap->getSize(),
2921 0,
2922 context->mHeap->getSize(),
2923 false, // readOnly
2924 true /* clearBuffer */);
2925 }
2926 throwExceptionAsNecessary(env, INVALID_OPERATION);
2927 return nullptr;
2928}
2929
2930static void android_media_MediaCodec_LinearBlock_native_recycle(
2931 JNIEnv *env, jobject thiz) {
2932 JMediaCodecLinearBlock *context =
2933 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2934 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, 0, false);
2935 delete context;
2936}
2937
2938static void PopulateNamesVector(
2939 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
2940 jsize length = env->GetArrayLength(codecNames);
2941 for (jsize i = 0; i < length; ++i) {
2942 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
2943 if (jstr == nullptr) {
2944 // null entries are ignored
2945 continue;
2946 }
2947 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
2948 if (cstr == nullptr) {
2949 throwExceptionAsNecessary(env, BAD_VALUE);
2950 return;
2951 }
2952 names->emplace_back(cstr);
2953 env->ReleaseStringUTFChars(jstr, cstr);
2954 }
2955}
2956
2957static void android_media_MediaCodec_LinearBlock_native_obtain(
2958 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
2959 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
2960 std::vector<std::string> names;
2961 PopulateNamesVector(env, codecNames, &names);
2962 bool hasSecure = false;
2963 bool hasNonSecure = false;
2964 for (const std::string &name : names) {
2965 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
2966 hasSecure = true;
2967 } else {
2968 hasNonSecure = true;
2969 }
2970 }
2971 if (hasSecure && !hasNonSecure) {
2972 context->mHeap = new MemoryHeapBase(capacity);
2973 context->mMemory = hardware::fromHeap(context->mHeap);
2974 } else {
2975 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
2976 if (!context->mBlock) {
2977 jniThrowException(env, "java/io/IOException", nullptr);
2978 return;
2979 }
2980 }
2981 env->CallVoidMethod(
2982 thiz,
2983 gLinearBlockInfo.setInternalStateId,
2984 (jlong)context.release(),
2985 true /* isMappable */);
2986}
2987
2988static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07002989 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002990 std::vector<std::string> names;
2991 PopulateNamesVector(env, codecNames, &names);
2992 bool isCompatible = false;
2993 bool hasSecure = false;
2994 bool hasNonSecure = false;
2995 for (const std::string &name : names) {
2996 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
2997 hasSecure = true;
2998 } else {
2999 hasNonSecure = true;
3000 }
3001 }
3002 if (hasSecure && hasNonSecure) {
3003 return false;
3004 }
3005 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3006 if (err != OK) {
3007 throwExceptionAsNecessary(env, err);
3008 }
3009 return isCompatible;
3010}
3011
Daniel Micay76f6a862015-09-19 17:31:01 -04003012static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003013 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003014
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003015 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3016
Chong Zhang8034d602015-04-28 13:38:48 -07003017 { "native_releasePersistentInputSurface",
3018 "(Landroid/view/Surface;)V",
3019 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3020
3021 { "native_createPersistentInputSurface",
3022 "()Landroid/media/MediaCodec$PersistentSurface;",
3023 (void *)android_media_MediaCodec_createPersistentInputSurface },
3024
Chong Zhang9560ddb2015-05-13 10:25:29 -07003025 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3026 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003027
Lajos Molnard8578572015-06-05 20:17:33 -07003028 { "native_enableOnFrameRenderedListener", "(Z)V",
3029 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3030
Chong Zhang8d5e5562014-07-08 18:49:21 -07003031 { "native_setCallback",
3032 "(Landroid/media/MediaCodec$Callback;)V",
3033 (void *)android_media_MediaCodec_native_setCallback },
3034
Andreas Huber88572f72012-02-21 11:47:18 -08003035 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003036 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003037 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003038 (void *)android_media_MediaCodec_native_configure },
3039
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003040 { "native_setSurface",
3041 "(Landroid/view/Surface;)V",
3042 (void *)android_media_MediaCodec_native_setSurface },
3043
Andy McFadden2621e402013-02-19 07:29:21 -08003044 { "createInputSurface", "()Landroid/view/Surface;",
3045 (void *)android_media_MediaCodec_createInputSurface },
3046
Lajos Molnard4023112014-07-11 15:12:59 -07003047 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003048 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003049 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003050
Lajos Molnard4023112014-07-11 15:12:59 -07003051 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003052 (void *)android_media_MediaCodec_queueInputBuffer },
3053
Lajos Molnard4023112014-07-11 15:12:59 -07003054 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003055 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3056
Wonsik Kim637afb22020-02-25 14:27:29 -08003057 { "native_mapHardwareBuffer",
3058 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3059 (void *)android_media_MediaCodec_mapHardwareBuffer },
3060
3061 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3062
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003063 { "native_queueLinearBlock",
3064 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3065 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3066 (void *)android_media_MediaCodec_native_queueLinearBlock },
3067
Wonsik Kim637afb22020-02-25 14:27:29 -08003068 { "native_queueHardwareBuffer",
3069 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3070 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003071
3072 { "native_getOutputFrame",
3073 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3074 (void *)android_media_MediaCodec_native_getOutputFrame },
3075
Lajos Molnard4023112014-07-11 15:12:59 -07003076 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003077 (void *)android_media_MediaCodec_dequeueInputBuffer },
3078
Lajos Molnard4023112014-07-11 15:12:59 -07003079 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003080 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3081
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003082 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003083 (void *)android_media_MediaCodec_releaseOutputBuffer },
3084
Andy McFadden2621e402013-02-19 07:29:21 -08003085 { "signalEndOfInputStream", "()V",
3086 (void *)android_media_MediaCodec_signalEndOfInputStream },
3087
Lajos Molnard4023112014-07-11 15:12:59 -07003088 { "getFormatNative", "(Z)Ljava/util/Map;",
3089 (void *)android_media_MediaCodec_getFormatNative },
3090
3091 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3092 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003093
3094 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3095 (void *)android_media_MediaCodec_getBuffers },
3096
Lajos Molnard4023112014-07-11 15:12:59 -07003097 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3098 (void *)android_media_MediaCodec_getBuffer },
3099
3100 { "getImage", "(ZI)Landroid/media/Image;",
3101 (void *)android_media_MediaCodec_getImage },
3102
Lajos Molnard2a7f472018-11-15 12:49:20 -08003103 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003104 (void *)android_media_MediaCodec_getName },
3105
Chong Zhanga0b72a62018-02-28 18:46:26 -08003106 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3107 (void *)android_media_MediaCodec_getOwnCodecInfo },
3108
Ray Essick10353e32017-04-14 10:22:55 -07003109 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003110 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003111
Andreas Huber226065b2013-08-12 10:14:11 -07003112 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3113 (void *)android_media_MediaCodec_setParameters },
3114
Andreas Huberb12a5392012-04-30 14:18:33 -07003115 { "setVideoScalingMode", "(I)V",
3116 (void *)android_media_MediaCodec_setVideoScalingMode },
3117
ybai5e053202018-11-01 13:02:15 +08003118 { "native_setAudioPresentation", "(II)V",
3119 (void *)android_media_MediaCodec_setAudioPresentation },
3120
Andreas Huber88572f72012-02-21 11:47:18 -08003121 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3122
3123 { "native_setup", "(Ljava/lang/String;ZZ)V",
3124 (void *)android_media_MediaCodec_native_setup },
3125
3126 { "native_finalize", "()V",
3127 (void *)android_media_MediaCodec_native_finalize },
3128};
3129
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003130static const JNINativeMethod gLinearBlockMethods[] = {
3131 { "native_map", "()Ljava/nio/ByteBuffer;",
3132 (void *)android_media_MediaCodec_LinearBlock_native_map },
3133
3134 { "native_recycle", "()V",
3135 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3136
3137 { "native_obtain", "(I[Ljava/lang/String;)V",
3138 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3139
3140 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3141 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3142};
3143
Andreas Huber88572f72012-02-21 11:47:18 -08003144int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003145 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003146 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003147 if (result != JNI_OK) {
3148 return result;
3149 }
3150 result = AndroidRuntime::registerNativeMethods(env,
3151 "android/media/MediaCodec$LinearBlock",
3152 gLinearBlockMethods,
3153 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003154 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003155}