1 /*
2 * Android MediaCodec Wrapper
3 *
4 * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
24
28
32
34
38
41
48
52
56
64
68
69 };
70
74 {
"android/media/MediaCodecList",
"findDecoderForFormat",
"(Landroid/media/MediaFormat;)Ljava/lang/String;",
FF_JNI_METHOD, offsetof(
struct JNIAMediaCodecListFields, find_decoder_for_format_id), 0 },
75
78
81 {
"android/media/MediaCodecInfo",
"getCapabilitiesForType",
"(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
FF_JNI_METHOD, offsetof(
struct JNIAMediaCodecListFields, get_codec_capabilities_id), 1 },
85
88 {
"android/media/MediaCodecInfo$CodecCapabilities",
"profileLevels",
"[Landroid/media/MediaCodecInfo$CodecProfileLevel;",
FF_JNI_FIELD, offsetof(
struct JNIAMediaCodecListFields, profile_levels_id), 1 },
89
93
101
105
107 };
108
110
112
114
116
122
128
130
131 };
132
135
137
139
143 {
"android/media/MediaFormat",
"getByteBuffer",
"(Ljava/lang/String;)Ljava/nio/ByteBuffer;",
FF_JNI_METHOD, offsetof(
struct JNIAMediaFormatFields, get_bytebuffer_id), 1 },
145
149 {
"android/media/MediaFormat",
"setByteBuffer",
"(Ljava/lang/String;Ljava/nio/ByteBuffer;)V",
FF_JNI_METHOD, offsetof(
struct JNIAMediaFormatFields, set_bytebuffer_id), 1 },
151
153
155 };
156
161 };
162
164
168 };
169
171
173
177
181
183
187
189
195
197
202
208
210
212
217
218 };
219
222
226
230
232
236
238
239 {
"android/media/MediaCodec",
"configure",
"(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V",
FF_JNI_METHOD, offsetof(
struct JNIAMediaCodecFields, configure_id), 1 },
244
245 {
"android/media/MediaCodec",
"getOutputFormat",
"()Landroid/media/MediaFormat;",
FF_JNI_METHOD, offsetof(
struct JNIAMediaCodecFields, get_output_format_id), 1 },
246
251
252 {
"android/media/MediaCodec",
"dequeueOutputBuffer",
"(Landroid/media/MediaCodec$BufferInfo;J)I",
FF_JNI_METHOD, offsetof(
struct JNIAMediaCodecFields, dequeue_output_buffer_id), 1 },
257
259
265
267 };
268
273 };
274
276
278
280
283
286
290
294
296
298 };
299
300 #define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do { \
301 (env) = ff_jni_get_env(log_ctx); \
302 if (!(env)) { \
303 return ret; \
304 } \
305 } while (0)
306
307 #define JNI_GET_ENV_OR_RETURN_VOID(env, log_ctx) do { \
308 (env) = ff_jni_get_env(log_ctx); \
309 if (!(env)) { \
310 return; \
311 } \
312 } while (0)
313
315 {
317
320 jfieldID field_id = 0;
321
323
325 goto done;
326 }
327
333 break;
336 break;
339 break;
342 break;
346 break;
350 break;
355 break;
356 }
362 break;
365 break;
366 }
367 }
368
369 if (field_id) {
373 goto done;
374 }
375 }
376
377 done:
379
381 }
382
384 {
387 int codec_count;
388 int found_codec = 0;
390 char *supported_type =
NULL;
391
395
396 jobject codec_name =
NULL;
397
400 jobjectArray types =
NULL;
401
402 jobject capabilities =
NULL;
403 jobject profile_level =
NULL;
404 jobjectArray profile_levels =
NULL;
405
407
409 goto done;
410 }
411
413 goto done;
414 }
415
418 goto done;
419 }
420
421 for(
i = 0;
i < codec_count;
i++) {
422 int j;
423 int type_count;
424 int is_encoder;
425
428 goto done;
429 }
430
433 goto done;
434 }
435
438 goto done;
439 }
440
441 if (is_encoder != encoder) {
442 goto done_with_info;
443 }
444
448 goto done;
449 }
450
451 if (is_software_only) {
452 goto done_with_info;
453 }
454 }
455
458 goto done;
459 }
460
463 goto done;
464 }
465
466 if (codec_name) {
467 (*env)->DeleteLocalRef(env, codec_name);
469 }
470
471 /* Skip software decoders */
472 if (
473 strstr(
name,
"OMX.google") ||
474 strstr(
name,
"OMX.ffmpeg") ||
475 (strstr(
name,
"OMX.SEC") && strstr(
name,
".sw.")) ||
476 !strcmp(
name,
"OMX.qcom.video.decoder.hevcswvdec")) {
477 goto done_with_info;
478 }
479
480 type_count = (*env)->GetArrayLength(env, types);
481 for (j = 0; j < type_count; j++) {
482 int k;
483 int profile_count;
484
485 type = (*env)->GetObjectArrayElement(env, types, j);
487 goto done;
488 }
489
491 if (!supported_type) {
492 goto done;
493 }
494
496 goto done_with_type;
497 }
498
501 goto done;
502 }
503
504 profile_levels = (*env)->GetObjectField(env, capabilities, jfields.
profile_levels_id);
506 goto done;
507 }
508
509 profile_count = (*env)->GetArrayLength(env, profile_levels);
510 if (!profile_count) {
511 found_codec = 1;
512 }
513 for (k = 0; k < profile_count; k++) {
514 int supported_profile = 0;
515
517 found_codec = 1;
518 break;
519 }
520
521 profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
523 goto done;
524 }
525
526 supported_profile = (*env)->GetIntField(env, profile_level, jfields.
profile_id);
528 goto done;
529 }
530
531 found_codec =
profile == supported_profile;
532
533 if (profile_level) {
534 (*env)->DeleteLocalRef(env, profile_level);
535 profile_level =
NULL;
536 }
537
538 if (found_codec) {
539 break;
540 }
541 }
542
543 done_with_type:
544 if (profile_levels) {
545 (*env)->DeleteLocalRef(env, profile_levels);
546 profile_levels =
NULL;
547 }
548
549 if (capabilities) {
550 (*env)->DeleteLocalRef(env, capabilities);
552 }
553
555 (*env)->DeleteLocalRef(env,
type);
557 }
558
560
561 if (found_codec) {
562 break;
563 }
564 }
565
566 done_with_info:
568 (*env)->DeleteLocalRef(env,
info);
570 }
571
572 if (types) {
573 (*env)->DeleteLocalRef(env, types);
575 }
576
577 if (found_codec) {
578 break;
579 }
580
582 }
583
584 done:
585 if (codec_name) {
586 (*env)->DeleteLocalRef(env, codec_name);
587 }
588
590 (*env)->DeleteLocalRef(env,
info);
591 }
592
594 (*env)->DeleteLocalRef(env,
type);
595 }
596
597 if (types) {
598 (*env)->DeleteLocalRef(env, types);
599 }
600
601 if (capabilities) {
602 (*env)->DeleteLocalRef(env, capabilities);
603 }
604
605 if (profile_level) {
606 (*env)->DeleteLocalRef(env, profile_level);
607 }
608
609 if (profile_levels) {
610 (*env)->DeleteLocalRef(env, profile_levels);
611 }
612
614
617
618 if (!found_codec) {
620 }
621
623 }
624
626 {
629 jobject
object =
NULL;
630
634 }
636
638 if (!env) {
641 }
642
645 }
646
647 object = (*env)->NewObject(env,
format->jfields.mediaformat_class,
format->jfields.init_id);
648 if (!object) {
650 }
651
652 format->object = (*env)->NewGlobalRef(env,
object);
655 }
656
658 if (object) {
659 (*env)->DeleteLocalRef(env, object);
660 }
661
665 }
666
668 }
669
671 {
674
678 }
680
682 if (!env) {
685 }
686
689 }
690
691 format->object = (*env)->NewGlobalRef(env,
object);
694 }
695
699
701
703 }
704
706 {
708
710
712 return 0;
713 }
714
716
717 (*env)->DeleteGlobalRef(env,
format->object);
719
721
723
725 }
726
728 {
730
733
735
737
741 }
742
747 }
748
750 }
751
753 {
755
758 jboolean contains_key;
759
761
763
768 }
769
770 contains_key = (*env)->CallBooleanMethod(env,
format->object,
format->jfields.contains_key_id,
key);
774 }
775
776 *
out = (*env)->CallIntMethod(env,
format->object,
format->jfields.get_integer_id,
key);
780 }
781
785 (*env)->DeleteLocalRef(env,
key);
786 }
787
789 }
790
792 {
794
797 jboolean contains_key;
798
800
802
807 }
808
809 contains_key = (*env)->CallBooleanMethod(env,
format->object,
format->jfields.contains_key_id,
key);
813 }
814
819 }
820
824 (*env)->DeleteLocalRef(env,
key);
825 }
826
828 }
829
831 {
833
836 jboolean contains_key;
837
839
841
846 }
847
848 contains_key = (*env)->CallBooleanMethod(env,
format->object,
format->jfields.contains_key_id,
key);
852 }
853
854 *
out = (*env)->CallFloatMethod(env,
format->object,
format->jfields.get_float_id,
key);
858 }
859
863 (*env)->DeleteLocalRef(env,
key);
864 }
865
867 }
868
870 {
872
875 jboolean contains_key;
877
879
881
886 }
887
888 contains_key = (*env)->CallBooleanMethod(env,
format->object,
format->jfields.contains_key_id,
key);
892 }
893
898 }
899
900 *
data = (*env)->GetDirectBufferAddress(env,
result);
901 *
size = (*env)->GetDirectBufferCapacity(env,
result);
902
909 }
910
912 }
913
917 (*env)->DeleteLocalRef(env,
key);
918 }
919
921 (*env)->DeleteLocalRef(env,
result);
922 }
923
925 }
926
928 {
930
933 jboolean contains_key;
935
937
939
944 }
945
946 contains_key = (*env)->CallBooleanMethod(env,
format->object,
format->jfields.contains_key_id,
key);
950 }
951
956 }
957
962 }
963
967 (*env)->DeleteLocalRef(env,
key);
968 }
969
971 (*env)->DeleteLocalRef(env,
result);
972 }
973
975 }
976
978 {
981
983
985
989 }
990
994 }
995
998 (*env)->DeleteLocalRef(env,
key);
999 }
1000 }
1001
1003 {
1006
1008
1010
1014 }
1015
1019 }
1020
1023 (*env)->DeleteLocalRef(env,
key);
1024 }
1025 }
1026
1028 {
1031
1033
1035
1039 }
1040
1044 }
1045
1048 (*env)->DeleteLocalRef(env,
key);
1049 }
1050 }
1051
1053 {
1056 jstring
string =
NULL;
1057
1059
1061
1065 }
1066
1068 if (!string) {
1070 }
1071
1072 (*env)->CallVoidMethod(env,
format->object,
format->jfields.set_string_id,
key,
string);
1075 }
1076
1079 (*env)->DeleteLocalRef(env,
key);
1080 }
1081
1082 if (string) {
1083 (*env)->DeleteLocalRef(env, string);
1084 }
1085 }
1086
1088 {
1093
1095
1097
1101 }
1102
1105 }
1106
1110 }
1111
1113
1117 }
1118
1122 }
1123
1126 (*env)->DeleteLocalRef(env,
key);
1127 }
1128
1130 (*env)->DeleteLocalRef(env,
buffer);
1131 }
1132 }
1133
1135 {
1138
1140
1144 }
1145
1149 }
1150
1154 }
1155
1160 }
1161 }
1162
1166 }
1167
1171 }
1172
1176 }
1177
1181 }
1182
1184
1186 }
1187
1188 #define CREATE_CODEC_BY_NAME 0
1189 #define CREATE_DECODER_BY_TYPE 1
1190 #define CREATE_ENCODER_BY_TYPE 2
1191
1193 {
1197 jstring jarg =
NULL;
1198 jobject
object =
NULL;
1199 jobject buffer_info =
NULL;
1200 jmethodID create_id =
NULL;
1201
1203 if (!codec) {
1205 }
1207
1209 if (!env) {
1212 }
1213
1216 }
1217
1219 if (!jarg) {
1221 }
1222
1223 switch (method) {
1227 default:
1229 }
1230
1231 object = (*env)->CallStaticObjectMethod(env,
1233 create_id,
1234 jarg);
1237 }
1238
1239 codec->
object = (*env)->NewGlobalRef(env,
object);
1242 }
1243
1246 }
1247
1250 }
1251
1255 }
1256
1257 codec->
buffer_info = (*env)->NewGlobalRef(env, buffer_info);
1260 }
1261
1264 if (jarg) {
1265 (*env)->DeleteLocalRef(env, jarg);
1266 }
1267
1268 if (object) {
1269 (*env)->DeleteLocalRef(env, object);
1270 }
1271
1272 if (buffer_info) {
1273 (*env)->DeleteLocalRef(env, buffer_info);
1274 }
1275
1278 (*env)->DeleteGlobalRef(env, codec->
object);
1279 }
1280
1283 }
1284
1287 }
1288
1289 return codec;
1290 }
1291
1292 #define DECLARE_FF_AMEDIACODEC_CREATE_FUNC(name, method) \
1293 FFAMediaCodec *ff_AMediaCodec_##name(const char *arg) \
1294 { \
1295 return codec_create(method, arg); \
1296 } \
1297
1301
1303 {
1305
1307
1308 if (!codec) {
1309 return 0;
1310 }
1311
1313
1314 (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1317 }
1318
1319 (*env)->DeleteGlobalRef(env, codec->input_buffers);
1320 codec->input_buffers =
NULL;
1321
1322 (*env)->DeleteGlobalRef(env, codec->output_buffers);
1323 codec->output_buffers =
NULL;
1324
1325 (*env)->DeleteGlobalRef(env, codec->object);
1326 codec->object =
NULL;
1327
1328 (*env)->DeleteGlobalRef(env, codec->buffer_info);
1329 codec->buffer_info =
NULL;
1330
1332
1334
1336 }
1337
1339 {
1343
1345
1349 }
1350
1352
1355 (*env)->DeleteLocalRef(env,
name);
1356 }
1357
1359 }
1360
1362 {
1365
1367
1372 }
1373
1376 }
1377
1379 {
1382
1384
1389 }
1390
1393 }
1394
1396 {
1399
1401
1406 }
1407
1410 }
1411
1413 {
1416
1418
1423 }
1424
1427 }
1428
1430 {
1433
1435
1440 }
1441
1444 }
1445
1447 {
1450
1452
1457 }
1458
1461 }
1462
1464 {
1467
1469
1474 }
1475
1478 }
1479
1481 {
1484
1486
1491 }
1492
1495 }
1496
1498 {
1501
1503
1507 }
1508
1512 }
1513
1517 }
1518
1522 }
1523
1527 }
1528
1530 }
1531
1533 {
1536
1538 jobject input_buffers =
NULL;
1539
1541
1546 }
1547 } else {
1552 }
1553
1554 codec->
input_buffers = (*env)->NewGlobalRef(env, input_buffers);
1557 }
1558 }
1559
1563 }
1564 }
1565
1566 ret = (*env)->GetDirectBufferAddress(env,
buffer);
1570 (*env)->DeleteLocalRef(env,
buffer);
1571 }
1572
1573 if (input_buffers) {
1574 (*env)->DeleteLocalRef(env, input_buffers);
1575 }
1576
1578 }
1579
1581 {
1584
1586 jobject output_buffers =
NULL;
1587
1589
1594 }
1595 } else {
1600 }
1601
1602 codec->
output_buffers = (*env)->NewGlobalRef(env, output_buffers);
1605 }
1606 }
1607
1611 }
1612 }
1613
1614 ret = (*env)->GetDirectBufferAddress(env,
buffer);
1618 (*env)->DeleteLocalRef(env,
buffer);
1619 }
1620
1621 if (output_buffers) {
1622 (*env)->DeleteLocalRef(env, output_buffers);
1623 }
1624
1626 }
1627
1629 {
1632
1633 jobject mediaformat =
NULL;
1634
1636
1640 }
1641
1644 if (mediaformat) {
1645 (*env)->DeleteLocalRef(env, mediaformat);
1646 }
1647
1649 }
1650
1652 {
1654 }
1655
1657 {
1659 }
1660
1662 {
1664 }
1665
1667 {
1669 }
1670
1672 {
1674 }
1675
1677 {
1679 }
1680
1682 {
1684 }
1685
1687 {
1689
1693
1695 if (!env) {
1698 }
1699
1702 }
1703 }
1704
1707 }
1708
1710 {
1713 jclass versionClass;
1714 jfieldID sdkIntFieldID;
1716
1717 versionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
1718 sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I");
1719 ret = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
1720 (*env)->DeleteLocalRef(env, versionClass);
1722 }