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 jint cryptoErrorUnsupportedOperation;
69 } gCryptoErrorCodes;
70
71 static struct CodecActionCodes {
72 jint codecActionTransient;
73 jint codecActionRecoverable;
74 } gCodecActionCodes;
75
76 static struct CodecErrorCodes {
77 jint errorInsufficientResource;
78 jint errorReclaimed;
79 } gCodecErrorCodes;
80
81 static struct {
82 jclass clazz;
83 jfieldID mLock;
84 jfieldID mPersistentObject;
85 jmethodID ctor;
86 jmethodID setNativeObjectLocked;
87 } gPersistentSurfaceClassInfo;
88
89 static struct {
90 jint Unencrypted;
91 jint AesCtr;
92 jint AesCbc;
93 } gCryptoModes;
94
95
96 struct fields_t {
97 jfieldID context;
98 jmethodID postEventFromNativeID;
99 jfieldID cryptoInfoNumSubSamplesID;
100 jfieldID cryptoInfoNumBytesOfClearDataID;
101 jfieldID cryptoInfoNumBytesOfEncryptedDataID;
102 jfieldID cryptoInfoKeyID;
103 jfieldID cryptoInfoIVID;
104 jfieldID cryptoInfoModeID;
105 jfieldID cryptoInfoPatternID;
106 jfieldID patternEncryptBlocksID;
107 jfieldID patternSkipBlocksID;
108 };
109
110 static fields_t gFields;
111 static const void *sRefBaseOwner;
112
113 ////////////////////////////////////////////////////////////////////////////////
114
JMediaCodec(JNIEnv * env,jobject thiz,const char * name,bool nameIsType,bool encoder)115 JMediaCodec::JMediaCodec(
116 JNIEnv *env, jobject thiz,
117 const char *name, bool nameIsType, bool encoder)
118 : mClass(NULL),
119 mObject(NULL) {
120 jclass clazz = env->GetObjectClass(thiz);
121 CHECK(clazz != NULL);
122
123 mClass = (jclass)env->NewGlobalRef(clazz);
124 mObject = env->NewWeakGlobalRef(thiz);
125
126 cacheJavaObjects(env);
127
128 mLooper = new ALooper;
129 mLooper->setName("MediaCodec_looper");
130
131 mLooper->start(
132 false, // runOnCallingThread
133 true, // canCallJava
134 PRIORITY_FOREGROUND);
135
136 if (nameIsType) {
137 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
138 } else {
139 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
140 }
141 CHECK((mCodec != NULL) != (mInitStatus != OK));
142 }
143
cacheJavaObjects(JNIEnv * env)144 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
145 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer");
146 mByteBufferClass = (jclass)env->NewGlobalRef(clazz);
147 CHECK(mByteBufferClass != NULL);
148
149 ScopedLocalRef<jclass> byteOrderClass(
150 env, env->FindClass("java/nio/ByteOrder"));
151 CHECK(byteOrderClass.get() != NULL);
152
153 jmethodID nativeOrderID = env->GetStaticMethodID(
154 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;");
155 CHECK(nativeOrderID != NULL);
156
157 jobject nativeByteOrderObj =
158 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID);
159 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj);
160 CHECK(mNativeByteOrderObj != NULL);
161 env->DeleteLocalRef(nativeByteOrderObj);
162 nativeByteOrderObj = NULL;
163
164 mByteBufferOrderMethodID = env->GetMethodID(
165 mByteBufferClass,
166 "order",
167 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
168 CHECK(mByteBufferOrderMethodID != NULL);
169
170 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID(
171 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
172 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL);
173
174 mByteBufferPositionMethodID = env->GetMethodID(
175 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;");
176 CHECK(mByteBufferPositionMethodID != NULL);
177
178 mByteBufferLimitMethodID = env->GetMethodID(
179 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;");
180 CHECK(mByteBufferLimitMethodID != NULL);
181 }
182
initCheck() const183 status_t JMediaCodec::initCheck() const {
184 return mInitStatus;
185 }
186
registerSelf()187 void JMediaCodec::registerSelf() {
188 mLooper->registerHandler(this);
189 }
190
release()191 void JMediaCodec::release() {
192 if (mCodec != NULL) {
193 mCodec->release();
194 mCodec.clear();
195 mInitStatus = NO_INIT;
196 }
197
198 if (mLooper != NULL) {
199 mLooper->unregisterHandler(id());
200 mLooper->stop();
201 mLooper.clear();
202 }
203 }
204
~JMediaCodec()205 JMediaCodec::~JMediaCodec() {
206 if (mCodec != NULL || mLooper != NULL) {
207 /* MediaCodec and looper should have been released explicitly already
208 * in setMediaCodec() (see comments in setMediaCodec()).
209 *
210 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the
211 * message handler, doing release() there risks deadlock as MediaCodec::
212 * release() post synchronous message to the same looper.
213 *
214 * Print a warning and try to proceed with releasing.
215 */
216 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()...");
217 release();
218 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec().");
219 }
220
221 JNIEnv *env = AndroidRuntime::getJNIEnv();
222
223 env->DeleteWeakGlobalRef(mObject);
224 mObject = NULL;
225 env->DeleteGlobalRef(mClass);
226 mClass = NULL;
227 deleteJavaObjects(env);
228 }
229
deleteJavaObjects(JNIEnv * env)230 void JMediaCodec::deleteJavaObjects(JNIEnv *env) {
231 env->DeleteGlobalRef(mByteBufferClass);
232 mByteBufferClass = NULL;
233 env->DeleteGlobalRef(mNativeByteOrderObj);
234 mNativeByteOrderObj = NULL;
235
236 mByteBufferOrderMethodID = NULL;
237 mByteBufferAsReadOnlyBufferMethodID = NULL;
238 mByteBufferPositionMethodID = NULL;
239 mByteBufferLimitMethodID = NULL;
240 }
241
enableOnFrameRenderedListener(jboolean enable)242 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
243 if (enable) {
244 if (mOnFrameRenderedNotification == NULL) {
245 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
246 }
247 } else {
248 mOnFrameRenderedNotification.clear();
249 }
250
251 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
252 }
253
setCallback(jobject cb)254 status_t JMediaCodec::setCallback(jobject cb) {
255 if (cb != NULL) {
256 if (mCallbackNotification == NULL) {
257 mCallbackNotification = new AMessage(kWhatCallbackNotify, this);
258 }
259 } else {
260 mCallbackNotification.clear();
261 }
262
263 return mCodec->setCallback(mCallbackNotification);
264 }
265
configure(const sp<AMessage> & format,const sp<IGraphicBufferProducer> & bufferProducer,const sp<ICrypto> & crypto,int flags)266 status_t JMediaCodec::configure(
267 const sp<AMessage> &format,
268 const sp<IGraphicBufferProducer> &bufferProducer,
269 const sp<ICrypto> &crypto,
270 int flags) {
271 sp<Surface> client;
272 if (bufferProducer != NULL) {
273 mSurfaceTextureClient =
274 new Surface(bufferProducer, true /* controlledByApp */);
275 } else {
276 mSurfaceTextureClient.clear();
277 }
278
279 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
280 }
281
setSurface(const sp<IGraphicBufferProducer> & bufferProducer)282 status_t JMediaCodec::setSurface(
283 const sp<IGraphicBufferProducer> &bufferProducer) {
284 sp<Surface> client;
285 if (bufferProducer != NULL) {
286 client = new Surface(bufferProducer, true /* controlledByApp */);
287 }
288 status_t err = mCodec->setSurface(client);
289 if (err == OK) {
290 mSurfaceTextureClient = client;
291 }
292 return err;
293 }
294
createInputSurface(sp<IGraphicBufferProducer> * bufferProducer)295 status_t JMediaCodec::createInputSurface(
296 sp<IGraphicBufferProducer>* bufferProducer) {
297 return mCodec->createInputSurface(bufferProducer);
298 }
299
setInputSurface(const sp<PersistentSurface> & surface)300 status_t JMediaCodec::setInputSurface(
301 const sp<PersistentSurface> &surface) {
302 return mCodec->setInputSurface(surface);
303 }
304
start()305 status_t JMediaCodec::start() {
306 return mCodec->start();
307 }
308
stop()309 status_t JMediaCodec::stop() {
310 mSurfaceTextureClient.clear();
311
312 return mCodec->stop();
313 }
314
flush()315 status_t JMediaCodec::flush() {
316 return mCodec->flush();
317 }
318
reset()319 status_t JMediaCodec::reset() {
320 return mCodec->reset();
321 }
322
queueInputBuffer(size_t index,size_t offset,size_t size,int64_t timeUs,uint32_t flags,AString * errorDetailMsg)323 status_t JMediaCodec::queueInputBuffer(
324 size_t index,
325 size_t offset, size_t size, int64_t timeUs, uint32_t flags,
326 AString *errorDetailMsg) {
327 return mCodec->queueInputBuffer(
328 index, offset, size, timeUs, flags, errorDetailMsg);
329 }
330
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,const CryptoPlugin::Pattern & pattern,int64_t presentationTimeUs,uint32_t flags,AString * errorDetailMsg)331 status_t JMediaCodec::queueSecureInputBuffer(
332 size_t index,
333 size_t offset,
334 const CryptoPlugin::SubSample *subSamples,
335 size_t numSubSamples,
336 const uint8_t key[16],
337 const uint8_t iv[16],
338 CryptoPlugin::Mode mode,
339 const CryptoPlugin::Pattern &pattern,
340 int64_t presentationTimeUs,
341 uint32_t flags,
342 AString *errorDetailMsg) {
343 return mCodec->queueSecureInputBuffer(
344 index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
345 presentationTimeUs, flags, errorDetailMsg);
346 }
347
dequeueInputBuffer(size_t * index,int64_t timeoutUs)348 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
349 return mCodec->dequeueInputBuffer(index, timeoutUs);
350 }
351
dequeueOutputBuffer(JNIEnv * env,jobject bufferInfo,size_t * index,int64_t timeoutUs)352 status_t JMediaCodec::dequeueOutputBuffer(
353 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) {
354 size_t size, offset;
355 int64_t timeUs;
356 uint32_t flags;
357 status_t err = mCodec->dequeueOutputBuffer(
358 index, &offset, &size, &timeUs, &flags, timeoutUs);
359
360 if (err != OK) {
361 return err;
362 }
363
364 ScopedLocalRef<jclass> clazz(
365 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
366
367 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
368 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
369
370 return OK;
371 }
372
releaseOutputBuffer(size_t index,bool render,bool updatePTS,int64_t timestampNs)373 status_t JMediaCodec::releaseOutputBuffer(
374 size_t index, bool render, bool updatePTS, int64_t timestampNs) {
375 if (updatePTS) {
376 return mCodec->renderOutputBufferAndRelease(index, timestampNs);
377 }
378 return render
379 ? mCodec->renderOutputBufferAndRelease(index)
380 : mCodec->releaseOutputBuffer(index);
381 }
382
signalEndOfInputStream()383 status_t JMediaCodec::signalEndOfInputStream() {
384 return mCodec->signalEndOfInputStream();
385 }
386
getFormat(JNIEnv * env,bool input,jobject * format) const387 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const {
388 sp<AMessage> msg;
389 status_t err;
390 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg);
391 if (err != OK) {
392 return err;
393 }
394
395 return ConvertMessageToMap(env, msg, format);
396 }
397
getOutputFormat(JNIEnv * env,size_t index,jobject * format) const398 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const {
399 sp<AMessage> msg;
400 status_t err;
401 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) {
402 return err;
403 }
404
405 return ConvertMessageToMap(env, msg, format);
406 }
407
getBuffers(JNIEnv * env,bool input,jobjectArray * bufArray) const408 status_t JMediaCodec::getBuffers(
409 JNIEnv *env, bool input, jobjectArray *bufArray) const {
410 Vector<sp<ABuffer> > buffers;
411
412 status_t err =
413 input
414 ? mCodec->getInputBuffers(&buffers)
415 : mCodec->getOutputBuffers(&buffers);
416
417 if (err != OK) {
418 return err;
419 }
420
421 *bufArray = (jobjectArray)env->NewObjectArray(
422 buffers.size(), mByteBufferClass, NULL);
423 if (*bufArray == NULL) {
424 return NO_MEMORY;
425 }
426
427 for (size_t i = 0; i < buffers.size(); ++i) {
428 const sp<ABuffer> &buffer = buffers.itemAt(i);
429
430 jobject byteBuffer = NULL;
431 err = createByteBufferFromABuffer(
432 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer);
433 if (err != OK) {
434 return err;
435 }
436 if (byteBuffer != NULL) {
437 env->SetObjectArrayElement(
438 *bufArray, i, byteBuffer);
439
440 env->DeleteLocalRef(byteBuffer);
441 byteBuffer = NULL;
442 }
443 }
444
445 return OK;
446 }
447
448 // static
createByteBufferFromABuffer(JNIEnv * env,bool readOnly,bool clearBuffer,const sp<ABuffer> & buffer,jobject * buf) const449 status_t JMediaCodec::createByteBufferFromABuffer(
450 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
451 jobject *buf) const {
452 // if this is an ABuffer that doesn't actually hold any accessible memory,
453 // use a null ByteBuffer
454 *buf = NULL;
455
456 if (buffer == NULL) {
457 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL");
458 return OK;
459 }
460
461 if (buffer->base() == NULL) {
462 return OK;
463 }
464
465 jobject byteBuffer =
466 env->NewDirectByteBuffer(buffer->base(), buffer->capacity());
467 if (readOnly && byteBuffer != NULL) {
468 jobject readOnlyBuffer = env->CallObjectMethod(
469 byteBuffer, mByteBufferAsReadOnlyBufferMethodID);
470 env->DeleteLocalRef(byteBuffer);
471 byteBuffer = readOnlyBuffer;
472 }
473 if (byteBuffer == NULL) {
474 return NO_MEMORY;
475 }
476 jobject me = env->CallObjectMethod(
477 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj);
478 env->DeleteLocalRef(me);
479 me = env->CallObjectMethod(
480 byteBuffer, mByteBufferLimitMethodID,
481 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size()));
482 env->DeleteLocalRef(me);
483 me = env->CallObjectMethod(
484 byteBuffer, mByteBufferPositionMethodID,
485 clearBuffer ? 0 : buffer->offset());
486 env->DeleteLocalRef(me);
487 me = NULL;
488
489 *buf = byteBuffer;
490 return OK;
491 }
492
getBuffer(JNIEnv * env,bool input,size_t index,jobject * buf) const493 status_t JMediaCodec::getBuffer(
494 JNIEnv *env, bool input, size_t index, jobject *buf) const {
495 sp<ABuffer> buffer;
496
497 status_t err =
498 input
499 ? mCodec->getInputBuffer(index, &buffer)
500 : mCodec->getOutputBuffer(index, &buffer);
501
502 if (err != OK) {
503 return err;
504 }
505
506 return createByteBufferFromABuffer(
507 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
508 }
509
getImage(JNIEnv * env,bool input,size_t index,jobject * buf) const510 status_t JMediaCodec::getImage(
511 JNIEnv *env, bool input, size_t index, jobject *buf) const {
512 sp<ABuffer> buffer;
513
514 status_t err =
515 input
516 ? mCodec->getInputBuffer(index, &buffer)
517 : mCodec->getOutputBuffer(index, &buffer);
518
519 if (err != OK) {
520 return err;
521 }
522
523 // if this is an ABuffer that doesn't actually hold any accessible memory,
524 // use a null ByteBuffer
525 *buf = NULL;
526 if (buffer->base() == NULL) {
527 return OK;
528 }
529
530 // check if buffer is an image
531 sp<ABuffer> imageData;
532 if (!buffer->meta()->findBuffer("image-data", &imageData)) {
533 return OK;
534 }
535
536 int64_t timestamp = 0;
537 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) {
538 timestamp *= 1000; // adjust to ns
539 }
540
541 jobject byteBuffer = NULL;
542 err = createByteBufferFromABuffer(
543 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer);
544 if (err != OK) {
545 return OK;
546 }
547
548 jobject infoBuffer = NULL;
549 err = createByteBufferFromABuffer(
550 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer);
551 if (err != OK) {
552 env->DeleteLocalRef(byteBuffer);
553 byteBuffer = NULL;
554 return OK;
555 }
556
557 jobject cropRect = NULL;
558 int32_t left, top, right, bottom;
559 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) {
560 ScopedLocalRef<jclass> rectClazz(
561 env, env->FindClass("android/graphics/Rect"));
562 CHECK(rectClazz.get() != NULL);
563
564 jmethodID rectConstructID = env->GetMethodID(
565 rectClazz.get(), "<init>", "(IIII)V");
566
567 cropRect = env->NewObject(
568 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1);
569 }
570
571 ScopedLocalRef<jclass> imageClazz(
572 env, env->FindClass("android/media/MediaCodec$MediaImage"));
573 CHECK(imageClazz.get() != NULL);
574
575 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>",
576 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V");
577
578 *buf = env->NewObject(imageClazz.get(), imageConstructID,
579 byteBuffer, infoBuffer,
580 (jboolean)!input /* readOnly */,
581 (jlong)timestamp,
582 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect);
583
584 // if MediaImage creation fails, return null
585 if (env->ExceptionCheck()) {
586 env->ExceptionDescribe();
587 env->ExceptionClear();
588 *buf = NULL;
589 }
590
591 if (cropRect != NULL) {
592 env->DeleteLocalRef(cropRect);
593 cropRect = NULL;
594 }
595
596 env->DeleteLocalRef(byteBuffer);
597 byteBuffer = NULL;
598
599 env->DeleteLocalRef(infoBuffer);
600 infoBuffer = NULL;
601
602 return OK;
603 }
604
getName(JNIEnv * env,jstring * nameStr) const605 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const {
606 AString name;
607
608 status_t err = mCodec->getName(&name);
609
610 if (err != OK) {
611 return err;
612 }
613
614 *nameStr = env->NewStringUTF(name.c_str());
615
616 return OK;
617 }
618
setParameters(const sp<AMessage> & msg)619 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
620 return mCodec->setParameters(msg);
621 }
622
setVideoScalingMode(int mode)623 void JMediaCodec::setVideoScalingMode(int mode) {
624 if (mSurfaceTextureClient != NULL) {
625 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
626 }
627 }
628
createCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg=NULL)629 static jthrowable createCodecException(
630 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
631 ScopedLocalRef<jclass> clazz(
632 env, env->FindClass("android/media/MediaCodec$CodecException"));
633 CHECK(clazz.get() != NULL);
634
635 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
636 CHECK(ctor != NULL);
637
638 ScopedLocalRef<jstring> msgObj(
639 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
640
641 // translate action code to Java equivalent
642 switch (actionCode) {
643 case ACTION_CODE_TRANSIENT:
644 actionCode = gCodecActionCodes.codecActionTransient;
645 break;
646 case ACTION_CODE_RECOVERABLE:
647 actionCode = gCodecActionCodes.codecActionRecoverable;
648 break;
649 default:
650 actionCode = 0; // everything else is fatal
651 break;
652 }
653
654 /* translate OS errors to Java API CodecException errorCodes */
655 switch (err) {
656 case NO_MEMORY:
657 err = gCodecErrorCodes.errorInsufficientResource;
658 break;
659 case DEAD_OBJECT:
660 err = gCodecErrorCodes.errorReclaimed;
661 break;
662 default: /* Other error codes go out as is. */
663 break;
664 }
665
666 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
667 }
668
handleCallback(const sp<AMessage> & msg)669 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
670 int32_t arg1, arg2 = 0;
671 jobject obj = NULL;
672 CHECK(msg->findInt32("callbackID", &arg1));
673 JNIEnv *env = AndroidRuntime::getJNIEnv();
674
675 switch (arg1) {
676 case MediaCodec::CB_INPUT_AVAILABLE:
677 {
678 CHECK(msg->findInt32("index", &arg2));
679 break;
680 }
681
682 case MediaCodec::CB_OUTPUT_AVAILABLE:
683 {
684 CHECK(msg->findInt32("index", &arg2));
685
686 size_t size, offset;
687 int64_t timeUs;
688 uint32_t flags;
689 CHECK(msg->findSize("size", &size));
690 CHECK(msg->findSize("offset", &offset));
691 CHECK(msg->findInt64("timeUs", &timeUs));
692 CHECK(msg->findInt32("flags", (int32_t *)&flags));
693
694 ScopedLocalRef<jclass> clazz(
695 env, env->FindClass("android/media/MediaCodec$BufferInfo"));
696 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
697 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
698
699 obj = env->NewObject(clazz.get(), ctor);
700
701 if (obj == NULL) {
702 if (env->ExceptionCheck()) {
703 ALOGE("Could not create MediaCodec.BufferInfo.");
704 env->ExceptionClear();
705 }
706 jniThrowException(env, "java/lang/IllegalStateException", NULL);
707 return;
708 }
709
710 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
711 break;
712 }
713
714 case MediaCodec::CB_ERROR:
715 {
716 int32_t err, actionCode;
717 CHECK(msg->findInt32("err", &err));
718 CHECK(msg->findInt32("actionCode", &actionCode));
719
720 // note that DRM errors could conceivably alias into a CodecException
721 obj = (jobject)createCodecException(env, err, actionCode);
722
723 if (obj == NULL) {
724 if (env->ExceptionCheck()) {
725 ALOGE("Could not create CodecException object.");
726 env->ExceptionClear();
727 }
728 jniThrowException(env, "java/lang/IllegalStateException", NULL);
729 return;
730 }
731
732 break;
733 }
734
735 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
736 {
737 sp<AMessage> format;
738 CHECK(msg->findMessage("format", &format));
739
740 if (OK != ConvertMessageToMap(env, format, &obj)) {
741 jniThrowException(env, "java/lang/IllegalStateException", NULL);
742 return;
743 }
744
745 break;
746 }
747
748 default:
749 TRESPASS();
750 }
751
752 env->CallVoidMethod(
753 mObject,
754 gFields.postEventFromNativeID,
755 EVENT_CALLBACK,
756 arg1,
757 arg2,
758 obj);
759
760 env->DeleteLocalRef(obj);
761 }
762
handleFrameRenderedNotification(const sp<AMessage> & msg)763 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
764 int32_t arg1 = 0, arg2 = 0;
765 jobject obj = NULL;
766 JNIEnv *env = AndroidRuntime::getJNIEnv();
767
768 sp<AMessage> data;
769 CHECK(msg->findMessage("data", &data));
770
771 status_t err = ConvertMessageToMap(env, data, &obj);
772 if (err != OK) {
773 jniThrowException(env, "java/lang/IllegalStateException", NULL);
774 return;
775 }
776
777 env->CallVoidMethod(
778 mObject, gFields.postEventFromNativeID,
779 EVENT_FRAME_RENDERED, arg1, arg2, obj);
780
781 env->DeleteLocalRef(obj);
782 }
783
onMessageReceived(const sp<AMessage> & msg)784 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
785 switch (msg->what()) {
786 case kWhatCallbackNotify:
787 {
788 handleCallback(msg);
789 break;
790 }
791 case kWhatFrameRendered:
792 {
793 handleFrameRenderedNotification(msg);
794 break;
795 }
796 default:
797 TRESPASS();
798 }
799 }
800
801 } // namespace android
802
803 ////////////////////////////////////////////////////////////////////////////////
804
805 using namespace android;
806
setMediaCodec(JNIEnv * env,jobject thiz,const sp<JMediaCodec> & codec)807 static sp<JMediaCodec> setMediaCodec(
808 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) {
809 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context);
810 if (codec != NULL) {
811 codec->incStrong(thiz);
812 }
813 if (old != NULL) {
814 /* release MediaCodec and stop the looper now before decStrong.
815 * otherwise JMediaCodec::~JMediaCodec() could be called from within
816 * its message handler, doing release() from there will deadlock
817 * (as MediaCodec::release() post synchronous message to the same looper)
818 */
819 old->release();
820 old->decStrong(thiz);
821 }
822 env->SetLongField(thiz, gFields.context, (jlong)codec.get());
823
824 return old;
825 }
826
getMediaCodec(JNIEnv * env,jobject thiz)827 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) {
828 return (JMediaCodec *)env->GetLongField(thiz, gFields.context);
829 }
830
android_media_MediaCodec_release(JNIEnv * env,jobject thiz)831 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
832 setMediaCodec(env, thiz, NULL);
833 }
834
throwCodecException(JNIEnv * env,status_t err,int32_t actionCode,const char * msg)835 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
836 jthrowable exception = createCodecException(env, err, actionCode, msg);
837 env->Throw(exception);
838 }
839
throwCryptoException(JNIEnv * env,status_t err,const char * msg)840 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
841 ScopedLocalRef<jclass> clazz(
842 env, env->FindClass("android/media/MediaCodec$CryptoException"));
843 CHECK(clazz.get() != NULL);
844
845 jmethodID constructID =
846 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
847 CHECK(constructID != NULL);
848
849 const char *defaultMsg = "Unknown Error";
850
851 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
852 switch (err) {
853 case ERROR_DRM_NO_LICENSE:
854 err = gCryptoErrorCodes.cryptoErrorNoKey;
855 defaultMsg = "Crypto key not available";
856 break;
857 case ERROR_DRM_LICENSE_EXPIRED:
858 err = gCryptoErrorCodes.cryptoErrorKeyExpired;
859 defaultMsg = "License expired";
860 break;
861 case ERROR_DRM_RESOURCE_BUSY:
862 err = gCryptoErrorCodes.cryptoErrorResourceBusy;
863 defaultMsg = "Resource busy or unavailable";
864 break;
865 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
866 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
867 defaultMsg = "Required output protections are not active";
868 break;
869 case ERROR_DRM_SESSION_NOT_OPENED:
870 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
871 defaultMsg = "Attempted to use a closed session";
872 break;
873 case ERROR_DRM_CANNOT_HANDLE:
874 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
875 defaultMsg = "Operation not supported in this configuration";
876 break;
877 default: /* Other negative DRM error codes go out as is. */
878 break;
879 }
880
881 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg);
882
883 jthrowable exception =
884 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj);
885
886 env->Throw(exception);
887 }
888
throwExceptionAsNecessary(JNIEnv * env,status_t err,int32_t actionCode=ACTION_CODE_FATAL,const char * msg=NULL)889 static jint throwExceptionAsNecessary(
890 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
891 const char *msg = NULL) {
892 switch (err) {
893 case OK:
894 return 0;
895
896 case -EAGAIN:
897 return DEQUEUE_INFO_TRY_AGAIN_LATER;
898
899 case INFO_FORMAT_CHANGED:
900 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED;
901
902 case INFO_OUTPUT_BUFFERS_CHANGED:
903 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
904
905 case INVALID_OPERATION:
906 jniThrowException(env, "java/lang/IllegalStateException", msg);
907 return 0;
908
909 case BAD_VALUE:
910 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
911 return 0;
912
913 default:
914 if (isCryptoError(err)) {
915 throwCryptoException(env, err, msg);
916 return 0;
917 }
918 throwCodecException(env, err, actionCode, msg);
919 return 0;
920 }
921 }
922
android_media_MediaCodec_native_enableOnFrameRenderedListener(JNIEnv * env,jobject thiz,jboolean enabled)923 static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
924 JNIEnv *env,
925 jobject thiz,
926 jboolean enabled) {
927 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
928
929 if (codec == NULL) {
930 throwExceptionAsNecessary(env, INVALID_OPERATION);
931 return;
932 }
933
934 status_t err = codec->enableOnFrameRenderedListener(enabled);
935
936 throwExceptionAsNecessary(env, err);
937 }
938
android_media_MediaCodec_native_setCallback(JNIEnv * env,jobject thiz,jobject cb)939 static void android_media_MediaCodec_native_setCallback(
940 JNIEnv *env,
941 jobject thiz,
942 jobject cb) {
943 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
944
945 if (codec == NULL) {
946 throwExceptionAsNecessary(env, INVALID_OPERATION);
947 return;
948 }
949
950 status_t err = codec->setCallback(cb);
951
952 throwExceptionAsNecessary(env, err);
953 }
954
android_media_MediaCodec_native_configure(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray values,jobject jsurface,jobject jcrypto,jint flags)955 static void android_media_MediaCodec_native_configure(
956 JNIEnv *env,
957 jobject thiz,
958 jobjectArray keys, jobjectArray values,
959 jobject jsurface,
960 jobject jcrypto,
961 jint flags) {
962 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
963
964 if (codec == NULL) {
965 throwExceptionAsNecessary(env, INVALID_OPERATION);
966 return;
967 }
968
969 sp<AMessage> format;
970 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format);
971
972 if (err != OK) {
973 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
974 return;
975 }
976
977 sp<IGraphicBufferProducer> bufferProducer;
978 if (jsurface != NULL) {
979 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
980 if (surface != NULL) {
981 bufferProducer = surface->getIGraphicBufferProducer();
982 } else {
983 jniThrowException(
984 env,
985 "java/lang/IllegalArgumentException",
986 "The surface has been released");
987 return;
988 }
989 }
990
991 sp<ICrypto> crypto;
992 if (jcrypto != NULL) {
993 crypto = JCrypto::GetCrypto(env, jcrypto);
994 }
995
996 err = codec->configure(format, bufferProducer, crypto, flags);
997
998 throwExceptionAsNecessary(env, err);
999 }
1000
android_media_MediaCodec_native_setSurface(JNIEnv * env,jobject thiz,jobject jsurface)1001 static void android_media_MediaCodec_native_setSurface(
1002 JNIEnv *env,
1003 jobject thiz,
1004 jobject jsurface) {
1005 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1006
1007 if (codec == NULL) {
1008 throwExceptionAsNecessary(env, INVALID_OPERATION);
1009 return;
1010 }
1011
1012 sp<IGraphicBufferProducer> bufferProducer;
1013 if (jsurface != NULL) {
1014 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
1015 if (surface != NULL) {
1016 bufferProducer = surface->getIGraphicBufferProducer();
1017 } else {
1018 jniThrowException(
1019 env,
1020 "java/lang/IllegalArgumentException",
1021 "The surface has been released");
1022 return;
1023 }
1024 }
1025
1026 status_t err = codec->setSurface(bufferProducer);
1027 throwExceptionAsNecessary(env, err);
1028 }
1029
android_media_MediaCodec_getPersistentInputSurface(JNIEnv * env,jobject object)1030 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
1031 JNIEnv* env, jobject object) {
1032 sp<PersistentSurface> persistentSurface;
1033
1034 jobject lock = env->GetObjectField(
1035 object, gPersistentSurfaceClassInfo.mLock);
1036 if (env->MonitorEnter(lock) == JNI_OK) {
1037 persistentSurface = reinterpret_cast<PersistentSurface *>(
1038 env->GetLongField(object,
1039 gPersistentSurfaceClassInfo.mPersistentObject));
1040 env->MonitorExit(lock);
1041 }
1042 env->DeleteLocalRef(lock);
1043
1044 return persistentSurface;
1045 }
1046
android_media_MediaCodec_createPersistentInputSurface(JNIEnv * env,jclass)1047 static jobject android_media_MediaCodec_createPersistentInputSurface(
1048 JNIEnv* env, jclass /* clazz */) {
1049 ALOGV("android_media_MediaCodec_createPersistentInputSurface");
1050 sp<PersistentSurface> persistentSurface =
1051 MediaCodec::CreatePersistentInputSurface();
1052
1053 if (persistentSurface == NULL) {
1054 return NULL;
1055 }
1056
1057 sp<Surface> surface = new Surface(
1058 persistentSurface->getBufferProducer(), true);
1059 if (surface == NULL) {
1060 return NULL;
1061 }
1062
1063 jobject object = env->NewObject(
1064 gPersistentSurfaceClassInfo.clazz,
1065 gPersistentSurfaceClassInfo.ctor);
1066
1067 if (object == NULL) {
1068 if (env->ExceptionCheck()) {
1069 ALOGE("Could not create PersistentSurface.");
1070 env->ExceptionClear();
1071 }
1072 return NULL;
1073 }
1074
1075 jobject lock = env->GetObjectField(
1076 object, gPersistentSurfaceClassInfo.mLock);
1077 if (env->MonitorEnter(lock) == JNI_OK) {
1078 env->CallVoidMethod(
1079 object,
1080 gPersistentSurfaceClassInfo.setNativeObjectLocked,
1081 (jlong)surface.get());
1082 env->SetLongField(
1083 object,
1084 gPersistentSurfaceClassInfo.mPersistentObject,
1085 (jlong)persistentSurface.get());
1086 env->MonitorExit(lock);
1087 } else {
1088 env->DeleteLocalRef(object);
1089 object = NULL;
1090 }
1091 env->DeleteLocalRef(lock);
1092
1093 if (object != NULL) {
1094 surface->incStrong(&sRefBaseOwner);
1095 persistentSurface->incStrong(&sRefBaseOwner);
1096 }
1097
1098 return object;
1099 }
1100
android_media_MediaCodec_releasePersistentInputSurface(JNIEnv * env,jclass,jobject object)1101 static void android_media_MediaCodec_releasePersistentInputSurface(
1102 JNIEnv* env, jclass /* clazz */, jobject object) {
1103 sp<PersistentSurface> persistentSurface;
1104
1105 jobject lock = env->GetObjectField(
1106 object, gPersistentSurfaceClassInfo.mLock);
1107 if (env->MonitorEnter(lock) == JNI_OK) {
1108 persistentSurface = reinterpret_cast<PersistentSurface *>(
1109 env->GetLongField(
1110 object, gPersistentSurfaceClassInfo.mPersistentObject));
1111 env->SetLongField(
1112 object,
1113 gPersistentSurfaceClassInfo.mPersistentObject,
1114 (jlong)0);
1115 env->MonitorExit(lock);
1116 }
1117 env->DeleteLocalRef(lock);
1118
1119 if (persistentSurface != NULL) {
1120 persistentSurface->decStrong(&sRefBaseOwner);
1121 }
1122 // no need to release surface as it will be released by Surface's jni
1123 }
1124
android_media_MediaCodec_setInputSurface(JNIEnv * env,jobject thiz,jobject object)1125 static void android_media_MediaCodec_setInputSurface(
1126 JNIEnv* env, jobject thiz, jobject object) {
1127 ALOGV("android_media_MediaCodec_setInputSurface");
1128
1129 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1130 if (codec == NULL) {
1131 throwExceptionAsNecessary(env, INVALID_OPERATION);
1132 return;
1133 }
1134
1135 sp<PersistentSurface> persistentSurface =
1136 android_media_MediaCodec_getPersistentInputSurface(env, object);
1137
1138 status_t err = codec->setInputSurface(persistentSurface);
1139 if (err != NO_ERROR) {
1140 throwExceptionAsNecessary(env, err);
1141 }
1142 }
1143
android_media_MediaCodec_createInputSurface(JNIEnv * env,jobject thiz)1144 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
1145 jobject thiz) {
1146 ALOGV("android_media_MediaCodec_createInputSurface");
1147
1148 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1149 if (codec == NULL) {
1150 throwExceptionAsNecessary(env, INVALID_OPERATION);
1151 return NULL;
1152 }
1153
1154 // Tell the MediaCodec that we want to use a Surface as input.
1155 sp<IGraphicBufferProducer> bufferProducer;
1156 status_t err = codec->createInputSurface(&bufferProducer);
1157 if (err != NO_ERROR) {
1158 throwExceptionAsNecessary(env, err);
1159 return NULL;
1160 }
1161
1162 // Wrap the IGBP in a Java-language Surface.
1163 return android_view_Surface_createFromIGraphicBufferProducer(env,
1164 bufferProducer);
1165 }
1166
android_media_MediaCodec_start(JNIEnv * env,jobject thiz)1167 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
1168 ALOGV("android_media_MediaCodec_start");
1169
1170 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1171
1172 if (codec == NULL) {
1173 throwExceptionAsNecessary(env, INVALID_OPERATION);
1174 return;
1175 }
1176
1177 status_t err = codec->start();
1178
1179 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
1180 }
1181
android_media_MediaCodec_stop(JNIEnv * env,jobject thiz)1182 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
1183 ALOGV("android_media_MediaCodec_stop");
1184
1185 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1186
1187 if (codec == NULL) {
1188 throwExceptionAsNecessary(env, INVALID_OPERATION);
1189 return;
1190 }
1191
1192 status_t err = codec->stop();
1193
1194 throwExceptionAsNecessary(env, err);
1195 }
1196
android_media_MediaCodec_reset(JNIEnv * env,jobject thiz)1197 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
1198 ALOGV("android_media_MediaCodec_reset");
1199
1200 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1201
1202 if (codec == NULL) {
1203 throwExceptionAsNecessary(env, INVALID_OPERATION);
1204 return;
1205 }
1206
1207 status_t err = codec->reset();
1208 if (err != OK) {
1209 // treat all errors as fatal for now, though resource not available
1210 // errors could be treated as transient.
1211 // we also should avoid sending INVALID_OPERATION here due to
1212 // the transitory nature of reset(), it should not inadvertently
1213 // trigger an IllegalStateException.
1214 err = UNKNOWN_ERROR;
1215 }
1216 throwExceptionAsNecessary(env, err);
1217 }
1218
android_media_MediaCodec_flush(JNIEnv * env,jobject thiz)1219 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
1220 ALOGV("android_media_MediaCodec_flush");
1221
1222 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1223
1224 if (codec == NULL) {
1225 throwExceptionAsNecessary(env, INVALID_OPERATION);
1226 return;
1227 }
1228
1229 status_t err = codec->flush();
1230
1231 throwExceptionAsNecessary(env, err);
1232 }
1233
android_media_MediaCodec_queueInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jint size,jlong timestampUs,jint flags)1234 static void android_media_MediaCodec_queueInputBuffer(
1235 JNIEnv *env,
1236 jobject thiz,
1237 jint index,
1238 jint offset,
1239 jint size,
1240 jlong timestampUs,
1241 jint flags) {
1242 ALOGV("android_media_MediaCodec_queueInputBuffer");
1243
1244 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1245
1246 if (codec == NULL) {
1247 throwExceptionAsNecessary(env, INVALID_OPERATION);
1248 return;
1249 }
1250
1251 AString errorDetailMsg;
1252
1253 status_t err = codec->queueInputBuffer(
1254 index, offset, size, timestampUs, flags, &errorDetailMsg);
1255
1256 throwExceptionAsNecessary(
1257 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1258 }
1259
android_media_MediaCodec_queueSecureInputBuffer(JNIEnv * env,jobject thiz,jint index,jint offset,jobject cryptoInfoObj,jlong timestampUs,jint flags)1260 static void android_media_MediaCodec_queueSecureInputBuffer(
1261 JNIEnv *env,
1262 jobject thiz,
1263 jint index,
1264 jint offset,
1265 jobject cryptoInfoObj,
1266 jlong timestampUs,
1267 jint flags) {
1268 ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
1269
1270 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1271
1272 if (codec == NULL) {
1273 throwExceptionAsNecessary(env, INVALID_OPERATION);
1274 return;
1275 }
1276
1277 jint numSubSamples =
1278 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
1279
1280 jintArray numBytesOfClearDataObj =
1281 (jintArray)env->GetObjectField(
1282 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
1283
1284 jintArray numBytesOfEncryptedDataObj =
1285 (jintArray)env->GetObjectField(
1286 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
1287
1288 jbyteArray keyObj =
1289 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
1290
1291 jbyteArray ivObj =
1292 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
1293
1294 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
1295 enum CryptoPlugin::Mode mode;
1296 if (jmode == gCryptoModes.Unencrypted) {
1297 mode = CryptoPlugin::kMode_Unencrypted;
1298 } else if (jmode == gCryptoModes.AesCtr) {
1299 mode = CryptoPlugin::kMode_AES_CTR;
1300 } else if (jmode == gCryptoModes.AesCbc) {
1301 mode = CryptoPlugin::kMode_AES_CBC;
1302 } else {
1303 throwExceptionAsNecessary(env, INVALID_OPERATION);
1304 return;
1305 }
1306
1307 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
1308
1309 CryptoPlugin::Pattern pattern;
1310 if (patternObj == NULL) {
1311 pattern.mEncryptBlocks = 0;
1312 pattern.mSkipBlocks = 0;
1313 } else {
1314 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
1315 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
1316 }
1317
1318 status_t err = OK;
1319
1320 CryptoPlugin::SubSample *subSamples = NULL;
1321 jbyte *key = NULL;
1322 jbyte *iv = NULL;
1323
1324 if (numSubSamples <= 0) {
1325 err = -EINVAL;
1326 } else if (numBytesOfClearDataObj == NULL
1327 && numBytesOfEncryptedDataObj == NULL) {
1328 err = -EINVAL;
1329 } else if (numBytesOfEncryptedDataObj != NULL
1330 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
1331 err = -ERANGE;
1332 } else if (numBytesOfClearDataObj != NULL
1333 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
1334 err = -ERANGE;
1335 // subSamples array may silently overflow if number of samples are too large. Use
1336 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
1337 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
1338 err = -EINVAL;
1339 } else {
1340 jboolean isCopy;
1341
1342 jint *numBytesOfClearData =
1343 (numBytesOfClearDataObj == NULL)
1344 ? NULL
1345 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
1346
1347 jint *numBytesOfEncryptedData =
1348 (numBytesOfEncryptedDataObj == NULL)
1349 ? NULL
1350 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
1351
1352 subSamples = new CryptoPlugin::SubSample[numSubSamples];
1353
1354 for (jint i = 0; i < numSubSamples; ++i) {
1355 subSamples[i].mNumBytesOfClearData =
1356 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
1357
1358 subSamples[i].mNumBytesOfEncryptedData =
1359 (numBytesOfEncryptedData == NULL)
1360 ? 0 : numBytesOfEncryptedData[i];
1361 }
1362
1363 if (numBytesOfEncryptedData != NULL) {
1364 env->ReleaseIntArrayElements(
1365 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
1366 numBytesOfEncryptedData = NULL;
1367 }
1368
1369 if (numBytesOfClearData != NULL) {
1370 env->ReleaseIntArrayElements(
1371 numBytesOfClearDataObj, numBytesOfClearData, 0);
1372 numBytesOfClearData = NULL;
1373 }
1374 }
1375
1376 if (err == OK && keyObj != NULL) {
1377 if (env->GetArrayLength(keyObj) != 16) {
1378 err = -EINVAL;
1379 } else {
1380 jboolean isCopy;
1381 key = env->GetByteArrayElements(keyObj, &isCopy);
1382 }
1383 }
1384
1385 if (err == OK && ivObj != NULL) {
1386 if (env->GetArrayLength(ivObj) != 16) {
1387 err = -EINVAL;
1388 } else {
1389 jboolean isCopy;
1390 iv = env->GetByteArrayElements(ivObj, &isCopy);
1391 }
1392 }
1393
1394 AString errorDetailMsg;
1395
1396 if (err == OK) {
1397 err = codec->queueSecureInputBuffer(
1398 index, offset,
1399 subSamples, numSubSamples,
1400 (const uint8_t *)key, (const uint8_t *)iv,
1401 mode,
1402 pattern,
1403 timestampUs,
1404 flags,
1405 &errorDetailMsg);
1406 }
1407
1408 if (iv != NULL) {
1409 env->ReleaseByteArrayElements(ivObj, iv, 0);
1410 iv = NULL;
1411 }
1412
1413 if (key != NULL) {
1414 env->ReleaseByteArrayElements(keyObj, key, 0);
1415 key = NULL;
1416 }
1417
1418 delete[] subSamples;
1419 subSamples = NULL;
1420
1421 throwExceptionAsNecessary(
1422 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
1423 }
1424
android_media_MediaCodec_dequeueInputBuffer(JNIEnv * env,jobject thiz,jlong timeoutUs)1425 static jint android_media_MediaCodec_dequeueInputBuffer(
1426 JNIEnv *env, jobject thiz, jlong timeoutUs) {
1427 ALOGV("android_media_MediaCodec_dequeueInputBuffer");
1428
1429 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1430
1431 if (codec == NULL) {
1432 throwExceptionAsNecessary(env, INVALID_OPERATION);
1433 return -1;
1434 }
1435
1436 size_t index;
1437 status_t err = codec->dequeueInputBuffer(&index, timeoutUs);
1438
1439 if (err == OK) {
1440 return (jint) index;
1441 }
1442
1443 return throwExceptionAsNecessary(env, err);
1444 }
1445
android_media_MediaCodec_dequeueOutputBuffer(JNIEnv * env,jobject thiz,jobject bufferInfo,jlong timeoutUs)1446 static jint android_media_MediaCodec_dequeueOutputBuffer(
1447 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) {
1448 ALOGV("android_media_MediaCodec_dequeueOutputBuffer");
1449
1450 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1451
1452 if (codec == NULL) {
1453 throwExceptionAsNecessary(env, INVALID_OPERATION);
1454 return 0;
1455 }
1456
1457 size_t index;
1458 status_t err = codec->dequeueOutputBuffer(
1459 env, bufferInfo, &index, timeoutUs);
1460
1461 if (err == OK) {
1462 return (jint) index;
1463 }
1464
1465 return throwExceptionAsNecessary(env, err);
1466 }
1467
android_media_MediaCodec_releaseOutputBuffer(JNIEnv * env,jobject thiz,jint index,jboolean render,jboolean updatePTS,jlong timestampNs)1468 static void android_media_MediaCodec_releaseOutputBuffer(
1469 JNIEnv *env, jobject thiz,
1470 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
1471 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
1472
1473 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1474
1475 if (codec == NULL) {
1476 throwExceptionAsNecessary(env, INVALID_OPERATION);
1477 return;
1478 }
1479
1480 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
1481
1482 throwExceptionAsNecessary(env, err);
1483 }
1484
android_media_MediaCodec_signalEndOfInputStream(JNIEnv * env,jobject thiz)1485 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
1486 jobject thiz) {
1487 ALOGV("android_media_MediaCodec_signalEndOfInputStream");
1488
1489 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1490 if (codec == NULL) {
1491 throwExceptionAsNecessary(env, INVALID_OPERATION);
1492 return;
1493 }
1494
1495 status_t err = codec->signalEndOfInputStream();
1496
1497 throwExceptionAsNecessary(env, err);
1498 }
1499
android_media_MediaCodec_getFormatNative(JNIEnv * env,jobject thiz,jboolean input)1500 static jobject android_media_MediaCodec_getFormatNative(
1501 JNIEnv *env, jobject thiz, jboolean input) {
1502 ALOGV("android_media_MediaCodec_getFormatNative");
1503
1504 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1505
1506 if (codec == NULL) {
1507 throwExceptionAsNecessary(env, INVALID_OPERATION);
1508 return NULL;
1509 }
1510
1511 jobject format;
1512 status_t err = codec->getFormat(env, input, &format);
1513
1514 if (err == OK) {
1515 return format;
1516 }
1517
1518 throwExceptionAsNecessary(env, err);
1519
1520 return NULL;
1521 }
1522
android_media_MediaCodec_getOutputFormatForIndexNative(JNIEnv * env,jobject thiz,jint index)1523 static jobject android_media_MediaCodec_getOutputFormatForIndexNative(
1524 JNIEnv *env, jobject thiz, jint index) {
1525 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative");
1526
1527 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1528
1529 if (codec == NULL) {
1530 throwExceptionAsNecessary(env, INVALID_OPERATION);
1531 return NULL;
1532 }
1533
1534 jobject format;
1535 status_t err = codec->getOutputFormat(env, index, &format);
1536
1537 if (err == OK) {
1538 return format;
1539 }
1540
1541 throwExceptionAsNecessary(env, err);
1542
1543 return NULL;
1544 }
1545
android_media_MediaCodec_getBuffers(JNIEnv * env,jobject thiz,jboolean input)1546 static jobjectArray android_media_MediaCodec_getBuffers(
1547 JNIEnv *env, jobject thiz, jboolean input) {
1548 ALOGV("android_media_MediaCodec_getBuffers");
1549
1550 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1551
1552 if (codec == NULL) {
1553 throwExceptionAsNecessary(env, INVALID_OPERATION);
1554 return NULL;
1555 }
1556
1557 jobjectArray buffers;
1558 status_t err = codec->getBuffers(env, input, &buffers);
1559
1560 if (err == OK) {
1561 return buffers;
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_getBuffer(JNIEnv * env,jobject thiz,jboolean input,jint index)1572 static jobject android_media_MediaCodec_getBuffer(
1573 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1574 ALOGV("android_media_MediaCodec_getBuffer");
1575
1576 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1577
1578 if (codec == NULL) {
1579 throwExceptionAsNecessary(env, INVALID_OPERATION);
1580 return NULL;
1581 }
1582
1583 jobject buffer;
1584 status_t err = codec->getBuffer(env, input, index, &buffer);
1585
1586 if (err == OK) {
1587 return buffer;
1588 }
1589
1590 // if we're out of memory, an exception was already thrown
1591 if (err != NO_MEMORY) {
1592 throwExceptionAsNecessary(env, err);
1593 }
1594
1595 return NULL;
1596 }
1597
android_media_MediaCodec_getImage(JNIEnv * env,jobject thiz,jboolean input,jint index)1598 static jobject android_media_MediaCodec_getImage(
1599 JNIEnv *env, jobject thiz, jboolean input, jint index) {
1600 ALOGV("android_media_MediaCodec_getImage");
1601
1602 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1603
1604 if (codec == NULL) {
1605 throwExceptionAsNecessary(env, INVALID_OPERATION);
1606 return NULL;
1607 }
1608
1609 jobject image;
1610 status_t err = codec->getImage(env, input, index, &image);
1611
1612 if (err == OK) {
1613 return image;
1614 }
1615
1616 // if we're out of memory, an exception was already thrown
1617 if (err != NO_MEMORY) {
1618 throwExceptionAsNecessary(env, err);
1619 }
1620
1621 return NULL;
1622 }
1623
android_media_MediaCodec_getName(JNIEnv * env,jobject thiz)1624 static jobject android_media_MediaCodec_getName(
1625 JNIEnv *env, jobject thiz) {
1626 ALOGV("android_media_MediaCodec_getName");
1627
1628 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1629
1630 if (codec == NULL) {
1631 throwExceptionAsNecessary(env, INVALID_OPERATION);
1632 return NULL;
1633 }
1634
1635 jstring name;
1636 status_t err = codec->getName(env, &name);
1637
1638 if (err == OK) {
1639 return name;
1640 }
1641
1642 throwExceptionAsNecessary(env, err);
1643
1644 return NULL;
1645 }
1646
android_media_MediaCodec_setParameters(JNIEnv * env,jobject thiz,jobjectArray keys,jobjectArray vals)1647 static void android_media_MediaCodec_setParameters(
1648 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
1649 ALOGV("android_media_MediaCodec_setParameters");
1650
1651 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1652
1653 if (codec == NULL) {
1654 throwExceptionAsNecessary(env, INVALID_OPERATION);
1655 return;
1656 }
1657
1658 sp<AMessage> params;
1659 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms);
1660
1661 if (err == OK) {
1662 err = codec->setParameters(params);
1663 }
1664
1665 throwExceptionAsNecessary(env, err);
1666 }
1667
android_media_MediaCodec_setVideoScalingMode(JNIEnv * env,jobject thiz,jint mode)1668 static void android_media_MediaCodec_setVideoScalingMode(
1669 JNIEnv *env, jobject thiz, jint mode) {
1670 sp<JMediaCodec> codec = getMediaCodec(env, thiz);
1671
1672 if (codec == NULL) {
1673 throwExceptionAsNecessary(env, INVALID_OPERATION);
1674 return;
1675 }
1676
1677 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
1678 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
1679 jniThrowException(env, "java/lang/InvalidArgumentException", NULL);
1680 return;
1681 }
1682
1683 codec->setVideoScalingMode(mode);
1684 }
1685
android_media_MediaCodec_native_init(JNIEnv * env)1686 static void android_media_MediaCodec_native_init(JNIEnv *env) {
1687 ScopedLocalRef<jclass> clazz(
1688 env, env->FindClass("android/media/MediaCodec"));
1689 CHECK(clazz.get() != NULL);
1690
1691 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
1692 CHECK(gFields.context != NULL);
1693
1694 gFields.postEventFromNativeID =
1695 env->GetMethodID(
1696 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
1697
1698 CHECK(gFields.postEventFromNativeID != NULL);
1699
1700 jfieldID field;
1701 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
1702 CHECK(field != NULL);
1703 gCryptoModes.Unencrypted =
1704 env->GetStaticIntField(clazz.get(), field);
1705
1706 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
1707 CHECK(field != NULL);
1708 gCryptoModes.AesCtr =
1709 env->GetStaticIntField(clazz.get(), field);
1710
1711 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
1712 CHECK(field != NULL);
1713 gCryptoModes.AesCbc =
1714 env->GetStaticIntField(clazz.get(), field);
1715
1716 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
1717 CHECK(clazz.get() != NULL);
1718
1719 gFields.cryptoInfoNumSubSamplesID =
1720 env->GetFieldID(clazz.get(), "numSubSamples", "I");
1721 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
1722
1723 gFields.cryptoInfoNumBytesOfClearDataID =
1724 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I");
1725 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
1726
1727 gFields.cryptoInfoNumBytesOfEncryptedDataID =
1728 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I");
1729 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
1730
1731 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B");
1732 CHECK(gFields.cryptoInfoKeyID != NULL);
1733
1734 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B");
1735 CHECK(gFields.cryptoInfoIVID != NULL);
1736
1737 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
1738 CHECK(gFields.cryptoInfoModeID != NULL);
1739
1740 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
1741 "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
1742 CHECK(gFields.cryptoInfoPatternID != NULL);
1743
1744 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
1745 CHECK(clazz.get() != NULL);
1746
1747 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
1748 CHECK(gFields.patternEncryptBlocksID != NULL);
1749
1750 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
1751 CHECK(gFields.patternSkipBlocksID != NULL);
1752
1753 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
1754 CHECK(clazz.get() != NULL);
1755
1756 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
1757 CHECK(field != NULL);
1758 gCryptoErrorCodes.cryptoErrorNoKey =
1759 env->GetStaticIntField(clazz.get(), field);
1760
1761 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I");
1762 CHECK(field != NULL);
1763 gCryptoErrorCodes.cryptoErrorKeyExpired =
1764 env->GetStaticIntField(clazz.get(), field);
1765
1766 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I");
1767 CHECK(field != NULL);
1768 gCryptoErrorCodes.cryptoErrorResourceBusy =
1769 env->GetStaticIntField(clazz.get(), field);
1770
1771 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
1772 CHECK(field != NULL);
1773 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
1774 env->GetStaticIntField(clazz.get(), field);
1775
1776 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I");
1777 CHECK(field != NULL);
1778 gCryptoErrorCodes.cryptoErrorSessionNotOpened =
1779 env->GetStaticIntField(clazz.get(), field);
1780
1781 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
1782 CHECK(field != NULL);
1783 gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
1784 env->GetStaticIntField(clazz.get(), field);
1785
1786 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
1787 CHECK(clazz.get() != NULL);
1788 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
1789 CHECK(field != NULL);
1790 gCodecActionCodes.codecActionTransient =
1791 env->GetStaticIntField(clazz.get(), field);
1792
1793 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
1794 CHECK(field != NULL);
1795 gCodecActionCodes.codecActionRecoverable =
1796 env->GetStaticIntField(clazz.get(), field);
1797
1798 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I");
1799 CHECK(field != NULL);
1800 gCodecErrorCodes.errorInsufficientResource =
1801 env->GetStaticIntField(clazz.get(), field);
1802
1803 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I");
1804 CHECK(field != NULL);
1805 gCodecErrorCodes.errorReclaimed =
1806 env->GetStaticIntField(clazz.get(), field);
1807
1808 clazz.reset(env->FindClass("android/view/Surface"));
1809 CHECK(clazz.get() != NULL);
1810
1811 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
1812 CHECK(field != NULL);
1813 gPersistentSurfaceClassInfo.mLock = field;
1814
1815 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
1816 CHECK(method != NULL);
1817 gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
1818
1819 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
1820 CHECK(clazz.get() != NULL);
1821 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
1822
1823 method = env->GetMethodID(clazz.get(), "<init>", "()V");
1824 CHECK(method != NULL);
1825 gPersistentSurfaceClassInfo.ctor = method;
1826
1827 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
1828 CHECK(field != NULL);
1829 gPersistentSurfaceClassInfo.mPersistentObject = field;
1830 }
1831
android_media_MediaCodec_native_setup(JNIEnv * env,jobject thiz,jstring name,jboolean nameIsType,jboolean encoder)1832 static void android_media_MediaCodec_native_setup(
1833 JNIEnv *env, jobject thiz,
1834 jstring name, jboolean nameIsType, jboolean encoder) {
1835 if (name == NULL) {
1836 jniThrowException(env, "java/lang/NullPointerException", NULL);
1837 return;
1838 }
1839
1840 const char *tmp = env->GetStringUTFChars(name, NULL);
1841
1842 if (tmp == NULL) {
1843 return;
1844 }
1845
1846 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
1847
1848 const status_t err = codec->initCheck();
1849 if (err == NAME_NOT_FOUND) {
1850 // fail and do not try again.
1851 jniThrowException(env, "java/lang/IllegalArgumentException",
1852 String8::format("Failed to initialize %s, error %#x", tmp, err));
1853 env->ReleaseStringUTFChars(name, tmp);
1854 return;
1855 } if (err == NO_MEMORY) {
1856 throwCodecException(env, err, ACTION_CODE_TRANSIENT,
1857 String8::format("Failed to initialize %s, error %#x", tmp, err));
1858 env->ReleaseStringUTFChars(name, tmp);
1859 return;
1860 } else if (err != OK) {
1861 // believed possible to try again
1862 jniThrowException(env, "java/io/IOException",
1863 String8::format("Failed to find matching codec %s, error %#x", tmp, err));
1864 env->ReleaseStringUTFChars(name, tmp);
1865 return;
1866 }
1867
1868 env->ReleaseStringUTFChars(name, tmp);
1869
1870 codec->registerSelf();
1871
1872 setMediaCodec(env,thiz, codec);
1873 }
1874
android_media_MediaCodec_native_finalize(JNIEnv * env,jobject thiz)1875 static void android_media_MediaCodec_native_finalize(
1876 JNIEnv *env, jobject thiz) {
1877 android_media_MediaCodec_release(env, thiz);
1878 }
1879
1880 static const JNINativeMethod gMethods[] = {
1881 { "native_release", "()V", (void *)android_media_MediaCodec_release },
1882
1883 { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
1884
1885 { "native_releasePersistentInputSurface",
1886 "(Landroid/view/Surface;)V",
1887 (void *)android_media_MediaCodec_releasePersistentInputSurface},
1888
1889 { "native_createPersistentInputSurface",
1890 "()Landroid/media/MediaCodec$PersistentSurface;",
1891 (void *)android_media_MediaCodec_createPersistentInputSurface },
1892
1893 { "native_setInputSurface", "(Landroid/view/Surface;)V",
1894 (void *)android_media_MediaCodec_setInputSurface },
1895
1896 { "native_enableOnFrameRenderedListener", "(Z)V",
1897 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
1898
1899 { "native_setCallback",
1900 "(Landroid/media/MediaCodec$Callback;)V",
1901 (void *)android_media_MediaCodec_native_setCallback },
1902
1903 { "native_configure",
1904 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
1905 "Landroid/media/MediaCrypto;I)V",
1906 (void *)android_media_MediaCodec_native_configure },
1907
1908 { "native_setSurface",
1909 "(Landroid/view/Surface;)V",
1910 (void *)android_media_MediaCodec_native_setSurface },
1911
1912 { "createInputSurface", "()Landroid/view/Surface;",
1913 (void *)android_media_MediaCodec_createInputSurface },
1914
1915 { "native_start", "()V", (void *)android_media_MediaCodec_start },
1916 { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
1917 { "native_flush", "()V", (void *)android_media_MediaCodec_flush },
1918
1919 { "native_queueInputBuffer", "(IIIJI)V",
1920 (void *)android_media_MediaCodec_queueInputBuffer },
1921
1922 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
1923 (void *)android_media_MediaCodec_queueSecureInputBuffer },
1924
1925 { "native_dequeueInputBuffer", "(J)I",
1926 (void *)android_media_MediaCodec_dequeueInputBuffer },
1927
1928 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
1929 (void *)android_media_MediaCodec_dequeueOutputBuffer },
1930
1931 { "releaseOutputBuffer", "(IZZJ)V",
1932 (void *)android_media_MediaCodec_releaseOutputBuffer },
1933
1934 { "signalEndOfInputStream", "()V",
1935 (void *)android_media_MediaCodec_signalEndOfInputStream },
1936
1937 { "getFormatNative", "(Z)Ljava/util/Map;",
1938 (void *)android_media_MediaCodec_getFormatNative },
1939
1940 { "getOutputFormatNative", "(I)Ljava/util/Map;",
1941 (void *)android_media_MediaCodec_getOutputFormatForIndexNative },
1942
1943 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;",
1944 (void *)android_media_MediaCodec_getBuffers },
1945
1946 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;",
1947 (void *)android_media_MediaCodec_getBuffer },
1948
1949 { "getImage", "(ZI)Landroid/media/Image;",
1950 (void *)android_media_MediaCodec_getImage },
1951
1952 { "getName", "()Ljava/lang/String;",
1953 (void *)android_media_MediaCodec_getName },
1954
1955 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
1956 (void *)android_media_MediaCodec_setParameters },
1957
1958 { "setVideoScalingMode", "(I)V",
1959 (void *)android_media_MediaCodec_setVideoScalingMode },
1960
1961 { "native_init", "()V", (void *)android_media_MediaCodec_native_init },
1962
1963 { "native_setup", "(Ljava/lang/String;ZZ)V",
1964 (void *)android_media_MediaCodec_native_setup },
1965
1966 { "native_finalize", "()V",
1967 (void *)android_media_MediaCodec_native_finalize },
1968 };
1969
register_android_media_MediaCodec(JNIEnv * env)1970 int register_android_media_MediaCodec(JNIEnv *env) {
1971 return AndroidRuntime::registerNativeMethods(env,
1972 "android/media/MediaCodec", gMethods, NELEM(gMethods));
1973 }
1974