blob: 98e68b8b53f268f32376a13526d2e1f8825054bb [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec-JNI"
19#include <utils/Log.h>
20
Wonsik Kimccb7ac62019-12-27 17:12:40 -080021#include <type_traits>
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include "android_media_MediaCodec.h"
24
shubangd49681e2020-02-17 21:32:30 -080025#include "android_media_MediaCodecLinearBlock.h"
Andreas Huber07ea4262012-04-11 12:21:20 -070026#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070027#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080028#include "android_media_MediaMetricsJNI.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090029#include "android_media_Streams.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "android_runtime/AndroidRuntime.h"
31#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080032#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080033#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080035#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080036
Wonsik Kim637afb22020-02-25 14:27:29 -080037#include <C2AllocatorGralloc.h>
38#include <C2BlockInternal.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080039#include <C2Buffer.h>
Wonsik Kimb8ebdb32020-04-21 17:00:13 -070040#include <C2PlatformSupport.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080041
Chong Zhang2659c2f2017-04-27 13:18:20 -070042#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080043
Wonsik Kim637afb22020-02-25 14:27:29 -080044#include <android_runtime/android_hardware_HardwareBuffer.h>
45
Wonsik Kimccb7ac62019-12-27 17:12:40 -080046#include <binder/MemoryHeapBase.h>
47
Lajos Molnar7ac4f562014-03-24 15:57:51 -070048#include <cutils/compiler.h>
49
Mathias Agopian8335f1c2012-02-25 18:48:35 -080050#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080051
Wonsik Kimccb7ac62019-12-27 17:12:40 -080052#include <hidlmemory/FrameworkUtils.h>
53
Wonsik Kim4273dd02016-09-27 15:23:35 +090054#include <media/MediaCodecBuffer.h>
Wonsik Kimccb7ac62019-12-27 17:12:40 -080055#include <media/hardware/VideoAPI.h>
Andreas Huber88572f72012-02-21 11:47:18 -080056#include <media/stagefright/MediaCodec.h>
57#include <media/stagefright/foundation/ABuffer.h>
58#include <media/stagefright/foundation/ADebug.h>
59#include <media/stagefright/foundation/ALooper.h>
60#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070061#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080062#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070063#include <media/stagefright/PersistentSurface.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080064#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070065
Wonsik Kim637afb22020-02-25 14:27:29 -080066#include <private/android/AHardwareBufferHelpers.h>
67
Andreas Huberb12a5392012-04-30 14:18:33 -070068#include <system/window.h>
69
Andreas Huber88572f72012-02-21 11:47:18 -080070namespace android {
71
72// Keep these in sync with their equivalents in MediaCodec.java !!!
73enum {
74 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
75 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
76 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
77};
78
Andreas Huberaba67132013-10-22 12:40:01 -070079enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070080 EVENT_CALLBACK = 1,
81 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070082 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070083};
84
Andy Hung5f9aa0b2014-07-30 15:48:21 -070085static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070086 jint cryptoErrorNoKey;
87 jint cryptoErrorKeyExpired;
88 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070089 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070090 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -080091 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -080092 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -080093 jint cryptoErrorFrameTooLarge;
94 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -070095} gCryptoErrorCodes;
96
Andy Hung5f9aa0b2014-07-30 15:48:21 -070097static struct CodecActionCodes {
98 jint codecActionTransient;
99 jint codecActionRecoverable;
100} gCodecActionCodes;
101
Ronghua Wuc53ad692015-05-08 14:40:49 -0700102static struct CodecErrorCodes {
103 jint errorInsufficientResource;
104 jint errorReclaimed;
105} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -0700106
Chong Zhang8034d602015-04-28 13:38:48 -0700107static struct {
108 jclass clazz;
109 jfieldID mLock;
110 jfieldID mPersistentObject;
111 jmethodID ctor;
112 jmethodID setNativeObjectLocked;
113} gPersistentSurfaceClassInfo;
114
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800115static struct {
116 jint Unencrypted;
117 jint AesCtr;
118 jint AesCbc;
119} gCryptoModes;
120
Chong Zhanga0b72a62018-02-28 18:46:26 -0800121static struct {
122 jclass capsClazz;
123 jmethodID capsCtorId;
124 jclass profileLevelClazz;
125 jfieldID profileField;
126 jfieldID levelField;
127} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800128
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800129static struct {
130 jclass clazz;
131 jobject nativeByteOrder;
132 jmethodID orderId;
133 jmethodID asReadOnlyBufferId;
134 jmethodID positionId;
135 jmethodID limitId;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -0700136 jmethodID getPositionId;
137 jmethodID getLimitId;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800138} gByteBufferInfo;
139
140static struct {
141 jmethodID sizeId;
142 jmethodID getId;
143 jmethodID addId;
144} gArrayListInfo;
145
146static struct {
147 jclass clazz;
148 jmethodID ctorId;
149 jmethodID setInternalStateId;
150 jfieldID contextId;
151 jfieldID validId;
152 jfieldID lockId;
153} gLinearBlockInfo;
154
Andreas Huber88572f72012-02-21 11:47:18 -0800155struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700156 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700157 jmethodID lockAndGetContextID;
158 jmethodID setAndUnlockContextID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700159 jfieldID cryptoInfoNumSubSamplesID;
160 jfieldID cryptoInfoNumBytesOfClearDataID;
161 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
162 jfieldID cryptoInfoKeyID;
163 jfieldID cryptoInfoIVID;
164 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800165 jfieldID cryptoInfoPatternID;
166 jfieldID patternEncryptBlocksID;
167 jfieldID patternSkipBlocksID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800168 jfieldID queueRequestIndexID;
169 jfieldID outputFrameLinearBlockID;
Wonsik Kim637afb22020-02-25 14:27:29 -0800170 jfieldID outputFrameHardwareBufferID;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800171 jfieldID outputFrameChangedKeysID;
172 jfieldID outputFrameFormatID;
Andreas Huber88572f72012-02-21 11:47:18 -0800173};
174
175static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700176static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800177
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800178
Andreas Huber88572f72012-02-21 11:47:18 -0800179////////////////////////////////////////////////////////////////////////////////
180
181JMediaCodec::JMediaCodec(
182 JNIEnv *env, jobject thiz,
183 const char *name, bool nameIsType, bool encoder)
184 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700185 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800186 jclass clazz = env->GetObjectClass(thiz);
187 CHECK(clazz != NULL);
188
189 mClass = (jclass)env->NewGlobalRef(clazz);
190 mObject = env->NewWeakGlobalRef(thiz);
191
192 mLooper = new ALooper;
193 mLooper->setName("MediaCodec_looper");
194
195 mLooper->start(
196 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700197 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700198 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800199
200 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700201 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800202 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
203 mNameAtCreation = "(null)";
204 }
Andreas Huber88572f72012-02-21 11:47:18 -0800205 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700206 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800207 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800208 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700209 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800210}
211
212status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700213 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800214}
215
Andreas Huberaba67132013-10-22 12:40:01 -0700216void JMediaCodec::registerSelf() {
217 mLooper->registerHandler(this);
218}
219
Chong Zhang128b0122014-03-01 18:04:13 -0800220void JMediaCodec::release() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700221 std::call_once(mReleaseFlag, [this] {
222 if (mCodec != NULL) {
223 mCodec->release();
224 mInitStatus = NO_INIT;
225 }
Andreas Huber88572f72012-02-21 11:47:18 -0800226
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700227 if (mLooper != NULL) {
228 mLooper->unregisterHandler(id());
229 mLooper->stop();
230 mLooper.clear();
231 }
232 });
Chong Zhang128b0122014-03-01 18:04:13 -0800233}
234
Wonsik Kim89666622020-04-28 10:43:47 -0700235void JMediaCodec::releaseAsync() {
236 if (mCodec != NULL) {
237 mCodec->releaseAsync();
238 }
239 mInitStatus = NO_INIT;
240}
241
Chong Zhang128b0122014-03-01 18:04:13 -0800242JMediaCodec::~JMediaCodec() {
Wonsik Kimeaed9f52019-06-18 17:25:02 -0700243 if (mLooper != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800244 /* MediaCodec and looper should have been released explicitly already
245 * in setMediaCodec() (see comments in setMediaCodec()).
246 *
247 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
248 * message handler, doing release() there risks deadlock as MediaCodec::
249 * release() post synchronous message to the same looper.
250 *
251 * Print a warning and try to proceed with releasing.
252 */
253 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
254 release();
255 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
256 }
257
Andreas Huber88572f72012-02-21 11:47:18 -0800258 JNIEnv *env = AndroidRuntime::getJNIEnv();
259
260 env->DeleteWeakGlobalRef(mObject);
261 mObject = NULL;
262 env->DeleteGlobalRef(mClass);
263 mClass = NULL;
264}
265
Lajos Molnard8578572015-06-05 20:17:33 -0700266status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
267 if (enable) {
268 if (mOnFrameRenderedNotification == NULL) {
269 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
270 }
271 } else {
272 mOnFrameRenderedNotification.clear();
273 }
274
275 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
276}
277
Chong Zhang8d5e5562014-07-08 18:49:21 -0700278status_t JMediaCodec::setCallback(jobject cb) {
279 if (cb != NULL) {
280 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800281 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700282 }
283 } else {
284 mCallbackNotification.clear();
285 }
286
287 return mCodec->setCallback(mCallbackNotification);
288}
289
Andreas Huber88572f72012-02-21 11:47:18 -0800290status_t JMediaCodec::configure(
291 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800292 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700293 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800294 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800295 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800296 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800297 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700298 mSurfaceTextureClient =
299 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700300 } else {
301 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800302 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700303
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800304 constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
305 AString mime;
306 CHECK(format->findString("mime", &mime));
307 mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
308 && !(flags & CONFIGURE_FLAG_ENCODE);
309
Chong Zhangd5927ae2017-01-03 11:07:18 -0800310 return mCodec->configure(
311 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800312}
313
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700314status_t JMediaCodec::setSurface(
315 const sp<IGraphicBufferProducer> &bufferProducer) {
316 sp<Surface> client;
317 if (bufferProducer != NULL) {
318 client = new Surface(bufferProducer, true /* controlledByApp */);
319 }
320 status_t err = mCodec->setSurface(client);
321 if (err == OK) {
322 mSurfaceTextureClient = client;
323 }
324 return err;
325}
326
Andy McFadden2621e402013-02-19 07:29:21 -0800327status_t JMediaCodec::createInputSurface(
328 sp<IGraphicBufferProducer>* bufferProducer) {
329 return mCodec->createInputSurface(bufferProducer);
330}
331
Chong Zhang9560ddb2015-05-13 10:25:29 -0700332status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700333 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700334 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700335}
336
Andreas Huber88572f72012-02-21 11:47:18 -0800337status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700338 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800339}
340
341status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700342 mSurfaceTextureClient.clear();
343
Chong Zhang8d5e5562014-07-08 18:49:21 -0700344 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800345}
346
347status_t JMediaCodec::flush() {
348 return mCodec->flush();
349}
350
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700351status_t JMediaCodec::reset() {
352 return mCodec->reset();
353}
354
Andreas Huber88572f72012-02-21 11:47:18 -0800355status_t JMediaCodec::queueInputBuffer(
356 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700357 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
358 AString *errorDetailMsg) {
359 return mCodec->queueInputBuffer(
360 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800361}
362
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700363status_t JMediaCodec::queueSecureInputBuffer(
364 size_t index,
365 size_t offset,
366 const CryptoPlugin::SubSample *subSamples,
367 size_t numSubSamples,
368 const uint8_t key[16],
369 const uint8_t iv[16],
370 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800371 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700372 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700373 uint32_t flags,
374 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700375 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800376 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700377 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700378}
379
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800380status_t JMediaCodec::queueBuffer(
381 size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
382 uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
383 return mCodec->queueBuffer(
384 index, buffer, timeUs, flags, tunings, errorDetailMsg);
385}
386
387status_t JMediaCodec::queueEncryptedLinearBlock(
388 size_t index,
389 const sp<hardware::HidlMemory> &buffer,
390 size_t offset,
391 const CryptoPlugin::SubSample *subSamples,
392 size_t numSubSamples,
393 const uint8_t key[16],
394 const uint8_t iv[16],
395 CryptoPlugin::Mode mode,
396 const CryptoPlugin::Pattern &pattern,
397 int64_t presentationTimeUs,
398 uint32_t flags,
399 const sp<AMessage> &tunings,
400 AString *errorDetailMsg) {
401 return mCodec->queueEncryptedBuffer(
402 index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
403 presentationTimeUs, flags, tunings, errorDetailMsg);
404}
405
Andreas Huber88572f72012-02-21 11:47:18 -0800406status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700407 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800408}
409
410status_t JMediaCodec::dequeueOutputBuffer(
411 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
412 size_t size, offset;
413 int64_t timeUs;
414 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700415 status_t err = mCodec->dequeueOutputBuffer(
416 index, &offset, &size, &timeUs, &flags, timeoutUs);
417
Andreas Huberaba67132013-10-22 12:40:01 -0700418 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800419 return err;
420 }
421
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700422 ScopedLocalRef<jclass> clazz(
423 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800424
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700425 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000426 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800427
428 return OK;
429}
430
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700431status_t JMediaCodec::releaseOutputBuffer(
432 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
433 if (updatePTS) {
434 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
435 }
Andreas Huber88572f72012-02-21 11:47:18 -0800436 return render
437 ? mCodec->renderOutputBufferAndRelease(index)
438 : mCodec->releaseOutputBuffer(index);
439}
440
Andy McFadden2621e402013-02-19 07:29:21 -0800441status_t JMediaCodec::signalEndOfInputStream() {
442 return mCodec->signalEndOfInputStream();
443}
444
Lajos Molnard4023112014-07-11 15:12:59 -0700445status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800446 sp<AMessage> msg;
447 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700448 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
449 if (err != OK) {
450 return err;
451 }
452
453 return ConvertMessageToMap(env, msg, format);
454}
455
456status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
457 sp<AMessage> msg;
458 status_t err;
459 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800460 return err;
461 }
462
463 return ConvertMessageToMap(env, msg, format);
464}
465
466status_t JMediaCodec::getBuffers(
467 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900468 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800469
470 status_t err =
471 input
472 ? mCodec->getInputBuffers(&buffers)
473 : mCodec->getOutputBuffers(&buffers);
474
475 if (err != OK) {
476 return err;
477 }
478
Andreas Huber88572f72012-02-21 11:47:18 -0800479 *bufArray = (jobjectArray)env->NewObjectArray(
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800480 buffers.size(), gByteBufferInfo.clazz, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800481 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800482 return NO_MEMORY;
483 }
Andreas Huber88572f72012-02-21 11:47:18 -0800484
485 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900486 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800487
Lajos Molnar7de28d32014-07-25 07:51:02 -0700488 jobject byteBuffer = NULL;
489 err = createByteBufferFromABuffer(
490 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
491 if (err != OK) {
492 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800493 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700494 if (byteBuffer != NULL) {
495 env->SetObjectArrayElement(
496 *bufArray, i, byteBuffer);
497
Lajos Molnard4023112014-07-11 15:12:59 -0700498 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700499 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700500 }
Andreas Huber88572f72012-02-21 11:47:18 -0800501 }
502
Lajos Molnar7de28d32014-07-25 07:51:02 -0700503 return OK;
504}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700505
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800506template <typename T>
507static jobject CreateByteBuffer(
508 JNIEnv *env, T *base, size_t capacity, size_t offset, size_t size,
509 bool readOnly, bool clearBuffer) {
510 jobject byteBuffer =
511 env->NewDirectByteBuffer(
512 const_cast<typename std::remove_const<T>::type *>(base),
513 capacity);
514 if (readOnly && byteBuffer != NULL) {
515 jobject readOnlyBuffer = env->CallObjectMethod(
516 byteBuffer, gByteBufferInfo.asReadOnlyBufferId);
517 env->DeleteLocalRef(byteBuffer);
518 byteBuffer = readOnlyBuffer;
519 }
520 if (byteBuffer == NULL) {
521 return nullptr;
522 }
523 jobject me = env->CallObjectMethod(
524 byteBuffer, gByteBufferInfo.orderId, gByteBufferInfo.nativeByteOrder);
525 env->DeleteLocalRef(me);
526 me = env->CallObjectMethod(
527 byteBuffer, gByteBufferInfo.limitId,
528 clearBuffer ? capacity : offset + size);
529 env->DeleteLocalRef(me);
530 me = env->CallObjectMethod(
531 byteBuffer, gByteBufferInfo.positionId,
532 clearBuffer ? 0 : offset);
533 env->DeleteLocalRef(me);
534 me = NULL;
535 return byteBuffer;
536}
537
538
Lajos Molnar7de28d32014-07-25 07:51:02 -0700539// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900540template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700541status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900542 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700543 jobject *buf) const {
544 // if this is an ABuffer that doesn't actually hold any accessible memory,
545 // use a null ByteBuffer
546 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700547
548 if (buffer == NULL) {
549 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
550 return OK;
551 }
552
Lajos Molnar7de28d32014-07-25 07:51:02 -0700553 if (buffer->base() == NULL) {
554 return OK;
555 }
556
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800557 jobject byteBuffer = CreateByteBuffer(
558 env, buffer->base(), buffer->capacity(), buffer->offset(), buffer->size(),
559 readOnly, clearBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700560
561 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800562 return OK;
563}
564
Lajos Molnard4023112014-07-11 15:12:59 -0700565status_t JMediaCodec::getBuffer(
566 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900567 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700568
569 status_t err =
570 input
571 ? mCodec->getInputBuffer(index, &buffer)
572 : mCodec->getOutputBuffer(index, &buffer);
573
574 if (err != OK) {
575 return err;
576 }
577
Lajos Molnar7de28d32014-07-25 07:51:02 -0700578 return createByteBufferFromABuffer(
579 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700580}
581
582status_t JMediaCodec::getImage(
583 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900584 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700585
586 status_t err =
587 input
588 ? mCodec->getInputBuffer(index, &buffer)
589 : mCodec->getOutputBuffer(index, &buffer);
590
591 if (err != OK) {
592 return err;
593 }
594
595 // if this is an ABuffer that doesn't actually hold any accessible memory,
596 // use a null ByteBuffer
597 *buf = NULL;
598 if (buffer->base() == NULL) {
599 return OK;
600 }
601
602 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700603 sp<ABuffer> imageData;
604 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700605 return OK;
606 }
607
Lajos Molnar7de28d32014-07-25 07:51:02 -0700608 int64_t timestamp = 0;
609 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
610 timestamp *= 1000; // adjust to ns
611 }
612
613 jobject byteBuffer = NULL;
614 err = createByteBufferFromABuffer(
615 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
616 if (err != OK) {
617 return OK;
618 }
619
620 jobject infoBuffer = NULL;
621 err = createByteBufferFromABuffer(
622 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
623 if (err != OK) {
624 env->DeleteLocalRef(byteBuffer);
625 byteBuffer = NULL;
626 return OK;
627 }
628
629 jobject cropRect = NULL;
630 int32_t left, top, right, bottom;
631 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
632 ScopedLocalRef<jclass> rectClazz(
633 env, env->FindClass("android/graphics/Rect"));
634 CHECK(rectClazz.get() != NULL);
635
636 jmethodID rectConstructID = env->GetMethodID(
637 rectClazz.get(), "<init>", "(IIII)V");
638
639 cropRect = env->NewObject(
640 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
641 }
642
643 ScopedLocalRef<jclass> imageClazz(
644 env, env->FindClass("android/media/MediaCodec$MediaImage"));
645 CHECK(imageClazz.get() != NULL);
646
647 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
648 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
649
650 *buf = env->NewObject(imageClazz.get(), imageConstructID,
651 byteBuffer, infoBuffer,
652 (jboolean)!input /* readOnly */,
653 (jlong)timestamp,
654 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
655
656 // if MediaImage creation fails, return null
657 if (env->ExceptionCheck()) {
658 env->ExceptionDescribe();
659 env->ExceptionClear();
660 *buf = NULL;
661 }
662
663 if (cropRect != NULL) {
664 env->DeleteLocalRef(cropRect);
665 cropRect = NULL;
666 }
667
668 env->DeleteLocalRef(byteBuffer);
669 byteBuffer = NULL;
670
671 env->DeleteLocalRef(infoBuffer);
672 infoBuffer = NULL;
673
Lajos Molnard4023112014-07-11 15:12:59 -0700674 return OK;
675}
676
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800677status_t JMediaCodec::getOutputFrame(
678 JNIEnv *env, jobject frame, size_t index) const {
679 sp<MediaCodecBuffer> buffer;
680
681 status_t err = mCodec->getOutputBuffer(index, &buffer);
682 if (err != OK) {
683 return err;
684 }
685
686 if (buffer->size() > 0) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800687 std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800688 if (c2Buffer) {
689 switch (c2Buffer->data().type()) {
690 case C2BufferData::LINEAR: {
691 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
692 context->mBuffer = c2Buffer;
693 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
694 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800695 env->CallVoidMethod(
696 linearBlock.get(),
697 gLinearBlockInfo.setInternalStateId,
698 (jlong)context.release(),
699 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800700 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
701 break;
702 }
703 case C2BufferData::GRAPHIC: {
Wonsik Kim637afb22020-02-25 14:27:29 -0800704 const C2Handle *c2Handle = c2Buffer->data().graphicBlocks().front().handle();
705 uint32_t width, height, format, stride, igbp_slot, generation;
706 uint64_t usage, igbp_id;
707 _UnwrapNativeCodec2GrallocMetadata(
708 c2Handle, &width, &height, &format, &usage, &stride, &generation,
709 &igbp_id, &igbp_slot);
710 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
711 GraphicBuffer* graphicBuffer = new GraphicBuffer(
712 grallocHandle, GraphicBuffer::CLONE_HANDLE,
713 width, height, format, 1, usage, stride);
714 ScopedLocalRef<jobject> hardwareBuffer{
715 env,
716 android_hardware_HardwareBuffer_createFromAHardwareBuffer(
717 env, AHardwareBuffer_from_GraphicBuffer(graphicBuffer))};
718 env->SetObjectField(
719 frame, gFields.outputFrameHardwareBufferID, hardwareBuffer.get());
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800720 break;
721 }
722 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
723 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
724 case C2BufferData::INVALID: [[fallthrough]];
725 default:
726 return INVALID_OPERATION;
727 }
728 } else {
729 if (!mGraphicOutput) {
730 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
731 context->mLegacyBuffer = buffer;
732 ScopedLocalRef<jobject> linearBlock{env, env->NewObject(
733 gLinearBlockInfo.clazz, gLinearBlockInfo.ctorId)};
Wonsik Kim7954ccd2020-01-29 22:23:52 -0800734 env->CallVoidMethod(
735 linearBlock.get(),
736 gLinearBlockInfo.setInternalStateId,
737 (jlong)context.release(),
738 true);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800739 env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
740 } else {
Wonsik Kim637afb22020-02-25 14:27:29 -0800741 // No-op.
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800742 }
743 }
744 }
745
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700746 jobject formatMap;
747 err = getOutputFormat(env, index, &formatMap);
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800748 if (err != OK) {
749 return err;
750 }
Wonsik Kimbedf6ba2020-04-17 10:55:19 -0700751 ScopedLocalRef<jclass> mediaFormatClass{env, env->FindClass("android/media/MediaFormat")};
752 ScopedLocalRef<jobject> format{env, env->NewObject(
753 mediaFormatClass.get(),
754 env->GetMethodID(mediaFormatClass.get(), "<init>", "(Ljava/util/Map;)V"),
755 formatMap)};
756 env->SetObjectField(frame, gFields.outputFrameFormatID, format.get());
757 env->DeleteLocalRef(formatMap);
758 formatMap = nullptr;
Wonsik Kimccb7ac62019-12-27 17:12:40 -0800759
760 sp<RefBase> obj;
761 if (buffer->meta()->findObject("changedKeys", &obj) && obj) {
762 sp<MediaCodec::WrapperObject<std::set<std::string>>> changedKeys{
763 (decltype(changedKeys.get()))obj.get()};
764 ScopedLocalRef<jobject> changedKeysObj{env, env->GetObjectField(
765 frame, gFields.outputFrameChangedKeysID)};
766 for (const std::string &key : changedKeys->value) {
767 ScopedLocalRef<jstring> keyStr{env, env->NewStringUTF(key.c_str())};
768 (void)env->CallBooleanMethod(changedKeysObj.get(), gArrayListInfo.addId, keyStr.get());
769 }
770 }
771 return OK;
772}
773
774
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300775status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
776 AString name;
777
778 status_t err = mCodec->getName(&name);
779
780 if (err != OK) {
781 return err;
782 }
783
784 *nameStr = env->NewStringUTF(name.c_str());
785
786 return OK;
787}
788
Chong Zhanga0b72a62018-02-28 18:46:26 -0800789static jobject getCodecCapabilitiesObject(
790 JNIEnv *env, const char *mime, bool isEncoder,
791 const sp<MediaCodecInfo::Capabilities> &capabilities) {
792 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
793 Vector<uint32_t> colorFormats;
794
795 sp<AMessage> defaultFormat = new AMessage();
796 defaultFormat->setString("mime", mime);
797
798 capabilities->getSupportedColorFormats(&colorFormats);
799 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800800 sp<AMessage> details = capabilities->getDetails();
801
802 jobject defaultFormatObj = NULL;
803 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
804 return NULL;
805 }
806 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
807
808 jobject detailsObj = NULL;
809 if (ConvertMessageToMap(env, details, &detailsObj)) {
810 return NULL;
811 }
812 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
813
814 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
815 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
816
817 for (size_t i = 0; i < profileLevels.size(); ++i) {
818 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
819
820 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
821 gCodecInfo.profileLevelClazz));
822
823 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
824 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
825
826 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
827 }
828
829 ScopedLocalRef<jintArray> colorFormatsArray(
830 env, env->NewIntArray(colorFormats.size()));
831 for (size_t i = 0; i < colorFormats.size(); ++i) {
832 jint val = colorFormats.itemAt(i);
833 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
834 }
835
836 return env->NewObject(
837 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800838 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800839 defaultFormatRef.get(), detailsRef.get());
840}
841
842status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
843 sp<MediaCodecInfo> codecInfo;
844
845 status_t err = mCodec->getCodecInfo(&codecInfo);
846
847 if (err != OK) {
848 return err;
849 }
850
851 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800852 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800853
Lajos Molnard2a7f472018-11-15 12:49:20 -0800854 ScopedLocalRef<jstring> canonicalNameObject(env,
855 env->NewStringUTF(codecInfo->getCodecName()));
856
857 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800858 bool isEncoder = codecInfo->isEncoder();
859
Lajos Molnard2a7f472018-11-15 12:49:20 -0800860 Vector<AString> mediaTypes;
861 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800862
863 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800864 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800865
Lajos Molnard2a7f472018-11-15 12:49:20 -0800866 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800867 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800868 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800869
870 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800871 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800872
873 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
874 }
875
876 ScopedLocalRef<jclass> codecInfoClazz(env,
877 env->FindClass("android/media/MediaCodecInfo"));
878 CHECK(codecInfoClazz.get() != NULL);
879
880 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800881 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800882
883 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800884 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800885
886 return OK;
887}
888
Ray Essick81fbc5b2019-12-07 06:24:59 -0800889status_t JMediaCodec::getMetrics(JNIEnv *, mediametrics::Item * &reply) const {
890 mediametrics_handle_t reply2 = mediametrics::Item::convert(reply);
Ray Essick8268c412019-08-26 15:34:10 -0700891 status_t status = mCodec->getMetrics(reply2);
Ray Essick758c7382019-09-18 14:04:28 -0700892 // getMetrics() updates reply2, pass the converted update along to our caller.
Ray Essick81fbc5b2019-12-07 06:24:59 -0800893 reply = mediametrics::Item::convert(reply2);
Ray Essick0e0fee12017-01-25 18:01:56 -0800894 return status;
895}
896
Andreas Huber226065b2013-08-12 10:14:11 -0700897status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
898 return mCodec->setParameters(msg);
899}
900
Andreas Huberb12a5392012-04-30 14:18:33 -0700901void JMediaCodec::setVideoScalingMode(int mode) {
902 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700903 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700904 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700905 // also signal via param for components that queue to IGBP
906 sp<AMessage> msg = new AMessage;
907 msg->setInt32("android._video-scaling", mode);
908 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700909 }
910}
911
ybai5e053202018-11-01 13:02:15 +0800912void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
913 sp<AMessage> msg = new AMessage;
914 msg->setInt32("audio-presentation-presentation-id", presentationId);
915 msg->setInt32("audio-presentation-program-id", programId);
916 (void)mCodec->setParameters(msg);
917}
918
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700919static jthrowable createCodecException(
920 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
921 ScopedLocalRef<jclass> clazz(
922 env, env->FindClass("android/media/MediaCodec$CodecException"));
923 CHECK(clazz.get() != NULL);
924
Ronghua Wuc53ad692015-05-08 14:40:49 -0700925 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700926 CHECK(ctor != NULL);
927
928 ScopedLocalRef<jstring> msgObj(
929 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
930
931 // translate action code to Java equivalent
932 switch (actionCode) {
933 case ACTION_CODE_TRANSIENT:
934 actionCode = gCodecActionCodes.codecActionTransient;
935 break;
936 case ACTION_CODE_RECOVERABLE:
937 actionCode = gCodecActionCodes.codecActionRecoverable;
938 break;
939 default:
940 actionCode = 0; // everything else is fatal
941 break;
942 }
943
Ronghua Wuc53ad692015-05-08 14:40:49 -0700944 /* translate OS errors to Java API CodecException errorCodes */
945 switch (err) {
946 case NO_MEMORY:
947 err = gCodecErrorCodes.errorInsufficientResource;
948 break;
949 case DEAD_OBJECT:
950 err = gCodecErrorCodes.errorReclaimed;
951 break;
952 default: /* Other error codes go out as is. */
953 break;
954 }
955
956 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700957}
958
Chong Zhang8d5e5562014-07-08 18:49:21 -0700959void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
960 int32_t arg1, arg2 = 0;
961 jobject obj = NULL;
962 CHECK(msg->findInt32("callbackID", &arg1));
963 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700964
Chong Zhang8d5e5562014-07-08 18:49:21 -0700965 switch (arg1) {
966 case MediaCodec::CB_INPUT_AVAILABLE:
967 {
968 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700969 break;
970 }
971
Chong Zhang8d5e5562014-07-08 18:49:21 -0700972 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700973 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700974 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700975
Chong Zhang8d5e5562014-07-08 18:49:21 -0700976 size_t size, offset;
977 int64_t timeUs;
978 uint32_t flags;
979 CHECK(msg->findSize("size", &size));
980 CHECK(msg->findSize("offset", &offset));
981 CHECK(msg->findInt64("timeUs", &timeUs));
982 CHECK(msg->findInt32("flags", (int32_t *)&flags));
983
984 ScopedLocalRef<jclass> clazz(
985 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
986 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
987 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
988
989 obj = env->NewObject(clazz.get(), ctor);
990
991 if (obj == NULL) {
992 if (env->ExceptionCheck()) {
993 ALOGE("Could not create MediaCodec.BufferInfo.");
994 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700995 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700996 jniThrowException(env, "java/lang/IllegalStateException", NULL);
997 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700998 }
999
Chong Zhang8d5e5562014-07-08 18:49:21 -07001000 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
1001 break;
1002 }
1003
1004 case MediaCodec::CB_ERROR:
1005 {
Chong Zhang94686d12014-07-11 15:53:58 -07001006 int32_t err, actionCode;
1007 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -07001008 CHECK(msg->findInt32("actionCode", &actionCode));
1009
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001010 // note that DRM errors could conceivably alias into a CodecException
1011 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001012
1013 if (obj == NULL) {
1014 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -07001015 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -07001016 env->ExceptionClear();
1017 }
1018 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1019 return;
1020 }
Andreas Huberaba67132013-10-22 12:40:01 -07001021
1022 break;
1023 }
1024
Chong Zhang8d5e5562014-07-08 18:49:21 -07001025 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -07001026 {
Chong Zhang8d5e5562014-07-08 18:49:21 -07001027 sp<AMessage> format;
1028 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -07001029
Chong Zhang8d5e5562014-07-08 18:49:21 -07001030 if (OK != ConvertMessageToMap(env, format, &obj)) {
1031 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1032 return;
1033 }
Andreas Huberaba67132013-10-22 12:40:01 -07001034
Andreas Huberaba67132013-10-22 12:40:01 -07001035 break;
1036 }
1037
1038 default:
1039 TRESPASS();
1040 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001041
1042 env->CallVoidMethod(
1043 mObject,
1044 gFields.postEventFromNativeID,
1045 EVENT_CALLBACK,
1046 arg1,
1047 arg2,
1048 obj);
1049
1050 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -07001051}
1052
Lajos Molnard8578572015-06-05 20:17:33 -07001053void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
1054 int32_t arg1 = 0, arg2 = 0;
1055 jobject obj = NULL;
1056 JNIEnv *env = AndroidRuntime::getJNIEnv();
1057
1058 sp<AMessage> data;
1059 CHECK(msg->findMessage("data", &data));
1060
1061 status_t err = ConvertMessageToMap(env, data, &obj);
1062 if (err != OK) {
1063 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1064 return;
1065 }
1066
1067 env->CallVoidMethod(
1068 mObject, gFields.postEventFromNativeID,
1069 EVENT_FRAME_RENDERED, arg1, arg2, obj);
1070
1071 env->DeleteLocalRef(obj);
1072}
1073
Chong Zhang8d5e5562014-07-08 18:49:21 -07001074void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
1075 switch (msg->what()) {
1076 case kWhatCallbackNotify:
1077 {
1078 handleCallback(msg);
1079 break;
1080 }
Lajos Molnard8578572015-06-05 20:17:33 -07001081 case kWhatFrameRendered:
1082 {
1083 handleFrameRenderedNotification(msg);
1084 break;
1085 }
Chong Zhang8d5e5562014-07-08 18:49:21 -07001086 default:
1087 TRESPASS();
1088 }
Andreas Huberaba67132013-10-22 12:40:01 -07001089}
1090
Andreas Huber88572f72012-02-21 11:47:18 -08001091} // namespace android
1092
1093////////////////////////////////////////////////////////////////////////////////
1094
1095using namespace android;
1096
1097static sp<JMediaCodec> setMediaCodec(
1098 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001099 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -08001100 if (codec != NULL) {
1101 codec->incStrong(thiz);
1102 }
1103 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -08001104 /* release MediaCodec and stop the looper now before decStrong.
1105 * otherwise JMediaCodec::~JMediaCodec() could be called from within
1106 * its message handler, doing release() from there will deadlock
1107 * (as MediaCodec::release() post synchronous message to the same looper)
1108 */
1109 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -08001110 old->decStrong(thiz);
1111 }
Wonsik Kim61796fd2018-09-13 13:15:59 -07001112 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -08001113
1114 return old;
1115}
1116
1117static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -07001118 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
1119 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
1120 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -08001121}
1122
1123static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07001124 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1125 if (codec != NULL) {
1126 codec->releaseAsync();
1127 }
Andreas Huber88572f72012-02-21 11:47:18 -08001128}
1129
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001130static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
1131 jthrowable exception = createCodecException(env, err, actionCode, msg);
1132 env->Throw(exception);
1133}
1134
Andreas Huberbfc56f42012-04-19 12:47:07 -07001135static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001136 ScopedLocalRef<jclass> clazz(
1137 env, env->FindClass("android/media/MediaCodec$CryptoException"));
1138 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001139
1140 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001141 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -07001142 CHECK(constructID != NULL);
1143
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001144 const char *defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -07001145
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001146 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001147 switch (err) {
1148 case ERROR_DRM_NO_LICENSE:
1149 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001150 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001151 break;
1152 case ERROR_DRM_LICENSE_EXPIRED:
1153 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001154 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001155 break;
1156 case ERROR_DRM_RESOURCE_BUSY:
1157 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001158 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001159 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001160 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1161 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001162 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001163 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001164 case ERROR_DRM_SESSION_NOT_OPENED:
1165 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001166 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001167 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001168 case ERROR_DRM_INSUFFICIENT_SECURITY:
1169 err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1170 defaultMsg = "Required security level is not met";
1171 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001172 case ERROR_DRM_CANNOT_HANDLE:
1173 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1174 defaultMsg = "Operation not supported in this configuration";
1175 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001176 case ERROR_DRM_FRAME_TOO_LARGE:
1177 err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1178 defaultMsg = "Decrytped frame exceeds size of output buffer";
1179 break;
1180 case ERROR_DRM_SESSION_LOST_STATE:
1181 err = gCryptoErrorCodes.cryptoErrorLostState;
1182 defaultMsg = "Session state was lost, open a new session and retry";
1183 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001184 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001185 break;
1186 }
1187
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001188 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
1189
Andreas Huberbfc56f42012-04-19 12:47:07 -07001190 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001191 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001192
1193 env->Throw(exception);
1194}
1195
1196static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001197 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1198 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001199 switch (err) {
1200 case OK:
1201 return 0;
1202
1203 case -EAGAIN:
1204 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1205
1206 case INFO_FORMAT_CHANGED:
1207 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1208
1209 case INFO_OUTPUT_BUFFERS_CHANGED:
1210 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1211
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001212 case INVALID_OPERATION:
1213 jniThrowException(env, "java/lang/IllegalStateException", msg);
1214 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001215
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001216 case BAD_VALUE:
1217 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1218 return 0;
1219
Andreas Huber88572f72012-02-21 11:47:18 -08001220 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001221 if (isCryptoError(err)) {
1222 throwCryptoException(env, err, msg);
1223 return 0;
1224 }
1225 throwCodecException(env, err, actionCode, msg);
1226 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001227 }
Andreas Huber88572f72012-02-21 11:47:18 -08001228}
1229
Lajos Molnard8578572015-06-05 20:17:33 -07001230static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1231 JNIEnv *env,
1232 jobject thiz,
1233 jboolean enabled) {
1234 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1235
1236 if (codec == NULL) {
1237 throwExceptionAsNecessary(env, INVALID_OPERATION);
1238 return;
1239 }
1240
1241 status_t err = codec->enableOnFrameRenderedListener(enabled);
1242
1243 throwExceptionAsNecessary(env, err);
1244}
1245
Chong Zhang8d5e5562014-07-08 18:49:21 -07001246static void android_media_MediaCodec_native_setCallback(
1247 JNIEnv *env,
1248 jobject thiz,
1249 jobject cb) {
1250 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1251
1252 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001253 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001254 return;
1255 }
1256
1257 status_t err = codec->setCallback(cb);
1258
1259 throwExceptionAsNecessary(env, err);
1260}
1261
Andreas Huber88572f72012-02-21 11:47:18 -08001262static void android_media_MediaCodec_native_configure(
1263 JNIEnv *env,
1264 jobject thiz,
1265 jobjectArray keys, jobjectArray values,
1266 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001267 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001268 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001269 jint flags) {
1270 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1271
1272 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001273 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001274 return;
1275 }
1276
1277 sp<AMessage> format;
1278 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1279
1280 if (err != OK) {
1281 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1282 return;
1283 }
1284
Andy McFaddend47f7d82012-12-18 09:48:38 -08001285 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001286 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001287 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001288 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001289 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001290 } else {
1291 jniThrowException(
1292 env,
1293 "java/lang/IllegalArgumentException",
1294 "The surface has been released");
1295 return;
1296 }
1297 }
1298
Andreas Huber8240d922012-04-04 14:06:32 -07001299 sp<ICrypto> crypto;
1300 if (jcrypto != NULL) {
1301 crypto = JCrypto::GetCrypto(env, jcrypto);
1302 }
1303
Chong Zhangd5927ae2017-01-03 11:07:18 -08001304 sp<IDescrambler> descrambler;
1305 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001306 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001307 }
1308
1309 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001310
1311 throwExceptionAsNecessary(env, err);
1312}
1313
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001314static void android_media_MediaCodec_native_setSurface(
1315 JNIEnv *env,
1316 jobject thiz,
1317 jobject jsurface) {
1318 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1319
1320 if (codec == NULL) {
1321 throwExceptionAsNecessary(env, INVALID_OPERATION);
1322 return;
1323 }
1324
1325 sp<IGraphicBufferProducer> bufferProducer;
1326 if (jsurface != NULL) {
1327 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1328 if (surface != NULL) {
1329 bufferProducer = surface->getIGraphicBufferProducer();
1330 } else {
1331 jniThrowException(
1332 env,
1333 "java/lang/IllegalArgumentException",
1334 "The surface has been released");
1335 return;
1336 }
1337 }
1338
1339 status_t err = codec->setSurface(bufferProducer);
1340 throwExceptionAsNecessary(env, err);
1341}
1342
Chong Zhang8034d602015-04-28 13:38:48 -07001343sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1344 JNIEnv* env, jobject object) {
1345 sp<PersistentSurface> persistentSurface;
1346
1347 jobject lock = env->GetObjectField(
1348 object, gPersistentSurfaceClassInfo.mLock);
1349 if (env->MonitorEnter(lock) == JNI_OK) {
1350 persistentSurface = reinterpret_cast<PersistentSurface *>(
1351 env->GetLongField(object,
1352 gPersistentSurfaceClassInfo.mPersistentObject));
1353 env->MonitorExit(lock);
1354 }
1355 env->DeleteLocalRef(lock);
1356
1357 return persistentSurface;
1358}
1359
1360static jobject android_media_MediaCodec_createPersistentInputSurface(
1361 JNIEnv* env, jclass /* clazz */) {
1362 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1363 sp<PersistentSurface> persistentSurface =
1364 MediaCodec::CreatePersistentInputSurface();
1365
1366 if (persistentSurface == NULL) {
1367 return NULL;
1368 }
1369
1370 sp<Surface> surface = new Surface(
1371 persistentSurface->getBufferProducer(), true);
1372 if (surface == NULL) {
1373 return NULL;
1374 }
1375
1376 jobject object = env->NewObject(
1377 gPersistentSurfaceClassInfo.clazz,
1378 gPersistentSurfaceClassInfo.ctor);
1379
1380 if (object == NULL) {
1381 if (env->ExceptionCheck()) {
1382 ALOGE("Could not create PersistentSurface.");
1383 env->ExceptionClear();
1384 }
1385 return NULL;
1386 }
1387
1388 jobject lock = env->GetObjectField(
1389 object, gPersistentSurfaceClassInfo.mLock);
1390 if (env->MonitorEnter(lock) == JNI_OK) {
1391 env->CallVoidMethod(
1392 object,
1393 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1394 (jlong)surface.get());
1395 env->SetLongField(
1396 object,
1397 gPersistentSurfaceClassInfo.mPersistentObject,
1398 (jlong)persistentSurface.get());
1399 env->MonitorExit(lock);
1400 } else {
1401 env->DeleteLocalRef(object);
1402 object = NULL;
1403 }
1404 env->DeleteLocalRef(lock);
1405
1406 if (object != NULL) {
1407 surface->incStrong(&sRefBaseOwner);
1408 persistentSurface->incStrong(&sRefBaseOwner);
1409 }
1410
1411 return object;
1412}
1413
1414static void android_media_MediaCodec_releasePersistentInputSurface(
1415 JNIEnv* env, jclass /* clazz */, jobject object) {
1416 sp<PersistentSurface> persistentSurface;
1417
1418 jobject lock = env->GetObjectField(
1419 object, gPersistentSurfaceClassInfo.mLock);
1420 if (env->MonitorEnter(lock) == JNI_OK) {
1421 persistentSurface = reinterpret_cast<PersistentSurface *>(
1422 env->GetLongField(
1423 object, gPersistentSurfaceClassInfo.mPersistentObject));
1424 env->SetLongField(
1425 object,
1426 gPersistentSurfaceClassInfo.mPersistentObject,
1427 (jlong)0);
1428 env->MonitorExit(lock);
1429 }
1430 env->DeleteLocalRef(lock);
1431
1432 if (persistentSurface != NULL) {
1433 persistentSurface->decStrong(&sRefBaseOwner);
1434 }
1435 // no need to release surface as it will be released by Surface's jni
1436}
1437
Chong Zhang9560ddb2015-05-13 10:25:29 -07001438static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001439 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001440 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001441
1442 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1443 if (codec == NULL) {
1444 throwExceptionAsNecessary(env, INVALID_OPERATION);
1445 return;
1446 }
1447
1448 sp<PersistentSurface> persistentSurface =
1449 android_media_MediaCodec_getPersistentInputSurface(env, object);
1450
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001451 if (persistentSurface == NULL) {
1452 throwExceptionAsNecessary(
1453 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1454 return;
1455 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001456 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001457 if (err != NO_ERROR) {
1458 throwExceptionAsNecessary(env, err);
1459 }
1460}
1461
Andy McFadden2621e402013-02-19 07:29:21 -08001462static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1463 jobject thiz) {
1464 ALOGV("android_media_MediaCodec_createInputSurface");
1465
1466 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1467 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001468 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001469 return NULL;
1470 }
1471
1472 // Tell the MediaCodec that we want to use a Surface as input.
1473 sp<IGraphicBufferProducer> bufferProducer;
1474 status_t err = codec->createInputSurface(&bufferProducer);
1475 if (err != NO_ERROR) {
1476 throwExceptionAsNecessary(env, err);
1477 return NULL;
1478 }
1479
1480 // Wrap the IGBP in a Java-language Surface.
1481 return android_view_Surface_createFromIGraphicBufferProducer(env,
1482 bufferProducer);
1483}
1484
Andreas Huber88572f72012-02-21 11:47:18 -08001485static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1486 ALOGV("android_media_MediaCodec_start");
1487
1488 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1489
1490 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001491 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001492 return;
1493 }
1494
1495 status_t err = codec->start();
1496
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001497 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001498}
1499
1500static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1501 ALOGV("android_media_MediaCodec_stop");
1502
1503 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1504
1505 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001506 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001507 return;
1508 }
1509
1510 status_t err = codec->stop();
1511
1512 throwExceptionAsNecessary(env, err);
1513}
1514
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001515static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1516 ALOGV("android_media_MediaCodec_reset");
1517
1518 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1519
1520 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001521 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001522 return;
1523 }
1524
1525 status_t err = codec->reset();
1526 if (err != OK) {
1527 // treat all errors as fatal for now, though resource not available
1528 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001529 // we also should avoid sending INVALID_OPERATION here due to
1530 // the transitory nature of reset(), it should not inadvertently
1531 // trigger an IllegalStateException.
1532 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001533 }
1534 throwExceptionAsNecessary(env, err);
1535}
1536
Andreas Huber88572f72012-02-21 11:47:18 -08001537static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1538 ALOGV("android_media_MediaCodec_flush");
1539
1540 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1541
1542 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001543 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001544 return;
1545 }
1546
1547 status_t err = codec->flush();
1548
1549 throwExceptionAsNecessary(env, err);
1550}
1551
1552static void android_media_MediaCodec_queueInputBuffer(
1553 JNIEnv *env,
1554 jobject thiz,
1555 jint index,
1556 jint offset,
1557 jint size,
1558 jlong timestampUs,
1559 jint flags) {
1560 ALOGV("android_media_MediaCodec_queueInputBuffer");
1561
1562 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1563
1564 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001565 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001566 return;
1567 }
1568
Andreas Huberbfc56f42012-04-19 12:47:07 -07001569 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001570
Andreas Huberbfc56f42012-04-19 12:47:07 -07001571 status_t err = codec->queueInputBuffer(
1572 index, offset, size, timestampUs, flags, &errorDetailMsg);
1573
1574 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001575 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001576}
1577
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001578struct NativeCryptoInfo {
1579 NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
1580 : mEnv{env},
1581 mIvObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID)},
1582 mKeyObj{env, (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID)} {
1583 mNumSubSamples = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1584
1585 ScopedLocalRef<jintArray> numBytesOfClearDataObj{env, (jintArray)env->GetObjectField(
1586 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID)};
1587
1588 ScopedLocalRef<jintArray> numBytesOfEncryptedDataObj{env, (jintArray)env->GetObjectField(
1589 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID)};
1590
1591 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1592 if (jmode == gCryptoModes.Unencrypted) {
1593 mMode = CryptoPlugin::kMode_Unencrypted;
1594 } else if (jmode == gCryptoModes.AesCtr) {
1595 mMode = CryptoPlugin::kMode_AES_CTR;
1596 } else if (jmode == gCryptoModes.AesCbc) {
1597 mMode = CryptoPlugin::kMode_AES_CBC;
1598 } else {
1599 throwExceptionAsNecessary(env, INVALID_OPERATION);
1600 return;
1601 }
1602
1603 ScopedLocalRef<jobject> patternObj{
1604 env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
1605
1606 CryptoPlugin::Pattern pattern;
1607 if (patternObj.get() == nullptr) {
1608 pattern.mEncryptBlocks = 0;
1609 pattern.mSkipBlocks = 0;
1610 } else {
1611 pattern.mEncryptBlocks = env->GetIntField(
1612 patternObj.get(), gFields.patternEncryptBlocksID);
1613 pattern.mSkipBlocks = env->GetIntField(
1614 patternObj.get(), gFields.patternSkipBlocksID);
1615 }
1616
1617 mErr = OK;
1618 if (mNumSubSamples <= 0) {
1619 mErr = -EINVAL;
1620 } else if (numBytesOfClearDataObj == nullptr
1621 && numBytesOfEncryptedDataObj == nullptr) {
1622 mErr = -EINVAL;
1623 } else if (numBytesOfEncryptedDataObj != nullptr
1624 && env->GetArrayLength(numBytesOfEncryptedDataObj.get()) < mNumSubSamples) {
1625 mErr = -ERANGE;
1626 } else if (numBytesOfClearDataObj != nullptr
1627 && env->GetArrayLength(numBytesOfClearDataObj.get()) < mNumSubSamples) {
1628 mErr = -ERANGE;
1629 // subSamples array may silently overflow if number of samples are too large. Use
1630 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1631 } else if (CC_UNLIKELY(mNumSubSamples >= (signed)(INT32_MAX / sizeof(*mSubSamples))) ) {
1632 mErr = -EINVAL;
1633 } else {
1634 jint *numBytesOfClearData =
1635 (numBytesOfClearDataObj == nullptr)
1636 ? nullptr
1637 : env->GetIntArrayElements(numBytesOfClearDataObj.get(), nullptr);
1638
1639 jint *numBytesOfEncryptedData =
1640 (numBytesOfEncryptedDataObj == nullptr)
1641 ? nullptr
1642 : env->GetIntArrayElements(numBytesOfEncryptedDataObj.get(), nullptr);
1643
1644 mSubSamples = new CryptoPlugin::SubSample[mNumSubSamples];
1645
1646 for (jint i = 0; i < mNumSubSamples; ++i) {
1647 mSubSamples[i].mNumBytesOfClearData =
1648 (numBytesOfClearData == nullptr) ? 0 : numBytesOfClearData[i];
1649
1650 mSubSamples[i].mNumBytesOfEncryptedData =
1651 (numBytesOfEncryptedData == nullptr) ? 0 : numBytesOfEncryptedData[i];
1652 }
1653
1654 if (numBytesOfEncryptedData != nullptr) {
1655 env->ReleaseIntArrayElements(
1656 numBytesOfEncryptedDataObj.get(), numBytesOfEncryptedData, 0);
1657 numBytesOfEncryptedData = nullptr;
1658 }
1659
1660 if (numBytesOfClearData != nullptr) {
1661 env->ReleaseIntArrayElements(
1662 numBytesOfClearDataObj.get(), numBytesOfClearData, 0);
1663 numBytesOfClearData = nullptr;
1664 }
1665 }
1666
1667 if (mErr == OK && mKeyObj.get() != nullptr) {
1668 if (env->GetArrayLength(mKeyObj.get()) != 16) {
1669 mErr = -EINVAL;
1670 } else {
1671 mKey = env->GetByteArrayElements(mKeyObj.get(), nullptr);
1672 }
1673 }
1674
1675 if (mErr == OK && mIvObj.get() != nullptr) {
1676 if (env->GetArrayLength(mIvObj.get()) != 16) {
1677 mErr = -EINVAL;
1678 } else {
1679 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
1680 }
1681 }
1682 }
1683
1684 ~NativeCryptoInfo() {
1685 if (mIv != nullptr) {
1686 mEnv->ReleaseByteArrayElements(mIvObj.get(), mIv, 0);
1687 }
1688
1689 if (mKey != nullptr) {
1690 mEnv->ReleaseByteArrayElements(mKeyObj.get(), mKey, 0);
1691 }
1692
1693 if (mSubSamples != nullptr) {
1694 delete[] mSubSamples;
1695 }
1696 }
1697
1698 JNIEnv *mEnv{nullptr};
1699 ScopedLocalRef<jbyteArray> mIvObj;
1700 ScopedLocalRef<jbyteArray> mKeyObj;
1701 status_t mErr{OK};
1702
1703 CryptoPlugin::SubSample *mSubSamples{nullptr};
1704 int32_t mNumSubSamples{0};
1705 jbyte *mIv{nullptr};
1706 jbyte *mKey{nullptr};
1707 enum CryptoPlugin::Mode mMode;
1708 CryptoPlugin::Pattern mPattern;
1709};
1710
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001711static void android_media_MediaCodec_queueSecureInputBuffer(
1712 JNIEnv *env,
1713 jobject thiz,
1714 jint index,
1715 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001716 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001717 jlong timestampUs,
1718 jint flags) {
1719 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1720
1721 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1722
1723 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001724 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001725 return;
1726 }
1727
Wonsik Kim1cac4252020-01-24 11:45:37 -08001728 jint numSubSamples =
1729 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1730
1731 jintArray numBytesOfClearDataObj =
1732 (jintArray)env->GetObjectField(
1733 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1734
1735 jintArray numBytesOfEncryptedDataObj =
1736 (jintArray)env->GetObjectField(
1737 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1738
1739 jbyteArray keyObj =
1740 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1741
1742 jbyteArray ivObj =
1743 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1744
1745 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1746 enum CryptoPlugin::Mode mode;
1747 if (jmode == gCryptoModes.Unencrypted) {
1748 mode = CryptoPlugin::kMode_Unencrypted;
1749 } else if (jmode == gCryptoModes.AesCtr) {
1750 mode = CryptoPlugin::kMode_AES_CTR;
1751 } else if (jmode == gCryptoModes.AesCbc) {
1752 mode = CryptoPlugin::kMode_AES_CBC;
1753 } else {
1754 throwExceptionAsNecessary(env, INVALID_OPERATION);
1755 return;
1756 }
1757
1758 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1759
1760 CryptoPlugin::Pattern pattern;
1761 if (patternObj == NULL) {
1762 pattern.mEncryptBlocks = 0;
1763 pattern.mSkipBlocks = 0;
1764 } else {
1765 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1766 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1767 }
1768
1769 status_t err = OK;
1770
1771 CryptoPlugin::SubSample *subSamples = NULL;
1772 jbyte *key = NULL;
1773 jbyte *iv = NULL;
1774
1775 if (numSubSamples <= 0) {
1776 err = -EINVAL;
1777 } else if (numBytesOfClearDataObj == NULL
1778 && numBytesOfEncryptedDataObj == NULL) {
1779 err = -EINVAL;
1780 } else if (numBytesOfEncryptedDataObj != NULL
1781 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1782 err = -ERANGE;
1783 } else if (numBytesOfClearDataObj != NULL
1784 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1785 err = -ERANGE;
1786 // subSamples array may silently overflow if number of samples are too large. Use
1787 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1788 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1789 err = -EINVAL;
1790 } else {
1791 jboolean isCopy;
1792
1793 jint *numBytesOfClearData =
1794 (numBytesOfClearDataObj == NULL)
1795 ? NULL
1796 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1797
1798 jint *numBytesOfEncryptedData =
1799 (numBytesOfEncryptedDataObj == NULL)
1800 ? NULL
1801 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1802
1803 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1804
1805 for (jint i = 0; i < numSubSamples; ++i) {
1806 subSamples[i].mNumBytesOfClearData =
1807 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1808
1809 subSamples[i].mNumBytesOfEncryptedData =
1810 (numBytesOfEncryptedData == NULL)
1811 ? 0 : numBytesOfEncryptedData[i];
1812 }
1813
1814 if (numBytesOfEncryptedData != NULL) {
1815 env->ReleaseIntArrayElements(
1816 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1817 numBytesOfEncryptedData = NULL;
1818 }
1819
1820 if (numBytesOfClearData != NULL) {
1821 env->ReleaseIntArrayElements(
1822 numBytesOfClearDataObj, numBytesOfClearData, 0);
1823 numBytesOfClearData = NULL;
1824 }
1825 }
1826
1827 if (err == OK && keyObj != NULL) {
1828 if (env->GetArrayLength(keyObj) != 16) {
1829 err = -EINVAL;
1830 } else {
1831 jboolean isCopy;
1832 key = env->GetByteArrayElements(keyObj, &isCopy);
1833 }
1834 }
1835
1836 if (err == OK && ivObj != NULL) {
1837 if (env->GetArrayLength(ivObj) != 16) {
1838 err = -EINVAL;
1839 } else {
1840 jboolean isCopy;
1841 iv = env->GetByteArrayElements(ivObj, &isCopy);
1842 }
1843 }
1844
Andreas Huberbfc56f42012-04-19 12:47:07 -07001845 AString errorDetailMsg;
1846
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001847 if (err == OK) {
1848 err = codec->queueSecureInputBuffer(
1849 index, offset,
Wonsik Kim1cac4252020-01-24 11:45:37 -08001850 subSamples, numSubSamples,
1851 (const uint8_t *)key, (const uint8_t *)iv,
1852 mode,
1853 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001854 timestampUs,
1855 flags,
1856 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001857 }
1858
Wonsik Kim1cac4252020-01-24 11:45:37 -08001859 if (iv != NULL) {
1860 env->ReleaseByteArrayElements(ivObj, iv, 0);
1861 iv = NULL;
1862 }
1863
1864 if (key != NULL) {
1865 env->ReleaseByteArrayElements(keyObj, key, 0);
1866 key = NULL;
1867 }
1868
1869 delete[] subSamples;
1870 subSamples = NULL;
1871
Andreas Huberbfc56f42012-04-19 12:47:07 -07001872 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001873 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001874}
1875
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001876static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
Wonsik Kim637afb22020-02-25 14:27:29 -08001877 ALOGV("android_media_MediaCodec_mapHardwareBuffer");
1878 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
1879 env, bufferObj);
1880 AHardwareBuffer_Desc desc;
1881 AHardwareBuffer_describe(hardwareBuffer, &desc);
1882 if (desc.format != AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420) {
1883 ALOGI("mapHardwareBuffer: unmappable format: %d", desc.format);
1884 return nullptr;
1885 }
1886 if ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK) == 0) {
1887 ALOGI("mapHardwareBuffer: buffer not CPU readable");
1888 return nullptr;
1889 }
1890 bool readOnly = ((desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK) == 0);
1891
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001892 uint64_t cpuUsage = 0;
1893 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_READ_MASK);
1894 cpuUsage |= (desc.usage & AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK);
Wonsik Kim637afb22020-02-25 14:27:29 -08001895
1896 AHardwareBuffer_Planes planes;
1897 int err = AHardwareBuffer_lockPlanes(
1898 hardwareBuffer, cpuUsage, -1 /* fence */, nullptr /* rect */, &planes);
1899 if (err != 0) {
1900 ALOGI("mapHardwareBuffer: Failed to lock planes (err=%d)", err);
1901 return nullptr;
1902 }
1903
1904 if (planes.planeCount != 3) {
1905 ALOGI("mapHardwareBuffer: planeCount expected 3, actual %u", planes.planeCount);
1906 return nullptr;
1907 }
1908
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001909 ScopedLocalRef<jobjectArray> buffersArray{
1910 env, env->NewObjectArray(3, gByteBufferInfo.clazz, NULL)};
1911 ScopedLocalRef<jintArray> rowStridesArray{env, env->NewIntArray(3)};
1912 ScopedLocalRef<jintArray> pixelStridesArray{env, env->NewIntArray(3)};
Wonsik Kim637afb22020-02-25 14:27:29 -08001913
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001914 jboolean isCopy = JNI_FALSE;
1915 jint *rowStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1916 jint *pixelStrides = env->GetIntArrayElements(rowStridesArray.get(), &isCopy);
1917
1918 // For Y plane
1919 int rowSampling = 1;
1920 int colSampling = 1;
Wonsik Kim637afb22020-02-25 14:27:29 -08001921 // plane indices are Y-U-V.
1922 for (uint32_t i = 0; i < 3; ++i) {
1923 const AHardwareBuffer_Plane &plane = planes.planes[i];
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001924 int maxRowOffset = plane.rowStride * (desc.height / rowSampling - 1);
1925 int maxColOffset = plane.pixelStride * (desc.width / colSampling - 1);
1926 int maxOffset = maxRowOffset + maxColOffset;
Wonsik Kim637afb22020-02-25 14:27:29 -08001927 ScopedLocalRef<jobject> byteBuffer{env, CreateByteBuffer(
1928 env,
1929 plane.data,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001930 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08001931 0,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001932 maxOffset + 1,
Wonsik Kim637afb22020-02-25 14:27:29 -08001933 readOnly,
1934 true)};
1935
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001936 env->SetObjectArrayElement(buffersArray.get(), i, byteBuffer.get());
1937 rowStrides[i] = plane.rowStride;
1938 pixelStrides[i] = plane.pixelStride;
1939 // For U-V planes
1940 rowSampling = 2;
1941 colSampling = 2;
Wonsik Kim637afb22020-02-25 14:27:29 -08001942 }
1943
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001944 env->ReleaseIntArrayElements(rowStridesArray.get(), rowStrides, 0);
1945 env->ReleaseIntArrayElements(pixelStridesArray.get(), pixelStrides, 0);
1946 rowStrides = pixelStrides = nullptr;
1947
Wonsik Kim637afb22020-02-25 14:27:29 -08001948 ScopedLocalRef<jclass> imageClazz(
1949 env, env->FindClass("android/media/MediaCodec$MediaImage"));
1950 CHECK(imageClazz.get() != NULL);
1951
1952 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001953 "([Ljava/nio/ByteBuffer;[I[IIIIZJIILandroid/graphics/Rect;J)V");
Wonsik Kim637afb22020-02-25 14:27:29 -08001954
1955 jobject img = env->NewObject(imageClazz.get(), imageConstructID,
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001956 buffersArray.get(),
1957 rowStridesArray.get(),
1958 pixelStridesArray.get(),
Wonsik Kim637afb22020-02-25 14:27:29 -08001959 desc.width,
1960 desc.height,
1961 desc.format, // ???
1962 (jboolean)readOnly /* readOnly */,
1963 (jlong)0 /* timestamp */,
1964 (jint)0 /* xOffset */, (jint)0 /* yOffset */, nullptr /* cropRect */,
1965 (jlong)hardwareBuffer);
1966
1967 // if MediaImage creation fails, return null
1968 if (env->ExceptionCheck()) {
1969 env->ExceptionDescribe();
1970 env->ExceptionClear();
1971 return nullptr;
1972 }
1973
1974 AHardwareBuffer_acquire(hardwareBuffer);
1975
1976 return img;
1977}
1978
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001979static void android_media_MediaCodec_closeMediaImage(JNIEnv *, jclass, jlong context) {
1980 ALOGV("android_media_MediaCodec_closeMediaImage");
Wonsik Kim637afb22020-02-25 14:27:29 -08001981 if (context == 0) {
1982 return;
1983 }
1984 AHardwareBuffer *hardwareBuffer = (AHardwareBuffer *)context;
1985
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07001986 int err = AHardwareBuffer_unlock(hardwareBuffer, nullptr);
1987 if (err != 0) {
Wonsik Kim637afb22020-02-25 14:27:29 -08001988 ALOGI("closeMediaImage: failed to unlock (err=%d)", err);
1989 // Continue to release the hardwareBuffer
1990 }
1991
1992 AHardwareBuffer_release(hardwareBuffer);
1993}
1994
Wonsik Kimccb7ac62019-12-27 17:12:40 -08001995static status_t ConvertKeyValueListsToAMessage(
1996 JNIEnv *env, jobject keys, jobject values, sp<AMessage> *msg) {
1997 static struct Fields {
1998 explicit Fields(JNIEnv *env) {
1999 ScopedLocalRef<jclass> clazz{env, env->FindClass("java/lang/String")};
2000 CHECK(clazz.get() != NULL);
2001 mStringClass = (jclass)env->NewGlobalRef(clazz.get());
2002
2003 clazz.reset(env->FindClass("java/lang/Integer"));
2004 CHECK(clazz.get() != NULL);
2005 mIntegerClass = (jclass)env->NewGlobalRef(clazz.get());
2006
2007 mIntegerValueId = env->GetMethodID(clazz.get(), "intValue", "()I");
2008 CHECK(mIntegerValueId != NULL);
2009
2010 clazz.reset(env->FindClass("java/lang/Long"));
2011 CHECK(clazz.get() != NULL);
2012 mLongClass = (jclass)env->NewGlobalRef(clazz.get());
2013
2014 mLongValueId = env->GetMethodID(clazz.get(), "longValue", "()J");
2015 CHECK(mLongValueId != NULL);
2016
2017 clazz.reset(env->FindClass("java/lang/Float"));
2018 CHECK(clazz.get() != NULL);
2019 mFloatClass = (jclass)env->NewGlobalRef(clazz.get());
2020
2021 mFloatValueId = env->GetMethodID(clazz.get(), "floatValue", "()F");
2022 CHECK(mFloatValueId != NULL);
2023
2024 clazz.reset(env->FindClass("java/util/ArrayList"));
2025 CHECK(clazz.get() != NULL);
2026
2027 mByteBufferArrayId = env->GetMethodID(gByteBufferInfo.clazz, "array", "()[B");
2028 CHECK(mByteBufferArrayId != NULL);
2029 }
2030
2031 jclass mStringClass;
2032 jclass mIntegerClass;
2033 jmethodID mIntegerValueId;
2034 jclass mLongClass;
2035 jmethodID mLongValueId;
2036 jclass mFloatClass;
2037 jmethodID mFloatValueId;
2038 jmethodID mByteBufferArrayId;
2039 } sFields{env};
2040
2041 jint size = env->CallIntMethod(keys, gArrayListInfo.sizeId);
2042 if (size != env->CallIntMethod(values, gArrayListInfo.sizeId)) {
2043 return BAD_VALUE;
2044 }
2045
2046 sp<AMessage> result{new AMessage};
2047 for (jint i = 0; i < size; ++i) {
2048 ScopedLocalRef<jstring> jkey{
2049 env, (jstring)env->CallObjectMethod(keys, gArrayListInfo.getId, i)};
2050 const char *tmp = env->GetStringUTFChars(jkey.get(), nullptr);
2051 AString key;
2052 if (tmp) {
2053 key.setTo(tmp);
2054 }
2055 env->ReleaseStringUTFChars(jkey.get(), tmp);
2056 if (key.empty()) {
2057 return NO_MEMORY;
2058 }
2059
2060 ScopedLocalRef<jobject> jvalue{
2061 env, env->CallObjectMethod(values, gArrayListInfo.getId, i)};
2062
2063 if (env->IsInstanceOf(jvalue.get(), sFields.mStringClass)) {
2064 const char *tmp = env->GetStringUTFChars((jstring)jvalue.get(), nullptr);
2065 AString value;
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002066 if (!tmp) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002067 return NO_MEMORY;
2068 }
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002069 value.setTo(tmp);
2070 env->ReleaseStringUTFChars((jstring)jvalue.get(), tmp);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002071 result->setString(key.c_str(), value);
2072 } else if (env->IsInstanceOf(jvalue.get(), sFields.mIntegerClass)) {
2073 jint value = env->CallIntMethod(jvalue.get(), sFields.mIntegerValueId);
2074 result->setInt32(key.c_str(), value);
2075 } else if (env->IsInstanceOf(jvalue.get(), sFields.mLongClass)) {
2076 jlong value = env->CallLongMethod(jvalue.get(), sFields.mLongValueId);
2077 result->setInt64(key.c_str(), value);
2078 } else if (env->IsInstanceOf(jvalue.get(), sFields.mFloatClass)) {
2079 jfloat value = env->CallFloatMethod(jvalue.get(), sFields.mFloatValueId);
2080 result->setFloat(key.c_str(), value);
2081 } else if (env->IsInstanceOf(jvalue.get(), gByteBufferInfo.clazz)) {
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002082 jint position = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getPositionId);
2083 jint limit = env->CallIntMethod(jvalue.get(), gByteBufferInfo.getLimitId);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002084 sp<ABuffer> buffer{new ABuffer(limit - position)};
2085 void *data = env->GetDirectBufferAddress(jvalue.get());
2086 if (data != nullptr) {
2087 memcpy(buffer->data(),
2088 static_cast<const uint8_t *>(data) + position,
2089 buffer->size());
2090 } else {
2091 ScopedLocalRef<jbyteArray> byteArray{env, (jbyteArray)env->CallObjectMethod(
2092 jvalue.get(), sFields.mByteBufferArrayId)};
2093 env->GetByteArrayRegion(byteArray.get(), position, buffer->size(),
2094 reinterpret_cast<jbyte *>(buffer->data()));
2095 }
2096 result->setBuffer(key.c_str(), buffer);
2097 }
2098 }
2099
2100 *msg = result;
2101 return OK;
2102}
2103
2104static void android_media_MediaCodec_native_queueLinearBlock(
2105 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2106 jint offset, jint size, jobject cryptoInfoObj,
2107 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
2108 ALOGV("android_media_MediaCodec_native_queueLinearBlock");
2109
2110 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2111
2112 if (codec == nullptr) {
2113 throwExceptionAsNecessary(env, INVALID_OPERATION);
2114 return;
2115 }
2116
2117 sp<AMessage> tunings;
2118 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2119 if (err != OK) {
2120 throwExceptionAsNecessary(env, err);
2121 return;
2122 }
2123
2124 std::shared_ptr<C2Buffer> buffer;
2125 sp<hardware::HidlMemory> memory;
2126 ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
2127 if (env->MonitorEnter(lock.get()) == JNI_OK) {
2128 if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
2129 JMediaCodecLinearBlock *context =
2130 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
2131 if (cryptoInfoObj != nullptr) {
2132 memory = context->toHidlMemory();
2133 } else {
2134 buffer = context->toC2Buffer(offset, size);
2135 }
2136 }
2137 env->MonitorExit(lock.get());
2138 } else {
2139 throwExceptionAsNecessary(env, INVALID_OPERATION);
2140 return;
2141 }
2142
2143 AString errorDetailMsg;
2144 if (cryptoInfoObj != nullptr) {
2145 if (!memory) {
2146 throwExceptionAsNecessary(env, BAD_VALUE);
2147 return;
2148 }
2149
2150 NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002151 err = codec->queueEncryptedLinearBlock(
2152 index,
2153 memory,
2154 offset,
2155 cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
2156 (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
2157 cryptoInfo.mMode,
2158 cryptoInfo.mPattern,
2159 presentationTimeUs,
2160 flags,
2161 tunings,
2162 &errorDetailMsg);
2163 } else {
2164 if (!buffer) {
2165 throwExceptionAsNecessary(env, BAD_VALUE);
2166 return;
2167 }
2168 err = codec->queueBuffer(
2169 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
2170 }
2171 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2172}
2173
Wonsik Kim637afb22020-02-25 14:27:29 -08002174static void android_media_MediaCodec_native_queueHardwareBuffer(
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002175 JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
2176 jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
Wonsik Kim637afb22020-02-25 14:27:29 -08002177 ALOGV("android_media_MediaCodec_native_queueHardwareBuffer");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002178
2179 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2180
2181 if (codec == NULL) {
2182 throwExceptionAsNecessary(env, INVALID_OPERATION);
2183 return;
2184 }
2185
2186 sp<AMessage> tunings;
2187 status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
2188 if (err != OK) {
2189 throwExceptionAsNecessary(env, err);
2190 return;
2191 }
2192
Wonsik Kim637afb22020-02-25 14:27:29 -08002193 AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
2194 env, bufferObj);
2195 sp<GraphicBuffer> graphicBuffer{AHardwareBuffer_to_GraphicBuffer(hardwareBuffer)};
2196 C2Handle *handle = WrapNativeCodec2GrallocHandle(
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002197 graphicBuffer->handle, graphicBuffer->width, graphicBuffer->height,
2198 graphicBuffer->format, graphicBuffer->usage, graphicBuffer->stride);
2199 static std::shared_ptr<C2Allocator> sGrallocAlloc = []() -> std::shared_ptr<C2Allocator> {
2200 std::shared_ptr<C2Allocator> alloc;
2201 c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
2202 C2PlatformAllocatorStore::GRALLOC, &alloc);
2203 if (err == C2_OK) {
2204 return alloc;
2205 }
2206 return nullptr;
2207 }();
2208 std::shared_ptr<C2GraphicAllocation> alloc;
2209 c2_status_t c2err = sGrallocAlloc->priorGraphicAllocation(handle, &alloc);
2210 if (c2err != C2_OK) {
2211 ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002212 throwExceptionAsNecessary(env, BAD_VALUE);
2213 return;
2214 }
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002215 std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
Wonsik Kim637afb22020-02-25 14:27:29 -08002216 std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
2217 block->crop(), C2Fence{}));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002218 AString errorDetailMsg;
Wonsik Kimb8ebdb32020-04-21 17:00:13 -07002219 err = codec->queueBuffer(
2220 index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002221 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
2222}
2223
2224static void android_media_MediaCodec_native_getOutputFrame(
2225 JNIEnv *env, jobject thiz, jobject frame, jint index) {
2226 ALOGV("android_media_MediaCodec_native_getOutputFrame");
2227
2228 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2229
2230 if (codec == NULL) {
2231 throwExceptionAsNecessary(env, INVALID_OPERATION);
2232 return;
2233 }
2234
2235 status_t err = codec->getOutputFrame(env, frame, index);
2236 if (err != OK) {
2237 throwExceptionAsNecessary(env, err);
2238 }
2239}
2240
Andreas Huber88572f72012-02-21 11:47:18 -08002241static jint android_media_MediaCodec_dequeueInputBuffer(
2242 JNIEnv *env, jobject thiz, jlong timeoutUs) {
2243 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
2244
2245 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2246
2247 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002248 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002249 return -1;
2250 }
2251
2252 size_t index;
2253 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
2254
2255 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002256 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002257 }
2258
2259 return throwExceptionAsNecessary(env, err);
2260}
2261
2262static jint android_media_MediaCodec_dequeueOutputBuffer(
2263 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
2264 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
2265
2266 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2267
2268 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002269 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07002270 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08002271 }
2272
2273 size_t index;
2274 status_t err = codec->dequeueOutputBuffer(
2275 env, bufferInfo, &index, timeoutUs);
2276
2277 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00002278 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08002279 }
2280
2281 return throwExceptionAsNecessary(env, err);
2282}
2283
2284static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002285 JNIEnv *env, jobject thiz,
2286 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08002287 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
2288
2289 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2290
2291 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002292 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002293 return;
2294 }
2295
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002296 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08002297
2298 throwExceptionAsNecessary(env, err);
2299}
2300
Andy McFadden2621e402013-02-19 07:29:21 -08002301static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
2302 jobject thiz) {
2303 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
2304
2305 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2306 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002307 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08002308 return;
2309 }
2310
2311 status_t err = codec->signalEndOfInputStream();
2312
2313 throwExceptionAsNecessary(env, err);
2314}
2315
Lajos Molnard4023112014-07-11 15:12:59 -07002316static jobject android_media_MediaCodec_getFormatNative(
2317 JNIEnv *env, jobject thiz, jboolean input) {
2318 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08002319
2320 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2321
2322 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002323 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002324 return NULL;
2325 }
2326
2327 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07002328 status_t err = codec->getFormat(env, input, &format);
2329
2330 if (err == OK) {
2331 return format;
2332 }
2333
2334 throwExceptionAsNecessary(env, err);
2335
2336 return NULL;
2337}
2338
2339static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
2340 JNIEnv *env, jobject thiz, jint index) {
2341 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
2342
2343 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2344
2345 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002346 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002347 return NULL;
2348 }
2349
2350 jobject format;
2351 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08002352
2353 if (err == OK) {
2354 return format;
2355 }
2356
2357 throwExceptionAsNecessary(env, err);
2358
2359 return NULL;
2360}
2361
2362static jobjectArray android_media_MediaCodec_getBuffers(
2363 JNIEnv *env, jobject thiz, jboolean input) {
2364 ALOGV("android_media_MediaCodec_getBuffers");
2365
2366 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2367
2368 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002369 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08002370 return NULL;
2371 }
2372
2373 jobjectArray buffers;
2374 status_t err = codec->getBuffers(env, input, &buffers);
2375
2376 if (err == OK) {
2377 return buffers;
2378 }
2379
Marco Nelissencbbea8e2012-12-19 11:42:55 -08002380 // if we're out of memory, an exception was already thrown
2381 if (err != NO_MEMORY) {
2382 throwExceptionAsNecessary(env, err);
2383 }
Andreas Huber88572f72012-02-21 11:47:18 -08002384
2385 return NULL;
2386}
2387
Lajos Molnard4023112014-07-11 15:12:59 -07002388static jobject android_media_MediaCodec_getBuffer(
2389 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2390 ALOGV("android_media_MediaCodec_getBuffer");
2391
2392 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2393
2394 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002395 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002396 return NULL;
2397 }
2398
2399 jobject buffer;
2400 status_t err = codec->getBuffer(env, input, index, &buffer);
2401
2402 if (err == OK) {
2403 return buffer;
2404 }
2405
2406 // if we're out of memory, an exception was already thrown
2407 if (err != NO_MEMORY) {
2408 throwExceptionAsNecessary(env, err);
2409 }
2410
2411 return NULL;
2412}
2413
2414static jobject android_media_MediaCodec_getImage(
2415 JNIEnv *env, jobject thiz, jboolean input, jint index) {
2416 ALOGV("android_media_MediaCodec_getImage");
2417
2418 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2419
2420 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002421 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07002422 return NULL;
2423 }
2424
2425 jobject image;
2426 status_t err = codec->getImage(env, input, index, &image);
2427
2428 if (err == OK) {
2429 return image;
2430 }
2431
2432 // if we're out of memory, an exception was already thrown
2433 if (err != NO_MEMORY) {
2434 throwExceptionAsNecessary(env, err);
2435 }
2436
2437 return NULL;
2438}
2439
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002440static jobject android_media_MediaCodec_getName(
2441 JNIEnv *env, jobject thiz) {
2442 ALOGV("android_media_MediaCodec_getName");
2443
2444 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2445
2446 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002447 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002448 return NULL;
2449 }
2450
2451 jstring name;
2452 status_t err = codec->getName(env, &name);
2453
2454 if (err == OK) {
2455 return name;
2456 }
2457
2458 throwExceptionAsNecessary(env, err);
2459
2460 return NULL;
2461}
2462
Chong Zhanga0b72a62018-02-28 18:46:26 -08002463static jobject android_media_MediaCodec_getOwnCodecInfo(
2464 JNIEnv *env, jobject thiz) {
2465 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
2466
2467 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2468
2469 if (codec == NULL) {
2470 throwExceptionAsNecessary(env, INVALID_OPERATION);
2471 return NULL;
2472 }
2473
2474 jobject codecInfoObj;
2475 status_t err = codec->getCodecInfo(env, &codecInfoObj);
2476
2477 if (err == OK) {
2478 return codecInfoObj;
2479 }
2480
2481 throwExceptionAsNecessary(env, err);
2482
2483 return NULL;
2484}
2485
Ray Essick0e0fee12017-01-25 18:01:56 -08002486static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08002487android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08002488{
Ray Essickf2d0e402017-03-09 10:17:51 -08002489 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08002490
2491 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2492 if (codec == NULL ) {
2493 jniThrowException(env, "java/lang/IllegalStateException", NULL);
2494 return 0;
2495 }
2496
2497 // get what we have for the metrics from the codec
Ray Essick81fbc5b2019-12-07 06:24:59 -08002498 mediametrics::Item *item = 0;
Ray Essickf2d0e402017-03-09 10:17:51 -08002499
2500 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08002501 if (err != OK) {
2502 ALOGE("getMetrics failed");
2503 return (jobject) NULL;
2504 }
2505
Ray Essick0e0fee12017-01-25 18:01:56 -08002506 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
2507
2508 // housekeeping
2509 delete item;
Ray Essick8268c412019-08-26 15:34:10 -07002510 item = 0;
Ray Essick0e0fee12017-01-25 18:01:56 -08002511
2512 return mybundle;
2513}
2514
Andreas Huber226065b2013-08-12 10:14:11 -07002515static void android_media_MediaCodec_setParameters(
2516 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
2517 ALOGV("android_media_MediaCodec_setParameters");
2518
2519 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2520
2521 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002522 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07002523 return;
2524 }
2525
2526 sp<AMessage> params;
2527 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
2528
2529 if (err == OK) {
2530 err = codec->setParameters(params);
2531 }
2532
2533 throwExceptionAsNecessary(env, err);
2534}
2535
Andreas Huberb12a5392012-04-30 14:18:33 -07002536static void android_media_MediaCodec_setVideoScalingMode(
2537 JNIEnv *env, jobject thiz, jint mode) {
2538 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2539
2540 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002541 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07002542 return;
2543 }
2544
2545 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
2546 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07002547 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07002548 return;
2549 }
2550
2551 codec->setVideoScalingMode(mode);
2552}
2553
ybai5e053202018-11-01 13:02:15 +08002554static void android_media_MediaCodec_setAudioPresentation(
2555 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
2556 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
2557
2558 if (codec == NULL) {
2559 throwExceptionAsNecessary(env, INVALID_OPERATION);
2560 return;
2561 }
2562
2563 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
2564}
2565
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07002566static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002567 ScopedLocalRef<jclass> clazz(
2568 env, env->FindClass("android/media/MediaCodec"));
2569 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002570
Andreas Huberaba67132013-10-22 12:40:01 -07002571 gFields.postEventFromNativeID =
2572 env->GetMethodID(
2573 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07002574 CHECK(gFields.postEventFromNativeID != NULL);
2575
Wonsik Kim61796fd2018-09-13 13:15:59 -07002576 gFields.lockAndGetContextID =
2577 env->GetMethodID(
2578 clazz.get(), "lockAndGetContext", "()J");
2579 CHECK(gFields.lockAndGetContextID != NULL);
2580
2581 gFields.setAndUnlockContextID =
2582 env->GetMethodID(
2583 clazz.get(), "setAndUnlockContext", "(J)V");
2584 CHECK(gFields.setAndUnlockContextID != NULL);
2585
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002586 jfieldID field;
2587 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
2588 CHECK(field != NULL);
2589 gCryptoModes.Unencrypted =
2590 env->GetStaticIntField(clazz.get(), field);
2591
2592 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
2593 CHECK(field != NULL);
2594 gCryptoModes.AesCtr =
2595 env->GetStaticIntField(clazz.get(), field);
2596
2597 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
2598 CHECK(field != NULL);
2599 gCryptoModes.AesCbc =
2600 env->GetStaticIntField(clazz.get(), field);
2601
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002602 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
2603 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07002604
2605 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002606 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002607 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
2608
2609 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002610 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002611 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
2612
2613 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002614 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002615 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
2616
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002617 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002618 CHECK(gFields.cryptoInfoKeyID != NULL);
2619
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002620 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07002621 CHECK(gFields.cryptoInfoIVID != NULL);
2622
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002623 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07002624 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002625
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08002626 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
2627 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
2628 CHECK(gFields.cryptoInfoPatternID != NULL);
2629
2630 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
2631 CHECK(clazz.get() != NULL);
2632
2633 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
2634 CHECK(gFields.patternEncryptBlocksID != NULL);
2635
2636 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
2637 CHECK(gFields.patternSkipBlocksID != NULL);
2638
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002639 clazz.reset(env->FindClass("android/media/MediaCodec$QueueRequest"));
2640 CHECK(clazz.get() != NULL);
2641
2642 gFields.queueRequestIndexID = env->GetFieldID(clazz.get(), "mIndex", "I");
2643 CHECK(gFields.queueRequestIndexID != NULL);
2644
2645 clazz.reset(env->FindClass("android/media/MediaCodec$OutputFrame"));
2646 CHECK(clazz.get() != NULL);
2647
2648 gFields.outputFrameLinearBlockID =
2649 env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
2650 CHECK(gFields.outputFrameLinearBlockID != NULL);
2651
Wonsik Kim637afb22020-02-25 14:27:29 -08002652 gFields.outputFrameHardwareBufferID =
2653 env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
2654 CHECK(gFields.outputFrameHardwareBufferID != NULL);
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002655
2656 gFields.outputFrameChangedKeysID =
2657 env->GetFieldID(clazz.get(), "mChangedKeys", "Ljava/util/ArrayList;");
2658 CHECK(gFields.outputFrameChangedKeysID != NULL);
2659
2660 gFields.outputFrameFormatID =
2661 env->GetFieldID(clazz.get(), "mFormat", "Landroid/media/MediaFormat;");
2662 CHECK(gFields.outputFrameFormatID != NULL);
2663
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002664 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
2665 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002666
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002667 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002668 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002669 gCryptoErrorCodes.cryptoErrorNoKey =
2670 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002671
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002672 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002673 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002674 gCryptoErrorCodes.cryptoErrorKeyExpired =
2675 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002676
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002677 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002678 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002679 gCryptoErrorCodes.cryptoErrorResourceBusy =
2680 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002681
Jeff Tinker336d3ea2014-08-28 17:57:36 -07002682 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
2683 CHECK(field != NULL);
2684 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
2685 env->GetStaticIntField(clazz.get(), field);
2686
Jeff Tinker96a2a952015-07-01 17:35:18 -07002687 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
2688 CHECK(field != NULL);
2689 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
2690 env->GetStaticIntField(clazz.get(), field);
2691
Jeff Tinker20594d82018-12-12 08:31:22 -08002692 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
2693 CHECK(field != NULL);
2694 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
2695 env->GetStaticIntField(clazz.get(), field);
2696
Jeff Tinkerd3932162016-03-05 11:35:20 -08002697 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
2698 CHECK(field != NULL);
2699 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
2700 env->GetStaticIntField(clazz.get(), field);
2701
Jeff Tinker20594d82018-12-12 08:31:22 -08002702 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
2703 CHECK(field != NULL);
2704 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
2705 env->GetStaticIntField(clazz.get(), field);
2706
2707 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
2708 CHECK(field != NULL);
2709 gCryptoErrorCodes.cryptoErrorLostState =
2710 env->GetStaticIntField(clazz.get(), field);
2711
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002712 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
2713 CHECK(clazz.get() != NULL);
2714 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
2715 CHECK(field != NULL);
2716 gCodecActionCodes.codecActionTransient =
2717 env->GetStaticIntField(clazz.get(), field);
2718
2719 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
2720 CHECK(field != NULL);
2721 gCodecActionCodes.codecActionRecoverable =
2722 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002723
Ronghua Wuc53ad692015-05-08 14:40:49 -07002724 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002725 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002726 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002727 env->GetStaticIntField(clazz.get(), field);
2728
Ronghua Wuc53ad692015-05-08 14:40:49 -07002729 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002730 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002731 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002732 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07002733
2734 clazz.reset(env->FindClass("android/view/Surface"));
2735 CHECK(clazz.get() != NULL);
2736
2737 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2738 CHECK(field != NULL);
2739 gPersistentSurfaceClassInfo.mLock = field;
2740
2741 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
2742 CHECK(method != NULL);
2743 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2744
2745 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2746 CHECK(clazz.get() != NULL);
2747 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2748
2749 method = env->GetMethodID(clazz.get(), "<init>", "()V");
2750 CHECK(method != NULL);
2751 gPersistentSurfaceClassInfo.ctor = method;
2752
2753 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2754 CHECK(field != NULL);
2755 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08002756
2757 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2758 CHECK(clazz.get() != NULL);
2759 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2760
2761 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08002762 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08002763 "Ljava/util/Map;Ljava/util/Map;)V");
2764 CHECK(method != NULL);
2765 gCodecInfo.capsCtorId = method;
2766
2767 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2768 CHECK(clazz.get() != NULL);
2769 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2770
2771 field = env->GetFieldID(clazz.get(), "profile", "I");
2772 CHECK(field != NULL);
2773 gCodecInfo.profileField = field;
2774
2775 field = env->GetFieldID(clazz.get(), "level", "I");
2776 CHECK(field != NULL);
2777 gCodecInfo.levelField = field;
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002778
2779 clazz.reset(env->FindClass("java/nio/ByteBuffer"));
2780 CHECK(clazz.get() != NULL);
2781 gByteBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2782
2783 ScopedLocalRef<jclass> byteOrderClass(
2784 env, env->FindClass("java/nio/ByteOrder"));
2785 CHECK(byteOrderClass.get() != NULL);
2786
2787 jmethodID nativeOrderID = env->GetStaticMethodID(
2788 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
2789 CHECK(nativeOrderID != NULL);
2790
2791 ScopedLocalRef<jobject> nativeByteOrderObj{
2792 env, env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID)};
2793 gByteBufferInfo.nativeByteOrder = env->NewGlobalRef(nativeByteOrderObj.get());
2794 CHECK(gByteBufferInfo.nativeByteOrder != NULL);
2795 nativeByteOrderObj.reset();
2796
2797 gByteBufferInfo.orderId = env->GetMethodID(
2798 clazz.get(),
2799 "order",
2800 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
2801 CHECK(gByteBufferInfo.orderId != NULL);
2802
2803 gByteBufferInfo.asReadOnlyBufferId = env->GetMethodID(
2804 clazz.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
2805 CHECK(gByteBufferInfo.asReadOnlyBufferId != NULL);
2806
2807 gByteBufferInfo.positionId = env->GetMethodID(
2808 clazz.get(), "position", "(I)Ljava/nio/Buffer;");
2809 CHECK(gByteBufferInfo.positionId != NULL);
2810
2811 gByteBufferInfo.limitId = env->GetMethodID(
2812 clazz.get(), "limit", "(I)Ljava/nio/Buffer;");
2813 CHECK(gByteBufferInfo.limitId != NULL);
2814
Wonsik Kimc3c53cf2020-04-15 10:39:45 -07002815 gByteBufferInfo.getPositionId = env->GetMethodID(
2816 clazz.get(), "position", "()I");
2817 CHECK(gByteBufferInfo.getPositionId != NULL);
2818
2819 gByteBufferInfo.getLimitId = env->GetMethodID(
2820 clazz.get(), "limit", "()I");
2821 CHECK(gByteBufferInfo.getLimitId != NULL);
2822
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002823 clazz.reset(env->FindClass("java/util/ArrayList"));
2824 CHECK(clazz.get() != NULL);
2825
2826 gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
2827 CHECK(gArrayListInfo.sizeId != NULL);
2828
2829 gArrayListInfo.getId = env->GetMethodID(clazz.get(), "get", "(I)Ljava/lang/Object;");
2830 CHECK(gArrayListInfo.getId != NULL);
2831
2832 gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
2833 CHECK(gArrayListInfo.addId != NULL);
2834
2835 clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
2836 CHECK(clazz.get() != NULL);
2837
2838 gLinearBlockInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2839
2840 gLinearBlockInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
2841 CHECK(gLinearBlockInfo.ctorId != NULL);
2842
2843 gLinearBlockInfo.setInternalStateId = env->GetMethodID(
2844 clazz.get(), "setInternalStateLocked", "(JZ)V");
2845 CHECK(gLinearBlockInfo.setInternalStateId != NULL);
2846
2847 gLinearBlockInfo.contextId = env->GetFieldID(clazz.get(), "mNativeContext", "J");
2848 CHECK(gLinearBlockInfo.contextId != NULL);
2849
2850 gLinearBlockInfo.validId = env->GetFieldID(clazz.get(), "mValid", "Z");
2851 CHECK(gLinearBlockInfo.validId != NULL);
2852
2853 gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2854 CHECK(gLinearBlockInfo.lockId != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002855}
2856
2857static void android_media_MediaCodec_native_setup(
2858 JNIEnv *env, jobject thiz,
2859 jstring name, jboolean nameIsType, jboolean encoder) {
2860 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002861 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002862 return;
2863 }
2864
2865 const char *tmp = env->GetStringUTFChars(name, NULL);
2866
2867 if (tmp == NULL) {
2868 return;
2869 }
2870
2871 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2872
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002873 const status_t err = codec->initCheck();
2874 if (err == NAME_NOT_FOUND) {
2875 // fail and do not try again.
2876 jniThrowException(env, "java/lang/IllegalArgumentException",
2877 String8::format("Failed to initialize %s, error %#x", tmp, err));
2878 env->ReleaseStringUTFChars(name, tmp);
2879 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07002880 } if (err == NO_MEMORY) {
2881 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2882 String8::format("Failed to initialize %s, error %#x", tmp, err));
2883 env->ReleaseStringUTFChars(name, tmp);
2884 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002885 } else if (err != OK) {
2886 // believed possible to try again
2887 jniThrowException(env, "java/io/IOException",
2888 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2889 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08002890 return;
2891 }
2892
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002893 env->ReleaseStringUTFChars(name, tmp);
2894
Andreas Huberaba67132013-10-22 12:40:01 -07002895 codec->registerSelf();
2896
Andreas Huber88572f72012-02-21 11:47:18 -08002897 setMediaCodec(env,thiz, codec);
2898}
2899
2900static void android_media_MediaCodec_native_finalize(
2901 JNIEnv *env, jobject thiz) {
Wonsik Kim89666622020-04-28 10:43:47 -07002902 setMediaCodec(env, thiz, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002903}
2904
Wonsik Kimccb7ac62019-12-27 17:12:40 -08002905// MediaCodec.LinearBlock
2906
2907static jobject android_media_MediaCodec_LinearBlock_native_map(
2908 JNIEnv *env, jobject thiz) {
2909 JMediaCodecLinearBlock *context =
2910 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2911 if (context->mBuffer) {
2912 std::shared_ptr<C2Buffer> buffer = context->mBuffer;
2913 if (!context->mReadonlyMapping) {
2914 const C2BufferData data = buffer->data();
2915 if (data.type() != C2BufferData::LINEAR) {
2916 throwExceptionAsNecessary(env, INVALID_OPERATION);
2917 return nullptr;
2918 }
2919 if (data.linearBlocks().size() != 1u) {
2920 throwExceptionAsNecessary(env, INVALID_OPERATION);
2921 return nullptr;
2922 }
2923 C2ConstLinearBlock block = data.linearBlocks().front();
2924 context->mReadonlyMapping =
2925 std::make_shared<C2ReadView>(block.map().get());
2926 }
2927 return CreateByteBuffer(
2928 env,
2929 context->mReadonlyMapping->data(), // base
2930 context->mReadonlyMapping->capacity(), // capacity
2931 0u, // offset
2932 context->mReadonlyMapping->capacity(), // size
2933 true, // readOnly
2934 true /* clearBuffer */);
2935 } else if (context->mBlock) {
2936 std::shared_ptr<C2LinearBlock> block = context->mBlock;
2937 if (!context->mReadWriteMapping) {
2938 context->mReadWriteMapping =
2939 std::make_shared<C2WriteView>(block->map().get());
2940 }
2941 return CreateByteBuffer(
2942 env,
2943 context->mReadWriteMapping->base(),
2944 context->mReadWriteMapping->capacity(),
2945 context->mReadWriteMapping->offset(),
2946 context->mReadWriteMapping->size(),
2947 false, // readOnly
2948 true /* clearBuffer */);
2949 } else if (context->mLegacyBuffer) {
2950 return CreateByteBuffer(
2951 env,
2952 context->mLegacyBuffer->base(),
2953 context->mLegacyBuffer->capacity(),
2954 context->mLegacyBuffer->offset(),
2955 context->mLegacyBuffer->size(),
2956 true, // readOnly
2957 true /* clearBuffer */);
2958 } else if (context->mHeap) {
2959 return CreateByteBuffer(
2960 env,
2961 static_cast<uint8_t *>(context->mHeap->getBase()) + context->mHeap->getOffset(),
2962 context->mHeap->getSize(),
2963 0,
2964 context->mHeap->getSize(),
2965 false, // readOnly
2966 true /* clearBuffer */);
2967 }
2968 throwExceptionAsNecessary(env, INVALID_OPERATION);
2969 return nullptr;
2970}
2971
2972static void android_media_MediaCodec_LinearBlock_native_recycle(
2973 JNIEnv *env, jobject thiz) {
2974 JMediaCodecLinearBlock *context =
2975 (JMediaCodecLinearBlock *)env->GetLongField(thiz, gLinearBlockInfo.contextId);
2976 env->CallVoidMethod(thiz, gLinearBlockInfo.setInternalStateId, 0, false);
2977 delete context;
2978}
2979
2980static void PopulateNamesVector(
2981 JNIEnv *env, jobjectArray codecNames, std::vector<std::string> *names) {
2982 jsize length = env->GetArrayLength(codecNames);
2983 for (jsize i = 0; i < length; ++i) {
2984 jstring jstr = static_cast<jstring>(env->GetObjectArrayElement(codecNames, i));
2985 if (jstr == nullptr) {
2986 // null entries are ignored
2987 continue;
2988 }
2989 const char *cstr = env->GetStringUTFChars(jstr, nullptr);
2990 if (cstr == nullptr) {
2991 throwExceptionAsNecessary(env, BAD_VALUE);
2992 return;
2993 }
2994 names->emplace_back(cstr);
2995 env->ReleaseStringUTFChars(jstr, cstr);
2996 }
2997}
2998
2999static void android_media_MediaCodec_LinearBlock_native_obtain(
3000 JNIEnv *env, jobject thiz, jint capacity, jobjectArray codecNames) {
3001 std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
3002 std::vector<std::string> names;
3003 PopulateNamesVector(env, codecNames, &names);
3004 bool hasSecure = false;
3005 bool hasNonSecure = false;
3006 for (const std::string &name : names) {
3007 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3008 hasSecure = true;
3009 } else {
3010 hasNonSecure = true;
3011 }
3012 }
3013 if (hasSecure && !hasNonSecure) {
3014 context->mHeap = new MemoryHeapBase(capacity);
3015 context->mMemory = hardware::fromHeap(context->mHeap);
3016 } else {
3017 context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
3018 if (!context->mBlock) {
3019 jniThrowException(env, "java/io/IOException", nullptr);
3020 return;
3021 }
3022 }
3023 env->CallVoidMethod(
3024 thiz,
3025 gLinearBlockInfo.setInternalStateId,
3026 (jlong)context.release(),
3027 true /* isMappable */);
3028}
3029
3030static jboolean android_media_MediaCodec_LinearBlock_checkCompatible(
Wonsik Kimad4cd5c02020-03-31 22:31:44 -07003031 JNIEnv *env, jclass, jobjectArray codecNames) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003032 std::vector<std::string> names;
3033 PopulateNamesVector(env, codecNames, &names);
3034 bool isCompatible = false;
3035 bool hasSecure = false;
3036 bool hasNonSecure = false;
3037 for (const std::string &name : names) {
3038 if (name.length() >= 7 && name.substr(name.length() - 7) == ".secure") {
3039 hasSecure = true;
3040 } else {
3041 hasNonSecure = true;
3042 }
3043 }
3044 if (hasSecure && hasNonSecure) {
3045 return false;
3046 }
3047 status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
3048 if (err != OK) {
3049 throwExceptionAsNecessary(env, err);
3050 }
3051 return isCompatible;
3052}
3053
Daniel Micay76f6a862015-09-19 17:31:01 -04003054static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07003055 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08003056
Lajos Molnar1e6e8012014-07-15 16:07:13 -07003057 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
3058
Chong Zhang8034d602015-04-28 13:38:48 -07003059 { "native_releasePersistentInputSurface",
3060 "(Landroid/view/Surface;)V",
3061 (void *)android_media_MediaCodec_releasePersistentInputSurface},
3062
3063 { "native_createPersistentInputSurface",
3064 "()Landroid/media/MediaCodec$PersistentSurface;",
3065 (void *)android_media_MediaCodec_createPersistentInputSurface },
3066
Chong Zhang9560ddb2015-05-13 10:25:29 -07003067 { "native_setInputSurface", "(Landroid/view/Surface;)V",
3068 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07003069
Lajos Molnard8578572015-06-05 20:17:33 -07003070 { "native_enableOnFrameRenderedListener", "(Z)V",
3071 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
3072
Chong Zhang8d5e5562014-07-08 18:49:21 -07003073 { "native_setCallback",
3074 "(Landroid/media/MediaCodec$Callback;)V",
3075 (void *)android_media_MediaCodec_native_setCallback },
3076
Andreas Huber88572f72012-02-21 11:47:18 -08003077 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07003078 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07003079 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003080 (void *)android_media_MediaCodec_native_configure },
3081
Lajos Molnar5e02ba92015-05-01 15:59:35 -07003082 { "native_setSurface",
3083 "(Landroid/view/Surface;)V",
3084 (void *)android_media_MediaCodec_native_setSurface },
3085
Andy McFadden2621e402013-02-19 07:29:21 -08003086 { "createInputSurface", "()Landroid/view/Surface;",
3087 (void *)android_media_MediaCodec_createInputSurface },
3088
Lajos Molnard4023112014-07-11 15:12:59 -07003089 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07003090 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07003091 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08003092
Lajos Molnard4023112014-07-11 15:12:59 -07003093 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003094 (void *)android_media_MediaCodec_queueInputBuffer },
3095
Lajos Molnard4023112014-07-11 15:12:59 -07003096 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07003097 (void *)android_media_MediaCodec_queueSecureInputBuffer },
3098
Wonsik Kim637afb22020-02-25 14:27:29 -08003099 { "native_mapHardwareBuffer",
3100 "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
3101 (void *)android_media_MediaCodec_mapHardwareBuffer },
3102
3103 { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
3104
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003105 { "native_queueLinearBlock",
3106 "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
3107 "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
3108 (void *)android_media_MediaCodec_native_queueLinearBlock },
3109
Wonsik Kim637afb22020-02-25 14:27:29 -08003110 { "native_queueHardwareBuffer",
3111 "(ILandroid/hardware/HardwareBuffer;JILjava/util/ArrayList;Ljava/util/ArrayList;)V",
3112 (void *)android_media_MediaCodec_native_queueHardwareBuffer },
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003113
3114 { "native_getOutputFrame",
3115 "(Landroid/media/MediaCodec$OutputFrame;I)V",
3116 (void *)android_media_MediaCodec_native_getOutputFrame },
3117
Lajos Molnard4023112014-07-11 15:12:59 -07003118 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003119 (void *)android_media_MediaCodec_dequeueInputBuffer },
3120
Lajos Molnard4023112014-07-11 15:12:59 -07003121 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08003122 (void *)android_media_MediaCodec_dequeueOutputBuffer },
3123
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07003124 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08003125 (void *)android_media_MediaCodec_releaseOutputBuffer },
3126
Andy McFadden2621e402013-02-19 07:29:21 -08003127 { "signalEndOfInputStream", "()V",
3128 (void *)android_media_MediaCodec_signalEndOfInputStream },
3129
Lajos Molnard4023112014-07-11 15:12:59 -07003130 { "getFormatNative", "(Z)Ljava/util/Map;",
3131 (void *)android_media_MediaCodec_getFormatNative },
3132
3133 { "getOutputFormatNative", "(I)Ljava/util/Map;",
3134 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08003135
3136 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
3137 (void *)android_media_MediaCodec_getBuffers },
3138
Lajos Molnard4023112014-07-11 15:12:59 -07003139 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
3140 (void *)android_media_MediaCodec_getBuffer },
3141
3142 { "getImage", "(ZI)Landroid/media/Image;",
3143 (void *)android_media_MediaCodec_getImage },
3144
Lajos Molnard2a7f472018-11-15 12:49:20 -08003145 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03003146 (void *)android_media_MediaCodec_getName },
3147
Chong Zhanga0b72a62018-02-28 18:46:26 -08003148 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
3149 (void *)android_media_MediaCodec_getOwnCodecInfo },
3150
Ray Essick10353e32017-04-14 10:22:55 -07003151 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08003152 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08003153
Andreas Huber226065b2013-08-12 10:14:11 -07003154 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
3155 (void *)android_media_MediaCodec_setParameters },
3156
Andreas Huberb12a5392012-04-30 14:18:33 -07003157 { "setVideoScalingMode", "(I)V",
3158 (void *)android_media_MediaCodec_setVideoScalingMode },
3159
ybai5e053202018-11-01 13:02:15 +08003160 { "native_setAudioPresentation", "(II)V",
3161 (void *)android_media_MediaCodec_setAudioPresentation },
3162
Andreas Huber88572f72012-02-21 11:47:18 -08003163 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
3164
3165 { "native_setup", "(Ljava/lang/String;ZZ)V",
3166 (void *)android_media_MediaCodec_native_setup },
3167
3168 { "native_finalize", "()V",
3169 (void *)android_media_MediaCodec_native_finalize },
3170};
3171
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003172static const JNINativeMethod gLinearBlockMethods[] = {
3173 { "native_map", "()Ljava/nio/ByteBuffer;",
3174 (void *)android_media_MediaCodec_LinearBlock_native_map },
3175
3176 { "native_recycle", "()V",
3177 (void *)android_media_MediaCodec_LinearBlock_native_recycle },
3178
3179 { "native_obtain", "(I[Ljava/lang/String;)V",
3180 (void *)android_media_MediaCodec_LinearBlock_native_obtain },
3181
3182 { "native_checkCompatible", "([Ljava/lang/String;)Z",
3183 (void *)android_media_MediaCodec_LinearBlock_checkCompatible },
3184};
3185
Andreas Huber88572f72012-02-21 11:47:18 -08003186int register_android_media_MediaCodec(JNIEnv *env) {
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003187 int result = AndroidRuntime::registerNativeMethods(env,
Andreas Huber88572f72012-02-21 11:47:18 -08003188 "android/media/MediaCodec", gMethods, NELEM(gMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003189 if (result != JNI_OK) {
3190 return result;
3191 }
3192 result = AndroidRuntime::registerNativeMethods(env,
3193 "android/media/MediaCodec$LinearBlock",
3194 gLinearBlockMethods,
3195 NELEM(gLinearBlockMethods));
Wonsik Kimccb7ac62019-12-27 17:12:40 -08003196 return result;
Andreas Huber88572f72012-02-21 11:47:18 -08003197}