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