blob: 022198beae45b1fb83efa8882b4152d95d6a55c4 [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>
Andreas Huber88572f72012-02-21 11:47:18 -080032
Chong Zhang2659c2f2017-04-27 13:18:20 -070033#include <android/hardware/cas/native/1.0/IDescrambler.h>
Chong Zhangd5927ae2017-01-03 11:07:18 -080034
Lajos Molnar7ac4f562014-03-24 15:57:51 -070035#include <cutils/compiler.h>
36
Mathias Agopian8335f1c2012-02-25 18:48:35 -080037#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080038
Andreas Huber0e97fc22012-04-03 13:32:16 -070039#include <media/ICrypto.h>
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>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070049#include <nativehelper/ScopedLocalRef.h>
50
Andreas Huberb12a5392012-04-30 14:18:33 -070051#include <system/window.h>
52
Andreas Huber88572f72012-02-21 11:47:18 -080053namespace android {
54
55// Keep these in sync with their equivalents in MediaCodec.java !!!
56enum {
57 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
58 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
59 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
60};
61
Andreas Huberaba67132013-10-22 12:40:01 -070062enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070063 EVENT_CALLBACK = 1,
64 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070065 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070066};
67
Andy Hung5f9aa0b2014-07-30 15:48:21 -070068static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070069 jint cryptoErrorNoKey;
70 jint cryptoErrorKeyExpired;
71 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070072 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070073 jint cryptoErrorSessionNotOpened;
Jeff Tinkerd3932162016-03-05 11:35:20 -080074 jint cryptoErrorUnsupportedOperation;
Jeff Tinker3ed38262013-08-02 23:24:51 -070075} gCryptoErrorCodes;
76
Andy Hung5f9aa0b2014-07-30 15:48:21 -070077static struct CodecActionCodes {
78 jint codecActionTransient;
79 jint codecActionRecoverable;
80} gCodecActionCodes;
81
Ronghua Wuc53ad692015-05-08 14:40:49 -070082static struct CodecErrorCodes {
83 jint errorInsufficientResource;
84 jint errorReclaimed;
85} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -070086
Chong Zhang8034d602015-04-28 13:38:48 -070087static struct {
88 jclass clazz;
89 jfieldID mLock;
90 jfieldID mPersistentObject;
91 jmethodID ctor;
92 jmethodID setNativeObjectLocked;
93} gPersistentSurfaceClassInfo;
94
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -080095static struct {
96 jint Unencrypted;
97 jint AesCtr;
98 jint AesCbc;
99} gCryptoModes;
100
101
Andreas Huber88572f72012-02-21 11:47:18 -0800102struct fields_t {
103 jfieldID context;
Andreas Huberaba67132013-10-22 12:40:01 -0700104 jmethodID postEventFromNativeID;
Andreas Huber91befdc2012-04-18 12:19:51 -0700105 jfieldID cryptoInfoNumSubSamplesID;
106 jfieldID cryptoInfoNumBytesOfClearDataID;
107 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
108 jfieldID cryptoInfoKeyID;
109 jfieldID cryptoInfoIVID;
110 jfieldID cryptoInfoModeID;
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800111 jfieldID cryptoInfoPatternID;
112 jfieldID patternEncryptBlocksID;
113 jfieldID patternSkipBlocksID;
Andreas Huber88572f72012-02-21 11:47:18 -0800114};
115
116static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700117static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800118
119////////////////////////////////////////////////////////////////////////////////
120
121JMediaCodec::JMediaCodec(
122 JNIEnv *env, jobject thiz,
123 const char *name, bool nameIsType, bool encoder)
124 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700125 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800126 jclass clazz = env->GetObjectClass(thiz);
127 CHECK(clazz != NULL);
128
129 mClass = (jclass)env->NewGlobalRef(clazz);
130 mObject = env->NewWeakGlobalRef(thiz);
131
Lajos Molnar7de28d32014-07-25 07:51:02 -0700132 cacheJavaObjects(env);
133
Andreas Huber88572f72012-02-21 11:47:18 -0800134 mLooper = new ALooper;
135 mLooper->setName("MediaCodec_looper");
136
137 mLooper->start(
138 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700139 true, // canCallJava
Jeff Tinkere182d202017-09-07 16:46:50 -0700140 ANDROID_PRIORITY_VIDEO);
Andreas Huber88572f72012-02-21 11:47:18 -0800141
142 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700143 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800144 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700145 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800146 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700147 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800148}
149
Lajos Molnar7de28d32014-07-25 07:51:02 -0700150void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
151 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
152 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
153 CHECK(mByteBufferClass != NULL);
154
155 ScopedLocalRef<jclass> byteOrderClass(
156 env, env->FindClass("java/nio/ByteOrder"));
157 CHECK(byteOrderClass.get() != NULL);
158
159 jmethodID nativeOrderID = env->GetStaticMethodID(
160 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
161 CHECK(nativeOrderID != NULL);
162
163 jobject nativeByteOrderObj =
164 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
165 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
166 CHECK(mNativeByteOrderObj != NULL);
167 env->DeleteLocalRef(nativeByteOrderObj);
168 nativeByteOrderObj = NULL;
169
170 mByteBufferOrderMethodID = env->GetMethodID(
171 mByteBufferClass,
172 "order",
173 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
174 CHECK(mByteBufferOrderMethodID != NULL);
175
176 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
177 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
178 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
179
180 mByteBufferPositionMethodID = env->GetMethodID(
181 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
182 CHECK(mByteBufferPositionMethodID != NULL);
183
184 mByteBufferLimitMethodID = env->GetMethodID(
185 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
186 CHECK(mByteBufferLimitMethodID != NULL);
187}
188
Andreas Huber88572f72012-02-21 11:47:18 -0800189status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700190 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800191}
192
Andreas Huberaba67132013-10-22 12:40:01 -0700193void JMediaCodec::registerSelf() {
194 mLooper->registerHandler(this);
195}
196
Chong Zhang128b0122014-03-01 18:04:13 -0800197void JMediaCodec::release() {
Martin Storsjod932de92012-07-13 13:01:06 +0300198 if (mCodec != NULL) {
199 mCodec->release();
200 mCodec.clear();
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700201 mInitStatus = NO_INIT;
Martin Storsjod932de92012-07-13 13:01:06 +0300202 }
Andreas Huber88572f72012-02-21 11:47:18 -0800203
Chong Zhang128b0122014-03-01 18:04:13 -0800204 if (mLooper != NULL) {
205 mLooper->unregisterHandler(id());
206 mLooper->stop();
207 mLooper.clear();
208 }
209}
210
211JMediaCodec::~JMediaCodec() {
212 if (mCodec != NULL || mLooper != NULL) {
213 /* MediaCodec and looper should have been released explicitly already
214 * in setMediaCodec() (see comments in setMediaCodec()).
215 *
216 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
217 * message handler, doing release() there risks deadlock as MediaCodec::
218 * release() post synchronous message to the same looper.
219 *
220 * Print a warning and try to proceed with releasing.
221 */
222 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
223 release();
224 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
225 }
226
Andreas Huber88572f72012-02-21 11:47:18 -0800227 JNIEnv *env = AndroidRuntime::getJNIEnv();
228
229 env->DeleteWeakGlobalRef(mObject);
230 mObject = NULL;
231 env->DeleteGlobalRef(mClass);
232 mClass = NULL;
Lajos Molnar7de28d32014-07-25 07:51:02 -0700233 deleteJavaObjects(env);
234}
235
236void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
237 env->DeleteGlobalRef(mByteBufferClass);
238 mByteBufferClass = NULL;
239 env->DeleteGlobalRef(mNativeByteOrderObj);
240 mNativeByteOrderObj = NULL;
241
242 mByteBufferOrderMethodID = NULL;
243 mByteBufferAsReadOnlyBufferMethodID = NULL;
244 mByteBufferPositionMethodID = NULL;
245 mByteBufferLimitMethodID = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800246}
247
Lajos Molnard8578572015-06-05 20:17:33 -0700248status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
249 if (enable) {
250 if (mOnFrameRenderedNotification == NULL) {
251 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
252 }
253 } else {
254 mOnFrameRenderedNotification.clear();
255 }
256
257 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
258}
259
Chong Zhang8d5e5562014-07-08 18:49:21 -0700260status_t JMediaCodec::setCallback(jobject cb) {
261 if (cb != NULL) {
262 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800263 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700264 }
265 } else {
266 mCallbackNotification.clear();
267 }
268
269 return mCodec->setCallback(mCallbackNotification);
270}
271
Andreas Huber88572f72012-02-21 11:47:18 -0800272status_t JMediaCodec::configure(
273 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800274 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700275 const sp<ICrypto> &crypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800276 const sp<IDescrambler> &descrambler,
Andreas Huber88572f72012-02-21 11:47:18 -0800277 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800278 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800279 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700280 mSurfaceTextureClient =
281 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700282 } else {
283 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800284 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700285
Chong Zhangd5927ae2017-01-03 11:07:18 -0800286 return mCodec->configure(
287 format, mSurfaceTextureClient, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800288}
289
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700290status_t JMediaCodec::setSurface(
291 const sp<IGraphicBufferProducer> &bufferProducer) {
292 sp<Surface> client;
293 if (bufferProducer != NULL) {
294 client = new Surface(bufferProducer, true /* controlledByApp */);
295 }
296 status_t err = mCodec->setSurface(client);
297 if (err == OK) {
298 mSurfaceTextureClient = client;
299 }
300 return err;
301}
302
Andy McFadden2621e402013-02-19 07:29:21 -0800303status_t JMediaCodec::createInputSurface(
304 sp<IGraphicBufferProducer>* bufferProducer) {
305 return mCodec->createInputSurface(bufferProducer);
306}
307
Chong Zhang9560ddb2015-05-13 10:25:29 -0700308status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700309 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700310 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700311}
312
Andreas Huber88572f72012-02-21 11:47:18 -0800313status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700314 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800315}
316
317status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700318 mSurfaceTextureClient.clear();
319
Chong Zhang8d5e5562014-07-08 18:49:21 -0700320 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800321}
322
323status_t JMediaCodec::flush() {
324 return mCodec->flush();
325}
326
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700327status_t JMediaCodec::reset() {
328 return mCodec->reset();
329}
330
Andreas Huber88572f72012-02-21 11:47:18 -0800331status_t JMediaCodec::queueInputBuffer(
332 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700333 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
334 AString *errorDetailMsg) {
335 return mCodec->queueInputBuffer(
336 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800337}
338
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700339status_t JMediaCodec::queueSecureInputBuffer(
340 size_t index,
341 size_t offset,
342 const CryptoPlugin::SubSample *subSamples,
343 size_t numSubSamples,
344 const uint8_t key[16],
345 const uint8_t iv[16],
346 CryptoPlugin::Mode mode,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800347 const CryptoPlugin::Pattern &pattern,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700348 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700349 uint32_t flags,
350 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700351 return mCodec->queueSecureInputBuffer(
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -0800352 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700353 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700354}
355
Andreas Huber88572f72012-02-21 11:47:18 -0800356status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700357 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800358}
359
360status_t JMediaCodec::dequeueOutputBuffer(
361 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
362 size_t size, offset;
363 int64_t timeUs;
364 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700365 status_t err = mCodec->dequeueOutputBuffer(
366 index, &offset, &size, &timeUs, &flags, timeoutUs);
367
Andreas Huberaba67132013-10-22 12:40:01 -0700368 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800369 return err;
370 }
371
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700372 ScopedLocalRef<jclass> clazz(
373 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800374
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700375 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000376 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800377
378 return OK;
379}
380
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700381status_t JMediaCodec::releaseOutputBuffer(
382 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
383 if (updatePTS) {
384 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
385 }
Andreas Huber88572f72012-02-21 11:47:18 -0800386 return render
387 ? mCodec->renderOutputBufferAndRelease(index)
388 : mCodec->releaseOutputBuffer(index);
389}
390
Andy McFadden2621e402013-02-19 07:29:21 -0800391status_t JMediaCodec::signalEndOfInputStream() {
392 return mCodec->signalEndOfInputStream();
393}
394
Lajos Molnard4023112014-07-11 15:12:59 -0700395status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800396 sp<AMessage> msg;
397 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700398 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
399 if (err != OK) {
400 return err;
401 }
402
403 return ConvertMessageToMap(env, msg, format);
404}
405
406status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
407 sp<AMessage> msg;
408 status_t err;
409 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800410 return err;
411 }
412
413 return ConvertMessageToMap(env, msg, format);
414}
415
416status_t JMediaCodec::getBuffers(
417 JNIEnv *env, bool input, jobjectArray *bufArray) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900418 Vector<sp<MediaCodecBuffer> > buffers;
Andreas Huber88572f72012-02-21 11:47:18 -0800419
420 status_t err =
421 input
422 ? mCodec->getInputBuffers(&buffers)
423 : mCodec->getOutputBuffers(&buffers);
424
425 if (err != OK) {
426 return err;
427 }
428
Andreas Huber88572f72012-02-21 11:47:18 -0800429 *bufArray = (jobjectArray)env->NewObjectArray(
Lajos Molnar7de28d32014-07-25 07:51:02 -0700430 buffers.size(), mByteBufferClass, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800431 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800432 return NO_MEMORY;
433 }
Andreas Huber88572f72012-02-21 11:47:18 -0800434
435 for (size_t i = 0; i < buffers.size(); ++i) {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900436 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
Andreas Huber88572f72012-02-21 11:47:18 -0800437
Lajos Molnar7de28d32014-07-25 07:51:02 -0700438 jobject byteBuffer = NULL;
439 err = createByteBufferFromABuffer(
440 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
441 if (err != OK) {
442 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800443 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700444 if (byteBuffer != NULL) {
445 env->SetObjectArrayElement(
446 *bufArray, i, byteBuffer);
447
Lajos Molnard4023112014-07-11 15:12:59 -0700448 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700449 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700450 }
Andreas Huber88572f72012-02-21 11:47:18 -0800451 }
452
Lajos Molnar7de28d32014-07-25 07:51:02 -0700453 return OK;
454}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700455
Lajos Molnar7de28d32014-07-25 07:51:02 -0700456// static
Wonsik Kim4273dd02016-09-27 15:23:35 +0900457template <typename T>
Lajos Molnar7de28d32014-07-25 07:51:02 -0700458status_t JMediaCodec::createByteBufferFromABuffer(
Wonsik Kim4273dd02016-09-27 15:23:35 +0900459 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
Lajos Molnar7de28d32014-07-25 07:51:02 -0700460 jobject *buf) const {
461 // if this is an ABuffer that doesn't actually hold any accessible memory,
462 // use a null ByteBuffer
463 *buf = NULL;
Aaron Vaagee5b641e2015-09-03 15:12:57 -0700464
465 if (buffer == NULL) {
466 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
467 return OK;
468 }
469
Lajos Molnar7de28d32014-07-25 07:51:02 -0700470 if (buffer->base() == NULL) {
471 return OK;
472 }
473
474 jobject byteBuffer =
475 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
476 if (readOnly && byteBuffer != NULL) {
477 jobject readOnlyBuffer = env->CallObjectMethod(
478 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
479 env->DeleteLocalRef(byteBuffer);
480 byteBuffer = readOnlyBuffer;
481 }
482 if (byteBuffer == NULL) {
483 return NO_MEMORY;
484 }
485 jobject me = env->CallObjectMethod(
486 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
487 env->DeleteLocalRef(me);
488 me = env->CallObjectMethod(
489 byteBuffer, mByteBufferLimitMethodID,
490 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
491 env->DeleteLocalRef(me);
492 me = env->CallObjectMethod(
493 byteBuffer, mByteBufferPositionMethodID,
494 clearBuffer ? 0 : buffer->offset());
495 env->DeleteLocalRef(me);
496 me = NULL;
497
498 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800499 return OK;
500}
501
Lajos Molnard4023112014-07-11 15:12:59 -0700502status_t JMediaCodec::getBuffer(
503 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900504 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700505
506 status_t err =
507 input
508 ? mCodec->getInputBuffer(index, &buffer)
509 : mCodec->getOutputBuffer(index, &buffer);
510
511 if (err != OK) {
512 return err;
513 }
514
Lajos Molnar7de28d32014-07-25 07:51:02 -0700515 return createByteBufferFromABuffer(
516 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700517}
518
519status_t JMediaCodec::getImage(
520 JNIEnv *env, bool input, size_t index, jobject *buf) const {
Wonsik Kim4273dd02016-09-27 15:23:35 +0900521 sp<MediaCodecBuffer> buffer;
Lajos Molnard4023112014-07-11 15:12:59 -0700522
523 status_t err =
524 input
525 ? mCodec->getInputBuffer(index, &buffer)
526 : mCodec->getOutputBuffer(index, &buffer);
527
528 if (err != OK) {
529 return err;
530 }
531
532 // if this is an ABuffer that doesn't actually hold any accessible memory,
533 // use a null ByteBuffer
534 *buf = NULL;
535 if (buffer->base() == NULL) {
536 return OK;
537 }
538
539 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700540 sp<ABuffer> imageData;
541 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700542 return OK;
543 }
544
Lajos Molnar7de28d32014-07-25 07:51:02 -0700545 int64_t timestamp = 0;
546 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
547 timestamp *= 1000; // adjust to ns
548 }
549
550 jobject byteBuffer = NULL;
551 err = createByteBufferFromABuffer(
552 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
553 if (err != OK) {
554 return OK;
555 }
556
557 jobject infoBuffer = NULL;
558 err = createByteBufferFromABuffer(
559 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
560 if (err != OK) {
561 env->DeleteLocalRef(byteBuffer);
562 byteBuffer = NULL;
563 return OK;
564 }
565
566 jobject cropRect = NULL;
567 int32_t left, top, right, bottom;
568 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
569 ScopedLocalRef<jclass> rectClazz(
570 env, env->FindClass("android/graphics/Rect"));
571 CHECK(rectClazz.get() != NULL);
572
573 jmethodID rectConstructID = env->GetMethodID(
574 rectClazz.get(), "<init>", "(IIII)V");
575
576 cropRect = env->NewObject(
577 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
578 }
579
580 ScopedLocalRef<jclass> imageClazz(
581 env, env->FindClass("android/media/MediaCodec$MediaImage"));
582 CHECK(imageClazz.get() != NULL);
583
584 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
585 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
586
587 *buf = env->NewObject(imageClazz.get(), imageConstructID,
588 byteBuffer, infoBuffer,
589 (jboolean)!input /* readOnly */,
590 (jlong)timestamp,
591 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
592
593 // if MediaImage creation fails, return null
594 if (env->ExceptionCheck()) {
595 env->ExceptionDescribe();
596 env->ExceptionClear();
597 *buf = NULL;
598 }
599
600 if (cropRect != NULL) {
601 env->DeleteLocalRef(cropRect);
602 cropRect = NULL;
603 }
604
605 env->DeleteLocalRef(byteBuffer);
606 byteBuffer = NULL;
607
608 env->DeleteLocalRef(infoBuffer);
609 infoBuffer = NULL;
610
Lajos Molnard4023112014-07-11 15:12:59 -0700611 return OK;
612}
613
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300614status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
615 AString name;
616
617 status_t err = mCodec->getName(&name);
618
619 if (err != OK) {
620 return err;
621 }
622
623 *nameStr = env->NewStringUTF(name.c_str());
624
625 return OK;
626}
627
Ray Essickf2d0e402017-03-09 10:17:51 -0800628status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
Ray Essick0e0fee12017-01-25 18:01:56 -0800629
630 status_t status = mCodec->getMetrics(reply);
631 return status;
632}
633
Andreas Huber226065b2013-08-12 10:14:11 -0700634status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
635 return mCodec->setParameters(msg);
636}
637
Andreas Huberb12a5392012-04-30 14:18:33 -0700638void JMediaCodec::setVideoScalingMode(int mode) {
639 if (mSurfaceTextureClient != NULL) {
640 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
641 }
642}
643
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700644static jthrowable createCodecException(
645 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
646 ScopedLocalRef<jclass> clazz(
647 env, env->FindClass("android/media/MediaCodec$CodecException"));
648 CHECK(clazz.get() != NULL);
649
Ronghua Wuc53ad692015-05-08 14:40:49 -0700650 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700651 CHECK(ctor != NULL);
652
653 ScopedLocalRef<jstring> msgObj(
654 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
655
656 // translate action code to Java equivalent
657 switch (actionCode) {
658 case ACTION_CODE_TRANSIENT:
659 actionCode = gCodecActionCodes.codecActionTransient;
660 break;
661 case ACTION_CODE_RECOVERABLE:
662 actionCode = gCodecActionCodes.codecActionRecoverable;
663 break;
664 default:
665 actionCode = 0; // everything else is fatal
666 break;
667 }
668
Ronghua Wuc53ad692015-05-08 14:40:49 -0700669 /* translate OS errors to Java API CodecException errorCodes */
670 switch (err) {
671 case NO_MEMORY:
672 err = gCodecErrorCodes.errorInsufficientResource;
673 break;
674 case DEAD_OBJECT:
675 err = gCodecErrorCodes.errorReclaimed;
676 break;
677 default: /* Other error codes go out as is. */
678 break;
679 }
680
681 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700682}
683
Chong Zhang8d5e5562014-07-08 18:49:21 -0700684void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
685 int32_t arg1, arg2 = 0;
686 jobject obj = NULL;
687 CHECK(msg->findInt32("callbackID", &arg1));
688 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700689
Chong Zhang8d5e5562014-07-08 18:49:21 -0700690 switch (arg1) {
691 case MediaCodec::CB_INPUT_AVAILABLE:
692 {
693 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700694 break;
695 }
696
Chong Zhang8d5e5562014-07-08 18:49:21 -0700697 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700698 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700699 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700700
Chong Zhang8d5e5562014-07-08 18:49:21 -0700701 size_t size, offset;
702 int64_t timeUs;
703 uint32_t flags;
704 CHECK(msg->findSize("size", &size));
705 CHECK(msg->findSize("offset", &offset));
706 CHECK(msg->findInt64("timeUs", &timeUs));
707 CHECK(msg->findInt32("flags", (int32_t *)&flags));
708
709 ScopedLocalRef<jclass> clazz(
710 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
711 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
712 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
713
714 obj = env->NewObject(clazz.get(), ctor);
715
716 if (obj == NULL) {
717 if (env->ExceptionCheck()) {
718 ALOGE("Could not create MediaCodec.BufferInfo.");
719 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700720 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700721 jniThrowException(env, "java/lang/IllegalStateException", NULL);
722 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700723 }
724
Chong Zhang8d5e5562014-07-08 18:49:21 -0700725 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
726 break;
727 }
728
729 case MediaCodec::CB_ERROR:
730 {
Chong Zhang94686d12014-07-11 15:53:58 -0700731 int32_t err, actionCode;
732 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -0700733 CHECK(msg->findInt32("actionCode", &actionCode));
734
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700735 // note that DRM errors could conceivably alias into a CodecException
736 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700737
738 if (obj == NULL) {
739 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -0700740 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -0700741 env->ExceptionClear();
742 }
743 jniThrowException(env, "java/lang/IllegalStateException", NULL);
744 return;
745 }
Andreas Huberaba67132013-10-22 12:40:01 -0700746
747 break;
748 }
749
Chong Zhang8d5e5562014-07-08 18:49:21 -0700750 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -0700751 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700752 sp<AMessage> format;
753 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -0700754
Chong Zhang8d5e5562014-07-08 18:49:21 -0700755 if (OK != ConvertMessageToMap(env, format, &obj)) {
756 jniThrowException(env, "java/lang/IllegalStateException", NULL);
757 return;
758 }
Andreas Huberaba67132013-10-22 12:40:01 -0700759
Andreas Huberaba67132013-10-22 12:40:01 -0700760 break;
761 }
762
763 default:
764 TRESPASS();
765 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700766
767 env->CallVoidMethod(
768 mObject,
769 gFields.postEventFromNativeID,
770 EVENT_CALLBACK,
771 arg1,
772 arg2,
773 obj);
774
775 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -0700776}
777
Lajos Molnard8578572015-06-05 20:17:33 -0700778void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
779 int32_t arg1 = 0, arg2 = 0;
780 jobject obj = NULL;
781 JNIEnv *env = AndroidRuntime::getJNIEnv();
782
783 sp<AMessage> data;
784 CHECK(msg->findMessage("data", &data));
785
786 status_t err = ConvertMessageToMap(env, data, &obj);
787 if (err != OK) {
788 jniThrowException(env, "java/lang/IllegalStateException", NULL);
789 return;
790 }
791
792 env->CallVoidMethod(
793 mObject, gFields.postEventFromNativeID,
794 EVENT_FRAME_RENDERED, arg1, arg2, obj);
795
796 env->DeleteLocalRef(obj);
797}
798
Chong Zhang8d5e5562014-07-08 18:49:21 -0700799void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
800 switch (msg->what()) {
801 case kWhatCallbackNotify:
802 {
803 handleCallback(msg);
804 break;
805 }
Lajos Molnard8578572015-06-05 20:17:33 -0700806 case kWhatFrameRendered:
807 {
808 handleFrameRenderedNotification(msg);
809 break;
810 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700811 default:
812 TRESPASS();
813 }
Andreas Huberaba67132013-10-22 12:40:01 -0700814}
815
Andreas Huber88572f72012-02-21 11:47:18 -0800816} // namespace android
817
818////////////////////////////////////////////////////////////////////////////////
819
820using namespace android;
821
822static sp<JMediaCodec> setMediaCodec(
823 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000824 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800825 if (codec != NULL) {
826 codec->incStrong(thiz);
827 }
828 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800829 /* release MediaCodec and stop the looper now before decStrong.
830 * otherwise JMediaCodec::~JMediaCodec() could be called from within
831 * its message handler, doing release() from there will deadlock
832 * (as MediaCodec::release() post synchronous message to the same looper)
833 */
834 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -0800835 old->decStrong(thiz);
836 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000837 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -0800838
839 return old;
840}
841
842static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000843 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800844}
845
846static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
847 setMediaCodec(env, thiz, NULL);
848}
849
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700850static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
851 jthrowable exception = createCodecException(env, err, actionCode, msg);
852 env->Throw(exception);
853}
854
Andreas Huberbfc56f42012-04-19 12:47:07 -0700855static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700856 ScopedLocalRef<jclass> clazz(
857 env, env->FindClass("android/media/MediaCodec$CryptoException"));
858 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700859
860 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700861 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -0700862 CHECK(constructID != NULL);
863
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800864 const char *defaultMsg = "Unknown Error";
Andreas Huberbfc56f42012-04-19 12:47:07 -0700865
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700866 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700867 switch (err) {
868 case ERROR_DRM_NO_LICENSE:
869 err = gCryptoErrorCodes.cryptoErrorNoKey;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800870 defaultMsg = "Crypto key not available";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700871 break;
872 case ERROR_DRM_LICENSE_EXPIRED:
873 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800874 defaultMsg = "License expired";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700875 break;
876 case ERROR_DRM_RESOURCE_BUSY:
877 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800878 defaultMsg = "Resource busy or unavailable";
Jeff Tinker3ed38262013-08-02 23:24:51 -0700879 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700880 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
881 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800882 defaultMsg = "Required output protections are not active";
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700883 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700884 case ERROR_DRM_SESSION_NOT_OPENED:
885 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800886 defaultMsg = "Attempted to use a closed session";
Jeff Tinker96a2a952015-07-01 17:35:18 -0700887 break;
Jeff Tinkerd3932162016-03-05 11:35:20 -0800888 case ERROR_DRM_CANNOT_HANDLE:
889 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
890 defaultMsg = "Operation not supported in this configuration";
891 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700892 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700893 break;
894 }
895
Jeff Tinker3ccb34d2015-11-09 17:31:05 -0800896 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
897
Andreas Huberbfc56f42012-04-19 12:47:07 -0700898 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700899 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700900
901 env->Throw(exception);
902}
903
904static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700905 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
906 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800907 switch (err) {
908 case OK:
909 return 0;
910
911 case -EAGAIN:
912 return DEQUEUE_INFO_TRY_AGAIN_LATER;
913
914 case INFO_FORMAT_CHANGED:
915 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
916
917 case INFO_OUTPUT_BUFFERS_CHANGED:
918 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
919
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700920 case INVALID_OPERATION:
921 jniThrowException(env, "java/lang/IllegalStateException", msg);
922 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700923
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700924 case BAD_VALUE:
925 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
926 return 0;
927
Andreas Huber88572f72012-02-21 11:47:18 -0800928 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700929 if (isCryptoError(err)) {
930 throwCryptoException(env, err, msg);
931 return 0;
932 }
933 throwCodecException(env, err, actionCode, msg);
934 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -0800935 }
Andreas Huber88572f72012-02-21 11:47:18 -0800936}
937
Lajos Molnard8578572015-06-05 20:17:33 -0700938static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
939 JNIEnv *env,
940 jobject thiz,
941 jboolean enabled) {
942 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
943
944 if (codec == NULL) {
945 throwExceptionAsNecessary(env, INVALID_OPERATION);
946 return;
947 }
948
949 status_t err = codec->enableOnFrameRenderedListener(enabled);
950
951 throwExceptionAsNecessary(env, err);
952}
953
Chong Zhang8d5e5562014-07-08 18:49:21 -0700954static void android_media_MediaCodec_native_setCallback(
955 JNIEnv *env,
956 jobject thiz,
957 jobject cb) {
958 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
959
960 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700961 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700962 return;
963 }
964
965 status_t err = codec->setCallback(cb);
966
967 throwExceptionAsNecessary(env, err);
968}
969
Andreas Huber88572f72012-02-21 11:47:18 -0800970static void android_media_MediaCodec_native_configure(
971 JNIEnv *env,
972 jobject thiz,
973 jobjectArray keys, jobjectArray values,
974 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -0700975 jobject jcrypto,
Chong Zhangd5927ae2017-01-03 11:07:18 -0800976 jobject descramblerBinderObj,
Andreas Huber88572f72012-02-21 11:47:18 -0800977 jint flags) {
978 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
979
980 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700981 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -0800982 return;
983 }
984
985 sp<AMessage> format;
986 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
987
988 if (err != OK) {
989 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
990 return;
991 }
992
Andy McFaddend47f7d82012-12-18 09:48:38 -0800993 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -0800994 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700995 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -0800996 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -0800997 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -0800998 } else {
999 jniThrowException(
1000 env,
1001 "java/lang/IllegalArgumentException",
1002 "The surface has been released");
1003 return;
1004 }
1005 }
1006
Andreas Huber8240d922012-04-04 14:06:32 -07001007 sp<ICrypto> crypto;
1008 if (jcrypto != NULL) {
1009 crypto = JCrypto::GetCrypto(env, jcrypto);
1010 }
1011
Chong Zhangd5927ae2017-01-03 11:07:18 -08001012 sp<IDescrambler> descrambler;
1013 if (descramblerBinderObj != NULL) {
Chong Zhang2659c2f2017-04-27 13:18:20 -07001014 descrambler = JDescrambler::GetDescrambler(env, descramblerBinderObj);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001015 }
1016
1017 err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
Andreas Huber88572f72012-02-21 11:47:18 -08001018
1019 throwExceptionAsNecessary(env, err);
1020}
1021
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001022static void android_media_MediaCodec_native_setSurface(
1023 JNIEnv *env,
1024 jobject thiz,
1025 jobject jsurface) {
1026 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1027
1028 if (codec == NULL) {
1029 throwExceptionAsNecessary(env, INVALID_OPERATION);
1030 return;
1031 }
1032
1033 sp<IGraphicBufferProducer> bufferProducer;
1034 if (jsurface != NULL) {
1035 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1036 if (surface != NULL) {
1037 bufferProducer = surface->getIGraphicBufferProducer();
1038 } else {
1039 jniThrowException(
1040 env,
1041 "java/lang/IllegalArgumentException",
1042 "The surface has been released");
1043 return;
1044 }
1045 }
1046
1047 status_t err = codec->setSurface(bufferProducer);
1048 throwExceptionAsNecessary(env, err);
1049}
1050
Chong Zhang8034d602015-04-28 13:38:48 -07001051sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1052 JNIEnv* env, jobject object) {
1053 sp<PersistentSurface> persistentSurface;
1054
1055 jobject lock = env->GetObjectField(
1056 object, gPersistentSurfaceClassInfo.mLock);
1057 if (env->MonitorEnter(lock) == JNI_OK) {
1058 persistentSurface = reinterpret_cast<PersistentSurface *>(
1059 env->GetLongField(object,
1060 gPersistentSurfaceClassInfo.mPersistentObject));
1061 env->MonitorExit(lock);
1062 }
1063 env->DeleteLocalRef(lock);
1064
1065 return persistentSurface;
1066}
1067
1068static jobject android_media_MediaCodec_createPersistentInputSurface(
1069 JNIEnv* env, jclass /* clazz */) {
1070 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1071 sp<PersistentSurface> persistentSurface =
1072 MediaCodec::CreatePersistentInputSurface();
1073
1074 if (persistentSurface == NULL) {
1075 return NULL;
1076 }
1077
1078 sp<Surface> surface = new Surface(
1079 persistentSurface->getBufferProducer(), true);
1080 if (surface == NULL) {
1081 return NULL;
1082 }
1083
1084 jobject object = env->NewObject(
1085 gPersistentSurfaceClassInfo.clazz,
1086 gPersistentSurfaceClassInfo.ctor);
1087
1088 if (object == NULL) {
1089 if (env->ExceptionCheck()) {
1090 ALOGE("Could not create PersistentSurface.");
1091 env->ExceptionClear();
1092 }
1093 return NULL;
1094 }
1095
1096 jobject lock = env->GetObjectField(
1097 object, gPersistentSurfaceClassInfo.mLock);
1098 if (env->MonitorEnter(lock) == JNI_OK) {
1099 env->CallVoidMethod(
1100 object,
1101 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1102 (jlong)surface.get());
1103 env->SetLongField(
1104 object,
1105 gPersistentSurfaceClassInfo.mPersistentObject,
1106 (jlong)persistentSurface.get());
1107 env->MonitorExit(lock);
1108 } else {
1109 env->DeleteLocalRef(object);
1110 object = NULL;
1111 }
1112 env->DeleteLocalRef(lock);
1113
1114 if (object != NULL) {
1115 surface->incStrong(&sRefBaseOwner);
1116 persistentSurface->incStrong(&sRefBaseOwner);
1117 }
1118
1119 return object;
1120}
1121
1122static void android_media_MediaCodec_releasePersistentInputSurface(
1123 JNIEnv* env, jclass /* clazz */, jobject object) {
1124 sp<PersistentSurface> persistentSurface;
1125
1126 jobject lock = env->GetObjectField(
1127 object, gPersistentSurfaceClassInfo.mLock);
1128 if (env->MonitorEnter(lock) == JNI_OK) {
1129 persistentSurface = reinterpret_cast<PersistentSurface *>(
1130 env->GetLongField(
1131 object, gPersistentSurfaceClassInfo.mPersistentObject));
1132 env->SetLongField(
1133 object,
1134 gPersistentSurfaceClassInfo.mPersistentObject,
1135 (jlong)0);
1136 env->MonitorExit(lock);
1137 }
1138 env->DeleteLocalRef(lock);
1139
1140 if (persistentSurface != NULL) {
1141 persistentSurface->decStrong(&sRefBaseOwner);
1142 }
1143 // no need to release surface as it will be released by Surface's jni
1144}
1145
Chong Zhang9560ddb2015-05-13 10:25:29 -07001146static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001147 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001148 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001149
1150 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1151 if (codec == NULL) {
1152 throwExceptionAsNecessary(env, INVALID_OPERATION);
1153 return;
1154 }
1155
1156 sp<PersistentSurface> persistentSurface =
1157 android_media_MediaCodec_getPersistentInputSurface(env, object);
1158
Chong Zhang9560ddb2015-05-13 10:25:29 -07001159 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001160 if (err != NO_ERROR) {
1161 throwExceptionAsNecessary(env, err);
1162 }
1163}
1164
Andy McFadden2621e402013-02-19 07:29:21 -08001165static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1166 jobject thiz) {
1167 ALOGV("android_media_MediaCodec_createInputSurface");
1168
1169 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1170 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001171 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001172 return NULL;
1173 }
1174
1175 // Tell the MediaCodec that we want to use a Surface as input.
1176 sp<IGraphicBufferProducer> bufferProducer;
1177 status_t err = codec->createInputSurface(&bufferProducer);
1178 if (err != NO_ERROR) {
1179 throwExceptionAsNecessary(env, err);
1180 return NULL;
1181 }
1182
1183 // Wrap the IGBP in a Java-language Surface.
1184 return android_view_Surface_createFromIGraphicBufferProducer(env,
1185 bufferProducer);
1186}
1187
Andreas Huber88572f72012-02-21 11:47:18 -08001188static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1189 ALOGV("android_media_MediaCodec_start");
1190
1191 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1192
1193 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001194 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001195 return;
1196 }
1197
1198 status_t err = codec->start();
1199
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001200 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001201}
1202
1203static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1204 ALOGV("android_media_MediaCodec_stop");
1205
1206 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1207
1208 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001209 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001210 return;
1211 }
1212
1213 status_t err = codec->stop();
1214
1215 throwExceptionAsNecessary(env, err);
1216}
1217
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001218static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1219 ALOGV("android_media_MediaCodec_reset");
1220
1221 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1222
1223 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001224 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001225 return;
1226 }
1227
1228 status_t err = codec->reset();
1229 if (err != OK) {
1230 // treat all errors as fatal for now, though resource not available
1231 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001232 // we also should avoid sending INVALID_OPERATION here due to
1233 // the transitory nature of reset(), it should not inadvertently
1234 // trigger an IllegalStateException.
1235 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001236 }
1237 throwExceptionAsNecessary(env, err);
1238}
1239
Andreas Huber88572f72012-02-21 11:47:18 -08001240static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1241 ALOGV("android_media_MediaCodec_flush");
1242
1243 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1244
1245 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001246 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001247 return;
1248 }
1249
1250 status_t err = codec->flush();
1251
1252 throwExceptionAsNecessary(env, err);
1253}
1254
1255static void android_media_MediaCodec_queueInputBuffer(
1256 JNIEnv *env,
1257 jobject thiz,
1258 jint index,
1259 jint offset,
1260 jint size,
1261 jlong timestampUs,
1262 jint flags) {
1263 ALOGV("android_media_MediaCodec_queueInputBuffer");
1264
1265 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1266
1267 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001268 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001269 return;
1270 }
1271
Andreas Huberbfc56f42012-04-19 12:47:07 -07001272 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001273
Andreas Huberbfc56f42012-04-19 12:47:07 -07001274 status_t err = codec->queueInputBuffer(
1275 index, offset, size, timestampUs, flags, &errorDetailMsg);
1276
1277 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001278 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001279}
1280
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001281static void android_media_MediaCodec_queueSecureInputBuffer(
1282 JNIEnv *env,
1283 jobject thiz,
1284 jint index,
1285 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001286 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001287 jlong timestampUs,
1288 jint flags) {
1289 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1290
1291 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1292
1293 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001294 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001295 return;
1296 }
1297
Andreas Huber91befdc2012-04-18 12:19:51 -07001298 jint numSubSamples =
1299 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1300
1301 jintArray numBytesOfClearDataObj =
1302 (jintArray)env->GetObjectField(
1303 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1304
1305 jintArray numBytesOfEncryptedDataObj =
1306 (jintArray)env->GetObjectField(
1307 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1308
1309 jbyteArray keyObj =
1310 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1311
1312 jbyteArray ivObj =
1313 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1314
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001315 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1316 enum CryptoPlugin::Mode mode;
1317 if (jmode == gCryptoModes.Unencrypted) {
1318 mode = CryptoPlugin::kMode_Unencrypted;
1319 } else if (jmode == gCryptoModes.AesCtr) {
1320 mode = CryptoPlugin::kMode_AES_CTR;
1321 } else if (jmode == gCryptoModes.AesCbc) {
1322 mode = CryptoPlugin::kMode_AES_CBC;
1323 } else {
1324 throwExceptionAsNecessary(env, INVALID_OPERATION);
1325 return;
1326 }
1327
1328 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1329
1330 CryptoPlugin::Pattern pattern;
Jeff Tinkere872ac42016-03-03 15:47:09 -08001331 if (patternObj == NULL) {
1332 pattern.mEncryptBlocks = 0;
1333 pattern.mSkipBlocks = 0;
1334 } else {
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001335 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1336 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1337 }
Andreas Huber91befdc2012-04-18 12:19:51 -07001338
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001339 status_t err = OK;
1340
1341 CryptoPlugin::SubSample *subSamples = NULL;
1342 jbyte *key = NULL;
1343 jbyte *iv = NULL;
1344
1345 if (numSubSamples <= 0) {
1346 err = -EINVAL;
1347 } else if (numBytesOfClearDataObj == NULL
1348 && numBytesOfEncryptedDataObj == NULL) {
1349 err = -EINVAL;
1350 } else if (numBytesOfEncryptedDataObj != NULL
1351 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1352 err = -ERANGE;
1353 } else if (numBytesOfClearDataObj != NULL
1354 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1355 err = -ERANGE;
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001356 // subSamples array may silently overflow if number of samples are too large. Use
1357 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001358 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001359 err = -EINVAL;
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001360 } else {
1361 jboolean isCopy;
1362
1363 jint *numBytesOfClearData =
1364 (numBytesOfClearDataObj == NULL)
1365 ? NULL
1366 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1367
1368 jint *numBytesOfEncryptedData =
1369 (numBytesOfEncryptedDataObj == NULL)
1370 ? NULL
1371 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1372
1373 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1374
1375 for (jint i = 0; i < numSubSamples; ++i) {
1376 subSamples[i].mNumBytesOfClearData =
1377 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1378
1379 subSamples[i].mNumBytesOfEncryptedData =
1380 (numBytesOfEncryptedData == NULL)
1381 ? 0 : numBytesOfEncryptedData[i];
1382 }
1383
1384 if (numBytesOfEncryptedData != NULL) {
1385 env->ReleaseIntArrayElements(
1386 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1387 numBytesOfEncryptedData = NULL;
1388 }
1389
1390 if (numBytesOfClearData != NULL) {
1391 env->ReleaseIntArrayElements(
1392 numBytesOfClearDataObj, numBytesOfClearData, 0);
1393 numBytesOfClearData = NULL;
1394 }
1395 }
1396
1397 if (err == OK && keyObj != NULL) {
1398 if (env->GetArrayLength(keyObj) != 16) {
1399 err = -EINVAL;
1400 } else {
1401 jboolean isCopy;
1402 key = env->GetByteArrayElements(keyObj, &isCopy);
1403 }
1404 }
1405
1406 if (err == OK && ivObj != NULL) {
1407 if (env->GetArrayLength(ivObj) != 16) {
1408 err = -EINVAL;
1409 } else {
1410 jboolean isCopy;
1411 iv = env->GetByteArrayElements(ivObj, &isCopy);
1412 }
1413 }
1414
Andreas Huberbfc56f42012-04-19 12:47:07 -07001415 AString errorDetailMsg;
1416
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001417 if (err == OK) {
1418 err = codec->queueSecureInputBuffer(
1419 index, offset,
1420 subSamples, numSubSamples,
1421 (const uint8_t *)key, (const uint8_t *)iv,
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001422 mode,
1423 pattern,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001424 timestampUs,
1425 flags,
1426 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001427 }
1428
1429 if (iv != NULL) {
1430 env->ReleaseByteArrayElements(ivObj, iv, 0);
1431 iv = NULL;
1432 }
1433
1434 if (key != NULL) {
1435 env->ReleaseByteArrayElements(keyObj, key, 0);
1436 key = NULL;
1437 }
1438
1439 delete[] subSamples;
1440 subSamples = NULL;
1441
Andreas Huberbfc56f42012-04-19 12:47:07 -07001442 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001443 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001444}
1445
Andreas Huber88572f72012-02-21 11:47:18 -08001446static jint android_media_MediaCodec_dequeueInputBuffer(
1447 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1448 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1449
1450 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1451
1452 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001453 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001454 return -1;
1455 }
1456
1457 size_t index;
1458 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1459
1460 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001461 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001462 }
1463
1464 return throwExceptionAsNecessary(env, err);
1465}
1466
1467static jint android_media_MediaCodec_dequeueOutputBuffer(
1468 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1469 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1470
1471 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1472
1473 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001474 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07001475 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001476 }
1477
1478 size_t index;
1479 status_t err = codec->dequeueOutputBuffer(
1480 env, bufferInfo, &index, timeoutUs);
1481
1482 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001483 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001484 }
1485
1486 return throwExceptionAsNecessary(env, err);
1487}
1488
1489static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001490 JNIEnv *env, jobject thiz,
1491 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08001492 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1493
1494 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1495
1496 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001497 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001498 return;
1499 }
1500
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001501 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08001502
1503 throwExceptionAsNecessary(env, err);
1504}
1505
Andy McFadden2621e402013-02-19 07:29:21 -08001506static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1507 jobject thiz) {
1508 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1509
1510 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1511 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001512 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001513 return;
1514 }
1515
1516 status_t err = codec->signalEndOfInputStream();
1517
1518 throwExceptionAsNecessary(env, err);
1519}
1520
Lajos Molnard4023112014-07-11 15:12:59 -07001521static jobject android_media_MediaCodec_getFormatNative(
1522 JNIEnv *env, jobject thiz, jboolean input) {
1523 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08001524
1525 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1526
1527 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001528 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001529 return NULL;
1530 }
1531
1532 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07001533 status_t err = codec->getFormat(env, input, &format);
1534
1535 if (err == OK) {
1536 return format;
1537 }
1538
1539 throwExceptionAsNecessary(env, err);
1540
1541 return NULL;
1542}
1543
1544static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1545 JNIEnv *env, jobject thiz, jint index) {
1546 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1547
1548 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1549
1550 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001551 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001552 return NULL;
1553 }
1554
1555 jobject format;
1556 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08001557
1558 if (err == OK) {
1559 return format;
1560 }
1561
1562 throwExceptionAsNecessary(env, err);
1563
1564 return NULL;
1565}
1566
1567static jobjectArray android_media_MediaCodec_getBuffers(
1568 JNIEnv *env, jobject thiz, jboolean input) {
1569 ALOGV("android_media_MediaCodec_getBuffers");
1570
1571 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1572
1573 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001574 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001575 return NULL;
1576 }
1577
1578 jobjectArray buffers;
1579 status_t err = codec->getBuffers(env, input, &buffers);
1580
1581 if (err == OK) {
1582 return buffers;
1583 }
1584
Marco Nelissencbbea8e2012-12-19 11:42:55 -08001585 // if we're out of memory, an exception was already thrown
1586 if (err != NO_MEMORY) {
1587 throwExceptionAsNecessary(env, err);
1588 }
Andreas Huber88572f72012-02-21 11:47:18 -08001589
1590 return NULL;
1591}
1592
Lajos Molnard4023112014-07-11 15:12:59 -07001593static jobject android_media_MediaCodec_getBuffer(
1594 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1595 ALOGV("android_media_MediaCodec_getBuffer");
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);
Lajos Molnard4023112014-07-11 15:12:59 -07001601 return NULL;
1602 }
1603
1604 jobject buffer;
1605 status_t err = codec->getBuffer(env, input, index, &buffer);
1606
1607 if (err == OK) {
1608 return buffer;
1609 }
1610
1611 // if we're out of memory, an exception was already thrown
1612 if (err != NO_MEMORY) {
1613 throwExceptionAsNecessary(env, err);
1614 }
1615
1616 return NULL;
1617}
1618
1619static jobject android_media_MediaCodec_getImage(
1620 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1621 ALOGV("android_media_MediaCodec_getImage");
1622
1623 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1624
1625 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001626 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001627 return NULL;
1628 }
1629
1630 jobject image;
1631 status_t err = codec->getImage(env, input, index, &image);
1632
1633 if (err == OK) {
1634 return image;
1635 }
1636
1637 // if we're out of memory, an exception was already thrown
1638 if (err != NO_MEMORY) {
1639 throwExceptionAsNecessary(env, err);
1640 }
1641
1642 return NULL;
1643}
1644
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001645static jobject android_media_MediaCodec_getName(
1646 JNIEnv *env, jobject thiz) {
1647 ALOGV("android_media_MediaCodec_getName");
1648
1649 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1650
1651 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001652 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001653 return NULL;
1654 }
1655
1656 jstring name;
1657 status_t err = codec->getName(env, &name);
1658
1659 if (err == OK) {
1660 return name;
1661 }
1662
1663 throwExceptionAsNecessary(env, err);
1664
1665 return NULL;
1666}
1667
Ray Essick0e0fee12017-01-25 18:01:56 -08001668static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -08001669android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -08001670{
Ray Essickf2d0e402017-03-09 10:17:51 -08001671 ALOGV("android_media_MediaCodec_native_getMetrics");
Ray Essick0e0fee12017-01-25 18:01:56 -08001672
1673 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1674 if (codec == NULL ) {
1675 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1676 return 0;
1677 }
1678
1679 // get what we have for the metrics from the codec
Ray Essickf2d0e402017-03-09 10:17:51 -08001680 MediaAnalyticsItem *item = NULL;
1681
1682 status_t err = codec->getMetrics(env, item);
Ray Essick0e0fee12017-01-25 18:01:56 -08001683 if (err != OK) {
1684 ALOGE("getMetrics failed");
1685 return (jobject) NULL;
1686 }
1687
Ray Essick0e0fee12017-01-25 18:01:56 -08001688 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
1689
1690 // housekeeping
1691 delete item;
1692 item = NULL;
1693
1694 return mybundle;
1695}
1696
Andreas Huber226065b2013-08-12 10:14:11 -07001697static void android_media_MediaCodec_setParameters(
1698 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1699 ALOGV("android_media_MediaCodec_setParameters");
1700
1701 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1702
1703 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001704 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07001705 return;
1706 }
1707
1708 sp<AMessage> params;
1709 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
1710
1711 if (err == OK) {
1712 err = codec->setParameters(params);
1713 }
1714
1715 throwExceptionAsNecessary(env, err);
1716}
1717
Andreas Huberb12a5392012-04-30 14:18:33 -07001718static void android_media_MediaCodec_setVideoScalingMode(
1719 JNIEnv *env, jobject thiz, jint mode) {
1720 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1721
1722 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001723 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07001724 return;
1725 }
1726
1727 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1728 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
Dongwon Kangbef01e42017-06-16 14:02:31 -07001729 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Andreas Huberb12a5392012-04-30 14:18:33 -07001730 return;
1731 }
1732
1733 codec->setVideoScalingMode(mode);
1734}
1735
Andreas Huber88572f72012-02-21 11:47:18 -08001736static void android_media_MediaCodec_native_init(JNIEnv *env) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001737 ScopedLocalRef<jclass> clazz(
1738 env, env->FindClass("android/media/MediaCodec"));
1739 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001740
Ashok Bhat075e9a12014-01-06 13:45:09 +00001741 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08001742 CHECK(gFields.context != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001743
Andreas Huberaba67132013-10-22 12:40:01 -07001744 gFields.postEventFromNativeID =
1745 env->GetMethodID(
1746 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1747
1748 CHECK(gFields.postEventFromNativeID != NULL);
1749
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001750 jfieldID field;
1751 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
1752 CHECK(field != NULL);
1753 gCryptoModes.Unencrypted =
1754 env->GetStaticIntField(clazz.get(), field);
1755
1756 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
1757 CHECK(field != NULL);
1758 gCryptoModes.AesCtr =
1759 env->GetStaticIntField(clazz.get(), field);
1760
1761 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
1762 CHECK(field != NULL);
1763 gCryptoModes.AesCbc =
1764 env->GetStaticIntField(clazz.get(), field);
1765
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001766 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1767 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001768
1769 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001770 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001771 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1772
1773 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001774 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001775 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1776
1777 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001778 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001779 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1780
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001781 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001782 CHECK(gFields.cryptoInfoKeyID != NULL);
1783
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001784 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001785 CHECK(gFields.cryptoInfoIVID != NULL);
1786
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001787 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001788 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001789
Jeff Tinkerd4ea5d32015-12-18 11:56:22 -08001790 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
1791 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
1792 CHECK(gFields.cryptoInfoPatternID != NULL);
1793
1794 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
1795 CHECK(clazz.get() != NULL);
1796
1797 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
1798 CHECK(gFields.patternEncryptBlocksID != NULL);
1799
1800 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
1801 CHECK(gFields.patternSkipBlocksID != NULL);
1802
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001803 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1804 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001805
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001806 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001807 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001808 gCryptoErrorCodes.cryptoErrorNoKey =
1809 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001810
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001811 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001812 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001813 gCryptoErrorCodes.cryptoErrorKeyExpired =
1814 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001815
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001816 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001817 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001818 gCryptoErrorCodes.cryptoErrorResourceBusy =
1819 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001820
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001821 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1822 CHECK(field != NULL);
1823 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1824 env->GetStaticIntField(clazz.get(), field);
1825
Jeff Tinker96a2a952015-07-01 17:35:18 -07001826 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1827 CHECK(field != NULL);
1828 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1829 env->GetStaticIntField(clazz.get(), field);
1830
Jeff Tinkerd3932162016-03-05 11:35:20 -08001831 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
1832 CHECK(field != NULL);
1833 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
1834 env->GetStaticIntField(clazz.get(), field);
1835
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001836 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
1837 CHECK(clazz.get() != NULL);
1838 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
1839 CHECK(field != NULL);
1840 gCodecActionCodes.codecActionTransient =
1841 env->GetStaticIntField(clazz.get(), field);
1842
1843 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
1844 CHECK(field != NULL);
1845 gCodecActionCodes.codecActionRecoverable =
1846 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001847
Ronghua Wuc53ad692015-05-08 14:40:49 -07001848 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001849 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001850 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001851 env->GetStaticIntField(clazz.get(), field);
1852
Ronghua Wuc53ad692015-05-08 14:40:49 -07001853 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001854 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001855 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001856 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07001857
1858 clazz.reset(env->FindClass("android/view/Surface"));
1859 CHECK(clazz.get() != NULL);
1860
1861 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
1862 CHECK(field != NULL);
1863 gPersistentSurfaceClassInfo.mLock = field;
1864
1865 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
1866 CHECK(method != NULL);
1867 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
1868
1869 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
1870 CHECK(clazz.get() != NULL);
1871 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
1872
1873 method = env->GetMethodID(clazz.get(), "<init>", "()V");
1874 CHECK(method != NULL);
1875 gPersistentSurfaceClassInfo.ctor = method;
1876
1877 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
1878 CHECK(field != NULL);
1879 gPersistentSurfaceClassInfo.mPersistentObject = field;
Andreas Huber88572f72012-02-21 11:47:18 -08001880}
1881
1882static void android_media_MediaCodec_native_setup(
1883 JNIEnv *env, jobject thiz,
1884 jstring name, jboolean nameIsType, jboolean encoder) {
1885 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001886 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001887 return;
1888 }
1889
1890 const char *tmp = env->GetStringUTFChars(name, NULL);
1891
1892 if (tmp == NULL) {
1893 return;
1894 }
1895
1896 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
1897
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001898 const status_t err = codec->initCheck();
1899 if (err == NAME_NOT_FOUND) {
1900 // fail and do not try again.
1901 jniThrowException(env, "java/lang/IllegalArgumentException",
1902 String8::format("Failed to initialize %s, error %#x", tmp, err));
1903 env->ReleaseStringUTFChars(name, tmp);
1904 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07001905 } if (err == NO_MEMORY) {
1906 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
1907 String8::format("Failed to initialize %s, error %#x", tmp, err));
1908 env->ReleaseStringUTFChars(name, tmp);
1909 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001910 } else if (err != OK) {
1911 // believed possible to try again
1912 jniThrowException(env, "java/io/IOException",
1913 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
1914 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08001915 return;
1916 }
1917
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001918 env->ReleaseStringUTFChars(name, tmp);
1919
Andreas Huberaba67132013-10-22 12:40:01 -07001920 codec->registerSelf();
1921
Andreas Huber88572f72012-02-21 11:47:18 -08001922 setMediaCodec(env,thiz, codec);
1923}
1924
1925static void android_media_MediaCodec_native_finalize(
1926 JNIEnv *env, jobject thiz) {
1927 android_media_MediaCodec_release(env, thiz);
1928}
1929
Daniel Micay76f6a862015-09-19 17:31:01 -04001930static const JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07001931 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08001932
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001933 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1934
Chong Zhang8034d602015-04-28 13:38:48 -07001935 { "native_releasePersistentInputSurface",
1936 "(Landroid/view/Surface;)V",
1937 (void *)android_media_MediaCodec_releasePersistentInputSurface},
1938
1939 { "native_createPersistentInputSurface",
1940 "()Landroid/media/MediaCodec$PersistentSurface;",
1941 (void *)android_media_MediaCodec_createPersistentInputSurface },
1942
Chong Zhang9560ddb2015-05-13 10:25:29 -07001943 { "native_setInputSurface", "(Landroid/view/Surface;)V",
1944 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07001945
Lajos Molnard8578572015-06-05 20:17:33 -07001946 { "native_enableOnFrameRenderedListener", "(Z)V",
1947 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
1948
Chong Zhang8d5e5562014-07-08 18:49:21 -07001949 { "native_setCallback",
1950 "(Landroid/media/MediaCodec$Callback;)V",
1951 (void *)android_media_MediaCodec_native_setCallback },
1952
Andreas Huber88572f72012-02-21 11:47:18 -08001953 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07001954 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Chong Zhang2659c2f2017-04-27 13:18:20 -07001955 "Landroid/media/MediaCrypto;Landroid/os/IHwBinder;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001956 (void *)android_media_MediaCodec_native_configure },
1957
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001958 { "native_setSurface",
1959 "(Landroid/view/Surface;)V",
1960 (void *)android_media_MediaCodec_native_setSurface },
1961
Andy McFadden2621e402013-02-19 07:29:21 -08001962 { "createInputSurface", "()Landroid/view/Surface;",
1963 (void *)android_media_MediaCodec_createInputSurface },
1964
Lajos Molnard4023112014-07-11 15:12:59 -07001965 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07001966 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07001967 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08001968
Lajos Molnard4023112014-07-11 15:12:59 -07001969 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001970 (void *)android_media_MediaCodec_queueInputBuffer },
1971
Lajos Molnard4023112014-07-11 15:12:59 -07001972 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001973 (void *)android_media_MediaCodec_queueSecureInputBuffer },
1974
Lajos Molnard4023112014-07-11 15:12:59 -07001975 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08001976 (void *)android_media_MediaCodec_dequeueInputBuffer },
1977
Lajos Molnard4023112014-07-11 15:12:59 -07001978 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08001979 (void *)android_media_MediaCodec_dequeueOutputBuffer },
1980
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001981 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001982 (void *)android_media_MediaCodec_releaseOutputBuffer },
1983
Andy McFadden2621e402013-02-19 07:29:21 -08001984 { "signalEndOfInputStream", "()V",
1985 (void *)android_media_MediaCodec_signalEndOfInputStream },
1986
Lajos Molnard4023112014-07-11 15:12:59 -07001987 { "getFormatNative", "(Z)Ljava/util/Map;",
1988 (void *)android_media_MediaCodec_getFormatNative },
1989
1990 { "getOutputFormatNative", "(I)Ljava/util/Map;",
1991 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08001992
1993 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1994 (void *)android_media_MediaCodec_getBuffers },
1995
Lajos Molnard4023112014-07-11 15:12:59 -07001996 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
1997 (void *)android_media_MediaCodec_getBuffer },
1998
1999 { "getImage", "(ZI)Landroid/media/Image;",
2000 (void *)android_media_MediaCodec_getImage },
2001
Martin Storsjo056ef2e2012-09-25 11:53:04 +03002002 { "getName", "()Ljava/lang/String;",
2003 (void *)android_media_MediaCodec_getName },
2004
Ray Essick10353e32017-04-14 10:22:55 -07002005 { "native_getMetrics", "()Landroid/os/PersistableBundle;",
Ray Essickf2d0e402017-03-09 10:17:51 -08002006 (void *)android_media_MediaCodec_native_getMetrics},
Ray Essick0e0fee12017-01-25 18:01:56 -08002007
Andreas Huber226065b2013-08-12 10:14:11 -07002008 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
2009 (void *)android_media_MediaCodec_setParameters },
2010
Andreas Huberb12a5392012-04-30 14:18:33 -07002011 { "setVideoScalingMode", "(I)V",
2012 (void *)android_media_MediaCodec_setVideoScalingMode },
2013
Andreas Huber88572f72012-02-21 11:47:18 -08002014 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
2015
2016 { "native_setup", "(Ljava/lang/String;ZZ)V",
2017 (void *)android_media_MediaCodec_native_setup },
2018
2019 { "native_finalize", "()V",
2020 (void *)android_media_MediaCodec_native_finalize },
2021};
2022
2023int register_android_media_MediaCodec(JNIEnv *env) {
2024 return AndroidRuntime::registerNativeMethods(env,
2025 "android/media/MediaCodec", gMethods, NELEM(gMethods));
2026}