lavc: add h264 mediacodec decoder
[ffmpeg.git] / 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
402 int ff_AMediaFormat_delete(FFAMediaFormat* format)
403 {
404     int ret = 0;
405
406     int attached = 0;
407     JNIEnv *env = NULL;
408
409     if (!format) {
410         return 0;
411     }
412
413     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, AVERROR_EXTERNAL);
414
415     (*env)->DeleteGlobalRef(env, format->object);
416     format->object = NULL;
417
418     ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
419
420     JNI_DETACH_ENV(attached, format);
421
422     av_freep(&format);
423
424     return ret;
425 }
426
427 char* ff_AMediaFormat_toString(FFAMediaFormat* format)
428 {
429     char *ret = NULL;
430
431     int attached = 0;
432     JNIEnv *env = NULL;
433     jstring description = NULL;
434
435     av_assert0(format != NULL);
436
437     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, NULL);
438
439     description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id);
440     if (ff_jni_exception_check(env, 1, NULL) < 0) {
441         goto fail;
442     }
443
444     ret = ff_jni_jstring_to_utf_chars(env, description, format);
445 fail:
446
447     if (description) {
448         (*env)->DeleteLocalRef(env, description);
449     }
450
451     JNI_DETACH_ENV(attached, format);
452
453     return ret;
454 }
455
456 int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *out)
457 {
458     int ret = 1;
459
460     int attached = 0;
461     JNIEnv *env = NULL;
462     jstring key = NULL;
463
464     av_assert0(format != NULL);
465
466     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
467
468     key = ff_jni_utf_chars_to_jstring(env, name, format);
469     if (!key) {
470         ret = 0;
471         goto fail;
472     }
473
474     *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
475     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
476         ret = 0;
477         goto fail;
478     }
479
480     ret = 1;
481 fail:
482     if (key) {
483         (*env)->DeleteLocalRef(env, key);
484     }
485
486     JNI_DETACH_ENV(attached, format);
487
488     return ret;
489 }
490
491 int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *out)
492 {
493     int ret = 1;
494
495     int attached = 0;
496     JNIEnv *env = NULL;
497     jstring key = NULL;
498
499     av_assert0(format != NULL);
500
501     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
502
503     key = ff_jni_utf_chars_to_jstring(env, name, format);
504     if (!key) {
505         ret = 0;
506         goto fail;
507     }
508
509     *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
510     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
511         ret = 0;
512         goto fail;
513     }
514
515     ret = 1;
516 fail:
517     if (key) {
518         (*env)->DeleteLocalRef(env, key);
519     }
520
521     JNI_DETACH_ENV(attached, format);
522
523     return ret;
524 }
525
526 int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *out)
527 {
528     int ret = 1;
529
530     int attached = 0;
531     JNIEnv *env = NULL;
532     jstring key = NULL;
533
534     av_assert0(format != NULL);
535
536     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
537
538     key = ff_jni_utf_chars_to_jstring(env, name, format);
539     if (!key) {
540         ret = 0;
541         goto fail;
542     }
543
544     *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
545     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
546         ret = 0;
547         goto fail;
548     }
549
550     ret = 1;
551 fail:
552     if (key) {
553         (*env)->DeleteLocalRef(env, key);
554     }
555
556     JNI_DETACH_ENV(attached, format);
557
558     return ret;
559 }
560
561 int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** data, size_t *size)
562 {
563     int ret = 1;
564
565     int attached = 0;
566     JNIEnv *env = NULL;
567     jstring key = NULL;
568     jobject result = NULL;
569
570     av_assert0(format != NULL);
571
572     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
573
574     key = ff_jni_utf_chars_to_jstring(env, name, format);
575     if (!key) {
576         ret = 0;
577         goto fail;
578     }
579
580     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
581     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
582         ret = 0;
583         goto fail;
584     }
585
586     *data = (*env)->GetDirectBufferAddress(env, result);
587     *size = (*env)->GetDirectBufferCapacity(env, result);
588
589     if (*data && *size) {
590         void *src = *data;
591         *data = av_malloc(*size);
592         if (!*data) {
593             ret = 0;
594             goto fail;
595         }
596
597         memcpy(*data, src, *size);
598     }
599
600     ret = 1;
601 fail:
602     if (key) {
603         (*env)->DeleteLocalRef(env, key);
604     }
605
606     if (result) {
607         (*env)->DeleteLocalRef(env, result);
608     }
609
610     JNI_DETACH_ENV(attached, format);
611
612     return ret;
613 }
614
615 int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const char **out)
616 {
617     int ret = 1;
618
619     int attached = 0;
620     JNIEnv *env = NULL;
621     jstring key = NULL;
622     jstring result = NULL;
623
624     av_assert0(format != NULL);
625
626     JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0);
627
628     key = ff_jni_utf_chars_to_jstring(env, name, format);
629     if (!key) {
630         ret = 0;
631         goto fail;
632     }
633
634     result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
635     if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
636         ret = 0;
637         goto fail;
638     }
639
640     *out = ff_jni_jstring_to_utf_chars(env, result, format);
641     if (!*out) {
642         ret = 0;
643         goto fail;
644     }
645
646     ret = 1;
647 fail:
648     if (key) {
649         (*env)->DeleteLocalRef(env, key);
650     }
651
652     if (result) {
653         (*env)->DeleteLocalRef(env, result);
654     }
655
656     JNI_DETACH_ENV(attached, format);
657
658     return ret;
659 }
660
661
662 void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value)
663 {
664     int attached = 0;
665     JNIEnv *env = NULL;
666     jstring key = NULL;
667
668     av_assert0(format != NULL);
669
670     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
671
672     key = ff_jni_utf_chars_to_jstring(env, name, format);
673     if (!key) {
674         goto fail;
675     }
676
677     (*env)->CallVoidMethod(env, format->object, format->jfields.set_integer_id, key, value);
678     if (ff_jni_exception_check(env, 1, format) < 0) {
679         goto fail;
680     }
681
682 fail:
683     if (key) {
684         (*env)->DeleteLocalRef(env, key);
685     }
686
687     JNI_DETACH_ENV(attached, format);
688 }
689
690 void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value)
691 {
692     int attached = 0;
693     JNIEnv *env = NULL;
694     jstring key = NULL;
695
696     av_assert0(format != NULL);
697
698     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
699
700     key = ff_jni_utf_chars_to_jstring(env, name, format);
701     if (!key) {
702         goto fail;
703     }
704
705     (*env)->CallVoidMethod(env, format->object, format->jfields.set_long_id, key, value);
706     if (ff_jni_exception_check(env, 1, format) < 0) {
707         goto fail;
708     }
709
710 fail:
711     if (key) {
712         (*env)->DeleteLocalRef(env, key);
713     }
714
715     JNI_DETACH_ENV(attached, NULL);
716 }
717
718 void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value)
719 {
720     int attached = 0;
721     JNIEnv *env = NULL;
722     jstring key = NULL;
723
724     av_assert0(format != NULL);
725
726     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
727
728     key = ff_jni_utf_chars_to_jstring(env, name, format);
729     if (!key) {
730         goto fail;
731     }
732
733     (*env)->CallVoidMethod(env, format->object, format->jfields.set_float_id, key, value);
734     if (ff_jni_exception_check(env, 1, format) < 0) {
735         goto fail;
736     }
737
738 fail:
739     if (key) {
740         (*env)->DeleteLocalRef(env, key);
741     }
742
743     JNI_DETACH_ENV(attached, NULL);
744 }
745
746 void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value)
747 {
748     int attached = 0;
749     JNIEnv *env = NULL;
750     jstring key = NULL;
751     jstring string = NULL;
752
753     av_assert0(format != NULL);
754
755     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
756
757     key = ff_jni_utf_chars_to_jstring(env, name, format);
758     if (!key) {
759         goto fail;
760     }
761
762     string = ff_jni_utf_chars_to_jstring(env, value, format);
763     if (!string) {
764         goto fail;
765     }
766
767     (*env)->CallVoidMethod(env, format->object, format->jfields.set_string_id, key, string);
768     if (ff_jni_exception_check(env, 1, format) < 0) {
769         goto fail;
770     }
771
772 fail:
773     if (key) {
774         (*env)->DeleteLocalRef(env, key);
775     }
776
777     if (string) {
778         (*env)->DeleteLocalRef(env, string);
779     }
780
781     JNI_DETACH_ENV(attached, format);
782 }
783
784 void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size)
785 {
786     int attached = 0;
787     JNIEnv *env = NULL;
788     jstring key = NULL;
789     jobject buffer = NULL;
790     void *buffer_data = NULL;
791
792     av_assert0(format != NULL);
793
794     JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format);
795
796     key = ff_jni_utf_chars_to_jstring(env, name, format);
797     if (!key) {
798         goto fail;
799     }
800
801     if (!data || !size) {
802         goto fail;
803     }
804
805     buffer_data = av_malloc(size);
806     if (!buffer_data) {
807         goto fail;
808     }
809
810     memcpy(buffer_data, data, size);
811
812     buffer = (*env)->NewDirectByteBuffer(env, buffer_data, size);
813     if (!buffer) {
814         goto fail;
815     }
816
817     (*env)->CallVoidMethod(env, format->object, format->jfields.set_bytebuffer_id, key, buffer);
818     if (ff_jni_exception_check(env, 1, format) < 0) {
819         goto fail;
820     }
821
822 fail:
823     if (key) {
824         (*env)->DeleteLocalRef(env, key);
825     }
826
827     if (buffer) {
828         (*env)->DeleteLocalRef(env, buffer);
829     }
830
831     JNI_DETACH_ENV(attached, format);
832 }
833
834 struct JNIAMediaCodecFields {
835
836     jclass mediacodec_class;
837
838     jfieldID info_try_again_later_id;
839     jfieldID info_output_buffers_changed_id;
840     jfieldID info_output_format_changed_id;
841
842     jfieldID buffer_flag_codec_config_id;
843     jfieldID buffer_flag_end_of_stream_id;
844     jfieldID buffer_flag_key_frame_id;
845
846     jfieldID configure_flag_encode_id;
847
848     jmethodID create_by_codec_name_id;
849     jmethodID create_decoder_by_type_id;
850     jmethodID create_encoder_by_type_id;
851
852     jmethodID get_name_id;
853
854     jmethodID configure_id;
855     jmethodID start_id;
856     jmethodID flush_id;
857     jmethodID stop_id;
858     jmethodID release_id;
859
860     jmethodID get_output_format_id;
861
862     jmethodID dequeue_input_buffer_id;
863     jmethodID queue_input_buffer_id;
864     jmethodID get_input_buffer_id;
865     jmethodID get_input_buffers_id;
866
867     jmethodID dequeue_output_buffer_id;
868     jmethodID get_output_buffer_id;
869     jmethodID get_output_buffers_id;
870     jmethodID release_output_buffer_id;
871     jmethodID release_output_buffer_at_time_id;
872
873     jclass mediainfo_class;
874
875     jmethodID init_id;
876
877     jfieldID flags_id;
878     jfieldID offset_id;
879     jfieldID presentation_time_us_id;
880     jfieldID size_id;
881
882 } JNIAMediaCodecFields;
883
884 static const struct FFJniField jni_amediacodec_mapping[] = {
885     { "android/media/MediaCodec", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediacodec_class), 1 },
886
887         { "android/media/MediaCodec", "INFO_TRY_AGAIN_LATER", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_try_again_later_id), 1 },
888         { "android/media/MediaCodec", "INFO_OUTPUT_BUFFERS_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_buffers_changed_id), 1 },
889         { "android/media/MediaCodec", "INFO_OUTPUT_FORMAT_CHANGED", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, info_output_format_changed_id), 1 },
890
891         { "android/media/MediaCodec", "BUFFER_FLAG_CODEC_CONFIG", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_codec_config_id), 1 },
892         { "android/media/MediaCodec", "BUFFER_FLAG_END_OF_STREAM", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_end_of_stream_id), 1 },
893         { "android/media/MediaCodec", "BUFFER_FLAG_KEY_FRAME", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, buffer_flag_key_frame_id), 0 },
894
895         { "android/media/MediaCodec", "CONFIGURE_FLAG_ENCODE", "I", FF_JNI_STATIC_FIELD, offsetof(struct JNIAMediaCodecFields, configure_flag_encode_id), 1 },
896
897         { "android/media/MediaCodec", "createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_by_codec_name_id), 1 },
898         { "android/media/MediaCodec", "createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_decoder_by_type_id), 1 },
899         { "android/media/MediaCodec", "createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, offsetof(struct JNIAMediaCodecFields, create_encoder_by_type_id), 1 },
900
901         { "android/media/MediaCodec", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_name_id), 1 },
902
903         { "android/media/MediaCodec", "configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, configure_id), 1 },
904         { "android/media/MediaCodec", "start", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, start_id), 1 },
905         { "android/media/MediaCodec", "flush", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, flush_id), 1 },
906         { "android/media/MediaCodec", "stop", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, stop_id), 1 },
907         { "android/media/MediaCodec", "release", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_id), 1 },
908
909         { "android/media/MediaCodec", "getOutputFormat", "()Landroid/media/MediaFormat;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_format_id), 1 },
910
911         { "android/media/MediaCodec", "dequeueInputBuffer", "(J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_input_buffer_id), 1 },
912         { "android/media/MediaCodec", "queueInputBuffer", "(IIIJI)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, queue_input_buffer_id), 1 },
913         { "android/media/MediaCodec", "getInputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffer_id), 0 },
914         { "android/media/MediaCodec", "getInputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_input_buffers_id), 1 },
915
916
917         { "android/media/MediaCodec", "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, dequeue_output_buffer_id), 1 },
918         { "android/media/MediaCodec", "getOutputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffer_id), 0 },
919         { "android/media/MediaCodec", "getOutputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, get_output_buffers_id), 1 },
920         { "android/media/MediaCodec", "releaseOutputBuffer", "(IZ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_id), 1 },
921         { "android/media/MediaCodec", "releaseOutputBuffer", "(IJ)V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, release_output_buffer_at_time_id), 0 },
922
923     { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecFields, mediainfo_class), 1 },
924
925         { "android/media/MediaCodec.BufferInfo", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecFields, init_id), 1 },
926         { "android/media/MediaCodec.BufferInfo", "flags", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, flags_id), 1 },
927         { "android/media/MediaCodec.BufferInfo", "offset", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, offset_id), 1 },
928         { "android/media/MediaCodec.BufferInfo", "presentationTimeUs", "J", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, presentation_time_us_id), 1 },
929         { "android/media/MediaCodec.BufferInfo", "size", "I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecFields, size_id), 1 },
930
931     { NULL }
932 };
933
934
935 static const AVClass amediacodec_class = {
936     .class_name = "amediacodec",
937     .item_name  = av_default_item_name,
938     .version    = LIBAVCODEC_VERSION_INT,
939 };
940
941 struct FFAMediaCodec {
942
943     const AVClass *class;
944
945     struct JNIAMediaCodecFields jfields;
946
947     jobject object;
948
949     jobject input_buffers;
950     jobject output_buffers;
951
952     int INFO_TRY_AGAIN_LATER;
953     int INFO_OUTPUT_BUFFERS_CHANGED;
954     int INFO_OUTPUT_FORMAT_CHANGED;
955
956     int BUFFER_FLAG_CODEC_CONFIG;
957     int BUFFER_FLAG_END_OF_STREAM;
958     int BUFFER_FLAG_KEY_FRAME;
959
960     int CONFIGURE_FLAG_ENCODE;
961
962     int has_get_i_o_buffer;
963 };
964
965 FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name)
966 {
967     int attached = 0;
968     JNIEnv *env = NULL;
969     FFAMediaCodec *codec = NULL;
970     jstring codec_name = NULL;
971
972     codec = av_mallocz(sizeof(FFAMediaCodec));
973     if (!codec) {
974         return NULL;
975     }
976     codec->class = &amediacodec_class;
977
978     env = ff_jni_attach_env(&attached, codec);
979     if (!env) {
980         av_freep(&codec);
981         return NULL;
982     }
983
984     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
985         goto fail;
986     }
987
988     codec_name = ff_jni_utf_chars_to_jstring(env, name, codec);
989     if (!codec_name) {
990         goto fail;
991     }
992
993     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name);
994     if (ff_jni_exception_check(env, 1, codec) < 0) {
995         goto fail;
996     }
997
998     codec->object = (*env)->NewGlobalRef(env, codec->object);
999     if (!codec->object) {
1000         goto fail;
1001     }
1002
1003     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1004     if (ff_jni_exception_check(env, 1, codec) < 0) {
1005         goto fail;
1006     }
1007
1008     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1009     if (ff_jni_exception_check(env, 1, codec) < 0) {
1010         goto fail;
1011     }
1012
1013     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1014     if (ff_jni_exception_check(env, 1, codec) < 0) {
1015         goto fail;
1016     }
1017
1018     if (codec->jfields.buffer_flag_key_frame_id) {
1019         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1020         if (ff_jni_exception_check(env, 1, codec) < 0) {
1021             goto fail;
1022         }
1023     }
1024
1025     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1026     if (ff_jni_exception_check(env, 1, codec) < 0) {
1027         goto fail;
1028     }
1029
1030     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1031     if (ff_jni_exception_check(env, 1, codec) < 0) {
1032         goto fail;
1033     }
1034
1035     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1036     if (ff_jni_exception_check(env, 1, codec) < 0) {
1037         goto fail;
1038     }
1039
1040     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1041     if (ff_jni_exception_check(env, 1, codec) < 0) {
1042         goto fail;
1043     }
1044
1045     JNI_DETACH_ENV(attached, codec);
1046
1047     return codec;
1048 fail:
1049     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1050
1051     if (codec_name) {
1052         (*env)->DeleteLocalRef(env, codec_name);
1053     }
1054
1055     JNI_DETACH_ENV(attached, codec);
1056
1057     av_freep(&codec);
1058
1059     return NULL;
1060 }
1061
1062 FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime)
1063 {
1064     int attached = 0;
1065     JNIEnv *env = NULL;
1066     FFAMediaCodec *codec = NULL;
1067     jstring mime_type = NULL;
1068
1069     codec = av_mallocz(sizeof(FFAMediaCodec));
1070     if (!codec) {
1071         return NULL;
1072     }
1073     codec->class = &amediacodec_class;
1074
1075     env = ff_jni_attach_env(&attached, codec);
1076     if (!env) {
1077         av_freep(&codec);
1078         return NULL;
1079     }
1080
1081     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1082         goto fail;
1083     }
1084
1085     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1086     if (!mime_type) {
1087         goto fail;
1088     }
1089
1090     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type);
1091     if (ff_jni_exception_check(env, 1, codec) < 0) {
1092         goto fail;
1093     }
1094
1095     codec->object = (*env)->NewGlobalRef(env, codec->object);
1096     if (!codec->object) {
1097         goto fail;
1098     }
1099
1100     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1101     if (ff_jni_exception_check(env, 1, codec) < 0) {
1102         goto fail;
1103     }
1104
1105     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1106     if (ff_jni_exception_check(env, 1, codec) < 0) {
1107         goto fail;
1108     }
1109
1110     if (codec->jfields.buffer_flag_key_frame_id) {
1111         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1112         if (ff_jni_exception_check(env, 1, codec) < 0) {
1113             goto fail;
1114         }
1115     }
1116
1117     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1118     if (ff_jni_exception_check(env, 1, codec) < 0) {
1119         goto fail;
1120     }
1121
1122     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1123     if (ff_jni_exception_check(env, 1, codec) < 0) {
1124         goto fail;
1125     }
1126
1127     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1128     if (ff_jni_exception_check(env, 1, codec) < 0) {
1129         goto fail;
1130     }
1131
1132     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1133     if (ff_jni_exception_check(env, 1, codec) < 0) {
1134         goto fail;
1135     }
1136
1137     if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) {
1138         codec->has_get_i_o_buffer = 1;
1139     }
1140
1141     JNI_DETACH_ENV(attached, codec);
1142
1143     return codec;
1144 fail:
1145     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1146
1147     if (mime_type) {
1148         (*env)->DeleteLocalRef(env, mime_type);
1149     }
1150
1151     JNI_DETACH_ENV(attached, codec);
1152
1153     av_freep(&codec);
1154
1155     return NULL;
1156 }
1157
1158 FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime)
1159 {
1160     int attached = 0;
1161     JNIEnv *env = NULL;
1162     FFAMediaCodec *codec = NULL;
1163     jstring mime_type = NULL;
1164
1165     codec = av_mallocz(sizeof(FFAMediaCodec));
1166     if (!codec) {
1167         return NULL;
1168     }
1169     codec->class = &amediacodec_class;
1170
1171     env = ff_jni_attach_env(&attached, codec);
1172     if (!env) {
1173         av_freep(&codec);
1174         return NULL;
1175     }
1176
1177     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1178         goto fail;
1179     }
1180
1181     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1182     if (!mime_type) {
1183         goto fail;
1184     }
1185
1186     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type);
1187     if (ff_jni_exception_check(env, 1, codec) < 0) {
1188         goto fail;
1189     }
1190
1191     codec->object = (*env)->NewGlobalRef(env, codec->object);
1192     if (!codec->object) {
1193         goto fail;
1194     }
1195
1196     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1197     if (ff_jni_exception_check(env, 1, codec) < 0) {
1198         goto fail;
1199     }
1200
1201     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1202     if (ff_jni_exception_check(env, 1, codec) < 0) {
1203         goto fail;
1204     }
1205
1206     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1207     if (ff_jni_exception_check(env, 1, codec) < 0) {
1208         goto fail;
1209     }
1210
1211     if (codec->jfields.buffer_flag_key_frame_id) {
1212         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1213         if (ff_jni_exception_check(env, 1, codec) < 0) {
1214             goto fail;
1215         }
1216     }
1217
1218     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1219     if (ff_jni_exception_check(env, 1, codec) < 0) {
1220         goto fail;
1221     }
1222
1223     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1224     if (ff_jni_exception_check(env, 1, codec) < 0) {
1225         goto fail;
1226     }
1227
1228     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1229     if (ff_jni_exception_check(env, 1, codec) < 0) {
1230         goto fail;
1231     }
1232
1233     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1234     if (ff_jni_exception_check(env, 1, codec) < 0) {
1235         goto fail;
1236     }
1237
1238     JNI_DETACH_ENV(attached, NULL);
1239
1240     return codec;
1241 fail:
1242     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1243
1244     if (mime_type) {
1245         (*env)->DeleteLocalRef(env, mime_type);
1246     }
1247
1248     JNI_DETACH_ENV(attached, codec);
1249
1250     av_freep(&codec);
1251
1252     return NULL;
1253 }
1254
1255
1256 int ff_AMediaCodec_delete(FFAMediaCodec* codec)
1257 {
1258     int ret = 0;
1259
1260     int attached = 0;
1261     JNIEnv *env = NULL;
1262
1263     if (!codec) {
1264         return 0;
1265     }
1266
1267     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1268
1269     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1270     if (ff_jni_exception_check(env, 1, codec) < 0) {
1271         ret = AVERROR_EXTERNAL;
1272     }
1273
1274     (*env)->DeleteGlobalRef(env, codec->object);
1275     codec->object = NULL;
1276
1277     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1278
1279     JNI_DETACH_ENV(attached, codec);
1280
1281     av_freep(&codec);
1282
1283     return ret;
1284 }
1285
1286 char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
1287 {
1288     char *ret = NULL;
1289     int attached = 0;
1290     JNIEnv *env = NULL;
1291     jobject *name = NULL;
1292
1293     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1294
1295     name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
1296     if (ff_jni_exception_check(env, 1, codec) < 0) {
1297         goto fail;
1298     }
1299
1300     ret = ff_jni_jstring_to_utf_chars(env, name, codec);
1301
1302 fail:
1303     JNI_DETACH_ENV(attached, NULL);
1304
1305     return ret;
1306 }
1307
1308 int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags)
1309 {
1310     int ret = 0;
1311     int attached = 0;
1312     JNIEnv *env = NULL;
1313
1314     /* TODO: implement surface handling */
1315     av_assert0(surface == NULL);
1316
1317     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1318
1319     (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1320     if (ff_jni_exception_check(env, 1, codec) < 0) {
1321         ret = AVERROR_EXTERNAL;
1322         goto fail;
1323     }
1324
1325 fail:
1326     JNI_DETACH_ENV(attached, NULL);
1327
1328     return ret;
1329 }
1330
1331 int ff_AMediaCodec_start(FFAMediaCodec* codec)
1332 {
1333     int ret = 0;
1334     int attached = 0;
1335     JNIEnv *env = NULL;
1336
1337     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1338
1339     (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
1340     if (ff_jni_exception_check(env, 1, codec) < 0) {
1341         ret = AVERROR_EXTERNAL;
1342         goto fail;
1343     }
1344
1345 fail:
1346     JNI_DETACH_ENV(attached, codec);
1347
1348     return ret;
1349 }
1350
1351 int ff_AMediaCodec_stop(FFAMediaCodec* codec)
1352 {
1353     int ret = 0;
1354     int attached = 0;
1355     JNIEnv *env = NULL;
1356
1357     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1358
1359     (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
1360     if (ff_jni_exception_check(env, 1, codec) < 0) {
1361         ret = AVERROR_EXTERNAL;
1362         goto fail;
1363     }
1364
1365 fail:
1366     JNI_DETACH_ENV(attached, codec);
1367
1368     return ret;
1369 }
1370
1371 int ff_AMediaCodec_flush(FFAMediaCodec* codec)
1372 {
1373     int ret = 0;
1374     int attached = 0;
1375     JNIEnv *env = NULL;
1376
1377     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1378
1379     (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
1380     if (ff_jni_exception_check(env, 1, codec) < 0) {
1381         ret = AVERROR_EXTERNAL;
1382         goto fail;
1383     }
1384
1385 fail:
1386     JNI_DETACH_ENV(attached, codec);
1387
1388     return ret;
1389 }
1390
1391
1392 int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render)
1393 {
1394     int ret = 0;
1395     int attached = 0;
1396     JNIEnv *env = NULL;
1397
1398     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1399
1400     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, idx, render);
1401     if (ff_jni_exception_check(env, 1, codec) < 0) {
1402         ret = AVERROR_EXTERNAL;
1403         goto fail;
1404     }
1405
1406 fail:
1407     JNI_DETACH_ENV(attached, codec);
1408
1409     return ret;
1410 }
1411
1412 int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs)
1413 {
1414     int ret = 0;
1415     int attached = 0;
1416     JNIEnv *env = NULL;
1417
1418     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1419
1420     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, idx, timestampNs);
1421     if (ff_jni_exception_check(env, 1, codec) < 0) {
1422         ret = AVERROR_EXTERNAL;
1423         goto fail;
1424     }
1425
1426 fail:
1427     JNI_DETACH_ENV(attached, codec);
1428
1429     return ret;
1430 }
1431
1432
1433 ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs)
1434 {
1435     int ret = 0;
1436     int attached = 0;
1437     JNIEnv *env = NULL;
1438
1439     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1440
1441     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
1442     if (ff_jni_exception_check(env, 1, codec) < 0) {
1443         ret = AVERROR_EXTERNAL;
1444         goto fail;
1445     }
1446
1447 fail:
1448     JNI_DETACH_ENV(attached, codec);
1449
1450     return ret;
1451 }
1452
1453 int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
1454 {
1455     int ret = 0;
1456     int attached = 0;
1457     JNIEnv *env = NULL;
1458
1459     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1460
1461     (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, idx, offset, size, time, flags);
1462     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1463         ret = AVERROR_EXTERNAL;
1464         goto fail;
1465     }
1466
1467 fail:
1468     JNI_DETACH_ENV(attached, codec);
1469
1470     return ret;
1471 }
1472
1473 ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
1474 {
1475     int ret = 0;
1476     int attached = 0;
1477     JNIEnv *env = NULL;
1478
1479     jobject mediainfo = NULL;
1480
1481     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1482
1483     mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
1484     if (ff_jni_exception_check(env, 1, codec) < 0) {
1485         ret = AVERROR_EXTERNAL;
1486         goto fail;
1487     }
1488
1489     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
1490     if (ff_jni_exception_check(env, 1, codec) < 0) {
1491         ret = AVERROR_EXTERNAL;
1492         goto fail;
1493     }
1494
1495     info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
1496     if (ff_jni_exception_check(env, 1, codec) < 0) {
1497         ret = AVERROR_EXTERNAL;
1498         goto fail;
1499     }
1500
1501     info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
1502     if (ff_jni_exception_check(env, 1, codec) < 0) {
1503         ret = AVERROR_EXTERNAL;
1504         goto fail;
1505     }
1506
1507     info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
1508     if (ff_jni_exception_check(env, 1, codec) < 0) {
1509         ret = AVERROR_EXTERNAL;
1510         goto fail;
1511     }
1512
1513     info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
1514     if (ff_jni_exception_check(env, 1, codec) < 0) {
1515         ret = AVERROR_EXTERNAL;
1516         goto fail;
1517     }
1518 fail:
1519     if (mediainfo) {
1520         (*env)->DeleteLocalRef(env, mediainfo);
1521     }
1522
1523     JNI_DETACH_ENV(attached, NULL);
1524
1525     return ret;
1526 }
1527
1528 uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1529 {
1530     uint8_t *ret = NULL;
1531     int attached = 0;
1532     JNIEnv *env = NULL;
1533
1534     jobject buffer = NULL;
1535
1536     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1537
1538     if (codec->has_get_i_o_buffer) {
1539         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, idx);
1540         if (ff_jni_exception_check(env, 1, codec) < 0) {
1541             goto fail;
1542         }
1543     } else {
1544         if (!codec->input_buffers) {
1545             codec->input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
1546             if (ff_jni_exception_check(env, 1, codec) < 0) {
1547                 goto fail;
1548             }
1549
1550             codec->input_buffers = (*env)->NewGlobalRef(env, codec->input_buffers);
1551             if (ff_jni_exception_check(env, 1, codec) < 0) {
1552                 goto fail;
1553             }
1554         }
1555
1556         buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
1557         if (ff_jni_exception_check(env, 1, codec) < 0) {
1558             goto fail;
1559         }
1560     }
1561
1562     ret = (*env)->GetDirectBufferAddress(env, buffer);
1563     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1564 fail:
1565     if (buffer) {
1566         (*env)->DeleteLocalRef(env, buffer);
1567     }
1568
1569     JNI_DETACH_ENV(attached, codec);
1570
1571     return ret;
1572 }
1573
1574 uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1575 {
1576     uint8_t *ret = NULL;
1577     int attached = 0;
1578     JNIEnv *env = NULL;
1579
1580     jobject buffer = NULL;
1581
1582     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1583
1584     if (codec->has_get_i_o_buffer) {
1585         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, idx);
1586         if (ff_jni_exception_check(env, 1, codec) < 0) {
1587             goto fail;
1588         }
1589     } else {
1590         if (!codec->output_buffers) {
1591             codec->output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
1592             if (ff_jni_exception_check(env, 1, codec) < 0) {
1593                 goto fail;
1594             }
1595
1596             codec->output_buffers = (*env)->NewGlobalRef(env, codec->output_buffers);
1597             if (ff_jni_exception_check(env, 1, codec) < 0) {
1598                 goto fail;
1599             }
1600         }
1601
1602         buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
1603         if (ff_jni_exception_check(env, 1, codec) < 0) {
1604             goto fail;
1605         }
1606     }
1607
1608     ret = (*env)->GetDirectBufferAddress(env, buffer);
1609     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1610 fail:
1611     if (buffer) {
1612         (*env)->DeleteLocalRef(env, buffer);
1613     }
1614
1615     JNI_DETACH_ENV(attached, codec);
1616
1617     return ret;
1618 }
1619
1620 FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec)
1621 {
1622     FFAMediaFormat *ret = NULL;
1623     int attached = 0;
1624     JNIEnv *env = NULL;
1625
1626     jobject mediaformat = NULL;
1627
1628     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1629
1630     mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
1631     if (ff_jni_exception_check(env, 1, codec) < 0) {
1632         goto fail;
1633     }
1634
1635     ret = ff_AMediaFormat_newFromObject(mediaformat);
1636 fail:
1637     if (mediaformat) {
1638         (*env)->DeleteLocalRef(env, mediaformat);
1639     }
1640
1641     JNI_DETACH_ENV(attached, codec);
1642
1643     return ret;
1644 }
1645
1646 int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx)
1647 {
1648     return idx == codec->INFO_TRY_AGAIN_LATER;
1649 }
1650
1651 int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx)
1652 {
1653     return idx == codec->INFO_OUTPUT_BUFFERS_CHANGED;
1654 }
1655
1656 int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t idx)
1657 {
1658     return idx == codec->INFO_OUTPUT_FORMAT_CHANGED;
1659 }
1660
1661 int ff_AMediaCodec_getBufferFlagCodecConfig(FFAMediaCodec *codec)
1662 {
1663     return codec->BUFFER_FLAG_CODEC_CONFIG;
1664 }
1665
1666 int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec)
1667 {
1668     return codec->BUFFER_FLAG_END_OF_STREAM;
1669 }
1670
1671 int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec)
1672 {
1673     return codec->BUFFER_FLAG_KEY_FRAME;
1674 }
1675
1676 int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec)
1677 {
1678     return codec->CONFIGURE_FLAG_ENCODE;
1679 }
1680
1681 int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
1682 {
1683     int ret = 0;
1684
1685     if (!codec->has_get_i_o_buffer) {
1686         if (codec->output_buffers) {
1687             int attached = 0;
1688             JNIEnv *env = NULL;
1689
1690             env = ff_jni_attach_env(&attached, codec);
1691             if (!env) {
1692                 ret = AVERROR_EXTERNAL;
1693                 goto fail;
1694             }
1695
1696             (*env)->DeleteGlobalRef(env, codec->output_buffers);
1697             codec->output_buffers = NULL;
1698
1699             JNI_DETACH_ENV(attached, codec);
1700         }
1701     }
1702
1703 fail:
1704     return ret;
1705 }