mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 00:36:51 +00:00
ges: Enhance xges format versioning
Summary: Handle the fact that some new features can be added and that means generated files will not be fully understandable by older versions of the formatter. Make sure that we set the format version to 0.2 when we serialize the GstEncodingProfile.enabled property. Add some tests around that. + Fix a minor bug in the test-utils + Add a meta on the projects to tell in what format version a project has been serialized/parsed back API: GES_META_FORMAT_VERSION Depends on D178 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D184
This commit is contained in:
parent
ff274dee2e
commit
241e809a81
7 changed files with 100 additions and 42 deletions
|
@ -1035,6 +1035,7 @@ GES_META_FORMATTER_VERSION
|
||||||
GES_META_FORMATTER_RANK
|
GES_META_FORMATTER_RANK
|
||||||
GES_META_DESCRIPTION
|
GES_META_DESCRIPTION
|
||||||
|
|
||||||
|
GES_META_FORMAT_VERSION
|
||||||
|
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GESMetaContainerInterface
|
GESMetaContainerInterface
|
||||||
|
|
|
@ -92,6 +92,8 @@ _register_metas (GESExtractableInterface * iface, GObjectClass * class,
|
||||||
GES_META_FORMATTER_VERSION, fclass->version);
|
GES_META_FORMATTER_VERSION, fclass->version);
|
||||||
ges_meta_container_register_meta_uint (container, GES_META_READABLE,
|
ges_meta_container_register_meta_uint (container, GES_META_READABLE,
|
||||||
GES_META_FORMATTER_RANK, fclass->rank);
|
GES_META_FORMATTER_RANK, fclass->rank);
|
||||||
|
ges_meta_container_register_meta_string (container, GES_META_READ_WRITE,
|
||||||
|
GES_META_FORMAT_VERSION, NULL);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,13 @@ G_BEGIN_DECLS
|
||||||
*/
|
*/
|
||||||
#define GES_META_VOLUME_DEFAULT 1.0
|
#define GES_META_VOLUME_DEFAULT 1.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GES_META_FORMAT_VERSION:
|
||||||
|
*
|
||||||
|
* The version of the format in which a project is serialized
|
||||||
|
*/
|
||||||
|
#define GES_META_FORMAT_VERSION "format-version"
|
||||||
|
|
||||||
typedef struct _GESMetaContainer GESMetaContainer;
|
typedef struct _GESMetaContainer GESMetaContainer;
|
||||||
typedef struct _GESMetaContainerInterface GESMetaContainerInterface;
|
typedef struct _GESMetaContainerInterface GESMetaContainerInterface;
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
G_DEFINE_TYPE (GESXmlFormatter, ges_xml_formatter, GES_TYPE_BASE_XML_FORMATTER);
|
G_DEFINE_TYPE (GESXmlFormatter, ges_xml_formatter, GES_TYPE_BASE_XML_FORMATTER);
|
||||||
|
|
||||||
#define API_VERSION 0
|
#define API_VERSION 0
|
||||||
#define MINOR_VERSION 1
|
#define MINOR_VERSION 2
|
||||||
#define VERSION 0.1
|
#define VERSION 0.2
|
||||||
|
|
||||||
#define COLLECT_STR_OPT (G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL)
|
#define COLLECT_STR_OPT (G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL)
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@ struct _GESXmlFormatterPrivate
|
||||||
GHashTable *element_id;
|
GHashTable *element_id;
|
||||||
|
|
||||||
guint nbelements;
|
guint nbelements;
|
||||||
|
|
||||||
|
guint min_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -56,8 +58,8 @@ _parse_ges_element (GMarkupParseContext * context, const gchar * element_name,
|
||||||
const gchar ** attribute_names, const gchar ** attribute_values,
|
const gchar ** attribute_names, const gchar ** attribute_values,
|
||||||
GESXmlFormatter * self, GError ** error)
|
GESXmlFormatter * self, GError ** error)
|
||||||
{
|
{
|
||||||
|
guint api_version;
|
||||||
const gchar *version, *properties;
|
const gchar *version, *properties;
|
||||||
guint api_version, min_version;
|
|
||||||
|
|
||||||
gchar **split_version = NULL;
|
gchar **split_version = NULL;
|
||||||
|
|
||||||
|
@ -84,8 +86,8 @@ _parse_ges_element (GMarkupParseContext * context, const gchar * element_name,
|
||||||
if (errno || api_version != API_VERSION)
|
if (errno || api_version != API_VERSION)
|
||||||
goto stroull_failed;
|
goto stroull_failed;
|
||||||
|
|
||||||
min_version = g_ascii_strtoull (split_version[1], NULL, 10);
|
self->priv->min_version = g_ascii_strtoull (split_version[1], NULL, 10);
|
||||||
if (min_version > MINOR_VERSION)
|
if (self->priv->min_version > MINOR_VERSION)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
_GET_PRIV (self)->ges_opened = TRUE;
|
_GET_PRIV (self)->ges_opened = TRUE;
|
||||||
|
@ -780,6 +782,15 @@ _parse_element_end (GMarkupParseContext * context,
|
||||||
const gchar * element_name, gpointer self, GError ** error)
|
const gchar * element_name, gpointer self, GError ** error)
|
||||||
{
|
{
|
||||||
/*GESXmlFormatterPrivate *priv = _GET_PRIV (self); */
|
/*GESXmlFormatterPrivate *priv = _GET_PRIV (self); */
|
||||||
|
if (g_strcmp0 (element_name, "ges") == 0 && GES_FORMATTER (self)->project) {
|
||||||
|
gchar *version = g_strdup_printf ("%d.%d",
|
||||||
|
API_VERSION, GES_XML_FORMATTER (self)->priv->min_version);
|
||||||
|
|
||||||
|
ges_meta_container_set_string (GES_META_CONTAINER (GES_FORMATTER
|
||||||
|
(self)->project), GES_META_FORMAT_VERSION, version);
|
||||||
|
|
||||||
|
g_free (version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1272,8 +1283,8 @@ _save_timeline (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_save_stream_profiles (GString * str, GstEncodingProfile * sprof,
|
_save_stream_profiles (GESXmlFormatter * self, GString * str,
|
||||||
const gchar * profilename, guint id)
|
GstEncodingProfile * sprof, const gchar * profilename, guint id)
|
||||||
{
|
{
|
||||||
gchar *tmpc;
|
gchar *tmpc;
|
||||||
GstCaps *tmpcaps;
|
GstCaps *tmpcaps;
|
||||||
|
@ -1282,10 +1293,15 @@ _save_stream_profiles (GString * str, GstEncodingProfile * sprof,
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
g_markup_printf_escaped
|
g_markup_printf_escaped
|
||||||
(" <stream-profile parent='%s' id='%d' type='%s' "
|
(" <stream-profile parent='%s' id='%d' type='%s' "
|
||||||
"presence='%d' enabled='%d' ", profilename, id,
|
"presence='%d' ", profilename, id,
|
||||||
gst_encoding_profile_get_type_nick (sprof),
|
gst_encoding_profile_get_type_nick (sprof),
|
||||||
gst_encoding_profile_get_presence (sprof),
|
gst_encoding_profile_get_presence (sprof)));
|
||||||
gst_encoding_profile_is_enabled (sprof)));
|
|
||||||
|
if (!gst_encoding_profile_is_enabled (sprof)) {
|
||||||
|
append_escaped (str, g_strdup ("enabled='0' "));
|
||||||
|
|
||||||
|
self->priv->min_version = MAX (self->priv->min_version, 2);
|
||||||
|
}
|
||||||
|
|
||||||
tmpcaps = gst_encoding_profile_get_format (sprof);
|
tmpcaps = gst_encoding_profile_get_format (sprof);
|
||||||
if (tmpcaps) {
|
if (tmpcaps) {
|
||||||
|
@ -1334,7 +1350,8 @@ _save_stream_profiles (GString * str, GstEncodingProfile * sprof,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
_save_encoding_profiles (GString * str, GESProject * project)
|
_save_encoding_profiles (GESXmlFormatter * self, GString * str,
|
||||||
|
GESProject * project)
|
||||||
{
|
{
|
||||||
GstCaps *profformat;
|
GstCaps *profformat;
|
||||||
const gchar *profname, *profdesc, *profpreset, *proftype, *profpresetname;
|
const gchar *profname, *profdesc, *profpreset, *proftype, *profpresetname;
|
||||||
|
@ -1382,7 +1399,7 @@ _save_encoding_profiles (GString * str, GESProject * project)
|
||||||
for (tmp2 = gst_encoding_container_profile_get_profiles (container_prof);
|
for (tmp2 = gst_encoding_container_profile_get_profiles (container_prof);
|
||||||
tmp2; tmp2 = tmp2->next, i++) {
|
tmp2; tmp2 = tmp2->next, i++) {
|
||||||
GstEncodingProfile *sprof = (GstEncodingProfile *) tmp2->data;
|
GstEncodingProfile *sprof = (GstEncodingProfile *) tmp2->data;
|
||||||
_save_stream_profiles (str, sprof, profname, i);
|
_save_stream_profiles (self, str, sprof, profname, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
|
@ -1396,16 +1413,17 @@ _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
|
||||||
GString *str;
|
GString *str;
|
||||||
GESProject *project;
|
GESProject *project;
|
||||||
|
|
||||||
|
gchar *projstr = NULL, *version;
|
||||||
gchar *properties = NULL, *metas = NULL;
|
gchar *properties = NULL, *metas = NULL;
|
||||||
GESXmlFormatterPrivate *priv;
|
GESXmlFormatterPrivate *priv;
|
||||||
|
|
||||||
|
|
||||||
priv = _GET_PRIV (formatter);
|
priv = _GET_PRIV (formatter);
|
||||||
|
|
||||||
|
priv->min_version = 1;
|
||||||
project = formatter->project;
|
project = formatter->project;
|
||||||
str = priv->str = g_string_new (NULL);
|
str = priv->str = g_string_new (NULL);
|
||||||
|
|
||||||
g_string_append_printf (str, "<ges version='%i.%i'>\n", API_VERSION,
|
|
||||||
MINOR_VERSION);
|
|
||||||
properties = _serialize_properties (G_OBJECT (project), NULL);
|
properties = _serialize_properties (G_OBJECT (project), NULL);
|
||||||
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (project));
|
metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (project));
|
||||||
append_escaped (str,
|
append_escaped (str,
|
||||||
|
@ -1415,7 +1433,7 @@ _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
|
||||||
g_free (metas);
|
g_free (metas);
|
||||||
|
|
||||||
g_string_append (str, " <encoding-profiles>\n");
|
g_string_append (str, " <encoding-profiles>\n");
|
||||||
_save_encoding_profiles (str, project);
|
_save_encoding_profiles (GES_XML_FORMATTER (formatter), str, project);
|
||||||
g_string_append (str, " </encoding-profiles>\n");
|
g_string_append (str, " </encoding-profiles>\n");
|
||||||
|
|
||||||
g_string_append (str, " <ressources>\n");
|
g_string_append (str, " <ressources>\n");
|
||||||
|
@ -1425,6 +1443,22 @@ _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
|
||||||
_save_timeline (GES_XML_FORMATTER (formatter), str, timeline);
|
_save_timeline (GES_XML_FORMATTER (formatter), str, timeline);
|
||||||
g_string_append (str, "</project>\n</ges>");
|
g_string_append (str, "</project>\n</ges>");
|
||||||
|
|
||||||
|
projstr = g_strdup_printf ("<ges version='%i.%i'>\n", API_VERSION,
|
||||||
|
priv->min_version);
|
||||||
|
g_string_prepend (str, projstr);
|
||||||
|
g_free (projstr);
|
||||||
|
|
||||||
|
ges_meta_container_set_int (GES_META_CONTAINER (project),
|
||||||
|
GES_META_FORMAT_VERSION, priv->min_version);
|
||||||
|
|
||||||
|
version = g_strdup_printf ("%d.%d", API_VERSION,
|
||||||
|
GES_XML_FORMATTER (formatter)->priv->min_version);
|
||||||
|
|
||||||
|
ges_meta_container_set_string (GES_META_CONTAINER (project),
|
||||||
|
GES_META_FORMAT_VERSION, version);
|
||||||
|
|
||||||
|
g_free (version);
|
||||||
|
|
||||||
priv->str = NULL;
|
priv->str = NULL;
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
|
@ -1457,6 +1491,7 @@ ges_xml_formatter_init (GESXmlFormatter * self)
|
||||||
priv->element_id = g_hash_table_new (g_direct_hash, g_direct_equal);
|
priv->element_id = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
|
|
||||||
self->priv = priv;
|
self->priv = priv;
|
||||||
|
self->priv->min_version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -484,63 +484,77 @@ GST_END_TEST;
|
||||||
GST_START_TEST (test_project_load_xges)
|
GST_START_TEST (test_project_load_xges)
|
||||||
{
|
{
|
||||||
gboolean saved;
|
gboolean saved;
|
||||||
GESProject *project;
|
GESProject *loaded_project, *saved_project;
|
||||||
GESTimeline *timeline;
|
GESTimeline *timeline;
|
||||||
GESAsset *formatter_asset;
|
GESAsset *formatter_asset;
|
||||||
gchar *uri = ges_test_file_uri ("test-project.xges");
|
gchar *uri = ges_test_file_uri ("test-project.xges");
|
||||||
|
|
||||||
project = ges_project_new (uri);
|
loaded_project = ges_project_new (uri);
|
||||||
mainloop = g_main_loop_new (NULL, FALSE);
|
mainloop = g_main_loop_new (NULL, FALSE);
|
||||||
fail_unless (GES_IS_PROJECT (project));
|
fail_unless (GES_IS_PROJECT (loaded_project));
|
||||||
|
|
||||||
/* Connect the signals */
|
/* Connect the signals */
|
||||||
g_signal_connect (project, "asset-added", (GCallback) asset_added_cb, NULL);
|
g_signal_connect (loaded_project, "asset-added", (GCallback) asset_added_cb,
|
||||||
g_signal_connect (project, "loaded", (GCallback) project_loaded_cb, mainloop);
|
NULL);
|
||||||
|
g_signal_connect (loaded_project, "loaded", (GCallback) project_loaded_cb,
|
||||||
|
mainloop);
|
||||||
|
|
||||||
/* Make sure we update the project's dummy URL to some actual URL */
|
/* Make sure we update the project's dummy URL to some actual URL */
|
||||||
g_signal_connect (project, "missing-uri", (GCallback) _set_new_uri, NULL);
|
g_signal_connect (loaded_project, "missing-uri", (GCallback) _set_new_uri,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* Now extract a timeline from it */
|
/* Now extract a timeline from it */
|
||||||
GST_LOG ("Loading project");
|
GST_LOG ("Loading project");
|
||||||
timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), NULL));
|
timeline =
|
||||||
|
GES_TIMELINE (ges_asset_extract (GES_ASSET (loaded_project), NULL));
|
||||||
fail_unless (GES_IS_TIMELINE (timeline));
|
fail_unless (GES_IS_TIMELINE (timeline));
|
||||||
assert_equals_int (g_list_length (ges_project_get_loading_assets (project)),
|
assert_equals_int (g_list_length (ges_project_get_loading_assets
|
||||||
1);
|
(loaded_project)), 1);
|
||||||
|
|
||||||
g_main_loop_run (mainloop);
|
g_main_loop_run (mainloop);
|
||||||
GST_LOG ("Test first loading");
|
GST_LOG ("Test first loading");
|
||||||
_test_project (project, timeline);
|
_test_project (loaded_project, timeline);
|
||||||
g_free (uri);
|
g_free (uri);
|
||||||
|
|
||||||
uri = ges_test_get_tmp_uri ("test-project_TMP.xges");
|
uri = ges_test_get_tmp_uri ("test-project_TMP.xges");
|
||||||
formatter_asset = ges_asset_request (GES_TYPE_FORMATTER, "ges", NULL);
|
formatter_asset = ges_asset_request (GES_TYPE_FORMATTER, "ges", NULL);
|
||||||
saved =
|
saved =
|
||||||
ges_project_save (project, timeline, uri, formatter_asset, TRUE, NULL);
|
ges_project_save (loaded_project, timeline, uri, formatter_asset, TRUE,
|
||||||
|
NULL);
|
||||||
fail_unless (saved);
|
fail_unless (saved);
|
||||||
gst_object_unref (timeline);
|
gst_object_unref (timeline);
|
||||||
gst_object_unref (project);
|
|
||||||
|
|
||||||
project = ges_project_new (uri);
|
saved_project = ges_project_new (uri);
|
||||||
ASSERT_OBJECT_REFCOUNT (project, "Our + cache", 2);
|
ASSERT_OBJECT_REFCOUNT (saved_project, "Our + cache", 2);
|
||||||
g_signal_connect (project, "asset-added", (GCallback) asset_added_cb, NULL);
|
g_signal_connect (saved_project, "asset-added", (GCallback) asset_added_cb,
|
||||||
g_signal_connect (project, "loaded", (GCallback) project_loaded_cb, mainloop);
|
NULL);
|
||||||
|
g_signal_connect (saved_project, "loaded", (GCallback) project_loaded_cb,
|
||||||
|
mainloop);
|
||||||
|
|
||||||
GST_LOG ("Loading saved project");
|
GST_LOG ("Loading saved project");
|
||||||
timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (project), NULL));
|
timeline = GES_TIMELINE (ges_asset_extract (GES_ASSET (saved_project), NULL));
|
||||||
fail_unless (GES_IS_TIMELINE (timeline));
|
fail_unless (GES_IS_TIMELINE (timeline));
|
||||||
g_main_loop_run (mainloop);
|
g_main_loop_run (mainloop);
|
||||||
_test_project (project, timeline);
|
_test_project (saved_project, timeline);
|
||||||
|
|
||||||
|
fail_unless (ges_meta_container_get_string (GES_META_CONTAINER
|
||||||
|
(loaded_project), GES_META_FORMAT_VERSION));
|
||||||
|
fail_unless_equals_string (ges_meta_container_get_string (GES_META_CONTAINER
|
||||||
|
(loaded_project), GES_META_FORMAT_VERSION),
|
||||||
|
ges_meta_container_get_string (GES_META_CONTAINER (loaded_project),
|
||||||
|
GES_META_FORMAT_VERSION));
|
||||||
gst_object_unref (timeline);
|
gst_object_unref (timeline);
|
||||||
gst_object_unref (project);
|
gst_object_unref (saved_project);
|
||||||
|
gst_object_unref (loaded_project);
|
||||||
g_free (uri);
|
g_free (uri);
|
||||||
|
|
||||||
ASSERT_OBJECT_REFCOUNT (project, "Still 1 ref for asset cache", 1);
|
ASSERT_OBJECT_REFCOUNT (saved_project, "Still 1 ref for asset cache", 1);
|
||||||
|
|
||||||
g_main_loop_unref (mainloop);
|
g_main_loop_unref (mainloop);
|
||||||
g_signal_handlers_disconnect_by_func (project, (GCallback) project_loaded_cb,
|
g_signal_handlers_disconnect_by_func (saved_project,
|
||||||
mainloop);
|
(GCallback) project_loaded_cb, mainloop);
|
||||||
g_signal_handlers_disconnect_by_func (project, (GCallback) asset_added_cb,
|
g_signal_handlers_disconnect_by_func (saved_project,
|
||||||
NULL);
|
(GCallback) asset_added_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<project metadatas='metadatas, name=(string)"Example\ project";'>
|
<project metadatas='metadatas, name=(string)"Example\ project";'>
|
||||||
<encoding-profiles>
|
<encoding-profiles>
|
||||||
<encoding-profile name='first_profile' description='(null)' type='container' format='application/ogg'>
|
<encoding-profile name='first_profile' description='(null)' type='container' format='application/ogg'>
|
||||||
<stream-profile parent='first_profile' id='0' type='video' presence='0' format='video/x-h264' pass='0' variableframerate='0' />
|
<stream-profile parent='first_profile' enabled='0' id='0' type='video' presence='0' format='video/x-h264' pass='0' variableframerate='0' />
|
||||||
<stream-profile parent='first_profile' id='1' type='audio' presence='0' format='audio/x-aac' />
|
<stream-profile parent='first_profile' id='1' type='audio' presence='0' format='audio/x-aac' />
|
||||||
</encoding-profile>
|
</encoding-profile>
|
||||||
</encoding-profiles>
|
</encoding-profiles>
|
||||||
|
|
|
@ -283,8 +283,7 @@ ges_test_get_tmp_uri (const gchar * filename)
|
||||||
{
|
{
|
||||||
gchar *location, *uri;
|
gchar *location, *uri;
|
||||||
|
|
||||||
location = g_build_filename (g_get_tmp_dir (),
|
location = g_build_filename (g_get_tmp_dir (), filename, NULL);
|
||||||
"test-keyframes-save.xges", NULL);
|
|
||||||
|
|
||||||
uri = g_strconcat ("file://", location, NULL);
|
uri = g_strconcat ("file://", location, NULL);
|
||||||
g_free (location);
|
g_free (location);
|
||||||
|
|
Loading…
Reference in a new issue