blob: 218a11761b5a9666b12727970b7ef3a9e7aa92a2 [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"
Andreas Huber88572f72012-02-21 11:47:18 -080024#include "android_media_Utils.h"
25#include "android_runtime/AndroidRuntime.h"
26#include "android_runtime/android_view_Surface.h"
27#include "jni.h"
28#include "JNIHelp.h"
29
Lajos Molnar7ac4f562014-03-24 15:57:51 -070030#include <cutils/compiler.h>
31
Mathias Agopian8335f1c2012-02-25 18:48:35 -080032#include <gui/Surface.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080033
Andreas Huber0e97fc22012-04-03 13:32:16 -070034#include <media/ICrypto.h>
Andreas Huber88572f72012-02-21 11:47:18 -080035#include <media/stagefright/MediaCodec.h>
36#include <media/stagefright/foundation/ABuffer.h>
37#include <media/stagefright/foundation/ADebug.h>
38#include <media/stagefright/foundation/ALooper.h>
39#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070040#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080041#include <media/stagefright/MediaErrors.h>
Chong Zhang8034d602015-04-28 13:38:48 -070042#include <media/stagefright/PersistentSurface.h>
Andreas Huber8d5f3e32013-08-12 09:19:45 -070043#include <nativehelper/ScopedLocalRef.h>
44
Andreas Huberb12a5392012-04-30 14:18:33 -070045#include <system/window.h>
46
Andreas Huber88572f72012-02-21 11:47:18 -080047namespace android {
48
49// Keep these in sync with their equivalents in MediaCodec.java !!!
50enum {
51 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
52 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
53 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
54};
55
Andreas Huberaba67132013-10-22 12:40:01 -070056enum {
Chong Zhang8d5e5562014-07-08 18:49:21 -070057 EVENT_CALLBACK = 1,
58 EVENT_SET_CALLBACK = 2,
Lajos Molnard8578572015-06-05 20:17:33 -070059 EVENT_FRAME_RENDERED = 3,
Andreas Huberaba67132013-10-22 12:40:01 -070060};
61
Andy Hung5f9aa0b2014-07-30 15:48:21 -070062static struct CryptoErrorCodes {
Jeff Tinker3ed38262013-08-02 23:24:51 -070063 jint cryptoErrorNoKey;
64 jint cryptoErrorKeyExpired;
65 jint cryptoErrorResourceBusy;
Jeff Tinker336d3ea2014-08-28 17:57:36 -070066 jint cryptoErrorInsufficientOutputProtection;
Jeff Tinker96a2a952015-07-01 17:35:18 -070067 jint cryptoErrorSessionNotOpened;
Jeff Tinker3ed38262013-08-02 23:24:51 -070068} gCryptoErrorCodes;
69
Andy Hung5f9aa0b2014-07-30 15:48:21 -070070static struct CodecActionCodes {
71 jint codecActionTransient;
72 jint codecActionRecoverable;
73} gCodecActionCodes;
74
Ronghua Wuc53ad692015-05-08 14:40:49 -070075static struct CodecErrorCodes {
76 jint errorInsufficientResource;
77 jint errorReclaimed;
78} gCodecErrorCodes;
Ronghua Wu9e9ec942015-04-15 17:10:31 -070079
Chong Zhang8034d602015-04-28 13:38:48 -070080static struct {
81 jclass clazz;
82 jfieldID mLock;
83 jfieldID mPersistentObject;
84 jmethodID ctor;
85 jmethodID setNativeObjectLocked;
86} gPersistentSurfaceClassInfo;
87
Andreas Huber88572f72012-02-21 11:47:18 -080088struct fields_t {
89 jfieldID context;
Andreas Huberaba67132013-10-22 12:40:01 -070090 jmethodID postEventFromNativeID;
Andreas Huber91befdc2012-04-18 12:19:51 -070091 jfieldID cryptoInfoNumSubSamplesID;
92 jfieldID cryptoInfoNumBytesOfClearDataID;
93 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
94 jfieldID cryptoInfoKeyID;
95 jfieldID cryptoInfoIVID;
96 jfieldID cryptoInfoModeID;
Andreas Huber88572f72012-02-21 11:47:18 -080097};
98
99static fields_t gFields;
Chong Zhang8034d602015-04-28 13:38:48 -0700100static const void *sRefBaseOwner;
Andreas Huber88572f72012-02-21 11:47:18 -0800101
102////////////////////////////////////////////////////////////////////////////////
103
104JMediaCodec::JMediaCodec(
105 JNIEnv *env, jobject thiz,
106 const char *name, bool nameIsType, bool encoder)
107 : mClass(NULL),
Chong Zhang8d5e5562014-07-08 18:49:21 -0700108 mObject(NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800109 jclass clazz = env->GetObjectClass(thiz);
110 CHECK(clazz != NULL);
111
112 mClass = (jclass)env->NewGlobalRef(clazz);
113 mObject = env->NewWeakGlobalRef(thiz);
114
Lajos Molnar7de28d32014-07-25 07:51:02 -0700115 cacheJavaObjects(env);
116
Andreas Huber88572f72012-02-21 11:47:18 -0800117 mLooper = new ALooper;
118 mLooper->setName("MediaCodec_looper");
119
120 mLooper->start(
121 false, // runOnCallingThread
Andreas Huberaba67132013-10-22 12:40:01 -0700122 true, // canCallJava
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700123 PRIORITY_FOREGROUND);
Andreas Huber88572f72012-02-21 11:47:18 -0800124
125 if (nameIsType) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700126 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800127 } else {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700128 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
Andreas Huber88572f72012-02-21 11:47:18 -0800129 }
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700130 CHECK((mCodec != NULL) != (mInitStatus != OK));
Andreas Huber88572f72012-02-21 11:47:18 -0800131}
132
Lajos Molnar7de28d32014-07-25 07:51:02 -0700133void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
134 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
135 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
136 CHECK(mByteBufferClass != NULL);
137
138 ScopedLocalRef<jclass> byteOrderClass(
139 env, env->FindClass("java/nio/ByteOrder"));
140 CHECK(byteOrderClass.get() != NULL);
141
142 jmethodID nativeOrderID = env->GetStaticMethodID(
143 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
144 CHECK(nativeOrderID != NULL);
145
146 jobject nativeByteOrderObj =
147 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
148 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
149 CHECK(mNativeByteOrderObj != NULL);
150 env->DeleteLocalRef(nativeByteOrderObj);
151 nativeByteOrderObj = NULL;
152
153 mByteBufferOrderMethodID = env->GetMethodID(
154 mByteBufferClass,
155 "order",
156 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
157 CHECK(mByteBufferOrderMethodID != NULL);
158
159 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
160 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
161 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
162
163 mByteBufferPositionMethodID = env->GetMethodID(
164 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
165 CHECK(mByteBufferPositionMethodID != NULL);
166
167 mByteBufferLimitMethodID = env->GetMethodID(
168 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
169 CHECK(mByteBufferLimitMethodID != NULL);
170}
171
Andreas Huber88572f72012-02-21 11:47:18 -0800172status_t JMediaCodec::initCheck() const {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700173 return mInitStatus;
Andreas Huber88572f72012-02-21 11:47:18 -0800174}
175
Andreas Huberaba67132013-10-22 12:40:01 -0700176void JMediaCodec::registerSelf() {
177 mLooper->registerHandler(this);
178}
179
Chong Zhang128b0122014-03-01 18:04:13 -0800180void JMediaCodec::release() {
Martin Storsjod932de92012-07-13 13:01:06 +0300181 if (mCodec != NULL) {
182 mCodec->release();
183 mCodec.clear();
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700184 mInitStatus = NO_INIT;
Martin Storsjod932de92012-07-13 13:01:06 +0300185 }
Andreas Huber88572f72012-02-21 11:47:18 -0800186
Chong Zhang128b0122014-03-01 18:04:13 -0800187 if (mLooper != NULL) {
188 mLooper->unregisterHandler(id());
189 mLooper->stop();
190 mLooper.clear();
191 }
192}
193
194JMediaCodec::~JMediaCodec() {
195 if (mCodec != NULL || mLooper != NULL) {
196 /* MediaCodec and looper should have been released explicitly already
197 * in setMediaCodec() (see comments in setMediaCodec()).
198 *
199 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
200 * message handler, doing release() there risks deadlock as MediaCodec::
201 * release() post synchronous message to the same looper.
202 *
203 * Print a warning and try to proceed with releasing.
204 */
205 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
206 release();
207 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
208 }
209
Andreas Huber88572f72012-02-21 11:47:18 -0800210 JNIEnv *env = AndroidRuntime::getJNIEnv();
211
212 env->DeleteWeakGlobalRef(mObject);
213 mObject = NULL;
214 env->DeleteGlobalRef(mClass);
215 mClass = NULL;
Lajos Molnar7de28d32014-07-25 07:51:02 -0700216 deleteJavaObjects(env);
217}
218
219void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
220 env->DeleteGlobalRef(mByteBufferClass);
221 mByteBufferClass = NULL;
222 env->DeleteGlobalRef(mNativeByteOrderObj);
223 mNativeByteOrderObj = NULL;
224
225 mByteBufferOrderMethodID = NULL;
226 mByteBufferAsReadOnlyBufferMethodID = NULL;
227 mByteBufferPositionMethodID = NULL;
228 mByteBufferLimitMethodID = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800229}
230
Lajos Molnard8578572015-06-05 20:17:33 -0700231status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
232 if (enable) {
233 if (mOnFrameRenderedNotification == NULL) {
234 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
235 }
236 } else {
237 mOnFrameRenderedNotification.clear();
238 }
239
240 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
241}
242
Chong Zhang8d5e5562014-07-08 18:49:21 -0700243status_t JMediaCodec::setCallback(jobject cb) {
244 if (cb != NULL) {
245 if (mCallbackNotification == NULL) {
Lajos Molnar63834f42015-03-04 14:39:08 -0800246 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700247 }
248 } else {
249 mCallbackNotification.clear();
250 }
251
252 return mCodec->setCallback(mCallbackNotification);
253}
254
Andreas Huber88572f72012-02-21 11:47:18 -0800255status_t JMediaCodec::configure(
256 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800257 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700258 const sp<ICrypto> &crypto,
Andreas Huber88572f72012-02-21 11:47:18 -0800259 int flags) {
Mathias Agopian52800612013-02-14 17:11:20 -0800260 sp<Surface> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800261 if (bufferProducer != NULL) {
Andreas Huberaba67132013-10-22 12:40:01 -0700262 mSurfaceTextureClient =
263 new Surface(bufferProducer, true /* controlledByApp */);
Andreas Huberb12a5392012-04-30 14:18:33 -0700264 } else {
265 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800266 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700267
268 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800269}
270
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700271status_t JMediaCodec::setSurface(
272 const sp<IGraphicBufferProducer> &bufferProducer) {
273 sp<Surface> client;
274 if (bufferProducer != NULL) {
275 client = new Surface(bufferProducer, true /* controlledByApp */);
276 }
277 status_t err = mCodec->setSurface(client);
278 if (err == OK) {
279 mSurfaceTextureClient = client;
280 }
281 return err;
282}
283
Andy McFadden2621e402013-02-19 07:29:21 -0800284status_t JMediaCodec::createInputSurface(
285 sp<IGraphicBufferProducer>* bufferProducer) {
286 return mCodec->createInputSurface(bufferProducer);
287}
288
Chong Zhang9560ddb2015-05-13 10:25:29 -0700289status_t JMediaCodec::setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -0700290 const sp<PersistentSurface> &surface) {
Chong Zhang9560ddb2015-05-13 10:25:29 -0700291 return mCodec->setInputSurface(surface);
Chong Zhang8034d602015-04-28 13:38:48 -0700292}
293
Andreas Huber88572f72012-02-21 11:47:18 -0800294status_t JMediaCodec::start() {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700295 return mCodec->start();
Andreas Huber88572f72012-02-21 11:47:18 -0800296}
297
298status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700299 mSurfaceTextureClient.clear();
300
Chong Zhang8d5e5562014-07-08 18:49:21 -0700301 return mCodec->stop();
Andreas Huber88572f72012-02-21 11:47:18 -0800302}
303
304status_t JMediaCodec::flush() {
305 return mCodec->flush();
306}
307
Lajos Molnar1e6e8012014-07-15 16:07:13 -0700308status_t JMediaCodec::reset() {
309 return mCodec->reset();
310}
311
Andreas Huber88572f72012-02-21 11:47:18 -0800312status_t JMediaCodec::queueInputBuffer(
313 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700314 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
315 AString *errorDetailMsg) {
316 return mCodec->queueInputBuffer(
317 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800318}
319
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700320status_t JMediaCodec::queueSecureInputBuffer(
321 size_t index,
322 size_t offset,
323 const CryptoPlugin::SubSample *subSamples,
324 size_t numSubSamples,
325 const uint8_t key[16],
326 const uint8_t iv[16],
327 CryptoPlugin::Mode mode,
328 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700329 uint32_t flags,
330 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700331 return mCodec->queueSecureInputBuffer(
332 index, offset, subSamples, numSubSamples, key, iv, mode,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700333 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700334}
335
Andreas Huber88572f72012-02-21 11:47:18 -0800336status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700337 return mCodec->dequeueInputBuffer(index, timeoutUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800338}
339
340status_t JMediaCodec::dequeueOutputBuffer(
341 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
342 size_t size, offset;
343 int64_t timeUs;
344 uint32_t flags;
Andreas Huberaba67132013-10-22 12:40:01 -0700345 status_t err = mCodec->dequeueOutputBuffer(
346 index, &offset, &size, &timeUs, &flags, timeoutUs);
347
Andreas Huberaba67132013-10-22 12:40:01 -0700348 if (err != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800349 return err;
350 }
351
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700352 ScopedLocalRef<jclass> clazz(
353 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
Andreas Huber88572f72012-02-21 11:47:18 -0800354
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700355 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
Ashok Bhatfef85ef2014-03-05 15:06:05 +0000356 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800357
358 return OK;
359}
360
Lajos Molnar7c513b6b2014-05-08 17:16:45 -0700361status_t JMediaCodec::releaseOutputBuffer(
362 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
363 if (updatePTS) {
364 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
365 }
Andreas Huber88572f72012-02-21 11:47:18 -0800366 return render
367 ? mCodec->renderOutputBufferAndRelease(index)
368 : mCodec->releaseOutputBuffer(index);
369}
370
Andy McFadden2621e402013-02-19 07:29:21 -0800371status_t JMediaCodec::signalEndOfInputStream() {
372 return mCodec->signalEndOfInputStream();
373}
374
Lajos Molnard4023112014-07-11 15:12:59 -0700375status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
Andreas Huber88572f72012-02-21 11:47:18 -0800376 sp<AMessage> msg;
377 status_t err;
Lajos Molnard4023112014-07-11 15:12:59 -0700378 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
379 if (err != OK) {
380 return err;
381 }
382
383 return ConvertMessageToMap(env, msg, format);
384}
385
386status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
387 sp<AMessage> msg;
388 status_t err;
389 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800390 return err;
391 }
392
393 return ConvertMessageToMap(env, msg, format);
394}
395
396status_t JMediaCodec::getBuffers(
397 JNIEnv *env, bool input, jobjectArray *bufArray) const {
398 Vector<sp<ABuffer> > buffers;
399
400 status_t err =
401 input
402 ? mCodec->getInputBuffers(&buffers)
403 : mCodec->getOutputBuffers(&buffers);
404
405 if (err != OK) {
406 return err;
407 }
408
Andreas Huber88572f72012-02-21 11:47:18 -0800409 *bufArray = (jobjectArray)env->NewObjectArray(
Lajos Molnar7de28d32014-07-25 07:51:02 -0700410 buffers.size(), mByteBufferClass, NULL);
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800411 if (*bufArray == NULL) {
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800412 return NO_MEMORY;
413 }
Andreas Huber88572f72012-02-21 11:47:18 -0800414
415 for (size_t i = 0; i < buffers.size(); ++i) {
416 const sp<ABuffer> &buffer = buffers.itemAt(i);
417
Lajos Molnar7de28d32014-07-25 07:51:02 -0700418 jobject byteBuffer = NULL;
419 err = createByteBufferFromABuffer(
420 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
421 if (err != OK) {
422 return err;
Marco Nelissencbbea8e2012-12-19 11:42:55 -0800423 }
Lajos Molnar7de28d32014-07-25 07:51:02 -0700424 if (byteBuffer != NULL) {
425 env->SetObjectArrayElement(
426 *bufArray, i, byteBuffer);
427
Lajos Molnard4023112014-07-11 15:12:59 -0700428 env->DeleteLocalRef(byteBuffer);
Lajos Molnar7de28d32014-07-25 07:51:02 -0700429 byteBuffer = NULL;
Lajos Molnard4023112014-07-11 15:12:59 -0700430 }
Andreas Huber88572f72012-02-21 11:47:18 -0800431 }
432
Lajos Molnar7de28d32014-07-25 07:51:02 -0700433 return OK;
434}
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700435
Lajos Molnar7de28d32014-07-25 07:51:02 -0700436// static
437status_t JMediaCodec::createByteBufferFromABuffer(
438 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
439 jobject *buf) const {
440 // if this is an ABuffer that doesn't actually hold any accessible memory,
441 // use a null ByteBuffer
442 *buf = NULL;
443 if (buffer->base() == NULL) {
444 return OK;
445 }
446
447 jobject byteBuffer =
448 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
449 if (readOnly && byteBuffer != NULL) {
450 jobject readOnlyBuffer = env->CallObjectMethod(
451 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
452 env->DeleteLocalRef(byteBuffer);
453 byteBuffer = readOnlyBuffer;
454 }
455 if (byteBuffer == NULL) {
456 return NO_MEMORY;
457 }
458 jobject me = env->CallObjectMethod(
459 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
460 env->DeleteLocalRef(me);
461 me = env->CallObjectMethod(
462 byteBuffer, mByteBufferLimitMethodID,
463 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
464 env->DeleteLocalRef(me);
465 me = env->CallObjectMethod(
466 byteBuffer, mByteBufferPositionMethodID,
467 clearBuffer ? 0 : buffer->offset());
468 env->DeleteLocalRef(me);
469 me = NULL;
470
471 *buf = byteBuffer;
Andreas Huber88572f72012-02-21 11:47:18 -0800472 return OK;
473}
474
Lajos Molnard4023112014-07-11 15:12:59 -0700475status_t JMediaCodec::getBuffer(
476 JNIEnv *env, bool input, size_t index, jobject *buf) const {
477 sp<ABuffer> buffer;
478
479 status_t err =
480 input
481 ? mCodec->getInputBuffer(index, &buffer)
482 : mCodec->getOutputBuffer(index, &buffer);
483
484 if (err != OK) {
485 return err;
486 }
487
Lajos Molnar7de28d32014-07-25 07:51:02 -0700488 return createByteBufferFromABuffer(
489 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
Lajos Molnard4023112014-07-11 15:12:59 -0700490}
491
492status_t JMediaCodec::getImage(
493 JNIEnv *env, bool input, size_t index, jobject *buf) const {
494 sp<ABuffer> buffer;
495
496 status_t err =
497 input
498 ? mCodec->getInputBuffer(index, &buffer)
499 : mCodec->getOutputBuffer(index, &buffer);
500
501 if (err != OK) {
502 return err;
503 }
504
505 // if this is an ABuffer that doesn't actually hold any accessible memory,
506 // use a null ByteBuffer
507 *buf = NULL;
508 if (buffer->base() == NULL) {
509 return OK;
510 }
511
512 // check if buffer is an image
Lajos Molnar7de28d32014-07-25 07:51:02 -0700513 sp<ABuffer> imageData;
514 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
Lajos Molnard4023112014-07-11 15:12:59 -0700515 return OK;
516 }
517
Lajos Molnar7de28d32014-07-25 07:51:02 -0700518 int64_t timestamp = 0;
519 if (!input && buffer->meta()->findInt64("timeUs", &timestamp)) {
520 timestamp *= 1000; // adjust to ns
521 }
522
523 jobject byteBuffer = NULL;
524 err = createByteBufferFromABuffer(
525 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
526 if (err != OK) {
527 return OK;
528 }
529
530 jobject infoBuffer = NULL;
531 err = createByteBufferFromABuffer(
532 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
533 if (err != OK) {
534 env->DeleteLocalRef(byteBuffer);
535 byteBuffer = NULL;
536 return OK;
537 }
538
539 jobject cropRect = NULL;
540 int32_t left, top, right, bottom;
541 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
542 ScopedLocalRef<jclass> rectClazz(
543 env, env->FindClass("android/graphics/Rect"));
544 CHECK(rectClazz.get() != NULL);
545
546 jmethodID rectConstructID = env->GetMethodID(
547 rectClazz.get(), "<init>", "(IIII)V");
548
549 cropRect = env->NewObject(
550 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
551 }
552
553 ScopedLocalRef<jclass> imageClazz(
554 env, env->FindClass("android/media/MediaCodec$MediaImage"));
555 CHECK(imageClazz.get() != NULL);
556
557 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
558 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
559
560 *buf = env->NewObject(imageClazz.get(), imageConstructID,
561 byteBuffer, infoBuffer,
562 (jboolean)!input /* readOnly */,
563 (jlong)timestamp,
564 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
565
566 // if MediaImage creation fails, return null
567 if (env->ExceptionCheck()) {
568 env->ExceptionDescribe();
569 env->ExceptionClear();
570 *buf = NULL;
571 }
572
573 if (cropRect != NULL) {
574 env->DeleteLocalRef(cropRect);
575 cropRect = NULL;
576 }
577
578 env->DeleteLocalRef(byteBuffer);
579 byteBuffer = NULL;
580
581 env->DeleteLocalRef(infoBuffer);
582 infoBuffer = NULL;
583
Lajos Molnard4023112014-07-11 15:12:59 -0700584 return OK;
585}
586
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300587status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
588 AString name;
589
590 status_t err = mCodec->getName(&name);
591
592 if (err != OK) {
593 return err;
594 }
595
596 *nameStr = env->NewStringUTF(name.c_str());
597
598 return OK;
599}
600
Andreas Huber226065b2013-08-12 10:14:11 -0700601status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
602 return mCodec->setParameters(msg);
603}
604
Andreas Huberb12a5392012-04-30 14:18:33 -0700605void JMediaCodec::setVideoScalingMode(int mode) {
606 if (mSurfaceTextureClient != NULL) {
607 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
608 }
609}
610
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700611static jthrowable createCodecException(
612 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
613 ScopedLocalRef<jclass> clazz(
614 env, env->FindClass("android/media/MediaCodec$CodecException"));
615 CHECK(clazz.get() != NULL);
616
Ronghua Wuc53ad692015-05-08 14:40:49 -0700617 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700618 CHECK(ctor != NULL);
619
620 ScopedLocalRef<jstring> msgObj(
621 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
622
623 // translate action code to Java equivalent
624 switch (actionCode) {
625 case ACTION_CODE_TRANSIENT:
626 actionCode = gCodecActionCodes.codecActionTransient;
627 break;
628 case ACTION_CODE_RECOVERABLE:
629 actionCode = gCodecActionCodes.codecActionRecoverable;
630 break;
631 default:
632 actionCode = 0; // everything else is fatal
633 break;
634 }
635
Ronghua Wuc53ad692015-05-08 14:40:49 -0700636 /* translate OS errors to Java API CodecException errorCodes */
637 switch (err) {
638 case NO_MEMORY:
639 err = gCodecErrorCodes.errorInsufficientResource;
640 break;
641 case DEAD_OBJECT:
642 err = gCodecErrorCodes.errorReclaimed;
643 break;
644 default: /* Other error codes go out as is. */
645 break;
646 }
647
648 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700649}
650
Chong Zhang8d5e5562014-07-08 18:49:21 -0700651void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
652 int32_t arg1, arg2 = 0;
653 jobject obj = NULL;
654 CHECK(msg->findInt32("callbackID", &arg1));
655 JNIEnv *env = AndroidRuntime::getJNIEnv();
Andreas Huberaba67132013-10-22 12:40:01 -0700656
Chong Zhang8d5e5562014-07-08 18:49:21 -0700657 switch (arg1) {
658 case MediaCodec::CB_INPUT_AVAILABLE:
659 {
660 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700661 break;
662 }
663
Chong Zhang8d5e5562014-07-08 18:49:21 -0700664 case MediaCodec::CB_OUTPUT_AVAILABLE:
Andreas Huberaba67132013-10-22 12:40:01 -0700665 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700666 CHECK(msg->findInt32("index", &arg2));
Andreas Huberaba67132013-10-22 12:40:01 -0700667
Chong Zhang8d5e5562014-07-08 18:49:21 -0700668 size_t size, offset;
669 int64_t timeUs;
670 uint32_t flags;
671 CHECK(msg->findSize("size", &size));
672 CHECK(msg->findSize("offset", &offset));
673 CHECK(msg->findInt64("timeUs", &timeUs));
674 CHECK(msg->findInt32("flags", (int32_t *)&flags));
675
676 ScopedLocalRef<jclass> clazz(
677 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
678 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
679 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
680
681 obj = env->NewObject(clazz.get(), ctor);
682
683 if (obj == NULL) {
684 if (env->ExceptionCheck()) {
685 ALOGE("Could not create MediaCodec.BufferInfo.");
686 env->ExceptionClear();
Andreas Huberaba67132013-10-22 12:40:01 -0700687 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700688 jniThrowException(env, "java/lang/IllegalStateException", NULL);
689 return;
Andreas Huberaba67132013-10-22 12:40:01 -0700690 }
691
Chong Zhang8d5e5562014-07-08 18:49:21 -0700692 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
693 break;
694 }
695
696 case MediaCodec::CB_ERROR:
697 {
Chong Zhang94686d12014-07-11 15:53:58 -0700698 int32_t err, actionCode;
699 CHECK(msg->findInt32("err", &err));
Chong Zhang8d5e5562014-07-08 18:49:21 -0700700 CHECK(msg->findInt32("actionCode", &actionCode));
701
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700702 // note that DRM errors could conceivably alias into a CodecException
703 obj = (jobject)createCodecException(env, err, actionCode);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700704
705 if (obj == NULL) {
706 if (env->ExceptionCheck()) {
Chong Zhang94686d12014-07-11 15:53:58 -0700707 ALOGE("Could not create CodecException object.");
Chong Zhang8d5e5562014-07-08 18:49:21 -0700708 env->ExceptionClear();
709 }
710 jniThrowException(env, "java/lang/IllegalStateException", NULL);
711 return;
712 }
Andreas Huberaba67132013-10-22 12:40:01 -0700713
714 break;
715 }
716
Chong Zhang8d5e5562014-07-08 18:49:21 -0700717 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
Andreas Huberaba67132013-10-22 12:40:01 -0700718 {
Chong Zhang8d5e5562014-07-08 18:49:21 -0700719 sp<AMessage> format;
720 CHECK(msg->findMessage("format", &format));
Andreas Huberaba67132013-10-22 12:40:01 -0700721
Chong Zhang8d5e5562014-07-08 18:49:21 -0700722 if (OK != ConvertMessageToMap(env, format, &obj)) {
723 jniThrowException(env, "java/lang/IllegalStateException", NULL);
724 return;
725 }
Andreas Huberaba67132013-10-22 12:40:01 -0700726
Andreas Huberaba67132013-10-22 12:40:01 -0700727 break;
728 }
729
730 default:
731 TRESPASS();
732 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700733
734 env->CallVoidMethod(
735 mObject,
736 gFields.postEventFromNativeID,
737 EVENT_CALLBACK,
738 arg1,
739 arg2,
740 obj);
741
742 env->DeleteLocalRef(obj);
Andreas Huberaba67132013-10-22 12:40:01 -0700743}
744
Lajos Molnard8578572015-06-05 20:17:33 -0700745void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
746 int32_t arg1 = 0, arg2 = 0;
747 jobject obj = NULL;
748 JNIEnv *env = AndroidRuntime::getJNIEnv();
749
750 sp<AMessage> data;
751 CHECK(msg->findMessage("data", &data));
752
753 status_t err = ConvertMessageToMap(env, data, &obj);
754 if (err != OK) {
755 jniThrowException(env, "java/lang/IllegalStateException", NULL);
756 return;
757 }
758
759 env->CallVoidMethod(
760 mObject, gFields.postEventFromNativeID,
761 EVENT_FRAME_RENDERED, arg1, arg2, obj);
762
763 env->DeleteLocalRef(obj);
764}
765
Chong Zhang8d5e5562014-07-08 18:49:21 -0700766void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
767 switch (msg->what()) {
768 case kWhatCallbackNotify:
769 {
770 handleCallback(msg);
771 break;
772 }
Lajos Molnard8578572015-06-05 20:17:33 -0700773 case kWhatFrameRendered:
774 {
775 handleFrameRenderedNotification(msg);
776 break;
777 }
Chong Zhang8d5e5562014-07-08 18:49:21 -0700778 default:
779 TRESPASS();
780 }
Andreas Huberaba67132013-10-22 12:40:01 -0700781}
782
Andreas Huber88572f72012-02-21 11:47:18 -0800783} // namespace android
784
785////////////////////////////////////////////////////////////////////////////////
786
787using namespace android;
788
789static sp<JMediaCodec> setMediaCodec(
790 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000791 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800792 if (codec != NULL) {
793 codec->incStrong(thiz);
794 }
795 if (old != NULL) {
Chong Zhang128b0122014-03-01 18:04:13 -0800796 /* release MediaCodec and stop the looper now before decStrong.
797 * otherwise JMediaCodec::~JMediaCodec() could be called from within
798 * its message handler, doing release() from there will deadlock
799 * (as MediaCodec::release() post synchronous message to the same looper)
800 */
801 old->release();
Andreas Huber88572f72012-02-21 11:47:18 -0800802 old->decStrong(thiz);
803 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000804 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
Andreas Huber88572f72012-02-21 11:47:18 -0800805
806 return old;
807}
808
809static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000810 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800811}
812
813static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
814 setMediaCodec(env, thiz, NULL);
815}
816
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700817static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
818 jthrowable exception = createCodecException(env, err, actionCode, msg);
819 env->Throw(exception);
820}
821
Andreas Huberbfc56f42012-04-19 12:47:07 -0700822static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700823 ScopedLocalRef<jclass> clazz(
824 env, env->FindClass("android/media/MediaCodec$CryptoException"));
825 CHECK(clazz.get() != NULL);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700826
827 jmethodID constructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700828 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
Andreas Huberbfc56f42012-04-19 12:47:07 -0700829 CHECK(constructID != NULL);
830
831 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
832
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700833 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700834 switch (err) {
835 case ERROR_DRM_NO_LICENSE:
836 err = gCryptoErrorCodes.cryptoErrorNoKey;
837 break;
838 case ERROR_DRM_LICENSE_EXPIRED:
839 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
840 break;
841 case ERROR_DRM_RESOURCE_BUSY:
842 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
843 break;
Jeff Tinker336d3ea2014-08-28 17:57:36 -0700844 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
845 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
846 break;
Jeff Tinker96a2a952015-07-01 17:35:18 -0700847 case ERROR_DRM_SESSION_NOT_OPENED:
848 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
849 break;
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700850 default: /* Other negative DRM error codes go out as is. */
Jeff Tinker3ed38262013-08-02 23:24:51 -0700851 break;
852 }
853
Andreas Huberbfc56f42012-04-19 12:47:07 -0700854 jthrowable exception =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700855 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
Andreas Huberbfc56f42012-04-19 12:47:07 -0700856
857 env->Throw(exception);
858}
859
860static jint throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700861 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
862 const char *msg = NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800863 switch (err) {
864 case OK:
865 return 0;
866
867 case -EAGAIN:
868 return DEQUEUE_INFO_TRY_AGAIN_LATER;
869
870 case INFO_FORMAT_CHANGED:
871 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
872
873 case INFO_OUTPUT_BUFFERS_CHANGED:
874 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
875
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700876 case INVALID_OPERATION:
877 jniThrowException(env, "java/lang/IllegalStateException", msg);
878 return 0;
Jeff Tinker3ed38262013-08-02 23:24:51 -0700879
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700880 case BAD_VALUE:
881 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
882 return 0;
883
Andreas Huber88572f72012-02-21 11:47:18 -0800884 default:
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700885 if (isCryptoError(err)) {
886 throwCryptoException(env, err, msg);
887 return 0;
888 }
889 throwCodecException(env, err, actionCode, msg);
890 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -0800891 }
Andreas Huber88572f72012-02-21 11:47:18 -0800892}
893
Lajos Molnard8578572015-06-05 20:17:33 -0700894static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
895 JNIEnv *env,
896 jobject thiz,
897 jboolean enabled) {
898 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
899
900 if (codec == NULL) {
901 throwExceptionAsNecessary(env, INVALID_OPERATION);
902 return;
903 }
904
905 status_t err = codec->enableOnFrameRenderedListener(enabled);
906
907 throwExceptionAsNecessary(env, err);
908}
909
Chong Zhang8d5e5562014-07-08 18:49:21 -0700910static void android_media_MediaCodec_native_setCallback(
911 JNIEnv *env,
912 jobject thiz,
913 jobject cb) {
914 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
915
916 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700917 throwExceptionAsNecessary(env, INVALID_OPERATION);
Chong Zhang8d5e5562014-07-08 18:49:21 -0700918 return;
919 }
920
921 status_t err = codec->setCallback(cb);
922
923 throwExceptionAsNecessary(env, err);
924}
925
Andreas Huber88572f72012-02-21 11:47:18 -0800926static void android_media_MediaCodec_native_configure(
927 JNIEnv *env,
928 jobject thiz,
929 jobjectArray keys, jobjectArray values,
930 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -0700931 jobject jcrypto,
Andreas Huber88572f72012-02-21 11:47:18 -0800932 jint flags) {
933 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
934
935 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -0700936 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -0800937 return;
938 }
939
940 sp<AMessage> format;
941 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
942
943 if (err != OK) {
944 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
945 return;
946 }
947
Andy McFaddend47f7d82012-12-18 09:48:38 -0800948 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -0800949 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700950 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -0800951 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -0800952 bufferProducer = surface->getIGraphicBufferProducer();
Andreas Huber88572f72012-02-21 11:47:18 -0800953 } else {
954 jniThrowException(
955 env,
956 "java/lang/IllegalArgumentException",
957 "The surface has been released");
958 return;
959 }
960 }
961
Andreas Huber8240d922012-04-04 14:06:32 -0700962 sp<ICrypto> crypto;
963 if (jcrypto != NULL) {
964 crypto = JCrypto::GetCrypto(env, jcrypto);
965 }
966
Andy McFaddend47f7d82012-12-18 09:48:38 -0800967 err = codec->configure(format, bufferProducer, crypto, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800968
969 throwExceptionAsNecessary(env, err);
970}
971
Lajos Molnar5e02ba92015-05-01 15:59:35 -0700972static void android_media_MediaCodec_native_setSurface(
973 JNIEnv *env,
974 jobject thiz,
975 jobject jsurface) {
976 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
977
978 if (codec == NULL) {
979 throwExceptionAsNecessary(env, INVALID_OPERATION);
980 return;
981 }
982
983 sp<IGraphicBufferProducer> bufferProducer;
984 if (jsurface != NULL) {
985 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
986 if (surface != NULL) {
987 bufferProducer = surface->getIGraphicBufferProducer();
988 } else {
989 jniThrowException(
990 env,
991 "java/lang/IllegalArgumentException",
992 "The surface has been released");
993 return;
994 }
995 }
996
997 status_t err = codec->setSurface(bufferProducer);
998 throwExceptionAsNecessary(env, err);
999}
1000
Chong Zhang8034d602015-04-28 13:38:48 -07001001sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1002 JNIEnv* env, jobject object) {
1003 sp<PersistentSurface> persistentSurface;
1004
1005 jobject lock = env->GetObjectField(
1006 object, gPersistentSurfaceClassInfo.mLock);
1007 if (env->MonitorEnter(lock) == JNI_OK) {
1008 persistentSurface = reinterpret_cast<PersistentSurface *>(
1009 env->GetLongField(object,
1010 gPersistentSurfaceClassInfo.mPersistentObject));
1011 env->MonitorExit(lock);
1012 }
1013 env->DeleteLocalRef(lock);
1014
1015 return persistentSurface;
1016}
1017
1018static jobject android_media_MediaCodec_createPersistentInputSurface(
1019 JNIEnv* env, jclass /* clazz */) {
1020 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1021 sp<PersistentSurface> persistentSurface =
1022 MediaCodec::CreatePersistentInputSurface();
1023
1024 if (persistentSurface == NULL) {
1025 return NULL;
1026 }
1027
1028 sp<Surface> surface = new Surface(
1029 persistentSurface->getBufferProducer(), true);
1030 if (surface == NULL) {
1031 return NULL;
1032 }
1033
1034 jobject object = env->NewObject(
1035 gPersistentSurfaceClassInfo.clazz,
1036 gPersistentSurfaceClassInfo.ctor);
1037
1038 if (object == NULL) {
1039 if (env->ExceptionCheck()) {
1040 ALOGE("Could not create PersistentSurface.");
1041 env->ExceptionClear();
1042 }
1043 return NULL;
1044 }
1045
1046 jobject lock = env->GetObjectField(
1047 object, gPersistentSurfaceClassInfo.mLock);
1048 if (env->MonitorEnter(lock) == JNI_OK) {
1049 env->CallVoidMethod(
1050 object,
1051 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1052 (jlong)surface.get());
1053 env->SetLongField(
1054 object,
1055 gPersistentSurfaceClassInfo.mPersistentObject,
1056 (jlong)persistentSurface.get());
1057 env->MonitorExit(lock);
1058 } else {
1059 env->DeleteLocalRef(object);
1060 object = NULL;
1061 }
1062 env->DeleteLocalRef(lock);
1063
1064 if (object != NULL) {
1065 surface->incStrong(&sRefBaseOwner);
1066 persistentSurface->incStrong(&sRefBaseOwner);
1067 }
1068
1069 return object;
1070}
1071
1072static void android_media_MediaCodec_releasePersistentInputSurface(
1073 JNIEnv* env, jclass /* clazz */, jobject object) {
1074 sp<PersistentSurface> persistentSurface;
1075
1076 jobject lock = env->GetObjectField(
1077 object, gPersistentSurfaceClassInfo.mLock);
1078 if (env->MonitorEnter(lock) == JNI_OK) {
1079 persistentSurface = reinterpret_cast<PersistentSurface *>(
1080 env->GetLongField(
1081 object, gPersistentSurfaceClassInfo.mPersistentObject));
1082 env->SetLongField(
1083 object,
1084 gPersistentSurfaceClassInfo.mPersistentObject,
1085 (jlong)0);
1086 env->MonitorExit(lock);
1087 }
1088 env->DeleteLocalRef(lock);
1089
1090 if (persistentSurface != NULL) {
1091 persistentSurface->decStrong(&sRefBaseOwner);
1092 }
1093 // no need to release surface as it will be released by Surface's jni
1094}
1095
Chong Zhang9560ddb2015-05-13 10:25:29 -07001096static void android_media_MediaCodec_setInputSurface(
Chong Zhang8034d602015-04-28 13:38:48 -07001097 JNIEnv* env, jobject thiz, jobject object) {
Chong Zhang9560ddb2015-05-13 10:25:29 -07001098 ALOGV("android_media_MediaCodec_setInputSurface");
Chong Zhang8034d602015-04-28 13:38:48 -07001099
1100 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1101 if (codec == NULL) {
1102 throwExceptionAsNecessary(env, INVALID_OPERATION);
1103 return;
1104 }
1105
1106 sp<PersistentSurface> persistentSurface =
1107 android_media_MediaCodec_getPersistentInputSurface(env, object);
1108
Chong Zhang9560ddb2015-05-13 10:25:29 -07001109 status_t err = codec->setInputSurface(persistentSurface);
Chong Zhang8034d602015-04-28 13:38:48 -07001110 if (err != NO_ERROR) {
1111 throwExceptionAsNecessary(env, err);
1112 }
1113}
1114
Andy McFadden2621e402013-02-19 07:29:21 -08001115static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1116 jobject thiz) {
1117 ALOGV("android_media_MediaCodec_createInputSurface");
1118
1119 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1120 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001121 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001122 return NULL;
1123 }
1124
1125 // Tell the MediaCodec that we want to use a Surface as input.
1126 sp<IGraphicBufferProducer> bufferProducer;
1127 status_t err = codec->createInputSurface(&bufferProducer);
1128 if (err != NO_ERROR) {
1129 throwExceptionAsNecessary(env, err);
1130 return NULL;
1131 }
1132
1133 // Wrap the IGBP in a Java-language Surface.
1134 return android_view_Surface_createFromIGraphicBufferProducer(env,
1135 bufferProducer);
1136}
1137
Andreas Huber88572f72012-02-21 11:47:18 -08001138static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1139 ALOGV("android_media_MediaCodec_start");
1140
1141 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1142
1143 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001144 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001145 return;
1146 }
1147
1148 status_t err = codec->start();
1149
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001150 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
Andreas Huber88572f72012-02-21 11:47:18 -08001151}
1152
1153static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1154 ALOGV("android_media_MediaCodec_stop");
1155
1156 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1157
1158 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001159 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001160 return;
1161 }
1162
1163 status_t err = codec->stop();
1164
1165 throwExceptionAsNecessary(env, err);
1166}
1167
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001168static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1169 ALOGV("android_media_MediaCodec_reset");
1170
1171 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1172
1173 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001174 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001175 return;
1176 }
1177
1178 status_t err = codec->reset();
1179 if (err != OK) {
1180 // treat all errors as fatal for now, though resource not available
1181 // errors could be treated as transient.
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001182 // we also should avoid sending INVALID_OPERATION here due to
1183 // the transitory nature of reset(), it should not inadvertently
1184 // trigger an IllegalStateException.
1185 err = UNKNOWN_ERROR;
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001186 }
1187 throwExceptionAsNecessary(env, err);
1188}
1189
Andreas Huber88572f72012-02-21 11:47:18 -08001190static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1191 ALOGV("android_media_MediaCodec_flush");
1192
1193 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1194
1195 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001196 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001197 return;
1198 }
1199
1200 status_t err = codec->flush();
1201
1202 throwExceptionAsNecessary(env, err);
1203}
1204
1205static void android_media_MediaCodec_queueInputBuffer(
1206 JNIEnv *env,
1207 jobject thiz,
1208 jint index,
1209 jint offset,
1210 jint size,
1211 jlong timestampUs,
1212 jint flags) {
1213 ALOGV("android_media_MediaCodec_queueInputBuffer");
1214
1215 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1216
1217 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001218 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001219 return;
1220 }
1221
Andreas Huberbfc56f42012-04-19 12:47:07 -07001222 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -08001223
Andreas Huberbfc56f42012-04-19 12:47:07 -07001224 status_t err = codec->queueInputBuffer(
1225 index, offset, size, timestampUs, flags, &errorDetailMsg);
1226
1227 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001228 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -08001229}
1230
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001231static void android_media_MediaCodec_queueSecureInputBuffer(
1232 JNIEnv *env,
1233 jobject thiz,
1234 jint index,
1235 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -07001236 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001237 jlong timestampUs,
1238 jint flags) {
1239 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1240
1241 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1242
1243 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001244 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001245 return;
1246 }
1247
Andreas Huber91befdc2012-04-18 12:19:51 -07001248 jint numSubSamples =
1249 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1250
1251 jintArray numBytesOfClearDataObj =
1252 (jintArray)env->GetObjectField(
1253 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1254
1255 jintArray numBytesOfEncryptedDataObj =
1256 (jintArray)env->GetObjectField(
1257 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1258
1259 jbyteArray keyObj =
1260 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1261
1262 jbyteArray ivObj =
1263 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1264
1265 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1266
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001267 status_t err = OK;
1268
1269 CryptoPlugin::SubSample *subSamples = NULL;
1270 jbyte *key = NULL;
1271 jbyte *iv = NULL;
1272
1273 if (numSubSamples <= 0) {
1274 err = -EINVAL;
1275 } else if (numBytesOfClearDataObj == NULL
1276 && numBytesOfEncryptedDataObj == NULL) {
1277 err = -EINVAL;
1278 } else if (numBytesOfEncryptedDataObj != NULL
1279 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1280 err = -ERANGE;
1281 } else if (numBytesOfClearDataObj != NULL
1282 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1283 err = -ERANGE;
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001284 // subSamples array may silently overflow if number of samples are too large. Use
1285 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001286 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
Lajos Molnar7ac4f562014-03-24 15:57:51 -07001287 err = -EINVAL;
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001288 } else {
1289 jboolean isCopy;
1290
1291 jint *numBytesOfClearData =
1292 (numBytesOfClearDataObj == NULL)
1293 ? NULL
1294 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1295
1296 jint *numBytesOfEncryptedData =
1297 (numBytesOfEncryptedDataObj == NULL)
1298 ? NULL
1299 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1300
1301 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1302
1303 for (jint i = 0; i < numSubSamples; ++i) {
1304 subSamples[i].mNumBytesOfClearData =
1305 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1306
1307 subSamples[i].mNumBytesOfEncryptedData =
1308 (numBytesOfEncryptedData == NULL)
1309 ? 0 : numBytesOfEncryptedData[i];
1310 }
1311
1312 if (numBytesOfEncryptedData != NULL) {
1313 env->ReleaseIntArrayElements(
1314 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1315 numBytesOfEncryptedData = NULL;
1316 }
1317
1318 if (numBytesOfClearData != NULL) {
1319 env->ReleaseIntArrayElements(
1320 numBytesOfClearDataObj, numBytesOfClearData, 0);
1321 numBytesOfClearData = NULL;
1322 }
1323 }
1324
1325 if (err == OK && keyObj != NULL) {
1326 if (env->GetArrayLength(keyObj) != 16) {
1327 err = -EINVAL;
1328 } else {
1329 jboolean isCopy;
1330 key = env->GetByteArrayElements(keyObj, &isCopy);
1331 }
1332 }
1333
1334 if (err == OK && ivObj != NULL) {
1335 if (env->GetArrayLength(ivObj) != 16) {
1336 err = -EINVAL;
1337 } else {
1338 jboolean isCopy;
1339 iv = env->GetByteArrayElements(ivObj, &isCopy);
1340 }
1341 }
1342
Andreas Huberbfc56f42012-04-19 12:47:07 -07001343 AString errorDetailMsg;
1344
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001345 if (err == OK) {
1346 err = codec->queueSecureInputBuffer(
1347 index, offset,
1348 subSamples, numSubSamples,
1349 (const uint8_t *)key, (const uint8_t *)iv,
1350 (CryptoPlugin::Mode)mode,
Andreas Huberbfc56f42012-04-19 12:47:07 -07001351 timestampUs,
1352 flags,
1353 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001354 }
1355
1356 if (iv != NULL) {
1357 env->ReleaseByteArrayElements(ivObj, iv, 0);
1358 iv = NULL;
1359 }
1360
1361 if (key != NULL) {
1362 env->ReleaseByteArrayElements(keyObj, key, 0);
1363 key = NULL;
1364 }
1365
1366 delete[] subSamples;
1367 subSamples = NULL;
1368
Andreas Huberbfc56f42012-04-19 12:47:07 -07001369 throwExceptionAsNecessary(
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001370 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001371}
1372
Andreas Huber88572f72012-02-21 11:47:18 -08001373static jint android_media_MediaCodec_dequeueInputBuffer(
1374 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1375 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1376
1377 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1378
1379 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001380 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001381 return -1;
1382 }
1383
1384 size_t index;
1385 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1386
1387 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001388 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001389 }
1390
1391 return throwExceptionAsNecessary(env, err);
1392}
1393
1394static jint android_media_MediaCodec_dequeueOutputBuffer(
1395 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1396 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1397
1398 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1399
1400 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001401 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber0e97fc22012-04-03 13:32:16 -07001402 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -08001403 }
1404
1405 size_t index;
1406 status_t err = codec->dequeueOutputBuffer(
1407 env, bufferInfo, &index, timeoutUs);
1408
1409 if (err == OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +00001410 return (jint) index;
Andreas Huber88572f72012-02-21 11:47:18 -08001411 }
1412
1413 return throwExceptionAsNecessary(env, err);
1414}
1415
1416static void android_media_MediaCodec_releaseOutputBuffer(
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001417 JNIEnv *env, jobject thiz,
1418 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
Andreas Huber88572f72012-02-21 11:47:18 -08001419 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1420
1421 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1422
1423 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001424 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001425 return;
1426 }
1427
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001428 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
Andreas Huber88572f72012-02-21 11:47:18 -08001429
1430 throwExceptionAsNecessary(env, err);
1431}
1432
Andy McFadden2621e402013-02-19 07:29:21 -08001433static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1434 jobject thiz) {
1435 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1436
1437 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1438 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001439 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andy McFadden2621e402013-02-19 07:29:21 -08001440 return;
1441 }
1442
1443 status_t err = codec->signalEndOfInputStream();
1444
1445 throwExceptionAsNecessary(env, err);
1446}
1447
Lajos Molnard4023112014-07-11 15:12:59 -07001448static jobject android_media_MediaCodec_getFormatNative(
1449 JNIEnv *env, jobject thiz, jboolean input) {
1450 ALOGV("android_media_MediaCodec_getFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -08001451
1452 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1453
1454 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001455 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001456 return NULL;
1457 }
1458
1459 jobject format;
Lajos Molnard4023112014-07-11 15:12:59 -07001460 status_t err = codec->getFormat(env, input, &format);
1461
1462 if (err == OK) {
1463 return format;
1464 }
1465
1466 throwExceptionAsNecessary(env, err);
1467
1468 return NULL;
1469}
1470
1471static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1472 JNIEnv *env, jobject thiz, jint index) {
1473 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1474
1475 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1476
1477 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001478 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001479 return NULL;
1480 }
1481
1482 jobject format;
1483 status_t err = codec->getOutputFormat(env, index, &format);
Andreas Huber88572f72012-02-21 11:47:18 -08001484
1485 if (err == OK) {
1486 return format;
1487 }
1488
1489 throwExceptionAsNecessary(env, err);
1490
1491 return NULL;
1492}
1493
1494static jobjectArray android_media_MediaCodec_getBuffers(
1495 JNIEnv *env, jobject thiz, jboolean input) {
1496 ALOGV("android_media_MediaCodec_getBuffers");
1497
1498 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1499
1500 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001501 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber88572f72012-02-21 11:47:18 -08001502 return NULL;
1503 }
1504
1505 jobjectArray buffers;
1506 status_t err = codec->getBuffers(env, input, &buffers);
1507
1508 if (err == OK) {
1509 return buffers;
1510 }
1511
Marco Nelissencbbea8e2012-12-19 11:42:55 -08001512 // if we're out of memory, an exception was already thrown
1513 if (err != NO_MEMORY) {
1514 throwExceptionAsNecessary(env, err);
1515 }
Andreas Huber88572f72012-02-21 11:47:18 -08001516
1517 return NULL;
1518}
1519
Lajos Molnard4023112014-07-11 15:12:59 -07001520static jobject android_media_MediaCodec_getBuffer(
1521 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1522 ALOGV("android_media_MediaCodec_getBuffer");
1523
1524 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1525
1526 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001527 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001528 return NULL;
1529 }
1530
1531 jobject buffer;
1532 status_t err = codec->getBuffer(env, input, index, &buffer);
1533
1534 if (err == OK) {
1535 return buffer;
1536 }
1537
1538 // if we're out of memory, an exception was already thrown
1539 if (err != NO_MEMORY) {
1540 throwExceptionAsNecessary(env, err);
1541 }
1542
1543 return NULL;
1544}
1545
1546static jobject android_media_MediaCodec_getImage(
1547 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1548 ALOGV("android_media_MediaCodec_getImage");
1549
1550 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1551
1552 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001553 throwExceptionAsNecessary(env, INVALID_OPERATION);
Lajos Molnard4023112014-07-11 15:12:59 -07001554 return NULL;
1555 }
1556
1557 jobject image;
1558 status_t err = codec->getImage(env, input, index, &image);
1559
1560 if (err == OK) {
1561 return image;
1562 }
1563
1564 // if we're out of memory, an exception was already thrown
1565 if (err != NO_MEMORY) {
1566 throwExceptionAsNecessary(env, err);
1567 }
1568
1569 return NULL;
1570}
1571
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001572static jobject android_media_MediaCodec_getName(
1573 JNIEnv *env, jobject thiz) {
1574 ALOGV("android_media_MediaCodec_getName");
1575
1576 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1577
1578 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001579 throwExceptionAsNecessary(env, INVALID_OPERATION);
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001580 return NULL;
1581 }
1582
1583 jstring name;
1584 status_t err = codec->getName(env, &name);
1585
1586 if (err == OK) {
1587 return name;
1588 }
1589
1590 throwExceptionAsNecessary(env, err);
1591
1592 return NULL;
1593}
1594
Andreas Huber226065b2013-08-12 10:14:11 -07001595static void android_media_MediaCodec_setParameters(
1596 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1597 ALOGV("android_media_MediaCodec_setParameters");
1598
1599 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1600
1601 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001602 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huber226065b2013-08-12 10:14:11 -07001603 return;
1604 }
1605
1606 sp<AMessage> params;
1607 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
1608
1609 if (err == OK) {
1610 err = codec->setParameters(params);
1611 }
1612
1613 throwExceptionAsNecessary(env, err);
1614}
1615
Andreas Huberb12a5392012-04-30 14:18:33 -07001616static void android_media_MediaCodec_setVideoScalingMode(
1617 JNIEnv *env, jobject thiz, jint mode) {
1618 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1619
1620 if (codec == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001621 throwExceptionAsNecessary(env, INVALID_OPERATION);
Andreas Huberb12a5392012-04-30 14:18:33 -07001622 return;
1623 }
1624
1625 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1626 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
1627 jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
1628 return;
1629 }
1630
1631 codec->setVideoScalingMode(mode);
1632}
1633
Andreas Huber88572f72012-02-21 11:47:18 -08001634static void android_media_MediaCodec_native_init(JNIEnv *env) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001635 ScopedLocalRef<jclass> clazz(
1636 env, env->FindClass("android/media/MediaCodec"));
1637 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001638
Ashok Bhat075e9a12014-01-06 13:45:09 +00001639 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
Andreas Huber88572f72012-02-21 11:47:18 -08001640 CHECK(gFields.context != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001641
Andreas Huberaba67132013-10-22 12:40:01 -07001642 gFields.postEventFromNativeID =
1643 env->GetMethodID(
1644 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1645
1646 CHECK(gFields.postEventFromNativeID != NULL);
1647
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001648 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1649 CHECK(clazz.get() != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -07001650
1651 gFields.cryptoInfoNumSubSamplesID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001652 env->GetFieldID(clazz.get(), "numSubSamples", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001653 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1654
1655 gFields.cryptoInfoNumBytesOfClearDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001656 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001657 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1658
1659 gFields.cryptoInfoNumBytesOfEncryptedDataID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001660 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001661 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1662
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001663 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001664 CHECK(gFields.cryptoInfoKeyID != NULL);
1665
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001666 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
Andreas Huber91befdc2012-04-18 12:19:51 -07001667 CHECK(gFields.cryptoInfoIVID != NULL);
1668
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001669 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
Andreas Huber91befdc2012-04-18 12:19:51 -07001670 CHECK(gFields.cryptoInfoModeID != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001671
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001672 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1673 CHECK(clazz.get() != NULL);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001674
1675 jfieldID field;
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001676 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001677 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001678 gCryptoErrorCodes.cryptoErrorNoKey =
1679 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001680
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001681 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001682 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001683 gCryptoErrorCodes.cryptoErrorKeyExpired =
1684 env->GetStaticIntField(clazz.get(), field);
Jeff Tinker3ed38262013-08-02 23:24:51 -07001685
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001686 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
Jeff Tinker3ed38262013-08-02 23:24:51 -07001687 CHECK(field != NULL);
Andreas Huber8d5f3e32013-08-12 09:19:45 -07001688 gCryptoErrorCodes.cryptoErrorResourceBusy =
1689 env->GetStaticIntField(clazz.get(), field);
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001690
Jeff Tinker336d3ea2014-08-28 17:57:36 -07001691 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1692 CHECK(field != NULL);
1693 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1694 env->GetStaticIntField(clazz.get(), field);
1695
Jeff Tinker96a2a952015-07-01 17:35:18 -07001696 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1697 CHECK(field != NULL);
1698 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1699 env->GetStaticIntField(clazz.get(), field);
1700
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001701 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
1702 CHECK(clazz.get() != NULL);
1703 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
1704 CHECK(field != NULL);
1705 gCodecActionCodes.codecActionTransient =
1706 env->GetStaticIntField(clazz.get(), field);
1707
1708 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
1709 CHECK(field != NULL);
1710 gCodecActionCodes.codecActionRecoverable =
1711 env->GetStaticIntField(clazz.get(), field);
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001712
Ronghua Wuc53ad692015-05-08 14:40:49 -07001713 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001714 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001715 gCodecErrorCodes.errorInsufficientResource =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001716 env->GetStaticIntField(clazz.get(), field);
1717
Ronghua Wuc53ad692015-05-08 14:40:49 -07001718 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001719 CHECK(field != NULL);
Ronghua Wuc53ad692015-05-08 14:40:49 -07001720 gCodecErrorCodes.errorReclaimed =
Ronghua Wu9e9ec942015-04-15 17:10:31 -07001721 env->GetStaticIntField(clazz.get(), field);
Chong Zhang8034d602015-04-28 13:38:48 -07001722
1723 clazz.reset(env->FindClass("android/view/Surface"));
1724 CHECK(clazz.get() != NULL);
1725
1726 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
1727 CHECK(field != NULL);
1728 gPersistentSurfaceClassInfo.mLock = field;
1729
1730 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
1731 CHECK(method != NULL);
1732 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
1733
1734 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
1735 CHECK(clazz.get() != NULL);
1736 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
1737
1738 method = env->GetMethodID(clazz.get(), "<init>", "()V");
1739 CHECK(method != NULL);
1740 gPersistentSurfaceClassInfo.ctor = method;
1741
1742 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
1743 CHECK(field != NULL);
1744 gPersistentSurfaceClassInfo.mPersistentObject = field;
Andreas Huber88572f72012-02-21 11:47:18 -08001745}
1746
1747static void android_media_MediaCodec_native_setup(
1748 JNIEnv *env, jobject thiz,
1749 jstring name, jboolean nameIsType, jboolean encoder) {
1750 if (name == NULL) {
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001751 jniThrowException(env, "java/lang/NullPointerException", NULL);
Andreas Huber88572f72012-02-21 11:47:18 -08001752 return;
1753 }
1754
1755 const char *tmp = env->GetStringUTFChars(name, NULL);
1756
1757 if (tmp == NULL) {
1758 return;
1759 }
1760
1761 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
1762
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001763 const status_t err = codec->initCheck();
1764 if (err == NAME_NOT_FOUND) {
1765 // fail and do not try again.
1766 jniThrowException(env, "java/lang/IllegalArgumentException",
1767 String8::format("Failed to initialize %s, error %#x", tmp, err));
1768 env->ReleaseStringUTFChars(name, tmp);
1769 return;
Ronghua Wuc53ad692015-05-08 14:40:49 -07001770 } if (err == NO_MEMORY) {
1771 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
1772 String8::format("Failed to initialize %s, error %#x", tmp, err));
1773 env->ReleaseStringUTFChars(name, tmp);
1774 return;
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001775 } else if (err != OK) {
1776 // believed possible to try again
1777 jniThrowException(env, "java/io/IOException",
1778 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
1779 env->ReleaseStringUTFChars(name, tmp);
Andreas Huber88572f72012-02-21 11:47:18 -08001780 return;
1781 }
1782
Andy Hung5f9aa0b2014-07-30 15:48:21 -07001783 env->ReleaseStringUTFChars(name, tmp);
1784
Andreas Huberaba67132013-10-22 12:40:01 -07001785 codec->registerSelf();
1786
Andreas Huber88572f72012-02-21 11:47:18 -08001787 setMediaCodec(env,thiz, codec);
1788}
1789
1790static void android_media_MediaCodec_native_finalize(
1791 JNIEnv *env, jobject thiz) {
1792 android_media_MediaCodec_release(env, thiz);
1793}
1794
1795static JNINativeMethod gMethods[] = {
Lajos Molnard4023112014-07-11 15:12:59 -07001796 { "native_release", "()V", (void *)android_media_MediaCodec_release },
Andreas Huber88572f72012-02-21 11:47:18 -08001797
Lajos Molnar1e6e8012014-07-15 16:07:13 -07001798 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1799
Chong Zhang8034d602015-04-28 13:38:48 -07001800 { "native_releasePersistentInputSurface",
1801 "(Landroid/view/Surface;)V",
1802 (void *)android_media_MediaCodec_releasePersistentInputSurface},
1803
1804 { "native_createPersistentInputSurface",
1805 "()Landroid/media/MediaCodec$PersistentSurface;",
1806 (void *)android_media_MediaCodec_createPersistentInputSurface },
1807
Chong Zhang9560ddb2015-05-13 10:25:29 -07001808 { "native_setInputSurface", "(Landroid/view/Surface;)V",
1809 (void *)android_media_MediaCodec_setInputSurface },
Chong Zhang8034d602015-04-28 13:38:48 -07001810
Lajos Molnard8578572015-06-05 20:17:33 -07001811 { "native_enableOnFrameRenderedListener", "(Z)V",
1812 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
1813
Chong Zhang8d5e5562014-07-08 18:49:21 -07001814 { "native_setCallback",
1815 "(Landroid/media/MediaCodec$Callback;)V",
1816 (void *)android_media_MediaCodec_native_setCallback },
1817
Andreas Huber88572f72012-02-21 11:47:18 -08001818 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -07001819 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Andreas Huber07ea4262012-04-11 12:21:20 -07001820 "Landroid/media/MediaCrypto;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001821 (void *)android_media_MediaCodec_native_configure },
1822
Lajos Molnar5e02ba92015-05-01 15:59:35 -07001823 { "native_setSurface",
1824 "(Landroid/view/Surface;)V",
1825 (void *)android_media_MediaCodec_native_setSurface },
1826
Andy McFadden2621e402013-02-19 07:29:21 -08001827 { "createInputSurface", "()Landroid/view/Surface;",
1828 (void *)android_media_MediaCodec_createInputSurface },
1829
Lajos Molnard4023112014-07-11 15:12:59 -07001830 { "native_start", "()V", (void *)android_media_MediaCodec_start },
Andreas Huberaba67132013-10-22 12:40:01 -07001831 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
Lajos Molnard4023112014-07-11 15:12:59 -07001832 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
Andreas Huber88572f72012-02-21 11:47:18 -08001833
Lajos Molnard4023112014-07-11 15:12:59 -07001834 { "native_queueInputBuffer", "(IIIJI)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001835 (void *)android_media_MediaCodec_queueInputBuffer },
1836
Lajos Molnard4023112014-07-11 15:12:59 -07001837 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -07001838 (void *)android_media_MediaCodec_queueSecureInputBuffer },
1839
Lajos Molnard4023112014-07-11 15:12:59 -07001840 { "native_dequeueInputBuffer", "(J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08001841 (void *)android_media_MediaCodec_dequeueInputBuffer },
1842
Lajos Molnard4023112014-07-11 15:12:59 -07001843 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
Andreas Huber88572f72012-02-21 11:47:18 -08001844 (void *)android_media_MediaCodec_dequeueOutputBuffer },
1845
Lajos Molnar7c513b6b2014-05-08 17:16:45 -07001846 { "releaseOutputBuffer", "(IZZJ)V",
Andreas Huber88572f72012-02-21 11:47:18 -08001847 (void *)android_media_MediaCodec_releaseOutputBuffer },
1848
Andy McFadden2621e402013-02-19 07:29:21 -08001849 { "signalEndOfInputStream", "()V",
1850 (void *)android_media_MediaCodec_signalEndOfInputStream },
1851
Lajos Molnard4023112014-07-11 15:12:59 -07001852 { "getFormatNative", "(Z)Ljava/util/Map;",
1853 (void *)android_media_MediaCodec_getFormatNative },
1854
1855 { "getOutputFormatNative", "(I)Ljava/util/Map;",
1856 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
Andreas Huber88572f72012-02-21 11:47:18 -08001857
1858 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1859 (void *)android_media_MediaCodec_getBuffers },
1860
Lajos Molnard4023112014-07-11 15:12:59 -07001861 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
1862 (void *)android_media_MediaCodec_getBuffer },
1863
1864 { "getImage", "(ZI)Landroid/media/Image;",
1865 (void *)android_media_MediaCodec_getImage },
1866
Martin Storsjo056ef2e2012-09-25 11:53:04 +03001867 { "getName", "()Ljava/lang/String;",
1868 (void *)android_media_MediaCodec_getName },
1869
Andreas Huber226065b2013-08-12 10:14:11 -07001870 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
1871 (void *)android_media_MediaCodec_setParameters },
1872
Andreas Huberb12a5392012-04-30 14:18:33 -07001873 { "setVideoScalingMode", "(I)V",
1874 (void *)android_media_MediaCodec_setVideoScalingMode },
1875
Andreas Huber88572f72012-02-21 11:47:18 -08001876 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
1877
1878 { "native_setup", "(Ljava/lang/String;ZZ)V",
1879 (void *)android_media_MediaCodec_native_setup },
1880
1881 { "native_finalize", "()V",
1882 (void *)android_media_MediaCodec_native_finalize },
1883};
1884
1885int register_android_media_MediaCodec(JNIEnv *env) {
1886 return AndroidRuntime::registerNativeMethods(env,
1887 "android/media/MediaCodec", gMethods, NELEM(gMethods));
1888}