1 /*
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
23 #include "android_media_MediaCrypto.h"
24 #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
30 #include <cutils/compiler.h>
31
32 #include <gui/Surface.h>
33
34 #include <media/ICrypto.h>
35 #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>
40 #include <media/stagefright/foundation/AString.h>
41 #include <media/stagefright/MediaErrors.h>
42 #include <media/stagefright/PersistentSurface.h>
43 #include <nativehelper/ScopedLocalRef.h>
44
45 #include <system/window.h>
46
47 namespace android {
48
49 // Keep these in sync with their equivalents in MediaCodec.java !!!
50 enum {
51 DEQUEUE_INFO_TRY_AGAIN_LATER = -1,
52 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2,
53 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
54 };
55
56 enum {
57 EVENT_CALLBACK = 1,
58 EVENT_SET_CALLBACK = 2,
59 EVENT_FRAME_RENDERED = 3,
60 };
61
62 static struct CryptoErrorCodes {
63 jint cryptoErrorNoKey;
64 jint cryptoErrorKeyExpired;
65 jint cryptoErrorResourceBusy;
66 jint cryptoErrorInsufficientOutputProtection;
67 jint cryptoErrorSessionNotOpened;
68 } gCryptoErrorCodes;
69
70 static struct CodecActionCodes {
71 jint codecActionTransient;
72 jint codecActionRecoverable;
73 } gCodecActionCodes;
74
75 static struct CodecErrorCodes {
76 jint errorInsufficientResource;
77 jint errorReclaimed;
78 } gCodecErrorCodes;
79
80 static struct {
81 jclass clazz;
82 jfieldID mLock;
83 jfieldID mPersistentObject;
84 jmethodID ctor;
85 jmethodID setNativeObjectLocked;
86 } gPersistentSurfaceClassInfo;
87
88 struct fields_t {
89 jfieldID context;
90 jmethodID postEventFromNativeID;
91 jfieldID cryptoInfoNumSubSamplesID;
92 jfieldID cryptoInfoNumBytesOfClearDataID;
93 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
94 jfieldID cryptoInfoKeyID;
95 jfieldID cryptoInfoIVID;
96 jfieldID cryptoInfoModeID;
97 };
98
99 static fields_t gFields;
100 static const void *sRefBaseOwner;
101
102 ////////////////////////////////////////////////////////////////////////////////
103
JMediaCodec(JNIEnv * env,jobject thiz,const char * name,bool nameIsType,bool encoder)104 JMediaCodec::JMediaCodec(
105 JNIEnv *env, jobject thiz,
106 const char *name, bool nameIsType, bool encoder)
107 : mClass(NULL),
108 mObject(NULL) {
109 jclass clazz = env->GetObjectClass(thiz);
110 CHECK(clazz != NULL);
111
112 mClass = (jclass)env->NewGlobalRef(clazz);
113 mObject = env->NewWeakGlobalRef(thiz);
114
115 cacheJavaObjects(env);
116
117 mLooper = new ALooper;
118 mLooper->setName("MediaCodec_looper");
119
120 mLooper->start(
121 false, // runOnCallingThread
122 true, // canCallJava
123 PRIORITY_FOREGROUND);
124
125 if (nameIsType) {
126 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
127 } else {
128 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
129 }
130 CHECK((mCodec != NULL) != (mInitStatus != OK));
131 }
132
cacheJavaObjects(JNIEnv * env)133 void 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
initCheck() const172 status_t JMediaCodec::initCheck() const {
173 return mInitStatus;
174 }
175
registerSelf()176 void JMediaCodec::registerSelf() {
177 mLooper->registerHandler(this);
178 }
179
release()180 void JMediaCodec::release() {
181 if (mCodec != NULL) {
182 mCodec->release();
183 mCodec.clear();
184 mInitStatus = NO_INIT;
185 }
186
187 if (mLooper != NULL) {
188 mLooper->unregisterHandler(id());
189 mLooper->stop();
190 mLooper.clear();
191 }
192 }
193
~JMediaCodec()194 JMediaCodec::~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
210 JNIEnv *env = AndroidRuntime::getJNIEnv();
211
212 env->DeleteWeakGlobalRef(mObject);
213 mObject = NULL;
214 env->DeleteGlobalRef(mClass);
215 mClass = NULL;
216 deleteJavaObjects(env);
217 }
218
deleteJavaObjects(JNIEnv * env)219 void 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;
229 }
230
enableOnFrameRenderedListener(jboolean enable)231 status_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
setCallback(jobject cb)243 status_t JMediaCodec::setCallback(jobject cb) {
244 if (cb != NULL) {
245 if (mCallbackNotification == NULL) {
246 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
247 }
248 } else {
249 mCallbackNotification.clear();
250 }
251
252 return mCodec->setCallback(mCallbackNotification);
253 }
254
configure(const sp<AMessage> & format,const sp<IGraphicBufferProducer> & bufferProducer,const sp<ICrypto> & crypto,int flags)255 status_t JMediaCodec::configure(
256 const sp<AMessage> &format,
257 const sp<IGraphicBufferProducer> &bufferProducer,
258 const sp<ICrypto> &crypto,
259 int flags) {
260 sp<Surface> client;
261 if (bufferProducer != NULL) {
262 mSurfaceTextureClient =
263 new Surface(bufferProducer, true /* controlledByApp */);
264 } else {
265 mSurfaceTextureClient.clear();
266 }
267
268 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
269 }
270
setSurface(const sp<IGraphicBufferProducer> & bufferProducer)271 status_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
createInputSurface(sp<IGraphicBufferProducer> * bufferProducer)284 status_t JMediaCodec::createInputSurface(
285 sp<IGraphicBufferProducer>* bufferProducer) {
286 return mCodec->createInputSurface(bufferProducer);
287 }
288
setInputSurface(const sp<PersistentSurface> & surface)289 status_t JMediaCodec::setInputSurface(
290 const sp<PersistentSurface> &surface) {
291 return mCodec->setInputSurface(surface);
292 }
293
start()294 status_t JMediaCodec::start() {
295 return mCodec->start();
296 }
297
stop()298 status_t JMediaCodec::stop() {
299 mSurfaceTextureClient.clear();
300
301 return mCodec->stop();
302 }
303
flush()304 status_t JMediaCodec::flush() {
305 return mCodec->flush();
306 }
307
reset()308 status_t JMediaCodec::reset() {
309 return mCodec->reset();
310 }
311
queueInputBuffer(size_t index,size_t offset,size_t size,int64_t timeUs,uint32_t flags,AString * errorDetailMsg)312 status_t JMediaCodec::queueInputBuffer(
313 size_t index,
314 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);
318 }
319
queueSecureInputBuffer(size_t index,size_t offset,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,const uint8_t key[16],const uint8_t iv[16],CryptoPlugin::Mode mode,int64_t presentationTimeUs,uint32_t flags,AString * errorDetailMsg)320 status_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,
329 uint32_t flags,
330 AString *errorDetailMsg) {
331 return mCodec->queueSecureInputBuffer(
332 index, offset, subSamples, numSubSamples, key, iv, mode,
333 presentationTimeUs, flags, errorDetailMsg);
334 }
335
dequeueInputBuffer(size_t * index,int64_t timeoutUs)336 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
337 return mCodec->dequeueInputBuffer(index, timeoutUs);
338 }
339
dequeueOutputBuffer(JNIEnv * env,jobject bufferInfo,size_t * index,int64_t timeoutUs)340 status_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;
345 status_t err = mCodec->dequeueOutputBuffer(
346 index, &offset, &size, &timeUs, &flags, timeoutUs);
347
348 if (err != OK) {
349 return err;
350 }
351
352 ScopedLocalRef<jclass> clazz(
353 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
354
355 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
356 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
357
358 return OK;
359 }
360
releaseOutputBuffer(size_t index,bool render,bool updatePTS,int64_t timestampNs)361 status_t JMediaCodec::releaseOutputBuffer(
362 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
363 if (updatePTS) {
364 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
365 }
366 return render
367 ? mCodec->renderOutputBufferAndRelease(index)
368 : mCodec->releaseOutputBuffer(index);
369 }
370
signalEndOfInputStream()371 status_t JMediaCodec::signalEndOfInputStream() {
372 return mCodec->signalEndOfInputStream();
373 }
374
getFormat(JNIEnv * env,bool input,jobject * format) const375 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
376 sp<AMessage> msg;
377 status_t err;
378 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
getOutputFormat(JNIEnv * env,size_t index,jobject * format) const386 status_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) {
390 return err;
391 }
392
393 return ConvertMessageToMap(env, msg, format);
394 }
395
getBuffers(JNIEnv * env,bool input,jobjectArray * bufArray) const396 status_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
409 *bufArray = (jobjectArray)env->NewObjectArray(
410 buffers.size(), mByteBufferClass, NULL);
411 if (*bufArray == NULL) {
412 return NO_MEMORY;
413 }
414
415 for (size_t i = 0; i < buffers.size(); ++i) {
416 const sp<ABuffer> &buffer = buffers.itemAt(i);
417
418 jobject byteBuffer = NULL;
419 err = createByteBufferFromABuffer(
420 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
421 if (err != OK) {
422 return err;
423 }
424 if (byteBuffer != NULL) {
425 env->SetObjectArrayElement(
426 *bufArray, i, byteBuffer);
427
428 env->DeleteLocalRef(byteBuffer);
429 byteBuffer = NULL;
430 }
431 }
432
433 return OK;
434 }
435
436 // static
createByteBufferFromABuffer(JNIEnv * env,bool readOnly,bool clearBuffer,const sp<ABuffer> & buffer,jobject * buf) const437 status_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;
472 return OK;
473 }
474
getBuffer(JNIEnv * env,bool input,size_t index,jobject * buf) const475 status_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
488 return createByteBufferFromABuffer(
489 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
490 }
491
getImage(JNIEnv * env,bool input,size_t index,jobject * buf) const492 status_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
513 sp<ABuffer> imageData;
514 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
515 return OK;
516 }
517
518 int64_t timestamp = 0;
519 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) {
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
584 return OK;
585 }
586
getName(JNIEnv * env,jstring * nameStr) const587 status_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
setParameters(const sp<AMessage> & msg)601 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
602 return mCodec->setParameters(msg);
603 }
604
setVideoScalingMode(int mode)605 void JMediaCodec::setVideoScalingMode(int mode) {
606 if (mSurfaceTextureClient != NULL) {
607 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
608 }
609 }
610
createCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg=NULL)611 static 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
617 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
618 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
636 /* 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());
649 }
650
handleCallback(const sp<AMessage> & msg)651 void 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();
656
657 switch (arg1) {
658 case MediaCodec::CB_INPUT_AVAILABLE:
659 {
660 CHECK(msg->findInt32("index", &arg2));
661 break;
662 }
663
664 case MediaCodec::CB_OUTPUT_AVAILABLE:
665 {
666 CHECK(msg->findInt32("index", &arg2));
667
668 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();
687 }
688 jniThrowException(env, "java/lang/IllegalStateException", NULL);
689 return;
690 }
691
692 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
693 break;
694 }
695
696 case MediaCodec::CB_ERROR:
697 {
698 int32_t err, actionCode;
699 CHECK(msg->findInt32("err", &err));
700 CHECK(msg->findInt32("actionCode", &actionCode));
701
702 // note that DRM errors could conceivably alias into a CodecException
703 obj = (jobject)createCodecException(env, err, actionCode);
704
705 if (obj == NULL) {
706 if (env->ExceptionCheck()) {
707 ALOGE("Could not create CodecException object.");
708 env->ExceptionClear();
709 }
710 jniThrowException(env, "java/lang/IllegalStateException", NULL);
711 return;
712 }
713
714 break;
715 }
716
717 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
718 {
719 sp<AMessage> format;
720 CHECK(msg->findMessage("format", &format));
721
722 if (OK != ConvertMessageToMap(env, format, &obj)) {
723 jniThrowException(env, "java/lang/IllegalStateException", NULL);
724 return;
725 }
726
727 break;
728 }
729
730 default:
731 TRESPASS();
732 }
733
734 env->CallVoidMethod(
735 mObject,
736 gFields.postEventFromNativeID,
737 EVENT_CALLBACK,
738 arg1,
739 arg2,
740 obj);
741
742 env->DeleteLocalRef(obj);
743 }
744
handleFrameRenderedNotification(const sp<AMessage> & msg)745 void 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
onMessageReceived(const sp<AMessage> & msg)766 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
767 switch (msg->what()) {
768 case kWhatCallbackNotify:
769 {
770 handleCallback(msg);
771 break;
772 }
773 case kWhatFrameRendered:
774 {
775 handleFrameRenderedNotification(msg);
776 break;
777 }
778 default:
779 TRESPASS();
780 }
781 }
782
783 } // namespace android
784
785 ////////////////////////////////////////////////////////////////////////////////
786
787 using namespace android;
788
setMediaCodec(JNIEnv * env,jobject thiz,const sp<JMediaCodec> & codec)789 static sp<JMediaCodec> setMediaCodec(
790 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
791 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
792 if (codec != NULL) {
793 codec->incStrong(thiz);
794 }
795 if (old != NULL) {
796 /* 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();
802 old->decStrong(thiz);
803 }
804 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
805
806 return old;
807 }
808
getMediaCodec(JNIEnv * env,jobject thiz)809 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
810 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
811 }
812
android_media_MediaCodec_release(JNIEnv * env,jobject thiz)813 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
814 setMediaCodec(env, thiz, NULL);
815 }
816
throwCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg)817 static 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
throwCryptoException(JNIEnv * env,status_t err,const char * msg)822 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
823 ScopedLocalRef<jclass> clazz(
824 env, env->FindClass("android/media/MediaCodec$CryptoException"));
825 CHECK(clazz.get() != NULL);
826
827 jmethodID constructID =
828 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
829 CHECK(constructID != NULL);
830
831 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
832
833 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
834 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;
844 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
845 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
846 break;
847 case ERROR_DRM_SESSION_NOT_OPENED:
848 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
849 break;
850 default: /* Other negative DRM error codes go out as is. */
851 break;
852 }
853
854 jthrowable exception =
855 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
856
857 env->Throw(exception);
858 }
859
throwExceptionAsNecessary(JNIEnv * env,status_t err,int32_t actionCode=ACTION_CODE_FATAL,const char * msg=NULL)860 static jint throwExceptionAsNecessary(
861 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
862 const char *msg = NULL) {
863 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
876 case INVALID_OPERATION:
877 jniThrowException(env, "java/lang/IllegalStateException", msg);
878 return 0;
879
880 case BAD_VALUE:
881 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
882 return 0;
883
884 default:
885 if (isCryptoError(err)) {
886 throwCryptoException(env, err, msg);
887 return 0;
888 }
889 throwCodecException(env, err, actionCode, msg);
890 return 0;
891 }
892 }
893
android_media_MediaCodec_native_enableOnFrameRenderedListener(JNIEnv * env,jobject thiz,jboolean enabled)894 static 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
android_media_MediaCodec_native_setCallback(JNIEnv * env,jobject thiz,jobject cb)910 static 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) {
917 throwExceptionAsNecessary(env, INVALID_OPERATION);
918 return;
919 }
920
921 status_t err = codec->setCallback(cb);
922
923 throwExceptionAsNecessary(env, err);
924 }
925
android_media_MediaCodec_native_configure(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray values,jobject jsurface,jobject jcrypto,jint flags)926 static void android_media_MediaCodec_native_configure(
927 JNIEnv *env,
928 jobject thiz,
929 jobjectArray keys, jobjectArray values,
930 jobject jsurface,
931 jobject jcrypto,
932 jint flags) {
933 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
934
935 if (codec == NULL) {
936 throwExceptionAsNecessary(env, INVALID_OPERATION);
937 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
948 sp<IGraphicBufferProducer> bufferProducer;
949 if (jsurface != NULL) {
950 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
951 if (surface != NULL) {
952 bufferProducer = surface->getIGraphicBufferProducer();
953 } else {
954 jniThrowException(
955 env,
956 "java/lang/IllegalArgumentException",
957 "The surface has been released");
958 return;
959 }
960 }
961
962 sp<ICrypto> crypto;
963 if (jcrypto != NULL) {
964 crypto = JCrypto::GetCrypto(env, jcrypto);
965 }
966
967 err = codec->configure(format, bufferProducer, crypto, flags);
968
969 throwExceptionAsNecessary(env, err);
970 }
971
android_media_MediaCodec_native_setSurface(JNIEnv * env,jobject thiz,jobject jsurface)972 static 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
android_media_MediaCodec_getPersistentInputSurface(JNIEnv * env,jobject object)1001 sp<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
android_media_MediaCodec_createPersistentInputSurface(JNIEnv * env,jclass)1018 static 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
android_media_MediaCodec_releasePersistentInputSurface(JNIEnv * env,jclass,jobject object)1072 static 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
android_media_MediaCodec_setInputSurface(JNIEnv * env,jobject thiz,jobject object)1096 static void android_media_MediaCodec_setInputSurface(
1097 JNIEnv* env, jobject thiz, jobject object) {
1098 ALOGV("android_media_MediaCodec_setInputSurface");
1099
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
1109 status_t err = codec->setInputSurface(persistentSurface);
1110 if (err != NO_ERROR) {
1111 throwExceptionAsNecessary(env, err);
1112 }
1113 }
1114
android_media_MediaCodec_createInputSurface(JNIEnv * env,jobject thiz)1115 static 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) {
1121 throwExceptionAsNecessary(env, INVALID_OPERATION);
1122 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
android_media_MediaCodec_start(JNIEnv * env,jobject thiz)1138 static 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) {
1144 throwExceptionAsNecessary(env, INVALID_OPERATION);
1145 return;
1146 }
1147
1148 status_t err = codec->start();
1149
1150 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
1151 }
1152
android_media_MediaCodec_stop(JNIEnv * env,jobject thiz)1153 static 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) {
1159 throwExceptionAsNecessary(env, INVALID_OPERATION);
1160 return;
1161 }
1162
1163 status_t err = codec->stop();
1164
1165 throwExceptionAsNecessary(env, err);
1166 }
1167
android_media_MediaCodec_reset(JNIEnv * env,jobject thiz)1168 static 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) {
1174 throwExceptionAsNecessary(env, INVALID_OPERATION);
1175 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.
1182 // 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;
1186 }
1187 throwExceptionAsNecessary(env, err);
1188 }
1189
android_media_MediaCodec_flush(JNIEnv * env,jobject thiz)1190 static 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) {
1196 throwExceptionAsNecessary(env, INVALID_OPERATION);
1197 return;
1198 }
1199
1200 status_t err = codec->flush();
1201
1202 throwExceptionAsNecessary(env, err);
1203 }
1204
android_media_MediaCodec_queueInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jint size,jlong timestampUs,jint flags)1205 static 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) {
1218 throwExceptionAsNecessary(env, INVALID_OPERATION);
1219 return;
1220 }
1221
1222 AString errorDetailMsg;
1223
1224 status_t err = codec->queueInputBuffer(
1225 index, offset, size, timestampUs, flags, &errorDetailMsg);
1226
1227 throwExceptionAsNecessary(
1228 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1229 }
1230
android_media_MediaCodec_queueSecureInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jobject cryptoInfoObj,jlong timestampUs,jint flags)1231 static void android_media_MediaCodec_queueSecureInputBuffer(
1232 JNIEnv *env,
1233 jobject thiz,
1234 jint index,
1235 jint offset,
1236 jobject cryptoInfoObj,
1237 jlong timestampUs,
1238 jint flags) {
1239 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1240
1241 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1242
1243 if (codec == NULL) {
1244 throwExceptionAsNecessary(env, INVALID_OPERATION);
1245 return;
1246 }
1247
1248 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
1267 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;
1284 // 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
1286 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1287 err = -EINVAL;
1288 } 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
1343 AString errorDetailMsg;
1344
1345 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,
1351 timestampUs,
1352 flags,
1353 &errorDetailMsg);
1354 }
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
1369 throwExceptionAsNecessary(
1370 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1371 }
1372
android_media_MediaCodec_dequeueInputBuffer(JNIEnv * env,jobject thiz,jlong timeoutUs)1373 static 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) {
1380 throwExceptionAsNecessary(env, INVALID_OPERATION);
1381 return -1;
1382 }
1383
1384 size_t index;
1385 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1386
1387 if (err == OK) {
1388 return (jint) index;
1389 }
1390
1391 return throwExceptionAsNecessary(env, err);
1392 }
1393
android_media_MediaCodec_dequeueOutputBuffer(JNIEnv * env,jobject thiz,jobject bufferInfo,jlong timeoutUs)1394 static 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) {
1401 throwExceptionAsNecessary(env, INVALID_OPERATION);
1402 return 0;
1403 }
1404
1405 size_t index;
1406 status_t err = codec->dequeueOutputBuffer(
1407 env, bufferInfo, &index, timeoutUs);
1408
1409 if (err == OK) {
1410 return (jint) index;
1411 }
1412
1413 return throwExceptionAsNecessary(env, err);
1414 }
1415
android_media_MediaCodec_releaseOutputBuffer(JNIEnv * env,jobject thiz,jint index,jboolean render,jboolean updatePTS,jlong timestampNs)1416 static void android_media_MediaCodec_releaseOutputBuffer(
1417 JNIEnv *env, jobject thiz,
1418 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
1419 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1420
1421 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1422
1423 if (codec == NULL) {
1424 throwExceptionAsNecessary(env, INVALID_OPERATION);
1425 return;
1426 }
1427
1428 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
1429
1430 throwExceptionAsNecessary(env, err);
1431 }
1432
android_media_MediaCodec_signalEndOfInputStream(JNIEnv * env,jobject thiz)1433 static 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) {
1439 throwExceptionAsNecessary(env, INVALID_OPERATION);
1440 return;
1441 }
1442
1443 status_t err = codec->signalEndOfInputStream();
1444
1445 throwExceptionAsNecessary(env, err);
1446 }
1447
android_media_MediaCodec_getFormatNative(JNIEnv * env,jobject thiz,jboolean input)1448 static jobject android_media_MediaCodec_getFormatNative(
1449 JNIEnv *env, jobject thiz, jboolean input) {
1450 ALOGV("android_media_MediaCodec_getFormatNative");
1451
1452 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1453
1454 if (codec == NULL) {
1455 throwExceptionAsNecessary(env, INVALID_OPERATION);
1456 return NULL;
1457 }
1458
1459 jobject format;
1460 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
android_media_MediaCodec_getOutputFormatForIndexNative(JNIEnv * env,jobject thiz,jint index)1471 static 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) {
1478 throwExceptionAsNecessary(env, INVALID_OPERATION);
1479 return NULL;
1480 }
1481
1482 jobject format;
1483 status_t err = codec->getOutputFormat(env, index, &format);
1484
1485 if (err == OK) {
1486 return format;
1487 }
1488
1489 throwExceptionAsNecessary(env, err);
1490
1491 return NULL;
1492 }
1493
android_media_MediaCodec_getBuffers(JNIEnv * env,jobject thiz,jboolean input)1494 static 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) {
1501 throwExceptionAsNecessary(env, INVALID_OPERATION);
1502 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
1512 // if we're out of memory, an exception was already thrown
1513 if (err != NO_MEMORY) {
1514 throwExceptionAsNecessary(env, err);
1515 }
1516
1517 return NULL;
1518 }
1519
android_media_MediaCodec_getBuffer(JNIEnv * env,jobject thiz,jboolean input,jint index)1520 static 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) {
1527 throwExceptionAsNecessary(env, INVALID_OPERATION);
1528 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
android_media_MediaCodec_getImage(JNIEnv * env,jobject thiz,jboolean input,jint index)1546 static 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) {
1553 throwExceptionAsNecessary(env, INVALID_OPERATION);
1554 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
android_media_MediaCodec_getName(JNIEnv * env,jobject thiz)1572 static 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) {
1579 throwExceptionAsNecessary(env, INVALID_OPERATION);
1580 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
android_media_MediaCodec_setParameters(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray vals)1595 static 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) {
1602 throwExceptionAsNecessary(env, INVALID_OPERATION);
1603 return;
1604 }
1605
1606 sp<AMessage> params;
1607 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms);
1608
1609 if (err == OK) {
1610 err = codec->setParameters(params);
1611 }
1612
1613 throwExceptionAsNecessary(env, err);
1614 }
1615
android_media_MediaCodec_setVideoScalingMode(JNIEnv * env,jobject thiz,jint mode)1616 static void android_media_MediaCodec_setVideoScalingMode(
1617 JNIEnv *env, jobject thiz, jint mode) {
1618 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1619
1620 if (codec == NULL) {
1621 throwExceptionAsNecessary(env, INVALID_OPERATION);
1622 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
android_media_MediaCodec_native_init(JNIEnv * env)1634 static void android_media_MediaCodec_native_init(JNIEnv *env) {
1635 ScopedLocalRef<jclass> clazz(
1636 env, env->FindClass("android/media/MediaCodec"));
1637 CHECK(clazz.get() != NULL);
1638
1639 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
1640 CHECK(gFields.context != NULL);
1641
1642 gFields.postEventFromNativeID =
1643 env->GetMethodID(
1644 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1645
1646 CHECK(gFields.postEventFromNativeID != NULL);
1647
1648 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1649 CHECK(clazz.get() != NULL);
1650
1651 gFields.cryptoInfoNumSubSamplesID =
1652 env->GetFieldID(clazz.get(), "numSubSamples", "I");
1653 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1654
1655 gFields.cryptoInfoNumBytesOfClearDataID =
1656 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
1657 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1658
1659 gFields.cryptoInfoNumBytesOfEncryptedDataID =
1660 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
1661 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1662
1663 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
1664 CHECK(gFields.cryptoInfoKeyID != NULL);
1665
1666 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
1667 CHECK(gFields.cryptoInfoIVID != NULL);
1668
1669 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
1670 CHECK(gFields.cryptoInfoModeID != NULL);
1671
1672 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1673 CHECK(clazz.get() != NULL);
1674
1675 jfieldID field;
1676 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
1677 CHECK(field != NULL);
1678 gCryptoErrorCodes.cryptoErrorNoKey =
1679 env->GetStaticIntField(clazz.get(), field);
1680
1681 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
1682 CHECK(field != NULL);
1683 gCryptoErrorCodes.cryptoErrorKeyExpired =
1684 env->GetStaticIntField(clazz.get(), field);
1685
1686 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
1687 CHECK(field != NULL);
1688 gCryptoErrorCodes.cryptoErrorResourceBusy =
1689 env->GetStaticIntField(clazz.get(), field);
1690
1691 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1692 CHECK(field != NULL);
1693 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1694 env->GetStaticIntField(clazz.get(), field);
1695
1696 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1697 CHECK(field != NULL);
1698 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1699 env->GetStaticIntField(clazz.get(), field);
1700
1701 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);
1712
1713 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
1714 CHECK(field != NULL);
1715 gCodecErrorCodes.errorInsufficientResource =
1716 env->GetStaticIntField(clazz.get(), field);
1717
1718 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
1719 CHECK(field != NULL);
1720 gCodecErrorCodes.errorReclaimed =
1721 env->GetStaticIntField(clazz.get(), field);
1722
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;
1745 }
1746
android_media_MediaCodec_native_setup(JNIEnv * env,jobject thiz,jstring name,jboolean nameIsType,jboolean encoder)1747 static void android_media_MediaCodec_native_setup(
1748 JNIEnv *env, jobject thiz,
1749 jstring name, jboolean nameIsType, jboolean encoder) {
1750 if (name == NULL) {
1751 jniThrowException(env, "java/lang/NullPointerException", NULL);
1752 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
1763 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;
1770 } 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;
1775 } 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);
1780 return;
1781 }
1782
1783 env->ReleaseStringUTFChars(name, tmp);
1784
1785 codec->registerSelf();
1786
1787 setMediaCodec(env,thiz, codec);
1788 }
1789
android_media_MediaCodec_native_finalize(JNIEnv * env,jobject thiz)1790 static void android_media_MediaCodec_native_finalize(
1791 JNIEnv *env, jobject thiz) {
1792 android_media_MediaCodec_release(env, thiz);
1793 }
1794
1795 static JNINativeMethod gMethods[] = {
1796 { "native_release", "()V", (void *)android_media_MediaCodec_release },
1797
1798 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1799
1800 { "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
1808 { "native_setInputSurface", "(Landroid/view/Surface;)V",
1809 (void *)android_media_MediaCodec_setInputSurface },
1810
1811 { "native_enableOnFrameRenderedListener", "(Z)V",
1812 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
1813
1814 { "native_setCallback",
1815 "(Landroid/media/MediaCodec$Callback;)V",
1816 (void *)android_media_MediaCodec_native_setCallback },
1817
1818 { "native_configure",
1819 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
1820 "Landroid/media/MediaCrypto;I)V",
1821 (void *)android_media_MediaCodec_native_configure },
1822
1823 { "native_setSurface",
1824 "(Landroid/view/Surface;)V",
1825 (void *)android_media_MediaCodec_native_setSurface },
1826
1827 { "createInputSurface", "()Landroid/view/Surface;",
1828 (void *)android_media_MediaCodec_createInputSurface },
1829
1830 { "native_start", "()V", (void *)android_media_MediaCodec_start },
1831 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
1832 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
1833
1834 { "native_queueInputBuffer", "(IIIJI)V",
1835 (void *)android_media_MediaCodec_queueInputBuffer },
1836
1837 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
1838 (void *)android_media_MediaCodec_queueSecureInputBuffer },
1839
1840 { "native_dequeueInputBuffer", "(J)I",
1841 (void *)android_media_MediaCodec_dequeueInputBuffer },
1842
1843 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
1844 (void *)android_media_MediaCodec_dequeueOutputBuffer },
1845
1846 { "releaseOutputBuffer", "(IZZJ)V",
1847 (void *)android_media_MediaCodec_releaseOutputBuffer },
1848
1849 { "signalEndOfInputStream", "()V",
1850 (void *)android_media_MediaCodec_signalEndOfInputStream },
1851
1852 { "getFormatNative", "(Z)Ljava/util/Map;",
1853 (void *)android_media_MediaCodec_getFormatNative },
1854
1855 { "getOutputFormatNative", "(I)Ljava/util/Map;",
1856 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
1857
1858 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1859 (void *)android_media_MediaCodec_getBuffers },
1860
1861 { "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
1867 { "getName", "()Ljava/lang/String;",
1868 (void *)android_media_MediaCodec_getName },
1869
1870 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
1871 (void *)android_media_MediaCodec_setParameters },
1872
1873 { "setVideoScalingMode", "(I)V",
1874 (void *)android_media_MediaCodec_setVideoScalingMode },
1875
1876 { "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
register_android_media_MediaCodec(JNIEnv * env)1885 int register_android_media_MediaCodec(JNIEnv *env) {
1886 return AndroidRuntime::registerNativeMethods(env,
1887 "android/media/MediaCodec", gMethods, NELEM(gMethods));
1888 }
1889