blob: 16f6284b60314a4ca3a627d4eee1ec0919e6f2b6 [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 Tinkerd3932162016-03-05 11:35:20 -080075 jint cryptoErrorUnsupportedOperation;
Jeff Tinker3ed38262013-08-02 23:24:51 -070076} gCryptoErrorCodes;
77
Andy Hung5f9aa0b2014-07-30 15:48:21 -070078static struct CodecActionCodes {
79 jint codecActionTransient;
80 jint codecActionRecoverable;
81} gCodecActionCodes;
82
Ronghua Wuc53ad692015-05-08 14:40:49 -070083static struct CodecErrorCodes {
84 jint errorInsufficientResource;
85 jint errorReclaimed;
86} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -070087
Chong Zhang8034d602015-04-28 13:38:48 -070088static struct {
89 jclass clazz;
90 jfieldID mLock;
91 jfieldID mPersistentObject;
92 jmethodID ctor;
93 jmethodID setNativeObjectLocked;
94} gPersistentSurfaceClassInfo;
95
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -080096static struct {
97 jint Unencrypted;
98 jint AesCtr;
99 jint AesCbc;
100} gCryptoModes;
101
Chong Zhanga0b72a62018-02-28 18:46:26 -0800102static struct {
103 jclass capsClazz;
104 jmethodID capsCtorId;
105 jclass profileLevelClazz;
106 jfieldID profileField;
107 jfieldID levelField;
108} gCodecInfo;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800109
Andreas Huber88572f72012-02-21 11:47:18 -0800110struct fields_t {
111 jfieldID context;
Andreas Huberaba67132013-10-22 12:40:01 -0700112 jmethodID postEventFromNativeID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700113 jfieldID cryptoInfoNumSubSamplesID;
114 jfieldID cryptoInfoNumBytesOfClearDataID;
115 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
116 jfieldID cryptoInfoKeyID;
117 jfieldID cryptoInfoIVID;
118 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800119 jfieldID cryptoInfoPatternID;
120 jfieldID patternEncryptBlocksID;
121 jfieldID patternSkipBlocksID;
Andreas Huber88572f72012-02-21 11:47:18 -0800122};
123
124static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700125static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800126
127////////////////////////////////////////////////////////////////////////////////
128
129JMediaCodec::JMediaCodec(
130 JNIEnv *env, jobject thiz,
131 const char *name, bool nameIsType, bool encoder)
132 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700133 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800134 jclass clazz = env->GetObjectClass(thiz);
135 CHECK(clazz != NULL);
136
137 mClass = (jclass)env->NewGlobalRef(clazz);
138 mObject = env->NewWeakGlobalRef(thiz);
139
Lajos Molnar7de28d32014-07-25 07:51:02 -0700140 cacheJavaObjects(env);
141
Andreas Huber88572f72012-02-21 11:47:18 -0800142 mLooper = new ALooper;
143 mLooper->setName("MediaCodec_looper");
144
145 mLooper->start(
146 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700147 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700148 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800149
150 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700151 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800152 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700153 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800154 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700155 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800156}
157
Lajos Molnar7de28d32014-07-25 07:51:02 -0700158void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
159 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
160 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
161 CHECK(mByteBufferClass != NULL);
162
163 ScopedLocalRef<jclass> byteOrderClass(
164 env, env->FindClass("java/nio/ByteOrder"));
165 CHECK(byteOrderClass.get() != NULL);
166
167 jmethodID nativeOrderID = env->GetStaticMethodID(
168 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
169 CHECK(nativeOrderID != NULL);
170
171 jobject nativeByteOrderObj =
172 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
173 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
174 CHECK(mNativeByteOrderObj != NULL);
175 env->DeleteLocalRef(nativeByteOrderObj);
176 nativeByteOrderObj = NULL;
177
178 mByteBufferOrderMethodID = env->GetMethodID(
179 mByteBufferClass,
180 "order",
181 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
182 CHECK(mByteBufferOrderMethodID != NULL);
183
184 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
185 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
186 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
187
188 mByteBufferPositionMethodID = env->GetMethodID(
189 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
190 CHECK(mByteBufferPositionMethodID != NULL);
191
192 mByteBufferLimitMethodID = env->GetMethodID(
193 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
194 CHECK(mByteBufferLimitMethodID != NULL);
195}
196
Andreas Huber88572f72012-02-21 11:47:18 -0800197status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700198 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800199}
200
Andreas Huberaba67132013-10-22 12:40:01 -0700201void JMediaCodec::registerSelf() {
202 mLooper->registerHandler(this);
203}
204
Chong Zhang128b0122014-03-01 18:04:13 -0800205void JMediaCodec::release() {
Martin Storsjod932de92012-07-13 13:01:06 +0300206 if (mCodec != NULL) {
207 mCodec->release();
208 mCodec.clear();
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700209 mInitStatus = NO_INIT;
Martin Storsjod932de92012-07-13 13:01:06 +0300210 }
Andreas Huber88572f72012-02-21 11:47:18 -0800211
Chong Zhang128b0122014-03-01 18:04:13 -0800212 if (mLooper != NULL) {
213 mLooper->unregisterHandler(id());
214 mLooper->stop();
215 mLooper.clear();
216 }
217}
218
219JMediaCodec::~JMediaCodec() {
220 if (mCodec != NULL || mLooper != NULL) {
221 /* MediaCodec and looper should have been released explicitly already
222 * in setMediaCodec() (see comments in setMediaCodec()).
223 *
224 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
225 * message handler, doing release() there risks deadlock as MediaCodec::
226 * release() post synchronous message to the same looper.
227 *
228 * Print a warning and try to proceed with releasing.
229 */
230 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
231 release();
232 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
233 }
234
Andreas Huber88572f72012-02-21 11:47:18 -0800235 JNIEnv *env = AndroidRuntime::getJNIEnv();
236
237 env->DeleteWeakGlobalRef(mObject);
238 mObject = NULL;
239 env->DeleteGlobalRef(mClass);
240 mClass = NULL;
Lajos Molnar7de28d32014-07-25 07:51:02 -0700241 deleteJavaObjects(env);
242}
243
244void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
245 env->DeleteGlobalRef(mByteBufferClass);
246 mByteBufferClass = NULL;
247 env->DeleteGlobalRef(mNativeByteOrderObj);
248 mNativeByteOrderObj = NULL;
249
250 mByteBufferOrderMethodID = NULL;
251 mByteBufferAsReadOnlyBufferMethodID = NULL;
252 mByteBufferPositionMethodID = NULL;
253 mByteBufferLimitMethodID = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800254}
255
Lajos Molnard8578572015-06-05 20:17:33 -0700256status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
257 if (enable) {
258 if (mOnFrameRenderedNotification == NULL) {
259 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
260 }
261 } else {
262 mOnFrameRenderedNotification.clear();
263 }
264
265 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
266}
267
Chong Zhang8d5e5562014-07-08 18:49:21 -0700268status_t JMediaCodec::setCallback(jobject cb) {
269 if (cb != NULL) {
270 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800271 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700272 }
273 } else {
274 mCallbackNotification.clear();
275 }
276
277 return mCodec->setCallback(mCallbackNotification);
278}
279
Andreas Huber88572f72012-02-21 11:47:18 -0800280status_t JMediaCodec::configure(
281 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800282 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700283 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800284 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800285 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800286 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800287 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700288 mSurfaceTextureClient =
289 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700290 } else {
291 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800292 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700293
Chong Zhangd5927ae2017-01-03 11:07:18 -0800294 return mCodec->configure(
295 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800296}
297
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700298status_t JMediaCodec::setSurface(
299 const sp<IGraphicBufferProducer> &bufferProducer) {
300 sp<Surface> client;
301 if (bufferProducer != NULL) {
302 client = new Surface(bufferProducer, true /* controlledByApp */);
303 }
304 status_t err = mCodec->setSurface(client);
305 if (err == OK) {
306 mSurfaceTextureClient = client;
307 }
308 return err;
309}
310
Andy McFadden2621e402013-02-19 07:29:21 -0800311status_t JMediaCodec::createInputSurface(
312 sp<IGraphicBufferProducer>* bufferProducer) {
313 return mCodec->createInputSurface(bufferProducer);
314}
315
Chong Zhang9560ddb2015-05-13 10:25:29 -0700316status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700317 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700318 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700319}
320
Andreas Huber88572f72012-02-21 11:47:18 -0800321status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700322 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800323}
324
325status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700326 mSurfaceTextureClient.clear();
327
Chong Zhang8d5e5562014-07-08 18:49:21 -0700328 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800329}
330
331status_t JMediaCodec::flush() {
332 return mCodec->flush();
333}
334
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700335status_t JMediaCodec::reset() {
336 return mCodec->reset();
337}
338
Andreas Huber88572f72012-02-21 11:47:18 -0800339status_t JMediaCodec::queueInputBuffer(
340 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700341 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
342 AString *errorDetailMsg) {
343 return mCodec->queueInputBuffer(
344 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800345}
346
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700347status_t JMediaCodec::queueSecureInputBuffer(
348 size_t index,
349 size_t offset,
350 const CryptoPlugin::SubSample *subSamples,
351 size_t numSubSamples,
352 const uint8_t key[16],
353 const uint8_t iv[16],
354 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800355 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700356 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700357 uint32_t flags,
358 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700359 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800360 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700361 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700362}
363
Andreas Huber88572f72012-02-21 11:47:18 -0800364status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700365 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800366}
367
368status_t JMediaCodec::dequeueOutputBuffer(
369 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
370 size_t size, offset;
371 int64_t timeUs;
372 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700373 status_t err = mCodec->dequeueOutputBuffer(
374 index, &offset, &size, &timeUs, &flags, timeoutUs);
375
Andreas Huberaba67132013-10-22 12:40:01 -0700376 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800377 return err;
378 }
379
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700380 ScopedLocalRef<jclass> clazz(
381 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800382
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700383 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000384 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800385
386 return OK;
387}
388
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700389status_t JMediaCodec::releaseOutputBuffer(
390 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
391 if (updatePTS) {
392 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
393 }
Andreas Huber88572f72012-02-21 11:47:18 -0800394 return render
395 ? mCodec->renderOutputBufferAndRelease(index)
396 : mCodec->releaseOutputBuffer(index);
397}
398
Andy McFadden2621e402013-02-19 07:29:21 -0800399status_t JMediaCodec::signalEndOfInputStream() {
400 return mCodec->signalEndOfInputStream();
401}
402
Lajos Molnard4023112014-07-11 15:12:59 -0700403status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800404 sp<AMessage> msg;
405 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700406 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
407 if (err != OK) {
408 return err;
409 }
410
411 return ConvertMessageToMap(env, msg, format);
412}
413
414status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
415 sp<AMessage> msg;
416 status_t err;
417 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800418 return err;
419 }
420
421 return ConvertMessageToMap(env, msg, format);
422}
423
424status_t JMediaCodec::getBuffers(
425 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900426 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800427
428 status_t err =
429 input
430 ? mCodec->getInputBuffers(&buffers)
431 : mCodec->getOutputBuffers(&buffers);
432
433 if (err != OK) {
434 return err;
435 }
436
Andreas Huber88572f72012-02-21 11:47:18 -0800437 *bufArray = (jobjectArray)env->NewObjectArray(
Lajos Molnar7de28d32014-07-25 07:51:02 -0700438 buffers.size(), mByteBufferClass, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800439 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800440 return NO_MEMORY;
441 }
Andreas Huber88572f72012-02-21 11:47:18 -0800442
443 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900444 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800445
Lajos Molnar7de28d32014-07-25 07:51:02 -0700446 jobject byteBuffer = NULL;
447 err = createByteBufferFromABuffer(
448 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
449 if (err != OK) {
450 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800451 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700452 if (byteBuffer != NULL) {
453 env->SetObjectArrayElement(
454 *bufArray, i, byteBuffer);
455
Lajos Molnard4023112014-07-11 15:12:59 -0700456 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700457 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700458 }
Andreas Huber88572f72012-02-21 11:47:18 -0800459 }
460
Lajos Molnar7de28d32014-07-25 07:51:02 -0700461 return OK;
462}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700463
Lajos Molnar7de28d32014-07-25 07:51:02 -0700464// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900465template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700466status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900467 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700468 jobject *buf) const {
469 // if this is an ABuffer that doesn't actually hold any accessible memory,
470 // use a null ByteBuffer
471 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700472
473 if (buffer == NULL) {
474 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
475 return OK;
476 }
477
Lajos Molnar7de28d32014-07-25 07:51:02 -0700478 if (buffer->base() == NULL) {
479 return OK;
480 }
481
482 jobject byteBuffer =
483 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
484 if (readOnly && byteBuffer != NULL) {
485 jobject readOnlyBuffer = env->CallObjectMethod(
486 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
487 env->DeleteLocalRef(byteBuffer);
488 byteBuffer = readOnlyBuffer;
489 }
490 if (byteBuffer == NULL) {
491 return NO_MEMORY;
492 }
493 jobject me = env->CallObjectMethod(
494 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
495 env->DeleteLocalRef(me);
496 me = env->CallObjectMethod(
497 byteBuffer, mByteBufferLimitMethodID,
498 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
499 env->DeleteLocalRef(me);
500 me = env->CallObjectMethod(
501 byteBuffer, mByteBufferPositionMethodID,
502 clearBuffer ? 0 : buffer->offset());
503 env->DeleteLocalRef(me);
504 me = NULL;
505
506 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800507 return OK;
508}
509
Lajos Molnard4023112014-07-11 15:12:59 -0700510status_t JMediaCodec::getBuffer(
511 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900512 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700513
514 status_t err =
515 input
516 ? mCodec->getInputBuffer(index, &buffer)
517 : mCodec->getOutputBuffer(index, &buffer);
518
519 if (err != OK) {
520 return err;
521 }
522
Lajos Molnar7de28d32014-07-25 07:51:02 -0700523 return createByteBufferFromABuffer(
524 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700525}
526
527status_t JMediaCodec::getImage(
528 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900529 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700530
531 status_t err =
532 input
533 ? mCodec->getInputBuffer(index, &buffer)
534 : mCodec->getOutputBuffer(index, &buffer);
535
536 if (err != OK) {
537 return err;
538 }
539
540 // if this is an ABuffer that doesn't actually hold any accessible memory,
541 // use a null ByteBuffer
542 *buf = NULL;
543 if (buffer->base() == NULL) {
544 return OK;
545 }
546
547 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700548 sp<ABuffer> imageData;
549 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700550 return OK;
551 }
552
Lajos Molnar7de28d32014-07-25 07:51:02 -0700553 int64_t timestamp = 0;
554 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
555 timestamp *= 1000; // adjust to ns
556 }
557
558 jobject byteBuffer = NULL;
559 err = createByteBufferFromABuffer(
560 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
561 if (err != OK) {
562 return OK;
563 }
564
565 jobject infoBuffer = NULL;
566 err = createByteBufferFromABuffer(
567 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
568 if (err != OK) {
569 env->DeleteLocalRef(byteBuffer);
570 byteBuffer = NULL;
571 return OK;
572 }
573
574 jobject cropRect = NULL;
575 int32_t left, top, right, bottom;
576 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
577 ScopedLocalRef<jclass> rectClazz(
578 env, env->FindClass("android/graphics/Rect"));
579 CHECK(rectClazz.get() != NULL);
580
581 jmethodID rectConstructID = env->GetMethodID(
582 rectClazz.get(), "<init>", "(IIII)V");
583
584 cropRect = env->NewObject(
585 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
586 }
587
588 ScopedLocalRef<jclass> imageClazz(
589 env, env->FindClass("android/media/MediaCodec$MediaImage"));
590 CHECK(imageClazz.get() != NULL);
591
592 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
593 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
594
595 *buf = env->NewObject(imageClazz.get(), imageConstructID,
596 byteBuffer, infoBuffer,
597 (jboolean)!input /* readOnly */,
598 (jlong)timestamp,
599 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
600
601 // if MediaImage creation fails, return null
602 if (env->ExceptionCheck()) {
603 env->ExceptionDescribe();
604 env->ExceptionClear();
605 *buf = NULL;
606 }
607
608 if (cropRect != NULL) {
609 env->DeleteLocalRef(cropRect);
610 cropRect = NULL;
611 }
612
613 env->DeleteLocalRef(byteBuffer);
614 byteBuffer = NULL;
615
616 env->DeleteLocalRef(infoBuffer);
617 infoBuffer = NULL;
618
Lajos Molnard4023112014-07-11 15:12:59 -0700619 return OK;
620}
621
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300622status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
623 AString name;
624
625 status_t err = mCodec->getName(&name);
626
627 if (err != OK) {
628 return err;
629 }
630
631 *nameStr = env->NewStringUTF(name.c_str());
632
633 return OK;
634}
635
Chong Zhanga0b72a62018-02-28 18:46:26 -0800636static jobject getCodecCapabilitiesObject(
637 JNIEnv *env, const char *mime, bool isEncoder,
638 const sp<MediaCodecInfo::Capabilities> &capabilities) {
639 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
640 Vector<uint32_t> colorFormats;
641
642 sp<AMessage> defaultFormat = new AMessage();
643 defaultFormat->setString("mime", mime);
644
645 capabilities->getSupportedColorFormats(&colorFormats);
646 capabilities->getSupportedProfileLevels(&profileLevels);
647 uint32_t flags = capabilities->getFlags();
648 sp<AMessage> details = capabilities->getDetails();
649
650 jobject defaultFormatObj = NULL;
651 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
652 return NULL;
653 }
654 ScopedLocalRef<jobject> defaultFormatRef(env, defaultFormatObj);
655
656 jobject detailsObj = NULL;
657 if (ConvertMessageToMap(env, details, &detailsObj)) {
658 return NULL;
659 }
660 ScopedLocalRef<jobject> detailsRef(env, detailsObj);
661
662 ScopedLocalRef<jobjectArray> profileLevelArray(env, env->NewObjectArray(
663 profileLevels.size(), gCodecInfo.profileLevelClazz, NULL));
664
665 for (size_t i = 0; i < profileLevels.size(); ++i) {
666 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
667
668 ScopedLocalRef<jobject> srcRef(env, env->AllocObject(
669 gCodecInfo.profileLevelClazz));
670
671 env->SetIntField(srcRef.get(), gCodecInfo.profileField, src.mProfile);
672 env->SetIntField(srcRef.get(), gCodecInfo.levelField, src.mLevel);
673
674 env->SetObjectArrayElement(profileLevelArray.get(), i, srcRef.get());
675 }
676
677 ScopedLocalRef<jintArray> colorFormatsArray(
678 env, env->NewIntArray(colorFormats.size()));
679 for (size_t i = 0; i < colorFormats.size(); ++i) {
680 jint val = colorFormats.itemAt(i);
681 env->SetIntArrayRegion(colorFormatsArray.get(), i, 1, &val);
682 }
683
684 return env->NewObject(
685 gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
686 profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags,
687 defaultFormatRef.get(), detailsRef.get());
688}
689
690status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const {
691 sp<MediaCodecInfo> codecInfo;
692
693 status_t err = mCodec->getCodecInfo(&codecInfo);
694
695 if (err != OK) {
696 return err;
697 }
698
699 ScopedLocalRef<jstring> nameObject(env,
700 env->NewStringUTF(codecInfo->getCodecName()));
701
702 bool isEncoder = codecInfo->isEncoder();
703
704 Vector<AString> mimes;
705 codecInfo->getSupportedMimes(&mimes);
706
707 ScopedLocalRef<jobjectArray> capsArrayObj(env,
708 env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL));
709
710 for (size_t i = 0; i < mimes.size(); i++) {
711 const sp<MediaCodecInfo::Capabilities> caps =
712 codecInfo->getCapabilitiesFor(mimes[i].c_str());
713
714 ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
715 env, mimes[i].c_str(), isEncoder, caps));
716
717 env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
718 }
719
720 ScopedLocalRef<jclass> codecInfoClazz(env,
721 env->FindClass("android/media/MediaCodecInfo"));
722 CHECK(codecInfoClazz.get() != NULL);
723
724 jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
725 "(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
726
727 *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
728 nameObject.get(), isEncoder, capsArrayObj.get());
729
730 return OK;
731}
732
Ray Essickf2d0e402017-03-09 10:17:51 -0800733status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
Ray Essick0e0fee12017-01-25 18:01:56 -0800734
735 status_t status = mCodec->getMetrics(reply);
736 return status;
737}
738
Andreas Huber226065b2013-08-12 10:14:11 -0700739status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
740 return mCodec->setParameters(msg);
741}
742
Andreas Huberb12a5392012-04-30 14:18:33 -0700743void JMediaCodec::setVideoScalingMode(int mode) {
744 if (mSurfaceTextureClient != NULL) {
745 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
746 }
747}
748
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700749static jthrowable createCodecException(
750 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
751 ScopedLocalRef<jclass> clazz(
752 env, env->FindClass("android/media/MediaCodec$CodecException"));
753 CHECK(clazz.get() != NULL);
754
Ronghua Wuc53ad692015-05-08 14:40:49 -0700755 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700756 CHECK(ctor != NULL);
757
758 ScopedLocalRef<jstring> msgObj(
759 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
760
761 // translate action code to Java equivalent
762 switch (actionCode) {
763 case ACTION_CODE_TRANSIENT:
764 actionCode = gCodecActionCodes.codecActionTransient;
765 break;
766 case ACTION_CODE_RECOVERABLE:
767 actionCode = gCodecActionCodes.codecActionRecoverable;
768 break;
769 default:
770 actionCode = 0; // everything else is fatal
771 break;
772 }
773
Ronghua Wuc53ad692015-05-08 14:40:49 -0700774 /* translate OS errors to Java API CodecException errorCodes */
775 switch (err) {
776 case NO_MEMORY:
777 err = gCodecErrorCodes.errorInsufficientResource;
778 break;
779 case DEAD_OBJECT:
780 err = gCodecErrorCodes.errorReclaimed;
781 break;
782 default: /* Other error codes go out as is. */
783 break;
784 }
785
786 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700787}
788
Chong Zhang8d5e5562014-07-08 18:49:21 -0700789void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
790 int32_t arg1, arg2 = 0;
791 jobject obj = NULL;
792 CHECK(msg->findInt32("callbackID", &arg1));
793 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700794
Chong Zhang8d5e5562014-07-08 18:49:21 -0700795 switch (arg1) {
796 case MediaCodec::CB_INPUT_AVAILABLE:
797 {
798 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700799 break;
800 }
801
Chong Zhang8d5e5562014-07-08 18:49:21 -0700802 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700803 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700804 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700805
Chong Zhang8d5e5562014-07-08 18:49:21 -0700806 size_t size, offset;
807 int64_t timeUs;
808 uint32_t flags;
809 CHECK(msg->findSize("size", &size));
810 CHECK(msg->findSize("offset", &offset));
811 CHECK(msg->findInt64("timeUs", &timeUs));
812 CHECK(msg->findInt32("flags", (int32_t *)&flags));
813
814 ScopedLocalRef<jclass> clazz(
815 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
816 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
817 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
818
819 obj = env->NewObject(clazz.get(), ctor);
820
821 if (obj == NULL) {
822 if (env->ExceptionCheck()) {
823 ALOGE("Could not create MediaCodec.BufferInfo.");
824 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700825 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700826 jniThrowException(env, "java/lang/IllegalStateException", NULL);
827 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700828 }
829
Chong Zhang8d5e5562014-07-08 18:49:21 -0700830 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
831 break;
832 }
833
834 case MediaCodec::CB_ERROR:
835 {
Chong Zhang94686d12014-07-11 15:53:58 -0700836 int32_t err, actionCode;
837 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -0700838 CHECK(msg->findInt32("actionCode", &actionCode));
839
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700840 // note that DRM errors could conceivably alias into a CodecException
841 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700842
843 if (obj == NULL) {
844 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -0700845 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -0700846 env->ExceptionClear();
847 }
848 jniThrowException(env, "java/lang/IllegalStateException", NULL);
849 return;
850 }
Andreas Huberaba67132013-10-22 12:40:01 -0700851
852 break;
853 }
854
Chong Zhang8d5e5562014-07-08 18:49:21 -0700855 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -0700856 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700857 sp<AMessage> format;
858 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -0700859
Chong Zhang8d5e5562014-07-08 18:49:21 -0700860 if (OK != ConvertMessageToMap(env, format, &obj)) {
861 jniThrowException(env, "java/lang/IllegalStateException", NULL);
862 return;
863 }
Andreas Huberaba67132013-10-22 12:40:01 -0700864
Andreas Huberaba67132013-10-22 12:40:01 -0700865 break;
866 }
867
868 default:
869 TRESPASS();
870 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700871
872 env->CallVoidMethod(
873 mObject,
874 gFields.postEventFromNativeID,
875 EVENT_CALLBACK,
876 arg1,
877 arg2,
878 obj);
879
880 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -0700881}
882
Lajos Molnard8578572015-06-05 20:17:33 -0700883void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
884 int32_t arg1 = 0, arg2 = 0;
885 jobject obj = NULL;
886 JNIEnv *env = AndroidRuntime::getJNIEnv();
887
888 sp<AMessage> data;
889 CHECK(msg->findMessage("data", &data));
890
891 status_t err = ConvertMessageToMap(env, data, &obj);
892 if (err != OK) {
893 jniThrowException(env, "java/lang/IllegalStateException", NULL);
894 return;
895 }
896
897 env->CallVoidMethod(
898 mObject, gFields.postEventFromNativeID,
899 EVENT_FRAME_RENDERED, arg1, arg2, obj);
900
901 env->DeleteLocalRef(obj);
902}
903
Chong Zhang8d5e5562014-07-08 18:49:21 -0700904void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
905 switch (msg->what()) {
906 case kWhatCallbackNotify:
907 {
908 handleCallback(msg);
909 break;
910 }
Lajos Molnard8578572015-06-05 20:17:33 -0700911 case kWhatFrameRendered:
912 {
913 handleFrameRenderedNotification(msg);
914 break;
915 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700916 default:
917 TRESPASS();
918 }
Andreas Huberaba67132013-10-22 12:40:01 -0700919}
920
Andreas Huber88572f72012-02-21 11:47:18 -0800921} // namespace android
922
923////////////////////////////////////////////////////////////////////////////////
924
925using namespace android;
926
927static sp<JMediaCodec> setMediaCodec(
928 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000929 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800930 if (codec != NULL) {
931 codec->incStrong(thiz);
932 }
933 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800934 /* release MediaCodec and stop the looper now before decStrong.
935 * otherwise JMediaCodec::~JMediaCodec() could be called from within
936 * its message handler, doing release() from there will deadlock
937 * (as MediaCodec::release() post synchronous message to the same looper)
938 */
939 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -0800940 old->decStrong(thiz);
941 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000942 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -0800943
944 return old;
945}
946
947static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000948 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800949}
950
951static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
952 setMediaCodec(env, thiz, NULL);
953}
954
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700955static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
956 jthrowable exception = createCodecException(env, err, actionCode, msg);
957 env->Throw(exception);
958}
959
Andreas Huberbfc56f42012-04-19 12:47:07 -0700960static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700961 ScopedLocalRef<jclass> clazz(
962 env, env->FindClass("android/media/MediaCodec$CryptoException"));
963 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700964
965 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700966 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -0700967 CHECK(constructID != NULL);
968
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800969 const char *defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -0700970
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700971 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700972 switch (err) {
973 case ERROR_DRM_NO_LICENSE:
974 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800975 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700976 break;
977 case ERROR_DRM_LICENSE_EXPIRED:
978 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800979 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700980 break;
981 case ERROR_DRM_RESOURCE_BUSY:
982 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800983 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700984 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700985 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
986 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800987 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700988 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700989 case ERROR_DRM_SESSION_NOT_OPENED:
990 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800991 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -0700992 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800993 case ERROR_DRM_CANNOT_HANDLE:
994 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
995 defaultMsg = "Operation not supported in this configuration";
996 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700997 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700998 break;
999 }
1000
Jeff Tinker3ccb34d2015-11-09 17:31:05 -08001001 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
1002
Andreas Huberbfc56f42012-04-19 12:47:07 -07001003 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001004 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -07001005
1006 env->Throw(exception);
1007}
1008
1009static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001010 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
1011 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -08001012 switch (err) {
1013 case OK:
1014 return 0;
1015
1016 case -EAGAIN:
1017 return DEQUEUE_INFO_TRY_AGAIN_LATER;
1018
1019 case INFO_FORMAT_CHANGED:
1020 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
1021
1022 case INFO_OUTPUT_BUFFERS_CHANGED:
1023 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
1024
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001025 case INVALID_OPERATION:
1026 jniThrowException(env, "java/lang/IllegalStateException", msg);
1027 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -07001028
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001029 case BAD_VALUE:
1030 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1031 return 0;
1032
Andreas Huber88572f72012-02-21 11:47:18 -08001033 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001034 if (isCryptoError(err)) {
1035 throwCryptoException(env, err, msg);
1036 return 0;
1037 }
1038 throwCodecException(env, err, actionCode, msg);
1039 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001040 }
Andreas Huber88572f72012-02-21 11:47:18 -08001041}
1042
Lajos Molnard8578572015-06-05 20:17:33 -07001043static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
1044 JNIEnv *env,
1045 jobject thiz,
1046 jboolean enabled) {
1047 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1048
1049 if (codec == NULL) {
1050 throwExceptionAsNecessary(env, INVALID_OPERATION);
1051 return;
1052 }
1053
1054 status_t err = codec->enableOnFrameRenderedListener(enabled);
1055
1056 throwExceptionAsNecessary(env, err);
1057}
1058
Chong Zhang8d5e5562014-07-08 18:49:21 -07001059static void android_media_MediaCodec_native_setCallback(
1060 JNIEnv *env,
1061 jobject thiz,
1062 jobject cb) {
1063 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1064
1065 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001066 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -07001067 return;
1068 }
1069
1070 status_t err = codec->setCallback(cb);
1071
1072 throwExceptionAsNecessary(env, err);
1073}
1074
Andreas Huber88572f72012-02-21 11:47:18 -08001075static void android_media_MediaCodec_native_configure(
1076 JNIEnv *env,
1077 jobject thiz,
1078 jobjectArray keys, jobjectArray values,
1079 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -07001080 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -08001081 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -08001082 jint flags) {
1083 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1084
1085 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001086 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001087 return;
1088 }
1089
1090 sp<AMessage> format;
1091 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
1092
1093 if (err != OK) {
1094 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1095 return;
1096 }
1097
Andy McFaddend47f7d82012-12-18 09:48:38 -08001098 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -08001099 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -07001100 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -08001101 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -08001102 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -08001103 } else {
1104 jniThrowException(
1105 env,
1106 "java/lang/IllegalArgumentException",
1107 "The surface has been released");
1108 return;
1109 }
1110 }
1111
Andreas Huber8240d922012-04-04 14:06:32 -07001112 sp<ICrypto> crypto;
1113 if (jcrypto != NULL) {
1114 crypto = JCrypto::GetCrypto(env, jcrypto);
1115 }
1116
Chong Zhangd5927ae2017-01-03 11:07:18 -08001117 sp<IDescrambler> descrambler;
1118 if (descramblerBinderObj != NULL) {
Chong Zhangcd538552018-02-21 17:22:19 -08001119 descrambler = GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001120 }
1121
1122 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001123
1124 throwExceptionAsNecessary(env, err);
1125}
1126
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001127static void android_media_MediaCodec_native_setSurface(
1128 JNIEnv *env,
1129 jobject thiz,
1130 jobject jsurface) {
1131 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1132
1133 if (codec == NULL) {
1134 throwExceptionAsNecessary(env, INVALID_OPERATION);
1135 return;
1136 }
1137
1138 sp<IGraphicBufferProducer> bufferProducer;
1139 if (jsurface != NULL) {
1140 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1141 if (surface != NULL) {
1142 bufferProducer = surface->getIGraphicBufferProducer();
1143 } else {
1144 jniThrowException(
1145 env,
1146 "java/lang/IllegalArgumentException",
1147 "The surface has been released");
1148 return;
1149 }
1150 }
1151
1152 status_t err = codec->setSurface(bufferProducer);
1153 throwExceptionAsNecessary(env, err);
1154}
1155
Chong Zhang8034d602015-04-28 13:38:48 -07001156sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1157 JNIEnv* env, jobject object) {
1158 sp<PersistentSurface> persistentSurface;
1159
1160 jobject lock = env->GetObjectField(
1161 object, gPersistentSurfaceClassInfo.mLock);
1162 if (env->MonitorEnter(lock) == JNI_OK) {
1163 persistentSurface = reinterpret_cast<PersistentSurface *>(
1164 env->GetLongField(object,
1165 gPersistentSurfaceClassInfo.mPersistentObject));
1166 env->MonitorExit(lock);
1167 }
1168 env->DeleteLocalRef(lock);
1169
1170 return persistentSurface;
1171}
1172
1173static jobject android_media_MediaCodec_createPersistentInputSurface(
1174 JNIEnv* env, jclass /* clazz */) {
1175 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1176 sp<PersistentSurface> persistentSurface =
1177 MediaCodec::CreatePersistentInputSurface();
1178
1179 if (persistentSurface == NULL) {
1180 return NULL;
1181 }
1182
1183 sp<Surface> surface = new Surface(
1184 persistentSurface->getBufferProducer(), true);
1185 if (surface == NULL) {
1186 return NULL;
1187 }
1188
1189 jobject object = env->NewObject(
1190 gPersistentSurfaceClassInfo.clazz,
1191 gPersistentSurfaceClassInfo.ctor);
1192
1193 if (object == NULL) {
1194 if (env->ExceptionCheck()) {
1195 ALOGE("Could not create PersistentSurface.");
1196 env->ExceptionClear();
1197 }
1198 return NULL;
1199 }
1200
1201 jobject lock = env->GetObjectField(
1202 object, gPersistentSurfaceClassInfo.mLock);
1203 if (env->MonitorEnter(lock) == JNI_OK) {
1204 env->CallVoidMethod(
1205 object,
1206 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1207 (jlong)surface.get());
1208 env->SetLongField(
1209 object,
1210 gPersistentSurfaceClassInfo.mPersistentObject,
1211 (jlong)persistentSurface.get());
1212 env->MonitorExit(lock);
1213 } else {
1214 env->DeleteLocalRef(object);
1215 object = NULL;
1216 }
1217 env->DeleteLocalRef(lock);
1218
1219 if (object != NULL) {
1220 surface->incStrong(&sRefBaseOwner);
1221 persistentSurface->incStrong(&sRefBaseOwner);
1222 }
1223
1224 return object;
1225}
1226
1227static void android_media_MediaCodec_releasePersistentInputSurface(
1228 JNIEnv* env, jclass /* clazz */, jobject object) {
1229 sp<PersistentSurface> persistentSurface;
1230
1231 jobject lock = env->GetObjectField(
1232 object, gPersistentSurfaceClassInfo.mLock);
1233 if (env->MonitorEnter(lock) == JNI_OK) {
1234 persistentSurface = reinterpret_cast<PersistentSurface *>(
1235 env->GetLongField(
1236 object, gPersistentSurfaceClassInfo.mPersistentObject));
1237 env->SetLongField(
1238 object,
1239 gPersistentSurfaceClassInfo.mPersistentObject,
1240 (jlong)0);
1241 env->MonitorExit(lock);
1242 }
1243 env->DeleteLocalRef(lock);
1244
1245 if (persistentSurface != NULL) {
1246 persistentSurface->decStrong(&sRefBaseOwner);
1247 }
1248 // no need to release surface as it will be released by Surface's jni
1249}
1250
Chong Zhang9560ddb2015-05-13 10:25:29 -07001251static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001252 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001253 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001254
1255 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1256 if (codec == NULL) {
1257 throwExceptionAsNecessary(env, INVALID_OPERATION);
1258 return;
1259 }
1260
1261 sp<PersistentSurface> persistentSurface =
1262 android_media_MediaCodec_getPersistentInputSurface(env, object);
1263
Marco Nelissen59cf9aa2018-04-19 11:02:00 -07001264 if (persistentSurface == NULL) {
1265 throwExceptionAsNecessary(
1266 env, BAD_VALUE, ACTION_CODE_FATAL, "input surface not valid");
1267 return;
1268 }
Chong Zhang9560ddb2015-05-13 10:25:29 -07001269 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001270 if (err != NO_ERROR) {
1271 throwExceptionAsNecessary(env, err);
1272 }
1273}
1274
Andy McFadden2621e402013-02-19 07:29:21 -08001275static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1276 jobject thiz) {
1277 ALOGV("android_media_MediaCodec_createInputSurface");
1278
1279 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1280 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001281 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001282 return NULL;
1283 }
1284
1285 // Tell the MediaCodec that we want to use a Surface as input.
1286 sp<IGraphicBufferProducer> bufferProducer;
1287 status_t err = codec->createInputSurface(&bufferProducer);
1288 if (err != NO_ERROR) {
1289 throwExceptionAsNecessary(env, err);
1290 return NULL;
1291 }
1292
1293 // Wrap the IGBP in a Java-language Surface.
1294 return android_view_Surface_createFromIGraphicBufferProducer(env,
1295 bufferProducer);
1296}
1297
Andreas Huber88572f72012-02-21 11:47:18 -08001298static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1299 ALOGV("android_media_MediaCodec_start");
1300
1301 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1302
1303 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001304 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001305 return;
1306 }
1307
1308 status_t err = codec->start();
1309
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001310 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001311}
1312
1313static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1314 ALOGV("android_media_MediaCodec_stop");
1315
1316 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1317
1318 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001319 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001320 return;
1321 }
1322
1323 status_t err = codec->stop();
1324
1325 throwExceptionAsNecessary(env, err);
1326}
1327
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001328static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1329 ALOGV("android_media_MediaCodec_reset");
1330
1331 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1332
1333 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001334 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001335 return;
1336 }
1337
1338 status_t err = codec->reset();
1339 if (err != OK) {
1340 // treat all errors as fatal for now, though resource not available
1341 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001342 // we also should avoid sending INVALID_OPERATION here due to
1343 // the transitory nature of reset(), it should not inadvertently
1344 // trigger an IllegalStateException.
1345 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001346 }
1347 throwExceptionAsNecessary(env, err);
1348}
1349
Andreas Huber88572f72012-02-21 11:47:18 -08001350static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1351 ALOGV("android_media_MediaCodec_flush");
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->flush();
1361
1362 throwExceptionAsNecessary(env, err);
1363}
1364
1365static void android_media_MediaCodec_queueInputBuffer(
1366 JNIEnv *env,
1367 jobject thiz,
1368 jint index,
1369 jint offset,
1370 jint size,
1371 jlong timestampUs,
1372 jint flags) {
1373 ALOGV("android_media_MediaCodec_queueInputBuffer");
1374
1375 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1376
1377 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001378 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001379 return;
1380 }
1381
Andreas Huberbfc56f42012-04-19 12:47:07 -07001382 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001383
Andreas Huberbfc56f42012-04-19 12:47:07 -07001384 status_t err = codec->queueInputBuffer(
1385 index, offset, size, timestampUs, flags, &errorDetailMsg);
1386
1387 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001388 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001389}
1390
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001391static void android_media_MediaCodec_queueSecureInputBuffer(
1392 JNIEnv *env,
1393 jobject thiz,
1394 jint index,
1395 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001396 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001397 jlong timestampUs,
1398 jint flags) {
1399 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1400
1401 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1402
1403 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001404 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001405 return;
1406 }
1407
Andreas Huber91befdc2012-04-18 12:19:51 -07001408 jint numSubSamples =
1409 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1410
1411 jintArray numBytesOfClearDataObj =
1412 (jintArray)env->GetObjectField(
1413 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1414
1415 jintArray numBytesOfEncryptedDataObj =
1416 (jintArray)env->GetObjectField(
1417 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1418
1419 jbyteArray keyObj =
1420 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1421
1422 jbyteArray ivObj =
1423 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1424
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001425 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1426 enum CryptoPlugin::Mode mode;
1427 if (jmode == gCryptoModes.Unencrypted) {
1428 mode = CryptoPlugin::kMode_Unencrypted;
1429 } else if (jmode == gCryptoModes.AesCtr) {
1430 mode = CryptoPlugin::kMode_AES_CTR;
1431 } else if (jmode == gCryptoModes.AesCbc) {
1432 mode = CryptoPlugin::kMode_AES_CBC;
1433 } else {
1434 throwExceptionAsNecessary(env, INVALID_OPERATION);
1435 return;
1436 }
1437
1438 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1439
1440 CryptoPlugin::Pattern pattern;
Jeff Tinkere872ac42016-03-03 15:47:09 -08001441 if (patternObj == NULL) {
1442 pattern.mEncryptBlocks = 0;
1443 pattern.mSkipBlocks = 0;
1444 } else {
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001445 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1446 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1447 }
Andreas Huber91befdc2012-04-18 12:19:51 -07001448
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001449 status_t err = OK;
1450
1451 CryptoPlugin::SubSample *subSamples = NULL;
1452 jbyte *key = NULL;
1453 jbyte *iv = NULL;
1454
1455 if (numSubSamples <= 0) {
1456 err = -EINVAL;
1457 } else if (numBytesOfClearDataObj == NULL
1458 && numBytesOfEncryptedDataObj == NULL) {
1459 err = -EINVAL;
1460 } else if (numBytesOfEncryptedDataObj != NULL
1461 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1462 err = -ERANGE;
1463 } else if (numBytesOfClearDataObj != NULL
1464 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1465 err = -ERANGE;
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001466 // subSamples array may silently overflow if number of samples are too large. Use
1467 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001468 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001469 err = -EINVAL;
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001470 } else {
1471 jboolean isCopy;
1472
1473 jint *numBytesOfClearData =
1474 (numBytesOfClearDataObj == NULL)
1475 ? NULL
1476 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1477
1478 jint *numBytesOfEncryptedData =
1479 (numBytesOfEncryptedDataObj == NULL)
1480 ? NULL
1481 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1482
1483 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1484
1485 for (jint i = 0; i < numSubSamples; ++i) {
1486 subSamples[i].mNumBytesOfClearData =
1487 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1488
1489 subSamples[i].mNumBytesOfEncryptedData =
1490 (numBytesOfEncryptedData == NULL)
1491 ? 0 : numBytesOfEncryptedData[i];
1492 }
1493
1494 if (numBytesOfEncryptedData != NULL) {
1495 env->ReleaseIntArrayElements(
1496 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1497 numBytesOfEncryptedData = NULL;
1498 }
1499
1500 if (numBytesOfClearData != NULL) {
1501 env->ReleaseIntArrayElements(
1502 numBytesOfClearDataObj, numBytesOfClearData, 0);
1503 numBytesOfClearData = NULL;
1504 }
1505 }
1506
1507 if (err == OK && keyObj != NULL) {
1508 if (env->GetArrayLength(keyObj) != 16) {
1509 err = -EINVAL;
1510 } else {
1511 jboolean isCopy;
1512 key = env->GetByteArrayElements(keyObj, &isCopy);
1513 }
1514 }
1515
1516 if (err == OK && ivObj != NULL) {
1517 if (env->GetArrayLength(ivObj) != 16) {
1518 err = -EINVAL;
1519 } else {
1520 jboolean isCopy;
1521 iv = env->GetByteArrayElements(ivObj, &isCopy);
1522 }
1523 }
1524
Andreas Huberbfc56f42012-04-19 12:47:07 -07001525 AString errorDetailMsg;
1526
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001527 if (err == OK) {
1528 err = codec->queueSecureInputBuffer(
1529 index, offset,
1530 subSamples, numSubSamples,
1531 (const uint8_t *)key, (const uint8_t *)iv,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001532 mode,
1533 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001534 timestampUs,
1535 flags,
1536 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001537 }
1538
1539 if (iv != NULL) {
1540 env->ReleaseByteArrayElements(ivObj, iv, 0);
1541 iv = NULL;
1542 }
1543
1544 if (key != NULL) {
1545 env->ReleaseByteArrayElements(keyObj, key, 0);
1546 key = NULL;
1547 }
1548
1549 delete[] subSamples;
1550 subSamples = NULL;
1551
Andreas Huberbfc56f42012-04-19 12:47:07 -07001552 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001553 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001554}
1555
Andreas Huber88572f72012-02-21 11:47:18 -08001556static jint android_media_MediaCodec_dequeueInputBuffer(
1557 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1558 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1559
1560 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1561
1562 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001563 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001564 return -1;
1565 }
1566
1567 size_t index;
1568 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1569
1570 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001571 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001572 }
1573
1574 return throwExceptionAsNecessary(env, err);
1575}
1576
1577static jint android_media_MediaCodec_dequeueOutputBuffer(
1578 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1579 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1580
1581 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1582
1583 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001584 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07001585 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001586 }
1587
1588 size_t index;
1589 status_t err = codec->dequeueOutputBuffer(
1590 env, bufferInfo, &index, timeoutUs);
1591
1592 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001593 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001594 }
1595
1596 return throwExceptionAsNecessary(env, err);
1597}
1598
1599static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001600 JNIEnv *env, jobject thiz,
1601 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08001602 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1603
1604 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1605
1606 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001607 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001608 return;
1609 }
1610
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001611 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08001612
1613 throwExceptionAsNecessary(env, err);
1614}
1615
Andy McFadden2621e402013-02-19 07:29:21 -08001616static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1617 jobject thiz) {
1618 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1619
1620 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1621 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001622 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001623 return;
1624 }
1625
1626 status_t err = codec->signalEndOfInputStream();
1627
1628 throwExceptionAsNecessary(env, err);
1629}
1630
Lajos Molnard4023112014-07-11 15:12:59 -07001631static jobject android_media_MediaCodec_getFormatNative(
1632 JNIEnv *env, jobject thiz, jboolean input) {
1633 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08001634
1635 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1636
1637 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001638 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001639 return NULL;
1640 }
1641
1642 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07001643 status_t err = codec->getFormat(env, input, &format);
1644
1645 if (err == OK) {
1646 return format;
1647 }
1648
1649 throwExceptionAsNecessary(env, err);
1650
1651 return NULL;
1652}
1653
1654static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1655 JNIEnv *env, jobject thiz, jint index) {
1656 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1657
1658 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1659
1660 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001661 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001662 return NULL;
1663 }
1664
1665 jobject format;
1666 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08001667
1668 if (err == OK) {
1669 return format;
1670 }
1671
1672 throwExceptionAsNecessary(env, err);
1673
1674 return NULL;
1675}
1676
1677static jobjectArray android_media_MediaCodec_getBuffers(
1678 JNIEnv *env, jobject thiz, jboolean input) {
1679 ALOGV("android_media_MediaCodec_getBuffers");
1680
1681 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1682
1683 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001684 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001685 return NULL;
1686 }
1687
1688 jobjectArray buffers;
1689 status_t err = codec->getBuffers(env, input, &buffers);
1690
1691 if (err == OK) {
1692 return buffers;
1693 }
1694
Marco Nelissencbbea8e2012-12-19 11:42:55 -08001695 // if we're out of memory, an exception was already thrown
1696 if (err != NO_MEMORY) {
1697 throwExceptionAsNecessary(env, err);
1698 }
Andreas Huber88572f72012-02-21 11:47:18 -08001699
1700 return NULL;
1701}
1702
Lajos Molnard4023112014-07-11 15:12:59 -07001703static jobject android_media_MediaCodec_getBuffer(
1704 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1705 ALOGV("android_media_MediaCodec_getBuffer");
1706
1707 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1708
1709 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001710 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001711 return NULL;
1712 }
1713
1714 jobject buffer;
1715 status_t err = codec->getBuffer(env, input, index, &buffer);
1716
1717 if (err == OK) {
1718 return buffer;
1719 }
1720
1721 // if we're out of memory, an exception was already thrown
1722 if (err != NO_MEMORY) {
1723 throwExceptionAsNecessary(env, err);
1724 }
1725
1726 return NULL;
1727}
1728
1729static jobject android_media_MediaCodec_getImage(
1730 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1731 ALOGV("android_media_MediaCodec_getImage");
1732
1733 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1734
1735 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001736 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001737 return NULL;
1738 }
1739
1740 jobject image;
1741 status_t err = codec->getImage(env, input, index, &image);
1742
1743 if (err == OK) {
1744 return image;
1745 }
1746
1747 // if we're out of memory, an exception was already thrown
1748 if (err != NO_MEMORY) {
1749 throwExceptionAsNecessary(env, err);
1750 }
1751
1752 return NULL;
1753}
1754
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001755static jobject android_media_MediaCodec_getName(
1756 JNIEnv *env, jobject thiz) {
1757 ALOGV("android_media_MediaCodec_getName");
1758
1759 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1760
1761 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001762 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001763 return NULL;
1764 }
1765
1766 jstring name;
1767 status_t err = codec->getName(env, &name);
1768
1769 if (err == OK) {
1770 return name;
1771 }
1772
1773 throwExceptionAsNecessary(env, err);
1774
1775 return NULL;
1776}
1777
Chong Zhanga0b72a62018-02-28 18:46:26 -08001778static jobject android_media_MediaCodec_getOwnCodecInfo(
1779 JNIEnv *env, jobject thiz) {
1780 ALOGV("android_media_MediaCodec_getOwnCodecInfo");
1781
1782 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1783
1784 if (codec == NULL) {
1785 throwExceptionAsNecessary(env, INVALID_OPERATION);
1786 return NULL;
1787 }
1788
1789 jobject codecInfoObj;
1790 status_t err = codec->getCodecInfo(env, &codecInfoObj);
1791
1792 if (err == OK) {
1793 return codecInfoObj;
1794 }
1795
1796 throwExceptionAsNecessary(env, err);
1797
1798 return NULL;
1799}
1800
Ray Essick0e0fee12017-01-25 18:01:56 -08001801static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08001802android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08001803{
Ray Essickf2d0e402017-03-09 10:17:51 -08001804 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08001805
1806 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1807 if (codec == NULL ) {
1808 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1809 return 0;
1810 }
1811
1812 // get what we have for the metrics from the codec
Ray Essickf2d0e402017-03-09 10:17:51 -08001813 MediaAnalyticsItem *item = NULL;
1814
1815 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08001816 if (err != OK) {
1817 ALOGE("getMetrics failed");
1818 return (jobject) NULL;
1819 }
1820
Ray Essick0e0fee12017-01-25 18:01:56 -08001821 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
1822
1823 // housekeeping
1824 delete item;
1825 item = NULL;
1826
1827 return mybundle;
1828}
1829
Andreas Huber226065b2013-08-12 10:14:11 -07001830static void android_media_MediaCodec_setParameters(
1831 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1832 ALOGV("android_media_MediaCodec_setParameters");
1833
1834 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1835
1836 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001837 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07001838 return;
1839 }
1840
1841 sp<AMessage> params;
1842 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
1843
1844 if (err == OK) {
1845 err = codec->setParameters(params);
1846 }
1847
1848 throwExceptionAsNecessary(env, err);
1849}
1850
Andreas Huberb12a5392012-04-30 14:18:33 -07001851static void android_media_MediaCodec_setVideoScalingMode(
1852 JNIEnv *env, jobject thiz, jint mode) {
1853 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1854
1855 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001856 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07001857 return;
1858 }
1859
1860 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1861 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07001862 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07001863 return;
1864 }
1865
1866 codec->setVideoScalingMode(mode);
1867}
1868
Andreas Huber88572f72012-02-21 11:47:18 -08001869static void android_media_MediaCodec_native_init(JNIEnv *env) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001870 ScopedLocalRef<jclass> clazz(
1871 env, env->FindClass("android/media/MediaCodec"));
1872 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001873
Ashok Bhat075e9a12014-01-06 13:45:09 +00001874 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08001875 CHECK(gFields.context != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001876
Andreas Huberaba67132013-10-22 12:40:01 -07001877 gFields.postEventFromNativeID =
1878 env->GetMethodID(
1879 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1880
1881 CHECK(gFields.postEventFromNativeID != NULL);
1882
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001883 jfieldID field;
1884 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
1885 CHECK(field != NULL);
1886 gCryptoModes.Unencrypted =
1887 env->GetStaticIntField(clazz.get(), field);
1888
1889 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
1890 CHECK(field != NULL);
1891 gCryptoModes.AesCtr =
1892 env->GetStaticIntField(clazz.get(), field);
1893
1894 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
1895 CHECK(field != NULL);
1896 gCryptoModes.AesCbc =
1897 env->GetStaticIntField(clazz.get(), field);
1898
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001899 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1900 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001901
1902 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001903 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001904 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1905
1906 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001907 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001908 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1909
1910 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001911 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001912 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1913
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001914 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001915 CHECK(gFields.cryptoInfoKeyID != NULL);
1916
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001917 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001918 CHECK(gFields.cryptoInfoIVID != NULL);
1919
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001920 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001921 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001922
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001923 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
1924 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
1925 CHECK(gFields.cryptoInfoPatternID != NULL);
1926
1927 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
1928 CHECK(clazz.get() != NULL);
1929
1930 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
1931 CHECK(gFields.patternEncryptBlocksID != NULL);
1932
1933 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
1934 CHECK(gFields.patternSkipBlocksID != NULL);
1935
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001936 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1937 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001938
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001939 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001940 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001941 gCryptoErrorCodes.cryptoErrorNoKey =
1942 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001943
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001944 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001945 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001946 gCryptoErrorCodes.cryptoErrorKeyExpired =
1947 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001948
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001949 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001950 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001951 gCryptoErrorCodes.cryptoErrorResourceBusy =
1952 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001953
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001954 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1955 CHECK(field != NULL);
1956 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1957 env->GetStaticIntField(clazz.get(), field);
1958
Jeff Tinker96a2a952015-07-01 17:35:18 -07001959 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1960 CHECK(field != NULL);
1961 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1962 env->GetStaticIntField(clazz.get(), field);
1963
Jeff Tinkerd3932162016-03-05 11:35:20 -08001964 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
1965 CHECK(field != NULL);
1966 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
1967 env->GetStaticIntField(clazz.get(), field);
1968
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001969 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
1970 CHECK(clazz.get() != NULL);
1971 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
1972 CHECK(field != NULL);
1973 gCodecActionCodes.codecActionTransient =
1974 env->GetStaticIntField(clazz.get(), field);
1975
1976 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
1977 CHECK(field != NULL);
1978 gCodecActionCodes.codecActionRecoverable =
1979 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001980
Ronghua Wuc53ad692015-05-08 14:40:49 -07001981 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001982 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001983 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001984 env->GetStaticIntField(clazz.get(), field);
1985
Ronghua Wuc53ad692015-05-08 14:40:49 -07001986 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001987 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001988 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001989 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07001990
1991 clazz.reset(env->FindClass("android/view/Surface"));
1992 CHECK(clazz.get() != NULL);
1993
1994 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
1995 CHECK(field != NULL);
1996 gPersistentSurfaceClassInfo.mLock = field;
1997
1998 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
1999 CHECK(method != NULL);
2000 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
2001
2002 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
2003 CHECK(clazz.get() != NULL);
2004 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
2005
2006 method = env->GetMethodID(clazz.get(), "<init>", "()V");
2007 CHECK(method != NULL);
2008 gPersistentSurfaceClassInfo.ctor = method;
2009
2010 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
2011 CHECK(field != NULL);
2012 gPersistentSurfaceClassInfo.mPersistentObject = field;
Chong Zhanga0b72a62018-02-28 18:46:26 -08002013
2014 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"));
2015 CHECK(clazz.get() != NULL);
2016 gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
2017
2018 method = env->GetMethodID(clazz.get(), "<init>",
2019 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
2020 "Ljava/util/Map;Ljava/util/Map;)V");
2021 CHECK(method != NULL);
2022 gCodecInfo.capsCtorId = method;
2023
2024 clazz.reset(env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel"));
2025 CHECK(clazz.get() != NULL);
2026 gCodecInfo.profileLevelClazz = (jclass)env->NewGlobalRef(clazz.get());
2027
2028 field = env->GetFieldID(clazz.get(), "profile", "I");
2029 CHECK(field != NULL);
2030 gCodecInfo.profileField = field;
2031
2032 field = env->GetFieldID(clazz.get(), "level", "I");
2033 CHECK(field != NULL);
2034 gCodecInfo.levelField = field;
Andreas Huber88572f72012-02-21 11:47:18 -08002035}
2036
2037static void android_media_MediaCodec_native_setup(
2038 JNIEnv *env, jobject thiz,
2039 jstring name, jboolean nameIsType, jboolean encoder) {
2040 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002041 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08002042 return;
2043 }
2044
2045 const char *tmp = env->GetStringUTFChars(name, NULL);
2046
2047 if (tmp == NULL) {
2048 return;
2049 }
2050
2051 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
2052
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002053 const status_t err = codec->initCheck();
2054 if (err == NAME_NOT_FOUND) {
2055 // fail and do not try again.
2056 jniThrowException(env, "java/lang/IllegalArgumentException",
2057 String8::format("Failed to initialize %s, error %#x", tmp, err));
2058 env->ReleaseStringUTFChars(name, tmp);
2059 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07002060 } if (err == NO_MEMORY) {
2061 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
2062 String8::format("Failed to initialize %s, error %#x", tmp, err));
2063 env->ReleaseStringUTFChars(name, tmp);
2064 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002065 } else if (err != OK) {
2066 // believed possible to try again
2067 jniThrowException(env, "java/io/IOException",
2068 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
2069 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08002070 return;
2071 }
2072
Andy Hung5f9aa0b2014-07-30 15:48:21 -07002073 env->ReleaseStringUTFChars(name, tmp);
2074
Andreas Huberaba67132013-10-22 12:40:01 -07002075 codec->registerSelf();
2076
Andreas Huber88572f72012-02-21 11:47:18 -08002077 setMediaCodec(env,thiz, codec);
2078}
2079
2080static void android_media_MediaCodec_native_finalize(
2081 JNIEnv *env, jobject thiz) {
2082 android_media_MediaCodec_release(env, thiz);
2083}
2084
Daniel Micay76f6a862015-09-19 17:31:01 -04002085static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07002086 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08002087
Lajos Molnar1e6e8012014-07-15 16:07:13 -07002088 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
2089
Chong Zhang8034d602015-04-28 13:38:48 -07002090 { "native_releasePersistentInputSurface",
2091 "(Landroid/view/Surface;)V",
2092 (void *)android_media_MediaCodec_releasePersistentInputSurface},
2093
2094 { "native_createPersistentInputSurface",
2095 "()Landroid/media/MediaCodec$PersistentSurface;",
2096 (void *)android_media_MediaCodec_createPersistentInputSurface },
2097
Chong Zhang9560ddb2015-05-13 10:25:29 -07002098 { "native_setInputSurface", "(Landroid/view/Surface;)V",
2099 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07002100
Lajos Molnard8578572015-06-05 20:17:33 -07002101 { "native_enableOnFrameRenderedListener", "(Z)V",
2102 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
2103
Chong Zhang8d5e5562014-07-08 18:49:21 -07002104 { "native_setCallback",
2105 "(Landroid/media/MediaCodec$Callback;)V",
2106 (void *)android_media_MediaCodec_native_setCallback },
2107
Andreas Huber88572f72012-02-21 11:47:18 -08002108 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07002109 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07002110 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002111 (void *)android_media_MediaCodec_native_configure },
2112
Lajos Molnar5e02ba92015-05-01 15:59:35 -07002113 { "native_setSurface",
2114 "(Landroid/view/Surface;)V",
2115 (void *)android_media_MediaCodec_native_setSurface },
2116
Andy McFadden2621e402013-02-19 07:29:21 -08002117 { "createInputSurface", "()Landroid/view/Surface;",
2118 (void *)android_media_MediaCodec_createInputSurface },
2119
Lajos Molnard4023112014-07-11 15:12:59 -07002120 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07002121 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07002122 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08002123
Lajos Molnard4023112014-07-11 15:12:59 -07002124 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002125 (void *)android_media_MediaCodec_queueInputBuffer },
2126
Lajos Molnard4023112014-07-11 15:12:59 -07002127 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07002128 (void *)android_media_MediaCodec_queueSecureInputBuffer },
2129
Lajos Molnard4023112014-07-11 15:12:59 -07002130 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08002131 (void *)android_media_MediaCodec_dequeueInputBuffer },
2132
Lajos Molnard4023112014-07-11 15:12:59 -07002133 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08002134 (void *)android_media_MediaCodec_dequeueOutputBuffer },
2135
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07002136 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08002137 (void *)android_media_MediaCodec_releaseOutputBuffer },
2138
Andy McFadden2621e402013-02-19 07:29:21 -08002139 { "signalEndOfInputStream", "()V",
2140 (void *)android_media_MediaCodec_signalEndOfInputStream },
2141
Lajos Molnard4023112014-07-11 15:12:59 -07002142 { "getFormatNative", "(Z)Ljava/util/Map;",
2143 (void *)android_media_MediaCodec_getFormatNative },
2144
2145 { "getOutputFormatNative", "(I)Ljava/util/Map;",
2146 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08002147
2148 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
2149 (void *)android_media_MediaCodec_getBuffers },
2150
Lajos Molnard4023112014-07-11 15:12:59 -07002151 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
2152 (void *)android_media_MediaCodec_getBuffer },
2153
2154 { "getImage", "(ZI)Landroid/media/Image;",
2155 (void *)android_media_MediaCodec_getImage },
2156
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002157 { "getName", "()Ljava/lang/String;",
2158 (void *)android_media_MediaCodec_getName },
2159
Chong Zhanga0b72a62018-02-28 18:46:26 -08002160 { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
2161 (void *)android_media_MediaCodec_getOwnCodecInfo },
2162
Ray Essick10353e32017-04-14 10:22:55 -07002163 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08002164 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08002165
Andreas Huber226065b2013-08-12 10:14:11 -07002166 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
2167 (void *)android_media_MediaCodec_setParameters },
2168
Andreas Huberb12a5392012-04-30 14:18:33 -07002169 { "setVideoScalingMode", "(I)V",
2170 (void *)android_media_MediaCodec_setVideoScalingMode },
2171
Andreas Huber88572f72012-02-21 11:47:18 -08002172 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
2173
2174 { "native_setup", "(Ljava/lang/String;ZZ)V",
2175 (void *)android_media_MediaCodec_native_setup },
2176
2177 { "native_finalize", "()V",
2178 (void *)android_media_MediaCodec_native_finalize },
2179};
2180
2181int register_android_media_MediaCodec(JNIEnv *env) {
2182 return AndroidRuntime::registerNativeMethods(env,
2183 "android/media/MediaCodec", gMethods, NELEM(gMethods));
2184}