gstreamer/ges/ges-pitivi-formatter.c
Mathieu Duponchelle c7a984824f ges: Implement a Pitivi Formatter
API: ges_pitivi_formatter_new
2012-01-11 11:56:14 -03:00

1018 lines
32 KiB
C

#include <ges/ges.h>
#include <unistd.h>
#define GetCurrentDir getcwd
G_DEFINE_TYPE (GESPitiviFormatter, ges_pitivi_formatter, GES_TYPE_FORMATTER);
static gboolean save_pitivi_timeline_to_uri (GESFormatter * pitivi_formatter,
GESTimeline * timeline, const gchar * uri);
static gboolean load_pitivi_file_from_uri (GESFormatter * self,
GESTimeline * timeline, const gchar * uri);
static void ges_pitivi_formatter_finalize (GObject * object);
static xmlDocPtr create_doc (const gchar * uri);
static GHashTable *get_nodes_infos (xmlNodePtr nodes);
static gboolean create_tracks (GESFormatter * self);
static GHashTable *list_sources (GESFormatter * self);
static gboolean parse_track_objects (GESFormatter * self);
static gboolean parse_timeline_objects (GESFormatter * self);
static void save_tracks (GESTimeline * timeline, xmlTextWriterPtr writer,
GList * source_list);
static GList *save_sources (GESTimelineLayer * layer, xmlTextWriterPtr writer);
static void save_track_objects (xmlTextWriterPtr writer, GList * source_list,
gchar * res, gint * id);
static void save_timeline_objects (xmlTextWriterPtr writer, GList * list);
static void destroy_all (GList * list);
static void create_new_source_table (gchar * key, gchar * value,
GHashTable * table);
static gboolean make_timeline_objects (GESFormatter * self);
void set_properties (GObject * obj, GHashTable * props_table);
void make_source (GList * ref_list,
GHashTable * source_table, GESFormatter * self);
void layers_table_destroyer (gpointer data, gpointer data2, void *unused);
void list_table_destroyer (gpointer data, gpointer data2, void *unused);
void destroyer (gpointer data, gpointer data2, void *unused);
void ultimate_table_destroyer (gpointer data, gpointer data2, void *unused);
static void
track_object_added_cb (GESTimelineObject * object,
GESTrackObject * track_object, GHashTable * props_table);
struct _GESPitiviFormatterPrivate
{
gint not_done;
xmlXPathContextPtr xpathCtx;
GHashTable *source_table, *track_objects_table, *timeline_objects_table,
*layers_table;
GESTimeline *timeline;
gboolean parsed;
GESTrack *tracka, *trackv;
GESTimelineTestSource *background;
};
static void
ges_pitivi_formatter_class_init (GESPitiviFormatterClass * klass)
{
GESFormatterClass *formatter_klass;
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
formatter_klass = GES_FORMATTER_CLASS (klass);
g_type_class_add_private (klass, sizeof (GESPitiviFormatterPrivate));
formatter_klass->save_to_uri = save_pitivi_timeline_to_uri;
formatter_klass->load_from_uri = load_pitivi_file_from_uri;
object_class->finalize = ges_pitivi_formatter_finalize;
}
static void
ges_pitivi_formatter_init (GESPitiviFormatter * self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
GES_TYPE_PITIVI_FORMATTER, GESPitiviFormatterPrivate);
self->priv->not_done = 0;
self->priv->track_objects_table =
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
self->priv->timeline_objects_table =
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
self->priv->layers_table =
g_hash_table_new_full (g_int_hash, g_str_equal, NULL, NULL);
self->priv->parsed = FALSE;
}
static void
ges_pitivi_formatter_finalize (GObject * object)
{
GESPitiviFormatter *self = GES_PITIVI_FORMATTER (object);
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
g_hash_table_foreach (priv->source_table, (GHFunc) ultimate_table_destroyer,
NULL);
g_hash_table_destroy (priv->source_table);
g_hash_table_foreach (priv->timeline_objects_table,
(GHFunc) list_table_destroyer, NULL);
g_hash_table_destroy (priv->timeline_objects_table);
g_hash_table_foreach (priv->layers_table, (GHFunc) layers_table_destroyer,
NULL);
g_hash_table_destroy (priv->layers_table);
g_hash_table_foreach (priv->track_objects_table,
(GHFunc) ultimate_table_destroyer, NULL);
g_hash_table_destroy (priv->track_objects_table);
G_OBJECT_CLASS (ges_pitivi_formatter_parent_class)->finalize (object);
}
static gboolean
save_pitivi_timeline_to_uri (GESFormatter * pitivi_formatter,
GESTimeline * timeline, const gchar * uri)
{
xmlTextWriterPtr writer;
GList *list = NULL, *layers = NULL, *tmp = NULL;
writer = xmlNewTextWriterFilename (uri, 0);
xmlTextWriterSetIndent (writer, 1);
xmlTextWriterStartElement (writer, BAD_CAST "pitivi");
layers = ges_timeline_get_layers (timeline);
xmlTextWriterStartElement (writer, BAD_CAST "factories");
xmlTextWriterStartElement (writer, BAD_CAST "sources");
for (tmp = layers; tmp; tmp = tmp->next) {
/* 99 is the priority of the background source. */
if (ges_timeline_layer_get_priority (tmp->data) != 99) {
list = save_sources (tmp->data, writer);
}
}
xmlTextWriterEndElement (writer);
xmlTextWriterEndElement (writer);
save_tracks (timeline, writer, list);
save_timeline_objects (writer, list);
xmlTextWriterEndDocument (writer);
xmlFreeTextWriter (writer);
g_list_free (layers);
g_list_foreach (list, (GFunc) destroy_all, NULL);
g_list_free (list);
return TRUE;
}
static gboolean
load_pitivi_file_from_uri (GESFormatter * self,
GESTimeline * timeline, const gchar * uri)
{
xmlDocPtr doc;
GESTimelineLayer *layer;
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
gboolean ret = TRUE;
gint *prio = malloc (sizeof (gint));
*prio = 0;
layer = ges_timeline_layer_new ();
g_object_set (layer, "auto-transition", TRUE, NULL);
g_hash_table_insert (priv->layers_table, prio, layer);
priv->timeline = timeline;
g_object_set (layer, "priority", (gint32) 0, NULL);
if (!ges_timeline_add_layer (timeline, layer)) {
GST_ERROR ("Couldn't add layer");
return FALSE;
}
if (!(doc = create_doc (uri))) {
GST_ERROR ("The xptv file for uri %s was badly formed or did not exist",
uri);
return FALSE;
}
priv->xpathCtx = xmlXPathNewContext (doc);
if (!create_tracks (self)) {
GST_ERROR ("Couldn't create tracks");
ret = FALSE;
goto fail;
}
priv->source_table = list_sources (self);
if (!parse_timeline_objects (self)) {
GST_ERROR ("Couldn't find timeline objects markup in the xptv file");
ret = FALSE;
goto fail;
}
if (!parse_track_objects (self)) {
GST_ERROR ("Couldn't find track objects markup in the xptv file");
ret = FALSE;
}
if (!make_timeline_objects (self))
ret = FALSE;
fail:
xmlXPathFreeContext (priv->xpathCtx);
xmlFreeDoc (doc);
return ret;
}
static void
save_timeline_objects (xmlTextWriterPtr writer, GList * list)
{
GList *tmp;
gint n_objects, i;
xmlTextWriterStartElement (writer, BAD_CAST "timeline-objects");
for (tmp = list; tmp; tmp = tmp->next) {
GList *elem;
xmlChar *cast;
xmlTextWriterStartElement (writer, BAD_CAST "timeline-object");
elem = tmp->data;
xmlTextWriterStartElement (writer, BAD_CAST "factory-ref");
cast = g_list_first (elem)->data;
xmlTextWriterWriteAttribute (writer, BAD_CAST "id", BAD_CAST cast);
xmlTextWriterEndElement (writer);
xmlTextWriterStartElement (writer, BAD_CAST "track-object-refs");
n_objects = g_list_length (elem) - 4;
for (i = 0; i < n_objects; i++) {
xmlTextWriterStartElement (writer, BAD_CAST "track-object-ref");
xmlTextWriterWriteAttribute (writer, BAD_CAST "id",
BAD_CAST (gchar *) (g_list_nth (elem, (guint) 4 + i)->data));
xmlTextWriterEndElement (writer);
}
xmlTextWriterEndElement (writer);
xmlTextWriterEndElement (writer);
}
xmlTextWriterEndElement (writer);
}
static GList *
save_sources (GESTimelineLayer * layer, xmlTextWriterPtr writer)
{
GList *objects, *tmp;
GHashTable *source_table;
GList *source_list = NULL;
int id = 1;
objects = ges_timeline_layer_get_objects (layer);
source_table =
g_hash_table_new_full (g_str_hash, g_int_equal, g_free, g_free);
for (tmp = objects; tmp; tmp = tmp->next) {
GList *ref_type_list = NULL;
GESTimelineObject *object;
gchar *tfs_uri;
xmlChar *cast;
object = tmp->data;
if GES_IS_TIMELINE_FILE_SOURCE
(object) {
tfs_uri = (gchar *) ges_timeline_filesource_get_uri
(GES_TIMELINE_FILE_SOURCE (object));
if (!g_hash_table_lookup (source_table, tfs_uri)) {
cast = xmlXPathCastNumberToString (id);
g_hash_table_insert (source_table, g_strdup (tfs_uri),
g_strdup ((gchar *) cast));
xmlFree (cast);
xmlTextWriterStartElement (writer, BAD_CAST "source");
xmlTextWriterWriteAttribute (writer, BAD_CAST "filename",
BAD_CAST tfs_uri);
cast = xmlXPathCastNumberToString (id);
xmlTextWriterWriteAttribute (writer, BAD_CAST "id", BAD_CAST cast);
xmlFree (cast);
xmlTextWriterEndElement (writer);
id++;
}
ref_type_list =
g_list_append (ref_type_list,
g_strdup (g_hash_table_lookup (source_table, tfs_uri)));
ref_type_list = g_list_append (ref_type_list, object);
ref_type_list = g_list_append (ref_type_list, g_strdup ("simple"));
ref_type_list =
g_list_append (ref_type_list,
GINT_TO_POINTER (ges_timeline_layer_get_priority (layer)));
source_list = g_list_append (source_list, g_list_copy (ref_type_list));
g_list_free (ref_type_list);
}
}
g_object_unref (G_OBJECT (layer));
g_list_free (objects);
g_hash_table_destroy (source_table);
return source_list;
}
static void
save_tracks (GESTimeline * timeline, xmlTextWriterPtr writer,
GList * source_list)
{
GList *tracks, *tmp;
gint id = 0;
xmlTextWriterStartElement (writer, BAD_CAST "timeline");
xmlTextWriterStartElement (writer, BAD_CAST "tracks");
tracks = ges_timeline_get_tracks (timeline);
for (tmp = tracks; tmp; tmp = tmp->next) {
gchar *type, *caps, *res;
GESTrack *track;
GValue v = { 0 };
track = GES_TRACK (tmp->data);
xmlTextWriterStartElement (writer, BAD_CAST "track");
xmlTextWriterStartElement (writer, BAD_CAST "stream");
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));
xmlTextWriterWriteAttribute (writer, BAD_CAST "caps", BAD_CAST caps);
g_free (caps);
if (!g_strcmp0 (type, "GES_TRACK_TYPE_AUDIO")) {
xmlTextWriterWriteAttribute (writer, BAD_CAST "type",
BAD_CAST "pitivi.stream.AudioStream");
xmlTextWriterEndElement (writer);
res = (gchar *) "audio";
} else {
xmlTextWriterWriteAttribute (writer, BAD_CAST "type",
BAD_CAST "pitivi.stream.VideoStream");
xmlTextWriterEndElement (writer);
res = (gchar *) "video";
}
g_free (type);
save_track_objects (writer, source_list, res, &id);
xmlTextWriterEndElement (writer);
}
g_list_free (tracks);
xmlTextWriterEndElement (writer);
}
static void
save_track_objects (xmlTextWriterPtr writer, GList * source_list, gchar * res,
gint * id)
{
GList *tmp, *tck_objs, *tmp_tck;
gchar *bin_desc;
xmlTextWriterStartElement (writer, BAD_CAST "track-objects");
for (tmp = source_list; tmp; tmp = tmp->next) {
GList *elem;
GESTimelineObject *object;
guint i, n, j;
elem = tmp->data;
object = g_list_next (elem)->data;
tck_objs = ges_timeline_object_get_track_objects (object);
for (tmp_tck = tck_objs; tmp_tck; tmp_tck = tmp_tck->next) {
GParamSpec **properties;
xmlChar *cast;
gchar *prio_str;
if (!ges_track_object_is_active (tmp_tck->data)) {
continue;
}
if (((ges_track_object_get_track (tmp_tck->data)->type ==
GES_TRACK_TYPE_VIDEO)
&& (!g_strcmp0 (res, (gchar *) "video")))
|| ((ges_track_object_get_track (tmp_tck->data)->type ==
GES_TRACK_TYPE_AUDIO)
&& (!g_strcmp0 (res, (gchar *) "audio")))) {
} else {
continue;
}
xmlTextWriterStartElement (writer, BAD_CAST "track-object");
cast =
xmlXPathCastNumberToString (GPOINTER_TO_INT (g_list_nth (elem,
(guint) 3)->data));
prio_str = g_strconcat ((gchar *) "(int)", (gchar *) cast, NULL);
xmlFree (cast);
xmlTextWriterWriteAttribute (writer, BAD_CAST "priority",
BAD_CAST prio_str);
g_free (prio_str);
properties =
g_object_class_list_properties (G_OBJECT_GET_CLASS (tmp_tck->data),
&n);
for (i = 0; i < n; i++) {
GParamSpec *p = properties[i];
GValue v = { 0 };
gchar *serialized, *concatenated;
if (!g_strcmp0 (p->name, (gchar *) "duration") ||
!g_strcmp0 (p->name, (gchar *) "start") ||
!g_strcmp0 (p->name, (gchar *) "in-point")) {
g_value_init (&v, p->value_type);
g_object_get_property (G_OBJECT (tmp_tck->data), p->name, &v);
serialized = gst_value_serialize (&v);
concatenated = g_strconcat ((gchar *) "(gint64)", serialized, NULL);
if (!g_strcmp0 (p->name, (gchar *) "in-point")) {
xmlTextWriterWriteAttribute (writer, BAD_CAST (gchar *) "in_point",
BAD_CAST concatenated);
} else {
xmlTextWriterWriteAttribute (writer, BAD_CAST p->name,
BAD_CAST concatenated);
}
g_free (concatenated);
g_free (serialized);
}
}
g_free (properties);
cast = xmlXPathCastNumberToString (*id);
xmlTextWriterWriteAttribute (writer, BAD_CAST "id", BAD_CAST cast);
xmlFree (cast);
if (GES_IS_TRACK_EFFECT (tmp_tck->data)) {
GParamSpec **pspecs, *spec;
gchar *serialized, *concatenated;
guint n_props = 0;
g_object_get (tmp_tck->data, "bin-description", &bin_desc, NULL);
xmlTextWriterStartElement (writer, BAD_CAST "effect");
xmlTextWriterStartElement (writer, BAD_CAST "factory");
xmlTextWriterWriteAttribute (writer, BAD_CAST "name",
BAD_CAST bin_desc);
xmlTextWriterEndElement (writer);
xmlTextWriterStartElement (writer, BAD_CAST "gst-element-properties");
pspecs =
ges_track_object_list_children_properties (tmp_tck->data, &n_props);
j = 0;
while (j < n_props) {
GValue val = { 0 };
spec = pspecs[j];
g_value_init (&val, spec->value_type);
ges_track_object_get_child_property_by_pspec (tmp_tck->data, spec,
&val);
serialized = gst_value_serialize (&val);
if (!g_strcmp0 (spec->name, (gchar *) "preset")) {
concatenated =
g_strconcat ("(GEnum)",
xmlXPathCastNumberToString ((g_value_get_enum (&val))), NULL);
xmlTextWriterWriteAttribute (writer, BAD_CAST spec->name,
BAD_CAST concatenated);
} else {
concatenated =
g_strconcat ("(", g_type_name (spec->value_type), ")",
serialized, NULL);
xmlTextWriterWriteAttribute (writer, BAD_CAST spec->name,
BAD_CAST concatenated);
}
j++;
}
xmlTextWriterEndElement (writer);
for (i = 0; i < n_props; i++) {
g_param_spec_unref (pspecs[i]);
}
g_free (pspecs);
} else {
xmlTextWriterStartElement (writer, BAD_CAST "factory-ref");
cast = g_list_first (elem)->data;
xmlTextWriterWriteAttribute (writer, BAD_CAST "id", BAD_CAST cast);
}
xmlTextWriterEndElement (writer);
xmlTextWriterEndElement (writer);
if (GES_IS_TRACK_EFFECT (tmp_tck->data)) {
elem = g_list_append (elem, xmlXPathCastNumberToString (*id));
} else {
elem = g_list_insert (elem, xmlXPathCastNumberToString (*id), 4);
}
*id = *id + 1;
}
}
xmlTextWriterEndElement (writer);
}
static xmlDocPtr
create_doc (const gchar * uri)
{
xmlDocPtr doc;
doc = xmlParseFile (uri);
return doc;
}
static GHashTable *
list_sources (GESFormatter * self)
{
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
xmlXPathObjectPtr xpathObj;
GHashTable *table, *sources_table;
int size, j;
gchar *id;
xmlNodeSetPtr nodes;
sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
xpathObj = xmlXPathEvalExpression ((const xmlChar *)
"/pitivi/factories/sources/source", priv->xpathCtx);
nodes = xpathObj->nodesetval;
size = (nodes) ? nodes->nodeNr : 0;
for (j = 0; j < size; ++j) {
table = get_nodes_infos (nodes->nodeTab[j]);
id = (gchar *) g_hash_table_lookup (table, (gchar *) "id");
g_hash_table_insert (sources_table, g_strdup (id), table);
}
xmlXPathFreeObject (xpathObj);
return sources_table;
}
static gboolean
make_timeline_objects (GESFormatter * self)
{
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
GHashTable *source_table;
GESTimelineLayer *back_layer;
gint i;
gint *prio = malloc (sizeof (gint));
GList *keys = NULL, *tmp = NULL, *ref_list = NULL;
*prio = 0;
priv->background = ges_timeline_test_source_new ();
back_layer = ges_timeline_layer_new ();
ges_timeline_layer_set_priority (back_layer, 99);
if (!ges_timeline_add_layer (priv->timeline, back_layer)) {
GST_ERROR ("Couldn't add layer");
return FALSE;
}
if (!ges_timeline_layer_add_object (back_layer,
GES_TIMELINE_OBJECT (priv->background))) {
GST_ERROR ("Couldn't add background to the layer");
return FALSE;
}
keys = g_hash_table_get_keys (priv->timeline_objects_table);
for (tmp = keys, i = 1; tmp; tmp = tmp->next, i++) {
if (i == g_list_length (keys))
priv->parsed = TRUE;
ref_list =
g_hash_table_lookup (priv->timeline_objects_table, (gchar *) tmp->data);
source_table =
g_hash_table_lookup (priv->source_table, (gchar *) tmp->data);
make_source (ref_list, source_table, self);
}
g_hash_table_insert (priv->layers_table, prio, back_layer);
free (prio);
g_list_free (keys);
return TRUE;
}
void
make_source (GList * ref_list, GHashTable * source_table, GESFormatter * self)
{
GHashTable *props_table, *effect_table;
gchar **prio_array;
GESTimelineLayer *layer;
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
gchar *fac_ref = NULL, *media_type = NULL, *filename = NULL;
GList *tmp = NULL, *keys, *tmp_key;
GESTimelineFileSource *src = NULL;
gint cast_prio = 0;
gint *prio = malloc (sizeof (gint));
gboolean a_avail = FALSE, v_avail = FALSE, video = FALSE;
for (tmp = ref_list; tmp; tmp = tmp->next) {
props_table =
g_hash_table_lookup (priv->track_objects_table, (gchar *) tmp->data);
prio_array =
g_strsplit ((gchar *) g_hash_table_lookup (props_table,
(gchar *) "priority"), ")", 0);
cast_prio = (gint) g_ascii_strtod (prio_array[1], NULL);
*prio = cast_prio;
fac_ref = (gchar *) g_hash_table_lookup (props_table, (gchar *) "fac_ref");
media_type =
(gchar *) g_hash_table_lookup (props_table, (gchar *) "media_type");
g_strfreev (prio_array);
if (!g_strcmp0 (media_type, (gchar *) "pitivi.stream.VideoStream"))
video = TRUE;
else
video = FALSE;
if (!(layer = g_hash_table_lookup (priv->layers_table, &cast_prio))) {
layer = ges_timeline_layer_new ();
g_object_set (layer, "auto-transition", TRUE, NULL);
ges_timeline_layer_set_priority (layer, cast_prio);
ges_timeline_add_layer (priv->timeline, layer);
g_hash_table_insert (priv->layers_table, prio, layer);
free (prio);
}
if (g_strcmp0 (fac_ref, (gchar *) "effect") && a_avail && (!video)) {
a_avail = FALSE;
g_signal_connect (src, "track-object-added",
G_CALLBACK (track_object_added_cb), props_table);
} else if (g_strcmp0 (fac_ref, (gchar *) "effect") && v_avail && (video)) {
v_avail = FALSE;
g_signal_connect (src, "track-object-added",
G_CALLBACK (track_object_added_cb), props_table);
} else if (g_strcmp0 (fac_ref, (gchar *) "effect")) {
char cCurrentPath[FILENAME_MAX], *path;
if (a_avail) {
ges_timeline_filesource_set_supported_formats (src,
GES_TRACK_TYPE_VIDEO);
} else if (v_avail) {
ges_timeline_filesource_set_supported_formats (src,
GES_TRACK_TYPE_AUDIO);
}
filename =
(gchar *) g_hash_table_lookup (source_table, (gchar *) "filename");
path = GetCurrentDir (cCurrentPath, sizeof (cCurrentPath));
if (!g_strcmp0 (filename, (gchar *) "/DJ5r3oNFVeE.flv") ||
!g_strcmp0 (filename, (gchar *) "/a1Y73sPHKxw.flv")) {
filename = g_strconcat ("file://", path, filename, NULL);
src = ges_timeline_filesource_new (filename);
g_free (filename);
} else {
src = ges_timeline_filesource_new (filename);
}
if (!video) {
v_avail = TRUE;
a_avail = FALSE;
} else {
a_avail = TRUE;
v_avail = FALSE;
}
set_properties (G_OBJECT (src), props_table);
ges_timeline_layer_add_object (layer, GES_TIMELINE_OBJECT (src));
} else if (!g_strcmp0 (fac_ref, (gchar *) "effect")) {
GESTrackParseLaunchEffect *effect;
gchar *active = (gchar *)
g_hash_table_lookup (props_table, (gchar *) "active");
effect = ges_track_parse_launch_effect_new ((gchar *)
g_hash_table_lookup (props_table, (gchar *) "effect_name"));
effect_table =
g_hash_table_lookup (props_table, (gchar *) "effect_props");
ges_timeline_object_add_track_object (GES_TIMELINE_OBJECT (src),
GES_TRACK_OBJECT (effect));
if (!g_strcmp0 (active, (gchar *) "(bool)False"))
ges_track_object_set_active (GES_TRACK_OBJECT (effect), FALSE);
if (video)
ges_track_add_object (priv->trackv, GES_TRACK_OBJECT (effect));
else
ges_track_add_object (priv->tracka, GES_TRACK_OBJECT (effect));
keys = g_hash_table_get_keys (effect_table);
for (tmp_key = keys; tmp_key; tmp_key = tmp_key->next) {
gchar **value_array =
g_strsplit ((gchar *) g_hash_table_lookup (effect_table,
(gchar *) tmp_key->data),
(gchar *) ")", (gint) 0);
gchar *value = g_ascii_strdown (value_array[1], -1);
if (!g_strcmp0 (value, (gchar *) "true"))
ges_track_object_set_child_property (GES_TRACK_OBJECT (effect),
(gchar *) tmp_key->data, TRUE, NULL);
else if (!g_strcmp0 (value, (gchar *) "false"))
ges_track_object_set_child_property (GES_TRACK_OBJECT (effect),
(gchar *) tmp_key->data, FALSE, NULL);
else if (!g_strcmp0 (value, (gchar *) "effect"))
continue;
else if (!g_strcmp0 ((gchar *) "(guint", value_array[0])
|| !g_strcmp0 ((gchar *) "(GEnum", value_array[0])
|| !g_strcmp0 ((gchar *) "(gint", value_array[0]))
ges_track_object_set_child_property (GES_TRACK_OBJECT (effect),
(gchar *) tmp_key->data, g_ascii_strtoll (value, NULL, 0), NULL);
else
ges_track_object_set_child_property (GES_TRACK_OBJECT (effect),
(gchar *) tmp_key->data, g_ascii_strtod (value, NULL), NULL);
}
}
}
if (a_avail) {
ges_timeline_filesource_set_supported_formats (src, GES_TRACK_TYPE_VIDEO);
} else if (v_avail) {
ges_timeline_filesource_set_supported_formats (src, GES_TRACK_TYPE_AUDIO);
}
free (prio);
}
void
set_properties (GObject * obj, GHashTable * props_table)
{
gint i;
gchar **prop_array;
gint64 prop_value;
gchar list[3][10] = { "duration", "in_point", "start" };
for (i = 0; i < 3; i++) {
prop_array =
g_strsplit ((gchar *) g_hash_table_lookup (props_table, list[i]),
(gchar *) ")", (gint) 0);
prop_value = g_ascii_strtoll ((gchar *) prop_array[1], NULL, 0);
g_object_set (obj, list[i], prop_value, NULL);
g_strfreev (prop_array);
}
}
static gboolean
parse_track_objects (GESFormatter * self)
{
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
int size, j;
gchar *id, *fac_ref;
GHashTable *table = NULL, *new_table, *effect_table;
xmlNode *ref_node;
gchar *media_type;
xpathObj = xmlXPathEvalExpression ((const xmlChar *)
"/pitivi/timeline/tracks/track/track-objects/track-object",
priv->xpathCtx);
if (xpathObj == NULL) {
xmlXPathFreeObject (xpathObj);
return FALSE;
}
nodes = xpathObj->nodesetval;
size = (nodes) ? nodes->nodeNr : 0;
for (j = 0; j < size; ++j) {
GHashTable *new_effect_table = NULL;
table = get_nodes_infos (nodes->nodeTab[j]);
id = (gchar *) g_hash_table_lookup (table, (gchar *) "id");
ref_node = nodes->nodeTab[j]->children->next;
fac_ref = (gchar *) xmlGetProp (ref_node, (xmlChar *) "id");
new_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
if (!g_strcmp0 ((gchar *) ref_node->name, (gchar *) "effect")) {
fac_ref = (gchar *) "effect";
ref_node = ref_node->children->next;
new_effect_table =
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
g_hash_table_insert (table, g_strdup ((gchar *) "effect_name"),
g_strdup ((gchar *) xmlGetProp (ref_node, (xmlChar *) "name")));
effect_table = get_nodes_infos (ref_node->next->next);
g_hash_table_foreach (effect_table, (GHFunc) create_new_source_table,
new_effect_table);
}
g_hash_table_insert (table, g_strdup ((gchar *) "fac_ref"),
g_strdup (fac_ref));
media_type =
(gchar *) xmlGetProp (nodes->nodeTab[j]->parent->prev->prev,
(xmlChar *) "type");
g_hash_table_insert (table, g_strdup ((gchar *) "media_type"),
g_strdup (media_type));
g_hash_table_foreach (table, (GHFunc) create_new_source_table, new_table);
if (new_effect_table) {
g_hash_table_insert (new_table, (gchar *) "effect_props",
new_effect_table);
}
g_hash_table_insert (priv->track_objects_table, g_strdup (id), new_table);
xmlFree (media_type);
if (g_strcmp0 (fac_ref, (gchar *) "effect")) {
xmlFree (fac_ref);
}
g_hash_table_foreach (table, (GHFunc) destroyer, NULL);
g_hash_table_destroy (table);
}
xmlXPathFreeObject (xpathObj);
return TRUE;
}
static gboolean
parse_timeline_objects (GESFormatter * self)
{
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
xmlXPathObjectPtr xpathObj;
xmlNodeSetPtr nodes;
int size, j;
gchar *id, *ref;
xmlChar *refxml;
GList *ref_list = NULL, *tmp_list = NULL, *tmp = NULL;
xmlNode *cur_node = NULL;
xpathObj = xmlXPathEvalExpression ((const xmlChar *)
"/pitivi/timeline/timeline-objects/timeline-object/factory-ref",
priv->xpathCtx);
if (xpathObj == NULL) {
xmlXPathFreeObject (xpathObj);
return FALSE;
}
nodes = xpathObj->nodesetval;
size = (nodes) ? nodes->nodeNr : 0;
for (j = 0; j < size; ++j) {
cur_node = nodes->nodeTab[j];
id = (gchar *) xmlGetProp (cur_node, (xmlChar *) "id");
cur_node = cur_node->next->next->children->next;
ref_list = NULL;
for (cur_node = cur_node; cur_node; cur_node = cur_node->next->next) {
refxml = xmlGetProp (cur_node, (xmlChar *) "id");
ref = (gchar *) refxml;
ref_list = g_list_append (ref_list, g_strdup (ref));
xmlFree (refxml);
}
tmp_list = g_hash_table_lookup (priv->timeline_objects_table, id);
if (tmp_list != NULL) {
for (tmp = tmp_list; tmp; tmp = tmp->next) {
ref_list = g_list_append (ref_list, tmp->data);
}
}
g_hash_table_insert (priv->timeline_objects_table, g_strdup (id),
g_list_copy (ref_list));
xmlFree (id);
g_list_free (ref_list);
g_list_free (tmp_list);
g_list_free (tmp);
}
xmlXPathFreeObject (xpathObj);
return TRUE;
}
static void
create_new_source_table (gchar * key, gchar * value, GHashTable * table)
{
g_hash_table_insert (table, g_strdup (key), g_strdup (value));
}
static gboolean
create_tracks (GESFormatter * self)
{
GESPitiviFormatterPrivate *priv = GES_PITIVI_FORMATTER (self)->priv;
GList *tracks = NULL;
tracks = ges_timeline_get_tracks (priv->timeline);
if (g_list_length (tracks)) {
GList *tmp = NULL;
GESTrack *track;
for (tmp = tracks; tmp; tmp = tmp->next) {
track = tmp->data;
if (track->type == GES_TRACK_TYPE_AUDIO) {
priv->tracka = track;
} else {
priv->trackv = track;
}
}
g_list_free (tracks);
return TRUE;
}
priv->tracka = ges_track_audio_raw_new ();
priv->trackv = ges_track_video_raw_new ();
if (!ges_timeline_add_track (priv->timeline, priv->trackv)) {
return FALSE;
}
if (!ges_timeline_add_track (priv->timeline, priv->tracka)) {
return FALSE;
}
return TRUE;
}
static GHashTable *
get_nodes_infos (xmlNodePtr node)
{
xmlAttr *cur_attr;
GHashTable *props_table;
gchar *name, *value;
props_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
for (cur_attr = node->properties; cur_attr; cur_attr = cur_attr->next) {
name = (gchar *) cur_attr->name;
value = (gchar *) xmlGetProp (node, cur_attr->name);
g_hash_table_insert (props_table, g_strdup (name), g_strdup (value));
xmlFree (value);
}
return props_table;
}
static void
destroy_all (GList * list)
{
g_free (g_list_nth (list, (guint) 2)->data);
g_object_unref (G_OBJECT (g_list_nth (list, (guint) 1)->data));
g_free (g_list_nth (list, (guint) 3)->data);
if (g_list_length (list) == 6) {
g_free (g_list_nth (list, (guint) 5)->data);
}
g_free (g_list_nth (list, (guint) 0)->data);
g_list_free (list);
}
static void
track_object_added_cb (GESTimelineObject * object,
GESTrackObject * track_object, GHashTable * props_table)
{
gchar *media_type = NULL;
GList *tck_objs = NULL, *tmp = NULL;
GESTrack *object_track;
gint64 start, duration;
gboolean has_effect = FALSE;
gint type = 0;
tck_objs = ges_timeline_object_get_track_objects (object);
media_type =
(gchar *) g_hash_table_lookup (props_table, (gchar *) "media_type");
for (tmp = tck_objs; tmp; tmp = tmp->next) {
object_track = ges_track_object_get_track (tmp->data);
if (GES_IS_TRACK_PARSE_LAUNCH_EFFECT (tmp->data)) {
has_effect = TRUE;
continue;
}
if ((!g_strcmp0 (media_type, "pitivi.stream.VideoStream")
&& object_track->type == GES_TRACK_TYPE_VIDEO)
|| (!g_strcmp0 (media_type, "pitivi.stream.AudioStream")
&& object_track->type == GES_TRACK_TYPE_AUDIO)) {
ges_track_object_set_locked (tmp->data, FALSE);
set_properties (G_OBJECT (tmp->data), props_table);
ges_track_object_set_locked (tmp->data, TRUE);
type = object_track->type;
g_object_get (tmp->data, "start", &start, "duration", &duration, NULL);
}
}
if (has_effect) {
tck_objs = ges_timeline_object_get_track_objects (object);
for (tmp = tck_objs; tmp; tmp = tmp->next) {
object_track = ges_track_object_get_track (tmp->data);
if (GES_IS_TRACK_PARSE_LAUNCH_EFFECT (tmp->data)
&& (type == object_track->type)) {
ges_track_object_set_locked (tmp->data, FALSE);
g_object_set (tmp->data, "start", start, "duration", duration, NULL);
ges_track_object_set_locked (tmp->data, TRUE);
}
}
}
}
void
ultimate_table_destroyer (gpointer data, gpointer data2, void *unused)
{
g_free (data);
g_hash_table_foreach (data2, (GHFunc) destroyer, NULL);
g_hash_table_destroy (data2);
}
void
layers_table_destroyer (gpointer data, gpointer data2, void *unused)
{
g_object_unref (data2);
g_free (data);
}
void
list_table_destroyer (gpointer data, gpointer data2, void *unused)
{
g_list_foreach (data2, (GFunc) g_free, NULL);
g_list_free (data2);
g_free (data);
}
void
destroyer (gpointer data, gpointer data2, void *unused)
{
if (!g_strcmp0 ((gchar *) data, (gchar *) "private")) {
} else if (!g_strcmp0 ((gchar *) data, (gchar *) "effect_props")) {
g_hash_table_foreach (data2, (GHFunc) destroyer, NULL);
g_hash_table_destroy (data2);
} else {
g_free (data2);
g_free (data);
}
}
GESPitiviFormatter *
ges_pitivi_formatter_new (void)
{
return g_object_new (GES_TYPE_PITIVI_FORMATTER, NULL);
}