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