1 /* Gstreamer Editing Services
3 * Copyright (C) <2012> Thibault Saunier <thibault.saunier@collabora.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
26 /* TODO Determine error codes numbers */
33 #include "ges-internal.h"
35 #define parent_class ges_xml_formatter_parent_class
37 #define MINOR_VERSION 5
40 #define COLLECT_STR_OPT (G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL)
42 #define _GET_PRIV(o) (((GESXmlFormatter*)o)->priv)
44 struct _GESXmlFormatterPrivate
47 gboolean project_opened;
51 GHashTable *element_id;
58 G_DEFINE_TYPE_WITH_PRIVATE (GESXmlFormatter, ges_xml_formatter,
59 GES_TYPE_BASE_XML_FORMATTER);
62 _parse_ges_element (GMarkupParseContext * context, const gchar * element_name,
63 const gchar ** attribute_names, const gchar ** attribute_values,
64 GESXmlFormatter * self, GError ** error)
67 const gchar *version, *properties;
69 gchar **split_version = NULL;
71 if (g_strcmp0 (element_name, "ges")) {
72 g_set_error (error, G_MARKUP_ERROR,
73 G_MARKUP_ERROR_INVALID_CONTENT,
74 "element '%s', Missing <ges> element'", element_name);
78 if (!g_markup_collect_attributes (element_name, attribute_names,
79 attribute_values, error, G_MARKUP_COLLECT_STRING, "version", &version,
80 COLLECT_STR_OPT, "properties", &properties,
81 G_MARKUP_COLLECT_INVALID)) {
85 split_version = g_strsplit (version, ".", 2);
86 if (split_version[1] == NULL)
90 api_version = g_ascii_strtoull (split_version[0], NULL, 10);
91 if (errno || api_version != API_VERSION)
94 self->priv->min_version = g_ascii_strtoull (split_version[1], NULL, 10);
95 if (self->priv->min_version > MINOR_VERSION)
98 _GET_PRIV (self)->ges_opened = TRUE;
99 g_strfreev (split_version);
103 g_set_error (error, G_MARKUP_ERROR,
104 G_MARKUP_ERROR_INVALID_CONTENT,
105 "element '%s', %s wrong version'", element_name, version);
107 g_strfreev (split_version);
112 GST_WARNING_OBJECT (self, "Error while strtoull: %s", g_strerror (errno));
117 _parse_project (GMarkupParseContext * context, const gchar * element_name,
118 const gchar ** attribute_names, const gchar ** attribute_values,
119 GESXmlFormatter * self, GError ** error)
121 const gchar *metadatas = NULL, *properties;
122 GESXmlFormatterPrivate *priv = _GET_PRIV (self);
124 if (g_strcmp0 (element_name, "project")) {
125 g_set_error (error, G_MARKUP_ERROR,
126 G_MARKUP_ERROR_INVALID_CONTENT,
127 "Found element '%s', Missing '<project>' element'", element_name);
129 priv->project_opened = TRUE;
130 if (!g_markup_collect_attributes (element_name, attribute_names,
131 attribute_values, error,
132 COLLECT_STR_OPT, "properties", &properties,
133 COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID))
136 if (GES_FORMATTER (self)->project && metadatas)
137 ges_meta_container_add_metas_from_string (GES_META_CONTAINER
138 (GES_FORMATTER (self)->project), metadatas);
144 _parse_encoding_profile (GMarkupParseContext * context,
145 const gchar * element_name, const gchar ** attribute_names,
146 const gchar ** attribute_values, GESXmlFormatter * self, GError ** error)
148 GstCaps *capsformat = NULL;
149 GstStructure *preset_properties = NULL;
150 const gchar *name, *description, *type, *preset = NULL,
151 *str_preset_properties = NULL, *preset_name = NULL, *format;
153 if (!g_markup_collect_attributes (element_name, attribute_names,
154 attribute_values, error,
155 G_MARKUP_COLLECT_STRING, "name", &name,
156 G_MARKUP_COLLECT_STRING, "description", &description,
157 G_MARKUP_COLLECT_STRING, "type", &type,
158 COLLECT_STR_OPT, "preset", &preset,
159 COLLECT_STR_OPT, "preset-properties", &str_preset_properties,
160 COLLECT_STR_OPT, "preset-name", &preset_name,
161 COLLECT_STR_OPT, "format", &format, G_MARKUP_COLLECT_INVALID))
165 capsformat = gst_caps_from_string (format);
167 if (str_preset_properties) {
168 preset_properties = gst_structure_from_string (str_preset_properties, NULL);
169 if (preset_properties == NULL) {
170 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
171 "element '%s', Wrong preset-properties format.", element_name);
176 ges_base_xml_formatter_add_encoding_profile (GES_BASE_XML_FORMATTER (self),
177 type, NULL, name, description, capsformat, preset, preset_properties,
178 preset_name, 0, 0, NULL, 0, FALSE, NULL, TRUE, error);
182 _parse_stream_profile (GMarkupParseContext * context,
183 const gchar * element_name, const gchar ** attribute_names,
184 const gchar ** attribute_values, GESXmlFormatter * self, GError ** error)
186 gboolean variableframerate = FALSE, enabled = TRUE;
187 guint id = 0, presence = 0, pass = 0;
188 GstCaps *format_caps = NULL, *restriction_caps = NULL;
189 GstStructure *preset_properties = NULL;
190 const gchar *parent, *strid, *type, *strpresence, *format = NULL,
191 *name = NULL, *description = NULL, *preset,
192 *str_preset_properties = NULL, *preset_name = NULL, *restriction = NULL,
193 *strpass = NULL, *strvariableframerate = NULL, *strenabled = NULL;
195 /* FIXME Looks like there is a bug in that function, if we put the parent
196 * at the beginning it set %NULL and not the real value... :/ */
197 if (!g_markup_collect_attributes (element_name, attribute_names,
198 attribute_values, error,
199 G_MARKUP_COLLECT_STRING, "id", &strid,
200 G_MARKUP_COLLECT_STRING, "type", &type,
201 G_MARKUP_COLLECT_STRING, "presence", &strpresence,
202 COLLECT_STR_OPT, "format", &format,
203 COLLECT_STR_OPT, "name", &name,
204 COLLECT_STR_OPT, "description", &description,
205 COLLECT_STR_OPT, "preset", &preset,
206 COLLECT_STR_OPT, "preset-properties", &str_preset_properties,
207 COLLECT_STR_OPT, "preset-name", &preset_name,
208 COLLECT_STR_OPT, "restriction", &restriction,
209 COLLECT_STR_OPT, "pass", &strpass,
210 COLLECT_STR_OPT, "variableframerate", &strvariableframerate,
211 COLLECT_STR_OPT, "enabled", &strenabled,
212 G_MARKUP_COLLECT_STRING, "parent", &parent, G_MARKUP_COLLECT_INVALID))
216 id = g_ascii_strtoll (strid, NULL, 10);
218 goto convertion_failed;
221 presence = g_ascii_strtoll (strpresence, NULL, 10);
223 goto convertion_failed;
226 if (str_preset_properties) {
227 preset_properties = gst_structure_from_string (str_preset_properties, NULL);
228 if (preset_properties == NULL)
229 goto convertion_failed;
233 pass = g_ascii_strtoll (strpass, NULL, 10);
235 goto convertion_failed;
238 if (strvariableframerate) {
239 variableframerate = g_ascii_strtoll (strvariableframerate, NULL, 10);
241 goto convertion_failed;
245 enabled = g_ascii_strtoll (strenabled, NULL, 10);
247 goto convertion_failed;
251 format_caps = gst_caps_from_string (format);
254 restriction_caps = gst_caps_from_string (restriction);
256 ges_base_xml_formatter_add_encoding_profile (GES_BASE_XML_FORMATTER (self),
257 type, parent, name, description, format_caps, preset, preset_properties,
258 preset_name, id, presence, restriction_caps, pass, variableframerate,
259 NULL, enabled, error);
261 if (preset_properties)
262 gst_structure_free (preset_properties);
267 g_set_error (error, G_MARKUP_ERROR,
268 G_MARKUP_ERROR_INVALID_CONTENT,
269 "element '%s', Wrong property type, error: %s'", element_name,
275 _parse_timeline (GMarkupParseContext * context, const gchar * element_name,
276 const gchar ** attribute_names, const gchar ** attribute_values,
277 GESXmlFormatter * self, GError ** error)
279 const gchar *metadatas = NULL, *properties = NULL;
280 GESTimeline *timeline = GES_FORMATTER (self)->timeline;
282 if (!g_markup_collect_attributes (element_name, attribute_names,
283 attribute_values, error,
284 COLLECT_STR_OPT, "properties", &properties,
285 COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID))
288 if (timeline == NULL)
291 ges_base_xml_formatter_set_timeline_properties (GES_BASE_XML_FORMATTER (self),
292 timeline, properties, metadatas);
296 _parse_asset (GMarkupParseContext * context, const gchar * element_name,
297 const gchar ** attribute_names, const gchar ** attribute_values,
298 GESXmlFormatter * self, GError ** error)
300 GType extractable_type;
301 const gchar *id, *extractable_type_name, *metadatas = NULL, *properties =
302 NULL, *proxy_id = NULL;
304 if (!g_markup_collect_attributes (element_name, attribute_names,
305 attribute_values, error, G_MARKUP_COLLECT_STRING, "id", &id,
306 G_MARKUP_COLLECT_STRING, "extractable-type-name",
307 &extractable_type_name,
308 COLLECT_STR_OPT, "properties", &properties,
309 COLLECT_STR_OPT, "metadatas", &metadatas,
310 COLLECT_STR_OPT, "proxy-id", &proxy_id, G_MARKUP_COLLECT_INVALID))
313 extractable_type = g_type_from_name (extractable_type_name);
314 if (extractable_type == G_TYPE_NONE)
315 g_set_error (error, G_MARKUP_ERROR,
316 G_MARKUP_ERROR_INVALID_CONTENT,
317 "element '%s' invalid extractable_type %s'",
318 element_name, extractable_type_name);
319 else if (!g_type_is_a (extractable_type, GES_TYPE_EXTRACTABLE))
320 g_set_error (error, G_MARKUP_ERROR,
321 G_MARKUP_ERROR_INVALID_CONTENT,
322 "element '%s', %s not an extractable_type'",
323 element_name, extractable_type_name);
325 GstStructure *props = NULL;
327 props = gst_structure_from_string (properties, NULL);
329 ges_base_xml_formatter_add_asset (GES_BASE_XML_FORMATTER (self), id,
330 extractable_type, props, metadatas, proxy_id, error);
332 gst_structure_free (props);
338 _parse_track (GMarkupParseContext * context, const gchar * element_name,
339 const gchar ** attribute_names, const gchar ** attribute_values,
340 GESXmlFormatter * self, GError ** error)
343 GESTrackType track_type;
344 GstStructure *props = NULL;
345 const gchar *strtrack_type, *strcaps, *strtrack_id, *metadatas =
346 NULL, *properties = NULL;
348 if (!g_markup_collect_attributes (element_name, attribute_names,
349 attribute_values, error,
350 G_MARKUP_COLLECT_STRING, "track-type", &strtrack_type,
351 G_MARKUP_COLLECT_STRING, "track-id", &strtrack_id,
352 COLLECT_STR_OPT, "properties", &properties,
353 COLLECT_STR_OPT, "metadatas", &metadatas,
354 G_MARKUP_COLLECT_STRING, "caps", &strcaps, G_MARKUP_COLLECT_INVALID))
357 if ((caps = gst_caps_from_string (strcaps)) == NULL)
361 track_type = g_ascii_strtoll (strtrack_type, NULL, 10);
363 goto convertion_failed;
366 props = gst_structure_from_string (properties, NULL);
369 ges_base_xml_formatter_add_track (GES_BASE_XML_FORMATTER (self), track_type,
370 caps, strtrack_id, props, metadatas, error);
373 gst_structure_free (props);
375 gst_caps_unref (caps);
380 g_set_error (error, G_MARKUP_ERROR,
381 G_MARKUP_ERROR_INVALID_CONTENT,
382 "element '%s', Can not create caps: %s'", element_name, strcaps);
386 gst_caps_unref (caps);
387 g_set_error (error, G_MARKUP_ERROR,
388 G_MARKUP_ERROR_INVALID_CONTENT,
389 "element '%s', Wrong property type, error: %s'", element_name,
396 _parse_layer (GMarkupParseContext * context, const gchar * element_name,
397 const gchar ** attribute_names, const gchar ** attribute_values,
398 GESXmlFormatter * self, GError ** error)
400 GstStructure *props = NULL;
402 GType extractable_type = G_TYPE_NONE;
403 const gchar *metadatas = NULL, *properties = NULL, *strprio = NULL,
404 *extractable_type_name;
406 if (!g_markup_collect_attributes (element_name, attribute_names,
407 attribute_values, error,
408 G_MARKUP_COLLECT_STRING, "priority", &strprio,
409 COLLECT_STR_OPT, "extractable-type-name", &extractable_type_name,
410 COLLECT_STR_OPT, "properties", &properties,
411 COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID))
414 if (extractable_type_name) {
415 extractable_type = g_type_from_name (extractable_type_name);
416 if (extractable_type == G_TYPE_NONE) {
417 g_set_error (error, G_MARKUP_ERROR,
418 G_MARKUP_ERROR_INVALID_CONTENT,
419 "element '%s' invalid extractable_type %s'",
420 element_name, extractable_type_name);
423 } else if (!g_type_is_a (extractable_type, GES_TYPE_EXTRACTABLE)) {
424 g_set_error (error, G_MARKUP_ERROR,
425 G_MARKUP_ERROR_INVALID_CONTENT,
426 "element '%s', %s not an extractable_type'",
427 element_name, extractable_type_name);
434 props = gst_structure_from_string (properties, NULL);
436 goto wrong_properties;
440 priority = g_ascii_strtoll (strprio, NULL, 10);
442 goto convertion_failed;
444 ges_base_xml_formatter_add_layer (GES_BASE_XML_FORMATTER (self),
445 extractable_type, priority, props, metadatas, error);
449 gst_structure_free (props);
454 g_set_error (error, G_MARKUP_ERROR,
455 G_MARKUP_ERROR_INVALID_CONTENT,
456 "element '%s', Wrong property type, error: %s'", element_name,
461 g_set_error (error, G_MARKUP_ERROR,
462 G_MARKUP_ERROR_INVALID_CONTENT,
463 "element '%s', wrong layer properties '%s', could no be deserialized",
464 element_name, properties);
468 _parse_clip (GMarkupParseContext * context,
469 const gchar * element_name, const gchar ** attribute_names,
470 const gchar ** attribute_values, GESXmlFormatter * self, GError ** error)
473 GstStructure *props = NULL, *children_props = NULL;
474 GESTrackType track_types;
475 GstClockTime start, inpoint = 0, duration, layer_prio;
477 const gchar *strid, *asset_id, *strstart, *strin, *strduration, *strrate,
478 *strtrack_types, *strtype, *metadatas = NULL, *properties =
479 NULL, *children_properties = NULL, *strlayer_prio;
481 if (!g_markup_collect_attributes (element_name, attribute_names,
482 attribute_values, error,
483 G_MARKUP_COLLECT_STRING, "id", &strid,
484 G_MARKUP_COLLECT_STRING, "type-name", &strtype,
485 G_MARKUP_COLLECT_STRING, "start", &strstart,
486 G_MARKUP_COLLECT_STRING, "duration", &strduration,
487 G_MARKUP_COLLECT_STRING, "asset-id", &asset_id,
488 G_MARKUP_COLLECT_STRING, "track-types", &strtrack_types,
489 G_MARKUP_COLLECT_STRING, "layer-priority", &strlayer_prio,
490 COLLECT_STR_OPT, "properties", &properties,
491 COLLECT_STR_OPT, "children-properties", &children_properties,
492 COLLECT_STR_OPT, "metadatas", &metadatas,
493 COLLECT_STR_OPT, "rate", &strrate,
494 COLLECT_STR_OPT, "inpoint", &strin, G_MARKUP_COLLECT_INVALID)) {
497 type = g_type_from_name (strtype);
498 if (!g_type_is_a (type, GES_TYPE_CLIP))
502 track_types = g_ascii_strtoll (strtrack_types, NULL, 10);
504 goto convertion_failed;
506 layer_prio = g_ascii_strtoll (strlayer_prio, NULL, 10);
508 goto convertion_failed;
511 inpoint = g_ascii_strtoull (strin, NULL, 10);
513 goto convertion_failed;
516 start = g_ascii_strtoull (strstart, NULL, 10);
518 goto convertion_failed;
520 duration = g_ascii_strtoull (strduration, NULL, 10);
522 goto convertion_failed;
525 props = gst_structure_from_string (properties, NULL);
527 goto wrong_properties;
530 if (children_properties) {
531 children_props = gst_structure_from_string (children_properties, NULL);
532 if (children_props == NULL)
533 goto wrong_children_properties;
536 ges_base_xml_formatter_add_clip (GES_BASE_XML_FORMATTER (self),
537 strid, asset_id, type, start, inpoint, duration, layer_prio,
538 track_types, props, children_props, metadatas, error);
540 gst_structure_free (props);
545 g_set_error (error, G_MARKUP_ERROR,
546 G_MARKUP_ERROR_INVALID_CONTENT,
547 "element '%s', Clip %s properties '%s', could no be deserialized",
548 element_name, asset_id, properties);
551 wrong_children_properties:
552 g_set_error (error, G_MARKUP_ERROR,
553 G_MARKUP_ERROR_INVALID_CONTENT,
554 "element '%s', Clip %s children properties '%s', could no be deserialized",
555 element_name, asset_id, children_properties);
559 g_set_error (error, G_MARKUP_ERROR,
560 G_MARKUP_ERROR_INVALID_CONTENT,
561 "element '%s', Wrong property type, error: %s'", element_name,
566 g_set_error (error, G_MARKUP_ERROR,
567 G_MARKUP_ERROR_INVALID_CONTENT,
568 "element '%s', %s not a GESClip'", element_name, strtype);
572 _parse_binding (GMarkupParseContext * context, const gchar * element_name,
573 const gchar ** attribute_names, const gchar ** attribute_values,
574 GESXmlFormatter * self, GError ** error)
576 const gchar *type = NULL, *source_type = NULL, *timed_values =
577 NULL, *property_name = NULL, *mode = NULL, *track_id = NULL;
578 gchar **pairs, **tmp;
582 if (!g_markup_collect_attributes (element_name, attribute_names,
583 attribute_values, error,
584 G_MARKUP_COLLECT_STRING, "type", &type,
585 G_MARKUP_COLLECT_STRING, "source_type", &source_type,
586 G_MARKUP_COLLECT_STRING, "property", &property_name,
587 G_MARKUP_COLLECT_STRING, "mode", &mode,
588 G_MARKUP_COLLECT_STRING, "track_id", &track_id,
589 G_MARKUP_COLLECT_STRING, "values", &timed_values,
590 G_MARKUP_COLLECT_INVALID)) {
594 pairs = g_strsplit (timed_values, " ", 0);
595 for (tmp = pairs; tmp != NULL; tmp += 1) {
602 GstTimedValue *value;
604 value = g_slice_new (GstTimedValue);
605 value_pair = g_strsplit (pair, ":", 0);
606 value->timestamp = g_ascii_strtoull (value_pair[0], NULL, 10);
607 value->value = g_ascii_strtod (value_pair[1], NULL);
608 list = g_slist_append (list, value);
609 g_strfreev (value_pair);
615 ges_base_xml_formatter_add_control_binding (GES_BASE_XML_FORMATTER (self),
618 property_name, (gint) g_ascii_strtoll (mode, NULL, 10), track_id, list);
622 _parse_source (GMarkupParseContext * context, const gchar * element_name,
623 const gchar ** attribute_names, const gchar ** attribute_values,
624 GESXmlFormatter * self, GError ** error)
626 GstStructure *children_props = NULL;
627 const gchar *track_id = NULL, *children_properties = NULL;
629 if (!g_markup_collect_attributes (element_name, attribute_names,
630 attribute_values, error,
631 G_MARKUP_COLLECT_STRING, "track-id", &track_id,
632 COLLECT_STR_OPT, "children-properties", &children_properties,
633 G_MARKUP_COLLECT_INVALID)) {
637 if (children_properties) {
638 children_props = gst_structure_from_string (children_properties, NULL);
639 if (children_props == NULL)
640 goto wrong_children_properties;
643 ges_base_xml_formatter_add_source (GES_BASE_XML_FORMATTER (self), track_id,
647 gst_structure_free (children_props);
651 wrong_children_properties:
652 g_set_error (error, G_MARKUP_ERROR,
653 G_MARKUP_ERROR_INVALID_CONTENT,
654 "element '%s', children properties '%s', could no be deserialized",
655 element_name, children_properties);
659 _parse_effect (GMarkupParseContext * context, const gchar * element_name,
660 const gchar ** attribute_names, const gchar ** attribute_values,
661 GESXmlFormatter * self, GError ** error)
665 GstStructure *children_props = NULL, *props = NULL;
666 const gchar *asset_id = NULL, *strtype = NULL, *track_id =
667 NULL, *metadatas = NULL, *properties = NULL, *track_type = NULL,
668 *children_properties = NULL, *clip_id;
670 if (!g_markup_collect_attributes (element_name, attribute_names,
671 attribute_values, error,
672 COLLECT_STR_OPT, "metadatas", &metadatas,
673 G_MARKUP_COLLECT_STRING, "asset-id", &asset_id,
674 G_MARKUP_COLLECT_STRING, "clip-id", &clip_id,
675 G_MARKUP_COLLECT_STRING, "type-name", &strtype,
676 G_MARKUP_COLLECT_STRING, "track-id", &track_id,
677 COLLECT_STR_OPT, "children-properties", &children_properties,
678 COLLECT_STR_OPT, "track-type", &track_type,
679 COLLECT_STR_OPT, "properties", &properties,
680 G_MARKUP_COLLECT_INVALID)) {
684 type = g_type_from_name (strtype);
685 if (!g_type_is_a (type, GES_TYPE_BASE_EFFECT))
688 if (children_properties) {
689 children_props = gst_structure_from_string (children_properties, NULL);
690 if (children_props == NULL)
691 goto wrong_children_properties;
695 props = gst_structure_from_string (properties, NULL);
697 goto wrong_properties;
700 ges_base_xml_formatter_add_track_element (GES_BASE_XML_FORMATTER (self),
701 type, asset_id, track_id, clip_id, children_props, props, metadatas,
707 gst_structure_free (props);
709 gst_structure_free (children_props);
714 g_set_error (error, G_MARKUP_ERROR,
715 G_MARKUP_ERROR_INVALID_CONTENT,
716 "element '%s', Effect %s properties '%s', could no be deserialized",
717 element_name, asset_id, properties);
720 wrong_children_properties:
721 g_set_error (error, G_MARKUP_ERROR,
722 G_MARKUP_ERROR_INVALID_CONTENT,
723 "element '%s', Effect %s children properties '%s', could no be deserialized",
724 element_name, asset_id, children_properties);
728 g_set_error (error, G_MARKUP_ERROR,
729 G_MARKUP_ERROR_INVALID_CONTENT,
730 "element '%s', %s not a GESBaseEffect'", element_name, strtype);
735 _parse_group (GMarkupParseContext * context, const gchar * element_name,
736 const gchar ** attribute_names, const gchar ** attribute_values,
737 GESXmlFormatter * self, GError ** error)
739 const gchar *id, *properties, *metadatas = NULL;
741 if (!g_markup_collect_attributes (element_name, attribute_names,
742 attribute_values, error,
743 G_MARKUP_COLLECT_STRING, "id", &id,
744 G_MARKUP_COLLECT_STRING, "properties", &properties,
745 COLLECT_STR_OPT, "metadatas", &metadatas, G_MARKUP_COLLECT_INVALID)) {
749 ges_base_xml_formatter_add_group (GES_BASE_XML_FORMATTER (self), id,
750 properties, metadatas);
754 _parse_group_child (GMarkupParseContext * context, const gchar * element_name,
755 const gchar ** attribute_names, const gchar ** attribute_values,
756 GESXmlFormatter * self, GError ** error)
758 const gchar *child_id, *name;
760 if (!g_markup_collect_attributes (element_name, attribute_names,
761 attribute_values, error,
762 G_MARKUP_COLLECT_STRING, "id", &child_id,
763 G_MARKUP_COLLECT_STRING, "name", &name, G_MARKUP_COLLECT_INVALID)) {
767 ges_base_xml_formatter_last_group_add_child (GES_BASE_XML_FORMATTER (self),
772 _parse_element_start (GMarkupParseContext * context, const gchar * element_name,
773 const gchar ** attribute_names, const gchar ** attribute_values,
774 gpointer self, GError ** error)
776 GESXmlFormatterPrivate *priv = _GET_PRIV (self);
778 if (!G_UNLIKELY (priv->ges_opened))
779 _parse_ges_element (context, element_name, attribute_names,
780 attribute_values, self, error);
781 else if (!G_UNLIKELY (priv->project_opened))
782 _parse_project (context, element_name, attribute_names, attribute_values,
784 else if (g_strcmp0 (element_name, "encoding-profile") == 0)
785 _parse_encoding_profile (context, element_name, attribute_names,
786 attribute_values, self, error);
787 else if (g_strcmp0 (element_name, "stream-profile") == 0)
788 _parse_stream_profile (context, element_name, attribute_names,
789 attribute_values, self, error);
790 else if (g_strcmp0 (element_name, "timeline") == 0)
791 _parse_timeline (context, element_name, attribute_names, attribute_values,
793 else if (g_strcmp0 (element_name, "asset") == 0)
794 _parse_asset (context, element_name, attribute_names, attribute_values,
796 else if (g_strcmp0 (element_name, "track") == 0)
797 _parse_track (context, element_name, attribute_names,
798 attribute_values, self, error);
799 else if (g_strcmp0 (element_name, "layer") == 0)
800 _parse_layer (context, element_name, attribute_names,
801 attribute_values, self, error);
802 else if (g_strcmp0 (element_name, "clip") == 0)
803 _parse_clip (context, element_name, attribute_names,
804 attribute_values, self, error);
805 else if (g_strcmp0 (element_name, "source") == 0)
806 _parse_source (context, element_name, attribute_names,
807 attribute_values, self, error);
808 else if (g_strcmp0 (element_name, "effect") == 0)
809 _parse_effect (context, element_name, attribute_names,
810 attribute_values, self, error);
811 else if (g_strcmp0 (element_name, "binding") == 0)
812 _parse_binding (context, element_name, attribute_names,
813 attribute_values, self, error);
814 else if (g_strcmp0 (element_name, "group") == 0)
815 _parse_group (context, element_name, attribute_names,
816 attribute_values, self, error);
817 else if (g_strcmp0 (element_name, "child") == 0)
818 _parse_group_child (context, element_name, attribute_names,
819 attribute_values, self, error);
821 GST_LOG_OBJECT (self, "Element %s not handled", element_name);
825 _parse_element_end (GMarkupParseContext * context,
826 const gchar * element_name, gpointer self, GError ** error)
828 /*GESXmlFormatterPrivate *priv = _GET_PRIV (self); */
829 if (g_strcmp0 (element_name, "ges") == 0 && GES_FORMATTER (self)->project) {
830 gchar *version = g_strdup_printf ("%d.%d",
831 API_VERSION, GES_XML_FORMATTER (self)->priv->min_version);
833 ges_meta_container_set_string (GES_META_CONTAINER (GES_FORMATTER
834 (self)->project), GES_META_FORMAT_VERSION, version);
841 _error_parsing (GMarkupParseContext * context, GError * error,
844 GST_WARNING ("Error occurred when parsing %s", error->message);
847 /***********************************************
849 * Saving implementation *
851 ***********************************************/
853 /* XML writting utils */
855 append_escaped (GString * str, gchar * tmpstr)
857 g_string_append (str, tmpstr);
861 static inline gboolean
862 _can_serialize_spec (GParamSpec * spec)
864 if (!(spec->flags & G_PARAM_WRITABLE)) {
865 GST_DEBUG ("%s from %s is not writable",
866 spec->name, g_type_name (spec->owner_type));
869 } else if (spec->flags & G_PARAM_CONSTRUCT_ONLY) {
870 GST_DEBUG ("%s from %s is construct only",
871 spec->name, g_type_name (spec->owner_type));
874 } else if (spec->flags & GES_PARAM_NO_SERIALIZATION &&
875 g_type_is_a (spec->owner_type, GES_TYPE_TIMELINE_ELEMENT)) {
876 GST_DEBUG ("%s from %s is set as GES_PARAM_NO_SERIALIZATION",
877 spec->name, g_type_name (spec->owner_type));
880 } else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (spec), G_TYPE_OBJECT)) {
881 GST_DEBUG ("%s from %s contains GObject, can't serialize that.",
882 spec->name, g_type_name (spec->owner_type));
885 } else if ((g_type_is_a (spec->owner_type, GST_TYPE_OBJECT) &&
886 !g_strcmp0 (spec->name, "name"))) {
888 GST_DEBUG ("We do not want to serialize the name of GstObjects.");
890 } else if (G_PARAM_SPEC_VALUE_TYPE (spec) == G_TYPE_GTYPE) {
891 GST_DEBUG ("%s from %s contains a GType, can't serialize.",
892 spec->name, g_type_name (spec->owner_type));
900 _init_value_from_spec_for_serialization (GValue * value, GParamSpec * spec)
903 if (g_type_is_a (spec->value_type, G_TYPE_ENUM) ||
904 g_type_is_a (spec->value_type, G_TYPE_FLAGS))
905 g_value_init (value, G_TYPE_INT);
907 g_value_init (value, spec->value_type);
911 _serialize_properties (GObject * object, const gchar * fieldname, ...)
915 GParamSpec *spec, **pspecs;
916 GObjectClass *class = G_OBJECT_GET_CLASS (object);
917 GstStructure *structure = gst_structure_new_empty ("properties");
919 pspecs = g_object_class_list_properties (class, &n_props);
920 for (j = 0; j < n_props; j++) {
924 if (spec->value_type == GST_TYPE_CAPS) {
928 g_object_get (object, spec->name, &caps, NULL);
929 caps_str = gst_caps_to_string (caps);
930 gst_structure_set (structure, spec->name, G_TYPE_STRING, caps_str, NULL);
932 gst_caps_unref (caps);
934 } else if (_can_serialize_spec (spec)) {
935 _init_value_from_spec_for_serialization (&val, spec);
936 g_object_get_property (object, spec->name, &val);
937 gst_structure_set_value (structure, spec->name, &val);
938 g_value_unset (&val);
945 va_start (varargs, fieldname);
946 gst_structure_remove_fields_valist (structure, fieldname, varargs);
950 ret = gst_structure_to_string (structure);
951 gst_structure_free (structure);
957 _save_assets (GESXmlFormatter * self, GString * str, GESProject * project)
959 char *properties, *metas;
960 GESAsset *asset, *proxy;
963 assets = ges_project_list_assets (project, GES_TYPE_EXTRACTABLE);
964 for (tmp = assets; tmp; tmp = tmp->next) {
965 asset = GES_ASSET (tmp->data);
966 properties = _serialize_properties (G_OBJECT (asset), NULL);
967 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (asset));
969 g_markup_printf_escaped
970 (" <asset id='%s' extractable-type-name='%s' properties='%s' metadatas='%s' ",
971 ges_asset_get_id (asset),
972 g_type_name (ges_asset_get_extractable_type (asset)), properties,
975 /*TODO Save the whole list of proxies */
976 proxy = ges_asset_get_proxy (asset);
978 append_escaped (str, g_markup_printf_escaped (" proxy-id='%s' ",
979 ges_asset_get_id (proxy)));
981 if (!g_list_find (assets, proxy)) {
982 assets = g_list_append (assets, gst_object_ref (proxy));
985 tmp->next = g_list_last (assets);
988 self->priv->min_version = MAX (self->priv->min_version, 3);
990 g_string_append (str, "/>\n");
994 g_list_free_full (assets, gst_object_unref);
998 _save_tracks (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
1000 gchar *strtmp, *metas;
1002 GList *tmp, *tracks;
1005 guint nb_tracks = 0;
1007 tracks = ges_timeline_get_tracks (timeline);
1008 for (tmp = tracks; tmp; tmp = tmp->next) {
1009 track = GES_TRACK (tmp->data);
1010 properties = _serialize_properties (G_OBJECT (track), NULL);
1011 strtmp = gst_caps_to_string (ges_track_get_caps (track));
1012 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (track));
1013 append_escaped (str,
1014 g_markup_printf_escaped
1015 (" <track caps='%s' track-type='%i' track-id='%i' properties='%s' metadatas='%s'/>\n",
1016 strtmp, track->type, nb_tracks++, properties, metas));
1019 g_free (properties);
1021 g_list_free_full (tracks, gst_object_unref);
1025 _save_children_properties (GString * str, GESTimelineElement * element)
1027 GstStructure *structure;
1028 GParamSpec **pspecs, *spec;
1032 pspecs = ges_timeline_element_list_children_properties (element, &n_props);
1034 structure = gst_structure_new_empty ("properties");
1035 for (i = 0; i < n_props; i++) {
1039 if (_can_serialize_spec (spec)) {
1041 g_strdup_printf ("%s::%s", g_type_name (spec->owner_type),
1044 _init_value_from_spec_for_serialization (&val, spec);
1045 ges_timeline_element_get_child_property_by_pspec (element, spec, &val);
1046 gst_structure_set_value (structure, spec_name, &val);
1049 g_value_unset (&val);
1051 g_param_spec_unref (spec);
1055 struct_str = gst_structure_to_string (structure);
1056 append_escaped (str,
1057 g_markup_printf_escaped (" children-properties='%s'", struct_str));
1058 gst_structure_free (structure);
1059 g_free (struct_str);
1062 /* TODO : Use this function for every track element with controllable properties */
1064 _save_keyframes (GString * str, GESTrackElement * trackelement, gint index)
1066 GHashTable *bindings_hashtable;
1067 GHashTableIter iter;
1068 gpointer key, value;
1070 bindings_hashtable =
1071 ges_track_element_get_all_control_bindings (trackelement);
1073 g_hash_table_iter_init (&iter, bindings_hashtable);
1075 /* We iterate over the bindings, and save the timed values */
1076 while (g_hash_table_iter_next (&iter, &key, &value)) {
1077 if (GST_IS_DIRECT_CONTROL_BINDING ((GstControlBinding *) value)) {
1078 GstControlSource *source;
1079 gboolean absolute = FALSE;
1080 GstDirectControlBinding *binding;
1082 binding = (GstDirectControlBinding *) value;
1084 g_object_get (binding, "control-source", &source,
1085 "absolute", &absolute, NULL);
1087 if (GST_IS_INTERPOLATION_CONTROL_SOURCE (source)) {
1088 GList *timed_values, *tmp;
1089 GstInterpolationMode mode;
1091 append_escaped (str,
1092 g_markup_printf_escaped
1093 (" <binding type='%s' source_type='interpolation' property='%s'",
1094 absolute ? "direct-absolute" : "direct", (gchar *) key));
1096 g_object_get (source, "mode", &mode, NULL);
1097 append_escaped (str, g_markup_printf_escaped (" mode='%d'", mode));
1098 append_escaped (str, g_markup_printf_escaped (" track_id='%d'", index));
1099 append_escaped (str, g_markup_printf_escaped (" values ='"));
1101 gst_timed_value_control_source_get_all
1102 (GST_TIMED_VALUE_CONTROL_SOURCE (source));
1103 for (tmp = timed_values; tmp; tmp = tmp->next) {
1104 gchar strbuf[G_ASCII_DTOSTR_BUF_SIZE];
1105 GstTimedValue *value;
1107 value = (GstTimedValue *) tmp->data;
1108 append_escaped (str, g_markup_printf_escaped (" %" G_GUINT64_FORMAT
1109 ":%s ", value->timestamp, g_ascii_dtostr (strbuf,
1110 G_ASCII_DTOSTR_BUF_SIZE, value->value)));
1112 append_escaped (str, g_markup_printf_escaped ("'/>\n"));
1114 GST_DEBUG ("control source not in [interpolation]");
1116 GST_DEBUG ("Binding type not in [direct, direct-absolute]");
1121 _save_effect (GString * str, guint clip_id, GESTrackElement * trackelement,
1122 GESTimeline * timeline)
1125 GList *tmp, *tracks;
1126 gchar *properties, *metas;
1129 gchar *extractable_id;
1131 g_object_get (trackelement, "serialize", &serialize, NULL);
1134 GST_DEBUG_OBJECT (trackelement, "Should not be serialized");
1139 tck = ges_track_element_get_track (trackelement);
1141 GST_WARNING_OBJECT (trackelement, " Not in any track, can not save it");
1146 tracks = ges_timeline_get_tracks (timeline);
1147 for (tmp = tracks; tmp; tmp = tmp->next) {
1148 if (tmp->data == tck)
1152 g_list_free_full (tracks, gst_object_unref);
1154 properties = _serialize_properties (G_OBJECT (trackelement), "start",
1155 "in-point", "duration", "locked", "max-duration", "name", "priority",
1158 ges_meta_container_metas_to_string (GES_META_CONTAINER (trackelement));
1159 extractable_id = ges_extractable_get_id (GES_EXTRACTABLE (trackelement));
1160 append_escaped (str,
1161 g_markup_printf_escaped (" <effect asset-id='%s' clip-id='%u'"
1162 " type-name='%s' track-type='%i' track-id='%i' properties='%s' metadatas='%s'",
1163 extractable_id, clip_id,
1164 g_type_name (G_OBJECT_TYPE (trackelement)), tck->type, track_id,
1165 properties, metas));
1166 g_free (extractable_id);
1167 g_free (properties);
1170 _save_children_properties (str, GES_TIMELINE_ELEMENT (trackelement));
1171 append_escaped (str, g_markup_printf_escaped (">\n"));
1173 _save_keyframes (str, trackelement, -1);
1175 append_escaped (str, g_markup_printf_escaped (" </effect>\n"));
1179 _save_layers (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
1181 gchar *properties, *metas;
1184 GList *tmplayer, *tmpclip, *clips;
1185 GESXmlFormatterPrivate *priv = self->priv;
1187 for (tmplayer = timeline->layers; tmplayer; tmplayer = tmplayer->next) {
1189 layer = GES_LAYER (tmplayer->data);
1191 priority = ges_layer_get_priority (layer);
1192 properties = _serialize_properties (G_OBJECT (layer), "priority", NULL);
1193 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (layer));
1194 append_escaped (str,
1195 g_markup_printf_escaped
1196 (" <layer priority='%i' properties='%s' metadatas='%s'>\n",
1197 priority, properties, metas));
1198 g_free (properties);
1201 clips = ges_layer_get_clips (layer);
1202 for (tmpclip = clips; tmpclip; tmpclip = tmpclip->next) {
1203 GList *effects, *tmpeffect;
1204 GList *tmptrackelement;
1207 gchar *extractable_id;
1209 clip = GES_CLIP (tmpclip->data);
1211 g_object_get (clip, "serialize", &serialize, NULL);
1213 GST_DEBUG_OBJECT (clip, "Should not be serialized");
1217 /* We escape all mandatrorry properties that are handled sparetely
1218 * and vtype for StandarTransition as it is the asset ID */
1219 properties = _serialize_properties (G_OBJECT (clip),
1220 "supported-formats", "rate", "in-point", "start", "duration",
1221 "max-duration", "priority", "vtype", "uri", NULL);
1222 extractable_id = ges_extractable_get_id (GES_EXTRACTABLE (clip));
1223 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (clip));
1224 append_escaped (str,
1225 g_markup_printf_escaped (" <clip id='%i' asset-id='%s'"
1226 " type-name='%s' layer-priority='%i' track-types='%i' start='%"
1227 G_GUINT64_FORMAT "' duration='%" G_GUINT64_FORMAT "' inpoint='%"
1228 G_GUINT64_FORMAT "' rate='%d' properties='%s' metadatas='%s'",
1229 priv->nbelements, extractable_id,
1230 g_type_name (G_OBJECT_TYPE (clip)), priority,
1231 ges_clip_get_supported_formats (clip), _START (clip),
1232 _DURATION (clip), _INPOINT (clip), 0, properties, metas));
1235 if (GES_IS_TRANSITION_CLIP (clip)) {
1236 _save_children_properties (str, GES_TIMELINE_ELEMENT (clip));
1237 self->priv->min_version = MAX (self->priv->min_version, 4);
1239 g_string_append (str, ">\n");
1241 g_free (extractable_id);
1242 g_free (properties);
1244 g_hash_table_insert (self->priv->element_id, clip,
1245 GINT_TO_POINTER (priv->nbelements));
1248 /* Effects must always be serialized in the right priority order.
1249 * List order is guaranteed by the fact that ges_clip_get_top_effects
1250 * sorts the effects. */
1251 effects = ges_clip_get_top_effects (clip);
1252 for (tmpeffect = effects; tmpeffect; tmpeffect = tmpeffect->next) {
1253 _save_effect (str, priv->nbelements,
1254 GES_TRACK_ELEMENT (tmpeffect->data), timeline);
1256 g_list_free (effects);
1257 tracks = ges_timeline_get_tracks (timeline);
1259 for (tmptrackelement = GES_CONTAINER_CHILDREN (clip); tmptrackelement;
1260 tmptrackelement = tmptrackelement->next) {
1264 if (!GES_IS_SOURCE (tmptrackelement->data))
1267 g_object_get (tmptrackelement->data, "serialize", &serialize, NULL);
1269 GST_DEBUG_OBJECT (tmptrackelement->data, "Should not be serialized");
1274 g_list_index (tracks,
1275 ges_track_element_get_track (tmptrackelement->data));
1276 append_escaped (str,
1277 g_markup_printf_escaped (" <source track-id='%i'", index));
1278 _save_children_properties (str, tmptrackelement->data);
1279 append_escaped (str, g_markup_printf_escaped (">\n"));
1280 _save_keyframes (str, tmptrackelement->data, index);
1281 append_escaped (str, g_markup_printf_escaped (" </source>\n"));
1284 g_list_free_full (tracks, gst_object_unref);
1286 g_string_append (str, " </clip>\n");
1290 g_list_free_full (clips, (GDestroyNotify) gst_object_unref);
1291 g_string_append (str, " </layer>\n");
1296 _save_group (GESXmlFormatter * self, GString * str, GList ** seen_groups,
1301 gchar *properties, *metadatas;
1303 g_object_get (group, "serialize", &serialize, NULL);
1306 GST_DEBUG_OBJECT (group, "Should not be serialized");
1311 if (g_list_find (*seen_groups, group)) {
1312 GST_DEBUG_OBJECT (group, "Already serialized");
1317 *seen_groups = g_list_prepend (*seen_groups, group);
1318 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
1319 if (GES_IS_GROUP (tmp->data)) {
1320 _save_group (self, str, seen_groups,
1321 GES_GROUP (GES_TIMELINE_ELEMENT (tmp->data)));
1325 properties = _serialize_properties (G_OBJECT (group), NULL);
1327 metadatas = ges_meta_container_metas_to_string (GES_META_CONTAINER (group));
1328 self->priv->min_version = MAX (self->priv->min_version, 5);
1330 g_string_append_printf (str,
1331 " <group id='%d' properties='%s' metadatas='%s'>\n",
1332 self->priv->nbelements, properties, metadatas);
1333 g_free (properties);
1335 g_hash_table_insert (self->priv->element_id, group,
1336 GINT_TO_POINTER (self->priv->nbelements));
1337 self->priv->nbelements++;
1339 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
1340 gint id = GPOINTER_TO_INT (g_hash_table_lookup (self->priv->element_id,
1343 g_string_append_printf (str, " <child id='%d' name='%s'/>\n", id,
1344 GES_TIMELINE_ELEMENT_NAME (tmp->data));
1346 g_string_append (str, " </group>\n");
1350 _save_groups (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
1353 GList *seen_groups = NULL;
1355 g_string_append (str, " <groups>\n");
1356 for (tmp = ges_timeline_get_groups (timeline); tmp; tmp = tmp->next) {
1357 _save_group (self, str, &seen_groups, tmp->data);
1359 g_list_free (seen_groups);
1360 g_string_append (str, " </groups>\n");
1364 _save_timeline (GESXmlFormatter * self, GString * str, GESTimeline * timeline)
1366 gchar *properties = NULL, *metas = NULL;
1368 properties = _serialize_properties (G_OBJECT (timeline), "update", "name",
1369 "async-handling", "message-forward", NULL);
1371 ges_meta_container_set_uint64 (GES_META_CONTAINER (timeline), "duration",
1372 ges_timeline_get_duration (timeline));
1373 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (timeline));
1374 append_escaped (str,
1375 g_markup_printf_escaped
1376 (" <timeline properties='%s' metadatas='%s'>\n", properties, metas));
1378 _save_tracks (self, str, timeline);
1379 _save_layers (self, str, timeline);
1380 _save_groups (self, str, timeline);
1382 g_string_append (str, " </timeline>\n");
1384 g_free (properties);
1389 _save_stream_profiles (GESXmlFormatter * self, GString * str,
1390 GstEncodingProfile * sprof, const gchar * profilename, guint id)
1394 const gchar *preset, *preset_name, *name, *description;
1396 append_escaped (str,
1397 g_markup_printf_escaped
1398 (" <stream-profile parent='%s' id='%d' type='%s' "
1399 "presence='%d' ", profilename, id,
1400 gst_encoding_profile_get_type_nick (sprof),
1401 gst_encoding_profile_get_presence (sprof)));
1403 if (!gst_encoding_profile_is_enabled (sprof)) {
1404 append_escaped (str, g_strdup ("enabled='0' "));
1406 self->priv->min_version = MAX (self->priv->min_version, 2);
1409 tmpcaps = gst_encoding_profile_get_format (sprof);
1411 tmpc = gst_caps_to_string (tmpcaps);
1412 append_escaped (str, g_markup_printf_escaped ("format='%s' ", tmpc));
1413 gst_caps_unref (tmpcaps);
1417 name = gst_encoding_profile_get_name (sprof);
1419 append_escaped (str, g_markup_printf_escaped ("name='%s' ", name));
1421 description = gst_encoding_profile_get_description (sprof);
1423 append_escaped (str, g_markup_printf_escaped ("description='%s' ",
1426 preset = gst_encoding_profile_get_preset (sprof);
1428 GstElement *encoder;
1430 append_escaped (str, g_markup_printf_escaped ("preset='%s' ", preset));
1432 encoder = get_element_for_encoding_profile (sprof,
1433 GST_ELEMENT_FACTORY_TYPE_ENCODER);
1435 if (GST_IS_PRESET (encoder) &&
1436 gst_preset_load_preset (GST_PRESET (encoder), preset)) {
1438 gchar *settings = _serialize_properties (G_OBJECT (encoder), NULL);
1439 append_escaped (str,
1440 g_markup_printf_escaped ("preset-properties='%s' ", settings));
1443 gst_object_unref (encoder);
1447 preset_name = gst_encoding_profile_get_preset_name (sprof);
1449 append_escaped (str, g_markup_printf_escaped ("preset-name='%s' ",
1452 tmpcaps = gst_encoding_profile_get_restriction (sprof);
1454 tmpc = gst_caps_to_string (tmpcaps);
1455 append_escaped (str, g_markup_printf_escaped ("restriction='%s' ", tmpc));
1456 gst_caps_unref (tmpcaps);
1460 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
1461 GstEncodingVideoProfile *vp = (GstEncodingVideoProfile *) sprof;
1463 append_escaped (str,
1464 g_markup_printf_escaped ("pass='%d' variableframerate='%i' ",
1465 gst_encoding_video_profile_get_pass (vp),
1466 gst_encoding_video_profile_get_variableframerate (vp)));
1469 g_string_append (str, "/>\n");
1473 _save_encoding_profiles (GESXmlFormatter * self, GString * str,
1474 GESProject * project)
1476 GstCaps *profformat;
1477 const gchar *profname, *profdesc, *profpreset, *proftype, *profpresetname;
1480 GList *profiles = g_list_reverse (g_list_copy ((GList *)
1481 ges_project_list_encoding_profiles (project)));
1483 for (tmp = profiles; tmp; tmp = tmp->next) {
1484 GstEncodingProfile *prof = GST_ENCODING_PROFILE (tmp->data);
1486 profname = gst_encoding_profile_get_name (prof);
1487 profdesc = gst_encoding_profile_get_description (prof);
1488 profpreset = gst_encoding_profile_get_preset (prof);
1489 profpresetname = gst_encoding_profile_get_preset_name (prof);
1490 proftype = gst_encoding_profile_get_type_nick (prof);
1492 append_escaped (str,
1493 g_markup_printf_escaped
1494 (" <encoding-profile name='%s' description='%s' type='%s' ",
1495 profname, profdesc, proftype));
1498 GstElement *element;
1500 append_escaped (str, g_markup_printf_escaped ("preset='%s' ",
1503 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
1504 element = get_element_for_encoding_profile (prof,
1505 GST_ELEMENT_FACTORY_TYPE_MUXER);
1507 element = get_element_for_encoding_profile (prof,
1508 GST_ELEMENT_FACTORY_TYPE_ENCODER);
1512 if (GST_IS_PRESET (element) &&
1513 gst_preset_load_preset (GST_PRESET (element), profpreset)) {
1514 gchar *settings = _serialize_properties (G_OBJECT (element), NULL);
1515 append_escaped (str,
1516 g_markup_printf_escaped ("preset-properties='%s' ", settings));
1519 gst_object_unref (element);
1525 append_escaped (str, g_markup_printf_escaped ("preset-name='%s' ",
1528 profformat = gst_encoding_profile_get_format (prof);
1530 gchar *format = gst_caps_to_string (profformat);
1531 append_escaped (str, g_markup_printf_escaped ("format='%s' ", format));
1533 gst_caps_unref (profformat);
1536 g_string_append (str, ">\n");
1538 if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) {
1541 GstEncodingContainerProfile *container_prof;
1543 container_prof = GST_ENCODING_CONTAINER_PROFILE (prof);
1544 for (tmp2 = gst_encoding_container_profile_get_profiles (container_prof);
1545 tmp2; tmp2 = tmp2->next, i++) {
1546 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp2->data;
1547 _save_stream_profiles (self, str, sprof, profname, i);
1550 append_escaped (str,
1551 g_markup_printf_escaped (" </encoding-profile>\n"));
1553 g_list_free (profiles);
1557 _save (GESFormatter * formatter, GESTimeline * timeline, GError ** error)
1560 GESProject *project;
1562 gchar *projstr = NULL, *version;
1563 gchar *properties = NULL, *metas = NULL;
1564 GESXmlFormatter *self = GES_XML_FORMATTER (formatter);
1565 GESXmlFormatterPrivate *priv;
1568 priv = _GET_PRIV (formatter);
1570 priv->min_version = 1;
1571 project = formatter->project;
1572 str = priv->str = g_string_new (NULL);
1574 properties = _serialize_properties (G_OBJECT (project), NULL);
1575 metas = ges_meta_container_metas_to_string (GES_META_CONTAINER (project));
1576 append_escaped (str,
1577 g_markup_printf_escaped (" <project properties='%s' metadatas='%s'>\n",
1578 properties, metas));
1579 g_free (properties);
1582 g_string_append (str, " <encoding-profiles>\n");
1583 _save_encoding_profiles (GES_XML_FORMATTER (formatter), str, project);
1584 g_string_append (str, " </encoding-profiles>\n");
1586 g_string_append (str, " <ressources>\n");
1587 _save_assets (self, str, project);
1588 g_string_append (str, " </ressources>\n");
1590 _save_timeline (self, str, timeline);
1591 g_string_append (str, "</project>\n</ges>");
1593 projstr = g_strdup_printf ("<ges version='%i.%i'>\n", API_VERSION,
1595 g_string_prepend (str, projstr);
1598 ges_meta_container_set_int (GES_META_CONTAINER (project),
1599 GES_META_FORMAT_VERSION, priv->min_version);
1601 version = g_strdup_printf ("%d.%d", API_VERSION,
1602 GES_XML_FORMATTER (formatter)->priv->min_version);
1604 ges_meta_container_set_string (GES_META_CONTAINER (project),
1605 GES_META_FORMAT_VERSION, version);
1614 /***********************************************
1616 * GObject virtual methods implementation *
1618 ***********************************************/
1621 _get_property (GObject * object, guint property_id,
1622 GValue * value, GParamSpec * pspec)
1627 _set_property (GObject * object, guint property_id,
1628 const GValue * value, GParamSpec * pspec)
1633 ges_xml_formatter_init (GESXmlFormatter * self)
1635 GESXmlFormatterPrivate *priv = ges_xml_formatter_get_instance_private (self);
1637 priv->project_opened = FALSE;
1638 priv->element_id = g_hash_table_new (g_direct_hash, g_direct_equal);
1641 self->priv->min_version = 1;
1645 _dispose (GObject * object)
1647 g_clear_pointer (&GES_XML_FORMATTER (object)->priv->element_id,
1648 g_hash_table_unref);
1650 G_OBJECT_CLASS (parent_class)->dispose (object);
1654 ges_xml_formatter_class_init (GESXmlFormatterClass * self_class)
1656 GObjectClass *object_class = G_OBJECT_CLASS (self_class);
1657 GESBaseXmlFormatterClass *basexmlformatter_class;
1659 basexmlformatter_class = GES_BASE_XML_FORMATTER_CLASS (self_class);
1661 object_class->get_property = _get_property;
1662 object_class->set_property = _set_property;
1663 object_class->dispose = _dispose;
1665 basexmlformatter_class->content_parser.start_element = _parse_element_start;
1666 basexmlformatter_class->content_parser.end_element = _parse_element_end;
1667 basexmlformatter_class->content_parser.text = NULL;
1668 basexmlformatter_class->content_parser.passthrough = NULL;
1669 basexmlformatter_class->content_parser.error = _error_parsing;
1671 ges_formatter_class_register_metas (GES_FORMATTER_CLASS (self_class),
1672 "ges", "GStreamer Editing Services project files",
1673 "xges", "application/ges", VERSION, GST_RANK_PRIMARY);
1675 basexmlformatter_class->save = _save;
1678 #undef COLLECT_STR_OPT