jmethodID get_codec_capabilities_id;
jmethodID get_supported_types_id;
jmethodID is_encoder_id;
+ jmethodID is_software_only_id;
jclass codec_capabilities_class;
jfieldID color_formats_id;
{ "android/media/MediaCodecInfo", "getCapabilitiesForType", "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_codec_capabilities_id), 1 },
{ "android/media/MediaCodecInfo", "getSupportedTypes", "()[Ljava/lang/String;", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, get_supported_types_id), 1 },
{ "android/media/MediaCodecInfo", "isEncoder", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_encoder_id), 1 },
+ { "android/media/MediaCodecInfo", "isSoftwareOnly", "()Z", FF_JNI_METHOD, offsetof(struct JNIAMediaCodecListFields, is_software_only_id), 0 },
{ "android/media/MediaCodecInfo$CodecCapabilities", NULL, NULL, FF_JNI_CLASS, offsetof(struct JNIAMediaCodecListFields, codec_capabilities_class), 1 },
{ "android/media/MediaCodecInfo$CodecCapabilities", "colorFormats", "[I", FF_JNI_FIELD, offsetof(struct JNIAMediaCodecListFields, color_formats_id), 1 },
jmethodID init_id;
+ jmethodID contains_key_id;
+
jmethodID get_integer_id;
jmethodID get_long_id;
jmethodID get_float_id;
{ "android/media/MediaFormat", "<init>", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, init_id), 1 },
+ { "android/media/MediaFormat", "containsKey", "(Ljava/lang/String;)Z", FF_JNI_METHOD,offsetof(struct JNIAMediaFormatFields, contains_key_id), 1 },
+
{ "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_integer_id), 1 },
{ "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_long_id), 1 },
{ "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_float_id), 1 },
static const AVClass amediaformat_class = {
.class_name = "amediaformat",
.item_name = av_default_item_name,
- .version = LIBAVCODEC_VERSION_INT,
+ .version = LIBAVUTIL_VERSION_INT,
};
struct FFAMediaFormat {
static const AVClass amediacodec_class = {
.class_name = "amediacodec",
.item_name = av_default_item_name,
- .version = LIBAVCODEC_VERSION_INT,
+ .version = LIBAVUTIL_VERSION_INT,
};
struct FFAMediaCodec {
struct JNIAMediaCodecFields jfields;
jobject object;
+ jobject buffer_info;
jobject input_buffers;
jobject output_buffers;
struct JNIAMediaCodecListFields jfields = { 0 };
struct JNIAMediaFormatFields mediaformat_jfields = { 0 };
- jobject format = NULL;
- jobject codec = NULL;
jobject codec_name = NULL;
jobject info = NULL;
goto done_with_info;
}
+ if (jfields.is_software_only_id) {
+ int is_software_only = (*env)->CallBooleanMethod(env, info, jfields.is_software_only_id);
+ if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+ goto done;
+ }
+
+ if (is_software_only) {
+ goto done_with_info;
+ }
+ }
+
+ codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
+ if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+ goto done;
+ }
+
+ name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
+ if (!name) {
+ goto done;
+ }
+
+ if (codec_name) {
+ (*env)->DeleteLocalRef(env, codec_name);
+ codec_name = NULL;
+ }
+
+ /* Skip software decoders */
+ if (
+ strstr(name, "OMX.google") ||
+ strstr(name, "OMX.ffmpeg") ||
+ (strstr(name, "OMX.SEC") && strstr(name, ".sw.")) ||
+ !strcmp(name, "OMX.qcom.video.decoder.hevcswvdec")) {
+ goto done_with_info;
+ }
+
type_count = (*env)->GetArrayLength(env, types);
for (j = 0; j < type_count; j++) {
int k;
goto done;
}
- if (!av_strcasecmp(supported_type, mime)) {
- codec_name = (*env)->CallObjectMethod(env, info, jfields.get_name_id);
- if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
- goto done;
- }
+ if (av_strcasecmp(supported_type, mime)) {
+ goto done_with_type;
+ }
- name = ff_jni_jstring_to_utf_chars(env, codec_name, log_ctx);
- if (!name) {
- goto done;
- }
+ capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
+ if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+ goto done;
+ }
+
+ profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
+ if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
+ goto done;
+ }
+
+ profile_count = (*env)->GetArrayLength(env, profile_levels);
+ if (!profile_count) {
+ found_codec = 1;
+ }
+ for (k = 0; k < profile_count; k++) {
+ int supported_profile = 0;
- if (strstr(name, "OMX.google")) {
- av_freep(&name);
- goto done_with_type;
+ if (profile < 0) {
+ found_codec = 1;
+ break;
}
- capabilities = (*env)->CallObjectMethod(env, info, jfields.get_codec_capabilities_id, type);
+ profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
goto done;
}
- profile_levels = (*env)->GetObjectField(env, capabilities, jfields.profile_levels_id);
+ supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
goto done;
}
- profile_count = (*env)->GetArrayLength(env, profile_levels);
- if (!profile_count) {
- found_codec = 1;
+ found_codec = profile == supported_profile;
+
+ if (profile_level) {
+ (*env)->DeleteLocalRef(env, profile_level);
+ profile_level = NULL;
}
- for (k = 0; k < profile_count; k++) {
- int supported_profile = 0;
-
- if (profile < 0) {
- found_codec = 1;
- break;
- }
-
- profile_level = (*env)->GetObjectArrayElement(env, profile_levels, k);
- if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
- goto done;
- }
-
- supported_profile = (*env)->GetIntField(env, profile_level, jfields.profile_id);
- if (ff_jni_exception_check(env, 1, log_ctx) < 0) {
- goto done;
- }
-
- found_codec = profile == supported_profile;
-
- if (profile_level) {
- (*env)->DeleteLocalRef(env, profile_level);
- profile_level = NULL;
- }
-
- if (found_codec) {
- break;
- }
+
+ if (found_codec) {
+ break;
}
}
if (found_codec) {
break;
}
-
- av_freep(&name);
}
done_with_info:
if (found_codec) {
break;
}
- }
-done:
- if (format) {
- (*env)->DeleteLocalRef(env, format);
- }
-
- if (codec) {
- (*env)->DeleteLocalRef(env, codec);
+ av_freep(&name);
}
+done:
if (codec_name) {
(*env)->DeleteLocalRef(env, codec_name);
}
JNIEnv *env = NULL;
jstring key = NULL;
+ jboolean contains_key;
av_assert0(format != NULL);
goto fail;
}
+ contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+ if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+ ret = 0;
+ goto fail;
+ }
+
*out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key);
if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
ret = 0;
JNIEnv *env = NULL;
jstring key = NULL;
+ jboolean contains_key;
av_assert0(format != NULL);
goto fail;
}
+ contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+ if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+ ret = 0;
+ goto fail;
+ }
+
*out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key);
if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
ret = 0;
JNIEnv *env = NULL;
jstring key = NULL;
+ jboolean contains_key;
av_assert0(format != NULL);
goto fail;
}
+ contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+ if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+ ret = 0;
+ goto fail;
+ }
+
*out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key);
if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
ret = 0;
JNIEnv *env = NULL;
jstring key = NULL;
+ jboolean contains_key;
jobject result = NULL;
av_assert0(format != NULL);
goto fail;
}
+ contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+ if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+ ret = 0;
+ goto fail;
+ }
+
result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key);
if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
ret = 0;
JNIEnv *env = NULL;
jstring key = NULL;
+ jboolean contains_key;
jstring result = NULL;
av_assert0(format != NULL);
goto fail;
}
+ contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key);
+ if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) {
+ ret = 0;
+ goto fail;
+ }
+
result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key);
if ((ret = ff_jni_exception_check(env, 1, format)) < 0) {
ret = 0;
FFAMediaCodec *codec = NULL;
jstring jarg = NULL;
jobject object = NULL;
+ jobject buffer_info = NULL;
jmethodID create_id = NULL;
codec = av_mallocz(sizeof(FFAMediaCodec));
codec->has_get_i_o_buffer = 1;
}
+ buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
+ if (ff_jni_exception_check(env, 1, codec) < 0) {
+ goto fail;
+ }
+
+ codec->buffer_info = (*env)->NewGlobalRef(env, buffer_info);
+ if (!codec->buffer_info) {
+ goto fail;
+ }
+
ret = 0;
fail:
if (jarg) {
(*env)->DeleteLocalRef(env, object);
}
+ if (buffer_info) {
+ (*env)->DeleteLocalRef(env, buffer_info);
+ }
+
if (ret < 0) {
if (codec->object) {
(*env)->DeleteGlobalRef(env, codec->object);
}
+
+ if (codec->buffer_info) {
+ (*env)->DeleteGlobalRef(env, codec->buffer_info);
+ }
+
ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
av_freep(&codec);
}
ret = AVERROR_EXTERNAL;
}
+ (*env)->DeleteGlobalRef(env, codec->input_buffers);
+ codec->input_buffers = NULL;
+
+ (*env)->DeleteGlobalRef(env, codec->output_buffers);
+ codec->output_buffers = NULL;
+
(*env)->DeleteGlobalRef(env, codec->object);
codec->object = NULL;
+ (*env)->DeleteGlobalRef(env, codec->buffer_info);
+ codec->buffer_info = NULL;
+
ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec);
av_freep(&codec);
ret = ff_jni_jstring_to_utf_chars(env, name, codec);
fail:
+ if (name) {
+ (*env)->DeleteLocalRef(env, name);
+ }
+
return ret;
}
JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
- (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, timestampNs);
+ (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, (jlong)timestampNs);
if (ff_jni_exception_check(env, 1, codec) < 0) {
ret = AVERROR_EXTERNAL;
goto fail;
int ret = 0;
JNIEnv *env = NULL;
- jobject mediainfo = NULL;
-
JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);
- mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id);
+ ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs);
if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
}
- ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs);
+ info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id);
if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
}
- info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id);
+ info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id);
if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
}
- info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id);
+ info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id);
if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
+ return AVERROR_EXTERNAL;
}
- info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id);
+ info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id);
if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
- }
-
- info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id);
- if (ff_jni_exception_check(env, 1, codec) < 0) {
- ret = AVERROR_EXTERNAL;
- goto fail;
- }
-fail:
- if (mediainfo) {
- (*env)->DeleteLocalRef(env, mediainfo);
+ return AVERROR_EXTERNAL;
}
return ret;
fail:
return ret;
}
+
+int ff_Build_SDK_INT(AVCodecContext *avctx)
+{
+ int ret = -1;
+ JNIEnv *env = NULL;
+ jclass versionClass;
+ jfieldID sdkIntFieldID;
+ JNI_GET_ENV_OR_RETURN(env, avctx, -1);
+
+ versionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
+ sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I");
+ ret = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
+ (*env)->DeleteLocalRef(env, versionClass);
+ return ret;
+}