Remove the GESKeyFileFormatter

It was using deprecated URI, and can not be used in real life anymore.

Also remove the ges_formatter_default_new method ges_formatter_new_for_uri
that are useless now
This commit is contained in:
Thibault Saunier 2012-11-23 23:51:17 -03:00
parent 35a3f72ad5
commit 97973f1eba
13 changed files with 10 additions and 1435 deletions

View file

@ -87,7 +87,6 @@ platform as well as Windows. It is released under the GNU Library General Public
<chapter>
<title>Serialization Classes</title>
<xi:include href="xml/ges-formatter.xml"/>
<xi:include href="xml/ges-keyfile-formatter.xml"/>
<xi:include href="xml/ges-pitivi-formatter.xml"/>
</chapter>

View file

@ -3,7 +3,6 @@
ges_custom_timeline_source_get_type
ges_formatter_get_type
ges_keyfile_formatter_get_type
ges_simple_timeline_layer_get_type
%ges_text_halign_get_type
%ges_text_valign_get_type

View file

@ -45,7 +45,6 @@ libges_@GST_API_VERSION@_la_SOURCES = \
ges-track-parse-launch-effect.c \
ges-screenshot.c \
ges-formatter.c \
ges-keyfile-formatter.c \
ges-pitivi-formatter.c \
ges-utils.c
@ -89,7 +88,6 @@ libges_@GST_API_VERSION@include_HEADERS = \
ges-track-text-overlay.h \
ges-screenshot.h \
ges-formatter.h \
ges-keyfile-formatter.h \
ges-pitivi-formatter.h \
ges-utils.h

View file

@ -48,7 +48,6 @@
#include <stdlib.h>
#include "ges-formatter.h"
#include "ges-keyfile-formatter.h"
#include "ges-internal.h"
#include "ges.h"
@ -168,39 +167,6 @@ ges_formatter_find_for_uri (const gchar * uri)
return ret;
}
/**
* ges_formatter_new_for_uri:
* @uri: a #gchar * pointing to the uri
*
* Creates a #GESFormatter that can handle the given URI.
*
* Returns: A GESFormatter that can load the given uri, or NULL if
* the uri is not supported.
*/
GESFormatter *
ges_formatter_new_for_uri (const gchar * uri)
{
if (ges_formatter_can_load_uri (uri, NULL))
return GES_FORMATTER (ges_keyfile_formatter_new ());
return NULL;
}
/**
* ges_default_formatter_new:
*
* Creates a new instance of the default GESFormatter type on this system
* (currently #GESKeyfileFormatter).
*
* Returns: (transfer full): a #GESFormatter instance or %NULL
*/
GESFormatter *
ges_default_formatter_new (void)
{
return GES_FORMATTER (ges_keyfile_formatter_new ());
}
static gboolean
default_can_load_uri (const gchar * uri, GError ** error)
{

View file

@ -169,9 +169,6 @@ struct _GESFormatterClass {
GType ges_formatter_get_type (void);
/* Main Formatter methods */
GESFormatter *ges_formatter_new_for_uri (const gchar *uri);
GESFormatter *ges_default_formatter_new (void);
gboolean ges_formatter_can_load_uri (const gchar * uri, GError **error);
gboolean ges_formatter_can_save_uri (const gchar * uri, GError **error);

View file

@ -1,463 +0,0 @@
/* GStreamer Editing Services
* Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
* 2010 Nokia Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:ges-keyfile-formatter
* @short_description: GKeyFile formatter
**/
#include <gst/gst.h>
#include <stdlib.h>
#include "ges.h"
#include "ges-internal.h"
G_DEFINE_TYPE (GESKeyfileFormatter, ges_keyfile_formatter, GES_TYPE_FORMATTER);
/* for ini format */
static gboolean save_keyfile (GESFormatter * keyfile_formatter,
GESTimeline * timeline);
static gboolean load_keyfile (GESFormatter * keyfile_formatter,
GESTimeline * timeline);
static void
ges_keyfile_formatter_class_init (GESKeyfileFormatterClass * klass)
{
GESFormatterClass *formatter_klass;
formatter_klass = GES_FORMATTER_CLASS (klass);
formatter_klass->save = save_keyfile;
formatter_klass->load = load_keyfile;
}
static void
ges_keyfile_formatter_init (GESKeyfileFormatter * object)
{
}
/**
* ges_keyfile_formatter_new:
*
* Creates a new #GESKeyfileFormatter.
*
* Returns: The newly created #GESKeyfileFormatter.
*/
GESKeyfileFormatter *
ges_keyfile_formatter_new (void)
{
return g_object_new (GES_TYPE_KEYFILE_FORMATTER, NULL);
}
static gboolean
save_keyfile (GESFormatter * keyfile_formatter, GESTimeline * timeline)
{
GKeyFile *kf;
GList *tmp, *tracks, *layers;
int i = 0;
int n_objects = 0;
gchar buffer[255];
gchar *data;
gsize length;
GST_DEBUG ("saving keyfile_formatter");
kf = g_key_file_new ();
g_key_file_set_value (kf, "General", "version", "1");
tracks = ges_timeline_get_tracks (timeline);
for (i = 0, tmp = tracks; tmp; i++, tmp = tmp->next) {
GESTrack *track;
gchar *type;
gchar *caps;
GValue v = { 0 };
track = GES_TRACK (tmp->data);
g_snprintf (buffer, 255, "Track%d", i);
g_value_init (&v, GES_TYPE_TRACK_TYPE);
g_object_get_property (G_OBJECT (track), "track-type", &v);
type = gst_value_serialize (&v);
caps = gst_caps_to_string (ges_track_get_caps (track));
g_key_file_set_value (kf, buffer, "type", type);
g_key_file_set_string (kf, buffer, "caps", caps);
g_free (caps);
g_free (type);
gst_object_unref (track);
tmp->data = NULL;
}
g_list_free (tracks);
layers = ges_timeline_get_layers (timeline);
for (i = 0, tmp = layers; tmp; i++, tmp = tmp->next) {
const gchar *type;
GESTimelineLayer *layer;
GList *objs, *cur;
layer = tmp->data;
g_snprintf (buffer, 255, "Layer%d", i);
if (GES_IS_SIMPLE_TIMELINE_LAYER (tmp->data)) {
type = "simple";
} else {
type = "default";
}
g_key_file_set_integer (kf, buffer, "priority",
ges_timeline_layer_get_priority (layer));
g_key_file_set_value (kf, buffer, "type", type);
objs = ges_timeline_layer_get_objects (layer);
for (cur = objs; cur; cur = cur->next) {
GESTimelineObject *obj;
GParamSpec **properties;
guint i, n;
obj = GES_TIMELINE_OBJECT (cur->data);
properties =
g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &n);
g_snprintf (buffer, 255, "Object%d", n_objects);
n_objects++;
g_key_file_set_value (kf, buffer, "type",
G_OBJECT_TYPE_NAME (G_OBJECT (obj)));
for (i = 0; i < n; i++) {
GValue v = { 0 };
gchar *serialized;
GParamSpec *p = properties[i];
g_value_init (&v, p->value_type);
g_object_get_property (G_OBJECT (obj), p->name, &v);
/* FIXME: does this work for properties marked G_PARAM_CONSTRUCT_ONLY?
* */
if ((p->flags & G_PARAM_READABLE) && (p->flags & G_PARAM_WRITABLE)) {
if (!(serialized = gst_value_serialize (&v)))
continue;
g_key_file_set_string (kf, buffer, p->name, serialized);
g_free (serialized);
}
g_value_unset (&v);
}
g_free (properties);
g_object_unref (obj);
cur->data = NULL;
}
g_list_free (objs);
}
g_list_foreach (layers, (GFunc) g_object_unref, NULL);
g_list_free (layers);
data = g_key_file_to_data (kf, &length, NULL);
ges_formatter_set_data (keyfile_formatter, data, length);
g_key_file_free (kf);
return TRUE;
}
static gboolean
create_track (GKeyFile * kf, gchar * group, GESTimeline * timeline)
{
GESTrack *track;
GstCaps *caps;
gchar *caps_field, *type_field;
gboolean res;
GValue v = { 0 };
if (!(caps_field = g_key_file_get_string (kf, group, "caps", NULL)))
return FALSE;
caps = gst_caps_from_string (caps_field);
g_free (caps_field);
if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
return FALSE;
g_value_init (&v, GES_TYPE_TRACK_TYPE);
res = gst_value_deserialize (&v, type_field);
g_free (type_field);
if (!caps || !res)
return FALSE;
track = ges_track_new (g_value_get_flags (&v), caps);
if (!ges_timeline_add_track (timeline, track)) {
g_object_unref (track);
return FALSE;
}
return TRUE;
}
static GESTimelineLayer *
create_layer (GKeyFile * kf, gchar * group, GESTimeline * timeline)
{
GESTimelineLayer *ret = NULL;
gchar *type_field, *priority_field;
gboolean is_simple;
guint priority;
if (!(type_field = g_key_file_get_value (kf, group, "type", NULL)))
return FALSE;
is_simple = g_str_equal (type_field, "simple");
g_free (type_field);
if (!(priority_field = g_key_file_get_value (kf, group, "priority", NULL)))
return FALSE;
priority = strtoul (priority_field, NULL, 10);
g_free (priority_field);
if (is_simple) {
GESSimpleTimelineLayer *simple;
simple = ges_simple_timeline_layer_new ();
ret = (GESTimelineLayer *) simple;
} else {
ret = ges_timeline_layer_new ();
}
ges_timeline_layer_set_priority (ret, priority);
if (!ges_timeline_add_layer (timeline, ret)) {
g_object_unref (ret);
ret = NULL;
}
return ret;
}
static gboolean
create_object (GKeyFile * kf, gchar * group, GESTimelineLayer * layer)
{
GType type;
gchar *type_name;
GObject *obj;
GESTimelineObject *timeline_obj;
gchar **keys;
gsize n_keys, i;
GParamSpec *pspec;
GObjectClass *klass;
GParameter *params, *p;
gboolean ret = FALSE;
GST_INFO ("processing '%s'", group);
/* get a reference to the object class */
if (!(type_name = g_key_file_get_value (kf, group, "type", NULL))) {
GST_ERROR ("no type name for object '%s'", group);
return FALSE;
}
if (!(type = g_type_from_name (type_name))) {
GST_ERROR ("invalid type name '%s'", type_name);
goto fail_free_type_name;
}
if (!(klass = g_type_class_ref (type))) {
GST_ERROR ("couldn't get class ref");
goto fail_free_type_name;
}
if (!(keys = g_key_file_get_keys (kf, group, &n_keys, NULL)))
goto fail_unref_class;
/* create an array of parameters for the call to g_new0 */
/* skip first field 'type' */
if (!(params = g_new0 (GParameter, (n_keys - 1)))) {
GST_ERROR ("couldn't allocate parameter list");
goto fail_free_keys;
}
GST_DEBUG ("processing parameter list '%s'", group);
for (p = params, i = 1; i < n_keys; i++, p++) {
gchar *value;
gchar *key;
key = keys[i];
GST_DEBUG ("processing key '%s'", key);
/* find the param spec for this property */
if (!(pspec = g_object_class_find_property (klass, key))) {
GST_ERROR ("Object type %s has no property %s", type_name, key);
goto fail_free_params;
}
p->name = key;
g_value_init (&p->value, pspec->value_type);
/* assume this is going to work */
value = g_key_file_get_string (kf, group, key, NULL);
if (!gst_value_deserialize (&p->value, value)) {
GST_ERROR ("Couldn't read property value '%s' for property '%s'",
key, value);
goto fail_free_params;
}
g_free (value);
}
/* create the object from the supplied type name */
if (!(obj = g_object_newv (type, (n_keys - 1), params))) {
GST_ERROR ("couldn't create object");
goto fail_free_type_name;
}
/* check that we have a subclass of GESTimelineObject */
if (!GES_IS_TIMELINE_OBJECT (obj)) {
GST_ERROR ("'%s' is not a subclass of GESTimelineObject!", type_name);
goto fail_unref_obj;
}
timeline_obj = (GESTimelineObject *) obj;
/* add the object to the layer */
if (GES_IS_SIMPLE_TIMELINE_LAYER (layer)) {
if (!ges_simple_timeline_layer_add_object ((GESSimpleTimelineLayer *)
layer, timeline_obj, -1)) {
goto fail_unref_obj;
}
} else {
if (!ges_timeline_layer_add_object (layer, timeline_obj)) {
goto fail_unref_obj;
}
}
ret = TRUE;
fail_unref_obj:
if (!ret)
g_object_unref (obj);
fail_free_params:
for (p = params, i = 1; i < n_keys; i++, p++) {
g_value_unset (&p->value);
}
g_free (params);
fail_free_keys:
g_strfreev (keys);
fail_unref_class:
g_type_class_unref (klass);
fail_free_type_name:
g_free (type_name);
return ret;
}
static gboolean
load_keyfile (GESFormatter * keyfile_formatter, GESTimeline * timeline)
{
GKeyFile *kf;
GError *error = NULL;
gboolean ret = TRUE;
gchar **groups;
gsize n_groups, i;
GESTimelineLayer *cur_layer = NULL;
gchar *data;
gsize length;
kf = g_key_file_new ();
data = ges_formatter_get_data (keyfile_formatter, &length);
if (!g_key_file_load_from_data (kf, data, length, G_KEY_FILE_NONE, &error)) {
ret = FALSE;
GST_ERROR ("%s", error->message);
GST_INFO ("%s", data);
goto free_kf;
}
if (!(groups = g_key_file_get_groups (kf, &n_groups))) {
goto free_kf;
}
for (i = 0; i < n_groups; i++) {
gchar *group = groups[i];
if (g_str_has_prefix (group, "Track")) {
if (!create_track (kf, group, timeline)) {
GST_ERROR ("couldn't create object for %s", group);
ret = FALSE;
break;
}
}
else if (g_str_has_prefix (group, "Layer")) {
if (!(cur_layer = create_layer (kf, group, timeline))) {
GST_ERROR ("couldn't create object for %s", group);
ret = FALSE;
break;
}
}
else if (g_str_has_prefix (group, "Object")) {
if (!cur_layer) {
GST_ERROR ("Group %s occurs outside of Layer", group);
ret = FALSE;
break;
}
if (!create_object (kf, group, cur_layer)) {
GST_ERROR ("couldn't create object for %s", group);
ret = FALSE;
break;
}
}
else if (g_str_equal (group, "General")) {
continue;
}
else {
GST_ERROR ("Unrecognized group name %s", group);
ret = FALSE;
break;
}
}
g_strfreev (groups);
free_kf:
g_key_file_free (kf);
return ret;
}

View file

@ -1,70 +0,0 @@
/* GStreamer Editing Services
* Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
* 2010 Nokia Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GES_KEYFILE_FORMATTER
#define _GES_KEYFILE_FORMATTER
#include <glib-object.h>
#include <ges/ges-timeline.h>
#define GES_TYPE_KEYFILE_FORMATTER ges_keyfile_formatter_get_type()
#define GES_KEYFILE_FORMATTER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatter))
#define GES_KEYFILE_FORMATTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatterClass))
#define GES_IS_KEYFILE_FORMATTER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_KEYFILE_FORMATTER))
#define GES_IS_KEYFILE_FORMATTER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_KEYFILE_FORMATTER))
#define GES_KEYFILE_FORMATTER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_KEYFILE_FORMATTER, GESKeyfileFormatterClass))
/**
* GESKeyfileFormatter:
*
* Serializes a #GESTimeline to a file using #GKeyFile
*/
struct _GESKeyfileFormatter {
/*< private >*/
GESFormatter parent;
/* Padding for API extension */
gpointer _ges_reserved[GES_PADDING];
};
struct _GESKeyfileFormatterClass {
/*< private >*/
GESFormatterClass parent_class;
/* Padding for API extension */
gpointer _ges_reserved[GES_PADDING];
};
GType ges_keyfile_formatter_get_type (void);
GESKeyfileFormatter *ges_keyfile_formatter_new (void);
#endif /* _GES_KEYFILE_FORMATTER */

View file

@ -1940,29 +1940,8 @@ gboolean
ges_timeline_load_from_uri (GESTimeline * timeline, const gchar * uri,
GError ** error)
{
GESFormatter *p = NULL;
gboolean ret = FALSE;
/* FIXME : we should have a GError** argument so the user can know why
* it wasn't able to load the uri
*/
if (!(p = ges_formatter_new_for_uri (uri))) {
GST_ERROR ("unsupported uri '%s'", uri);
goto fail;
}
if (!ges_formatter_load_from_uri (p, timeline, uri, error)) {
GST_ERROR ("error deserializing formatter");
goto fail;
}
ret = TRUE;
fail:
if (p)
g_object_unref (p);
return ret;
GST_FIXME ("This should be reimplemented");
return FALSE;
}
/**
@ -1980,32 +1959,8 @@ gboolean
ges_timeline_save_to_uri (GESTimeline * timeline, const gchar * uri,
GError ** error)
{
GESFormatter *p = NULL;
gboolean ret = FALSE;
/* FIXME : How will the user be able to chose the format he
* wishes to store to ? */
/* FIXME : How will we ensure a timeline loaded with a certain format
* will be saved with the same one by default ? We need to make this
* easy from an API perspective */
if (!(p = ges_formatter_new_for_uri (uri))) {
GST_ERROR ("unsupported uri '%s'", uri);
goto fail;
}
if (!ges_formatter_save_to_uri (p, timeline, uri, error)) {
GST_ERROR ("error serializing formatter");
goto fail;
}
ret = TRUE;
fail:
if (p)
g_object_unref (p);
return ret;
GST_FIXME ("This should be reimplemented");
return FALSE;
}
/**

View file

@ -72,7 +72,6 @@ ges_init (void)
/* register formatter types with the system */
GES_TYPE_PITIVI_FORMATTER;
GES_TYPE_KEYFILE_FORMATTER;
/* check the gnonlin elements are available */
if (!ges_check_gnonlin_availability ())

View file

@ -63,7 +63,6 @@
#include <ges/ges-track-effect.h>
#include <ges/ges-track-parse-launch-effect.h>
#include <ges/ges-formatter.h>
#include <ges/ges-keyfile-formatter.h>
#include <ges/ges-pitivi-formatter.h>
#include <ges/ges-utils.h>

View file

@ -39,8 +39,7 @@ check_PROGRAMS = \
ges/titles\
ges/transition \
ges/overlays\
ges/text_properties\
ges/save_and_load
ges/text_properties
noinst_LTLIBRARIES=$(testutils_noisnt_libraries)
noinst_HEADERS=$(testutils_noinst_headers)

View file

@ -1,808 +0,0 @@
/* GStreamer Editing Services
* Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "test-utils.h"
#include <ges/ges.h>
#include <gst/check/gstcheck.h>
#include <string.h>
#include <unistd.h>
#define GetCurrentDir getcwd
#include <gst/audio/audio.h>
#define KEY_FILE_START {\
if (cmp) g_key_file_free (cmp);\
cmp = g_key_file_new ();\
}
#define KEY(group, key, value) \
g_key_file_set_value (cmp, group, key, value)
#define COMPARE fail_unless(compare (cmp, formatter, timeline))
static gboolean
compare (GKeyFile * cmp, GESFormatter * formatter, GESTimeline * timeline)
{
gchar *data, *fmt_data;
gsize length;
gboolean result = TRUE;
data = g_key_file_to_data (cmp, &length, NULL);
ges_formatter_save (formatter, timeline);
fmt_data = ges_formatter_get_data (formatter, &length);
if (!(g_strcmp0 (data, fmt_data) == 0)) {
GST_ERROR ("difference between expected and output");
GST_ERROR ("expected: \n%s", data);
GST_ERROR ("actual: \n%s", fmt_data);
result = FALSE;
}
g_free (data);
return result;
}
GST_START_TEST (test_simple)
{
gchar *uri = ges_test_file_uri ("test.xptv");
ges_init ();
fail_unless (ges_formatter_can_load_uri (uri, NULL));
g_free (uri);
uri = ges_test_file_uri ("wrong_test.xptv");
fail_if (ges_formatter_can_load_uri (uri, NULL));
g_free (uri);
}
GST_END_TEST;
GST_START_TEST (test_keyfile_save)
{
GESTimeline *timeline;
GESTimelineLayer *layer, *layer2;
GESTrack *track;
GESTimelineObject *source;
GESFormatter *formatter;
GKeyFile *cmp = NULL;
ges_init ();
/* setup timeline */
GST_DEBUG ("Create a timeline");
timeline = ges_timeline_new ();
fail_unless (timeline != NULL);
/* create serialization object */
GST_DEBUG ("creating a keyfile formatter");
formatter = GES_FORMATTER (ges_keyfile_formatter_new ());
/* add a layer and make sure it's serialized */
GST_DEBUG ("Create a layer");
layer = GES_TIMELINE_LAYER (ges_simple_timeline_layer_new ());
fail_unless (layer != NULL);
GST_DEBUG ("Add the layer to the timeline");
fail_unless (ges_timeline_add_layer (timeline, layer));
KEY_FILE_START;
KEY ("General", "version", "1");
KEY ("Layer0", "priority", "0");
KEY ("Layer0", "type", "simple");
COMPARE;
/* add a track and make sure it's serialized */
GST_DEBUG ("Create a Track");
track = ges_track_audio_raw_new ();
fail_unless (track != NULL);
GST_DEBUG ("Add the track to the timeline");
fail_unless (ges_timeline_add_track (timeline, track));
KEY_FILE_START;
KEY ("General", "version", "1");
KEY ("Track0", "type", "GES_TRACK_TYPE_AUDIO");
KEY ("Track0", "caps", "audio/x-raw");
KEY ("Layer0", "priority", "0");
KEY ("Layer0", "type", "simple");
COMPARE;
/* add sources */
GST_DEBUG ("Adding first source");
source = (GESTimelineObject *) ges_timeline_test_source_new ();
ges_simple_timeline_layer_add_object (GES_SIMPLE_TIMELINE_LAYER (layer),
source, -1);
g_object_set (G_OBJECT (source), "duration", (guint64) 2 * GST_SECOND, NULL);
KEY ("Object0", "type", "GESTimelineTestSource");
KEY ("Object0", "start", "0");
KEY ("Object0", "in-point", "0");
KEY ("Object0", "duration", "2000000000");
KEY ("Object0", "priority", "2");
KEY ("Object0", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object0", "max-duration", "18446744073709551615");
KEY ("Object0", "mute", "false");
KEY ("Object0", "vpattern", "100% Black");
KEY ("Object0", "freq", "440");
KEY ("Object0", "volume", "0");
COMPARE;
GST_DEBUG ("Adding transition");
source = (GESTimelineObject *)
ges_timeline_standard_transition_new_for_nick ((gchar *) "bar-wipe-lr");
g_object_set (G_OBJECT (source), "duration", (guint64) GST_SECOND / 2, NULL);
ges_simple_timeline_layer_add_object (GES_SIMPLE_TIMELINE_LAYER (layer),
source, -1);
KEY ("Object1", "type", "GESTimelineStandardTransition");
KEY ("Object1", "start", "1500000000");
KEY ("Object1", "in-point", "0");
KEY ("Object1", "duration", "500000000");
KEY ("Object1", "priority", "1");
KEY ("Object1", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object1", "max-duration", "18446744073709551615");
KEY ("Object1", "vtype", "A bar moves from left to right");
COMPARE;
GST_DEBUG ("Adding second source");
source = (GESTimelineObject *) ges_timeline_test_source_new ();
g_object_set (G_OBJECT (source), "duration", (guint64) 2 * GST_SECOND, NULL);
ges_simple_timeline_layer_add_object (GES_SIMPLE_TIMELINE_LAYER (layer),
source, -1);
KEY ("Object2", "type", "GESTimelineTestSource");
KEY ("Object2", "start", "1500000000");
KEY ("Object2", "in-point", "0");
KEY ("Object2", "duration", "2000000000");
KEY ("Object2", "priority", "3");
KEY ("Object2", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object2", "max-duration", "18446744073709551615");
KEY ("Object2", "mute", "false");
KEY ("Object2", "vpattern", "100% Black");
KEY ("Object2", "freq", "440");
KEY ("Object2", "volume", "0");
COMPARE;
/* add a second layer to the timeline */
GST_DEBUG ("Adding a second layer to the timeline");
layer2 = ges_timeline_layer_new ();
ges_timeline_layer_set_priority (layer2, 1);
fail_unless (layer != NULL);
fail_unless (ges_timeline_add_layer (timeline, layer2));
KEY ("Layer1", "priority", "1");
KEY ("Layer1", "type", "default");
COMPARE;
GST_DEBUG ("Adding a few more sources");
source = (GESTimelineObject *) ges_timeline_title_source_new ();
g_object_set (G_OBJECT (source),
"duration", (guint64) GST_SECOND,
"start", (guint64) 5 * GST_SECOND, "text", "the quick brown fox", NULL);
fail_unless (ges_timeline_layer_add_object (layer2, source));
KEY ("Object3", "type", "GESTimelineTitleSource");
KEY ("Object3", "start", "5000000000");
KEY ("Object3", "in-point", "0");
KEY ("Object3", "duration", "1000000000");
KEY ("Object3", "priority", "0");
KEY ("Object3", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object3", "max-duration", "18446744073709551615");
KEY ("Object3", "mute", "false");
KEY ("Object3", "text", "\"the\\\\ quick\\\\ brown\\\\ fox\"");
KEY ("Object3", "font-desc", "\"Serif\\\\ 36\"");
KEY ("Object3", "halignment", "center");
KEY ("Object3", "valignment", "baseline");
KEY ("Object3", "color", "4294967295");
KEY ("Object3", "background", "4294967295");
KEY ("Object3", "xpos", "0.5");
KEY ("Object3", "ypos", "0.5");
COMPARE;
/* tear-down */
g_key_file_free (cmp);
GST_DEBUG ("Removing layer from the timeline");
fail_unless (ges_timeline_remove_layer (timeline, layer));
fail_unless (ges_timeline_remove_layer (timeline, layer2));
GST_DEBUG ("Removing track from the timeline");
g_object_ref (track);
fail_unless (ges_timeline_remove_track (timeline, track));
fail_unless (ges_track_get_timeline (track) == NULL);
ASSERT_OBJECT_REFCOUNT (track, "track", 1);
g_object_unref (track);
ASSERT_OBJECT_REFCOUNT (timeline, "timeline", 1);
g_object_unref (timeline);
g_object_unref (formatter);
}
GST_END_TEST;
/* do action for every item and then free the list */
#define g_list_free_all(list) \
{ \
g_list_foreach(list, (GFunc) g_object_unref, NULL); \
g_list_free(list); \
}
/* print out a helpful error message when a comparison fails. Works with the
* TIMELINE_COMPARE_*, LAYER*, SIMPLE_LAYER*, abd TRACK, macros below to give
* information about the source line where the failing object was created.
*/
#define CMP_FAIL(a, ...) \
fail_unless (FALSE, __VA_ARGS__);
/* compare two GObjects for equality. pointer identity and GType short-circuit
* the comparison. If a and b are not identical pointers and of the same
* GType, compares every readable property for equality using
* g_param_values_cmp.
*/
static gboolean
ges_objs_equal (GObject * a, GObject * b)
{
GType at;
GObjectClass *klass;
GParamSpec **props = NULL, **iter = NULL;
guint n_props, i;
guint ret = FALSE;
gchar *typename;
GST_DEBUG ("comparing %s (%p) and %s (%p)\n",
G_OBJECT_TYPE_NAME (a), a, G_OBJECT_TYPE_NAME (b), b);
if (a == b)
return TRUE;
at = G_TYPE_FROM_INSTANCE (a);
fail_unless (at == G_TYPE_FROM_INSTANCE (b));
typename = (gchar *) g_type_name (at);
/* compare every readable property */
klass = G_OBJECT_GET_CLASS (a);
props = g_object_class_list_properties (klass, &n_props);
for (i = 0, iter = props; i < n_props; i++, iter++) {
GValue av = { 0 }
, bv = {
0};
/* ignore name and layer properties */
if (!g_strcmp0 ("name", (*iter)->name) ||
!g_strcmp0 ("layer", (*iter)->name) ||
!g_strcmp0 ("parent", (*iter)->name))
continue;
/* special case caps property */
if (!g_strcmp0 ("caps", (*iter)->name)) {
GstCaps *acaps, *bcaps;
g_object_get (a, "caps", &acaps, NULL);
g_object_get (b, "caps", &bcaps, NULL);
if (gst_caps_is_equal (acaps, bcaps)) {
gst_caps_unref (acaps);
gst_caps_unref (bcaps);
continue;
} else {
gst_caps_unref (acaps);
gst_caps_unref (bcaps);
CMP_FAIL (b, "%s's %p and %p differ by property caps", a, b);
goto fail;
}
}
g_value_init (&av, (*iter)->value_type);
g_value_init (&bv, (*iter)->value_type);
if (!((*iter)->flags & G_PARAM_READABLE))
continue;
g_object_get_property (a, (*iter)->name, &av);
g_object_get_property (b, (*iter)->name, &bv);
if (g_param_values_cmp (*iter, &av, &bv) != 0) {
gchar *a_str, *b_str;
a_str = gst_value_serialize (&av);
b_str = gst_value_serialize (&bv);
CMP_FAIL (b, "%s's %p and %p differ by property %s (%s != %s)",
typename, a, b, (*iter)->name, a_str, b_str);
g_free (a_str);
g_free (b_str);
goto fail;
}
g_value_unset (&av);
g_value_unset (&bv);
}
ret = TRUE;
fail:
if (props)
g_free (props);
return ret;
}
static gboolean
ges_tracks_equal (GESTrack * a, GESTrack * b)
{
return ges_objs_equal (G_OBJECT (a), G_OBJECT (b));
}
static gboolean
ges_layers_equal (GESTimelineLayer * a, GESTimelineLayer * b)
{
GList *a_objs = NULL, *b_objs = NULL, *a_iter, *b_iter;
gboolean ret = FALSE;
guint i;
if (!ges_objs_equal (G_OBJECT (a), G_OBJECT (b)))
return FALSE;
a_objs = ges_timeline_layer_get_objects (a);
b_objs = ges_timeline_layer_get_objects (b);
/* one shortcoming of this procedure is that the objects need to be stored
* in the same order. Not sure if this is a problem in practice */
for (i = 0, a_iter = a_objs, b_iter = b_objs; a_iter && b_iter; a_iter =
a_iter->next, b_iter = b_iter->next, i++) {
if (!ges_objs_equal (a_iter->data, b_iter->data)) {
CMP_FAIL (b, "layers %p and %p differ by obj at position %d", a, b, i);
goto fail;
}
}
if (a_iter || b_iter) {
CMP_FAIL (b, "layers %p and %p have differing number of objects", a, b);
goto fail;
}
ret = TRUE;
fail:
g_list_free_all (a_objs);
g_list_free_all (b_objs);
return ret;
}
static gboolean
ges_timelines_equal (GESTimeline * a, GESTimeline * b)
{
GList *a_tracks, *b_tracks, *a_iter, *b_iter, *a_layers, *b_layers;
gboolean ret = FALSE;
guint i;
if (!ges_objs_equal (G_OBJECT (a), G_OBJECT (b))) {
CMP_FAIL (b, "%p and %p are not of the same type");
return FALSE;
}
a_tracks = ges_timeline_get_tracks (a);
b_tracks = ges_timeline_get_tracks (b);
a_layers = ges_timeline_get_layers (a);
b_layers = ges_timeline_get_layers (b);
/* one shortcoming of this procedure is that the objects need to be stored
* in the same order. Not sure if this is a problem in practice */
for (i = 0, a_iter = a_tracks, b_iter = b_tracks; a_iter && b_iter; a_iter =
a_iter->next, b_iter = b_iter->next, i++) {
if (!ges_tracks_equal (a_iter->data, b_iter->data)) {
CMP_FAIL (b, "GESTimelines %p and %p differ by tracks at position %d", a,
b, i);
goto fail;
}
}
if (a_iter || b_iter) {
CMP_FAIL (b, "GESTimelines %p and %p have differing number of tracks", a,
b);
goto fail;
}
for (i = 0, a_iter = a_layers, b_iter = b_layers; a_iter && b_iter; a_iter =
a_iter->next, b_iter = b_iter->next, i++) {
if (!ges_layers_equal (a_iter->data, b_iter->data)) {
goto fail;
}
}
if (a_iter || b_iter) {
CMP_FAIL (b, "GESTimelines %p and %p have differing numbre of layers", a,
b);
goto fail;
}
ret = TRUE;
fail:
g_list_free_all (a_tracks);
g_list_free_all (b_tracks);
g_list_free_all (a_layers);
g_list_free_all (b_layers);
return ret;
}
#define TIMELINE_BEGIN(location) \
{\
GESTimeline **a, *b;\
a = &(location);\
if (*a) g_object_unref (*a);\
b = ges_timeline_new();\
*a = b;\
#define TIMELINE_END }
#define TIMELINE_COMPARE(a, b)\
{\
fail_unless (ges_timelines_equal(a, b));\
}
#define TRACK(type, caps) \
{\
GESTrack *trk;\
GstCaps *c;\
c = gst_caps_from_string(caps);\
trk = ges_track_new (type, c);\
ges_timeline_add_track (b, trk);\
g_object_set_data(G_OBJECT(trk),"file", (void *) __FILE__);\
g_object_set_data(G_OBJECT(trk),"line", (void *) __LINE__);\
g_object_set_data(G_OBJECT(trk),"function", (void *) GST_FUNCTION);\
}
#define LAYER_BEGIN(priority) \
{\
GESTimelineLayer *l;\
l = ges_timeline_layer_new ();\
ges_timeline_add_layer (b, l);\
ges_timeline_layer_set_priority (l, priority);\
g_object_set_data(G_OBJECT(l),"file", (void *) __FILE__);\
g_object_set_data(G_OBJECT(l),"line", (void *) __LINE__);\
g_object_set_data(G_OBJECT(l),"function", (void *) GST_FUNCTION);
#define LAYER_END \
}
#define LAYER_OBJECT(type, ...) \
{\
GESTimelineObject *obj;\
obj = GES_TIMELINE_OBJECT(\
g_object_new ((type), __VA_ARGS__, NULL));\
ges_timeline_layer_add_object (l, obj);\
g_object_set_data(G_OBJECT(obj),"file", (void *) __FILE__);\
g_object_set_data(G_OBJECT(obj),"line", (void *) __LINE__);\
g_object_set_data(G_OBJECT(obj),"function", (void *) GST_FUNCTION);\
}
#define SIMPLE_LAYER_BEGIN(priority) \
{\
GESSimpleTimelineLayer *l;\
l = ges_simple_timeline_layer_new ();\
ges_timeline_add_layer (b, GES_TIMELINE_LAYER(l));\
ges_timeline_layer_set_priority(GES_TIMELINE_LAYER(l), priority);\
g_object_set_data(G_OBJECT(l),"file", (void *) __FILE__);\
g_object_set_data(G_OBJECT(l),"line", (void *) __LINE__);\
g_object_set_data(G_OBJECT(l),"function", (void *) GST_FUNCTION);
#define SIMPLE_LAYER_OBJECT(type, position, ...) \
{\
GESTimelineObject *obj;\
obj = GES_TIMELINE_OBJECT(\
g_object_new ((type), __VA_ARGS__, NULL));\
ges_simple_timeline_layer_add_object (l, obj, position);\
g_object_set_data(G_OBJECT(obj),"file", (void *) __FILE__);\
g_object_set_data(G_OBJECT(obj),"line", (void *) __LINE__);\
g_object_set_data(G_OBJECT(obj),"function", (void *) GST_FUNCTION);\
}
/* */
static const gchar *data = "\n[General]\n"
"[Track0]\n"
"type=GES_TRACK_TYPE_AUDIO\n"
"caps=audio/x-raw\n"
"\n"
"[Layer0]\n"
"priority=0\n"
"type=simple\n"
"\n"
"[Object0]\n"
"type=GESTimelineTestSource\n"
"start=0\n"
"in-point=0\n"
"duration=2000000000\n"
"priority=2\n"
"mute=false\n"
"vpattern=100% Black\n"
"freq=440\n"
"volume=0\n"
"\n"
"[Object1]\n"
"type=GESTimelineStandardTransition\n"
"start=1500000000\n"
"in-point=0\n"
"duration=500000000\n"
"priority=1\n"
"vtype=A bar moves from left to right\n"
"\n"
"[Object2]\n"
"type=GESTimelineTestSource\n"
"start=1500000000\n"
"in-point=0\n"
"duration=2000000000\n"
"priority=2\n"
"mute=false\n"
"vpattern=100% Black\n"
"freq=440\n"
"volume=0\n"
"\n"
"[Layer1]\n"
"priority=1\n"
"type=default\n"
"\n"
"[Object3]\n"
"type=GESTimelineTitleSource\n"
"start=5000000000\n"
"in-point=0\n"
"duration=1000000000\n"
"priority=2\n"
"mute=false\n"
"text=\"the\\\\ quick\\\\ brown\\\\ fox\"\n"
"font-desc=\"Serif\\\\ 36\"\n"
"halignment=center\n" "valignment=baseline\n";
GST_START_TEST (test_keyfile_load)
{
GESTimeline *timeline = NULL, *expected = NULL;
GESFormatter *formatter;
ges_init ();
/* setup timeline */
GST_DEBUG ("Create a timeline");
timeline = ges_timeline_new ();
fail_unless (timeline != NULL);
/* create serialization object */
GST_DEBUG ("creating a default formatter");
formatter = GES_FORMATTER (ges_keyfile_formatter_new ());
ges_formatter_set_data (formatter, g_strdup (data), strlen (data));
fail_unless (ges_formatter_load (formatter, timeline));
TIMELINE_BEGIN (expected) {
TRACK (GES_TRACK_TYPE_AUDIO, "audio/x-raw");
SIMPLE_LAYER_BEGIN (0) {
SIMPLE_LAYER_OBJECT ((GES_TYPE_TIMELINE_TEST_SOURCE), -1,
"duration", (guint64) 2 * GST_SECOND);
SIMPLE_LAYER_OBJECT ((GES_TYPE_TIMELINE_STANDARD_TRANSITION), -1,
"duration", (guint64) GST_SECOND / 2,
"vtype", GES_VIDEO_STANDARD_TRANSITION_TYPE_BAR_WIPE_LR);
SIMPLE_LAYER_OBJECT ((GES_TYPE_TIMELINE_TEST_SOURCE), -1,
"duration", (guint64) 2 * GST_SECOND);
} LAYER_END;
LAYER_BEGIN (1) {
LAYER_OBJECT (GES_TYPE_TIMELINE_TITLE_SOURCE,
"start", (guint64) 5 * GST_SECOND,
"duration", (guint64) GST_SECOND, "priority", 2, "text",
"the quick brown fox");
} LAYER_END;
} TIMELINE_END;
TIMELINE_COMPARE (timeline, expected);
/* tear-down */
g_object_unref (formatter);
g_object_unref (timeline);
g_object_unref (expected);
}
GST_END_TEST;
GST_START_TEST (test_pitivi_file_load)
{
GESFormatter *formatter;
GESTimeline *timeline, *expected;
GMainLoop *mainloop;
gchar *uri, *save_uri, *cur_dir;
/*create the expected timeline */
timeline = ges_timeline_new ();
mainloop = g_main_loop_new (NULL, FALSE);
expected = ges_timeline_new ();
/* create the timeline from formatter */
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
cur_dir = g_get_current_dir ();
uri = g_build_filename (cur_dir, "test.xptv", NULL);
save_uri = g_build_filename (cur_dir, "testsave.xptv", NULL);
g_free (cur_dir);
if (g_file_test (uri, G_FILE_TEST_EXISTS) == FALSE) {
GST_ERROR ("Could not test GESPitiviFormatter as no project file found");
return;
}
ges_formatter_load_from_uri (formatter, timeline, uri, NULL);
g_timeout_add (1000, (GSourceFunc) g_main_loop_quit, mainloop);
g_main_loop_run (mainloop);
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
ges_formatter_save_to_uri (formatter, timeline, save_uri, NULL);
formatter = GES_FORMATTER (ges_pitivi_formatter_new ());
ges_formatter_load_from_uri (formatter, expected, uri, NULL);
g_timeout_add (1000, (GSourceFunc) g_main_loop_quit, mainloop);
g_main_loop_run (mainloop);
/* compare the two timelines and fail test if they are different */
TIMELINE_COMPARE (expected, timeline);
g_free (uri);
g_free (save_uri);
g_main_loop_unref (mainloop);
g_object_unref (formatter);
g_object_unref (timeline);
g_object_unref (expected);
}
GST_END_TEST;
GST_START_TEST (test_keyfile_identity)
{
/* we will create several timelines. they will first be serialized, then
* deseriailzed and compared against the original. */
GESTimeline *orig = NULL, *serialized = NULL;
GESFormatter *formatter;
ges_init ();
formatter = GES_FORMATTER (ges_keyfile_formatter_new ());
TIMELINE_BEGIN (orig) {
TRACK (GES_TRACK_TYPE_AUDIO, "audio/x-raw,"
"format=(string)" GST_AUDIO_NE (S32) ",rate=8000");
TRACK (GES_TRACK_TYPE_VIDEO, "video/x-raw,format=(string)RGB24");
LAYER_BEGIN (5) {
LAYER_OBJECT (GES_TYPE_TIMELINE_TEXT_OVERLAY,
"start", (guint64) GST_SECOND,
"duration", (guint64) 2 * GST_SECOND,
"priority", 1,
"text", "Hello, world!",
"font-desc", "Sans 9",
"halignment", GES_TEXT_HALIGN_LEFT,
"valignment", GES_TEXT_VALIGN_TOP);
LAYER_OBJECT (GES_TYPE_TIMELINE_TEST_SOURCE,
"start", (guint64) 0,
"duration", (guint64) 5 * GST_SECOND,
"priority", 2,
"freq", (gdouble) 500,
"volume", 1.0, "vpattern", GES_VIDEO_TEST_PATTERN_WHITE);
LAYER_OBJECT (GES_TYPE_TIMELINE_TEXT_OVERLAY,
"start", (guint64) 7 * GST_SECOND,
"duration", (guint64) 2 * GST_SECOND,
"priority", 2,
"text", "Hello, world!",
"font-desc", "Sans 9",
"halignment", GES_TEXT_HALIGN_LEFT,
"valignment", GES_TEXT_VALIGN_TOP);
LAYER_OBJECT (GES_TYPE_TIMELINE_TEST_SOURCE,
"start", (guint64) 6 * GST_SECOND,
"duration", (guint64) 5 * GST_SECOND,
"priority", 3,
"freq", (gdouble) 600,
"volume", 1.0, "vpattern", GES_VIDEO_TEST_PATTERN_RED);
}
LAYER_END;
}
TIMELINE_END;
serialized = ges_timeline_new ();
ges_formatter_save (formatter, orig);
ges_formatter_load (formatter, serialized);
TIMELINE_COMPARE (serialized, orig);
g_object_unref (formatter);
g_object_unref (serialized);
g_object_unref (orig);
}
GST_END_TEST;
static Suite *
ges_suite (void)
{
Suite *s = suite_create ("ges-save-load");
TCase *tc_chain = tcase_create ("basic");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_simple);
tcase_add_test (tc_chain, test_keyfile_save);
tcase_add_test (tc_chain, test_keyfile_load);
tcase_add_test (tc_chain, test_keyfile_identity);
tcase_add_test (tc_chain, test_pitivi_file_load);
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = ges_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}

View file

@ -1377,6 +1377,8 @@ fail:
static gboolean
load_file_async (App * app)
{
#if 0
GESFormatter *formatter;
g_printf ("%s\n", app->pending_uri);
@ -1386,6 +1388,9 @@ load_file_async (App * app)
g_free (app->pending_uri);
app->pending_uri = NULL;
#endif
GST_FIXME ("This should be reimplemented");
return FALSE;
}