blob: f07f1e8fb62b22307b463c8d5561c2326fa6e5b2 [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
21#include "android_media_MediaCodec.h"
22
Andreas Huber07ea4262012-04-11 12:21:20 -070023#include "android_media_MediaCrypto.h"
Chong Zhang2659c2f2017-04-27 13:18:20 -070024#include "android_media_MediaDescrambler.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080025#include "android_media_MediaMetricsJNI.h"
Andreas Huber88572f72012-02-21 11:47:18 -080026#include "android_media_Utils.h"
27#include "android_runtime/AndroidRuntime.h"
28#include "android_runtime/android_view_Surface.h"
Chong Zhangd5927ae2017-01-03 11:07:18 -080029#include "android_util_Binder.h"
Andreas Huber88572f72012-02-21 11:47:18 -080030#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070031#include <nativehelper/JNIHelp.h>
Chong Zhanga0b72a62018-02-28 18:46:26 -080032#include <nativehelper/ScopedLocalRef.h>
Andreas Huber88572f72012-02-21 11:47:18 -080033
Chong Zhang2659c2f2017-04-27 13:18:20 -070034#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080035
Lajos Molnar7ac4f562014-03-24 15:57:51 -070036#include <cutils/compiler.h>
37
Mathias Agopian8335f1c2012-02-25 18:48:35 -080038#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080039
Wonsik Kim4273dd02016-09-27 15:23:35 +090040#include <media/MediaCodecBuffer.h>
Andreas Huber88572f72012-02-21 11:47:18 -080041#include <media/stagefright/MediaCodec.h>
42#include <media/stagefright/foundation/ABuffer.h>
43#include <media/stagefright/foundation/ADebug.h>
44#include <media/stagefright/foundation/ALooper.h>
45#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070046#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080047#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070048#include <media/stagefright/PersistentSurface.h>
Jeff Tinkercd4d28f2018-02-16 16:24:49 -080049#include <mediadrm/ICrypto.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070050#include <nativehelper/ScopedLocalRef.h>
51
Andreas Huberb12a5392012-04-30 14:18:33 -070052#include <system/window.h>
53
Andreas Huber88572f72012-02-21 11:47:18 -080054namespace android {
55
56// Keep these in sync with their equivalents in MediaCodec.java !!!
57enum {
58 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
59 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
60 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
61};
62
Andreas Huberaba67132013-10-22 12:40:01 -070063enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070064 EVENT_CALLBACK = 1,
65 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070066 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070067};
68
Andy Hung5f9aa0b2014-07-30 15:48:21 -070069static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070070 jint cryptoErrorNoKey;
71 jint cryptoErrorKeyExpired;
72 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070073 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070074 jint cryptoErrorSessionNotOpened;
Jeff Tinker20594d82018-12-12 08:31:22 -080075 jint cryptoErrorInsufficientSecurity;
Jeff Tinkerd3932162016-03-05 11:35:20 -080076 jint cryptoErrorUnsupportedOperation;
Jeff Tinker20594d82018-12-12 08:31:22 -080077 jint cryptoErrorFrameTooLarge;
78 jint cryptoErrorLostState;
Jeff Tinker3ed38262013-08-02 23:24:51 -070079} gCryptoErrorCodes;
80
Andy Hung5f9aa0b2014-07-30 15:48:21 -070081static struct CodecActionCodes {
82 jint codecActionTransient;
83 jint codecActionRecoverable;
84} gCodecActionCodes;
85
Ronghua Wuc53ad692015-05-08 14:40:49 -070086static struct CodecErrorCodes {
87 jint errorInsufficientResource;
88 jint errorReclaimed;
89} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -070090
Chong Zhang8034d602015-04-28 13:38:48 -070091static struct {
92 jclass clazz;
93 jfieldID mLock;
94 jfieldID mPersistentObject;
95 jmethodID ctor;
96 jmethodID setNativeObjectLocked;
97} gPersistentSurfaceClassInfo;
98
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -080099static struct {
100 jint Unencrypted;
101 jint AesCtr;
102 jint AesCbc;
103} gCryptoModes;
104
Chong Zhanga0b72a62018-02-28 18:46:26 -0800105static struct {
106 jclass capsClazz;
107 jmethodID capsCtorId;
108 jclass profileLevelClazz;
109 jfieldID profileField;
110 jfieldID levelField;
111} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800112
Andreas Huber88572f72012-02-21 11:47:18 -0800113struct fields_t {
Andreas Huberaba67132013-10-22 12:40:01 -0700114 jmethodID postEventFromNativeID;
Wonsik Kim61796fd2018-09-13 13:15:59 -0700115 jmethodID lockAndGetContextID;
116 jmethodID setAndUnlockContextID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700117 jfieldID cryptoInfoNumSubSamplesID;
118 jfieldID cryptoInfoNumBytesOfClearDataID;
119 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
120 jfieldID cryptoInfoKeyID;
121 jfieldID cryptoInfoIVID;
122 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800123 jfieldID cryptoInfoPatternID;
124 jfieldID patternEncryptBlocksID;
125 jfieldID patternSkipBlocksID;
Andreas Huber88572f72012-02-21 11:47:18 -0800126};
127
128static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700129static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800130
131////////////////////////////////////////////////////////////////////////////////
132
133JMediaCodec::JMediaCodec(
134 JNIEnv *env, jobject thiz,
135 const char *name, bool nameIsType, bool encoder)
136 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700137 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800138 jclass clazz = env->GetObjectClass(thiz);
139 CHECK(clazz != NULL);
140
141 mClass = (jclass)env->NewGlobalRef(clazz);
142 mObject = env->NewWeakGlobalRef(thiz);
143
Lajos Molnar7de28d32014-07-25 07:51:02 -0700144 cacheJavaObjects(env);
145
Andreas Huber88572f72012-02-21 11:47:18 -0800146 mLooper = new ALooper;
147 mLooper->setName("MediaCodec_looper");
148
149 mLooper->start(
150 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700151 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700152 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800153
154 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700155 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800156 if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
157 mNameAtCreation = "(null)";
158 }
Andreas Huber88572f72012-02-21 11:47:18 -0800159 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700160 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Lajos Molnare7473872019-02-05 18:54:27 -0800161 mNameAtCreation = name;
Andreas Huber88572f72012-02-21 11:47:18 -0800162 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700163 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800164}
165
Lajos Molnar7de28d32014-07-25 07:51:02 -0700166void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
167 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
168 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
169 CHECK(mByteBufferClass != NULL);
170
171 ScopedLocalRef<jclass> byteOrderClass(
172 env, env->FindClass("java/nio/ByteOrder"));
173 CHECK(byteOrderClass.get() != NULL);
174
175 jmethodID nativeOrderID = env->GetStaticMethodID(
176 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
177 CHECK(nativeOrderID != NULL);
178
179 jobject nativeByteOrderObj =
180 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
181 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
182 CHECK(mNativeByteOrderObj != NULL);
183 env->DeleteLocalRef(nativeByteOrderObj);
184 nativeByteOrderObj = NULL;
185
186 mByteBufferOrderMethodID = env->GetMethodID(
187 mByteBufferClass,
188 "order",
189 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
190 CHECK(mByteBufferOrderMethodID != NULL);
191
192 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
193 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
194 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
195
196 mByteBufferPositionMethodID = env->GetMethodID(
197 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
198 CHECK(mByteBufferPositionMethodID != NULL);
199
200 mByteBufferLimitMethodID = env->GetMethodID(
201 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
202 CHECK(mByteBufferLimitMethodID != NULL);
203}
204
Andreas Huber88572f72012-02-21 11:47:18 -0800205status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700206 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800207}
208
Andreas Huberaba67132013-10-22 12:40:01 -0700209void JMediaCodec::registerSelf() {
210 mLooper->registerHandler(this);
211}
212
Chong Zhang128b0122014-03-01 18:04:13 -0800213void JMediaCodec::release() {
Martin Storsjod932de92012-07-13 13:01:06 +0300214 if (mCodec != NULL) {
215 mCodec->release();
216 mCodec.clear();
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700217 mInitStatus = NO_INIT;
Martin Storsjod932de92012-07-13 13:01:06 +0300218 }
Andreas Huber88572f72012-02-21 11:47:18 -0800219
Chong Zhang128b0122014-03-01 18:04:13 -0800220 if (mLooper != NULL) {
221 mLooper->unregisterHandler(id());
222 mLooper->stop();
223 mLooper.clear();
224 }
225}
226
227JMediaCodec::~JMediaCodec() {
228 if (mCodec != NULL || mLooper != NULL) {
229 /* MediaCodec and looper should have been released explicitly already
230 * in setMediaCodec() (see comments in setMediaCodec()).
231 *
232 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
233 * message handler, doing release() there risks deadlock as MediaCodec::
234 * release() post synchronous message to the same looper.
235 *
236 * Print a warning and try to proceed with releasing.
237 */
238 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
239 release();
240 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
241 }
242
Andreas Huber88572f72012-02-21 11:47:18 -0800243 JNIEnv *env = AndroidRuntime::getJNIEnv();
244
245 env->DeleteWeakGlobalRef(mObject);
246 mObject = NULL;
247 env->DeleteGlobalRef(mClass);
248 mClass = NULL;
Lajos Molnar7de28d32014-07-25 07:51:02 -0700249 deleteJavaObjects(env);
250}
251
252void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
253 env->DeleteGlobalRef(mByteBufferClass);
254 mByteBufferClass = NULL;
255 env->DeleteGlobalRef(mNativeByteOrderObj);
256 mNativeByteOrderObj = NULL;
257
258 mByteBufferOrderMethodID = NULL;
259 mByteBufferAsReadOnlyBufferMethodID = NULL;
260 mByteBufferPositionMethodID = NULL;
261 mByteBufferLimitMethodID = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800262}
263
Lajos Molnard8578572015-06-05 20:17:33 -0700264status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
265 if (enable) {
266 if (mOnFrameRenderedNotification == NULL) {
267 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
268 }
269 } else {
270 mOnFrameRenderedNotification.clear();
271 }
272
273 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
274}
275
Chong Zhang8d5e5562014-07-08 18:49:21 -0700276status_t JMediaCodec::setCallback(jobject cb) {
277 if (cb != NULL) {
278 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800279 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700280 }
281 } else {
282 mCallbackNotification.clear();
283 }
284
285 return mCodec->setCallback(mCallbackNotification);
286}
287
Andreas Huber88572f72012-02-21 11:47:18 -0800288status_t JMediaCodec::configure(
289 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800290 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700291 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800292 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800293 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800294 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800295 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700296 mSurfaceTextureClient =
297 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700298 } else {
299 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800300 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700301
Chong Zhangd5927ae2017-01-03 11:07:18 -0800302 return mCodec->configure(
303 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800304}
305
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700306status_t JMediaCodec::setSurface(
307 const sp<IGraphicBufferProducer> &bufferProducer) {
308 sp<Surface> client;
309 if (bufferProducer != NULL) {
310 client = new Surface(bufferProducer, true /* controlledByApp */);
311 }
312 status_t err = mCodec->setSurface(client);
313 if (err == OK) {
314 mSurfaceTextureClient = client;
315 }
316 return err;
317}
318
Andy McFadden2621e402013-02-19 07:29:21 -0800319status_t JMediaCodec::createInputSurface(
320 sp<IGraphicBufferProducer>* bufferProducer) {
321 return mCodec->createInputSurface(bufferProducer);
322}
323
Chong Zhang9560ddb2015-05-13 10:25:29 -0700324status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700325 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700326 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700327}
328
Andreas Huber88572f72012-02-21 11:47:18 -0800329status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700330 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800331}
332
333status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700334 mSurfaceTextureClient.clear();
335
Chong Zhang8d5e5562014-07-08 18:49:21 -0700336 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800337}
338
339status_t JMediaCodec::flush() {
340 return mCodec->flush();
341}
342
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700343status_t JMediaCodec::reset() {
344 return mCodec->reset();
345}
346
Andreas Huber88572f72012-02-21 11:47:18 -0800347status_t JMediaCodec::queueInputBuffer(
348 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700349 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
350 AString *errorDetailMsg) {
351 return mCodec->queueInputBuffer(
352 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800353}
354
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700355status_t JMediaCodec::queueSecureInputBuffer(
356 size_t index,
357 size_t offset,
358 const CryptoPlugin::SubSample *subSamples,
359 size_t numSubSamples,
360 const uint8_t key[16],
361 const uint8_t iv[16],
362 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800363 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700364 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700365 uint32_t flags,
366 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700367 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800368 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700369 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700370}
371
Andreas Huber88572f72012-02-21 11:47:18 -0800372status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700373 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800374}
375
376status_t JMediaCodec::dequeueOutputBuffer(
377 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
378 size_t size, offset;
379 int64_t timeUs;
380 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700381 status_t err = mCodec->dequeueOutputBuffer(
382 index, &offset, &size, &timeUs, &flags, timeoutUs);
383
Andreas Huberaba67132013-10-22 12:40:01 -0700384 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800385 return err;
386 }
387
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700388 ScopedLocalRef<jclass> clazz(
389 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800390
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700391 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000392 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800393
394 return OK;
395}
396
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700397status_t JMediaCodec::releaseOutputBuffer(
398 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
399 if (updatePTS) {
400 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
401 }
Andreas Huber88572f72012-02-21 11:47:18 -0800402 return render
403 ? mCodec->renderOutputBufferAndRelease(index)
404 : mCodec->releaseOutputBuffer(index);
405}
406
Andy McFadden2621e402013-02-19 07:29:21 -0800407status_t JMediaCodec::signalEndOfInputStream() {
408 return mCodec->signalEndOfInputStream();
409}
410
Lajos Molnard4023112014-07-11 15:12:59 -0700411status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800412 sp<AMessage> msg;
413 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700414 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
415 if (err != OK) {
416 return err;
417 }
418
419 return ConvertMessageToMap(env, msg, format);
420}
421
422status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
423 sp<AMessage> msg;
424 status_t err;
425 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800426 return err;
427 }
428
429 return ConvertMessageToMap(env, msg, format);
430}
431
432status_t JMediaCodec::getBuffers(
433 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900434 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800435
436 status_t err =
437 input
438 ? mCodec->getInputBuffers(&buffers)
439 : mCodec->getOutputBuffers(&buffers);
440
441 if (err != OK) {
442 return err;
443 }
444
Andreas Huber88572f72012-02-21 11:47:18 -0800445 *bufArray = (jobjectArray)env->NewObjectArray(
Lajos Molnar7de28d32014-07-25 07:51:02 -0700446 buffers.size(), mByteBufferClass, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800447 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800448 return NO_MEMORY;
449 }
Andreas Huber88572f72012-02-21 11:47:18 -0800450
451 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900452 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800453
Lajos Molnar7de28d32014-07-25 07:51:02 -0700454 jobject byteBuffer = NULL;
455 err = createByteBufferFromABuffer(
456 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
457 if (err != OK) {
458 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800459 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700460 if (byteBuffer != NULL) {
461 env->SetObjectArrayElement(
462 *bufArray, i, byteBuffer);
463
Lajos Molnard4023112014-07-11 15:12:59 -0700464 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700465 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700466 }
Andreas Huber88572f72012-02-21 11:47:18 -0800467 }
468
Lajos Molnar7de28d32014-07-25 07:51:02 -0700469 return OK;
470}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700471
Lajos Molnar7de28d32014-07-25 07:51:02 -0700472// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900473template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700474status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900475 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700476 jobject *buf) const {
477 // if this is an ABuffer that doesn't actually hold any accessible memory,
478 // use a null ByteBuffer
479 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700480
481 if (buffer == NULL) {
482 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
483 return OK;
484 }
485
Lajos Molnar7de28d32014-07-25 07:51:02 -0700486 if (buffer->base() == NULL) {
487 return OK;
488 }
489
490 jobject byteBuffer =
491 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
492 if (readOnly && byteBuffer != NULL) {
493 jobject readOnlyBuffer = env->CallObjectMethod(
494 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
495 env->DeleteLocalRef(byteBuffer);
496 byteBuffer = readOnlyBuffer;
497 }
498 if (byteBuffer == NULL) {
499 return NO_MEMORY;
500 }
501 jobject me = env->CallObjectMethod(
502 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
503 env->DeleteLocalRef(me);
504 me = env->CallObjectMethod(
505 byteBuffer, mByteBufferLimitMethodID,
506 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
507 env->DeleteLocalRef(me);
508 me = env->CallObjectMethod(
509 byteBuffer, mByteBufferPositionMethodID,
510 clearBuffer ? 0 : buffer->offset());
511 env->DeleteLocalRef(me);
512 me = NULL;
513
514 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800515 return OK;
516}
517
Lajos Molnard4023112014-07-11 15:12:59 -0700518status_t JMediaCodec::getBuffer(
519 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900520 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700521
522 status_t err =
523 input
524 ? mCodec->getInputBuffer(index, &buffer)
525 : mCodec->getOutputBuffer(index, &buffer);
526
527 if (err != OK) {
528 return err;
529 }
530
Lajos Molnar7de28d32014-07-25 07:51:02 -0700531 return createByteBufferFromABuffer(
532 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700533}
534
535status_t JMediaCodec::getImage(
536 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900537 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700538
539 status_t err =
540 input
541 ? mCodec->getInputBuffer(index, &buffer)
542 : mCodec->getOutputBuffer(index, &buffer);
543
544 if (err != OK) {
545 return err;
546 }
547
548 // if this is an ABuffer that doesn't actually hold any accessible memory,
549 // use a null ByteBuffer
550 *buf = NULL;
551 if (buffer->base() == NULL) {
552 return OK;
553 }
554
555 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700556 sp<ABuffer> imageData;
557 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700558 return OK;
559 }
560
Lajos Molnar7de28d32014-07-25 07:51:02 -0700561 int64_t timestamp = 0;
562 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
563 timestamp *= 1000; // adjust to ns
564 }
565
566 jobject byteBuffer = NULL;
567 err = createByteBufferFromABuffer(
568 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
569 if (err != OK) {
570 return OK;
571 }
572
573 jobject infoBuffer = NULL;
574 err = createByteBufferFromABuffer(
575 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
576 if (err != OK) {
577 env->DeleteLocalRef(byteBuffer);
578 byteBuffer = NULL;
579 return OK;
580 }
581
582 jobject cropRect = NULL;
583 int32_t left, top, right, bottom;
584 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
585 ScopedLocalRef<jclass> rectClazz(
586 env, env->FindClass("android/graphics/Rect"));
587 CHECK(rectClazz.get() != NULL);
588
589 jmethodID rectConstructID = env->GetMethodID(
590 rectClazz.get(), "<init>", "(IIII)V");
591
592 cropRect = env->NewObject(
593 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
594 }
595
596 ScopedLocalRef<jclass> imageClazz(
597 env, env->FindClass("android/media/MediaCodec$MediaImage"));
598 CHECK(imageClazz.get() != NULL);
599
600 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
601 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
602
603 *buf = env->NewObject(imageClazz.get(), imageConstructID,
604 byteBuffer, infoBuffer,
605 (jboolean)!input /* readOnly */,
606 (jlong)timestamp,
607 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
608
609 // if MediaImage creation fails, return null
610 if (env->ExceptionCheck()) {
611 env->ExceptionDescribe();
612 env->ExceptionClear();
613 *buf = NULL;
614 }
615
616 if (cropRect != NULL) {
617 env->DeleteLocalRef(cropRect);
618 cropRect = NULL;
619 }
620
621 env->DeleteLocalRef(byteBuffer);
622 byteBuffer = NULL;
623
624 env->DeleteLocalRef(infoBuffer);
625 infoBuffer = NULL;
626
Lajos Molnard4023112014-07-11 15:12:59 -0700627 return OK;
628}
629
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300630status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
631 AString name;
632
633 status_t err = mCodec->getName(&name);
634
635 if (err != OK) {
636 return err;
637 }
638
639 *nameStr = env->NewStringUTF(name.c_str());
640
641 return OK;
642}
643
Chong Zhanga0b72a62018-02-28 18:46:26 -0800644static jobject getCodecCapabilitiesObject(
645 JNIEnv *env, const char *mime, bool isEncoder,
646 const sp<MediaCodecInfo::Capabilities> &capabilities) {
647 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
648 Vector<uint32_t> colorFormats;
649
650 sp<AMessage> defaultFormat = new AMessage();
651 defaultFormat->setString("mime", mime);
652
653 capabilities->getSupportedColorFormats(&colorFormats);
654 capabilities->getSupportedProfileLevels(&profileLevels);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800655 sp<AMessage> details = capabilities->getDetails();
656
657 jobject defaultFormatObj = NULL;
658 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
659 return NULL;
660 }
661 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
662
663 jobject detailsObj = NULL;
664 if (ConvertMessageToMap(env, details, &detailsObj)) {
665 return NULL;
666 }
667 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
668
669 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
670 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
671
672 for (size_t i = 0; i < profileLevels.size(); ++i) {
673 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
674
675 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
676 gCodecInfo.profileLevelClazz));
677
678 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
679 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
680
681 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
682 }
683
684 ScopedLocalRef<jintArray> colorFormatsArray(
685 env, env->NewIntArray(colorFormats.size()));
686 for (size_t i = 0; i < colorFormats.size(); ++i) {
687 jint val = colorFormats.itemAt(i);
688 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
689 }
690
691 return env->NewObject(
692 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800693 profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
Chong Zhanga0b72a62018-02-28 18:46:26 -0800694 defaultFormatRef.get(), detailsRef.get());
695}
696
697status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
698 sp<MediaCodecInfo> codecInfo;
699
700 status_t err = mCodec->getCodecInfo(&codecInfo);
701
702 if (err != OK) {
703 return err;
704 }
705
706 ScopedLocalRef<jstring> nameObject(env,
Lajos Molnare7473872019-02-05 18:54:27 -0800707 env->NewStringUTF(mNameAtCreation.c_str()));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800708
Lajos Molnard2a7f472018-11-15 12:49:20 -0800709 ScopedLocalRef<jstring> canonicalNameObject(env,
710 env->NewStringUTF(codecInfo->getCodecName()));
711
712 MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
Chong Zhanga0b72a62018-02-28 18:46:26 -0800713 bool isEncoder = codecInfo->isEncoder();
714
Lajos Molnard2a7f472018-11-15 12:49:20 -0800715 Vector<AString> mediaTypes;
716 codecInfo->getSupportedMediaTypes(&mediaTypes);
Chong Zhanga0b72a62018-02-28 18:46:26 -0800717
718 ScopedLocalRef<jobjectArray> capsArrayObj(env,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800719 env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800720
Lajos Molnard2a7f472018-11-15 12:49:20 -0800721 for (size_t i = 0; i < mediaTypes.size(); i++) {
Chong Zhanga0b72a62018-02-28 18:46:26 -0800722 const sp<MediaCodecInfo::Capabilities> caps =
Lajos Molnard2a7f472018-11-15 12:49:20 -0800723 codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800724
725 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
Lajos Molnard2a7f472018-11-15 12:49:20 -0800726 env, mediaTypes[i].c_str(), isEncoder, caps));
Chong Zhanga0b72a62018-02-28 18:46:26 -0800727
728 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
729 }
730
731 ScopedLocalRef<jclass> codecInfoClazz(env,
732 env->FindClass("android/media/MediaCodecInfo"));
733 CHECK(codecInfoClazz.get() != NULL);
734
735 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
Lajos Molnarb864a792019-01-17 16:26:22 -0800736 "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
Chong Zhanga0b72a62018-02-28 18:46:26 -0800737
738 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800739 nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
Chong Zhanga0b72a62018-02-28 18:46:26 -0800740
741 return OK;
742}
743
Ray Essickf2d0e402017-03-09 10:17:51 -0800744status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
Ray Essick0e0fee12017-01-25 18:01:56 -0800745
746 status_t status = mCodec->getMetrics(reply);
747 return status;
748}
749
Andreas Huber226065b2013-08-12 10:14:11 -0700750status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
751 return mCodec->setParameters(msg);
752}
753
Andreas Huberb12a5392012-04-30 14:18:33 -0700754void JMediaCodec::setVideoScalingMode(int mode) {
755 if (mSurfaceTextureClient != NULL) {
Lajos Molnar832939e2018-05-23 14:58:26 -0700756 // this works for components that queue to surface
Andreas Huberb12a5392012-04-30 14:18:33 -0700757 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
Lajos Molnar832939e2018-05-23 14:58:26 -0700758 // also signal via param for components that queue to IGBP
759 sp<AMessage> msg = new AMessage;
760 msg->setInt32("android._video-scaling", mode);
761 (void)mCodec->setParameters(msg);
Andreas Huberb12a5392012-04-30 14:18:33 -0700762 }
763}
764
ybai5e053202018-11-01 13:02:15 +0800765void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const int32_t programId) {
766 sp<AMessage> msg = new AMessage;
767 msg->setInt32("audio-presentation-presentation-id", presentationId);
768 msg->setInt32("audio-presentation-program-id", programId);
769 (void)mCodec->setParameters(msg);
770}
771
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700772static jthrowable createCodecException(
773 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
774 ScopedLocalRef<jclass> clazz(
775 env, env->FindClass("android/media/MediaCodec$CodecException"));
776 CHECK(clazz.get() != NULL);
777
Ronghua Wuc53ad692015-05-08 14:40:49 -0700778 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700779 CHECK(ctor != NULL);
780
781 ScopedLocalRef<jstring> msgObj(
782 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
783
784 // translate action code to Java equivalent
785 switch (actionCode) {
786 case ACTION_CODE_TRANSIENT:
787 actionCode = gCodecActionCodes.codecActionTransient;
788 break;
789 case ACTION_CODE_RECOVERABLE:
790 actionCode = gCodecActionCodes.codecActionRecoverable;
791 break;
792 default:
793 actionCode = 0; // everything else is fatal
794 break;
795 }
796
Ronghua Wuc53ad692015-05-08 14:40:49 -0700797 /* translate OS errors to Java API CodecException errorCodes */
798 switch (err) {
799 case NO_MEMORY:
800 err = gCodecErrorCodes.errorInsufficientResource;
801 break;
802 case DEAD_OBJECT:
803 err = gCodecErrorCodes.errorReclaimed;
804 break;
805 default: /* Other error codes go out as is. */
806 break;
807 }
808
809 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700810}
811
Chong Zhang8d5e5562014-07-08 18:49:21 -0700812void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
813 int32_t arg1, arg2 = 0;
814 jobject obj = NULL;
815 CHECK(msg->findInt32("callbackID", &arg1));
816 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700817
Chong Zhang8d5e5562014-07-08 18:49:21 -0700818 switch (arg1) {
819 case MediaCodec::CB_INPUT_AVAILABLE:
820 {
821 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700822 break;
823 }
824
Chong Zhang8d5e5562014-07-08 18:49:21 -0700825 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700826 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700827 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700828
Chong Zhang8d5e5562014-07-08 18:49:21 -0700829 size_t size, offset;
830 int64_t timeUs;
831 uint32_t flags;
832 CHECK(msg->findSize("size", &size));
833 CHECK(msg->findSize("offset", &offset));
834 CHECK(msg->findInt64("timeUs", &timeUs));
835 CHECK(msg->findInt32("flags", (int32_t *)&flags));
836
837 ScopedLocalRef<jclass> clazz(
838 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
839 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
840 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
841
842 obj = env->NewObject(clazz.get(), ctor);
843
844 if (obj == NULL) {
845 if (env->ExceptionCheck()) {
846 ALOGE("Could not create MediaCodec.BufferInfo.");
847 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700848 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700849 jniThrowException(env, "java/lang/IllegalStateException", NULL);
850 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700851 }
852
Chong Zhang8d5e5562014-07-08 18:49:21 -0700853 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
854 break;
855 }
856
857 case MediaCodec::CB_ERROR:
858 {
Chong Zhang94686d12014-07-11 15:53:58 -0700859 int32_t err, actionCode;
860 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -0700861 CHECK(msg->findInt32("actionCode", &actionCode));
862
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700863 // note that DRM errors could conceivably alias into a CodecException
864 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700865
866 if (obj == NULL) {
867 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -0700868 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -0700869 env->ExceptionClear();
870 }
871 jniThrowException(env, "java/lang/IllegalStateException", NULL);
872 return;
873 }
Andreas Huberaba67132013-10-22 12:40:01 -0700874
875 break;
876 }
877
Chong Zhang8d5e5562014-07-08 18:49:21 -0700878 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -0700879 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700880 sp<AMessage> format;
881 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -0700882
Chong Zhang8d5e5562014-07-08 18:49:21 -0700883 if (OK != ConvertMessageToMap(env, format, &obj)) {
884 jniThrowException(env, "java/lang/IllegalStateException", NULL);
885 return;
886 }
Andreas Huberaba67132013-10-22 12:40:01 -0700887
Andreas Huberaba67132013-10-22 12:40:01 -0700888 break;
889 }
890
891 default:
892 TRESPASS();
893 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700894
895 env->CallVoidMethod(
896 mObject,
897 gFields.postEventFromNativeID,
898 EVENT_CALLBACK,
899 arg1,
900 arg2,
901 obj);
902
903 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -0700904}
905
Lajos Molnard8578572015-06-05 20:17:33 -0700906void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
907 int32_t arg1 = 0, arg2 = 0;
908 jobject obj = NULL;
909 JNIEnv *env = AndroidRuntime::getJNIEnv();
910
911 sp<AMessage> data;
912 CHECK(msg->findMessage("data", &data));
913
914 status_t err = ConvertMessageToMap(env, data, &obj);
915 if (err != OK) {
916 jniThrowException(env, "java/lang/IllegalStateException", NULL);
917 return;
918 }
919
920 env->CallVoidMethod(
921 mObject, gFields.postEventFromNativeID,
922 EVENT_FRAME_RENDERED, arg1, arg2, obj);
923
924 env->DeleteLocalRef(obj);
925}
926
Chong Zhang8d5e5562014-07-08 18:49:21 -0700927void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
928 switch (msg->what()) {
929 case kWhatCallbackNotify:
930 {
931 handleCallback(msg);
932 break;
933 }
Lajos Molnard8578572015-06-05 20:17:33 -0700934 case kWhatFrameRendered:
935 {
936 handleFrameRenderedNotification(msg);
937 break;
938 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700939 default:
940 TRESPASS();
941 }
Andreas Huberaba67132013-10-22 12:40:01 -0700942}
943
Andreas Huber88572f72012-02-21 11:47:18 -0800944} // namespace android
945
946////////////////////////////////////////////////////////////////////////////////
947
948using namespace android;
949
950static sp<JMediaCodec> setMediaCodec(
951 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Wonsik Kim61796fd2018-09-13 13:15:59 -0700952 sp<JMediaCodec> old = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
Andreas Huber88572f72012-02-21 11:47:18 -0800953 if (codec != NULL) {
954 codec->incStrong(thiz);
955 }
956 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800957 /* release MediaCodec and stop the looper now before decStrong.
958 * otherwise JMediaCodec::~JMediaCodec() could be called from within
959 * its message handler, doing release() from there will deadlock
960 * (as MediaCodec::release() post synchronous message to the same looper)
961 */
962 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -0800963 old->decStrong(thiz);
964 }
Wonsik Kim61796fd2018-09-13 13:15:59 -0700965 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -0800966
967 return old;
968}
969
970static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Wonsik Kim61796fd2018-09-13 13:15:59 -0700971 sp<JMediaCodec> codec = (JMediaCodec *)env->CallLongMethod(thiz, gFields.lockAndGetContextID);
972 env->CallVoidMethod(thiz, gFields.setAndUnlockContextID, (jlong)codec.get());
973 return codec;
Andreas Huber88572f72012-02-21 11:47:18 -0800974}
975
976static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
977 setMediaCodec(env, thiz, NULL);
978}
979
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700980static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
981 jthrowable exception = createCodecException(env, err, actionCode, msg);
982 env->Throw(exception);
983}
984
Andreas Huberbfc56f42012-04-19 12:47:07 -0700985static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700986 ScopedLocalRef<jclass> clazz(
987 env, env->FindClass("android/media/MediaCodec$CryptoException"));
988 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700989
990 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700991 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -0700992 CHECK(constructID != NULL);
993
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800994 const char *defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -0700995
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700996 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700997 switch (err) {
998 case ERROR_DRM_NO_LICENSE:
999 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001000 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001001 break;
1002 case ERROR_DRM_LICENSE_EXPIRED:
1003 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001004 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001005 break;
1006 case ERROR_DRM_RESOURCE_BUSY:
1007 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001008 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -07001009 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001010 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
1011 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001012 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001013 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -07001014 case ERROR_DRM_SESSION_NOT_OPENED:
1015 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001016 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -07001017 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001018 case ERROR_DRM_INSUFFICIENT_SECURITY:
1019 err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
1020 defaultMsg = "Required security level is not met";
1021 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -08001022 case ERROR_DRM_CANNOT_HANDLE:
1023 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
1024 defaultMsg = "Operation not supported in this configuration";
1025 break;
Jeff Tinker20594d82018-12-12 08:31:22 -08001026 case ERROR_DRM_FRAME_TOO_LARGE:
1027 err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
1028 defaultMsg = "Decrytped frame exceeds size of output buffer";
1029 break;
1030 case ERROR_DRM_SESSION_LOST_STATE:
1031 err = gCryptoErrorCodes.cryptoErrorLostState;
1032 defaultMsg = "Session state was lost, open a new session and retry";
1033 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001034 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -07001035 break;
1036 }
1037
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001038 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
1039
Andreas Huberbfc56f42012-04-19 12:47:07 -07001040 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001041 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001042
1043 env->Throw(exception);
1044}
1045
1046static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001047 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1048 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001049 switch (err) {
1050 case OK:
1051 return 0;
1052
1053 case -EAGAIN:
1054 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1055
1056 case INFO_FORMAT_CHANGED:
1057 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1058
1059 case INFO_OUTPUT_BUFFERS_CHANGED:
1060 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1061
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001062 case INVALID_OPERATION:
1063 jniThrowException(env, "java/lang/IllegalStateException", msg);
1064 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001065
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001066 case BAD_VALUE:
1067 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1068 return 0;
1069
Andreas Huber88572f72012-02-21 11:47:18 -08001070 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001071 if (isCryptoError(err)) {
1072 throwCryptoException(env, err, msg);
1073 return 0;
1074 }
1075 throwCodecException(env, err, actionCode, msg);
1076 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001077 }
Andreas Huber88572f72012-02-21 11:47:18 -08001078}
1079
Lajos Molnard8578572015-06-05 20:17:33 -07001080static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1081 JNIEnv *env,
1082 jobject thiz,
1083 jboolean enabled) {
1084 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1085
1086 if (codec == NULL) {
1087 throwExceptionAsNecessary(env, INVALID_OPERATION);
1088 return;
1089 }
1090
1091 status_t err = codec->enableOnFrameRenderedListener(enabled);
1092
1093 throwExceptionAsNecessary(env, err);
1094}
1095
Chong Zhang8d5e5562014-07-08 18:49:21 -07001096static void android_media_MediaCodec_native_setCallback(
1097 JNIEnv *env,
1098 jobject thiz,
1099 jobject cb) {
1100 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1101
1102 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001103 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001104 return;
1105 }
1106
1107 status_t err = codec->setCallback(cb);
1108
1109 throwExceptionAsNecessary(env, err);
1110}
1111
Andreas Huber88572f72012-02-21 11:47:18 -08001112static void android_media_MediaCodec_native_configure(
1113 JNIEnv *env,
1114 jobject thiz,
1115 jobjectArray keys, jobjectArray values,
1116 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001117 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001118 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001119 jint flags) {
1120 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1121
1122 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001123 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001124 return;
1125 }
1126
1127 sp<AMessage> format;
1128 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1129
1130 if (err != OK) {
1131 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1132 return;
1133 }
1134
Andy McFaddend47f7d82012-12-18 09:48:38 -08001135 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001136 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001137 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001138 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001139 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001140 } else {
1141 jniThrowException(
1142 env,
1143 "java/lang/IllegalArgumentException",
1144 "The surface has been released");
1145 return;
1146 }
1147 }
1148
Andreas Huber8240d922012-04-04 14:06:32 -07001149 sp<ICrypto> crypto;
1150 if (jcrypto != NULL) {
1151 crypto = JCrypto::GetCrypto(env, jcrypto);
1152 }
1153
Chong Zhangd5927ae2017-01-03 11:07:18 -08001154 sp<IDescrambler> descrambler;
1155 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001156 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001157 }
1158
1159 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001160
1161 throwExceptionAsNecessary(env, err);
1162}
1163
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001164static void android_media_MediaCodec_native_setSurface(
1165 JNIEnv *env,
1166 jobject thiz,
1167 jobject jsurface) {
1168 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1169
1170 if (codec == NULL) {
1171 throwExceptionAsNecessary(env, INVALID_OPERATION);
1172 return;
1173 }
1174
1175 sp<IGraphicBufferProducer> bufferProducer;
1176 if (jsurface != NULL) {
1177 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1178 if (surface != NULL) {
1179 bufferProducer = surface->getIGraphicBufferProducer();
1180 } else {
1181 jniThrowException(
1182 env,
1183 "java/lang/IllegalArgumentException",
1184 "The surface has been released");
1185 return;
1186 }
1187 }
1188
1189 status_t err = codec->setSurface(bufferProducer);
1190 throwExceptionAsNecessary(env, err);
1191}
1192
Chong Zhang8034d602015-04-28 13:38:48 -07001193sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1194 JNIEnv* env, jobject object) {
1195 sp<PersistentSurface> persistentSurface;
1196
1197 jobject lock = env->GetObjectField(
1198 object, gPersistentSurfaceClassInfo.mLock);
1199 if (env->MonitorEnter(lock) == JNI_OK) {
1200 persistentSurface = reinterpret_cast<PersistentSurface *>(
1201 env->GetLongField(object,
1202 gPersistentSurfaceClassInfo.mPersistentObject));
1203 env->MonitorExit(lock);
1204 }
1205 env->DeleteLocalRef(lock);
1206
1207 return persistentSurface;
1208}
1209
1210static jobject android_media_MediaCodec_createPersistentInputSurface(
1211 JNIEnv* env, jclass /* clazz */) {
1212 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1213 sp<PersistentSurface> persistentSurface =
1214 MediaCodec::CreatePersistentInputSurface();
1215
1216 if (persistentSurface == NULL) {
1217 return NULL;
1218 }
1219
1220 sp<Surface> surface = new Surface(
1221 persistentSurface->getBufferProducer(), true);
1222 if (surface == NULL) {
1223 return NULL;
1224 }
1225
1226 jobject object = env->NewObject(
1227 gPersistentSurfaceClassInfo.clazz,
1228 gPersistentSurfaceClassInfo.ctor);
1229
1230 if (object == NULL) {
1231 if (env->ExceptionCheck()) {
1232 ALOGE("Could not create PersistentSurface.");
1233 env->ExceptionClear();
1234 }
1235 return NULL;
1236 }
1237
1238 jobject lock = env->GetObjectField(
1239 object, gPersistentSurfaceClassInfo.mLock);
1240 if (env->MonitorEnter(lock) == JNI_OK) {
1241 env->CallVoidMethod(
1242 object,
1243 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1244 (jlong)surface.get());
1245 env->SetLongField(
1246 object,
1247 gPersistentSurfaceClassInfo.mPersistentObject,
1248 (jlong)persistentSurface.get());
1249 env->MonitorExit(lock);
1250 } else {
1251 env->DeleteLocalRef(object);
1252 object = NULL;
1253 }
1254 env->DeleteLocalRef(lock);
1255
1256 if (object != NULL) {
1257 surface->incStrong(&sRefBaseOwner);
1258 persistentSurface->incStrong(&sRefBaseOwner);
1259 }
1260
1261 return object;
1262}
1263
1264static void android_media_MediaCodec_releasePersistentInputSurface(
1265 JNIEnv* env, jclass /* clazz */, jobject object) {
1266 sp<PersistentSurface> persistentSurface;
1267
1268 jobject lock = env->GetObjectField(
1269 object, gPersistentSurfaceClassInfo.mLock);
1270 if (env->MonitorEnter(lock) == JNI_OK) {
1271 persistentSurface = reinterpret_cast<PersistentSurface *>(
1272 env->GetLongField(
1273 object, gPersistentSurfaceClassInfo.mPersistentObject));
1274 env->SetLongField(
1275 object,
1276 gPersistentSurfaceClassInfo.mPersistentObject,
1277 (jlong)0);
1278 env->MonitorExit(lock);
1279 }
1280 env->DeleteLocalRef(lock);
1281
1282 if (persistentSurface != NULL) {
1283 persistentSurface->decStrong(&sRefBaseOwner);
1284 }
1285 // no need to release surface as it will be released by Surface's jni
1286}
1287
Chong Zhang9560ddb2015-05-13 10:25:29 -07001288static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001289 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001290 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001291
1292 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1293 if (codec == NULL) {
1294 throwExceptionAsNecessary(env, INVALID_OPERATION);
1295 return;
1296 }
1297
1298 sp<PersistentSurface> persistentSurface =
1299 android_media_MediaCodec_getPersistentInputSurface(env, object);
1300
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001301 if (persistentSurface == NULL) {
1302 throwExceptionAsNecessary(
1303 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1304 return;
1305 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001306 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001307 if (err != NO_ERROR) {
1308 throwExceptionAsNecessary(env, err);
1309 }
1310}
1311
Andy McFadden2621e402013-02-19 07:29:21 -08001312static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1313 jobject thiz) {
1314 ALOGV("android_media_MediaCodec_createInputSurface");
1315
1316 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1317 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001318 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001319 return NULL;
1320 }
1321
1322 // Tell the MediaCodec that we want to use a Surface as input.
1323 sp<IGraphicBufferProducer> bufferProducer;
1324 status_t err = codec->createInputSurface(&bufferProducer);
1325 if (err != NO_ERROR) {
1326 throwExceptionAsNecessary(env, err);
1327 return NULL;
1328 }
1329
1330 // Wrap the IGBP in a Java-language Surface.
1331 return android_view_Surface_createFromIGraphicBufferProducer(env,
1332 bufferProducer);
1333}
1334
Andreas Huber88572f72012-02-21 11:47:18 -08001335static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1336 ALOGV("android_media_MediaCodec_start");
1337
1338 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1339
1340 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001341 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001342 return;
1343 }
1344
1345 status_t err = codec->start();
1346
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001347 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001348}
1349
1350static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1351 ALOGV("android_media_MediaCodec_stop");
1352
1353 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1354
1355 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001356 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001357 return;
1358 }
1359
1360 status_t err = codec->stop();
1361
1362 throwExceptionAsNecessary(env, err);
1363}
1364
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001365static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1366 ALOGV("android_media_MediaCodec_reset");
1367
1368 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1369
1370 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001371 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001372 return;
1373 }
1374
1375 status_t err = codec->reset();
1376 if (err != OK) {
1377 // treat all errors as fatal for now, though resource not available
1378 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001379 // we also should avoid sending INVALID_OPERATION here due to
1380 // the transitory nature of reset(), it should not inadvertently
1381 // trigger an IllegalStateException.
1382 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001383 }
1384 throwExceptionAsNecessary(env, err);
1385}
1386
Andreas Huber88572f72012-02-21 11:47:18 -08001387static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1388 ALOGV("android_media_MediaCodec_flush");
1389
1390 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1391
1392 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001393 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001394 return;
1395 }
1396
1397 status_t err = codec->flush();
1398
1399 throwExceptionAsNecessary(env, err);
1400}
1401
1402static void android_media_MediaCodec_queueInputBuffer(
1403 JNIEnv *env,
1404 jobject thiz,
1405 jint index,
1406 jint offset,
1407 jint size,
1408 jlong timestampUs,
1409 jint flags) {
1410 ALOGV("android_media_MediaCodec_queueInputBuffer");
1411
1412 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1413
1414 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001415 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001416 return;
1417 }
1418
Andreas Huberbfc56f42012-04-19 12:47:07 -07001419 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001420
Andreas Huberbfc56f42012-04-19 12:47:07 -07001421 status_t err = codec->queueInputBuffer(
1422 index, offset, size, timestampUs, flags, &errorDetailMsg);
1423
1424 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001425 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001426}
1427
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001428static void android_media_MediaCodec_queueSecureInputBuffer(
1429 JNIEnv *env,
1430 jobject thiz,
1431 jint index,
1432 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001433 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001434 jlong timestampUs,
1435 jint flags) {
1436 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1437
1438 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1439
1440 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001441 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001442 return;
1443 }
1444
Andreas Huber91befdc2012-04-18 12:19:51 -07001445 jint numSubSamples =
1446 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1447
1448 jintArray numBytesOfClearDataObj =
1449 (jintArray)env->GetObjectField(
1450 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1451
1452 jintArray numBytesOfEncryptedDataObj =
1453 (jintArray)env->GetObjectField(
1454 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1455
1456 jbyteArray keyObj =
1457 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1458
1459 jbyteArray ivObj =
1460 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1461
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001462 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1463 enum CryptoPlugin::Mode mode;
1464 if (jmode == gCryptoModes.Unencrypted) {
1465 mode = CryptoPlugin::kMode_Unencrypted;
1466 } else if (jmode == gCryptoModes.AesCtr) {
1467 mode = CryptoPlugin::kMode_AES_CTR;
1468 } else if (jmode == gCryptoModes.AesCbc) {
1469 mode = CryptoPlugin::kMode_AES_CBC;
1470 } else {
1471 throwExceptionAsNecessary(env, INVALID_OPERATION);
1472 return;
1473 }
1474
1475 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1476
1477 CryptoPlugin::Pattern pattern;
Jeff Tinkere872ac42016-03-03 15:47:09 -08001478 if (patternObj == NULL) {
1479 pattern.mEncryptBlocks = 0;
1480 pattern.mSkipBlocks = 0;
1481 } else {
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001482 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1483 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1484 }
Andreas Huber91befdc2012-04-18 12:19:51 -07001485
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001486 status_t err = OK;
1487
1488 CryptoPlugin::SubSample *subSamples = NULL;
1489 jbyte *key = NULL;
1490 jbyte *iv = NULL;
1491
1492 if (numSubSamples <= 0) {
1493 err = -EINVAL;
1494 } else if (numBytesOfClearDataObj == NULL
1495 && numBytesOfEncryptedDataObj == NULL) {
1496 err = -EINVAL;
1497 } else if (numBytesOfEncryptedDataObj != NULL
1498 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1499 err = -ERANGE;
1500 } else if (numBytesOfClearDataObj != NULL
1501 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1502 err = -ERANGE;
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001503 // subSamples array may silently overflow if number of samples are too large. Use
1504 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001505 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001506 err = -EINVAL;
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001507 } else {
1508 jboolean isCopy;
1509
1510 jint *numBytesOfClearData =
1511 (numBytesOfClearDataObj == NULL)
1512 ? NULL
1513 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1514
1515 jint *numBytesOfEncryptedData =
1516 (numBytesOfEncryptedDataObj == NULL)
1517 ? NULL
1518 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1519
1520 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1521
1522 for (jint i = 0; i < numSubSamples; ++i) {
1523 subSamples[i].mNumBytesOfClearData =
1524 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1525
1526 subSamples[i].mNumBytesOfEncryptedData =
1527 (numBytesOfEncryptedData == NULL)
1528 ? 0 : numBytesOfEncryptedData[i];
1529 }
1530
1531 if (numBytesOfEncryptedData != NULL) {
1532 env->ReleaseIntArrayElements(
1533 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1534 numBytesOfEncryptedData = NULL;
1535 }
1536
1537 if (numBytesOfClearData != NULL) {
1538 env->ReleaseIntArrayElements(
1539 numBytesOfClearDataObj, numBytesOfClearData, 0);
1540 numBytesOfClearData = NULL;
1541 }
1542 }
1543
1544 if (err == OK && keyObj != NULL) {
1545 if (env->GetArrayLength(keyObj) != 16) {
1546 err = -EINVAL;
1547 } else {
1548 jboolean isCopy;
1549 key = env->GetByteArrayElements(keyObj, &isCopy);
1550 }
1551 }
1552
1553 if (err == OK && ivObj != NULL) {
1554 if (env->GetArrayLength(ivObj) != 16) {
1555 err = -EINVAL;
1556 } else {
1557 jboolean isCopy;
1558 iv = env->GetByteArrayElements(ivObj, &isCopy);
1559 }
1560 }
1561
Andreas Huberbfc56f42012-04-19 12:47:07 -07001562 AString errorDetailMsg;
1563
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001564 if (err == OK) {
1565 err = codec->queueSecureInputBuffer(
1566 index, offset,
1567 subSamples, numSubSamples,
1568 (const uint8_t *)key, (const uint8_t *)iv,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001569 mode,
1570 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001571 timestampUs,
1572 flags,
1573 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001574 }
1575
1576 if (iv != NULL) {
1577 env->ReleaseByteArrayElements(ivObj, iv, 0);
1578 iv = NULL;
1579 }
1580
1581 if (key != NULL) {
1582 env->ReleaseByteArrayElements(keyObj, key, 0);
1583 key = NULL;
1584 }
1585
1586 delete[] subSamples;
1587 subSamples = NULL;
1588
Andreas Huberbfc56f42012-04-19 12:47:07 -07001589 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001590 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001591}
1592
Andreas Huber88572f72012-02-21 11:47:18 -08001593static jint android_media_MediaCodec_dequeueInputBuffer(
1594 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1595 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1596
1597 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1598
1599 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001600 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001601 return -1;
1602 }
1603
1604 size_t index;
1605 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1606
1607 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001608 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001609 }
1610
1611 return throwExceptionAsNecessary(env, err);
1612}
1613
1614static jint android_media_MediaCodec_dequeueOutputBuffer(
1615 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1616 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1617
1618 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1619
1620 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001621 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07001622 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001623 }
1624
1625 size_t index;
1626 status_t err = codec->dequeueOutputBuffer(
1627 env, bufferInfo, &index, timeoutUs);
1628
1629 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001630 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001631 }
1632
1633 return throwExceptionAsNecessary(env, err);
1634}
1635
1636static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001637 JNIEnv *env, jobject thiz,
1638 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08001639 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1640
1641 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1642
1643 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001644 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001645 return;
1646 }
1647
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001648 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08001649
1650 throwExceptionAsNecessary(env, err);
1651}
1652
Andy McFadden2621e402013-02-19 07:29:21 -08001653static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1654 jobject thiz) {
1655 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1656
1657 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1658 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001659 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001660 return;
1661 }
1662
1663 status_t err = codec->signalEndOfInputStream();
1664
1665 throwExceptionAsNecessary(env, err);
1666}
1667
Lajos Molnard4023112014-07-11 15:12:59 -07001668static jobject android_media_MediaCodec_getFormatNative(
1669 JNIEnv *env, jobject thiz, jboolean input) {
1670 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08001671
1672 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1673
1674 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001675 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001676 return NULL;
1677 }
1678
1679 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07001680 status_t err = codec->getFormat(env, input, &format);
1681
1682 if (err == OK) {
1683 return format;
1684 }
1685
1686 throwExceptionAsNecessary(env, err);
1687
1688 return NULL;
1689}
1690
1691static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1692 JNIEnv *env, jobject thiz, jint index) {
1693 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1694
1695 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1696
1697 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001698 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001699 return NULL;
1700 }
1701
1702 jobject format;
1703 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08001704
1705 if (err == OK) {
1706 return format;
1707 }
1708
1709 throwExceptionAsNecessary(env, err);
1710
1711 return NULL;
1712}
1713
1714static jobjectArray android_media_MediaCodec_getBuffers(
1715 JNIEnv *env, jobject thiz, jboolean input) {
1716 ALOGV("android_media_MediaCodec_getBuffers");
1717
1718 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1719
1720 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001721 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001722 return NULL;
1723 }
1724
1725 jobjectArray buffers;
1726 status_t err = codec->getBuffers(env, input, &buffers);
1727
1728 if (err == OK) {
1729 return buffers;
1730 }
1731
Marco Nelissencbbea8e2012-12-19 11:42:55 -08001732 // if we're out of memory, an exception was already thrown
1733 if (err != NO_MEMORY) {
1734 throwExceptionAsNecessary(env, err);
1735 }
Andreas Huber88572f72012-02-21 11:47:18 -08001736
1737 return NULL;
1738}
1739
Lajos Molnard4023112014-07-11 15:12:59 -07001740static jobject android_media_MediaCodec_getBuffer(
1741 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1742 ALOGV("android_media_MediaCodec_getBuffer");
1743
1744 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1745
1746 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001747 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001748 return NULL;
1749 }
1750
1751 jobject buffer;
1752 status_t err = codec->getBuffer(env, input, index, &buffer);
1753
1754 if (err == OK) {
1755 return buffer;
1756 }
1757
1758 // if we're out of memory, an exception was already thrown
1759 if (err != NO_MEMORY) {
1760 throwExceptionAsNecessary(env, err);
1761 }
1762
1763 return NULL;
1764}
1765
1766static jobject android_media_MediaCodec_getImage(
1767 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1768 ALOGV("android_media_MediaCodec_getImage");
1769
1770 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1771
1772 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001773 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001774 return NULL;
1775 }
1776
1777 jobject image;
1778 status_t err = codec->getImage(env, input, index, &image);
1779
1780 if (err == OK) {
1781 return image;
1782 }
1783
1784 // if we're out of memory, an exception was already thrown
1785 if (err != NO_MEMORY) {
1786 throwExceptionAsNecessary(env, err);
1787 }
1788
1789 return NULL;
1790}
1791
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001792static jobject android_media_MediaCodec_getName(
1793 JNIEnv *env, jobject thiz) {
1794 ALOGV("android_media_MediaCodec_getName");
1795
1796 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1797
1798 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001799 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001800 return NULL;
1801 }
1802
1803 jstring name;
1804 status_t err = codec->getName(env, &name);
1805
1806 if (err == OK) {
1807 return name;
1808 }
1809
1810 throwExceptionAsNecessary(env, err);
1811
1812 return NULL;
1813}
1814
Chong Zhanga0b72a62018-02-28 18:46:26 -08001815static jobject android_media_MediaCodec_getOwnCodecInfo(
1816 JNIEnv *env, jobject thiz) {
1817 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
1818
1819 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1820
1821 if (codec == NULL) {
1822 throwExceptionAsNecessary(env, INVALID_OPERATION);
1823 return NULL;
1824 }
1825
1826 jobject codecInfoObj;
1827 status_t err = codec->getCodecInfo(env, &codecInfoObj);
1828
1829 if (err == OK) {
1830 return codecInfoObj;
1831 }
1832
1833 throwExceptionAsNecessary(env, err);
1834
1835 return NULL;
1836}
1837
Ray Essick0e0fee12017-01-25 18:01:56 -08001838static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08001839android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08001840{
Ray Essickf2d0e402017-03-09 10:17:51 -08001841 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08001842
1843 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1844 if (codec == NULL ) {
1845 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1846 return 0;
1847 }
1848
1849 // get what we have for the metrics from the codec
Ray Essickf2d0e402017-03-09 10:17:51 -08001850 MediaAnalyticsItem *item = NULL;
1851
1852 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08001853 if (err != OK) {
1854 ALOGE("getMetrics failed");
1855 return (jobject) NULL;
1856 }
1857
Ray Essick0e0fee12017-01-25 18:01:56 -08001858 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
1859
1860 // housekeeping
1861 delete item;
1862 item = NULL;
1863
1864 return mybundle;
1865}
1866
Andreas Huber226065b2013-08-12 10:14:11 -07001867static void android_media_MediaCodec_setParameters(
1868 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1869 ALOGV("android_media_MediaCodec_setParameters");
1870
1871 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1872
1873 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001874 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07001875 return;
1876 }
1877
1878 sp<AMessage> params;
1879 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
1880
1881 if (err == OK) {
1882 err = codec->setParameters(params);
1883 }
1884
1885 throwExceptionAsNecessary(env, err);
1886}
1887
Andreas Huberb12a5392012-04-30 14:18:33 -07001888static void android_media_MediaCodec_setVideoScalingMode(
1889 JNIEnv *env, jobject thiz, jint mode) {
1890 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1891
1892 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001893 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07001894 return;
1895 }
1896
1897 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1898 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07001899 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07001900 return;
1901 }
1902
1903 codec->setVideoScalingMode(mode);
1904}
1905
ybai5e053202018-11-01 13:02:15 +08001906static void android_media_MediaCodec_setAudioPresentation(
1907 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
1908 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1909
1910 if (codec == NULL) {
1911 throwExceptionAsNecessary(env, INVALID_OPERATION);
1912 return;
1913 }
1914
1915 codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
1916}
1917
Andreas Huber88572f72012-02-21 11:47:18 -08001918static void android_media_MediaCodec_native_init(JNIEnv *env) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001919 ScopedLocalRef<jclass> clazz(
1920 env, env->FindClass("android/media/MediaCodec"));
1921 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001922
Andreas Huberaba67132013-10-22 12:40:01 -07001923 gFields.postEventFromNativeID =
1924 env->GetMethodID(
1925 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
Andreas Huberaba67132013-10-22 12:40:01 -07001926 CHECK(gFields.postEventFromNativeID != NULL);
1927
Wonsik Kim61796fd2018-09-13 13:15:59 -07001928 gFields.lockAndGetContextID =
1929 env->GetMethodID(
1930 clazz.get(), "lockAndGetContext", "()J");
1931 CHECK(gFields.lockAndGetContextID != NULL);
1932
1933 gFields.setAndUnlockContextID =
1934 env->GetMethodID(
1935 clazz.get(), "setAndUnlockContext", "(J)V");
1936 CHECK(gFields.setAndUnlockContextID != NULL);
1937
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001938 jfieldID field;
1939 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
1940 CHECK(field != NULL);
1941 gCryptoModes.Unencrypted =
1942 env->GetStaticIntField(clazz.get(), field);
1943
1944 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
1945 CHECK(field != NULL);
1946 gCryptoModes.AesCtr =
1947 env->GetStaticIntField(clazz.get(), field);
1948
1949 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
1950 CHECK(field != NULL);
1951 gCryptoModes.AesCbc =
1952 env->GetStaticIntField(clazz.get(), field);
1953
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001954 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1955 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001956
1957 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001958 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001959 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1960
1961 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001962 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001963 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1964
1965 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001966 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001967 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1968
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001969 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001970 CHECK(gFields.cryptoInfoKeyID != NULL);
1971
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001972 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001973 CHECK(gFields.cryptoInfoIVID != NULL);
1974
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001975 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001976 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001977
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001978 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
1979 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
1980 CHECK(gFields.cryptoInfoPatternID != NULL);
1981
1982 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
1983 CHECK(clazz.get() != NULL);
1984
1985 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
1986 CHECK(gFields.patternEncryptBlocksID != NULL);
1987
1988 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
1989 CHECK(gFields.patternSkipBlocksID != NULL);
1990
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001991 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1992 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001993
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001994 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001995 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001996 gCryptoErrorCodes.cryptoErrorNoKey =
1997 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001998
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001999 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002000 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002001 gCryptoErrorCodes.cryptoErrorKeyExpired =
2002 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07002003
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002004 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07002005 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07002006 gCryptoErrorCodes.cryptoErrorResourceBusy =
2007 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002008
Jeff Tinker336d3ea2014-08-28 17:57:36 -07002009 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
2010 CHECK(field != NULL);
2011 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
2012 env->GetStaticIntField(clazz.get(), field);
2013
Jeff Tinker96a2a952015-07-01 17:35:18 -07002014 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
2015 CHECK(field != NULL);
2016 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
2017 env->GetStaticIntField(clazz.get(), field);
2018
Jeff Tinker20594d82018-12-12 08:31:22 -08002019 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
2020 CHECK(field != NULL);
2021 gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
2022 env->GetStaticIntField(clazz.get(), field);
2023
Jeff Tinkerd3932162016-03-05 11:35:20 -08002024 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
2025 CHECK(field != NULL);
2026 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
2027 env->GetStaticIntField(clazz.get(), field);
2028
Jeff Tinker20594d82018-12-12 08:31:22 -08002029 field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
2030 CHECK(field != NULL);
2031 gCryptoErrorCodes.cryptoErrorFrameTooLarge =
2032 env->GetStaticIntField(clazz.get(), field);
2033
2034 field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
2035 CHECK(field != NULL);
2036 gCryptoErrorCodes.cryptoErrorLostState =
2037 env->GetStaticIntField(clazz.get(), field);
2038
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002039 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
2040 CHECK(clazz.get() != NULL);
2041 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
2042 CHECK(field != NULL);
2043 gCodecActionCodes.codecActionTransient =
2044 env->GetStaticIntField(clazz.get(), field);
2045
2046 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
2047 CHECK(field != NULL);
2048 gCodecActionCodes.codecActionRecoverable =
2049 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002050
Ronghua Wuc53ad692015-05-08 14:40:49 -07002051 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002052 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002053 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002054 env->GetStaticIntField(clazz.get(), field);
2055
Ronghua Wuc53ad692015-05-08 14:40:49 -07002056 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002057 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07002058 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07002059 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07002060
2061 clazz.reset(env->FindClass("android/view/Surface"));
2062 CHECK(clazz.get() != NULL);
2063
2064 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
2065 CHECK(field != NULL);
2066 gPersistentSurfaceClassInfo.mLock = field;
2067
2068 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
2069 CHECK(method != NULL);
2070 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2071
2072 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2073 CHECK(clazz.get() != NULL);
2074 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2075
2076 method = env->GetMethodID(clazz.get(), "<init>", "()V");
2077 CHECK(method != NULL);
2078 gPersistentSurfaceClassInfo.ctor = method;
2079
2080 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2081 CHECK(field != NULL);
2082 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08002083
2084 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2085 CHECK(clazz.get() != NULL);
2086 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2087
2088 method = env->GetMethodID(clazz.get(), "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -08002089 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Chong Zhanga0b72a62018-02-28 18:46:26 -08002090 "Ljava/util/Map;Ljava/util/Map;)V");
2091 CHECK(method != NULL);
2092 gCodecInfo.capsCtorId = method;
2093
2094 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2095 CHECK(clazz.get() != NULL);
2096 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2097
2098 field = env->GetFieldID(clazz.get(), "profile", "I");
2099 CHECK(field != NULL);
2100 gCodecInfo.profileField = field;
2101
2102 field = env->GetFieldID(clazz.get(), "level", "I");
2103 CHECK(field != NULL);
2104 gCodecInfo.levelField = field;
Andreas Huber88572f72012-02-21 11:47:18 -08002105}
2106
2107static void android_media_MediaCodec_native_setup(
2108 JNIEnv *env, jobject thiz,
2109 jstring name, jboolean nameIsType, jboolean encoder) {
2110 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002111 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002112 return;
2113 }
2114
2115 const char *tmp = env->GetStringUTFChars(name, NULL);
2116
2117 if (tmp == NULL) {
2118 return;
2119 }
2120
2121 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2122
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002123 const status_t err = codec->initCheck();
2124 if (err == NAME_NOT_FOUND) {
2125 // fail and do not try again.
2126 jniThrowException(env, "java/lang/IllegalArgumentException",
2127 String8::format("Failed to initialize %s, error %#x", tmp, err));
2128 env->ReleaseStringUTFChars(name, tmp);
2129 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07002130 } if (err == NO_MEMORY) {
2131 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2132 String8::format("Failed to initialize %s, error %#x", tmp, err));
2133 env->ReleaseStringUTFChars(name, tmp);
2134 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002135 } else if (err != OK) {
2136 // believed possible to try again
2137 jniThrowException(env, "java/io/IOException",
2138 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2139 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08002140 return;
2141 }
2142
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002143 env->ReleaseStringUTFChars(name, tmp);
2144
Andreas Huberaba67132013-10-22 12:40:01 -07002145 codec->registerSelf();
2146
Andreas Huber88572f72012-02-21 11:47:18 -08002147 setMediaCodec(env,thiz, codec);
2148}
2149
2150static void android_media_MediaCodec_native_finalize(
2151 JNIEnv *env, jobject thiz) {
2152 android_media_MediaCodec_release(env, thiz);
2153}
2154
Daniel Micay76f6a862015-09-19 17:31:01 -04002155static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07002156 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08002157
Lajos Molnar1e6e8012014-07-15 16:07:13 -07002158 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
2159
Chong Zhang8034d602015-04-28 13:38:48 -07002160 { "native_releasePersistentInputSurface",
2161 "(Landroid/view/Surface;)V",
2162 (void *)android_media_MediaCodec_releasePersistentInputSurface},
2163
2164 { "native_createPersistentInputSurface",
2165 "()Landroid/media/MediaCodec$PersistentSurface;",
2166 (void *)android_media_MediaCodec_createPersistentInputSurface },
2167
Chong Zhang9560ddb2015-05-13 10:25:29 -07002168 { "native_setInputSurface", "(Landroid/view/Surface;)V",
2169 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07002170
Lajos Molnard8578572015-06-05 20:17:33 -07002171 { "native_enableOnFrameRenderedListener", "(Z)V",
2172 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
2173
Chong Zhang8d5e5562014-07-08 18:49:21 -07002174 { "native_setCallback",
2175 "(Landroid/media/MediaCodec$Callback;)V",
2176 (void *)android_media_MediaCodec_native_setCallback },
2177
Andreas Huber88572f72012-02-21 11:47:18 -08002178 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07002179 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07002180 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002181 (void *)android_media_MediaCodec_native_configure },
2182
Lajos Molnar5e02ba92015-05-01 15:59:35 -07002183 { "native_setSurface",
2184 "(Landroid/view/Surface;)V",
2185 (void *)android_media_MediaCodec_native_setSurface },
2186
Andy McFadden2621e402013-02-19 07:29:21 -08002187 { "createInputSurface", "()Landroid/view/Surface;",
2188 (void *)android_media_MediaCodec_createInputSurface },
2189
Lajos Molnard4023112014-07-11 15:12:59 -07002190 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07002191 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07002192 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08002193
Lajos Molnard4023112014-07-11 15:12:59 -07002194 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002195 (void *)android_media_MediaCodec_queueInputBuffer },
2196
Lajos Molnard4023112014-07-11 15:12:59 -07002197 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002198 (void *)android_media_MediaCodec_queueSecureInputBuffer },
2199
Lajos Molnard4023112014-07-11 15:12:59 -07002200 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08002201 (void *)android_media_MediaCodec_dequeueInputBuffer },
2202
Lajos Molnard4023112014-07-11 15:12:59 -07002203 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08002204 (void *)android_media_MediaCodec_dequeueOutputBuffer },
2205
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002206 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002207 (void *)android_media_MediaCodec_releaseOutputBuffer },
2208
Andy McFadden2621e402013-02-19 07:29:21 -08002209 { "signalEndOfInputStream", "()V",
2210 (void *)android_media_MediaCodec_signalEndOfInputStream },
2211
Lajos Molnard4023112014-07-11 15:12:59 -07002212 { "getFormatNative", "(Z)Ljava/util/Map;",
2213 (void *)android_media_MediaCodec_getFormatNative },
2214
2215 { "getOutputFormatNative", "(I)Ljava/util/Map;",
2216 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08002217
2218 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
2219 (void *)android_media_MediaCodec_getBuffers },
2220
Lajos Molnard4023112014-07-11 15:12:59 -07002221 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
2222 (void *)android_media_MediaCodec_getBuffer },
2223
2224 { "getImage", "(ZI)Landroid/media/Image;",
2225 (void *)android_media_MediaCodec_getImage },
2226
Lajos Molnard2a7f472018-11-15 12:49:20 -08002227 { "getCanonicalName", "()Ljava/lang/String;",
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002228 (void *)android_media_MediaCodec_getName },
2229
Chong Zhanga0b72a62018-02-28 18:46:26 -08002230 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
2231 (void *)android_media_MediaCodec_getOwnCodecInfo },
2232
Ray Essick10353e32017-04-14 10:22:55 -07002233 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08002234 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08002235
Andreas Huber226065b2013-08-12 10:14:11 -07002236 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
2237 (void *)android_media_MediaCodec_setParameters },
2238
Andreas Huberb12a5392012-04-30 14:18:33 -07002239 { "setVideoScalingMode", "(I)V",
2240 (void *)android_media_MediaCodec_setVideoScalingMode },
2241
ybai5e053202018-11-01 13:02:15 +08002242 { "native_setAudioPresentation", "(II)V",
2243 (void *)android_media_MediaCodec_setAudioPresentation },
2244
Andreas Huber88572f72012-02-21 11:47:18 -08002245 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
2246
2247 { "native_setup", "(Ljava/lang/String;ZZ)V",
2248 (void *)android_media_MediaCodec_native_setup },
2249
2250 { "native_finalize", "()V",
2251 (void *)android_media_MediaCodec_native_finalize },
2252};
2253
2254int register_android_media_MediaCodec(JNIEnv *env) {
2255 return AndroidRuntime::registerNativeMethods(env,
2256 "android/media/MediaCodec", gMethods, NELEM(gMethods));
2257}