diff --git a/sys/androidmedia/gstamc-codeclist.h b/sys/androidmedia/gstamc-codeclist.h new file mode 100644 index 0000000000..f7ebb01c13 --- /dev/null +++ b/sys/androidmedia/gstamc-codeclist.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GST_AMC_CODECLIST_H__ +#define __GST_AMC_CODECLIST_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GstAmcCodecInfoHandle GstAmcCodecInfoHandle; +typedef struct _GstAmcCodecCapabilitiesHandle GstAmcCodecCapabilitiesHandle; +typedef struct _GstAmcCodecProfileLevel GstAmcCodecProfileLevel; + +struct _GstAmcCodecProfileLevel +{ + gint profile; + gint level; +}; + +gboolean gst_amc_codeclist_static_init (void); + +gboolean gst_amc_codeclist_get_count (gint * count, GError **err); +GstAmcCodecInfoHandle * gst_amc_codeclist_get_codec_info_at (gint index, + GError **err); + +void gst_amc_codec_info_handle_free (GstAmcCodecInfoHandle * handle); +gchar * gst_amc_codec_info_handle_get_name (GstAmcCodecInfoHandle * handle, + GError ** err); +gboolean gst_amc_codec_info_handle_is_encoder (GstAmcCodecInfoHandle * handle, + gboolean * is_encoder, GError ** err); +gchar ** gst_amc_codec_info_handle_get_supported_types ( + GstAmcCodecInfoHandle * handle, gsize * length, GError ** err); +GstAmcCodecCapabilitiesHandle * gst_amc_codec_info_handle_get_capabilities_for_type ( + GstAmcCodecInfoHandle * handle, const gchar * type, GError ** err); + +void gst_amc_codec_capabilities_handle_free ( + GstAmcCodecCapabilitiesHandle * handle); +gint * gst_amc_codec_capabilities_handle_get_color_formats ( + GstAmcCodecCapabilitiesHandle * handle, gsize * length, GError ** err); +GstAmcCodecProfileLevel * gst_amc_codec_capabilities_handle_get_profile_levels ( + GstAmcCodecCapabilitiesHandle * handle, gsize * length, GError ** err); + +G_END_DECLS + +#endif /* __GST_AMC_CODECLIST_H__ */ diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c index fbf50d614a..1ea4a82072 100644 --- a/sys/androidmedia/gstamc.c +++ b/sys/androidmedia/gstamc.c @@ -64,11 +64,9 @@ static gboolean scan_codecs (GstPlugin * plugin) { gboolean ret = TRUE; - JNIEnv *env; - jclass codec_list_class = NULL; - jmethodID get_codec_count_id, get_codec_info_at_id; - jint codec_count, i; + gint codec_count, i; const GstStructure *cache_data; + GError *error = NULL; GST_DEBUG ("Scanning codecs"); @@ -149,41 +147,9 @@ scan_codecs (GstPlugin * plugin) return TRUE; } - env = gst_amc_jni_get_env (); - - codec_list_class = (*env)->FindClass (env, "android/media/MediaCodecList"); - if (!codec_list_class) { - ret = FALSE; - GST_ERROR ("Failed to get codec list class"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - - get_codec_count_id = - (*env)->GetStaticMethodID (env, codec_list_class, "getCodecCount", "()I"); - get_codec_info_at_id = - (*env)->GetStaticMethodID (env, codec_list_class, "getCodecInfoAt", - "(I)Landroid/media/MediaCodecInfo;"); - if (!get_codec_count_id || !get_codec_info_at_id) { - ret = FALSE; - GST_ERROR ("Failed to get codec list method IDs"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - - codec_count = - (*env)->CallStaticIntMethod (env, codec_list_class, get_codec_count_id); - if ((*env)->ExceptionCheck (env)) { - ret = FALSE; + if (!gst_amc_codeclist_get_count (&codec_count, &error)) { GST_ERROR ("Failed to get number of available codecs"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); + ret = FALSE; goto done; } @@ -191,79 +157,26 @@ scan_codecs (GstPlugin * plugin) for (i = 0; i < codec_count; i++) { GstAmcCodecInfo *gst_codec_info; - jobject codec_info = NULL; - jclass codec_info_class = NULL; - jmethodID get_capabilities_for_type_id, get_name_id; - jmethodID get_supported_types_id, is_encoder_id; - jobject name = NULL; - const gchar *name_str = NULL; - jboolean is_encoder; - jarray supported_types = NULL; - jsize n_supported_types; - jsize j; + GstAmcCodecInfoHandle *codec_info = NULL; + gchar *name_str = NULL; + gboolean is_encoder; + gchar **supported_types = NULL; + gsize n_supported_types; + gsize j; gboolean valid_codec = TRUE; gst_codec_info = g_new0 (GstAmcCodecInfo, 1); - codec_info = - (*env)->CallStaticObjectMethod (env, codec_list_class, - get_codec_info_at_id, i); - if ((*env)->ExceptionCheck (env) || !codec_info) { + codec_info = gst_amc_codeclist_get_codec_info_at (i, &error); + if (!codec_info) { GST_ERROR ("Failed to get codec info %d", i); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } valid_codec = FALSE; goto next_codec; } - codec_info_class = (*env)->GetObjectClass (env, codec_info); - if (!codec_list_class) { - GST_ERROR ("Failed to get codec info class"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - valid_codec = FALSE; - goto next_codec; - } - - get_capabilities_for_type_id = - (*env)->GetMethodID (env, codec_info_class, "getCapabilitiesForType", - "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;"); - get_name_id = - (*env)->GetMethodID (env, codec_info_class, "getName", - "()Ljava/lang/String;"); - get_supported_types_id = - (*env)->GetMethodID (env, codec_info_class, "getSupportedTypes", - "()[Ljava/lang/String;"); - is_encoder_id = - (*env)->GetMethodID (env, codec_info_class, "isEncoder", "()Z"); - if (!get_capabilities_for_type_id || !get_name_id - || !get_supported_types_id || !is_encoder_id) { - GST_ERROR ("Failed to get codec info method IDs"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - valid_codec = FALSE; - goto next_codec; - } - - name = (*env)->CallObjectMethod (env, codec_info, get_name_id); - if ((*env)->ExceptionCheck (env)) { + name_str = gst_amc_codec_info_handle_get_name (codec_info, &error); + if (!name_str) { GST_ERROR ("Failed to get codec name"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_codec; - } - name_str = (*env)->GetStringUTFChars (env, name, NULL); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to convert codec name to UTF8"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); valid_codec = FALSE; goto next_codec; } @@ -315,11 +228,8 @@ scan_codecs (GstPlugin * plugin) } gst_codec_info->name = g_strdup (name_str); - is_encoder = (*env)->CallBooleanMethod (env, codec_info, is_encoder_id); - if ((*env)->ExceptionCheck (env)) { + if (!gst_amc_codec_info_handle_is_encoder (codec_info, &is_encoder, &error)) { GST_ERROR ("Failed to detect if codec is an encoder"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); valid_codec = FALSE; goto next_codec; } @@ -327,25 +237,16 @@ scan_codecs (GstPlugin * plugin) gst_codec_info->gl_output_only = FALSE; supported_types = - (*env)->CallObjectMethod (env, codec_info, get_supported_types_id); - if ((*env)->ExceptionCheck (env)) { + gst_amc_codec_info_handle_get_supported_types (codec_info, + &n_supported_types, &error); + if (!supported_types) { GST_ERROR ("Failed to get supported types"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); valid_codec = FALSE; goto next_codec; } - n_supported_types = (*env)->GetArrayLength (env, supported_types); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get supported types array length"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_codec; - } - - GST_INFO ("Codec '%s' has %d supported types", name_str, n_supported_types); + GST_INFO ("Codec '%s' has %" G_GSIZE_FORMAT " supported types", name_str, + n_supported_types); gst_codec_info->supported_types = g_new0 (GstAmcCodecType, n_supported_types); @@ -359,110 +260,41 @@ scan_codecs (GstPlugin * plugin) for (j = 0; j < n_supported_types; j++) { GstAmcCodecType *gst_codec_type; - jobject supported_type = NULL; - const gchar *supported_type_str = NULL; - jobject capabilities = NULL; - jclass capabilities_class = NULL; - jfieldID profile_levels_id, color_formats_id; - jobject profile_levels = NULL; - jobject color_formats = NULL; - jint *color_formats_elems = NULL; - jsize n_elems, k; + const gchar *supported_type_str; + GstAmcCodecCapabilitiesHandle *capabilities = NULL; + gint k; gst_codec_type = &gst_codec_info->supported_types[j]; - - supported_type = (*env)->GetObjectArrayElement (env, supported_types, j); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get %d-th supported type", j); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - - supported_type_str = - (*env)->GetStringUTFChars (env, supported_type, NULL); - if ((*env)->ExceptionCheck (env) || !supported_type_str) { - GST_ERROR ("Failed to convert supported type to UTF8"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } + supported_type_str = supported_types[j]; GST_INFO ("Supported type '%s'", supported_type_str); gst_codec_type->mime = g_strdup (supported_type_str); capabilities = - (*env)->CallObjectMethod (env, codec_info, - get_capabilities_for_type_id, supported_type); - if ((*env)->ExceptionCheck (env)) { + gst_amc_codec_info_handle_get_capabilities_for_type (codec_info, + supported_type_str, &error); + if (!capabilities) { GST_ERROR ("Failed to get capabilities for supported type"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - - capabilities_class = (*env)->GetObjectClass (env, capabilities); - if (!capabilities_class) { - GST_ERROR ("Failed to get capabilities class"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - - color_formats_id = - (*env)->GetFieldID (env, capabilities_class, "colorFormats", "[I"); - profile_levels_id = - (*env)->GetFieldID (env, capabilities_class, "profileLevels", - "[Landroid/media/MediaCodecInfo$CodecProfileLevel;"); - if (!color_formats_id || !profile_levels_id) { - GST_ERROR ("Failed to get capabilities field IDs"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); valid_codec = FALSE; goto next_supported_type; } if (g_str_has_prefix (gst_codec_type->mime, "video/")) { - color_formats = - (*env)->GetObjectField (env, capabilities, color_formats_id); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get color formats"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - - n_elems = (*env)->GetArrayLength (env, color_formats); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get color formats array length"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - gst_codec_type->n_color_formats = n_elems; - gst_codec_type->color_formats = g_new0 (gint, n_elems); - color_formats_elems = - (*env)->GetIntArrayElements (env, color_formats, NULL); - if ((*env)->ExceptionCheck (env)) { + gst_codec_type->color_formats = + gst_amc_codec_capabilities_handle_get_color_formats (capabilities, + &gst_codec_type->n_color_formats, &error); + if (!gst_codec_type->color_formats) { GST_ERROR ("Failed to get color format elements"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); valid_codec = FALSE; goto next_supported_type; } - for (k = 0; k < n_elems; k++) { - GST_INFO ("Color format %d: 0x%x", k, color_formats_elems[k]); - gst_codec_type->color_formats[k] = color_formats_elems[k]; + for (k = 0; k < gst_codec_type->n_color_formats; k++) { + GST_INFO ("Color format %d: 0x%x", k, + gst_codec_type->color_formats[k]); } - if (!n_elems) { + if (!gst_codec_type->n_color_formats) { GST_ERROR ("No supported color formats for video codec"); valid_codec = FALSE; goto next_supported_type; @@ -478,118 +310,27 @@ scan_codecs (GstPlugin * plugin) } } - profile_levels = - (*env)->GetObjectField (env, capabilities, profile_levels_id); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get profile/levels"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - - n_elems = (*env)->GetArrayLength (env, profile_levels); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get profile/levels array length"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_supported_type; - } - gst_codec_type->n_profile_levels = n_elems; gst_codec_type->profile_levels = - g_malloc0 (sizeof (gst_codec_type->profile_levels[0]) * n_elems); - for (k = 0; k < n_elems; k++) { - jobject profile_level = NULL; - jclass profile_level_class = NULL; - jfieldID level_id, profile_id; - jint level, profile; + gst_amc_codec_capabilities_handle_get_profile_levels (capabilities, + &gst_codec_type->n_profile_levels, &error); + if (!gst_codec_type->profile_levels) { + GST_ERROR ("Failed to get profile/levels"); + valid_codec = FALSE; + goto next_supported_type; + } - profile_level = (*env)->GetObjectArrayElement (env, profile_levels, k); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get %d-th profile/level", k); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_profile_level; - } - - profile_level_class = (*env)->GetObjectClass (env, profile_level); - if (!profile_level_class) { - GST_ERROR ("Failed to get profile/level class"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_profile_level; - } - - level_id = (*env)->GetFieldID (env, profile_level_class, "level", "I"); - profile_id = - (*env)->GetFieldID (env, profile_level_class, "profile", "I"); - if (!level_id || !profile_id) { - GST_ERROR ("Failed to get profile/level field IDs"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_profile_level; - } - - level = (*env)->GetIntField (env, profile_level, level_id); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get level"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_profile_level; - } - GST_INFO ("Level %d: 0x%08x", k, level); - gst_codec_type->profile_levels[k].level = level; - - profile = (*env)->GetIntField (env, profile_level, profile_id); - if ((*env)->ExceptionCheck (env)) { - GST_ERROR ("Failed to get profile"); - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - valid_codec = FALSE; - goto next_profile_level; - } - GST_INFO ("Profile %d: 0x%08x", k, profile); - gst_codec_type->profile_levels[k].profile = profile; - - next_profile_level: - if (profile_level) - (*env)->DeleteLocalRef (env, profile_level); - profile_level = NULL; - if (profile_level_class) - (*env)->DeleteLocalRef (env, profile_level_class); - profile_level_class = NULL; - if (!valid_codec) - break; + for (k = 0; k < gst_codec_type->n_profile_levels; k++) { + GST_INFO ("Level %d: 0x%08x", k, + gst_codec_type->profile_levels[k].level); + GST_INFO ("Profile %d: 0x%08x", k, + gst_codec_type->profile_levels[k].profile); } next_supported_type: - if (color_formats_elems) - (*env)->ReleaseIntArrayElements (env, color_formats, - color_formats_elems, JNI_ABORT); - color_formats_elems = NULL; - if (color_formats) - (*env)->DeleteLocalRef (env, color_formats); - color_formats = NULL; - if (profile_levels) - (*env)->DeleteLocalRef (env, profile_levels); - color_formats = NULL; if (capabilities) - (*env)->DeleteLocalRef (env, capabilities); + gst_amc_codec_capabilities_handle_free (capabilities); capabilities = NULL; - if (capabilities_class) - (*env)->DeleteLocalRef (env, capabilities_class); - capabilities_class = NULL; - if (supported_type_str) - (*env)->ReleaseStringUTFChars (env, supported_type, supported_type_str); - supported_type_str = NULL; - if (supported_type) - (*env)->DeleteLocalRef (env, supported_type); - supported_type = NULL; + g_clear_error (&error); if (!valid_codec) break; } @@ -637,20 +378,14 @@ scan_codecs (GstPlugin * plugin) /* Clean up of all local references we got */ next_codec: if (name_str) - (*env)->ReleaseStringUTFChars (env, name, name_str); + g_free (name_str); name_str = NULL; - if (name) - (*env)->DeleteLocalRef (env, name); - name = NULL; if (supported_types) - (*env)->DeleteLocalRef (env, supported_types); + g_strfreev (supported_types); supported_types = NULL; if (codec_info) - (*env)->DeleteLocalRef (env, codec_info); + gst_amc_codec_info_handle_free (codec_info); codec_info = NULL; - if (codec_info_class) - (*env)->DeleteLocalRef (env, codec_info_class); - codec_info_class = NULL; if (gst_codec_info) { gint j; @@ -667,6 +402,7 @@ scan_codecs (GstPlugin * plugin) } gst_codec_info = NULL; valid_codec = TRUE; + g_clear_error (&error); } ret = codec_infos.length != 0; @@ -759,8 +495,7 @@ scan_codecs (GstPlugin * plugin) } done: - if (codec_list_class) - (*env)->DeleteLocalRef (env, codec_list_class); + g_clear_error (&error); return ret; } @@ -2084,6 +1819,9 @@ amc_init (GstPlugin * plugin) gst_amc_codec_info_quark = g_quark_from_static_string ("gst-amc-codec-info"); + if (!gst_amc_codeclist_static_init ()) + return FALSE; + if (!gst_amc_codec_static_init ()) return FALSE; diff --git a/sys/androidmedia/gstamc.h b/sys/androidmedia/gstamc.h index 3700322bde..511665de38 100644 --- a/sys/androidmedia/gstamc.h +++ b/sys/androidmedia/gstamc.h @@ -24,10 +24,8 @@ #include #include #include -#include - -#include "gstjniutils.h" #include "gstamc-codec.h" +#include "gstamc-codeclist.h" #include "gstamc-format.h" G_BEGIN_DECLS @@ -39,13 +37,10 @@ struct _GstAmcCodecType { gchar *mime; gint *color_formats; - gint n_color_formats; + gsize n_color_formats; - struct { - gint profile; - gint level; - } *profile_levels; - gint n_profile_levels; + GstAmcCodecProfileLevel * profile_levels; + gsize n_profile_levels; }; struct _GstAmcCodecInfo { @@ -56,7 +51,6 @@ struct _GstAmcCodecInfo { gint n_supported_types; }; - extern GQuark gst_amc_codec_info_quark; GstVideoFormat gst_amc_color_format_to_video_format (const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format); diff --git a/sys/androidmedia/jni/gstamc-codeclist-jni.c b/sys/androidmedia/jni/gstamc-codeclist-jni.c new file mode 100644 index 0000000000..7b36091ae4 --- /dev/null +++ b/sys/androidmedia/jni/gstamc-codeclist-jni.c @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * Copyright (C) 2015, Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../gstjniutils.h" +#include "../gstamc-codeclist.h" + +struct _GstAmcCodecInfoHandle +{ + jobject object; +}; + +struct _GstAmcCodecCapabilitiesHandle +{ + jobject object; +}; + +static struct +{ + jclass klass; + jmethodID get_codec_count; + jmethodID get_codec_info_at; +} media_codeclist; + +static struct +{ + jclass klass; + jmethodID get_capabilities_for_type; + jmethodID get_name; + jmethodID get_supported_types; + jmethodID is_encoder; +} media_codecinfo; + +static struct +{ + jclass klass; + jfieldID color_formats; + jfieldID profile_levels; +} media_codeccapabilities; + +static struct +{ + jclass klass; + jfieldID level; + jfieldID profile; +} media_codecprofilelevel; + +gboolean +gst_amc_codeclist_static_init (void) +{ + JNIEnv *env; + GError *err = NULL; + + env = gst_amc_jni_get_env (); + + media_codeclist.klass = + gst_amc_jni_get_class (env, &err, "android/media/MediaCodecList"); + if (!media_codeclist.klass) { + GST_ERROR ("Failed to get android.media.MediaCodecList class: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codeclist.get_codec_count = + gst_amc_jni_get_method_id (env, &err, media_codeclist.klass, + "getCodecCount", "()I"); + if (!media_codeclist.get_codec_count) { + GST_ERROR ("Failed to get android.media.MediaCodecList getCodecCount(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codeclist.get_codec_info_at = + gst_amc_jni_get_method_id (env, &err, media_codeclist.klass, + "getCodecInfoAt", "(I)Landroid/media/MediaCodecInfo;"); + if (!media_codeclist.get_codec_count) { + GST_ERROR + ("Failed to get android.media.MediaCodecList getCodecInfoAt(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecinfo.klass = + gst_amc_jni_get_class (env, &err, "android/media/MediaCodecInfo"); + if (!media_codecinfo.klass) { + GST_ERROR ("Failed to get android.media.MediaCodecInfo class: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecinfo.get_capabilities_for_type = + gst_amc_jni_get_method_id (env, &err, media_codecinfo.klass, + "getCapabilitiesForType", + "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;"); + if (!media_codecinfo.get_capabilities_for_type) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo getCapabilitiesForType(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecinfo.get_name = + gst_amc_jni_get_method_id (env, &err, media_codecinfo.klass, "getName", + "()Ljava/lang/String;"); + if (!media_codecinfo.get_name) { + GST_ERROR ("Failed to get android.media.MediaCodecInfo getName(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecinfo.get_supported_types = + gst_amc_jni_get_method_id (env, &err, media_codecinfo.klass, + "getSupportedTypes", "()[Ljava/lang/String;"); + if (!media_codecinfo.get_supported_types) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo getSupportedTypes(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecinfo.is_encoder = + gst_amc_jni_get_method_id (env, &err, media_codecinfo.klass, "isEncoder", + "()Z"); + if (!media_codecinfo.is_encoder) { + GST_ERROR ("Failed to get android.media.MediaCodecInfo isEncoder(): %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codeccapabilities.klass = + gst_amc_jni_get_class (env, &err, + "android/media/MediaCodecInfo/CodecCapabilities"); + if (!media_codeccapabilities.klass) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecCapabilities class: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codeccapabilities.color_formats = + gst_amc_jni_get_field_id (env, &err, media_codeccapabilities.klass, + "colorFormats", "[I"); + if (!media_codeccapabilities.color_formats) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecCapabilities colorFormats: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codeccapabilities.profile_levels = + gst_amc_jni_get_field_id (env, &err, media_codeccapabilities.klass, + "profileLevels", "[Landroid/media/MediaCodecInfo$CodecProfileLevel;"); + if (!media_codeccapabilities.profile_levels) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecCapabilities profileLevels: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecprofilelevel.klass = + gst_amc_jni_get_class (env, &err, + "android/media/MediaCodecInfo/CodecProfileLevel"); + if (!media_codecprofilelevel.klass) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecProfileLevel class: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecprofilelevel.level = + gst_amc_jni_get_field_id (env, &err, media_codecprofilelevel.klass, + "level", "I"); + if (!media_codecprofilelevel.level) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecProfileLevel level: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + media_codecprofilelevel.profile = + gst_amc_jni_get_field_id (env, &err, media_codecprofilelevel.klass, + "profile", "I"); + if (!media_codecprofilelevel.profile) { + GST_ERROR + ("Failed to get android.media.MediaCodecInfo.CodecProfileLevel profile: %s", + err->message); + g_clear_error (&err); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_amc_codeclist_get_count (gint * count, GError ** err) +{ + JNIEnv *env; + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_static_int_method (env, err, media_codeclist.klass, + media_codeclist.get_codec_count, count)) + return FALSE; + + return TRUE; +} + +GstAmcCodecInfoHandle * +gst_amc_codeclist_get_codec_info_at (gint index, GError ** err) +{ + GstAmcCodecInfoHandle *ret; + jobject object; + JNIEnv *env; + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_static_object_method (env, err, media_codeclist.klass, + media_codeclist.get_codec_info_at, &object, index)) + return NULL; + + ret = g_new0 (GstAmcCodecInfoHandle, 1); + ret->object = object; + return ret; +} + +void +gst_amc_codec_info_handle_free (GstAmcCodecInfoHandle * handle) +{ + JNIEnv *env; + + g_return_if_fail (handle != NULL); + + env = gst_amc_jni_get_env (); + + if (handle->object) + gst_amc_jni_object_unref (env, handle->object); + g_free (handle); +} + +gchar * +gst_amc_codec_info_handle_get_name (GstAmcCodecInfoHandle * handle, + GError ** err) +{ + JNIEnv *env; + jstring v_str = NULL; + + g_return_val_if_fail (handle != NULL, NULL); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, handle->object, + media_codecinfo.get_name, &v_str)) + return NULL; + + return gst_amc_jni_string_to_gchar (env, v_str, TRUE); +} + +gboolean +gst_amc_codec_info_handle_is_encoder (GstAmcCodecInfoHandle * handle, + gboolean * is_encoder, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (handle != NULL, FALSE); + g_return_val_if_fail (is_encoder != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_boolean_method (env, err, handle->object, + media_codecinfo.is_encoder, is_encoder)) + return FALSE; + + return TRUE; +} + +gchar ** +gst_amc_codec_info_handle_get_supported_types (GstAmcCodecInfoHandle * handle, + gsize * length, GError ** err) +{ + JNIEnv *env; + jarray array = NULL; + jsize len; + jsize i; + gchar **strv = NULL; + + g_return_val_if_fail (handle != NULL, NULL); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, handle->object, + media_codecinfo.get_name, &array)) + goto done; + + len = (*env)->GetArrayLength (env, array); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array length"); + goto done; + } + + strv = g_new0 (gchar *, len + 1); + *length = len; + + for (i = 0; i < len; i++) { + jstring string; + + string = (*env)->GetObjectArrayElement (env, array, i); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array element"); + g_strfreev (strv); + strv = NULL; + goto done; + } + + strv[i] = gst_amc_jni_string_to_gchar (env, string, TRUE); + if (!strv[i]) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed create string"); + g_strfreev (strv); + strv = NULL; + goto done; + } + } + +done: + if (array) + (*env)->DeleteLocalRef (env, array); + + return strv; +} + +GstAmcCodecCapabilitiesHandle * +gst_amc_codec_info_handle_get_capabilities_for_type (GstAmcCodecInfoHandle * + handle, const gchar * type, GError ** err) +{ + GstAmcCodecCapabilitiesHandle *ret = NULL; + jstring type_str; + jobject object; + JNIEnv *env; + + env = gst_amc_jni_get_env (); + + type_str = gst_amc_jni_string_from_gchar (env, err, FALSE, type); + if (!type_str) + goto done; + + if (!gst_amc_jni_call_object_method (env, err, handle->object, + media_codecinfo.get_capabilities_for_type, &object, type_str)) + goto done; + + ret = g_new0 (GstAmcCodecCapabilitiesHandle, 1); + ret->object = object; + +done: + if (type_str) + gst_amc_jni_object_local_unref (env, type_str); + + return ret; +} + +void +gst_amc_codec_capabilities_handle_free (GstAmcCodecCapabilitiesHandle * handle) +{ + JNIEnv *env; + + g_return_if_fail (handle != NULL); + + env = gst_amc_jni_get_env (); + + if (handle->object) + gst_amc_jni_object_unref (env, handle->object); + g_free (handle); +} + +gint *gst_amc_codec_capabilities_handle_get_color_formats + (GstAmcCodecCapabilitiesHandle * handle, gsize * length, GError ** err) +{ + JNIEnv *env; + jarray array = NULL; + jsize len; + jint *elems = NULL; + gint *ret = NULL; + + g_return_val_if_fail (handle != NULL, NULL); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_get_object_field (env, err, handle->object, + media_codeccapabilities.color_formats, &array)) + goto done; + + len = (*env)->GetArrayLength (env, array); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array length"); + goto done; + } + + elems = (*env)->GetIntArrayElements (env, array, NULL); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array elements"); + goto done; + } + + ret = g_memdup (elems, sizeof (jint) * len); + *length = len; + +done: + if (elems) + (*env)->ReleaseIntArrayElements (env, array, elems, JNI_ABORT); + if (array) + (*env)->DeleteLocalRef (env, array); + + return ret; +} + +GstAmcCodecProfileLevel *gst_amc_codec_capabilities_handle_get_profile_levels + (GstAmcCodecCapabilitiesHandle * handle, gsize * length, GError ** err) +{ + GstAmcCodecProfileLevel *ret = NULL; + JNIEnv *env; + jobject array = NULL; + jsize len; + jsize i; + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_get_object_field (env, err, handle->object, + media_codeccapabilities.profile_levels, &array)) + goto done; + + len = (*env)->GetArrayLength (env, array); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array length"); + goto done; + } + + ret = g_new0 (GstAmcCodecProfileLevel, len); + *length = len; + + for (i = 0; i < len; i++) { + jobject object = NULL; + + object = (*env)->GetObjectArrayElement (env, array, i); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get array element"); + g_free (ret); + ret = NULL; + goto done; + } + + if (!gst_amc_jni_get_int_field (env, err, object, + media_codecprofilelevel.level, &ret[i].level)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get level"); + (*env)->DeleteLocalRef (env, object); + g_free (ret); + ret = NULL; + goto done; + } + + if (!gst_amc_jni_get_int_field (env, err, object, + media_codecprofilelevel.profile, &ret[i].profile)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get profile"); + (*env)->DeleteLocalRef (env, object); + g_free (ret); + ret = NULL; + goto done; + } + + (*env)->DeleteLocalRef (env, object); + } + +done: + if (array) + (*env)->DeleteLocalRef (env, array); + + return ret; +} diff --git a/sys/androidmedia/meson.build b/sys/androidmedia/meson.build index 79bc2f8736..994faf79f2 100644 --- a/sys/androidmedia/meson.build +++ b/sys/androidmedia/meson.build @@ -12,6 +12,7 @@ androidmedia_sources = [ 'gst-android-hardware-sensor.c', 'gstjniutils.c', 'jni/gstamc-codec-jni.c', + 'jni/gstamc-codeclist-jni.c', 'jni/gstamc-format-jni.c', ]