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