From 6b67ff61adfcf4f714d709c0e77b53f1521639a8 Mon Sep 17 00:00:00 2001 From: Stefan Popa Date: Tue, 22 Aug 2017 14:23:45 +0000 Subject: [PATCH] xml-formatter: Save encoder and muxer advanced settings Added support for saving/loading encoder and muxer advanced settings. Differential Revision: https://phabricator.freedesktop.org/D1837 --- ges/ges-base-xml-formatter.c | 98 +++++++++++++++++++++++++++++++++++++------- ges/ges-internal.h | 8 +++- ges/ges-xml-formatter.c | 86 ++++++++++++++++++++++++++++++++------ 3 files changed, 164 insertions(+), 28 deletions(-) diff --git a/ges/ges-base-xml-formatter.c b/ges/ges-base-xml-formatter.c index 63284ec..ede45c8 100644 --- a/ges/ges-base-xml-formatter.c +++ b/ges/ges-base-xml-formatter.c @@ -792,12 +792,49 @@ done: _loading_done (self); } +GstElement * +get_element_for_encoding_profile (GstEncodingProfile * prof, + GstElementFactoryListType type) +{ + GstEncodingProfile *prof_copy; + GstElement *encodebin; + GList *tmp; + GstElement *element = NULL; + + prof_copy = gst_encoding_profile_copy (prof); + + gst_encoding_profile_set_presence (prof_copy, 1); + gst_encoding_profile_set_preset (prof_copy, NULL); + + encodebin = gst_element_factory_make ("encodebin", NULL); + g_object_set (encodebin, "profile", prof_copy, NULL); + + GST_OBJECT_LOCK (encodebin); + for (tmp = GST_BIN (encodebin)->children; tmp; tmp = tmp->next) { + GstElementFactory *factory; + factory = gst_element_get_factory (GST_ELEMENT (tmp->data)); + + if (factory && gst_element_factory_list_is_type (factory, type)) { + element = GST_ELEMENT (tmp->data); + gst_object_ref (element); + break; + } + } + GST_OBJECT_UNLOCK (encodebin); + gst_object_unref (encodebin); + + gst_encoding_profile_unref (prof_copy); + + return element; +} + static GstEncodingProfile * _create_profile (GESBaseXmlFormatter * self, const gchar * type, const gchar * parent, const gchar * name, const gchar * description, GstCaps * format, const gchar * preset, - const gchar * preset_name, gint id, guint presence, GstCaps * restriction, - guint pass, gboolean variableframerate, gboolean enabled) + GstStructure * preset_properties, const gchar * preset_name, gint id, + guint presence, GstCaps * restriction, guint pass, + gboolean variableframerate, gboolean enabled) { GstEncodingProfile *profile = NULL; @@ -805,8 +842,6 @@ _create_profile (GESBaseXmlFormatter * self, profile = GST_ENCODING_PROFILE (gst_encoding_container_profile_new (name, description, format, preset)); gst_encoding_profile_set_preset_name (profile, preset_name); - - return profile; } else if (!g_strcmp0 (type, "video")) { GstEncodingVideoProfile *sprof = gst_encoding_video_profile_new (format, preset, restriction, presence); @@ -824,10 +859,43 @@ _create_profile (GESBaseXmlFormatter * self, return NULL; } - gst_encoding_profile_set_name (profile, name); - gst_encoding_profile_set_enabled (profile, enabled); - gst_encoding_profile_set_description (profile, description); - gst_encoding_profile_set_preset_name (profile, preset_name); + if (!g_strcmp0 (type, "video") || !g_strcmp0 (type, "audio")) { + gst_encoding_profile_set_name (profile, name); + gst_encoding_profile_set_enabled (profile, enabled); + gst_encoding_profile_set_description (profile, description); + gst_encoding_profile_set_preset_name (profile, preset_name); + } + + if (preset && preset_properties) { + GstElement *element; + + if (!g_strcmp0 (type, "container")) { + element = get_element_for_encoding_profile (profile, + GST_ELEMENT_FACTORY_TYPE_MUXER); + } else { + element = get_element_for_encoding_profile (profile, + GST_ELEMENT_FACTORY_TYPE_ENCODER); + } + + if (G_UNLIKELY (!element || !GST_IS_PRESET (element))) { + GST_WARNING_OBJECT (element, "Element is not a GstPreset"); + goto done; + } + + /* If the preset doesn't exist on the system, create it */ + if (!gst_preset_load_preset (GST_PRESET (element), preset)) { + gst_structure_foreach (preset_properties, + (GstStructureForeachFunc) set_property_foreach, element); + + if (!gst_preset_save_preset (GST_PRESET (element), preset)) { + GST_WARNING_OBJECT (element, "Could not save preset %s", preset); + } + } + + done: + if (element) + gst_object_unref (element); + } return profile; } @@ -1236,9 +1304,10 @@ void ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self, const gchar * type, const gchar * parent, const gchar * name, const gchar * description, GstCaps * format, const gchar * preset, - const gchar * preset_name, guint id, guint presence, GstCaps * restriction, - guint pass, gboolean variableframerate, GstStructure * properties, - gboolean enabled, GError ** error) + GstStructure * preset_properties, const gchar * preset_name, guint id, + guint presence, GstCaps * restriction, guint pass, + gboolean variableframerate, GstStructure * properties, gboolean enabled, + GError ** error) { const GList *tmp; GstEncodingProfile *profile; @@ -1251,8 +1320,8 @@ ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self, if (parent == NULL) { profile = _create_profile (self, type, parent, name, description, format, preset, - preset_name, id, presence, restriction, pass, variableframerate, - enabled); + preset_properties, preset_name, id, presence, restriction, pass, + variableframerate, enabled); ges_project_add_encoding_profile (GES_FORMATTER (self)->project, profile); gst_object_unref (profile); @@ -1285,7 +1354,8 @@ ges_base_xml_formatter_add_encoding_profile (GESBaseXmlFormatter * self, profile = _create_profile (self, type, parent, name, description, format, preset, - preset_name, id, presence, restriction, pass, variableframerate, enabled); + preset_properties, preset_name, id, presence, restriction, pass, + variableframerate, enabled); if (profile == NULL) goto done; diff --git a/ges/ges-internal.h b/ges/ges-internal.h index f3b8670..3e62730 100644 --- a/ges/ges-internal.h +++ b/ges/ges-internal.h @@ -20,8 +20,8 @@ #ifndef __GES_INTERNAL_H__ #define __GES_INTERNAL_H__ - #include +#include #include #include "ges-timeline.h" @@ -258,6 +258,7 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_add_encoding_profile(GESBaseXmlForma const gchar * description, GstCaps * format, const gchar * preset, + GstStructure * preset_properties, const gchar * preset_name, guint id, guint presence, @@ -299,7 +300,10 @@ G_GNUC_INTERNAL void ges_base_xml_formatter_add_control_binding (GESBaseXmlForma G_GNUC_INTERNAL gboolean set_property_foreach (GQuark field_id, const GValue * value, - GObject * object);; + GObject * object); + +G_GNUC_INTERNAL GstElement * get_element_for_encoding_profile (GstEncodingProfile *prof, + GstElementFactoryListType type); /* Function to initialise GES */ G_GNUC_INTERNAL void _init_standard_transition_assets (void); diff --git a/ges/ges-xml-formatter.c b/ges/ges-xml-formatter.c index 28ddf48..bf2f9c7 100644 --- a/ges/ges-xml-formatter.c +++ b/ges/ges-xml-formatter.c @@ -141,8 +141,9 @@ _parse_encoding_profile (GMarkupParseContext * context, const gchar ** attribute_values, GESXmlFormatter * self, GError ** error) { GstCaps *capsformat = NULL; - const gchar *name, *description, *type, *preset = NULL, *preset_name = - NULL, *format; + GstStructure *preset_properties = NULL; + const gchar *name, *description, *type, *preset = NULL, + *str_preset_properties = NULL, *preset_name = NULL, *format; if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, @@ -150,6 +151,7 @@ _parse_encoding_profile (GMarkupParseContext * context, G_MARKUP_COLLECT_STRING, "description", &description, G_MARKUP_COLLECT_STRING, "type", &type, COLLECT_STR_OPT, "preset", &preset, + COLLECT_STR_OPT, "preset-properties", &str_preset_properties, COLLECT_STR_OPT, "preset-name", &preset_name, COLLECT_STR_OPT, "format", &format, G_MARKUP_COLLECT_INVALID)) return; @@ -157,9 +159,18 @@ _parse_encoding_profile (GMarkupParseContext * context, if (format) capsformat = gst_caps_from_string (format); + if (str_preset_properties) { + preset_properties = gst_structure_from_string (str_preset_properties, NULL); + if (preset_properties == NULL) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "element '%s', Wrong preset-properties format.", element_name); + return; + } + } + ges_base_xml_formatter_add_encoding_profile (GES_BASE_XML_FORMATTER (self), - type, NULL, name, description, capsformat, preset, preset_name, 0, 0, - NULL, 0, FALSE, NULL, TRUE, error); + type, NULL, name, description, capsformat, preset, preset_properties, + preset_name, 0, 0, NULL, 0, FALSE, NULL, TRUE, error); } static inline void @@ -170,10 +181,11 @@ _parse_stream_profile (GMarkupParseContext * context, gboolean variableframerate = FALSE, enabled = TRUE; guint id = 0, presence = 0, pass = 0; GstCaps *format_caps = NULL, *restriction_caps = NULL; + GstStructure *preset_properties = NULL; const gchar *parent, *strid, *type, *strpresence, *format = NULL, - *name = NULL, *description = NULL, *preset, *preset_name = - NULL, *restriction = NULL, *strpass = NULL, *strvariableframerate = NULL, - *strenabled = NULL; + *name = NULL, *description = NULL, *preset, + *str_preset_properties = NULL, *preset_name = NULL, *restriction = NULL, + *strpass = NULL, *strvariableframerate = NULL, *strenabled = NULL; /* FIXME Looks like there is a bug in that function, if we put the parent * at the beginning it set %NULL and not the real value... :/ */ @@ -186,6 +198,7 @@ _parse_stream_profile (GMarkupParseContext * context, COLLECT_STR_OPT, "name", &name, COLLECT_STR_OPT, "description", &description, COLLECT_STR_OPT, "preset", &preset, + COLLECT_STR_OPT, "preset-properties", &str_preset_properties, COLLECT_STR_OPT, "preset-name", &preset_name, COLLECT_STR_OPT, "restriction", &restriction, COLLECT_STR_OPT, "pass", &strpass, @@ -205,6 +218,12 @@ _parse_stream_profile (GMarkupParseContext * context, goto convertion_failed; } + if (str_preset_properties) { + preset_properties = gst_structure_from_string (str_preset_properties, NULL); + if (preset_properties == NULL) + goto convertion_failed; + } + if (strpass) { pass = g_ascii_strtoll (strpass, NULL, 10); if (errno) @@ -230,9 +249,12 @@ _parse_stream_profile (GMarkupParseContext * context, restriction_caps = gst_caps_from_string (restriction); ges_base_xml_formatter_add_encoding_profile (GES_BASE_XML_FORMATTER (self), - type, parent, name, description, format_caps, preset, preset_name, id, - presence, restriction_caps, pass, variableframerate, NULL, enabled, - error); + type, parent, name, description, format_caps, preset, preset_properties, + preset_name, id, presence, restriction_caps, pass, variableframerate, + NULL, enabled, error); + + if (preset_properties) + gst_structure_free (preset_properties); return; @@ -1363,9 +1385,26 @@ _save_stream_profiles (GESXmlFormatter * self, GString * str, description)); preset = gst_encoding_profile_get_preset (sprof); - if (preset) + if (preset) { + GstElement *encoder; + append_escaped (str, g_markup_printf_escaped ("preset='%s' ", preset)); + encoder = get_element_for_encoding_profile (sprof, + GST_ELEMENT_FACTORY_TYPE_ENCODER); + if (encoder) { + if (GST_IS_PRESET (encoder) && + gst_preset_load_preset (GST_PRESET (encoder), preset)) { + + gchar *settings = _serialize_properties (G_OBJECT (encoder), NULL); + append_escaped (str, + g_markup_printf_escaped ("preset-properties='%s' ", settings)); + g_free (settings); + } + gst_object_unref (encoder); + } + } + preset_name = gst_encoding_profile_get_preset_name (sprof); if (preset_name) append_escaped (str, g_markup_printf_escaped ("preset-name='%s' ", @@ -1416,10 +1455,33 @@ _save_encoding_profiles (GESXmlFormatter * self, GString * str, ("