avformat/mpeg: demux ivtv captions
[ffmpeg.git] / libavcodec / mediacodec_wrapper.c
blob283bbe72d682bb2b68ae2e0447dbca726d081ea7
1 /*
2 * Android MediaCodec Wrapper
4 * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
6 * This file is part of FFmpeg.
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.
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.
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
23 #include <dlfcn.h>
24 #include <jni.h>
25 #include <stdbool.h>
26 #include <media/NdkMediaFormat.h>
27 #include <media/NdkMediaCodec.h>
28 #include <android/native_window_jni.h>
30 #include "libavutil/avassert.h"
31 #include "libavutil/mem.h"
32 #include "libavutil/avstring.h"
34 #include "avcodec.h"
35 #include "ffjni.h"
36 #include "mediacodec_wrapper.h"
38 struct JNIAMediaCodecListFields {
40 jclass mediacodec_list_class;
41 jmethodID init_id;
42 jmethodID find_decoder_for_format_id;
44 jmethodID get_codec_count_id;
45 jmethodID get_codec_info_at_id;
47 jclass mediacodec_info_class;
48 jmethodID get_name_id;
49 jmethodID get_codec_capabilities_id;
50 jmethodID get_supported_types_id;
51 jmethodID is_encoder_id;
52 jmethodID is_software_only_id;
54 jclass codec_capabilities_class;
55 jfieldID color_formats_id;
56 jfieldID profile_levels_id;
58 jclass codec_profile_level_class;
59 jfieldID profile_id;
60 jfieldID level_id;
63 #define OFFSET(x) offsetof(struct JNIAMediaCodecListFields, x)
64 static const struct FFJniField jni_amediacodeclist_mapping[] = {
65 { "android/media/MediaCodecList", NULL, NULL, FF_JNI_CLASS, OFFSET(mediacodec_list_class), 1 },
66 { "android/media/MediaCodecList", "<init>", "(I)V", FF_JNI_METHOD, OFFSET(init_id), 0 },
67 { "android/media/MediaCodecList", "findDecoderForFormat", "(Landroid/media/MediaFormat;)Ljava/lang/String;", FF_JNI_METHOD, OFFSET(find_decoder_for_format_id), 0 },
69 { "android/media/MediaCodecList", "getCodecCount", "()I", FF_JNI_STATIC_METHOD, OFFSET(get_codec_count_id), 1 },
70 { "android/media/MediaCodecList", "getCodecInfoAt", "(I)Landroid/media/MediaCodecInfo;", FF_JNI_STATIC_METHOD, OFFSET(get_codec_info_at_id), 1 },
72 { "android/media/MediaCodecInfo", NULL, NULL, FF_JNI_CLASS, OFFSET(mediacodec_info_class), 1 },
73 { "android/media/MediaCodecInfo", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, OFFSET(get_name_id), 1 },
74 { "android/media/MediaCodecInfo", "getCapabilitiesForType", "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;", FF_JNI_METHOD, OFFSET(get_codec_capabilities_id), 1 },
75 { "android/media/MediaCodecInfo", "getSupportedTypes", "()[Ljava/lang/String;", FF_JNI_METHOD, OFFSET(get_supported_types_id), 1 },
76 { "android/media/MediaCodecInfo", "isEncoder", "()Z", FF_JNI_METHOD, OFFSET(is_encoder_id), 1 },
77 { "android/media/MediaCodecInfo", "isSoftwareOnly", "()Z", FF_JNI_METHOD, OFFSET(is_software_only_id), 0 },
79 { "android/media/MediaCodecInfo$CodecCapabilities", NULL, NULL, FF_JNI_CLASS, OFFSET(codec_capabilities_class), 1 },
80 { "android/media/MediaCodecInfo$CodecCapabilities", "colorFormats", "[I", FF_JNI_FIELD, OFFSET(color_formats_id), 1 },
81 { "android/media/MediaCodecInfo$CodecCapabilities", "profileLevels", "[Landroid/media/MediaCodecInfo$CodecProfileLevel;", FF_JNI_FIELD, OFFSET(profile_levels_id), 1 },
83 { "android/media/MediaCodecInfo$CodecProfileLevel", NULL, NULL, FF_JNI_CLASS, OFFSET(codec_profile_level_class), 1 },
84 { "android/media/MediaCodecInfo$CodecProfileLevel", "profile", "I", FF_JNI_FIELD, OFFSET(profile_id), 1 },
85 { "android/media/MediaCodecInfo$CodecProfileLevel", "level", "I", FF_JNI_FIELD, OFFSET(level_id), 1 },
87 { NULL }
89 #undef OFFSET
91 struct JNIAMediaFormatFields {
93 jclass mediaformat_class;
95 jmethodID init_id;
97 jmethodID contains_key_id;
99 jmethodID get_integer_id;
100 jmethodID get_long_id;
101 jmethodID get_float_id;
102 jmethodID get_bytebuffer_id;
103 jmethodID get_string_id;
105 jmethodID set_integer_id;
106 jmethodID set_long_id;
107 jmethodID set_float_id;
108 jmethodID set_bytebuffer_id;
109 jmethodID set_string_id;
111 jmethodID to_string_id;
115 #define OFFSET(x) offsetof(struct JNIAMediaFormatFields, x)
116 static const struct FFJniField jni_amediaformat_mapping[] = {
117 { "android/media/MediaFormat", NULL, NULL, FF_JNI_CLASS, OFFSET(mediaformat_class), 1 },
119 { "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 },
121 { "android/media/MediaFormat", "containsKey", "(Ljava/lang/String;)Z", FF_JNI_METHOD, OFFSET(contains_key_id), 1 },
123 { "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, OFFSET(get_integer_id), 1 },
124 { "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, OFFSET(get_long_id), 1 },
125 { "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, OFFSET(get_float_id), 1 },
126 { "android/media/MediaFormat", "getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, OFFSET(get_bytebuffer_id), 1 },
127 { "android/media/MediaFormat", "getString", "(Ljava/lang/String;)Ljava/lang/String;", FF_JNI_METHOD, OFFSET(get_string_id), 1 },
129 { "android/media/MediaFormat", "setInteger", "(Ljava/lang/String;I)V", FF_JNI_METHOD, OFFSET(set_integer_id), 1 },
130 { "android/media/MediaFormat", "setLong", "(Ljava/lang/String;J)V", FF_JNI_METHOD, OFFSET(set_long_id), 1 },
131 { "android/media/MediaFormat", "setFloat", "(Ljava/lang/String;F)V", FF_JNI_METHOD, OFFSET(set_float_id), 1 },
132 { "android/media/MediaFormat", "setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V", FF_JNI_METHOD, OFFSET(set_bytebuffer_id), 1 },
133 { "android/media/MediaFormat", "setString", "(Ljava/lang/String;Ljava/lang/String;)V", FF_JNI_METHOD, OFFSET(set_string_id), 1 },
135 { "android/media/MediaFormat", "toString", "()Ljava/lang/String;", FF_JNI_METHOD, OFFSET(to_string_id), 1 },
137 { NULL }
139 #undef OFFSET
141 static const AVClass amediaformat_class = {
142 .class_name = "amediaformat",
143 .item_name = av_default_item_name,
144 .version = LIBAVUTIL_VERSION_INT,
147 typedef struct FFAMediaFormatJni {
148 FFAMediaFormat api;
150 struct JNIAMediaFormatFields jfields;
151 jobject object;
152 } FFAMediaFormatJni;
154 static const FFAMediaFormat media_format_jni;
156 struct JNIAMediaCodecFields {
158 jclass mediacodec_class;
160 jfieldID info_try_again_later_id;
161 jfieldID info_output_buffers_changed_id;
162 jfieldID info_output_format_changed_id;
164 jfieldID buffer_flag_codec_config_id;
165 jfieldID buffer_flag_end_of_stream_id;
166 jfieldID buffer_flag_key_frame_id;
168 jfieldID configure_flag_encode_id;
170 jmethodID create_by_codec_name_id;
171 jmethodID create_decoder_by_type_id;
172 jmethodID create_encoder_by_type_id;
174 jmethodID get_name_id;
176 jmethodID configure_id;
177 jmethodID start_id;
178 jmethodID flush_id;
179 jmethodID stop_id;
180 jmethodID release_id;
182 jmethodID get_output_format_id;
184 jmethodID dequeue_input_buffer_id;
185 jmethodID queue_input_buffer_id;
186 jmethodID get_input_buffer_id;
187 jmethodID get_input_buffers_id;
189 jmethodID dequeue_output_buffer_id;
190 jmethodID get_output_buffer_id;
191 jmethodID get_output_buffers_id;
192 jmethodID release_output_buffer_id;
193 jmethodID release_output_buffer_at_time_id;
195 jmethodID set_input_surface_id;
196 jmethodID signal_end_of_input_stream_id;
198 jclass mediainfo_class;
200 jmethodID init_id;
202 jfieldID flags_id;
203 jfieldID offset_id;
204 jfieldID presentation_time_us_id;
205 jfieldID size_id;
209 #define OFFSET(x) offsetof(struct JNIAMediaCodecFields, x)
210 static const struct FFJniField jni_amediacodec_mapping[] = {
211 { "android/media/MediaCodec", NULL, NULL, FF_JNI_CLASS, OFFSET(mediacodec_class), 1 },
213 { "android/media/MediaCodec", "INFO_TRY_AGAIN_LATER", "I", FF_JNI_STATIC_FIELD, OFFSET(info_try_again_later_id), 1 },
214 { "android/media/MediaCodec", "INFO_OUTPUT_BUFFERS_CHANGED", "I", FF_JNI_STATIC_FIELD, OFFSET(info_output_buffers_changed_id), 1 },
215 { "android/media/MediaCodec", "INFO_OUTPUT_FORMAT_CHANGED", "I", FF_JNI_STATIC_FIELD, OFFSET(info_output_format_changed_id), 1 },
217 { "android/media/MediaCodec", "BUFFER_FLAG_CODEC_CONFIG", "I", FF_JNI_STATIC_FIELD, OFFSET(buffer_flag_codec_config_id), 1 },
218 { "android/media/MediaCodec", "BUFFER_FLAG_END_OF_STREAM", "I", FF_JNI_STATIC_FIELD, OFFSET(buffer_flag_end_of_stream_id), 1 },
219 { "android/media/MediaCodec", "BUFFER_FLAG_KEY_FRAME", "I", FF_JNI_STATIC_FIELD, OFFSET(buffer_flag_key_frame_id), 0 },
221 { "android/media/MediaCodec", "CONFIGURE_FLAG_ENCODE", "I", FF_JNI_STATIC_FIELD, OFFSET(configure_flag_encode_id), 1 },
223 { "android/media/MediaCodec", "createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, OFFSET(create_by_codec_name_id), 1 },
224 { "android/media/MediaCodec", "createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, OFFSET(create_decoder_by_type_id), 1 },
225 { "android/media/MediaCodec", "createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;", FF_JNI_STATIC_METHOD, OFFSET(create_encoder_by_type_id), 1 },
227 { "android/media/MediaCodec", "getName", "()Ljava/lang/String;", FF_JNI_METHOD, OFFSET(get_name_id), 1 },
229 { "android/media/MediaCodec", "configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V", FF_JNI_METHOD, OFFSET(configure_id), 1 },
230 { "android/media/MediaCodec", "start", "()V", FF_JNI_METHOD, OFFSET(start_id), 1 },
231 { "android/media/MediaCodec", "flush", "()V", FF_JNI_METHOD, OFFSET(flush_id), 1 },
232 { "android/media/MediaCodec", "stop", "()V", FF_JNI_METHOD, OFFSET(stop_id), 1 },
233 { "android/media/MediaCodec", "release", "()V", FF_JNI_METHOD, OFFSET(release_id), 1 },
235 { "android/media/MediaCodec", "getOutputFormat", "()Landroid/media/MediaFormat;", FF_JNI_METHOD, OFFSET(get_output_format_id), 1 },
237 { "android/media/MediaCodec", "dequeueInputBuffer", "(J)I", FF_JNI_METHOD, OFFSET(dequeue_input_buffer_id), 1 },
238 { "android/media/MediaCodec", "queueInputBuffer", "(IIIJI)V", FF_JNI_METHOD, OFFSET(queue_input_buffer_id), 1 },
239 { "android/media/MediaCodec", "getInputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, OFFSET(get_input_buffer_id), 0 },
240 { "android/media/MediaCodec", "getInputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, OFFSET(get_input_buffers_id), 1 },
242 { "android/media/MediaCodec", "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", FF_JNI_METHOD, OFFSET(dequeue_output_buffer_id), 1 },
243 { "android/media/MediaCodec", "getOutputBuffer", "(I)Ljava/nio/ByteBuffer;", FF_JNI_METHOD, OFFSET(get_output_buffer_id), 0 },
244 { "android/media/MediaCodec", "getOutputBuffers", "()[Ljava/nio/ByteBuffer;", FF_JNI_METHOD, OFFSET(get_output_buffers_id), 1 },
245 { "android/media/MediaCodec", "releaseOutputBuffer", "(IZ)V", FF_JNI_METHOD, OFFSET(release_output_buffer_id), 1 },
246 { "android/media/MediaCodec", "releaseOutputBuffer", "(IJ)V", FF_JNI_METHOD, OFFSET(release_output_buffer_at_time_id), 0 },
248 { "android/media/MediaCodec", "setInputSurface", "(Landroid/view/Surface;)V", FF_JNI_METHOD, OFFSET(set_input_surface_id), 0 },
249 { "android/media/MediaCodec", "signalEndOfInputStream", "()V", FF_JNI_METHOD, OFFSET(signal_end_of_input_stream_id), 0 },
251 { "android/media/MediaCodec$BufferInfo", NULL, NULL, FF_JNI_CLASS, OFFSET(mediainfo_class), 1 },
253 { "android/media/MediaCodec.BufferInfo", "<init>", "()V", FF_JNI_METHOD, OFFSET(init_id), 1 },
254 { "android/media/MediaCodec.BufferInfo", "flags", "I", FF_JNI_FIELD, OFFSET(flags_id), 1 },
255 { "android/media/MediaCodec.BufferInfo", "offset", "I", FF_JNI_FIELD, OFFSET(offset_id), 1 },
256 { "android/media/MediaCodec.BufferInfo", "presentationTimeUs", "J", FF_JNI_FIELD, OFFSET(presentation_time_us_id), 1 },
257 { "android/media/MediaCodec.BufferInfo", "size", "I", FF_JNI_FIELD, OFFSET(size_id), 1 },
259 { NULL }
261 #undef OFFSET
263 static const AVClass amediacodec_class = {
264 .class_name = "amediacodec",
265 .item_name = av_default_item_name,
266 .version = LIBAVUTIL_VERSION_INT,
269 typedef struct FFAMediaCodecJni {
270 FFAMediaCodec api;
272 struct JNIAMediaCodecFields jfields;
274 jobject object;
275 jobject buffer_info;
277 jobject input_buffers;
278 jobject output_buffers;
280 int INFO_TRY_AGAIN_LATER;
281 int INFO_OUTPUT_BUFFERS_CHANGED;
282 int INFO_OUTPUT_FORMAT_CHANGED;
284 int BUFFER_FLAG_CODEC_CONFIG;
285 int BUFFER_FLAG_END_OF_STREAM;
286 int BUFFER_FLAG_KEY_FRAME;
288 int CONFIGURE_FLAG_ENCODE;
290 int has_get_i_o_buffer;
291 } FFAMediaCodecJni;
293 static const FFAMediaCodec media_codec_jni;
295 #define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do { \
296 (env) = ff_jni_get_env(log_ctx); \
297 if (!(env)) { \
298 return ret; \
300 } while (0)
302 #define JNI_GET_ENV_OR_RETURN_VOID(env, log_ctx) do { \
303 (env) = ff_jni_get_env(log_ctx); \
304 if (!(env)) { \
305 return; \
307 } while (0)
309 int ff_AMediaCodecProfile_getProfileFromAVCodecContext(AVCodecContext *avctx)
311 // Copy and modified from MediaCodecInfo.java
312 static const int AVCProfileBaseline = 0x01;
313 static const int AVCProfileMain = 0x02;
314 static const int AVCProfileExtended = 0x04;
315 static const int AVCProfileHigh = 0x08;
316 static const int AVCProfileHigh10 = 0x10;
317 static const int AVCProfileHigh422 = 0x20;
318 static const int AVCProfileHigh444 = 0x40;
319 static const int AVCProfileConstrainedBaseline = 0x10000;
320 static const int AVCProfileConstrainedHigh = 0x80000;
322 static const int HEVCProfileMain = 0x01;
323 static const int HEVCProfileMain10 = 0x02;
324 static const int HEVCProfileMainStill = 0x04;
325 static const int HEVCProfileMain10HDR10 = 0x1000;
326 static const int HEVCProfileMain10HDR10Plus = 0x2000;
328 static const int VP9Profile0 = 0x01;
329 static const int VP9Profile1 = 0x02;
330 static const int VP9Profile2 = 0x04;
331 static const int VP9Profile3 = 0x08;
332 static const int VP9Profile2HDR = 0x1000;
333 static const int VP9Profile3HDR = 0x2000;
334 static const int VP9Profile2HDR10Plus = 0x4000;
335 static const int VP9Profile3HDR10Plus = 0x8000;
337 static const int MPEG4ProfileSimple = 0x01;
338 static const int MPEG4ProfileSimpleScalable = 0x02;
339 static const int MPEG4ProfileCore = 0x04;
340 static const int MPEG4ProfileMain = 0x08;
341 static const int MPEG4ProfileNbit = 0x10;
342 static const int MPEG4ProfileScalableTexture = 0x20;
343 static const int MPEG4ProfileSimpleFBA = 0x80;
344 static const int MPEG4ProfileSimpleFace = 0x40;
345 static const int MPEG4ProfileBasicAnimated = 0x100;
346 static const int MPEG4ProfileHybrid = 0x200;
347 static const int MPEG4ProfileAdvancedRealTime = 0x400;
348 static const int MPEG4ProfileCoreScalable = 0x800;
349 static const int MPEG4ProfileAdvancedCoding = 0x1000;
350 static const int MPEG4ProfileAdvancedCore = 0x2000;
351 static const int MPEG4ProfileAdvancedScalable = 0x4000;
352 static const int MPEG4ProfileAdvancedSimple = 0x8000;
355 static const int AV1ProfileMain8 = 0x1;
356 static const int AV1ProfileMain10 = 0x2;
357 static const int AV1ProfileMain10HDR10 = 0x1000;
358 static const int AV1ProfileMain10HDR10Plus = 0x2000;
360 // Unused yet.
361 (void)AVCProfileConstrainedHigh;
362 (void)HEVCProfileMain10HDR10;
363 (void)HEVCProfileMain10HDR10Plus;
364 (void)VP9Profile2HDR;
365 (void)VP9Profile3HDR;
366 (void)VP9Profile2HDR10Plus;
367 (void)VP9Profile3HDR10Plus;
368 (void)MPEG4ProfileSimpleFace;
369 (void)AV1ProfileMain10;
370 (void)AV1ProfileMain10HDR10;
371 (void)AV1ProfileMain10HDR10Plus;
373 if (avctx->codec_id == AV_CODEC_ID_H264) {
374 switch(avctx->profile) {
375 case AV_PROFILE_H264_BASELINE:
376 return AVCProfileBaseline;
377 case AV_PROFILE_H264_CONSTRAINED_BASELINE:
378 return AVCProfileConstrainedBaseline;
379 case AV_PROFILE_H264_MAIN:
380 return AVCProfileMain;
381 break;
382 case AV_PROFILE_H264_EXTENDED:
383 return AVCProfileExtended;
384 case AV_PROFILE_H264_HIGH:
385 return AVCProfileHigh;
386 case AV_PROFILE_H264_HIGH_10:
387 case AV_PROFILE_H264_HIGH_10_INTRA:
388 return AVCProfileHigh10;
389 case AV_PROFILE_H264_HIGH_422:
390 case AV_PROFILE_H264_HIGH_422_INTRA:
391 return AVCProfileHigh422;
392 case AV_PROFILE_H264_HIGH_444:
393 case AV_PROFILE_H264_HIGH_444_INTRA:
394 case AV_PROFILE_H264_HIGH_444_PREDICTIVE:
395 return AVCProfileHigh444;
397 } else if (avctx->codec_id == AV_CODEC_ID_HEVC) {
398 switch (avctx->profile) {
399 case AV_PROFILE_HEVC_MAIN:
400 return HEVCProfileMain;
401 case AV_PROFILE_HEVC_MAIN_STILL_PICTURE:
402 return HEVCProfileMainStill;
403 case AV_PROFILE_HEVC_MAIN_10:
404 return HEVCProfileMain10;
406 } else if (avctx->codec_id == AV_CODEC_ID_VP9) {
407 switch (avctx->profile) {
408 case AV_PROFILE_VP9_0:
409 return VP9Profile0;
410 case AV_PROFILE_VP9_1:
411 return VP9Profile1;
412 case AV_PROFILE_VP9_2:
413 return VP9Profile2;
414 case AV_PROFILE_VP9_3:
415 return VP9Profile3;
417 } else if(avctx->codec_id == AV_CODEC_ID_MPEG4) {
418 switch (avctx->profile)
420 case AV_PROFILE_MPEG4_SIMPLE:
421 return MPEG4ProfileSimple;
422 case AV_PROFILE_MPEG4_SIMPLE_SCALABLE:
423 return MPEG4ProfileSimpleScalable;
424 case AV_PROFILE_MPEG4_CORE:
425 return MPEG4ProfileCore;
426 case AV_PROFILE_MPEG4_MAIN:
427 return MPEG4ProfileMain;
428 case AV_PROFILE_MPEG4_N_BIT:
429 return MPEG4ProfileNbit;
430 case AV_PROFILE_MPEG4_SCALABLE_TEXTURE:
431 return MPEG4ProfileScalableTexture;
432 case AV_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION:
433 return MPEG4ProfileSimpleFBA;
434 case AV_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE:
435 return MPEG4ProfileBasicAnimated;
436 case AV_PROFILE_MPEG4_HYBRID:
437 return MPEG4ProfileHybrid;
438 case AV_PROFILE_MPEG4_ADVANCED_REAL_TIME:
439 return MPEG4ProfileAdvancedRealTime;
440 case AV_PROFILE_MPEG4_CORE_SCALABLE:
441 return MPEG4ProfileCoreScalable;
442 case AV_PROFILE_MPEG4_ADVANCED_CODING:
443 return MPEG4ProfileAdvancedCoding;
444 case AV_PROFILE_MPEG4_ADVANCED_CORE:
445 return MPEG4ProfileAdvancedCore;
446 case AV_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE:
447 return MPEG4ProfileAdvancedScalable;
448 case AV_PROFILE_MPEG4_ADVANCED_SIMPLE:
449 return MPEG4ProfileAdvancedSimple;
450 case AV_PROFILE_MPEG4_SIMPLE_STUDIO:
451 // Studio profiles are not supported by mediacodec.
452 default:
453 break;
455 } else if(avctx->codec_id == AV_CODEC_ID_AV1) {
456 switch (avctx->profile)
458 case AV_PROFILE_AV1_MAIN:
459 return AV1ProfileMain8;
460 case AV_PROFILE_AV1_HIGH:
461 case AV_PROFILE_AV1_PROFESSIONAL:
462 default:
463 break;
467 return -1;
470 char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int encoder, void *log_ctx)
472 int ret;
473 int i;
474 int codec_count;
475 int found_codec = 0;
476 char *name = NULL;
477 char *supported_type = NULL;
479 JNIEnv *env = NULL;
480 struct JNIAMediaCodecListFields jfields = { 0 };
481 struct JNIAMediaFormatFields mediaformat_jfields = { 0 };
483 jobject codec_name = NULL;
485 jobject info = NULL;
486 jobject type = NULL;
487 jobjectArray types = NULL;
489 jobject capabilities = NULL;
490 jobject profile_level = NULL;
491 jobjectArray profile_levels = NULL;
493 JNI_GET_ENV_OR_RETURN(env, log_ctx, NULL);
495 if ((ret = ff_jni_init_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx)) < 0) {
496 goto done;
499 if ((ret = ff_jni_init_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx)) < 0) {
500 goto done;
503 codec_count = (*env)->CallStaticIntMethod(env, jfields.mediacodec_list_class, jfields.get_codec_count_id);
504 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
505 goto done;
508 for(i = 0; i < codec_count; i++) {
509 int j;
510 int type_count;
511 int is_encoder;
513 info = (*env)->CallStaticObjectMethod(env, jfields.mediacodec_list_class, jfields.get_codec_info_at_id, i);
514 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
515 goto done;
518 types = (*env)->CallObjectMethod(env, info, jfields.get_supported_types_id);
519 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
520 goto done;
523 is_encoder = (*env)->CallBooleanMethod(env, info, jfields.is_encoder_id);
524 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
525 goto done;
528 if (is_encoder != encoder) {
529 goto done_with_info;
532 if (jfields.is_software_only_id) {
533 int is_software_only = (*env)->CallBooleanMethod(env, info, jfields.is_software_only_id);
534 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
535 goto done;
538 if (is_software_only) {
539 goto done_with_info;
543 codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
544 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
545 goto done;
548 name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
549 if (!name) {
550 goto done;
553 (*env)->DeleteLocalRef(env, codec_name);
554 codec_name = NULL;
556 /* Skip software decoders */
557 if (
558 strstr(name, "OMX.google") ||
559 strstr(name, "OMX.ffmpeg") ||
560 (strstr(name, "OMX.SEC") && strstr(name, ".sw.")) ||
561 !strcmp(name, "OMX.qcom.video.decoder.hevcswvdec")) {
562 goto done_with_info;
565 type_count = (*env)->GetArrayLength(env, types);
566 for (j = 0; j < type_count; j++) {
567 int k;
568 int profile_count;
570 type = (*env)->GetObjectArrayElement(env, types, j);
571 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
572 goto done;
575 supported_type = ff_jni_jstring_to_utf_chars(env, type, log_ctx);
576 if (!supported_type) {
577 goto done;
580 if (av_strcasecmp(supported_type, mime)) {
581 goto done_with_type;
584 capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
585 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
586 goto done;
589 profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
590 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
591 goto done;
594 profile_count = (*env)->GetArrayLength(env, profile_levels);
595 if (!profile_count) {
596 found_codec = 1;
598 for (k = 0; k < profile_count; k++) {
599 int supported_profile = 0;
601 if (profile < 0) {
602 found_codec = 1;
603 break;
606 profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
607 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
608 goto done;
611 supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
612 if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
613 goto done;
616 found_codec = profile == supported_profile;
618 (*env)->DeleteLocalRef(env, profile_level);
619 profile_level = NULL;
621 if (found_codec) {
622 break;
626 done_with_type:
627 (*env)->DeleteLocalRef(env, profile_levels);
628 profile_levels = NULL;
630 (*env)->DeleteLocalRef(env, capabilities);
631 capabilities = NULL;
633 (*env)->DeleteLocalRef(env, type);
634 type = NULL;
636 av_freep(&supported_type);
638 if (found_codec) {
639 break;
643 done_with_info:
644 (*env)->DeleteLocalRef(env, info);
645 info = NULL;
647 (*env)->DeleteLocalRef(env, types);
648 types = NULL;
650 if (found_codec) {
651 break;
654 av_freep(&name);
657 done:
658 (*env)->DeleteLocalRef(env, codec_name);
659 (*env)->DeleteLocalRef(env, info);
660 (*env)->DeleteLocalRef(env, type);
661 (*env)->DeleteLocalRef(env, types);
662 (*env)->DeleteLocalRef(env, capabilities);
663 (*env)->DeleteLocalRef(env, profile_level);
664 (*env)->DeleteLocalRef(env, profile_levels);
666 av_freep(&supported_type);
668 ff_jni_reset_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx);
669 ff_jni_reset_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx);
671 if (!found_codec) {
672 av_freep(&name);
675 return name;
678 static FFAMediaFormat *mediaformat_jni_new(void)
680 JNIEnv *env = NULL;
681 FFAMediaFormatJni *format = NULL;
682 jobject object = NULL;
684 format = av_mallocz(sizeof(*format));
685 if (!format) {
686 return NULL;
688 format->api = media_format_jni;
690 env = ff_jni_get_env(format);
691 if (!env) {
692 av_freep(&format);
693 return NULL;
696 if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
697 goto fail;
700 object = (*env)->NewObject(env, format->jfields.mediaformat_class, format->jfields.init_id);
701 if (!object) {
702 goto fail;
705 format->object = (*env)->NewGlobalRef(env, object);
706 if (!format->object) {
707 goto fail;
710 fail:
711 (*env)->DeleteLocalRef(env, object);
713 if (!format->object) {
714 ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
715 av_freep(&format);
718 return (FFAMediaFormat *)format;
721 static FFAMediaFormat *mediaformat_jni_newFromObject(void *object)
723 JNIEnv *env = NULL;
724 FFAMediaFormatJni *format = NULL;
726 format = av_mallocz(sizeof(*format));
727 if (!format) {
728 return NULL;
730 format->api = media_format_jni;
732 env = ff_jni_get_env(format);
733 if (!env) {
734 av_freep(&format);
735 return NULL;
738 if (ff_jni_init_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format) < 0) {
739 goto fail;
742 format->object = (*env)->NewGlobalRef(env, object);
743 if (!format->object) {
744 goto fail;
747 return (FFAMediaFormat *)format;
748 fail:
749 ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
751 av_freep(&format);
753 return NULL;
756 static int mediaformat_jni_delete(FFAMediaFormat* ctx)
758 int ret = 0;
759 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
760 JNIEnv *env = NULL;
762 if (!format) {
763 return 0;
766 JNI_GET_ENV_OR_RETURN(env, format, AVERROR_EXTERNAL);
768 (*env)->DeleteGlobalRef(env, format->object);
769 format->object = NULL;
771 ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format);
773 av_freep(&format);
775 return ret;
778 static char* mediaformat_jni_toString(FFAMediaFormat* ctx)
780 char *ret = NULL;
781 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
782 JNIEnv *env = NULL;
783 jstring description = NULL;
785 av_assert0(format != NULL);
787 JNI_GET_ENV_OR_RETURN(env, format, NULL);
789 description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id);
790 if (ff_jni_exception_check(env, 1, NULL) < 0) {
791 goto fail;
794 ret = ff_jni_jstring_to_utf_chars(env, description, format);
795 fail:
796 (*env)->DeleteLocalRef(env, description);
798 return ret;
801 static int mediaformat_jni_getInt32(FFAMediaFormat* ctx, const char *name, int32_t *out)
803 int ret = 1;
804 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
805 JNIEnv *env = NULL;
806 jstring key = NULL;
807 jboolean contains_key;
809 av_assert0(format != NULL);
811 JNI_GET_ENV_OR_RETURN(env, format, 0);
813 key = ff_jni_utf_chars_to_jstring(env, name, format);
814 if (!key) {
815 ret = 0;
816 goto fail;
819 contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
820 if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
821 ret = 0;
822 goto fail;
825 *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
826 if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
827 ret = 0;
828 goto fail;
831 ret = 1;
832 fail:
833 (*env)->DeleteLocalRef(env, key);
835 return ret;
838 static int mediaformat_jni_getInt64(FFAMediaFormat* ctx, const char *name, int64_t *out)
840 int ret = 1;
841 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
842 JNIEnv *env = NULL;
843 jstring key = NULL;
844 jboolean contains_key;
846 av_assert0(format != NULL);
848 JNI_GET_ENV_OR_RETURN(env, format, 0);
850 key = ff_jni_utf_chars_to_jstring(env, name, format);
851 if (!key) {
852 ret = 0;
853 goto fail;
856 contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
857 if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
858 ret = 0;
859 goto fail;
862 *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
863 if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
864 ret = 0;
865 goto fail;
868 ret = 1;
869 fail:
870 (*env)->DeleteLocalRef(env, key);
872 return ret;
875 static int mediaformat_jni_getFloat(FFAMediaFormat* ctx, const char *name, float *out)
877 int ret = 1;
878 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
879 JNIEnv *env = NULL;
880 jstring key = NULL;
881 jboolean contains_key;
883 av_assert0(format != NULL);
885 JNI_GET_ENV_OR_RETURN(env, format, 0);
887 key = ff_jni_utf_chars_to_jstring(env, name, format);
888 if (!key) {
889 ret = 0;
890 goto fail;
893 contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
894 if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
895 ret = 0;
896 goto fail;
899 *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
900 if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
901 ret = 0;
902 goto fail;
905 ret = 1;
906 fail:
907 (*env)->DeleteLocalRef(env, key);
909 return ret;
912 static int mediaformat_jni_getBuffer(FFAMediaFormat* ctx, const char *name, void** data, size_t *size)
914 int ret = 1;
915 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
916 JNIEnv *env = NULL;
917 jstring key = NULL;
918 jboolean contains_key;
919 jobject result = NULL;
921 av_assert0(format != NULL);
923 JNI_GET_ENV_OR_RETURN(env, format, 0);
925 key = ff_jni_utf_chars_to_jstring(env, name, format);
926 if (!key) {
927 ret = 0;
928 goto fail;
931 contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
932 if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
933 ret = 0;
934 goto fail;
937 result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
938 if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
939 ret = 0;
940 goto fail;
943 *data = (*env)->GetDirectBufferAddress(env, result);
944 *size = (*env)->GetDirectBufferCapacity(env, result);
946 if (*data && *size) {
947 void *src = *data;
948 *data = av_malloc(*size);
949 if (!*data) {
950 ret = 0;
951 goto fail;
954 memcpy(*data, src, *size);
957 ret = 1;
958 fail:
959 (*env)->DeleteLocalRef(env, key);
960 (*env)->DeleteLocalRef(env, result);
962 return ret;
965 static int mediaformat_jni_getString(FFAMediaFormat* ctx, const char *name, const char **out)
967 int ret = 1;
968 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
969 JNIEnv *env = NULL;
970 jstring key = NULL;
971 jboolean contains_key;
972 jstring result = NULL;
974 av_assert0(format != NULL);
976 JNI_GET_ENV_OR_RETURN(env, format, 0);
978 key = ff_jni_utf_chars_to_jstring(env, name, format);
979 if (!key) {
980 ret = 0;
981 goto fail;
984 contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
985 if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
986 ret = 0;
987 goto fail;
990 result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
991 if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
992 ret = 0;
993 goto fail;
996 *out = ff_jni_jstring_to_utf_chars(env, result, format);
997 if (!*out) {
998 ret = 0;
999 goto fail;
1002 ret = 1;
1003 fail:
1004 (*env)->DeleteLocalRef(env, key);
1005 (*env)->DeleteLocalRef(env, result);
1007 return ret;
1010 static void mediaformat_jni_setInt32(FFAMediaFormat* ctx, const char* name, int32_t value)
1012 JNIEnv *env = NULL;
1013 jstring key = NULL;
1014 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
1016 av_assert0(format != NULL);
1018 JNI_GET_ENV_OR_RETURN_VOID(env, format);
1020 key = ff_jni_utf_chars_to_jstring(env, name, format);
1021 if (!key) {
1022 goto fail;
1025 (*env)->CallVoidMethod(env, format->object, format->jfields.set_integer_id, key, value);
1026 if (ff_jni_exception_check(env, 1, format) < 0) {
1027 goto fail;
1030 fail:
1031 (*env)->DeleteLocalRef(env, key);
1034 static void mediaformat_jni_setInt64(FFAMediaFormat* ctx, const char* name, int64_t value)
1036 JNIEnv *env = NULL;
1037 jstring key = NULL;
1038 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
1040 av_assert0(format != NULL);
1042 JNI_GET_ENV_OR_RETURN_VOID(env, format);
1044 key = ff_jni_utf_chars_to_jstring(env, name, format);
1045 if (!key) {
1046 goto fail;
1049 (*env)->CallVoidMethod(env, format->object, format->jfields.set_long_id, key, value);
1050 if (ff_jni_exception_check(env, 1, format) < 0) {
1051 goto fail;
1054 fail:
1055 (*env)->DeleteLocalRef(env, key);
1058 static void mediaformat_jni_setFloat(FFAMediaFormat* ctx, const char* name, float value)
1060 JNIEnv *env = NULL;
1061 jstring key = NULL;
1062 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
1064 av_assert0(format != NULL);
1066 JNI_GET_ENV_OR_RETURN_VOID(env, format);
1068 key = ff_jni_utf_chars_to_jstring(env, name, format);
1069 if (!key) {
1070 goto fail;
1073 (*env)->CallVoidMethod(env, format->object, format->jfields.set_float_id, key, value);
1074 if (ff_jni_exception_check(env, 1, format) < 0) {
1075 goto fail;
1078 fail:
1079 (*env)->DeleteLocalRef(env, key);
1082 static void mediaformat_jni_setString(FFAMediaFormat* ctx, const char* name, const char* value)
1084 JNIEnv *env = NULL;
1085 jstring key = NULL;
1086 jstring string = NULL;
1087 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
1089 av_assert0(format != NULL);
1091 JNI_GET_ENV_OR_RETURN_VOID(env, format);
1093 key = ff_jni_utf_chars_to_jstring(env, name, format);
1094 if (!key) {
1095 goto fail;
1098 string = ff_jni_utf_chars_to_jstring(env, value, format);
1099 if (!string) {
1100 goto fail;
1103 (*env)->CallVoidMethod(env, format->object, format->jfields.set_string_id, key, string);
1104 if (ff_jni_exception_check(env, 1, format) < 0) {
1105 goto fail;
1108 fail:
1109 (*env)->DeleteLocalRef(env, key);
1110 (*env)->DeleteLocalRef(env, string);
1113 static void mediaformat_jni_setBuffer(FFAMediaFormat* ctx, const char* name, void* data, size_t size)
1115 JNIEnv *env = NULL;
1116 jstring key = NULL;
1117 jobject buffer = NULL;
1118 void *buffer_data = NULL;
1119 FFAMediaFormatJni *format = (FFAMediaFormatJni *)ctx;
1121 av_assert0(format != NULL);
1123 JNI_GET_ENV_OR_RETURN_VOID(env, format);
1125 key = ff_jni_utf_chars_to_jstring(env, name, format);
1126 if (!key) {
1127 goto fail;
1130 if (!data || !size) {
1131 goto fail;
1134 buffer_data = av_malloc(size);
1135 if (!buffer_data) {
1136 goto fail;
1139 memcpy(buffer_data, data, size);
1141 buffer = (*env)->NewDirectByteBuffer(env, buffer_data, size);
1142 if (!buffer) {
1143 goto fail;
1146 (*env)->CallVoidMethod(env, format->object, format->jfields.set_bytebuffer_id, key, buffer);
1147 if (ff_jni_exception_check(env, 1, format) < 0) {
1148 goto fail;
1151 fail:
1152 (*env)->DeleteLocalRef(env, key);
1153 (*env)->DeleteLocalRef(env, buffer);
1156 static int codec_init_static_fields(FFAMediaCodecJni *codec)
1158 int ret = 0;
1159 JNIEnv *env = NULL;
1161 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1163 codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1164 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1165 goto fail;
1168 codec->BUFFER_FLAG_CODEC_CONFIG = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_codec_config_id);
1169 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1170 goto fail;
1173 codec->BUFFER_FLAG_END_OF_STREAM = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_end_of_stream_id);
1174 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1175 goto fail;
1178 if (codec->jfields.buffer_flag_key_frame_id) {
1179 codec->BUFFER_FLAG_KEY_FRAME = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.buffer_flag_key_frame_id);
1180 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1181 goto fail;
1185 codec->CONFIGURE_FLAG_ENCODE = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.configure_flag_encode_id);
1186 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1187 goto fail;
1190 codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id);
1191 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1192 goto fail;
1195 codec->INFO_OUTPUT_BUFFERS_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_buffers_changed_id);
1196 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1197 goto fail;
1200 codec->INFO_OUTPUT_FORMAT_CHANGED = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_output_format_changed_id);
1201 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1202 goto fail;
1205 fail:
1207 return ret;
1210 #define CREATE_CODEC_BY_NAME 0
1211 #define CREATE_DECODER_BY_TYPE 1
1212 #define CREATE_ENCODER_BY_TYPE 2
1214 static inline FFAMediaCodec *codec_create(int method, const char *arg)
1216 int ret = -1;
1217 JNIEnv *env = NULL;
1218 FFAMediaCodecJni *codec = NULL;
1219 jstring jarg = NULL;
1220 jobject object = NULL;
1221 jobject buffer_info = NULL;
1222 jmethodID create_id = NULL;
1224 codec = av_mallocz(sizeof(*codec));
1225 if (!codec) {
1226 return NULL;
1228 codec->api = media_codec_jni;
1230 env = ff_jni_get_env(codec);
1231 if (!env) {
1232 av_freep(&codec);
1233 return NULL;
1236 if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) {
1237 goto fail;
1240 jarg = ff_jni_utf_chars_to_jstring(env, arg, codec);
1241 if (!jarg) {
1242 goto fail;
1245 switch (method) {
1246 case CREATE_CODEC_BY_NAME: create_id = codec->jfields.create_by_codec_name_id; break;
1247 case CREATE_DECODER_BY_TYPE: create_id = codec->jfields.create_decoder_by_type_id; break;
1248 case CREATE_ENCODER_BY_TYPE: create_id = codec->jfields.create_encoder_by_type_id; break;
1249 default:
1250 av_assert0(0);
1253 object = (*env)->CallStaticObjectMethod(env,
1254 codec->jfields.mediacodec_class,
1255 create_id,
1256 jarg);
1257 if (ff_jni_exception_check(env, 1, codec) < 0) {
1258 goto fail;
1261 codec->object = (*env)->NewGlobalRef(env, object);
1262 if (!codec->object) {
1263 goto fail;
1266 if (codec_init_static_fields(codec) < 0) {
1267 goto fail;
1270 if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) {
1271 codec->has_get_i_o_buffer = 1;
1274 buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
1275 if (ff_jni_exception_check(env, 1, codec) < 0) {
1276 goto fail;
1279 codec->buffer_info = (*env)->NewGlobalRef(env, buffer_info);
1280 if (!codec->buffer_info) {
1281 goto fail;
1284 ret = 0;
1285 fail:
1286 (*env)->DeleteLocalRef(env, jarg);
1287 (*env)->DeleteLocalRef(env, object);
1288 (*env)->DeleteLocalRef(env, buffer_info);
1290 if (ret < 0) {
1291 (*env)->DeleteGlobalRef(env, codec->object);
1292 (*env)->DeleteGlobalRef(env, codec->buffer_info);
1294 ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1295 av_freep(&codec);
1298 return (FFAMediaCodec *)codec;
1301 #define DECLARE_FF_AMEDIACODEC_CREATE_FUNC(name, method) \
1302 static FFAMediaCodec *mediacodec_jni_##name(const char *arg) \
1304 return codec_create(method, arg); \
1307 DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createCodecByName, CREATE_CODEC_BY_NAME)
1308 DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createDecoderByType, CREATE_DECODER_BY_TYPE)
1309 DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createEncoderByType, CREATE_ENCODER_BY_TYPE)
1311 static int mediacodec_jni_delete(FFAMediaCodec* ctx)
1313 int ret = 0;
1314 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1315 JNIEnv *env = NULL;
1317 if (!codec) {
1318 return 0;
1321 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1323 (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id);
1324 if (ff_jni_exception_check(env, 1, codec) < 0) {
1325 ret = AVERROR_EXTERNAL;
1328 (*env)->DeleteGlobalRef(env, codec->input_buffers);
1329 codec->input_buffers = NULL;
1331 (*env)->DeleteGlobalRef(env, codec->output_buffers);
1332 codec->output_buffers = NULL;
1334 (*env)->DeleteGlobalRef(env, codec->object);
1335 codec->object = NULL;
1337 (*env)->DeleteGlobalRef(env, codec->buffer_info);
1338 codec->buffer_info = NULL;
1340 ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
1342 av_freep(&codec);
1344 return ret;
1347 static char *mediacodec_jni_getName(FFAMediaCodec *ctx)
1349 char *ret = NULL;
1350 JNIEnv *env = NULL;
1351 jobject *name = NULL;
1352 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1354 JNI_GET_ENV_OR_RETURN(env, codec, NULL);
1356 name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id);
1357 if (ff_jni_exception_check(env, 1, codec) < 0) {
1358 goto fail;
1361 ret = ff_jni_jstring_to_utf_chars(env, name, codec);
1363 fail:
1364 if (name) {
1365 (*env)->DeleteLocalRef(env, name);
1368 return ret;
1371 static int mediacodec_jni_configure(FFAMediaCodec *ctx,
1372 const FFAMediaFormat* format_ctx,
1373 FFANativeWindow* window,
1374 void *crypto,
1375 uint32_t flags)
1377 int ret = 0;
1378 JNIEnv *env = NULL;
1379 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1380 const FFAMediaFormatJni *format = (FFAMediaFormatJni *)format_ctx;
1381 jobject *surface = window ? window->surface : NULL;
1383 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1385 if (flags & codec->CONFIGURE_FLAG_ENCODE) {
1386 if (surface && !codec->jfields.set_input_surface_id) {
1387 av_log(ctx, AV_LOG_ERROR, "System doesn't support setInputSurface\n");
1388 return AVERROR_EXTERNAL;
1391 (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, NULL, NULL, flags);
1392 if (ff_jni_exception_check(env, 1, codec) < 0)
1393 return AVERROR_EXTERNAL;
1395 if (!surface)
1396 return 0;
1398 (*env)->CallVoidMethod(env, codec->object, codec->jfields.set_input_surface_id, surface);
1399 if (ff_jni_exception_check(env, 1, codec) < 0)
1400 return AVERROR_EXTERNAL;
1401 return 0;
1402 } else {
1403 (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, surface, NULL, flags);
1405 if (ff_jni_exception_check(env, 1, codec) < 0) {
1406 ret = AVERROR_EXTERNAL;
1407 goto fail;
1410 fail:
1411 return ret;
1414 static int mediacodec_jni_start(FFAMediaCodec* ctx)
1416 int ret = 0;
1417 JNIEnv *env = NULL;
1418 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1420 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1422 (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id);
1423 if (ff_jni_exception_check(env, 1, codec) < 0) {
1424 ret = AVERROR_EXTERNAL;
1425 goto fail;
1428 fail:
1429 return ret;
1432 static int mediacodec_jni_stop(FFAMediaCodec* ctx)
1434 int ret = 0;
1435 JNIEnv *env = NULL;
1436 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1438 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1440 (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id);
1441 if (ff_jni_exception_check(env, 1, codec) < 0) {
1442 ret = AVERROR_EXTERNAL;
1443 goto fail;
1446 fail:
1447 return ret;
1450 static int mediacodec_jni_flush(FFAMediaCodec* ctx)
1452 int ret = 0;
1453 JNIEnv *env = NULL;
1454 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1456 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1458 (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id);
1459 if (ff_jni_exception_check(env, 1, codec) < 0) {
1460 ret = AVERROR_EXTERNAL;
1461 goto fail;
1464 fail:
1465 return ret;
1468 static int mediacodec_jni_releaseOutputBuffer(FFAMediaCodec* ctx, size_t idx, int render)
1470 int ret = 0;
1471 JNIEnv *env = NULL;
1472 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1474 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1476 (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, (jint)idx, (jboolean)render);
1477 if (ff_jni_exception_check(env, 1, codec) < 0) {
1478 ret = AVERROR_EXTERNAL;
1479 goto fail;
1482 fail:
1483 return ret;
1486 static int mediacodec_jni_releaseOutputBufferAtTime(FFAMediaCodec *ctx, size_t idx, int64_t timestampNs)
1488 int ret = 0;
1489 JNIEnv *env = NULL;
1490 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1492 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1494 (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, (jlong)timestampNs);
1495 if (ff_jni_exception_check(env, 1, codec) < 0) {
1496 ret = AVERROR_EXTERNAL;
1497 goto fail;
1500 fail:
1501 return ret;
1504 static ssize_t mediacodec_jni_dequeueInputBuffer(FFAMediaCodec* ctx, int64_t timeoutUs)
1506 int ret = 0;
1507 JNIEnv *env = NULL;
1508 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1510 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1512 ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs);
1513 if (ff_jni_exception_check(env, 1, codec) < 0) {
1514 ret = AVERROR_EXTERNAL;
1515 goto fail;
1518 fail:
1519 return ret;
1522 static int mediacodec_jni_queueInputBuffer(FFAMediaCodec* ctx, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags)
1524 int ret = 0;
1525 JNIEnv *env = NULL;
1526 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1528 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1530 (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, (jint)idx, (jint)offset, (jint)size, time, flags);
1531 if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) {
1532 ret = AVERROR_EXTERNAL;
1533 goto fail;
1536 fail:
1537 return ret;
1540 static ssize_t mediacodec_jni_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
1542 int ret = 0;
1543 JNIEnv *env = NULL;
1544 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1546 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1548 ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs);
1549 if (ff_jni_exception_check(env, 1, codec) < 0) {
1550 return AVERROR_EXTERNAL;
1553 info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id);
1554 if (ff_jni_exception_check(env, 1, codec) < 0) {
1555 return AVERROR_EXTERNAL;
1558 info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id);
1559 if (ff_jni_exception_check(env, 1, codec) < 0) {
1560 return AVERROR_EXTERNAL;
1563 info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id);
1564 if (ff_jni_exception_check(env, 1, codec) < 0) {
1565 return AVERROR_EXTERNAL;
1568 info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id);
1569 if (ff_jni_exception_check(env, 1, codec) < 0) {
1570 return AVERROR_EXTERNAL;
1573 return ret;
1576 static uint8_t* mediacodec_jni_getInputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
1578 uint8_t *ret = NULL;
1579 JNIEnv *env = NULL;
1580 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1581 jobject buffer = NULL;
1582 jobject input_buffers = NULL;
1584 JNI_GET_ENV_OR_RETURN(env, codec, NULL);
1586 if (codec->has_get_i_o_buffer) {
1587 buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, (jint)idx);
1588 if (ff_jni_exception_check(env, 1, codec) < 0) {
1589 goto fail;
1591 } else {
1592 if (!codec->input_buffers) {
1593 input_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffers_id);
1594 if (ff_jni_exception_check(env, 1, codec) < 0) {
1595 goto fail;
1598 codec->input_buffers = (*env)->NewGlobalRef(env, input_buffers);
1599 if (ff_jni_exception_check(env, 1, codec) < 0) {
1600 goto fail;
1604 buffer = (*env)->GetObjectArrayElement(env, codec->input_buffers, idx);
1605 if (ff_jni_exception_check(env, 1, codec) < 0) {
1606 goto fail;
1610 ret = (*env)->GetDirectBufferAddress(env, buffer);
1611 *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1612 fail:
1613 (*env)->DeleteLocalRef(env, buffer);
1614 (*env)->DeleteLocalRef(env, input_buffers);
1616 return ret;
1619 static uint8_t* mediacodec_jni_getOutputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
1621 uint8_t *ret = NULL;
1622 JNIEnv *env = NULL;
1623 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1624 jobject buffer = NULL;
1625 jobject output_buffers = NULL;
1627 JNI_GET_ENV_OR_RETURN(env, codec, NULL);
1629 if (codec->has_get_i_o_buffer) {
1630 buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, (jint)idx);
1631 if (ff_jni_exception_check(env, 1, codec) < 0) {
1632 goto fail;
1634 } else {
1635 if (!codec->output_buffers) {
1636 output_buffers = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffers_id);
1637 if (ff_jni_exception_check(env, 1, codec) < 0) {
1638 goto fail;
1641 codec->output_buffers = (*env)->NewGlobalRef(env, output_buffers);
1642 if (ff_jni_exception_check(env, 1, codec) < 0) {
1643 goto fail;
1647 buffer = (*env)->GetObjectArrayElement(env, codec->output_buffers, idx);
1648 if (ff_jni_exception_check(env, 1, codec) < 0) {
1649 goto fail;
1653 ret = (*env)->GetDirectBufferAddress(env, buffer);
1654 *out_size = (*env)->GetDirectBufferCapacity(env, buffer);
1655 fail:
1656 (*env)->DeleteLocalRef(env, buffer);
1657 (*env)->DeleteLocalRef(env, output_buffers);
1659 return ret;
1662 static FFAMediaFormat* mediacodec_jni_getOutputFormat(FFAMediaCodec* ctx)
1664 FFAMediaFormat *ret = NULL;
1665 JNIEnv *env = NULL;
1666 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1668 jobject mediaformat = NULL;
1670 JNI_GET_ENV_OR_RETURN(env, codec, NULL);
1672 mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id);
1673 if (ff_jni_exception_check(env, 1, codec) < 0) {
1674 goto fail;
1677 ret = mediaformat_jni_newFromObject(mediaformat);
1678 fail:
1679 (*env)->DeleteLocalRef(env, mediaformat);
1681 return ret;
1684 static int mediacodec_jni_infoTryAgainLater(FFAMediaCodec *ctx, ssize_t idx)
1686 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1687 return idx == codec->INFO_TRY_AGAIN_LATER;
1690 static int mediacodec_jni_infoOutputBuffersChanged(FFAMediaCodec *ctx, ssize_t idx)
1692 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1693 return idx == codec->INFO_OUTPUT_BUFFERS_CHANGED;
1696 static int mediacodec_jni_infoOutputFormatChanged(FFAMediaCodec *ctx, ssize_t idx)
1698 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1699 return idx == codec->INFO_OUTPUT_FORMAT_CHANGED;
1702 static int mediacodec_jni_getBufferFlagCodecConfig(FFAMediaCodec *ctx)
1704 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1705 return codec->BUFFER_FLAG_CODEC_CONFIG;
1708 static int mediacodec_jni_getBufferFlagEndOfStream(FFAMediaCodec *ctx)
1710 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1711 return codec->BUFFER_FLAG_END_OF_STREAM;
1714 static int mediacodec_jni_getBufferFlagKeyFrame(FFAMediaCodec *ctx)
1716 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1717 return codec->BUFFER_FLAG_KEY_FRAME;
1720 static int mediacodec_jni_getConfigureFlagEncode(FFAMediaCodec *ctx)
1722 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1723 return codec->CONFIGURE_FLAG_ENCODE;
1726 static int mediacodec_jni_cleanOutputBuffers(FFAMediaCodec *ctx)
1728 int ret = 0;
1729 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1731 if (!codec->has_get_i_o_buffer) {
1732 if (codec->output_buffers) {
1733 JNIEnv *env = NULL;
1735 env = ff_jni_get_env(codec);
1736 if (!env) {
1737 ret = AVERROR_EXTERNAL;
1738 goto fail;
1741 (*env)->DeleteGlobalRef(env, codec->output_buffers);
1742 codec->output_buffers = NULL;
1746 fail:
1747 return ret;
1750 static int mediacodec_jni_signalEndOfInputStream(FFAMediaCodec *ctx)
1752 JNIEnv *env = NULL;
1753 FFAMediaCodecJni *codec = (FFAMediaCodecJni *)ctx;
1755 JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
1757 (*env)->CallVoidMethod(env, codec->object, codec->jfields.signal_end_of_input_stream_id);
1758 if (ff_jni_exception_check(env, 1, codec) < 0) {
1759 return AVERROR_EXTERNAL;
1762 return 0;
1765 static int mediacodec_jni_setAsyncNotifyCallback(FFAMediaCodec *codec,
1766 const FFAMediaCodecOnAsyncNotifyCallback *callback,
1767 void *userdata)
1769 av_log(codec, AV_LOG_ERROR, "Doesn't support aync mode with JNI, please try ndk_codec=1\n");
1770 return AVERROR(ENOSYS);
1773 static const FFAMediaFormat media_format_jni = {
1774 .class = &amediaformat_class,
1776 .create = mediaformat_jni_new,
1777 .delete = mediaformat_jni_delete,
1779 .toString = mediaformat_jni_toString,
1781 .getInt32 = mediaformat_jni_getInt32,
1782 .getInt64 = mediaformat_jni_getInt64,
1783 .getFloat = mediaformat_jni_getFloat,
1784 .getBuffer = mediaformat_jni_getBuffer,
1785 .getString = mediaformat_jni_getString,
1787 .setInt32 = mediaformat_jni_setInt32,
1788 .setInt64 = mediaformat_jni_setInt64,
1789 .setFloat = mediaformat_jni_setFloat,
1790 .setString = mediaformat_jni_setString,
1791 .setBuffer = mediaformat_jni_setBuffer,
1794 static const FFAMediaCodec media_codec_jni = {
1795 .class = &amediacodec_class,
1797 .getName = mediacodec_jni_getName,
1799 .createCodecByName = mediacodec_jni_createCodecByName,
1800 .createDecoderByType = mediacodec_jni_createDecoderByType,
1801 .createEncoderByType = mediacodec_jni_createEncoderByType,
1802 .delete = mediacodec_jni_delete,
1804 .configure = mediacodec_jni_configure,
1805 .start = mediacodec_jni_start,
1806 .stop = mediacodec_jni_stop,
1807 .flush = mediacodec_jni_flush,
1809 .getInputBuffer = mediacodec_jni_getInputBuffer,
1810 .getOutputBuffer = mediacodec_jni_getOutputBuffer,
1812 .dequeueInputBuffer = mediacodec_jni_dequeueInputBuffer,
1813 .queueInputBuffer = mediacodec_jni_queueInputBuffer,
1815 .dequeueOutputBuffer = mediacodec_jni_dequeueOutputBuffer,
1816 .getOutputFormat = mediacodec_jni_getOutputFormat,
1818 .releaseOutputBuffer = mediacodec_jni_releaseOutputBuffer,
1819 .releaseOutputBufferAtTime = mediacodec_jni_releaseOutputBufferAtTime,
1821 .infoTryAgainLater = mediacodec_jni_infoTryAgainLater,
1822 .infoOutputBuffersChanged = mediacodec_jni_infoOutputBuffersChanged,
1823 .infoOutputFormatChanged = mediacodec_jni_infoOutputFormatChanged,
1825 .getBufferFlagCodecConfig = mediacodec_jni_getBufferFlagCodecConfig,
1826 .getBufferFlagEndOfStream = mediacodec_jni_getBufferFlagEndOfStream,
1827 .getBufferFlagKeyFrame = mediacodec_jni_getBufferFlagKeyFrame,
1829 .getConfigureFlagEncode = mediacodec_jni_getConfigureFlagEncode,
1830 .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers,
1831 .signalEndOfInputStream = mediacodec_jni_signalEndOfInputStream,
1832 .setAsyncNotifyCallback = mediacodec_jni_setAsyncNotifyCallback,
1835 typedef struct FFAMediaFormatNdk {
1836 FFAMediaFormat api;
1838 void *libmedia;
1839 AMediaFormat *impl;
1841 bool (*getRect)(AMediaFormat *, const char *name,
1842 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom);
1843 void (*setRect)(AMediaFormat *, const char *name,
1844 int32_t left, int32_t top, int32_t right, int32_t bottom);
1845 } FFAMediaFormatNdk;
1847 typedef struct FFAMediaCodecNdk {
1848 FFAMediaCodec api;
1850 void *libmedia;
1851 AMediaCodec *impl;
1852 ANativeWindow *window;
1854 FFAMediaCodecOnAsyncNotifyCallback async_cb;
1855 void *async_userdata;
1857 // Available since API level 28.
1858 media_status_t (*getName)(AMediaCodec*, char** out_name);
1859 void (*releaseName)(AMediaCodec*, char* name);
1861 // Available since API level 26.
1862 media_status_t (*setInputSurface)(AMediaCodec*, ANativeWindow *);
1863 media_status_t (*signalEndOfInputStream)(AMediaCodec *);
1864 media_status_t (*setAsyncNotifyCallback)(AMediaCodec *,
1865 struct AMediaCodecOnAsyncNotifyCallback callback, void *userdata);
1866 } FFAMediaCodecNdk;
1868 static const FFAMediaFormat media_format_ndk;
1869 static const FFAMediaCodec media_codec_ndk;
1871 static const AVClass amediaformat_ndk_class = {
1872 .class_name = "amediaformat_ndk",
1873 .item_name = av_default_item_name,
1874 .version = LIBAVUTIL_VERSION_INT,
1877 static const AVClass amediacodec_ndk_class = {
1878 .class_name = "amediacodec_ndk",
1879 .item_name = av_default_item_name,
1880 .version = LIBAVUTIL_VERSION_INT,
1883 static int media_status_to_error(media_status_t status)
1885 switch (status) {
1886 case AMEDIA_OK:
1887 return 0;
1888 case AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE:
1889 return AVERROR(ENOMEM);
1890 case AMEDIA_ERROR_MALFORMED:
1891 return AVERROR_INVALIDDATA;
1892 case AMEDIA_ERROR_UNSUPPORTED:
1893 return AVERROR(ENOTSUP);
1894 case AMEDIA_ERROR_INVALID_PARAMETER:
1895 return AVERROR(EINVAL);
1896 case AMEDIA_ERROR_INVALID_OPERATION:
1897 return AVERROR(EOPNOTSUPP);
1898 case AMEDIA_ERROR_END_OF_STREAM:
1899 return AVERROR_EOF;
1900 case AMEDIA_ERROR_IO:
1901 return AVERROR(EIO);
1902 case AMEDIA_ERROR_WOULD_BLOCK:
1903 return AVERROR(EWOULDBLOCK);
1904 default:
1905 return AVERROR_EXTERNAL;
1909 static FFAMediaFormat *mediaformat_ndk_create(AMediaFormat *impl)
1911 FFAMediaFormatNdk *format = av_mallocz(sizeof(*format));
1912 if (!format)
1913 return NULL;
1915 format->api = media_format_ndk;
1917 format->libmedia = dlopen("libmediandk.so", RTLD_NOW);
1918 if (!format->libmedia)
1919 goto error;
1921 #define GET_OPTIONAL_SYMBOL(sym) \
1922 format->sym = dlsym(format->libmedia, "AMediaFormat_" #sym);
1924 GET_OPTIONAL_SYMBOL(getRect)
1925 GET_OPTIONAL_SYMBOL(setRect)
1927 #undef GET_OPTIONAL_SYMBOL
1929 if (impl) {
1930 format->impl = impl;
1931 } else {
1932 format->impl = AMediaFormat_new();
1933 if (!format->impl)
1934 goto error;
1937 return (FFAMediaFormat *)format;
1939 error:
1940 if (format->libmedia)
1941 dlclose(format->libmedia);
1942 av_freep(&format);
1943 return NULL;
1946 static FFAMediaFormat *mediaformat_ndk_new(void)
1948 return mediaformat_ndk_create(NULL);
1951 static int mediaformat_ndk_delete(FFAMediaFormat* ctx)
1953 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1954 int ret = 0;
1955 if (!format)
1956 return 0;
1958 av_assert0(format->api.class == &amediaformat_ndk_class);
1960 if (format->impl && (AMediaFormat_delete(format->impl) != AMEDIA_OK))
1961 ret = AVERROR_EXTERNAL;
1962 if (format->libmedia)
1963 dlclose(format->libmedia);
1964 av_free(format);
1966 return ret;
1969 static char* mediaformat_ndk_toString(FFAMediaFormat* ctx)
1971 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1972 const char *str = AMediaFormat_toString(format->impl);
1973 return av_strdup(str);
1976 static int mediaformat_ndk_getInt32(FFAMediaFormat* ctx, const char *name, int32_t *out)
1978 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1979 return AMediaFormat_getInt32(format->impl, name, out);
1982 static int mediaformat_ndk_getInt64(FFAMediaFormat* ctx, const char *name, int64_t *out)
1984 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1985 return AMediaFormat_getInt64(format->impl, name, out);
1988 static int mediaformat_ndk_getFloat(FFAMediaFormat* ctx, const char *name, float *out)
1990 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1991 return AMediaFormat_getFloat(format->impl, name, out);
1994 static int mediaformat_ndk_getBuffer(FFAMediaFormat* ctx, const char *name, void** data, size_t *size)
1996 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
1997 return AMediaFormat_getBuffer(format->impl, name, data, size);
2000 static int mediaformat_ndk_getString(FFAMediaFormat* ctx, const char *name, const char **out)
2002 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2003 const char *tmp = NULL;
2004 int ret = AMediaFormat_getString(format->impl, name, &tmp);
2006 if (tmp)
2007 *out = av_strdup(tmp);
2008 return ret;
2011 static int mediaformat_ndk_getRect(FFAMediaFormat *ctx, const char *name,
2012 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom)
2014 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2015 if (!format->getRect)
2016 return AVERROR_EXTERNAL;
2017 return format->getRect(format->impl, name, left, top, right, bottom);
2020 static void mediaformat_ndk_setInt32(FFAMediaFormat* ctx, const char* name, int32_t value)
2022 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2023 AMediaFormat_setInt32(format->impl, name, value);
2026 static void mediaformat_ndk_setInt64(FFAMediaFormat* ctx, const char* name, int64_t value)
2028 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2029 AMediaFormat_setInt64(format->impl, name, value);
2032 static void mediaformat_ndk_setFloat(FFAMediaFormat* ctx, const char* name, float value)
2034 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2035 AMediaFormat_setFloat(format->impl, name, value);
2038 static void mediaformat_ndk_setString(FFAMediaFormat* ctx, const char* name, const char* value)
2040 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2041 AMediaFormat_setString(format->impl, name, value);
2044 static void mediaformat_ndk_setBuffer(FFAMediaFormat* ctx, const char* name, void* data, size_t size)
2046 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2047 AMediaFormat_setBuffer(format->impl, name, data, size);
2050 static void mediaformat_ndk_setRect(FFAMediaFormat *ctx, const char *name,
2051 int32_t left, int32_t top, int32_t right, int32_t bottom)
2053 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
2054 if (!format->setRect) {
2055 av_log(ctx, AV_LOG_WARNING, "Doesn't support setRect\n");
2056 return;
2058 format->setRect(format->impl, name, left, top, right, bottom);
2061 static char *mediacodec_ndk_getName(FFAMediaCodec *ctx)
2063 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2064 char *ret = NULL;
2065 char *name = NULL;
2067 if (!codec->getName || !codec->releaseName) {
2068 av_log(ctx, AV_LOG_DEBUG, "getName() unavailable\n");
2069 return ret;
2072 codec->getName(codec->impl, &name);
2073 if (name) {
2074 ret = av_strdup(name);
2075 codec->releaseName(codec->impl, name);
2078 return ret;
2081 static inline FFAMediaCodec *ndk_codec_create(int method, const char *arg) {
2082 FFAMediaCodecNdk *codec = av_mallocz(sizeof(*codec));
2083 const char *lib_name = "libmediandk.so";
2085 if (!codec)
2086 return NULL;
2088 codec->api = media_codec_ndk;
2089 codec->libmedia = dlopen(lib_name, RTLD_NOW);
2090 if (!codec->libmedia)
2091 goto error;
2093 #define GET_SYMBOL(sym) \
2094 codec->sym = dlsym(codec->libmedia, "AMediaCodec_" #sym); \
2095 if (!codec->sym) \
2096 av_log(codec, AV_LOG_INFO, #sym "() unavailable from %s\n", lib_name);
2098 GET_SYMBOL(getName)
2099 GET_SYMBOL(releaseName)
2101 GET_SYMBOL(setInputSurface)
2102 GET_SYMBOL(signalEndOfInputStream)
2103 GET_SYMBOL(setAsyncNotifyCallback)
2105 #undef GET_SYMBOL
2107 switch (method) {
2108 case CREATE_CODEC_BY_NAME:
2109 codec->impl = AMediaCodec_createCodecByName(arg);
2110 break;
2111 case CREATE_DECODER_BY_TYPE:
2112 codec->impl = AMediaCodec_createDecoderByType(arg);
2113 break;
2114 case CREATE_ENCODER_BY_TYPE:
2115 codec->impl = AMediaCodec_createEncoderByType(arg);
2116 break;
2117 default:
2118 av_assert0(0);
2120 if (!codec->impl)
2121 goto error;
2123 return (FFAMediaCodec *)codec;
2125 error:
2126 if (codec->libmedia)
2127 dlclose(codec->libmedia);
2128 av_freep(&codec);
2129 return NULL;
2132 #define DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(name, method) \
2133 static FFAMediaCodec *mediacodec_ndk_##name(const char *arg) \
2135 return ndk_codec_create(method, arg); \
2138 DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createCodecByName, CREATE_CODEC_BY_NAME)
2139 DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createDecoderByType, CREATE_DECODER_BY_TYPE)
2140 DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createEncoderByType, CREATE_ENCODER_BY_TYPE)
2142 static int mediacodec_ndk_delete(FFAMediaCodec* ctx)
2144 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2145 int ret = 0;
2147 if (!codec)
2148 return 0;
2150 av_assert0(codec->api.class == &amediacodec_ndk_class);
2152 if (codec->impl && (AMediaCodec_delete(codec->impl) != AMEDIA_OK))
2153 ret = AVERROR_EXTERNAL;
2154 if (codec->window)
2155 ANativeWindow_release(codec->window);
2156 if (codec->libmedia)
2157 dlclose(codec->libmedia);
2158 av_free(codec);
2160 return ret;
2163 static int mediacodec_ndk_configure(FFAMediaCodec* ctx,
2164 const FFAMediaFormat* format_ctx,
2165 FFANativeWindow* window,
2166 void *crypto,
2167 uint32_t flags)
2169 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2170 FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)format_ctx;
2171 media_status_t status;
2172 ANativeWindow *native_window = NULL;
2174 if (window) {
2175 if (window->surface) {
2176 JNIEnv *env = NULL;
2177 JNI_GET_ENV_OR_RETURN(env, ctx, -1);
2178 native_window = ANativeWindow_fromSurface(env, window->surface);
2179 // Save for release
2180 codec->window = native_window;
2181 } else if (window->native_window) {
2182 native_window = window->native_window;
2186 if (format_ctx->class != &amediaformat_ndk_class) {
2187 av_log(ctx, AV_LOG_ERROR, "invalid media format\n");
2188 return AVERROR(EINVAL);
2191 if (flags & AMEDIACODEC_CONFIGURE_FLAG_ENCODE) {
2192 if (native_window && !codec->setInputSurface) {
2193 av_log(ctx, AV_LOG_ERROR, "System doesn't support setInputSurface\n");
2194 return AVERROR_EXTERNAL;
2197 status = AMediaCodec_configure(codec->impl, format->impl, NULL, NULL, flags);
2198 if (status != AMEDIA_OK) {
2199 av_log(codec, AV_LOG_ERROR, "Encoder configure failed, %d\n", status);
2200 return AVERROR_EXTERNAL;
2203 if (!native_window)
2204 return 0;
2206 status = codec->setInputSurface(codec->impl, native_window);
2207 if (status != AMEDIA_OK) {
2208 av_log(codec, AV_LOG_ERROR, "Encoder set input surface failed, %d\n", status);
2209 return AVERROR_EXTERNAL;
2211 } else {
2212 status = AMediaCodec_configure(codec->impl, format->impl, native_window, NULL, flags);
2213 if (status != AMEDIA_OK) {
2214 av_log(codec, AV_LOG_ERROR, "Decoder configure failed, %d\n", status);
2215 return AVERROR_EXTERNAL;
2219 return 0;
2222 #define MEDIACODEC_NDK_WRAPPER(method) \
2223 static int mediacodec_ndk_ ## method(FFAMediaCodec* ctx) \
2225 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; \
2226 media_status_t status = AMediaCodec_ ## method (codec->impl); \
2228 if (status != AMEDIA_OK) { \
2229 av_log(codec, AV_LOG_ERROR, #method " failed, %d\n", status); \
2230 return AVERROR_EXTERNAL; \
2233 return 0; \
2236 MEDIACODEC_NDK_WRAPPER(start)
2237 MEDIACODEC_NDK_WRAPPER(stop)
2238 MEDIACODEC_NDK_WRAPPER(flush)
2240 static uint8_t* mediacodec_ndk_getInputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
2242 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2243 return AMediaCodec_getInputBuffer(codec->impl, idx, out_size);
2246 static uint8_t* mediacodec_ndk_getOutputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
2248 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2249 return AMediaCodec_getOutputBuffer(codec->impl, idx, out_size);
2252 static ssize_t mediacodec_ndk_dequeueInputBuffer(FFAMediaCodec* ctx, int64_t timeoutUs)
2254 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2255 return AMediaCodec_dequeueInputBuffer(codec->impl, timeoutUs);
2258 static int mediacodec_ndk_queueInputBuffer(FFAMediaCodec *ctx, size_t idx,
2259 off_t offset, size_t size,
2260 uint64_t time, uint32_t flags)
2262 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2263 return AMediaCodec_queueInputBuffer(codec->impl, idx, offset, size, time, flags);
2266 static ssize_t mediacodec_ndk_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
2268 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2269 AMediaCodecBufferInfo buf_info = {0};
2270 ssize_t ret;
2272 ret = AMediaCodec_dequeueOutputBuffer(codec->impl, &buf_info, timeoutUs);
2273 info->offset = buf_info.offset;
2274 info->size = buf_info.size;
2275 info->presentationTimeUs = buf_info.presentationTimeUs;
2276 info->flags = buf_info.flags;
2278 return ret;
2281 static FFAMediaFormat* mediacodec_ndk_getOutputFormat(FFAMediaCodec* ctx)
2283 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2284 AMediaFormat *format = AMediaCodec_getOutputFormat(codec->impl);
2286 if (!format)
2287 return NULL;
2288 return mediaformat_ndk_create(format);
2291 static int mediacodec_ndk_releaseOutputBuffer(FFAMediaCodec* ctx, size_t idx, int render)
2293 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2294 media_status_t status;
2296 status = AMediaCodec_releaseOutputBuffer(codec->impl, idx, render);
2297 if (status != AMEDIA_OK) {
2298 av_log(codec, AV_LOG_ERROR, "release output buffer failed, %d\n", status);
2299 return AVERROR_EXTERNAL;
2302 return 0;
2305 static int mediacodec_ndk_releaseOutputBufferAtTime(FFAMediaCodec *ctx, size_t idx, int64_t timestampNs)
2307 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2308 media_status_t status;
2310 status = AMediaCodec_releaseOutputBufferAtTime(codec->impl, idx, timestampNs);
2311 if (status != AMEDIA_OK) {
2312 av_log(codec, AV_LOG_ERROR, "releaseOutputBufferAtTime failed, %d\n", status);
2313 return AVERROR_EXTERNAL;
2316 return 0;
2319 static int mediacodec_ndk_infoTryAgainLater(FFAMediaCodec *ctx, ssize_t idx)
2321 return idx == AMEDIACODEC_INFO_TRY_AGAIN_LATER;
2324 static int mediacodec_ndk_infoOutputBuffersChanged(FFAMediaCodec *ctx, ssize_t idx)
2326 return idx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
2329 static int mediacodec_ndk_infoOutputFormatChanged(FFAMediaCodec *ctx, ssize_t idx)
2331 return idx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
2334 static int mediacodec_ndk_getBufferFlagCodecConfig(FFAMediaCodec *ctx)
2336 return AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
2339 static int mediacodec_ndk_getBufferFlagEndOfStream(FFAMediaCodec *ctx)
2341 return AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
2344 static int mediacodec_ndk_getBufferFlagKeyFrame(FFAMediaCodec *ctx)
2346 return 1;
2349 static int mediacodec_ndk_getConfigureFlagEncode(FFAMediaCodec *ctx)
2351 return AMEDIACODEC_CONFIGURE_FLAG_ENCODE;
2354 static int mediacodec_ndk_cleanOutputBuffers(FFAMediaCodec *ctx)
2356 return 0;
2359 static int mediacodec_ndk_signalEndOfInputStream(FFAMediaCodec *ctx)
2361 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2362 media_status_t status;
2364 if (!codec->signalEndOfInputStream) {
2365 av_log(codec, AV_LOG_ERROR, "signalEndOfInputStream unavailable\n");
2366 return AVERROR_EXTERNAL;
2369 status = codec->signalEndOfInputStream(codec->impl);
2370 if (status != AMEDIA_OK) {
2371 av_log(codec, AV_LOG_ERROR, "signalEndOfInputStream failed, %d\n", status);
2372 return AVERROR_EXTERNAL;
2374 av_log(codec, AV_LOG_DEBUG, "signalEndOfInputStream success\n");
2376 return 0;
2379 static void mediacodec_ndk_onInputAvailable(AMediaCodec *impl, void *userdata,
2380 int32_t index)
2382 FFAMediaCodecNdk *codec = userdata;
2383 codec->async_cb.onAsyncInputAvailable((FFAMediaCodec *) codec,
2384 codec->async_userdata, index);
2387 static void mediacodec_ndk_onOutputAvailable(AMediaCodec *impl,
2388 void *userdata,
2389 int32_t index,
2390 AMediaCodecBufferInfo *buffer_info)
2392 FFAMediaCodecNdk *codec = userdata;
2393 FFAMediaCodecBufferInfo info = {
2394 .offset = buffer_info->offset,
2395 .size = buffer_info->size,
2396 .presentationTimeUs = buffer_info->presentationTimeUs,
2397 .flags = buffer_info->flags,
2400 codec->async_cb.onAsyncOutputAvailable(&codec->api, codec->async_userdata,
2401 index, &info);
2404 static void mediacodec_ndk_onFormatChanged(AMediaCodec *impl, void *userdata,
2405 AMediaFormat *format)
2407 FFAMediaCodecNdk *codec = userdata;
2408 FFAMediaFormat *media_format = mediaformat_ndk_create(format);
2409 if (!media_format)
2410 return;
2412 codec->async_cb.onAsyncFormatChanged(&codec->api, codec->async_userdata,
2413 media_format);
2414 ff_AMediaFormat_delete(media_format);
2417 static void mediacodec_ndk_onError(AMediaCodec *impl, void *userdata,
2418 media_status_t status,
2419 int32_t actionCode,
2420 const char *detail)
2422 FFAMediaCodecNdk *codec = userdata;
2423 int error = media_status_to_error(status);
2425 codec->async_cb.onAsyncError(&codec->api, codec->async_userdata, error,
2426 detail);
2429 static int mediacodec_ndk_setAsyncNotifyCallback(FFAMediaCodec *ctx,
2430 const FFAMediaCodecOnAsyncNotifyCallback *callback,
2431 void *userdata)
2433 FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
2434 struct AMediaCodecOnAsyncNotifyCallback cb = {
2435 .onAsyncInputAvailable = mediacodec_ndk_onInputAvailable,
2436 .onAsyncOutputAvailable = mediacodec_ndk_onOutputAvailable,
2437 .onAsyncFormatChanged = mediacodec_ndk_onFormatChanged,
2438 .onAsyncError = mediacodec_ndk_onError,
2440 media_status_t status;
2442 if (!codec->setAsyncNotifyCallback) {
2443 av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback unavailable\n");
2444 return AVERROR(ENOSYS);
2447 if (!callback ||
2448 !callback->onAsyncInputAvailable ||
2449 !callback->onAsyncOutputAvailable ||
2450 !callback->onAsyncFormatChanged ||
2451 !callback->onAsyncError)
2452 return AVERROR(EINVAL);
2454 codec->async_cb = *callback;
2455 codec->async_userdata = userdata;
2457 status = codec->setAsyncNotifyCallback(codec->impl, cb, codec);
2458 if (status != AMEDIA_OK) {
2459 av_log(codec, AV_LOG_ERROR, "setAsyncNotifyCallback failed, %d\n",
2460 status);
2461 return AVERROR_EXTERNAL;
2464 return 0;
2467 static const FFAMediaFormat media_format_ndk = {
2468 .class = &amediaformat_ndk_class,
2470 .create = mediaformat_ndk_new,
2471 .delete = mediaformat_ndk_delete,
2473 .toString = mediaformat_ndk_toString,
2475 .getInt32 = mediaformat_ndk_getInt32,
2476 .getInt64 = mediaformat_ndk_getInt64,
2477 .getFloat = mediaformat_ndk_getFloat,
2478 .getBuffer = mediaformat_ndk_getBuffer,
2479 .getString = mediaformat_ndk_getString,
2480 .getRect = mediaformat_ndk_getRect,
2482 .setInt32 = mediaformat_ndk_setInt32,
2483 .setInt64 = mediaformat_ndk_setInt64,
2484 .setFloat = mediaformat_ndk_setFloat,
2485 .setString = mediaformat_ndk_setString,
2486 .setBuffer = mediaformat_ndk_setBuffer,
2487 .setRect = mediaformat_ndk_setRect,
2490 static const FFAMediaCodec media_codec_ndk = {
2491 .class = &amediacodec_ndk_class,
2493 .getName = mediacodec_ndk_getName,
2495 .createCodecByName = mediacodec_ndk_createCodecByName,
2496 .createDecoderByType = mediacodec_ndk_createDecoderByType,
2497 .createEncoderByType = mediacodec_ndk_createEncoderByType,
2498 .delete = mediacodec_ndk_delete,
2500 .configure = mediacodec_ndk_configure,
2501 .start = mediacodec_ndk_start,
2502 .stop = mediacodec_ndk_stop,
2503 .flush = mediacodec_ndk_flush,
2505 .getInputBuffer = mediacodec_ndk_getInputBuffer,
2506 .getOutputBuffer = mediacodec_ndk_getOutputBuffer,
2508 .dequeueInputBuffer = mediacodec_ndk_dequeueInputBuffer,
2509 .queueInputBuffer = mediacodec_ndk_queueInputBuffer,
2511 .dequeueOutputBuffer = mediacodec_ndk_dequeueOutputBuffer,
2512 .getOutputFormat = mediacodec_ndk_getOutputFormat,
2514 .releaseOutputBuffer = mediacodec_ndk_releaseOutputBuffer,
2515 .releaseOutputBufferAtTime = mediacodec_ndk_releaseOutputBufferAtTime,
2517 .infoTryAgainLater = mediacodec_ndk_infoTryAgainLater,
2518 .infoOutputBuffersChanged = mediacodec_ndk_infoOutputBuffersChanged,
2519 .infoOutputFormatChanged = mediacodec_ndk_infoOutputFormatChanged,
2521 .getBufferFlagCodecConfig = mediacodec_ndk_getBufferFlagCodecConfig,
2522 .getBufferFlagEndOfStream = mediacodec_ndk_getBufferFlagEndOfStream,
2523 .getBufferFlagKeyFrame = mediacodec_ndk_getBufferFlagKeyFrame,
2525 .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode,
2526 .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers,
2527 .signalEndOfInputStream = mediacodec_ndk_signalEndOfInputStream,
2528 .setAsyncNotifyCallback = mediacodec_ndk_setAsyncNotifyCallback,
2531 FFAMediaFormat *ff_AMediaFormat_new(int ndk)
2533 if (ndk)
2534 return media_format_ndk.create();
2535 return media_format_jni.create();
2538 FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name, int ndk)
2540 if (ndk)
2541 return media_codec_ndk.createCodecByName(name);
2542 return media_codec_jni.createCodecByName(name);
2545 FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type, int ndk)
2547 if (ndk)
2548 return media_codec_ndk.createDecoderByType(mime_type);
2549 return media_codec_jni.createDecoderByType(mime_type);
2552 FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type, int ndk)
2554 if (ndk)
2555 return media_codec_ndk.createEncoderByType(mime_type);
2556 return media_codec_jni.createEncoderByType(mime_type);
2559 int ff_Build_SDK_INT(AVCodecContext *avctx)
2561 int ret = -1;
2563 #if __ANDROID_API__ >= 24
2564 // android_get_device_api_level() is a static inline before API level 29.
2565 // dlsym() might doesn't work.
2567 // We can implement android_get_device_api_level() by
2568 // __system_property_get(), but __system_property_get() has created a lot of
2569 // troubles and is deprecated. So avoid using __system_property_get() for
2570 // now.
2572 // Hopy we can remove the conditional compilation finally by bumping the
2573 // required API level.
2575 ret = android_get_device_api_level();
2576 #else
2577 JNIEnv *env = NULL;
2578 jclass versionClass;
2579 jfieldID sdkIntFieldID;
2580 JNI_GET_ENV_OR_RETURN(env, avctx, -1);
2582 versionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
2583 sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I");
2584 ret = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
2585 (*env)->DeleteLocalRef(env, versionClass);
2586 #endif
2587 av_log(avctx, AV_LOG_DEBUG, "device api level %d\n", ret);
2589 return ret;
2592 static struct {
2593 enum FFAMediaFormatColorRange mf_range;
2594 enum AVColorRange range;
2595 } color_range_map[] = {
2596 { COLOR_RANGE_FULL, AVCOL_RANGE_JPEG },
2597 { COLOR_RANGE_LIMITED, AVCOL_RANGE_MPEG },
2600 static struct {
2601 enum FFAMediaFormatColorStandard mf_standard;
2602 enum AVColorSpace space;
2603 } color_space_map[] = {
2604 { COLOR_STANDARD_BT709, AVCOL_SPC_BT709 },
2605 { COLOR_STANDARD_BT601_PAL, AVCOL_SPC_BT470BG },
2606 { COLOR_STANDARD_BT601_NTSC, AVCOL_SPC_SMPTE170M },
2607 { COLOR_STANDARD_BT2020, AVCOL_SPC_BT2020_NCL },
2610 static struct {
2611 enum FFAMediaFormatColorStandard mf_standard;
2612 enum AVColorPrimaries primaries;
2613 } color_primaries_map[] = {
2614 { COLOR_STANDARD_BT709, AVCOL_PRI_BT709 },
2615 { COLOR_STANDARD_BT601_PAL, AVCOL_PRI_BT470BG },
2616 { COLOR_STANDARD_BT601_NTSC, AVCOL_PRI_SMPTE170M },
2617 { COLOR_STANDARD_BT2020, AVCOL_PRI_BT2020 },
2620 static struct {
2621 enum FFAMediaFormatColorTransfer mf_transfer;
2622 enum AVColorTransferCharacteristic transfer;
2623 } color_transfer_map[] = {
2624 { COLOR_TRANSFER_LINEAR, AVCOL_TRC_LINEAR },
2625 { COLOR_TRANSFER_SDR_VIDEO, AVCOL_TRC_SMPTE170M },
2626 { COLOR_TRANSFER_ST2084, AVCOL_TRC_SMPTEST2084 },
2627 { COLOR_TRANSFER_HLG, AVCOL_TRC_ARIB_STD_B67 },
2630 enum AVColorRange ff_AMediaFormatColorRange_to_AVColorRange(int color_range)
2632 for (int i = 0; i < FF_ARRAY_ELEMS(color_range_map); i++)
2633 if (color_range_map[i].mf_range == color_range)
2634 return color_range_map[i].range;
2636 return AVCOL_RANGE_UNSPECIFIED;
2639 int ff_AMediaFormatColorRange_from_AVColorRange(enum AVColorRange color_range)
2641 for (int i = 0; i < FF_ARRAY_ELEMS(color_range_map); i++)
2642 if (color_range_map[i].range == color_range)
2643 return color_range_map[i].mf_range;
2644 return COLOR_RANGE_UNSPECIFIED;
2647 enum AVColorSpace ff_AMediaFormatColorStandard_to_AVColorSpace(int color_standard)
2649 for (int i = 0; i < FF_ARRAY_ELEMS(color_space_map); i++)
2650 if (color_space_map[i].mf_standard == color_standard)
2651 return color_space_map[i].space;
2653 return AVCOL_SPC_UNSPECIFIED;
2656 int ff_AMediaFormatColorStandard_from_AVColorSpace(enum AVColorSpace color_space)
2658 for (int i = 0; i < FF_ARRAY_ELEMS(color_space_map); i++)
2659 if (color_space_map[i].space == color_space)
2660 return color_space_map[i].mf_standard;
2662 return COLOR_STANDARD_UNSPECIFIED;
2665 enum AVColorPrimaries ff_AMediaFormatColorStandard_to_AVColorPrimaries(int color_standard)
2667 for (int i = 0; i < FF_ARRAY_ELEMS(color_primaries_map); i++)
2668 if (color_primaries_map[i].mf_standard == color_standard)
2669 return color_primaries_map[i].primaries;
2671 return AVCOL_PRI_UNSPECIFIED;
2674 enum AVColorTransferCharacteristic
2675 ff_AMediaFormatColorTransfer_to_AVColorTransfer(int color_transfer)
2677 for (int i = 0; i < FF_ARRAY_ELEMS(color_transfer_map); i++)
2678 if (color_transfer_map[i].mf_transfer == color_transfer)
2679 return color_transfer_map[i].transfer;
2681 return AVCOL_TRC_UNSPECIFIED;
2684 int ff_AMediaFormatColorTransfer_from_AVColorTransfer(
2685 enum AVColorTransferCharacteristic color_transfer)
2687 for (int i = 0; i < FF_ARRAY_ELEMS(color_transfer_map); i++)
2688 if (color_transfer_map[i].transfer == color_transfer)
2689 return color_transfer_map[i].mf_transfer;
2691 return COLOR_TRANSFER_UNSPECIFIED;