]> git.sesse.net Git - ffmpeg/blob - libavcodec/mediacodec_wrapper.c
Merge commit '18019f8cb9663dd1032c65aa453eaec18d641905'
[ffmpeg] / libavcodec / mediacodec_wrapper.c
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
23 #include <jni.h>
24
25 #include "libavutil/avassert.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/avstring.h"
28
29 #include "ffjni.h"
30 #include "version.h"
31 #include "mediacodec_wrapper.h"
32
33 struct JNIAMediaCodecListFields {
34
35     jclass mediaformat_class;
36     jmethodID create_video_format_id;
37
38     jclass mediacodec_list_class;
39     jmethodID init_id;
40     jmethodID find_decoder_for_format_id;
41
42     jmethodID get_codec_count_id;
43     jmethodID get_codec_info_at_id;
44
45     jclass mediacodec_info_class;
46     jmethodID get_name_id;
47     jmethodID get_supported_types_id;
48     jmethodID is_encoder_id;
49
50 } JNIAMediaCodecListFields;
51
52 static const struct FFJniField jfields_mapping[] = {
53     { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediaformat_class), 1 },
54         { "android/media/MediaFormat", "createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, create_video_format_id), 1 },
55
56     { "android/media/MediaCodecList", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediacodec_list_class), 1 },
57         { "android/media/MediaCodecList", "<init>", "(I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, init_id), 0 },
58         { "android/media/MediaCodecList", "findDecoderForFormat", "(Landroid/media/MediaFormat;)Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, find_decoder_for_format_id), 0 },
59
60         { "android/media/MediaCodecList", "getCodecCount", "()I", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_count_id), 1 },
61         { "android/media/MediaCodecList", "getCodecInfoAt", "(I)Landroid/media/MediaCodecInfo;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_info_at_id), 1 },
62
63     { "android/media/MediaCodecInfo", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, mediacodec_info_class), 1 },
64         { "android/media/MediaCodecInfo", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_name_id), 1 },
65         { "android/media/MediaCodecInfo", "getSupportedTypes", "()[Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_supported_types_id), 1 },
66         { "android/media/MediaCodecInfo", "isEncoder", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_encoder_id), 1 },
67
68     { NULL }
69 };
70
71 #define JNI_ATTACH_ENV_OR_RETURN(env, attached, log_ctx, ret) do { \
72     (env) = ff_jni_attach_env(attached, log_ctx);                  \
73     if (!(env)) {                                                  \
74         return ret;                                                \
75     }                                                              \
76 } while (0)
77
78 #define JNI_ATTACH_ENV_OR_RETURN_VOID(env, attached, log_ctx) do { \
79     (env) = ff_jni_attach_env(attached, log_ctx);              \
80     if (!(env)) {                                                  \
81         return;                                                    \
82     }                                                              \
83 } while (0)
84
85 #define JNI_DETACH_ENV(attached, log_ctx) do { \
86     if (attached)                              \
87         ff_jni_detach_env(log_ctx);            \
88 } while (0)
89
90 char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int width, int height, void *log_ctx)
91 {
92     int ret;
93     char *name = NULL;
94     char *supported_type = NULL;
95
96     int attached = 0;
97     JNIEnv *env = NULL;
98     struct JNIAMediaCodecListFields jfields = { 0 };
99
100     jobject format = NULL;
101     jobject codec = NULL;
102     jstring tmp = NULL;
103
104     jobject info = NULL;
105     jobject type = NULL;
106     jobjectArray types = NULL;
107
108     JNI_ATTACH_ENV_OR_RETURN(env, &attached, log_ctx, NULL);
109
110     if ((ret = ff_jni_init_jfields(env, &jfields, jfields_mapping, 0, log_ctx)) < 0) {
111         goto done;
112     }
113
114     if (jfields.init_id && jfields.find_decoder_for_format_id) {
115         tmp = ff_jni_utf_chars_to_jstring(env, mime, log_ctx);
116         if (!tmp) {
117             goto done;
118         }
119
120         format = (*env)->CallStaticObjectMethod(env, jfields.mediaformat_class, jfields.create_video_format_id, tmp, width, height);
121         if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
122             goto done;
123         }
124         (*env)->DeleteLocalRef(env, tmp);
125
126         codec = (*env)->NewObject(env, jfields.mediacodec_list_class, jfields.init_id, 0);
127         if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
128             goto done;
129         }
130
131         tmp = (*env)->CallObjectMethod(env, codec, jfields.find_decoder_for_format_id, format);
132         if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
133             goto done;
134         }
135         if (!tmp) {
136             av_log(NULL, AV_LOG_ERROR, "Could not find decoder in media codec list "
137                                        "for format { mime=%s width=%d height=%d }\n", mime, width, height);
138             goto done;
139         }
140
141         name = ff_jni_jstring_to_utf_chars(env, tmp, log_ctx);
142         if (!name) {
143             goto done;
144         }
145
146     } else {
147         int i;
148         int codec_count;
149
150         codec_count = (*env)->CallStaticIntMethod(env, jfields.mediacodec_list_class, jfields.get_codec_count_id);
151         if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
152             goto done;
153         }
154
155         for(i = 0; i < codec_count; i++) {
156             int j;
157             int type_count;
158             int is_encoder;
159
160             info = (*env)->CallStaticObjectMethod(env, jfields.mediacodec_list_class, jfields.get_codec_info_at_id, i);
161             if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
162                 goto done;
163             }
164
165             types = (*env)->CallObjectMethod(env, info, jfields.get_supported_types_id);
166             if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
167                 goto done;
168             }
169
170             is_encoder = (*env)->CallBooleanMethod(env, info, jfields.is_encoder_id);
171             if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
172                 goto done;
173             }
174
175             if (is_encoder) {
176                 continue;
177             }
178
179             type_count = (*env)->GetArrayLength(env, types);
180             for (j = 0; j < type_count; j++) {
181
182                 type = (*env)->GetObjectArrayElement(env, types, j);
183                 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
184                     goto done;
185                 }
186
187                 supported_type = ff_jni_jstring_to_utf_chars(env, type, log_ctx);
188                 if (!supported_type) {
189                     goto done;
190                 }
191
192                 if (!av_strcasecmp(supported_type, mime)) {
193                     jobject codec_name;
194
195                     codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
196                     if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
197                         goto done;
198                     }
199
200                     name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
201                     if (!name) {
202                         goto done;
203                     }
204
205                     if (strstr(name, "OMX.google")) {
206                         av_freep(&name);
207                         continue;
208                     }
209                 }
210
211                 av_freep(&supported_type);
212             }
213
214             (*env)->DeleteLocalRef(env, info);
215             info = NULL;
216
217             (*env)->DeleteLocalRef(env, types);
218             types = NULL;
219
220             if (name)
221                 break;
222         }
223     }
224
225 done:
226     if (format) {
227         (*env)->DeleteLocalRef(env, format);
228     }
229
230     if (codec) {
231         (*env)->DeleteLocalRef(env, codec);
232     }
233
234     if (tmp) {
235         (*env)->DeleteLocalRef(env, tmp);
236     }
237
238     if (info) {
239         (*env)->DeleteLocalRef(env, info);
240     }
241
242     if (type) {
243         (*env)->DeleteLocalRef(env, type);
244     }
245
246     if (types) {
247         (*env)->DeleteLocalRef(env, types);
248     }
249
250     av_freep(&supported_type);
251
252     ff_jni_reset_jfields(env, &jfields, jfields_mapping, 0, log_ctx);
253
254     JNI_DETACH_ENV(attached, log_ctx);
255
256     return name;
257 }
258
259 struct JNIAMediaFormatFields {
260
261     jclass clazz;
262
263     jmethodID init_id;
264
265     jmethodID get_integer_id;
266     jmethodID get_long_id;
267     jmethodID get_float_id;
268     jmethodID get_bytebuffer_id;
269     jmethodID get_string_id;
270
271     jmethodID set_integer_id;
272     jmethodID set_long_id;
273     jmethodID set_float_id;
274     jmethodID set_bytebuffer_id;
275     jmethodID set_string_id;
276
277     jmethodID to_string_id;
278
279 } JNIAMediaFormatFields;
280
281 static const struct FFJniField jni_amediaformat_mapping[] = {
282     { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaFormatFields, clazz), 1 },
283
284         { "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, init_id), 1 },
285
286         { "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_integer_id), 1 },
287         { "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_long_id), 1 },
288         { "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_float_id), 1 },
289         { "android/media/MediaFormat", "getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_bytebuffer_id), 1 },
290         { "android/media/MediaFormat", "getString", "(Ljava/lang/String;)Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_string_id), 1 },
291
292         { "android/media/MediaFormat", "setInteger", "(Ljava/lang/String;I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_integer_id), 1 },
293         { "android/media/MediaFormat", "setLong", "(Ljava/lang/String;J)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_long_id), 1 },
294         { "android/media/MediaFormat", "setFloat", "(Ljava/lang/String;F)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_float_id), 1 },
295         { "android/media/MediaFormat", "setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_bytebuffer_id), 1 },
296         { "android/media/MediaFormat", "setString", "(Ljava/lang/String;Ljava/lang/String;)V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, set_string_id), 1 },
297
298         { "android/media/MediaFormat", "toString", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, to_string_id), 1 },
299
300     { NULL }
301 };
302
303 static const AVClass amediaformat_class = {
304     .class_name = "amediaformat",
305     .item_name  = av_default_item_name,
306     .version    = LIBAVCODEC_VERSION_INT,
307 };
308
309 struct FFAMediaFormat {
310
311     const AVClass *class;
312     struct JNIAMediaFormatFields jfields;
313     jobject object;
314 };
315
316 FFAMediaFormat *ff_AMediaFormat_new(void)
317 {
318     int attached = 0;
319     JNIEnv *env = NULL;
320     FFAMediaFormat *format = NULL;
321
322     format = av_mallocz(sizeof(FFAMediaFormat));
323     if (!format) {
324         return NULL;
325     }
326     format->class = &amediaformat_class;
327
328     env = ff_jni_attach_env(&attached, format);
329     if (!env) {
330         av_freep(&format);
331         return NULL;
332     }
333
334     if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
335         goto fail;
336     }
337
338     format->object = (*env)->NewObject(env, format->jfields.clazz, format->jfields.init_id);
339     if (!format->object) {
340         goto fail;
341     }
342
343     format->object = (*env)->NewGlobalRef(env, format->object);
344     if (!format->object) {
345         goto fail;
346     }
347
348     JNI_DETACH_ENV(attached, format);
349
350     return format;
351 fail:
352     ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
353
354     JNI_DETACH_ENV(attached, format);
355
356     av_freep(&format);
357
358     return NULL;
359 }
360
361 static FFAMediaFormat *ff_AMediaFormat_newFromObject(void *object)
362 {
363     int attached = 0;
364     JNIEnv *env = NULL;
365     FFAMediaFormat *format = NULL;
366
367     format = av_mallocz(sizeof(FFAMediaFormat));
368     if (!format) {
369         return NULL;
370     }
371     format->class = &amediaformat_class;
372
373     env = ff_jni_attach_env(&attached, format);
374     if (!env) {
375         av_freep(&format);
376         return NULL;
377     }
378
379     if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
380         goto fail;
381     }
382
383     format->object = (*env)->NewGlobalRef(env, object);
384     if (!format->object) {
385         goto fail;
386     }
387
388     JNI_DETACH_ENV(attached, format);
389
390     return format;
391 fail:
392     ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
393
394     JNI_DETACH_ENV(attached, format);
395
396     av_freep(&format);
397
398     return NULL;
399 }
400
401 int ff_AMediaFormat_delete(FFAMediaFormat* format)
402 {
403     int ret = 0;
404
405     int attached = 0;
406     JNIEnv *env = NULL;
407
408     if (!format) {
409         return 0;
410     }
411
412     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, AVERROR_EXTERNAL);
413
414     (*env)->DeleteGlobalRef(env, format->object);
415     format->object = NULL;
416
417     ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
418
419     JNI_DETACH_ENV(attached, format);
420
421     av_freep(&format);
422
423     return ret;
424 }
425
426 char* ff_AMediaFormat_toString(FFAMediaFormat* format)
427 {
428     char *ret = NULL;
429
430     int attached = 0;
431     JNIEnv *env = NULL;
432     jstring description = NULL;
433
434     av_assert0(format != NULL);
435
436     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, NULL);
437
438     description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id);
439     if (ff_jni_exception_check(env, 1, NULL) < 0) {
440         goto fail;
441     }
442
443     ret = ff_jni_jstring_to_utf_chars(env, description, format);
444 fail:
445
446     if (description) {
447         (*env)->DeleteLocalRef(env, description);
448     }
449
450     JNI_DETACH_ENV(attached, format);
451
452     return ret;
453 }
454
455 int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *out)
456 {
457     int ret = 1;
458
459     int attached = 0;
460     JNIEnv *env = NULL;
461     jstring key = NULL;
462
463     av_assert0(format != NULL);
464
465     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
466
467     key = ff_jni_utf_chars_to_jstring(env, name, format);
468     if (!key) {
469         ret = 0;
470         goto fail;
471     }
472
473     *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
474     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
475         ret = 0;
476         goto fail;
477     }
478
479     ret = 1;
480 fail:
481     if (key) {
482         (*env)->DeleteLocalRef(env, key);
483     }
484
485     JNI_DETACH_ENV(attached, format);
486
487     return ret;
488 }
489
490 int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *out)
491 {
492     int ret = 1;
493
494     int attached = 0;
495     JNIEnv *env = NULL;
496     jstring key = NULL;
497
498     av_assert0(format != NULL);
499
500     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
501
502     key = ff_jni_utf_chars_to_jstring(env, name, format);
503     if (!key) {
504         ret = 0;
505         goto fail;
506     }
507
508     *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
509     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
510         ret = 0;
511         goto fail;
512     }
513
514     ret = 1;
515 fail:
516     if (key) {
517         (*env)->DeleteLocalRef(env, key);
518     }
519
520     JNI_DETACH_ENV(attached, format);
521
522     return ret;
523 }
524
525 int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *out)
526 {
527     int ret = 1;
528
529     int attached = 0;
530     JNIEnv *env = NULL;
531     jstring key = NULL;
532
533     av_assert0(format != NULL);
534
535     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
536
537     key = ff_jni_utf_chars_to_jstring(env, name, format);
538     if (!key) {
539         ret = 0;
540         goto fail;
541     }
542
543     *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
544     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
545         ret = 0;
546         goto fail;
547     }
548
549     ret = 1;
550 fail:
551     if (key) {
552         (*env)->DeleteLocalRef(env, key);
553     }
554
555     JNI_DETACH_ENV(attached, format);
556
557     return ret;
558 }
559
560 int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** data, size_t *size)
561 {
562     int ret = 1;
563
564     int attached = 0;
565     JNIEnv *env = NULL;
566     jstring key = NULL;
567     jobject result = NULL;
568
569     av_assert0(format != NULL);
570
571     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
572
573     key = ff_jni_utf_chars_to_jstring(env, name, format);
574     if (!key) {
575         ret = 0;
576         goto fail;
577     }
578
579     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
580     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
581         ret = 0;
582         goto fail;
583     }
584
585     *data = (*env)->GetDirectBufferAddress(env, result);
586     *size = (*env)->GetDirectBufferCapacity(env, result);
587
588     if (*data && *size) {
589         void *src = *data;
590         *data = av_malloc(*size);
591         if (!*data) {
592             ret = 0;
593             goto fail;
594         }
595
596         memcpy(*data, src, *size);
597     }
598
599     ret = 1;
600 fail:
601     if (key) {
602         (*env)->DeleteLocalRef(env, key);
603     }
604
605     if (result) {
606         (*env)->DeleteLocalRef(env, result);
607     }
608
609     JNI_DETACH_ENV(attached, format);
610
611     return ret;
612 }
613
614 int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const char **out)
615 {
616     int ret = 1;
617
618     int attached = 0;
619     JNIEnv *env = NULL;
620     jstring key = NULL;
621     jstring result = NULL;
622
623     av_assert0(format != NULL);
624
625     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
626
627     key = ff_jni_utf_chars_to_jstring(env, name, format);
628     if (!key) {
629         ret = 0;
630         goto fail;
631     }
632
633     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
634     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
635         ret = 0;
636         goto fail;
637     }
638
639     *out = ff_jni_jstring_to_utf_chars(env, result, format);
640     if (!*out) {
641         ret = 0;
642         goto fail;
643     }
644
645     ret = 1;
646 fail:
647     if (key) {
648         (*env)->DeleteLocalRef(env, key);
649     }
650
651     if (result) {
652         (*env)->DeleteLocalRef(env, result);
653     }
654
655     JNI_DETACH_ENV(attached, format);
656
657     return ret;
658 }
659
660 void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value)
661 {
662     int attached = 0;
663     JNIEnv *env = NULL;
664     jstring key = NULL;
665
666     av_assert0(format != NULL);
667
668     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
669
670     key = ff_jni_utf_chars_to_jstring(env, name, format);
671     if (!key) {
672         goto fail;
673     }
674
675     (*env)->CallVoidMethod(env, format->object, format->jfields.set_integer_id, key, value);
676     if (ff_jni_exception_check(env, 1, format) < 0) {
677         goto fail;
678     }
679
680 fail:
681     if (key) {
682         (*env)->DeleteLocalRef(env, key);
683     }
684
685     JNI_DETACH_ENV(attached, format);
686 }
687
688 void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value)
689 {
690     int attached = 0;
691     JNIEnv *env = NULL;
692     jstring key = NULL;
693
694     av_assert0(format != NULL);
695
696     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
697
698     key = ff_jni_utf_chars_to_jstring(env, name, format);
699     if (!key) {
700         goto fail;
701     }
702
703     (*env)->CallVoidMethod(env, format->object, format->jfields.set_long_id, key, value);
704     if (ff_jni_exception_check(env, 1, format) < 0) {
705         goto fail;
706     }
707
708 fail:
709     if (key) {
710         (*env)->DeleteLocalRef(env, key);
711     }
712
713     JNI_DETACH_ENV(attached, NULL);
714 }
715
716 void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value)
717 {
718     int attached = 0;
719     JNIEnv *env = NULL;
720     jstring key = NULL;
721
722     av_assert0(format != NULL);
723
724     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
725
726     key = ff_jni_utf_chars_to_jstring(env, name, format);
727     if (!key) {
728         goto fail;
729     }
730
731     (*env)->CallVoidMethod(env, format->object, format->jfields.set_float_id, key, value);
732     if (ff_jni_exception_check(env, 1, format) < 0) {
733         goto fail;
734     }
735
736 fail:
737     if (key) {
738         (*env)->DeleteLocalRef(env, key);
739     }
740
741     JNI_DETACH_ENV(attached, NULL);
742 }
743
744 void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value)
745 {
746     int attached = 0;
747     JNIEnv *env = NULL;
748     jstring key = NULL;
749     jstring string = NULL;
750
751     av_assert0(format != NULL);
752
753     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
754
755     key = ff_jni_utf_chars_to_jstring(env, name, format);
756     if (!key) {
757         goto fail;
758     }
759
760     string = ff_jni_utf_chars_to_jstring(env, value, format);
761     if (!string) {
762         goto fail;
763     }
764
765     (*env)->CallVoidMethod(env, format->object, format->jfields.set_string_id, key, string);
766     if (ff_jni_exception_check(env, 1, format) < 0) {
767         goto fail;
768     }
769
770 fail:
771     if (key) {
772         (*env)->DeleteLocalRef(env, key);
773     }
774
775     if (string) {
776         (*env)->DeleteLocalRef(env, string);
777     }
778
779     JNI_DETACH_ENV(attached, format);
780 }
781
782 void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size)
783 {
784     int attached = 0;
785     JNIEnv *env = NULL;
786     jstring key = NULL;
787     jobject buffer = NULL;
788     void *buffer_data = NULL;
789
790     av_assert0(format != NULL);
791
792     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
793
794     key = ff_jni_utf_chars_to_jstring(env, name, format);
795     if (!key) {
796         goto fail;
797     }
798
799     if (!data || !size) {
800         goto fail;
801     }
802
803     buffer_data = av_malloc(size);
804     if (!buffer_data) {
805         goto fail;
806     }
807
808     memcpy(buffer_data, data, size);
809
810     buffer = (*env)->NewDirectByteBuffer(env, buffer_data, size);
811     if (!buffer) {
812         goto fail;
813     }
814
815     (*env)->CallVoidMethod(env, format->object, format->jfields.set_bytebuffer_id, key, buffer);
816     if (ff_jni_exception_check(env, 1, format) < 0) {
817         goto fail;
818     }
819
820 fail:
821     if (key) {
822         (*env)->DeleteLocalRef(env, key);
823     }
824
825     if (buffer) {
826         (*env)->DeleteLocalRef(env, buffer);
827     }
828
829     JNI_DETACH_ENV(attached, format);
830 }
831
832 struct JNIAMediaCodecFields {
833
834     jclass mediacodec_class;
835
836     jfieldID info_try_again_later_id;
837     jfieldID info_output_buffers_changed_id;
838     jfieldID info_output_format_changed_id;
839
840     jfieldID buffer_flag_codec_config_id;
841     jfieldID buffer_flag_end_of_stream_id;
842     jfieldID buffer_flag_key_frame_id;
843
844     jfieldID configure_flag_encode_id;
845
846     jmethodID create_by_codec_name_id;
847     jmethodID create_decoder_by_type_id;
848     jmethodID create_encoder_by_type_id;
849
850     jmethodID get_name_id;
851
852     jmethodID configure_id;
853     jmethodID start_id;
854     jmethodID flush_id;
855     jmethodID stop_id;
856     jmethodID release_id;
857
858     jmethodID get_output_format_id;
859
860     jmethodID dequeue_input_buffer_id;
861     jmethodID queue_input_buffer_id;
862     jmethodID get_input_buffer_id;
863     jmethodID get_input_buffers_id;
864
865     jmethodID dequeue_output_buffer_id;
866     jmethodID get_output_buffer_id;
867     jmethodID get_output_buffers_id;
868     jmethodID release_output_buffer_id;
869     jmethodID release_output_buffer_at_time_id;
870
871     jclass mediainfo_class;
872
873     jmethodID init_id;
874
875     jfieldID flags_id;
876     jfieldID offset_id;
877     jfieldID presentation_time_us_id;
878     jfieldID size_id;
879
880 } JNIAMediaCodecFields;
881
882 static const struct FFJniField jni_amediacodec_mapping[] = {
883     { "android/media/MediaCodec", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediacodec_class), 1 },
884
885         { "android/media/MediaCodec", "INFO_TRY_AGAIN_LATER", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_try_again_later_id), 1 },
886         { "android/media/MediaCodec", "INFO_OUTPUT_BUFFERS_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_buffers_changed_id), 1 },
887         { "android/media/MediaCodec", "INFO_OUTPUT_FORMAT_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_format_changed_id), 1 },
888
889         { "android/media/MediaCodec", "BUFFER_FLAG_CODEC_CONFIG", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_codec_config_id), 1 },
890         { "android/media/MediaCodec", "BUFFER_FLAG_END_OF_STREAM", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_end_of_stream_id), 1 },
891         { "android/media/MediaCodec", "BUFFER_FLAG_KEY_FRAME", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_key_frame_id), 0 },
892
893         { "android/media/MediaCodec", "CONFIGURE_FLAG_ENCODE", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, configure_flag_encode_id), 1 },
894
895         { "android/media/MediaCodec", "createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_by_codec_name_id), 1 },
896         { "android/media/MediaCodec", "createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_decoder_by_type_id), 1 },
897         { "android/media/MediaCodec", "createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_encoder_by_type_id), 1 },
898
899         { "android/media/MediaCodec", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_name_id), 1 },
900
901         { "android/media/MediaCodec", "configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, configure_id), 1 },
902         { "android/media/MediaCodec", "start", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, start_id), 1 },
903         { "android/media/MediaCodec", "flush", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, flush_id), 1 },
904         { "android/media/MediaCodec", "stop", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, stop_id), 1 },
905         { "android/media/MediaCodec", "release", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_id), 1 },
906
907         { "android/media/MediaCodec", "getOutputFormat", "()Landroid/media/MediaFormat;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_format_id), 1 },
908
909         { "android/media/MediaCodec", "dequeueInputBuffer", "(J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_input_buffer_id), 1 },
910         { "android/media/MediaCodec", "queueInputBuffer", "(IIIJI)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, queue_input_buffer_id), 1 },
911         { "android/media/MediaCodec", "getInputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffer_id), 0 },
912         { "android/media/MediaCodec", "getInputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffers_id), 1 },
913
914         { "android/media/MediaCodec", "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_output_buffer_id), 1 },
915         { "android/media/MediaCodec", "getOutputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffer_id), 0 },
916         { "android/media/MediaCodec", "getOutputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffers_id), 1 },
917         { "android/media/MediaCodec", "releaseOutputBuffer", "(IZ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_id), 1 },
918         { "android/media/MediaCodec", "releaseOutputBuffer", "(IJ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_at_time_id), 0 },
919
920     { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediainfo_class), 1 },
921
922         { "android/media/MediaCodec.BufferInfo", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, init_id), 1 },
923         { "android/media/MediaCodec.BufferInfo", "flags", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, flags_id), 1 },
924         { "android/media/MediaCodec.BufferInfo", "offset", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, offset_id), 1 },
925         { "android/media/MediaCodec.BufferInfo", "presentationTimeUs", "J", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, presentation_time_us_id), 1 },
926         { "android/media/MediaCodec.BufferInfo", "size", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, size_id), 1 },
927
928     { NULL }
929 };
930
931 static const AVClass amediacodec_class = {
932     .class_name = "amediacodec",
933     .item_name  = av_default_item_name,
934     .version    = LIBAVCODEC_VERSION_INT,
935 };
936
937 struct FFAMediaCodec {
938
939     const AVClass *class;
940
941     struct JNIAMediaCodecFields jfields;
942
943     jobject object;
944
945     jobject input_buffers;
946     jobject output_buffers;
947
948     int INFO_TRY_AGAIN_LATER;
949     int INFO_OUTPUT_BUFFERS_CHANGED;
950     int INFO_OUTPUT_FORMAT_CHANGED;
951
952     int BUFFER_FLAG_CODEC_CONFIG;
953     int BUFFER_FLAG_END_OF_STREAM;
954     int BUFFER_FLAG_KEY_FRAME;
955
956     int CONFIGURE_FLAG_ENCODE;
957
958     int has_get_i_o_buffer;
959 };
960
961 FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name)
962 {
963     int attached = 0;
964     JNIEnv *env = NULL;
965     FFAMediaCodec *codec = NULL;
966     jstring codec_name = NULL;
967
968     codec = av_mallocz(sizeof(FFAMediaCodec));
969     if (!codec) {
970         return NULL;
971     }
972     codec->class = &amediacodec_class;
973
974     env = ff_jni_attach_env(&attached, codec);
975     if (!env) {
976         av_freep(&codec);
977         return NULL;
978     }
979
980     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
981         goto fail;
982     }
983
984     codec_name = ff_jni_utf_chars_to_jstring(env, name, codec);
985     if (!codec_name) {
986         goto fail;
987     }
988
989     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name);
990     if (ff_jni_exception_check(env, 1, codec) < 0) {
991         goto fail;
992     }
993
994     codec->object = (*env)->NewGlobalRef(env, codec->object);
995     if (!codec->object) {
996         goto fail;
997     }
998
999     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1000     if (ff_jni_exception_check(env, 1, codec) < 0) {
1001         goto fail;
1002     }
1003
1004     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1005     if (ff_jni_exception_check(env, 1, codec) < 0) {
1006         goto fail;
1007     }
1008
1009     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1010     if (ff_jni_exception_check(env, 1, codec) < 0) {
1011         goto fail;
1012     }
1013
1014     if (codec->jfields.buffer_flag_key_frame_id) {
1015         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1016         if (ff_jni_exception_check(env, 1, codec) < 0) {
1017             goto fail;
1018         }
1019     }
1020
1021     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1022     if (ff_jni_exception_check(env, 1, codec) < 0) {
1023         goto fail;
1024     }
1025
1026     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1027     if (ff_jni_exception_check(env, 1, codec) < 0) {
1028         goto fail;
1029     }
1030
1031     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1032     if (ff_jni_exception_check(env, 1, codec) < 0) {
1033         goto fail;
1034     }
1035
1036     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1037     if (ff_jni_exception_check(env, 1, codec) < 0) {
1038         goto fail;
1039     }
1040
1041     JNI_DETACH_ENV(attached, codec);
1042
1043     return codec;
1044 fail:
1045     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1046
1047     if (codec_name) {
1048         (*env)->DeleteLocalRef(env, codec_name);
1049     }
1050
1051     JNI_DETACH_ENV(attached, codec);
1052
1053     av_freep(&codec);
1054
1055     return NULL;
1056 }
1057
1058 FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime)
1059 {
1060     int attached = 0;
1061     JNIEnv *env = NULL;
1062     FFAMediaCodec *codec = NULL;
1063     jstring mime_type = NULL;
1064
1065     codec = av_mallocz(sizeof(FFAMediaCodec));
1066     if (!codec) {
1067         return NULL;
1068     }
1069     codec->class = &amediacodec_class;
1070
1071     env = ff_jni_attach_env(&attached, codec);
1072     if (!env) {
1073         av_freep(&codec);
1074         return NULL;
1075     }
1076
1077     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1078         goto fail;
1079     }
1080
1081     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1082     if (!mime_type) {
1083         goto fail;
1084     }
1085
1086     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type);
1087     if (ff_jni_exception_check(env, 1, codec) < 0) {
1088         goto fail;
1089     }
1090
1091     codec->object = (*env)->NewGlobalRef(env, codec->object);
1092     if (!codec->object) {
1093         goto fail;
1094     }
1095
1096     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1097     if (ff_jni_exception_check(env, 1, codec) < 0) {
1098         goto fail;
1099     }
1100
1101     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1102     if (ff_jni_exception_check(env, 1, codec) < 0) {
1103         goto fail;
1104     }
1105
1106     if (codec->jfields.buffer_flag_key_frame_id) {
1107         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1108         if (ff_jni_exception_check(env, 1, codec) < 0) {
1109             goto fail;
1110         }
1111     }
1112
1113     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1114     if (ff_jni_exception_check(env, 1, codec) < 0) {
1115         goto fail;
1116     }
1117
1118     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1119     if (ff_jni_exception_check(env, 1, codec) < 0) {
1120         goto fail;
1121     }
1122
1123     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1124     if (ff_jni_exception_check(env, 1, codec) < 0) {
1125         goto fail;
1126     }
1127
1128     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1129     if (ff_jni_exception_check(env, 1, codec) < 0) {
1130         goto fail;
1131     }
1132
1133     if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) {
1134         codec->has_get_i_o_buffer = 1;
1135     }
1136
1137     JNI_DETACH_ENV(attached, codec);
1138
1139     return codec;
1140 fail:
1141     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1142
1143     if (mime_type) {
1144         (*env)->DeleteLocalRef(env, mime_type);
1145     }
1146
1147     JNI_DETACH_ENV(attached, codec);
1148
1149     av_freep(&codec);
1150
1151     return NULL;
1152 }
1153
1154 FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime)
1155 {
1156     int attached = 0;
1157     JNIEnv *env = NULL;
1158     FFAMediaCodec *codec = NULL;
1159     jstring mime_type = NULL;
1160
1161     codec = av_mallocz(sizeof(FFAMediaCodec));
1162     if (!codec) {
1163         return NULL;
1164     }
1165     codec->class = &amediacodec_class;
1166
1167     env = ff_jni_attach_env(&attached, codec);
1168     if (!env) {
1169         av_freep(&codec);
1170         return NULL;
1171     }
1172
1173     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1174         goto fail;
1175     }
1176
1177     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1178     if (!mime_type) {
1179         goto fail;
1180     }
1181
1182     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type);
1183     if (ff_jni_exception_check(env, 1, codec) < 0) {
1184         goto fail;
1185     }
1186
1187     codec->object = (*env)->NewGlobalRef(env, codec->object);
1188     if (!codec->object) {
1189         goto fail;
1190     }
1191
1192     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1193     if (ff_jni_exception_check(env, 1, codec) < 0) {
1194         goto fail;
1195     }
1196
1197     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1198     if (ff_jni_exception_check(env, 1, codec) < 0) {
1199         goto fail;
1200     }
1201
1202     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1203     if (ff_jni_exception_check(env, 1, codec) < 0) {
1204         goto fail;
1205     }
1206
1207     if (codec->jfields.buffer_flag_key_frame_id) {
1208         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1209         if (ff_jni_exception_check(env, 1, codec) < 0) {
1210             goto fail;
1211         }
1212     }
1213
1214     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1215     if (ff_jni_exception_check(env, 1, codec) < 0) {
1216         goto fail;
1217     }
1218
1219     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1220     if (ff_jni_exception_check(env, 1, codec) < 0) {
1221         goto fail;
1222     }
1223
1224     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1225     if (ff_jni_exception_check(env, 1, codec) < 0) {
1226         goto fail;
1227     }
1228
1229     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1230     if (ff_jni_exception_check(env, 1, codec) < 0) {
1231         goto fail;
1232     }
1233
1234     JNI_DETACH_ENV(attached, NULL);
1235
1236     return codec;
1237 fail:
1238     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1239
1240     if (mime_type) {
1241         (*env)->DeleteLocalRef(env, mime_type);
1242     }
1243
1244     JNI_DETACH_ENV(attached, codec);
1245
1246     av_freep(&codec);
1247
1248     return NULL;
1249 }
1250
1251 int ff_AMediaCodec_delete(FFAMediaCodec* codec)
1252 {
1253     int ret = 0;
1254
1255     int attached = 0;
1256     JNIEnv *env = NULL;
1257
1258     if (!codec) {
1259         return 0;
1260     }
1261
1262     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1263
1264     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1265     if (ff_jni_exception_check(env, 1, codec) < 0) {
1266         ret = AVERROR_EXTERNAL;
1267     }
1268
1269     (*env)->DeleteGlobalRef(env, codec->object);
1270     codec->object = NULL;
1271
1272     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1273
1274     JNI_DETACH_ENV(attached, codec);
1275
1276     av_freep(&codec);
1277
1278     return ret;
1279 }
1280
1281 char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
1282 {
1283     char *ret = NULL;
1284     int attached = 0;
1285     JNIEnv *env = NULL;
1286     jobject *name = NULL;
1287
1288     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1289
1290     name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
1291     if (ff_jni_exception_check(env, 1, codec) < 0) {
1292         goto fail;
1293     }
1294
1295     ret = ff_jni_jstring_to_utf_chars(env, name, codec);
1296
1297 fail:
1298     JNI_DETACH_ENV(attached, NULL);
1299
1300     return ret;
1301 }
1302
1303 int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags)
1304 {
1305     int ret = 0;
1306     int attached = 0;
1307     JNIEnv *env = NULL;
1308
1309     /* TODO: implement surface handling */
1310     av_assert0(surface == NULL);
1311
1312     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1313
1314     (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1315     if (ff_jni_exception_check(env, 1, codec) < 0) {
1316         ret = AVERROR_EXTERNAL;
1317         goto fail;
1318     }
1319
1320 fail:
1321     JNI_DETACH_ENV(attached, NULL);
1322
1323     return ret;
1324 }
1325
1326 int ff_AMediaCodec_start(FFAMediaCodec* codec)
1327 {
1328     int ret = 0;
1329     int attached = 0;
1330     JNIEnv *env = NULL;
1331
1332     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1333
1334     (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
1335     if (ff_jni_exception_check(env, 1, codec) < 0) {
1336         ret = AVERROR_EXTERNAL;
1337         goto fail;
1338     }
1339
1340 fail:
1341     JNI_DETACH_ENV(attached, codec);
1342
1343     return ret;
1344 }
1345
1346 int ff_AMediaCodec_stop(FFAMediaCodec* codec)
1347 {
1348     int ret = 0;
1349     int attached = 0;
1350     JNIEnv *env = NULL;
1351
1352     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1353
1354     (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
1355     if (ff_jni_exception_check(env, 1, codec) < 0) {
1356         ret = AVERROR_EXTERNAL;
1357         goto fail;
1358     }
1359
1360 fail:
1361     JNI_DETACH_ENV(attached, codec);
1362
1363     return ret;
1364 }
1365
1366 int ff_AMediaCodec_flush(FFAMediaCodec* codec)
1367 {
1368     int ret = 0;
1369     int attached = 0;
1370     JNIEnv *env = NULL;
1371
1372     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1373
1374     (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
1375     if (ff_jni_exception_check(env, 1, codec) < 0) {
1376         ret = AVERROR_EXTERNAL;
1377         goto fail;
1378     }
1379
1380 fail:
1381     JNI_DETACH_ENV(attached, codec);
1382
1383     return ret;
1384 }
1385
1386 int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render)
1387 {
1388     int ret = 0;
1389     int attached = 0;
1390     JNIEnv *env = NULL;
1391
1392     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1393
1394     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, idx, render);
1395     if (ff_jni_exception_check(env, 1, codec) < 0) {
1396         ret = AVERROR_EXTERNAL;
1397         goto fail;
1398     }
1399
1400 fail:
1401     JNI_DETACH_ENV(attached, codec);
1402
1403     return ret;
1404 }
1405
1406 int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs)
1407 {
1408     int ret = 0;
1409     int attached = 0;
1410     JNIEnv *env = NULL;
1411
1412     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1413
1414     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, idx, timestampNs);
1415     if (ff_jni_exception_check(env, 1, codec) < 0) {
1416         ret = AVERROR_EXTERNAL;
1417         goto fail;
1418     }
1419
1420 fail:
1421     JNI_DETACH_ENV(attached, codec);
1422
1423     return ret;
1424 }
1425
1426 ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs)
1427 {
1428     int ret = 0;
1429     int attached = 0;
1430     JNIEnv *env = NULL;
1431
1432     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1433
1434     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
1435     if (ff_jni_exception_check(env, 1, codec) < 0) {
1436         ret = AVERROR_EXTERNAL;
1437         goto fail;
1438     }
1439
1440 fail:
1441     JNI_DETACH_ENV(attached, codec);
1442
1443     return ret;
1444 }
1445
1446 int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
1447 {
1448     int ret = 0;
1449     int attached = 0;
1450     JNIEnv *env = NULL;
1451
1452     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1453
1454     (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, idx, offset, size, time, flags);
1455     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1456         ret = AVERROR_EXTERNAL;
1457         goto fail;
1458     }
1459
1460 fail:
1461     JNI_DETACH_ENV(attached, codec);
1462
1463     return ret;
1464 }
1465
1466 ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
1467 {
1468     int ret = 0;
1469     int attached = 0;
1470     JNIEnv *env = NULL;
1471
1472     jobject mediainfo = NULL;
1473
1474     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1475
1476     mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
1477     if (ff_jni_exception_check(env, 1, codec) < 0) {
1478         ret = AVERROR_EXTERNAL;
1479         goto fail;
1480     }
1481
1482     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
1483     if (ff_jni_exception_check(env, 1, codec) < 0) {
1484         ret = AVERROR_EXTERNAL;
1485         goto fail;
1486     }
1487
1488     info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
1489     if (ff_jni_exception_check(env, 1, codec) < 0) {
1490         ret = AVERROR_EXTERNAL;
1491         goto fail;
1492     }
1493
1494     info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
1495     if (ff_jni_exception_check(env, 1, codec) < 0) {
1496         ret = AVERROR_EXTERNAL;
1497         goto fail;
1498     }
1499
1500     info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
1501     if (ff_jni_exception_check(env, 1, codec) < 0) {
1502         ret = AVERROR_EXTERNAL;
1503         goto fail;
1504     }
1505
1506     info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
1507     if (ff_jni_exception_check(env, 1, codec) < 0) {
1508         ret = AVERROR_EXTERNAL;
1509         goto fail;
1510     }
1511 fail:
1512     if (mediainfo) {
1513         (*env)->DeleteLocalRef(env, mediainfo);
1514     }
1515
1516     JNI_DETACH_ENV(attached, NULL);
1517
1518     return ret;
1519 }
1520
1521 uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1522 {
1523     uint8_t *ret = NULL;
1524     int attached = 0;
1525     JNIEnv *env = NULL;
1526
1527     jobject buffer = NULL;
1528
1529     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1530
1531     if (codec->has_get_i_o_buffer) {
1532         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, idx);
1533         if (ff_jni_exception_check(env, 1, codec) < 0) {
1534             goto fail;
1535         }
1536     } else {
1537         if (!codec->input_buffers) {
1538             codec->input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
1539             if (ff_jni_exception_check(env, 1, codec) < 0) {
1540                 goto fail;
1541             }
1542
1543             codec->input_buffers = (*env)->NewGlobalRef(env, codec->input_buffers);
1544             if (ff_jni_exception_check(env, 1, codec) < 0) {
1545                 goto fail;
1546             }
1547         }
1548
1549         buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
1550         if (ff_jni_exception_check(env, 1, codec) < 0) {
1551             goto fail;
1552         }
1553     }
1554
1555     ret = (*env)->GetDirectBufferAddress(env, buffer);
1556     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1557 fail:
1558     if (buffer) {
1559         (*env)->DeleteLocalRef(env, buffer);
1560     }
1561
1562     JNI_DETACH_ENV(attached, codec);
1563
1564     return ret;
1565 }
1566
1567 uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1568 {
1569     uint8_t *ret = NULL;
1570     int attached = 0;
1571     JNIEnv *env = NULL;
1572
1573     jobject buffer = NULL;
1574
1575     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1576
1577     if (codec->has_get_i_o_buffer) {
1578         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, idx);
1579         if (ff_jni_exception_check(env, 1, codec) < 0) {
1580             goto fail;
1581         }
1582     } else {
1583         if (!codec->output_buffers) {
1584             codec->output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
1585             if (ff_jni_exception_check(env, 1, codec) < 0) {
1586                 goto fail;
1587             }
1588
1589             codec->output_buffers = (*env)->NewGlobalRef(env, codec->output_buffers);
1590             if (ff_jni_exception_check(env, 1, codec) < 0) {
1591                 goto fail;
1592             }
1593         }
1594
1595         buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
1596         if (ff_jni_exception_check(env, 1, codec) < 0) {
1597             goto fail;
1598         }
1599     }
1600
1601     ret = (*env)->GetDirectBufferAddress(env, buffer);
1602     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1603 fail:
1604     if (buffer) {
1605         (*env)->DeleteLocalRef(env, buffer);
1606     }
1607
1608     JNI_DETACH_ENV(attached, codec);
1609
1610     return ret;
1611 }
1612
1613 FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec)
1614 {
1615     FFAMediaFormat *ret = NULL;
1616     int attached = 0;
1617     JNIEnv *env = NULL;
1618
1619     jobject mediaformat = NULL;
1620
1621     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1622
1623     mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
1624     if (ff_jni_exception_check(env, 1, codec) < 0) {
1625         goto fail;
1626     }
1627
1628     ret = ff_AMediaFormat_newFromObject(mediaformat);
1629 fail:
1630     if (mediaformat) {
1631         (*env)->DeleteLocalRef(env, mediaformat);
1632     }
1633
1634     JNI_DETACH_ENV(attached, codec);
1635
1636     return ret;
1637 }
1638
1639 int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx)
1640 {
1641     return idx == codec->INFO_TRY_AGAIN_LATER;
1642 }
1643
1644 int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx)
1645 {
1646     return idx == codec->INFO_OUTPUT_BUFFERS_CHANGED;
1647 }
1648
1649 int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t idx)
1650 {
1651     return idx == codec->INFO_OUTPUT_FORMAT_CHANGED;
1652 }
1653
1654 int ff_AMediaCodec_getBufferFlagCodecConfig(FFAMediaCodec *codec)
1655 {
1656     return codec->BUFFER_FLAG_CODEC_CONFIG;
1657 }
1658
1659 int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec)
1660 {
1661     return codec->BUFFER_FLAG_END_OF_STREAM;
1662 }
1663
1664 int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec)
1665 {
1666     return codec->BUFFER_FLAG_KEY_FRAME;
1667 }
1668
1669 int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec)
1670 {
1671     return codec->CONFIGURE_FLAG_ENCODE;
1672 }
1673
1674 int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
1675 {
1676     int ret = 0;
1677
1678     if (!codec->has_get_i_o_buffer) {
1679         if (codec->output_buffers) {
1680             int attached = 0;
1681             JNIEnv *env = NULL;
1682
1683             env = ff_jni_attach_env(&attached, codec);
1684             if (!env) {
1685                 ret = AVERROR_EXTERNAL;
1686                 goto fail;
1687             }
1688
1689             (*env)->DeleteGlobalRef(env, codec->output_buffers);
1690             codec->output_buffers = NULL;
1691
1692             JNI_DETACH_ENV(attached, codec);
1693         }
1694     }
1695
1696 fail:
1697     return ret;
1698 }