blob: 8740c0854d6320794578da7697331da66699ba9f [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
Mathias Agopian8335f1c2012-02-25 18:48:35 -080030#include <gui/Surface.h>
31#include <gui/SurfaceTextureClient.h>
32
Andreas Huber0e97fc22012-04-03 13:32:16 -070033#include <media/ICrypto.h>
Andreas Huber88572f72012-02-21 11:47:18 -080034#include <media/stagefright/MediaCodec.h>
35#include <media/stagefright/foundation/ABuffer.h>
36#include <media/stagefright/foundation/ADebug.h>
37#include <media/stagefright/foundation/ALooper.h>
38#include <media/stagefright/foundation/AMessage.h>
Andreas Huberbfc56f42012-04-19 12:47:07 -070039#include <media/stagefright/foundation/AString.h>
Andreas Huber88572f72012-02-21 11:47:18 -080040#include <media/stagefright/MediaErrors.h>
Andreas Huber88572f72012-02-21 11:47:18 -080041
Andreas Huberb12a5392012-04-30 14:18:33 -070042#include <system/window.h>
43
Andreas Huber88572f72012-02-21 11:47:18 -080044namespace android {
45
46// Keep these in sync with their equivalents in MediaCodec.java !!!
47enum {
48 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
49 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
50 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
51};
52
53struct fields_t {
54 jfieldID context;
Andreas Huber91befdc2012-04-18 12:19:51 -070055
56 jfieldID cryptoInfoNumSubSamplesID;
57 jfieldID cryptoInfoNumBytesOfClearDataID;
58 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
59 jfieldID cryptoInfoKeyID;
60 jfieldID cryptoInfoIVID;
61 jfieldID cryptoInfoModeID;
Andreas Huber88572f72012-02-21 11:47:18 -080062};
63
64static fields_t gFields;
65
66////////////////////////////////////////////////////////////////////////////////
67
68JMediaCodec::JMediaCodec(
69 JNIEnv *env, jobject thiz,
70 const char *name, bool nameIsType, bool encoder)
71 : mClass(NULL),
72 mObject(NULL) {
73 jclass clazz = env->GetObjectClass(thiz);
74 CHECK(clazz != NULL);
75
76 mClass = (jclass)env->NewGlobalRef(clazz);
77 mObject = env->NewWeakGlobalRef(thiz);
78
79 mLooper = new ALooper;
80 mLooper->setName("MediaCodec_looper");
81
82 mLooper->start(
83 false, // runOnCallingThread
84 false, // canCallJava
85 PRIORITY_DEFAULT);
86
87 if (nameIsType) {
88 mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
89 } else {
90 mCodec = MediaCodec::CreateByComponentName(mLooper, name);
91 }
92}
93
94status_t JMediaCodec::initCheck() const {
95 return mCodec != NULL ? OK : NO_INIT;
96}
97
98JMediaCodec::~JMediaCodec() {
Martin Storsjod932de92012-07-13 13:01:06 +030099 if (mCodec != NULL) {
100 mCodec->release();
101 mCodec.clear();
102 }
Andreas Huber88572f72012-02-21 11:47:18 -0800103
104 JNIEnv *env = AndroidRuntime::getJNIEnv();
105
106 env->DeleteWeakGlobalRef(mObject);
107 mObject = NULL;
108 env->DeleteGlobalRef(mClass);
109 mClass = NULL;
110}
111
112status_t JMediaCodec::configure(
113 const sp<AMessage> &format,
Andy McFaddend47f7d82012-12-18 09:48:38 -0800114 const sp<IGraphicBufferProducer> &bufferProducer,
Andreas Huber8240d922012-04-04 14:06:32 -0700115 const sp<ICrypto> &crypto,
Andreas Huber88572f72012-02-21 11:47:18 -0800116 int flags) {
117 sp<SurfaceTextureClient> client;
Andy McFaddend47f7d82012-12-18 09:48:38 -0800118 if (bufferProducer != NULL) {
119 mSurfaceTextureClient = new SurfaceTextureClient(bufferProducer);
Andreas Huberb12a5392012-04-30 14:18:33 -0700120 } else {
121 mSurfaceTextureClient.clear();
Andreas Huber88572f72012-02-21 11:47:18 -0800122 }
Andreas Huberb12a5392012-04-30 14:18:33 -0700123
124 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800125}
126
127status_t JMediaCodec::start() {
128 return mCodec->start();
129}
130
131status_t JMediaCodec::stop() {
Andreas Huberb12a5392012-04-30 14:18:33 -0700132 mSurfaceTextureClient.clear();
133
Andreas Huber88572f72012-02-21 11:47:18 -0800134 return mCodec->stop();
135}
136
137status_t JMediaCodec::flush() {
138 return mCodec->flush();
139}
140
141status_t JMediaCodec::queueInputBuffer(
142 size_t index,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700143 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
144 AString *errorDetailMsg) {
145 return mCodec->queueInputBuffer(
146 index, offset, size, timeUs, flags, errorDetailMsg);
Andreas Huber88572f72012-02-21 11:47:18 -0800147}
148
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700149status_t JMediaCodec::queueSecureInputBuffer(
150 size_t index,
151 size_t offset,
152 const CryptoPlugin::SubSample *subSamples,
153 size_t numSubSamples,
154 const uint8_t key[16],
155 const uint8_t iv[16],
156 CryptoPlugin::Mode mode,
157 int64_t presentationTimeUs,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700158 uint32_t flags,
159 AString *errorDetailMsg) {
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700160 return mCodec->queueSecureInputBuffer(
161 index, offset, subSamples, numSubSamples, key, iv, mode,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700162 presentationTimeUs, flags, errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700163}
164
Andreas Huber88572f72012-02-21 11:47:18 -0800165status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
166 return mCodec->dequeueInputBuffer(index, timeoutUs);
167}
168
169status_t JMediaCodec::dequeueOutputBuffer(
170 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
171 size_t size, offset;
172 int64_t timeUs;
173 uint32_t flags;
174 status_t err;
175 if ((err = mCodec->dequeueOutputBuffer(
Andreas Huberc52b9802012-03-12 14:04:01 -0700176 index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) {
Andreas Huber88572f72012-02-21 11:47:18 -0800177 return err;
178 }
179
180 jclass clazz = env->FindClass("android/media/MediaCodec$BufferInfo");
181
182 jmethodID method = env->GetMethodID(clazz, "set", "(IIJI)V");
183 env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags);
184
185 return OK;
186}
187
188status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
189 return render
190 ? mCodec->renderOutputBufferAndRelease(index)
191 : mCodec->releaseOutputBuffer(index);
192}
193
194status_t JMediaCodec::getOutputFormat(JNIEnv *env, jobject *format) const {
195 sp<AMessage> msg;
196 status_t err;
197 if ((err = mCodec->getOutputFormat(&msg)) != OK) {
198 return err;
199 }
200
201 return ConvertMessageToMap(env, msg, format);
202}
203
204status_t JMediaCodec::getBuffers(
205 JNIEnv *env, bool input, jobjectArray *bufArray) const {
206 Vector<sp<ABuffer> > buffers;
207
208 status_t err =
209 input
210 ? mCodec->getInputBuffers(&buffers)
211 : mCodec->getOutputBuffers(&buffers);
212
213 if (err != OK) {
214 return err;
215 }
216
217 jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer");
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700218 CHECK(byteBufferClass != NULL);
219
220 jmethodID orderID = env->GetMethodID(
221 byteBufferClass,
222 "order",
223 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
224
225 CHECK(orderID != NULL);
226
227 jclass byteOrderClass = env->FindClass("java/nio/ByteOrder");
228 CHECK(byteOrderClass != NULL);
229
230 jmethodID nativeOrderID = env->GetStaticMethodID(
231 byteOrderClass, "nativeOrder", "()Ljava/nio/ByteOrder;");
232 CHECK(nativeOrderID != NULL);
233
234 jobject nativeByteOrderObj =
235 env->CallStaticObjectMethod(byteOrderClass, nativeOrderID);
236 CHECK(nativeByteOrderObj != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800237
238 *bufArray = (jobjectArray)env->NewObjectArray(
239 buffers.size(), byteBufferClass, NULL);
240
241 for (size_t i = 0; i < buffers.size(); ++i) {
242 const sp<ABuffer> &buffer = buffers.itemAt(i);
243
244 jobject byteBuffer =
245 env->NewDirectByteBuffer(
246 buffer->base(),
247 buffer->capacity());
248
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700249 jobject me = env->CallObjectMethod(
250 byteBuffer, orderID, nativeByteOrderObj);
251 env->DeleteLocalRef(me);
252 me = NULL;
253
Andreas Huber88572f72012-02-21 11:47:18 -0800254 env->SetObjectArrayElement(
255 *bufArray, i, byteBuffer);
256
257 env->DeleteLocalRef(byteBuffer);
258 byteBuffer = NULL;
259 }
260
Andreas Huber3dd7fd02012-05-08 13:50:45 -0700261 env->DeleteLocalRef(nativeByteOrderObj);
262 nativeByteOrderObj = NULL;
263
Andreas Huber88572f72012-02-21 11:47:18 -0800264 return OK;
265}
266
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300267status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
268 AString name;
269
270 status_t err = mCodec->getName(&name);
271
272 if (err != OK) {
273 return err;
274 }
275
276 *nameStr = env->NewStringUTF(name.c_str());
277
278 return OK;
279}
280
Andreas Huberb12a5392012-04-30 14:18:33 -0700281void JMediaCodec::setVideoScalingMode(int mode) {
282 if (mSurfaceTextureClient != NULL) {
283 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
284 }
285}
286
Andreas Huber88572f72012-02-21 11:47:18 -0800287} // namespace android
288
289////////////////////////////////////////////////////////////////////////////////
290
291using namespace android;
292
293static sp<JMediaCodec> setMediaCodec(
294 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
295 sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context);
296 if (codec != NULL) {
297 codec->incStrong(thiz);
298 }
299 if (old != NULL) {
300 old->decStrong(thiz);
301 }
302 env->SetIntField(thiz, gFields.context, (int)codec.get());
303
304 return old;
305}
306
307static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
308 return (JMediaCodec *)env->GetIntField(thiz, gFields.context);
309}
310
311static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
312 setMediaCodec(env, thiz, NULL);
313}
314
Andreas Huberbfc56f42012-04-19 12:47:07 -0700315static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
316 jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
317 CHECK(clazz != NULL);
318
319 jmethodID constructID =
320 env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
321 CHECK(constructID != NULL);
322
323 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
324
325 jthrowable exception =
326 (jthrowable)env->NewObject(clazz, constructID, err, msgObj);
327
328 env->Throw(exception);
329}
330
331static jint throwExceptionAsNecessary(
332 JNIEnv *env, status_t err, const char *msg = NULL) {
333 if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
334 // We'll throw our custom MediaCodec.CryptoException
335
336 throwCryptoException(env, err, msg);
337 return 0;
338 }
339
Andreas Huber88572f72012-02-21 11:47:18 -0800340 switch (err) {
341 case OK:
342 return 0;
343
344 case -EAGAIN:
345 return DEQUEUE_INFO_TRY_AGAIN_LATER;
346
347 case INFO_FORMAT_CHANGED:
348 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
349
350 case INFO_OUTPUT_BUFFERS_CHANGED:
351 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
352
353 default:
354 {
355 jniThrowException(env, "java/lang/IllegalStateException", NULL);
356 break;
357 }
358 }
359
360 return 0;
361}
362
363static void android_media_MediaCodec_native_configure(
364 JNIEnv *env,
365 jobject thiz,
366 jobjectArray keys, jobjectArray values,
367 jobject jsurface,
Andreas Huber8240d922012-04-04 14:06:32 -0700368 jobject jcrypto,
Andreas Huber88572f72012-02-21 11:47:18 -0800369 jint flags) {
370 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
371
372 if (codec == NULL) {
373 jniThrowException(env, "java/lang/IllegalStateException", NULL);
374 return;
375 }
376
377 sp<AMessage> format;
378 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
379
380 if (err != OK) {
381 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
382 return;
383 }
384
Andy McFaddend47f7d82012-12-18 09:48:38 -0800385 sp<IGraphicBufferProducer> bufferProducer;
Andreas Huber88572f72012-02-21 11:47:18 -0800386 if (jsurface != NULL) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700387 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Andreas Huber88572f72012-02-21 11:47:18 -0800388 if (surface != NULL) {
Andy McFaddend47f7d82012-12-18 09:48:38 -0800389 bufferProducer = surface->getSurfaceTexture();
Andreas Huber88572f72012-02-21 11:47:18 -0800390 } else {
391 jniThrowException(
392 env,
393 "java/lang/IllegalArgumentException",
394 "The surface has been released");
395 return;
396 }
397 }
398
Andreas Huber8240d922012-04-04 14:06:32 -0700399 sp<ICrypto> crypto;
400 if (jcrypto != NULL) {
401 crypto = JCrypto::GetCrypto(env, jcrypto);
402 }
403
Andy McFaddend47f7d82012-12-18 09:48:38 -0800404 err = codec->configure(format, bufferProducer, crypto, flags);
Andreas Huber88572f72012-02-21 11:47:18 -0800405
406 throwExceptionAsNecessary(env, err);
407}
408
409static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
410 ALOGV("android_media_MediaCodec_start");
411
412 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
413
414 if (codec == NULL) {
415 jniThrowException(env, "java/lang/IllegalStateException", NULL);
416 return;
417 }
418
419 status_t err = codec->start();
420
421 throwExceptionAsNecessary(env, err);
422}
423
424static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
425 ALOGV("android_media_MediaCodec_stop");
426
427 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
428
429 if (codec == NULL) {
430 jniThrowException(env, "java/lang/IllegalStateException", NULL);
431 return;
432 }
433
434 status_t err = codec->stop();
435
436 throwExceptionAsNecessary(env, err);
437}
438
439static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
440 ALOGV("android_media_MediaCodec_flush");
441
442 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
443
444 if (codec == NULL) {
445 jniThrowException(env, "java/lang/IllegalStateException", NULL);
446 return;
447 }
448
449 status_t err = codec->flush();
450
451 throwExceptionAsNecessary(env, err);
452}
453
454static void android_media_MediaCodec_queueInputBuffer(
455 JNIEnv *env,
456 jobject thiz,
457 jint index,
458 jint offset,
459 jint size,
460 jlong timestampUs,
461 jint flags) {
462 ALOGV("android_media_MediaCodec_queueInputBuffer");
463
464 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
465
466 if (codec == NULL) {
467 jniThrowException(env, "java/lang/IllegalStateException", NULL);
468 return;
469 }
470
Andreas Huberbfc56f42012-04-19 12:47:07 -0700471 AString errorDetailMsg;
Andreas Huber88572f72012-02-21 11:47:18 -0800472
Andreas Huberbfc56f42012-04-19 12:47:07 -0700473 status_t err = codec->queueInputBuffer(
474 index, offset, size, timestampUs, flags, &errorDetailMsg);
475
476 throwExceptionAsNecessary(
477 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber88572f72012-02-21 11:47:18 -0800478}
479
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700480static void android_media_MediaCodec_queueSecureInputBuffer(
481 JNIEnv *env,
482 jobject thiz,
483 jint index,
484 jint offset,
Andreas Huber91befdc2012-04-18 12:19:51 -0700485 jobject cryptoInfoObj,
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700486 jlong timestampUs,
487 jint flags) {
488 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
489
490 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
491
492 if (codec == NULL) {
493 jniThrowException(env, "java/lang/IllegalStateException", NULL);
494 return;
495 }
496
Andreas Huber91befdc2012-04-18 12:19:51 -0700497 jint numSubSamples =
498 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
499
500 jintArray numBytesOfClearDataObj =
501 (jintArray)env->GetObjectField(
502 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
503
504 jintArray numBytesOfEncryptedDataObj =
505 (jintArray)env->GetObjectField(
506 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
507
508 jbyteArray keyObj =
509 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
510
511 jbyteArray ivObj =
512 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
513
514 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
515
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700516 status_t err = OK;
517
518 CryptoPlugin::SubSample *subSamples = NULL;
519 jbyte *key = NULL;
520 jbyte *iv = NULL;
521
522 if (numSubSamples <= 0) {
523 err = -EINVAL;
524 } else if (numBytesOfClearDataObj == NULL
525 && numBytesOfEncryptedDataObj == NULL) {
526 err = -EINVAL;
527 } else if (numBytesOfEncryptedDataObj != NULL
528 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
529 err = -ERANGE;
530 } else if (numBytesOfClearDataObj != NULL
531 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
532 err = -ERANGE;
533 } else {
534 jboolean isCopy;
535
536 jint *numBytesOfClearData =
537 (numBytesOfClearDataObj == NULL)
538 ? NULL
539 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
540
541 jint *numBytesOfEncryptedData =
542 (numBytesOfEncryptedDataObj == NULL)
543 ? NULL
544 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
545
546 subSamples = new CryptoPlugin::SubSample[numSubSamples];
547
548 for (jint i = 0; i < numSubSamples; ++i) {
549 subSamples[i].mNumBytesOfClearData =
550 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
551
552 subSamples[i].mNumBytesOfEncryptedData =
553 (numBytesOfEncryptedData == NULL)
554 ? 0 : numBytesOfEncryptedData[i];
555 }
556
557 if (numBytesOfEncryptedData != NULL) {
558 env->ReleaseIntArrayElements(
559 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
560 numBytesOfEncryptedData = NULL;
561 }
562
563 if (numBytesOfClearData != NULL) {
564 env->ReleaseIntArrayElements(
565 numBytesOfClearDataObj, numBytesOfClearData, 0);
566 numBytesOfClearData = NULL;
567 }
568 }
569
570 if (err == OK && keyObj != NULL) {
571 if (env->GetArrayLength(keyObj) != 16) {
572 err = -EINVAL;
573 } else {
574 jboolean isCopy;
575 key = env->GetByteArrayElements(keyObj, &isCopy);
576 }
577 }
578
579 if (err == OK && ivObj != NULL) {
580 if (env->GetArrayLength(ivObj) != 16) {
581 err = -EINVAL;
582 } else {
583 jboolean isCopy;
584 iv = env->GetByteArrayElements(ivObj, &isCopy);
585 }
586 }
587
Andreas Huberbfc56f42012-04-19 12:47:07 -0700588 AString errorDetailMsg;
589
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700590 if (err == OK) {
591 err = codec->queueSecureInputBuffer(
592 index, offset,
593 subSamples, numSubSamples,
594 (const uint8_t *)key, (const uint8_t *)iv,
595 (CryptoPlugin::Mode)mode,
Andreas Huberbfc56f42012-04-19 12:47:07 -0700596 timestampUs,
597 flags,
598 &errorDetailMsg);
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700599 }
600
601 if (iv != NULL) {
602 env->ReleaseByteArrayElements(ivObj, iv, 0);
603 iv = NULL;
604 }
605
606 if (key != NULL) {
607 env->ReleaseByteArrayElements(keyObj, key, 0);
608 key = NULL;
609 }
610
611 delete[] subSamples;
612 subSamples = NULL;
613
Andreas Huberbfc56f42012-04-19 12:47:07 -0700614 throwExceptionAsNecessary(
615 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700616}
617
Andreas Huber88572f72012-02-21 11:47:18 -0800618static jint android_media_MediaCodec_dequeueInputBuffer(
619 JNIEnv *env, jobject thiz, jlong timeoutUs) {
620 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
621
622 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
623
624 if (codec == NULL) {
625 jniThrowException(env, "java/lang/IllegalStateException", NULL);
626 return -1;
627 }
628
629 size_t index;
630 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
631
632 if (err == OK) {
633 return index;
634 }
635
636 return throwExceptionAsNecessary(env, err);
637}
638
639static jint android_media_MediaCodec_dequeueOutputBuffer(
640 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
641 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
642
643 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
644
645 if (codec == NULL) {
646 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Andreas Huber0e97fc22012-04-03 13:32:16 -0700647 return 0;
Andreas Huber88572f72012-02-21 11:47:18 -0800648 }
649
650 size_t index;
651 status_t err = codec->dequeueOutputBuffer(
652 env, bufferInfo, &index, timeoutUs);
653
654 if (err == OK) {
655 return index;
656 }
657
658 return throwExceptionAsNecessary(env, err);
659}
660
661static void android_media_MediaCodec_releaseOutputBuffer(
662 JNIEnv *env, jobject thiz, jint index, jboolean render) {
663 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
664
665 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
666
667 if (codec == NULL) {
668 jniThrowException(env, "java/lang/IllegalStateException", NULL);
669 return;
670 }
671
672 status_t err = codec->releaseOutputBuffer(index, render);
673
674 throwExceptionAsNecessary(env, err);
675}
676
Andreas Huber60d610b2012-05-02 16:06:09 -0700677static jobject android_media_MediaCodec_getOutputFormatNative(
Andreas Huber88572f72012-02-21 11:47:18 -0800678 JNIEnv *env, jobject thiz) {
Andreas Huber60d610b2012-05-02 16:06:09 -0700679 ALOGV("android_media_MediaCodec_getOutputFormatNative");
Andreas Huber88572f72012-02-21 11:47:18 -0800680
681 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
682
683 if (codec == NULL) {
684 jniThrowException(env, "java/lang/IllegalStateException", NULL);
685 return NULL;
686 }
687
688 jobject format;
689 status_t err = codec->getOutputFormat(env, &format);
690
691 if (err == OK) {
692 return format;
693 }
694
695 throwExceptionAsNecessary(env, err);
696
697 return NULL;
698}
699
700static jobjectArray android_media_MediaCodec_getBuffers(
701 JNIEnv *env, jobject thiz, jboolean input) {
702 ALOGV("android_media_MediaCodec_getBuffers");
703
704 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
705
706 if (codec == NULL) {
707 jniThrowException(env, "java/lang/IllegalStateException", NULL);
708 return NULL;
709 }
710
711 jobjectArray buffers;
712 status_t err = codec->getBuffers(env, input, &buffers);
713
714 if (err == OK) {
715 return buffers;
716 }
717
718 throwExceptionAsNecessary(env, err);
719
720 return NULL;
721}
722
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300723static jobject android_media_MediaCodec_getName(
724 JNIEnv *env, jobject thiz) {
725 ALOGV("android_media_MediaCodec_getName");
726
727 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
728
729 if (codec == NULL) {
730 jniThrowException(env, "java/lang/IllegalStateException", NULL);
731 return NULL;
732 }
733
734 jstring name;
735 status_t err = codec->getName(env, &name);
736
737 if (err == OK) {
738 return name;
739 }
740
741 throwExceptionAsNecessary(env, err);
742
743 return NULL;
744}
745
Andreas Huberb12a5392012-04-30 14:18:33 -0700746static void android_media_MediaCodec_setVideoScalingMode(
747 JNIEnv *env, jobject thiz, jint mode) {
748 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
749
750 if (codec == NULL) {
751 jniThrowException(env, "java/lang/IllegalStateException", NULL);
752 return;
753 }
754
755 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
756 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
757 jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
758 return;
759 }
760
761 codec->setVideoScalingMode(mode);
762}
763
Andreas Huber88572f72012-02-21 11:47:18 -0800764static void android_media_MediaCodec_native_init(JNIEnv *env) {
765 jclass clazz = env->FindClass("android/media/MediaCodec");
766 CHECK(clazz != NULL);
767
768 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
769 CHECK(gFields.context != NULL);
Andreas Huber91befdc2012-04-18 12:19:51 -0700770
771 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
772 CHECK(clazz != NULL);
773
774 gFields.cryptoInfoNumSubSamplesID =
775 env->GetFieldID(clazz, "numSubSamples", "I");
776 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
777
778 gFields.cryptoInfoNumBytesOfClearDataID =
779 env->GetFieldID(clazz, "numBytesOfClearData", "[I");
780 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
781
782 gFields.cryptoInfoNumBytesOfEncryptedDataID =
783 env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
784 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
785
786 gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
787 CHECK(gFields.cryptoInfoKeyID != NULL);
788
789 gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
790 CHECK(gFields.cryptoInfoIVID != NULL);
791
792 gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
793 CHECK(gFields.cryptoInfoModeID != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800794}
795
796static void android_media_MediaCodec_native_setup(
797 JNIEnv *env, jobject thiz,
798 jstring name, jboolean nameIsType, jboolean encoder) {
799 if (name == NULL) {
800 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
801 return;
802 }
803
804 const char *tmp = env->GetStringUTFChars(name, NULL);
805
806 if (tmp == NULL) {
807 return;
808 }
809
810 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
811
812 status_t err = codec->initCheck();
813
814 env->ReleaseStringUTFChars(name, tmp);
815 tmp = NULL;
816
817 if (err != OK) {
818 jniThrowException(
819 env,
820 "java/io/IOException",
821 "Failed to allocate component instance");
822 return;
823 }
824
825 setMediaCodec(env,thiz, codec);
826}
827
828static void android_media_MediaCodec_native_finalize(
829 JNIEnv *env, jobject thiz) {
830 android_media_MediaCodec_release(env, thiz);
831}
832
833static JNINativeMethod gMethods[] = {
834 { "release", "()V", (void *)android_media_MediaCodec_release },
835
836 { "native_configure",
Andreas Huber8240d922012-04-04 14:06:32 -0700837 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
Andreas Huber07ea4262012-04-11 12:21:20 -0700838 "Landroid/media/MediaCrypto;I)V",
Andreas Huber88572f72012-02-21 11:47:18 -0800839 (void *)android_media_MediaCodec_native_configure },
840
841 { "start", "()V", (void *)android_media_MediaCodec_start },
842 { "stop", "()V", (void *)android_media_MediaCodec_stop },
843 { "flush", "()V", (void *)android_media_MediaCodec_flush },
844
845 { "queueInputBuffer", "(IIIJI)V",
846 (void *)android_media_MediaCodec_queueInputBuffer },
847
Andreas Huber91befdc2012-04-18 12:19:51 -0700848 { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
Andreas Huber9e6bcce2012-04-06 12:14:47 -0700849 (void *)android_media_MediaCodec_queueSecureInputBuffer },
850
Andreas Huber88572f72012-02-21 11:47:18 -0800851 { "dequeueInputBuffer", "(J)I",
852 (void *)android_media_MediaCodec_dequeueInputBuffer },
853
854 { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
855 (void *)android_media_MediaCodec_dequeueOutputBuffer },
856
857 { "releaseOutputBuffer", "(IZ)V",
858 (void *)android_media_MediaCodec_releaseOutputBuffer },
859
Andreas Huber60d610b2012-05-02 16:06:09 -0700860 { "getOutputFormatNative", "()Ljava/util/Map;",
861 (void *)android_media_MediaCodec_getOutputFormatNative },
Andreas Huber88572f72012-02-21 11:47:18 -0800862
863 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
864 (void *)android_media_MediaCodec_getBuffers },
865
Martin Storsjo056ef2e2012-09-25 11:53:04 +0300866 { "getName", "()Ljava/lang/String;",
867 (void *)android_media_MediaCodec_getName },
868
Andreas Huberb12a5392012-04-30 14:18:33 -0700869 { "setVideoScalingMode", "(I)V",
870 (void *)android_media_MediaCodec_setVideoScalingMode },
871
Andreas Huber88572f72012-02-21 11:47:18 -0800872 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
873
874 { "native_setup", "(Ljava/lang/String;ZZ)V",
875 (void *)android_media_MediaCodec_native_setup },
876
877 { "native_finalize", "()V",
878 (void *)android_media_MediaCodec_native_finalize },
879};
880
881int register_android_media_MediaCodec(JNIEnv *env) {
882 return AndroidRuntime::registerNativeMethods(env,
883 "android/media/MediaCodec", gMethods, NELEM(gMethods));
884}