]> git.sesse.net Git - ffmpeg/blob - libavcodec/mediacodec_wrapper.c
lavc/mediacodec: factorize static fields initialization
[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 static int codec_init_static_fields(FFAMediaCodec *codec)
962 {
963     int ret = 0;
964     int attached = 0;
965     JNIEnv *env = NULL;
966
967     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
968
969     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
970     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
971         goto fail;
972     }
973
974     codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
975     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
976         goto fail;
977     }
978
979     codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
980     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
981         goto fail;
982     }
983
984     if (codec->jfields.buffer_flag_key_frame_id) {
985         codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
986         if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
987             goto fail;
988         }
989     }
990
991     codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
992     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
993         goto fail;
994     }
995
996     codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
997     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
998         goto fail;
999     }
1000
1001     codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1002     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1003         goto fail;
1004     }
1005
1006     codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1007     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1008         goto fail;
1009     }
1010
1011 fail:
1012     JNI_DETACH_ENV(attached, NULL);
1013
1014     return ret;
1015 }
1016
1017 FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name)
1018 {
1019     int attached = 0;
1020     JNIEnv *env = NULL;
1021     FFAMediaCodec *codec = NULL;
1022     jstring codec_name = NULL;
1023
1024     codec = av_mallocz(sizeof(FFAMediaCodec));
1025     if (!codec) {
1026         return NULL;
1027     }
1028     codec->class = &amediacodec_class;
1029
1030     env = ff_jni_attach_env(&attached, codec);
1031     if (!env) {
1032         av_freep(&codec);
1033         return NULL;
1034     }
1035
1036     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1037         goto fail;
1038     }
1039
1040     codec_name = ff_jni_utf_chars_to_jstring(env, name, codec);
1041     if (!codec_name) {
1042         goto fail;
1043     }
1044
1045     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name);
1046     if (ff_jni_exception_check(env, 1, codec) < 0) {
1047         goto fail;
1048     }
1049
1050     codec->object = (*env)->NewGlobalRef(env, codec->object);
1051     if (!codec->object) {
1052         goto fail;
1053     }
1054
1055     if (codec_init_static_fields(codec) < 0) {
1056         goto fail;
1057     }
1058
1059     JNI_DETACH_ENV(attached, codec);
1060
1061     return codec;
1062 fail:
1063     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1064
1065     if (codec_name) {
1066         (*env)->DeleteLocalRef(env, codec_name);
1067     }
1068
1069     JNI_DETACH_ENV(attached, codec);
1070
1071     av_freep(&codec);
1072
1073     return NULL;
1074 }
1075
1076 FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime)
1077 {
1078     int attached = 0;
1079     JNIEnv *env = NULL;
1080     FFAMediaCodec *codec = NULL;
1081     jstring mime_type = NULL;
1082
1083     codec = av_mallocz(sizeof(FFAMediaCodec));
1084     if (!codec) {
1085         return NULL;
1086     }
1087     codec->class = &amediacodec_class;
1088
1089     env = ff_jni_attach_env(&attached, codec);
1090     if (!env) {
1091         av_freep(&codec);
1092         return NULL;
1093     }
1094
1095     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1096         goto fail;
1097     }
1098
1099     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1100     if (!mime_type) {
1101         goto fail;
1102     }
1103
1104     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type);
1105     if (ff_jni_exception_check(env, 1, codec) < 0) {
1106         goto fail;
1107     }
1108
1109     codec->object = (*env)->NewGlobalRef(env, codec->object);
1110     if (!codec->object) {
1111         goto fail;
1112     }
1113
1114     if (codec_init_static_fields(codec) < 0) {
1115         goto fail;
1116     }
1117
1118     if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) {
1119         codec->has_get_i_o_buffer = 1;
1120     }
1121
1122     JNI_DETACH_ENV(attached, codec);
1123
1124     return codec;
1125 fail:
1126     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1127
1128     if (mime_type) {
1129         (*env)->DeleteLocalRef(env, mime_type);
1130     }
1131
1132     JNI_DETACH_ENV(attached, codec);
1133
1134     av_freep(&codec);
1135
1136     return NULL;
1137 }
1138
1139 FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime)
1140 {
1141     int attached = 0;
1142     JNIEnv *env = NULL;
1143     FFAMediaCodec *codec = NULL;
1144     jstring mime_type = NULL;
1145
1146     codec = av_mallocz(sizeof(FFAMediaCodec));
1147     if (!codec) {
1148         return NULL;
1149     }
1150     codec->class = &amediacodec_class;
1151
1152     env = ff_jni_attach_env(&attached, codec);
1153     if (!env) {
1154         av_freep(&codec);
1155         return NULL;
1156     }
1157
1158     if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1159         goto fail;
1160     }
1161
1162     mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec);
1163     if (!mime_type) {
1164         goto fail;
1165     }
1166
1167     codec->object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type);
1168     if (ff_jni_exception_check(env, 1, codec) < 0) {
1169         goto fail;
1170     }
1171
1172     codec->object = (*env)->NewGlobalRef(env, codec->object);
1173     if (!codec->object) {
1174         goto fail;
1175     }
1176
1177     if (codec_init_static_fields(codec) < 0) {
1178         goto fail;
1179     }
1180
1181     JNI_DETACH_ENV(attached, NULL);
1182
1183     return codec;
1184 fail:
1185     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1186
1187     if (mime_type) {
1188         (*env)->DeleteLocalRef(env, mime_type);
1189     }
1190
1191     JNI_DETACH_ENV(attached, codec);
1192
1193     av_freep(&codec);
1194
1195     return NULL;
1196 }
1197
1198 int ff_AMediaCodec_delete(FFAMediaCodec* codec)
1199 {
1200     int ret = 0;
1201
1202     int attached = 0;
1203     JNIEnv *env = NULL;
1204
1205     if (!codec) {
1206         return 0;
1207     }
1208
1209     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1210
1211     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1212     if (ff_jni_exception_check(env, 1, codec) < 0) {
1213         ret = AVERROR_EXTERNAL;
1214     }
1215
1216     (*env)->DeleteGlobalRef(env, codec->object);
1217     codec->object = NULL;
1218
1219     ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1220
1221     JNI_DETACH_ENV(attached, codec);
1222
1223     av_freep(&codec);
1224
1225     return ret;
1226 }
1227
1228 char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
1229 {
1230     char *ret = NULL;
1231     int attached = 0;
1232     JNIEnv *env = NULL;
1233     jobject *name = NULL;
1234
1235     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1236
1237     name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
1238     if (ff_jni_exception_check(env, 1, codec) < 0) {
1239         goto fail;
1240     }
1241
1242     ret = ff_jni_jstring_to_utf_chars(env, name, codec);
1243
1244 fail:
1245     JNI_DETACH_ENV(attached, NULL);
1246
1247     return ret;
1248 }
1249
1250 int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags)
1251 {
1252     int ret = 0;
1253     int attached = 0;
1254     JNIEnv *env = NULL;
1255
1256     /* TODO: implement surface handling */
1257     av_assert0(surface == NULL);
1258
1259     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1260
1261     (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1262     if (ff_jni_exception_check(env, 1, codec) < 0) {
1263         ret = AVERROR_EXTERNAL;
1264         goto fail;
1265     }
1266
1267 fail:
1268     JNI_DETACH_ENV(attached, NULL);
1269
1270     return ret;
1271 }
1272
1273 int ff_AMediaCodec_start(FFAMediaCodec* codec)
1274 {
1275     int ret = 0;
1276     int attached = 0;
1277     JNIEnv *env = NULL;
1278
1279     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1280
1281     (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
1282     if (ff_jni_exception_check(env, 1, codec) < 0) {
1283         ret = AVERROR_EXTERNAL;
1284         goto fail;
1285     }
1286
1287 fail:
1288     JNI_DETACH_ENV(attached, codec);
1289
1290     return ret;
1291 }
1292
1293 int ff_AMediaCodec_stop(FFAMediaCodec* codec)
1294 {
1295     int ret = 0;
1296     int attached = 0;
1297     JNIEnv *env = NULL;
1298
1299     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1300
1301     (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
1302     if (ff_jni_exception_check(env, 1, codec) < 0) {
1303         ret = AVERROR_EXTERNAL;
1304         goto fail;
1305     }
1306
1307 fail:
1308     JNI_DETACH_ENV(attached, codec);
1309
1310     return ret;
1311 }
1312
1313 int ff_AMediaCodec_flush(FFAMediaCodec* codec)
1314 {
1315     int ret = 0;
1316     int attached = 0;
1317     JNIEnv *env = NULL;
1318
1319     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1320
1321     (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
1322     if (ff_jni_exception_check(env, 1, codec) < 0) {
1323         ret = AVERROR_EXTERNAL;
1324         goto fail;
1325     }
1326
1327 fail:
1328     JNI_DETACH_ENV(attached, codec);
1329
1330     return ret;
1331 }
1332
1333 int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render)
1334 {
1335     int ret = 0;
1336     int attached = 0;
1337     JNIEnv *env = NULL;
1338
1339     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1340
1341     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, idx, render);
1342     if (ff_jni_exception_check(env, 1, codec) < 0) {
1343         ret = AVERROR_EXTERNAL;
1344         goto fail;
1345     }
1346
1347 fail:
1348     JNI_DETACH_ENV(attached, codec);
1349
1350     return ret;
1351 }
1352
1353 int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs)
1354 {
1355     int ret = 0;
1356     int attached = 0;
1357     JNIEnv *env = NULL;
1358
1359     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1360
1361     (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, idx, timestampNs);
1362     if (ff_jni_exception_check(env, 1, codec) < 0) {
1363         ret = AVERROR_EXTERNAL;
1364         goto fail;
1365     }
1366
1367 fail:
1368     JNI_DETACH_ENV(attached, codec);
1369
1370     return ret;
1371 }
1372
1373 ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs)
1374 {
1375     int ret = 0;
1376     int attached = 0;
1377     JNIEnv *env = NULL;
1378
1379     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1380
1381     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
1382     if (ff_jni_exception_check(env, 1, codec) < 0) {
1383         ret = AVERROR_EXTERNAL;
1384         goto fail;
1385     }
1386
1387 fail:
1388     JNI_DETACH_ENV(attached, codec);
1389
1390     return ret;
1391 }
1392
1393 int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
1394 {
1395     int ret = 0;
1396     int attached = 0;
1397     JNIEnv *env = NULL;
1398
1399     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1400
1401     (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, idx, offset, size, time, flags);
1402     if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1403         ret = AVERROR_EXTERNAL;
1404         goto fail;
1405     }
1406
1407 fail:
1408     JNI_DETACH_ENV(attached, codec);
1409
1410     return ret;
1411 }
1412
1413 ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
1414 {
1415     int ret = 0;
1416     int attached = 0;
1417     JNIEnv *env = NULL;
1418
1419     jobject mediainfo = NULL;
1420
1421     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL);
1422
1423     mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
1424     if (ff_jni_exception_check(env, 1, codec) < 0) {
1425         ret = AVERROR_EXTERNAL;
1426         goto fail;
1427     }
1428
1429     ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
1430     if (ff_jni_exception_check(env, 1, codec) < 0) {
1431         ret = AVERROR_EXTERNAL;
1432         goto fail;
1433     }
1434
1435     info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
1436     if (ff_jni_exception_check(env, 1, codec) < 0) {
1437         ret = AVERROR_EXTERNAL;
1438         goto fail;
1439     }
1440
1441     info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
1442     if (ff_jni_exception_check(env, 1, codec) < 0) {
1443         ret = AVERROR_EXTERNAL;
1444         goto fail;
1445     }
1446
1447     info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
1448     if (ff_jni_exception_check(env, 1, codec) < 0) {
1449         ret = AVERROR_EXTERNAL;
1450         goto fail;
1451     }
1452
1453     info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
1454     if (ff_jni_exception_check(env, 1, codec) < 0) {
1455         ret = AVERROR_EXTERNAL;
1456         goto fail;
1457     }
1458 fail:
1459     if (mediainfo) {
1460         (*env)->DeleteLocalRef(env, mediainfo);
1461     }
1462
1463     JNI_DETACH_ENV(attached, NULL);
1464
1465     return ret;
1466 }
1467
1468 uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1469 {
1470     uint8_t *ret = NULL;
1471     int attached = 0;
1472     JNIEnv *env = NULL;
1473
1474     jobject buffer = NULL;
1475
1476     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1477
1478     if (codec->has_get_i_o_buffer) {
1479         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, idx);
1480         if (ff_jni_exception_check(env, 1, codec) < 0) {
1481             goto fail;
1482         }
1483     } else {
1484         if (!codec->input_buffers) {
1485             codec->input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
1486             if (ff_jni_exception_check(env, 1, codec) < 0) {
1487                 goto fail;
1488             }
1489
1490             codec->input_buffers = (*env)->NewGlobalRef(env, codec->input_buffers);
1491             if (ff_jni_exception_check(env, 1, codec) < 0) {
1492                 goto fail;
1493             }
1494         }
1495
1496         buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
1497         if (ff_jni_exception_check(env, 1, codec) < 0) {
1498             goto fail;
1499         }
1500     }
1501
1502     ret = (*env)->GetDirectBufferAddress(env, buffer);
1503     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1504 fail:
1505     if (buffer) {
1506         (*env)->DeleteLocalRef(env, buffer);
1507     }
1508
1509     JNI_DETACH_ENV(attached, codec);
1510
1511     return ret;
1512 }
1513
1514 uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size)
1515 {
1516     uint8_t *ret = NULL;
1517     int attached = 0;
1518     JNIEnv *env = NULL;
1519
1520     jobject buffer = NULL;
1521
1522     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1523
1524     if (codec->has_get_i_o_buffer) {
1525         buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, idx);
1526         if (ff_jni_exception_check(env, 1, codec) < 0) {
1527             goto fail;
1528         }
1529     } else {
1530         if (!codec->output_buffers) {
1531             codec->output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
1532             if (ff_jni_exception_check(env, 1, codec) < 0) {
1533                 goto fail;
1534             }
1535
1536             codec->output_buffers = (*env)->NewGlobalRef(env, codec->output_buffers);
1537             if (ff_jni_exception_check(env, 1, codec) < 0) {
1538                 goto fail;
1539             }
1540         }
1541
1542         buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
1543         if (ff_jni_exception_check(env, 1, codec) < 0) {
1544             goto fail;
1545         }
1546     }
1547
1548     ret = (*env)->GetDirectBufferAddress(env, buffer);
1549     *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1550 fail:
1551     if (buffer) {
1552         (*env)->DeleteLocalRef(env, buffer);
1553     }
1554
1555     JNI_DETACH_ENV(attached, codec);
1556
1557     return ret;
1558 }
1559
1560 FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec)
1561 {
1562     FFAMediaFormat *ret = NULL;
1563     int attached = 0;
1564     JNIEnv *env = NULL;
1565
1566     jobject mediaformat = NULL;
1567
1568     JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL);
1569
1570     mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
1571     if (ff_jni_exception_check(env, 1, codec) < 0) {
1572         goto fail;
1573     }
1574
1575     ret = ff_AMediaFormat_newFromObject(mediaformat);
1576 fail:
1577     if (mediaformat) {
1578         (*env)->DeleteLocalRef(env, mediaformat);
1579     }
1580
1581     JNI_DETACH_ENV(attached, codec);
1582
1583     return ret;
1584 }
1585
1586 int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx)
1587 {
1588     return idx == codec->INFO_TRY_AGAIN_LATER;
1589 }
1590
1591 int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx)
1592 {
1593     return idx == codec->INFO_OUTPUT_BUFFERS_CHANGED;
1594 }
1595
1596 int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t idx)
1597 {
1598     return idx == codec->INFO_OUTPUT_FORMAT_CHANGED;
1599 }
1600
1601 int ff_AMediaCodec_getBufferFlagCodecConfig(FFAMediaCodec *codec)
1602 {
1603     return codec->BUFFER_FLAG_CODEC_CONFIG;
1604 }
1605
1606 int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec)
1607 {
1608     return codec->BUFFER_FLAG_END_OF_STREAM;
1609 }
1610
1611 int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec)
1612 {
1613     return codec->BUFFER_FLAG_KEY_FRAME;
1614 }
1615
1616 int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec)
1617 {
1618     return codec->CONFIGURE_FLAG_ENCODE;
1619 }
1620
1621 int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec)
1622 {
1623     int ret = 0;
1624
1625     if (!codec->has_get_i_o_buffer) {
1626         if (codec->output_buffers) {
1627             int attached = 0;
1628             JNIEnv *env = NULL;
1629
1630             env = ff_jni_attach_env(&attached, codec);
1631             if (!env) {
1632                 ret = AVERROR_EXTERNAL;
1633                 goto fail;
1634             }
1635
1636             (*env)->DeleteGlobalRef(env, codec->output_buffers);
1637             codec->output_buffers = NULL;
1638
1639             JNI_DETACH_ENV(attached, codec);
1640         }
1641     }
1642
1643 fail:
1644     return ret;
1645 }