brasero r989 - in trunk: . po src src/plugins src/plugins/cdrdao src/plugins/cdrkit src/plugins/cdrtools src/plugins/dvdauthor src/plugins/libburnia src/plugins/local-track src/plugins/transcode src/plugins/vcdimager



Author: philippr
Date: Mon Jul 14 18:07:55 2008
New Revision: 989
URL: http://svn.gnome.org/viewvc/brasero?rev=989&view=rev

Log:
Added video project branch changes

Added:
   trunk/src/brasero-video-disc.c
   trunk/src/brasero-video-disc.h
   trunk/src/brasero-video-project.c   (contents, props changed)
   trunk/src/brasero-video-project.h   (contents, props changed)
   trunk/src/brasero-video-tree-model.c   (contents, props changed)
   trunk/src/brasero-video-tree-model.h   (contents, props changed)
   trunk/src/plugins/dvdauthor/
   trunk/src/plugins/dvdauthor/Makefile.am
   trunk/src/plugins/dvdauthor/burn-dvdauthor.c   (contents, props changed)
   trunk/src/plugins/dvdauthor/burn-dvdauthor.h   (contents, props changed)
   trunk/src/plugins/transcode/burn-vob.c   (contents, props changed)
   trunk/src/plugins/transcode/burn-vob.h   (contents, props changed)
   trunk/src/plugins/vcdimager/
   trunk/src/plugins/vcdimager/Makefile.am
   trunk/src/plugins/vcdimager/burn-vcdimager.c
   trunk/src/plugins/vcdimager/burn-vcdimager.h
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/po/POTFILES.in
   trunk/src/Makefile.am
   trunk/src/brasero-dest-selection.c
   trunk/src/brasero-disc-option-dialog.c
   trunk/src/brasero-disc.h
   trunk/src/brasero-file-chooser.c
   trunk/src/brasero-io.c
   trunk/src/brasero-io.h
   trunk/src/brasero-layout.c
   trunk/src/brasero-layout.h
   trunk/src/brasero-metadata.c
   trunk/src/brasero-metadata.h
   trunk/src/brasero-multi-song-props.c
   trunk/src/brasero-multi-song-props.h
   trunk/src/brasero-project-manager.c
   trunk/src/brasero-project-manager.h
   trunk/src/brasero-project-type-chooser.c
   trunk/src/brasero-project-type-chooser.h
   trunk/src/brasero-project.c
   trunk/src/brasero-project.h
   trunk/src/brasero-song-properties.c
   trunk/src/brasero-time-button.c
   trunk/src/brasero-time-button.h
   trunk/src/burn-basics.h
   trunk/src/burn-caps.c
   trunk/src/burn-debug.c
   trunk/src/burn-job.c
   trunk/src/burn-medium.c
   trunk/src/burn-plugin-private.h
   trunk/src/burn-plugin.c
   trunk/src/burn-process.c
   trunk/src/burn-session.c
   trunk/src/burn-session.h
   trunk/src/burn-track.h
   trunk/src/plugins/Makefile.am
   trunk/src/plugins/cdrdao/burn-toc2cue.c
   trunk/src/plugins/cdrkit/burn-wodim.c
   trunk/src/plugins/cdrtools/burn-cdrecord.c
   trunk/src/plugins/libburnia/burn-libburn.c
   trunk/src/plugins/local-track/burn-local-image.c
   trunk/src/plugins/transcode/Makefile.am
   trunk/src/plugins/transcode/burn-transcode.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Jul 14 18:07:55 2008
@@ -132,6 +132,16 @@
 BRASERO_GIO_CFLAGS="$BRASERO_GIO_CFLAGS $CFLAGS"
 BRASERO_GIO_LIBS="$BRASERO_GIO_LIBS $LDFLAGS"
 
+dnl ** used by brasero and one plugin
+PKG_CHECK_MODULES(BRASERO_LIBXML, 	\
+	libxml-2.0 >= $LIBXML2_REQUIRED)
+
+AC_SUBST(BRASERO_LIBXML_CFLAGS)
+AC_SUBST(BRASERO_LIBXML_LIBS)
+
+BRASERO_LIBXML_CFLAGS="$BRASERO_LIBXML_CFLAGS $CFLAGS"
+BRASERO_LIBXML_LIBS="$BRASERO_LIBXML_LIBS $LDFLAGS"
+
 dnl ** used by brasero and all modules
 PKG_CHECK_MODULES(BRASERO_BASE, 		\
 	gconf-2.0 >= $GCONF_REQUIRED		\
@@ -151,7 +161,6 @@
 	gtk+-2.0 >= $GTK_REQUIRED		\
 	libgnome-2.0 >= $LIBGNOME_REQUIRED	\
 	libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED	\
-	libxml-2.0 >= $LIBXML2_REQUIRED	\
 	dbus-glib-1 >= $DBUS_REQUIRED)
 
 AC_SUBST(BRASERO_CFLAGS)
@@ -349,8 +358,10 @@
 src/plugins/libburnia/Makefile
 src/plugins/transcode/Makefile
 src/plugins/dvdcss/Makefile
+src/plugins/dvdauthor/Makefile
 src/plugins/checksum/Makefile
 src/plugins/local-track/Makefile
+src/plugins/vcdimager/Makefile
 po/Makefile.in
 src/Makefile
 ])

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Mon Jul 14 18:07:55 2008
@@ -102,3 +102,8 @@
 src/brasero-jacket-edit.c
 src/brasero-multi-song-props.c
 src/brasero-rename.c
+src/brasero-video-disc.c
+src/brasero-video-tree-model.c
+src/plugins/dvdauthor/burn-dvdauthor.c
+src/plugins/transcode/burn-vob.c
+src/plugins/vcdimager/burn-vcdimager.c

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Mon Jul 14 18:07:55 2008
@@ -14,7 +14,8 @@
 	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    		\
 	-DBRASERO_LIBDIR=\"$(libdir)\"  	         		\
 	$(DISABLE_DEPRECATED)						\
-	$(BRASERO_CFLAGS)
+	$(BRASERO_CFLAGS)						\
+	$(BRASERO_LIBXML_CFLAGS)
 
 CLEANFILES = $(RECMARSHALFILES)
 
@@ -259,7 +260,13 @@
 	brasero-notify.c         \
 	brasero-notify.h         \
 	burn-volume-source.c         \
-	burn-volume-source.h
+	burn-volume-source.h         \
+	brasero-video-disc.c         \
+	brasero-video-disc.h         \
+	brasero-video-project.h         \
+	brasero-video-project.c         \
+	brasero-video-tree-model.c         \
+	brasero-video-tree-model.h
 
 if BUILD_INOTIFY
 brasero_SOURCES += brasero-file-monitor.c brasero-file-monitor.h
@@ -281,7 +288,7 @@
 endif
 
 brasero_LDADD =	\
-	$(BRASERO_LIBS)
+	$(BRASERO_LIBS) $(BRASERO_LIBXML_LIBS)
 
 
 

Modified: trunk/src/brasero-dest-selection.c
==============================================================================
--- trunk/src/brasero-dest-selection.c	(original)
+++ trunk/src/brasero-dest-selection.c	Mon Jul 14 18:07:55 2008
@@ -326,8 +326,24 @@
 		return;
 	}
 
-	if (source.type == BRASERO_TRACK_TYPE_AUDIO)
+	if (source.type == BRASERO_TRACK_TYPE_AUDIO) {
+		/* If that's AUDIO only without VIDEO then return */
+		if (!(source.subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|BRASERO_VIDEO_FORMAT_VCD|BRASERO_VIDEO_FORMAT_VIDEO_DVD)))
+			return;
+
+		/* Otherwise try all possible image types */
+		output->subtype.img_format = BRASERO_IMAGE_FORMAT_CDRDAO;
+		for (; output->subtype.img_format != BRASERO_IMAGE_FORMAT_NONE;
+		       output->subtype.img_format >>= 1) {
+		
+			result = brasero_burn_caps_is_output_supported (priv->caps,
+									priv->session,
+									output);
+			if (result == BRASERO_BURN_OK)
+				return;
+		}
 		return;
+	}
 
 	if (source.type == BRASERO_TRACK_TYPE_DATA
 	||  source.subtype.media & (BRASERO_MEDIUM_DVD|BRASERO_MEDIUM_DVD_DL)) {

Modified: trunk/src/brasero-disc-option-dialog.c
==============================================================================
--- trunk/src/brasero-disc-option-dialog.c	(original)
+++ trunk/src/brasero-disc-option-dialog.c	Mon Jul 14 18:07:55 2008
@@ -70,13 +70,18 @@
 
 	GtkWidget *button;
 
+	GtkWidget *video_options;
+	GtkWidget *dvd_audio;
+	GtkWidget *vcd_label;
+	GtkWidget *vcd_button;
+	GtkWidget *svcd_button;
+
 	guint label_modified:1;
 	guint joliet_warning:1;
 
 	guint checksum_saved:1;
 	guint joliet_saved:1;
 	guint multi_saved:1;
-	guint video_saved:1;
 };
 typedef struct _BraseroDiscOptionDialogPrivate BraseroDiscOptionDialogPrivate;
 
@@ -195,9 +200,14 @@
 		}
 	}
 	else if (source.type == BRASERO_TRACK_TYPE_AUDIO) {
-		/* NOTE to translators: the final string must not be over
-		 * 32 _bytes_ */
-		title_str = g_strdup_printf (_("Audio disc (%s)"), buffer);
+		if (source.subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|BRASERO_VIDEO_FORMAT_VCD|BRASERO_VIDEO_FORMAT_VIDEO_DVD))
+			/* NOTE to translators: the final string must not be over
+			 * 32 _bytes_ */
+			title_str = g_strdup_printf (_("Video disc (%s)"), buffer);
+		else
+			/* NOTE to translators: the final string must not be over
+			 * 32 _bytes_ */
+			title_str = g_strdup_printf (_("Audio disc (%s)"), buffer);
 
 		if (strlen (title_str) > 32) {
 			g_free (title_str);
@@ -394,6 +404,51 @@
 }
 
 static void
+brasero_disc_option_dialog_update_video (BraseroDiscOptionDialog *dialog)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+	BraseroMedia media;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+
+	media = brasero_burn_session_get_dest_media (priv->session);
+
+	if (media & BRASERO_MEDIUM_DVD) {
+		gtk_widget_show (priv->dvd_audio);
+		gtk_widget_hide (priv->vcd_label);
+		gtk_widget_hide (priv->vcd_button);
+		gtk_widget_hide (priv->svcd_button);
+	}
+	else if (media & BRASERO_MEDIUM_CD) {
+		gtk_widget_hide (priv->dvd_audio);
+		gtk_widget_show (priv->vcd_label);
+		gtk_widget_show (priv->vcd_button);
+		gtk_widget_show (priv->svcd_button);
+	}
+	else if (media & BRASERO_MEDIUM_FILE) {
+		BraseroImageFormat format;
+
+		/* if we create a CUE file then that's a SVCD */
+		format = brasero_burn_session_get_output_format (priv->session);
+		if (format == BRASERO_IMAGE_FORMAT_NONE)
+			return;
+
+		if (format == BRASERO_IMAGE_FORMAT_CUE) {
+			gtk_widget_hide (priv->dvd_audio);
+			gtk_widget_show (priv->vcd_label);
+			gtk_widget_show (priv->vcd_button);
+			gtk_widget_show (priv->svcd_button);
+		}
+		else if (format == BRASERO_IMAGE_FORMAT_BIN) {
+			gtk_widget_show (priv->dvd_audio);
+			gtk_widget_hide (priv->vcd_label);
+			gtk_widget_hide (priv->vcd_button);
+			gtk_widget_hide (priv->svcd_button);
+		}
+	}
+}
+
+static void
 brasero_disc_option_dialog_output_changed (BraseroBurnSession *session,
 					   BraseroDiscOptionDialog *dialog)
 {
@@ -404,12 +459,17 @@
 	/* update the multi button:
 	 * NOTE: order is important here multi then video */
 	brasero_disc_option_dialog_update_multi (dialog);
+
 	/* update the joliet button */
 	brasero_disc_option_dialog_update_joliet (dialog);
 
 	/* see if we need to update the label */
 	if (!priv->label_modified)
 		brasero_disc_option_dialog_update_label (dialog);
+
+	/* for video disc see what's the output : CD or DVD */
+	if (priv->dvd_audio)
+		brasero_disc_option_dialog_update_video (dialog);
 }
 
 /**
@@ -753,7 +813,7 @@
 			  G_CALLBACK (brasero_disc_option_dialog_multi_toggled),
 			  dialog);
 	gtk_widget_set_tooltip_text (priv->multi_toggle,
-			      _("Allow create what is called an enhanced CD or CD+"));
+				     _("Allow create what is called an enhanced CD or CD+"));
 
 	options = brasero_utils_pack_properties (_("<b>Disc options</b>"),
 						 priv->multi_toggle,
@@ -764,6 +824,398 @@
 	gtk_widget_show_all (widget);
 }
 
+static void
+brasero_disc_option_dialog_AC3 (GtkToggleButton *button,
+				BraseroDiscOptionDialog *dialog)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+	BraseroAudioFormat format;
+	GValue *value = NULL;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+
+	brasero_burn_session_tag_lookup (priv->session,
+					 BRASERO_DVD_AUDIO_STREAMS,
+					 &value);
+
+	if (value)
+		format = g_value_get_int (value);
+	else
+		format = BRASERO_AUDIO_FORMAT_NONE;
+
+	if (gtk_toggle_button_get_active (button))
+		format |= BRASERO_AUDIO_FORMAT_AC3;
+	else
+		format &= ~BRASERO_AUDIO_FORMAT_AC3;
+
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_INT);
+	g_value_set_int (value, format);
+	brasero_burn_session_tag_add (priv->session,
+				      BRASERO_DVD_AUDIO_STREAMS,
+				      value);
+}
+
+static void
+brasero_disc_option_dialog_MP2 (GtkToggleButton *button,
+				BraseroDiscOptionDialog *dialog)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+	BraseroAudioFormat format;
+	GValue *value = NULL;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+
+	brasero_burn_session_tag_lookup (priv->session,
+					 BRASERO_DVD_AUDIO_STREAMS,
+					 &value);
+
+	if (value)
+		format = g_value_get_int (value);
+	else
+		format = BRASERO_AUDIO_FORMAT_NONE;
+
+	if (gtk_toggle_button_get_active (button))
+		format |= BRASERO_AUDIO_FORMAT_MP2;
+	else
+		format &= ~BRASERO_AUDIO_FORMAT_MP2;
+
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_INT);
+	g_value_set_int (value, format);
+	brasero_burn_session_tag_add (priv->session,
+				      BRASERO_DVD_AUDIO_STREAMS,
+				      value);
+}
+
+static void
+brasero_disc_option_dialog_set_tag (BraseroDiscOptionDialog *dialog,
+				    const gchar *tag,
+				    gint contents)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+	GValue *value;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+
+	value = g_new0 (GValue, 1);
+	g_value_init (value, G_TYPE_INT);
+	g_value_set_int (value, contents);
+	brasero_burn_session_tag_add (priv->session,
+				      tag,
+				      value);
+}
+
+static void
+brasero_disc_option_dialog_SVCD (GtkToggleButton *button,
+				 BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VCD_TYPE,
+					    BRASERO_SVCD);
+}
+
+static void
+brasero_disc_option_dialog_VCD (GtkToggleButton *button,
+				BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VCD_TYPE,
+					    BRASERO_VCD_V2);
+}
+
+static void
+brasero_disc_option_dialog_NTSC (GtkToggleButton *button,
+				 BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VIDEO_OUTPUT_FRAMERATE,
+					    BRASERO_VIDEO_FRAMERATE_NTSC);
+}
+
+static void
+brasero_disc_option_dialog_PAL_SECAM (GtkToggleButton *button,
+				      BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VIDEO_OUTPUT_FRAMERATE,
+					    BRASERO_VIDEO_FRAMERATE_PAL_SECAM);
+}
+
+static void
+brasero_disc_option_dialog_native_framerate (GtkToggleButton *button,
+					     BraseroDiscOptionDialog *dialog)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+	brasero_burn_session_tag_remove (priv->session,
+					 BRASERO_VIDEO_OUTPUT_FRAMERATE);
+}
+
+static void
+brasero_disc_option_dialog_16_9 (GtkToggleButton *button,
+				 BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VIDEO_OUTPUT_ASPECT,
+					    BRASERO_VIDEO_ASPECT_16_9);
+}
+
+static void
+brasero_disc_option_dialog_4_3 (GtkToggleButton *button,
+				BraseroDiscOptionDialog *dialog)
+{
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	brasero_disc_option_dialog_set_tag (dialog,
+					    BRASERO_VIDEO_OUTPUT_ASPECT,
+					    BRASERO_VIDEO_ASPECT_4_3);
+}
+
+static void
+brasero_disc_option_dialog_native_aspect (GtkToggleButton *button,
+					     BraseroDiscOptionDialog *dialog)
+{
+	BraseroDiscOptionDialogPrivate *priv;
+
+	if (!gtk_toggle_button_get_active (button))
+		return;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+	brasero_burn_session_tag_remove (priv->session,
+					 BRASERO_VIDEO_OUTPUT_ASPECT);
+}
+
+static void
+brasero_disc_option_dialog_add_video_options (BraseroDiscOptionDialog *dialog)
+{
+	GtkWidget *label;
+	GtkWidget *table;
+	GtkWidget *widget;
+	GtkWidget *button1;
+	GtkWidget *button2;
+	GtkWidget *button3;
+	GtkWidget *options;
+	BraseroDiscOptionDialogPrivate *priv;
+
+	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (dialog);
+
+	widget = gtk_vbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+			    widget,
+			    FALSE,
+			    FALSE,
+			    6);
+
+	table = gtk_table_new (3, 4, FALSE);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 8);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+	gtk_widget_show (table);
+
+	label = gtk_label_new (_("Video format:"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+	gtk_table_attach (GTK_TABLE (table),
+			  label,
+			  0, 1,
+			  0, 1,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button1 = gtk_radio_button_new_with_mnemonic (NULL,
+						      _("_NTSC"));
+	gtk_widget_set_tooltip_text (button1, _("Format used mostly on the North American Continent"));
+	g_signal_connect (button1,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_NTSC),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button1,
+			  3, 4,
+			  0, 1,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button2 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button1),
+								  _("_PAL/SECAM"));
+	gtk_widget_set_tooltip_text (button2, _("Format used mostly in Europe"));
+	g_signal_connect (button2,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_PAL_SECAM),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button2,
+			  2, 3,
+			  0, 1,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button3 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button1),
+								  _("Native _format"));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button3), TRUE);
+	g_signal_connect (button3,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_native_framerate),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button3,
+			  1, 2,
+			  0, 1,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	label = gtk_label_new (_("Aspect ratio:"));
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+	gtk_table_attach (GTK_TABLE (table),
+			  label,
+			  0, 1,
+			  1, 2,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button1 = gtk_radio_button_new_with_mnemonic (NULL,
+						      _("_4:3"));
+	g_signal_connect (button1,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_4_3),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button1,
+			  3, 4,
+			  1, 2,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button2 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button1),
+								  _("_16:9"));
+	g_signal_connect (button2,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_16_9),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button2,
+			  2, 3,
+			  1, 2,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button3 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button1),
+								  _("Native aspect _ratio"));
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button3), TRUE);
+	g_signal_connect (button3,
+			  "toggled",
+			  G_CALLBACK (brasero_disc_option_dialog_native_aspect),
+			  dialog);
+	gtk_table_attach (GTK_TABLE (table),
+			  button3,
+			  1, 2,
+			  1, 2,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	/* Video options for (S)VCD */
+	label = gtk_label_new (_("VCD type:"));
+	priv->vcd_label = label;
+
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+	gtk_table_attach (GTK_TABLE (table),
+			  label,
+			  0, 1,
+			  2, 3,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	button1 = gtk_radio_button_new_with_mnemonic_from_widget (NULL, _("Create a SVCD"));
+	priv->svcd_button = button1;
+	gtk_table_attach (GTK_TABLE (table),
+			  button1,
+			  1, 2,
+			  2, 3,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	g_signal_connect (button1,
+			  "clicked",
+			  G_CALLBACK (brasero_disc_option_dialog_SVCD),
+			  dialog);
+
+	button2 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button1), _("Create a VCD"));
+	priv->vcd_button = button2;
+	gtk_table_attach (GTK_TABLE (table),
+			  button2,
+			  2, 3,
+			  2, 3,
+			  GTK_FILL,
+			  GTK_FILL,
+			  0, 0);
+
+	g_signal_connect (button2,
+			  "clicked",
+			  G_CALLBACK (brasero_disc_option_dialog_VCD),
+			  dialog);
+
+	options = brasero_utils_pack_properties (_("<b>Video Options</b>"),
+						 table,
+						 NULL);
+	gtk_box_pack_start (GTK_BOX (widget), options, FALSE, FALSE, 0);
+
+	/* Audio options for DVDs */
+	button1 = gtk_check_button_new_with_mnemonic (_("Add _AC3 audio stream"));
+	button2 = gtk_check_button_new_with_mnemonic (_("Add _MP2 audio stream"));
+	options = brasero_utils_pack_properties (_("<b>Audio Options</b>"),
+						 button1,
+						 button2,
+						 NULL);
+	g_signal_connect (button1,
+			  "clicked",
+			  G_CALLBACK (brasero_disc_option_dialog_AC3),
+			  dialog);
+	g_signal_connect (button2,
+			  "clicked",
+			  G_CALLBACK (brasero_disc_option_dialog_MP2),
+			  dialog);
+
+	gtk_box_pack_start (GTK_BOX (widget), options, FALSE, FALSE, 0);
+	priv->dvd_audio = options;
+
+	gtk_widget_show_all (widget);
+	brasero_disc_option_dialog_update_video (dialog);
+
+	priv->video_options = widget;
+}
+
 void
 brasero_disc_option_dialog_set_disc (BraseroDiscOptionDialog *dialog,
 				     BraseroDisc *disc)
@@ -802,15 +1254,23 @@
 
 	brasero_burn_session_get_input_type (priv->session, &type);
 	if (type.type == BRASERO_TRACK_TYPE_DATA) {
-	brasero_drive_selection_set_type_shown (BRASERO_DRIVE_SELECTION (priv->selection),
-						BRASERO_MEDIA_TYPE_WRITABLE|
-						BRASERO_MEDIA_TYPE_FILE);
+		brasero_drive_selection_set_type_shown (BRASERO_DRIVE_SELECTION (priv->selection),
+							BRASERO_MEDIA_TYPE_WRITABLE|
+							BRASERO_MEDIA_TYPE_FILE);
 		brasero_disc_option_dialog_add_data_options (dialog);
 	}
 	else if (type.type == BRASERO_TRACK_TYPE_AUDIO) {
-		brasero_drive_selection_set_type_shown (BRASERO_DRIVE_SELECTION (priv->selection),
-							BRASERO_MEDIA_TYPE_WRITABLE);
-		brasero_disc_option_dialog_add_audio_options (dialog);
+		if (type.subtype.audio_format & (BRASERO_VIDEO_FORMAT_UNDEFINED|BRASERO_VIDEO_FORMAT_VCD|BRASERO_VIDEO_FORMAT_VIDEO_DVD)) {
+			brasero_drive_selection_set_type_shown (BRASERO_DRIVE_SELECTION (priv->selection),
+								BRASERO_MEDIA_TYPE_WRITABLE|
+								BRASERO_MEDIA_TYPE_FILE);
+			brasero_disc_option_dialog_add_video_options (dialog);
+		}
+		else {
+			brasero_drive_selection_set_type_shown (BRASERO_DRIVE_SELECTION (priv->selection),
+								BRASERO_MEDIA_TYPE_WRITABLE);
+			brasero_disc_option_dialog_add_audio_options (dialog);
+		}
 	}
 }
 
@@ -823,6 +1283,9 @@
 
 	priv = BRASERO_DISC_OPTION_DIALOG_PRIVATE (self);
 	gtk_widget_set_sensitive (priv->button, valid);
+
+	if (priv->video_options)
+		gtk_widget_set_sensitive (priv->video_options, valid);
 }
 
 BraseroBurnSession *

Modified: trunk/src/brasero-disc.h
==============================================================================
--- trunk/src/brasero-disc.h	(original)
+++ trunk/src/brasero-disc.h	Mon Jul 14 18:07:55 2008
@@ -63,8 +63,9 @@
 } BraseroDiscResult;
 
 typedef enum {
-	BRASERO_DISC_TRACK_NONE,
+	BRASERO_DISC_TRACK_NONE = 0,
 	BRASERO_DISC_TRACK_AUDIO,
+	BRASERO_DISC_TRACK_VIDEO,
 	BRASERO_DISC_TRACK_DATA,
 } BraseroDiscTrackType;
 

Modified: trunk/src/brasero-file-chooser.c
==============================================================================
--- trunk/src/brasero-file-chooser.c	(original)
+++ trunk/src/brasero-file-chooser.c	Mon Jul 14 18:07:55 2008
@@ -68,6 +68,7 @@
 
 	GtkFileFilter *filter_any;
 	GtkFileFilter *filter_audio;
+	GtkFileFilter *filter_video;
 };
 
 static GObjectClass *parent_class = NULL;
@@ -234,6 +235,8 @@
 	gtk_file_filter_add_mime_type (filter, "application/x-flash-video");
 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (obj->priv->chooser), filter);
 
+	obj->priv->filter_video = filter;
+
 	filter = gtk_file_filter_new ();
 	gtk_file_filter_set_name (filter, _("Image files only"));
 	gtk_file_filter_add_mime_type (filter, "image/*");
@@ -373,6 +376,9 @@
 	if (type == BRASERO_LAYOUT_AUDIO)
 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self->priv->chooser),
 					     self->priv->filter_audio);
+	else if (type == BRASERO_LAYOUT_VIDEO)
+		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self->priv->chooser),
+					     self->priv->filter_video);
 	else
 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self->priv->chooser),
 					     self->priv->filter_any);

Modified: trunk/src/brasero-io.c
==============================================================================
--- trunk/src/brasero-io.c	(original)
+++ trunk/src/brasero-io.c	Mon Jul 14 18:07:55 2008
@@ -628,6 +628,9 @@
 	g_file_info_set_attribute_boolean (info, BRASERO_IO_HAS_VIDEO, metadata->has_video);
 	g_file_info_set_attribute_boolean (info, BRASERO_IO_IS_SEEKABLE, metadata->is_seekable);
 
+	if (metadata->snapshot)
+		g_file_info_set_attribute_object (info, BRASERO_IO_SNAPSHOT, G_OBJECT (metadata->snapshot));
+
 	/* FIXME: what about silences */
 }
 
@@ -668,10 +671,24 @@
 		cached = node->data;
 		last_modified = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
 		if (last_modified == cached->last_modified) {
-			brasero_metadata_info_copy (meta_info, cached->info);
-			return TRUE;
+			if (flags & BRASERO_METADATA_FLAG_SNAPHOT) {
+				/* If there isn't any snapshot retry */
+				if (cached->info->snapshot) {
+					brasero_metadata_info_copy (meta_info, cached->info);
+					return TRUE;
+				}
+			}
+			else {
+				brasero_metadata_info_copy (meta_info, cached->info);
+				return TRUE;
+			}
 		}
 
+		/* remove it from the queue since we can't keep the same
+		 * URI twice */
+		brasero_metadata_info_free (node->data);
+		g_queue_remove (priv->meta_buffer, node->data);
+
 		BRASERO_BURN_LOG ("Updating cache information for %s", uri);
 	}
 
@@ -796,7 +813,8 @@
 						       cancel,
 						       uri,
 						       info,
-						       (options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0,
+						       ((options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0) |
+						       ((options & BRASERO_IO_INFO_METADATA_SNAPSHOT) ? BRASERO_METADATA_FLAG_SNAPHOT : 0),
 						       &metadata);
 
 		if (result)
@@ -1151,6 +1169,7 @@
 						       child_uri,
 						       info,
 						       ((data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0) |
+						       ((data->job.options & BRASERO_IO_INFO_METADATA_SNAPSHOT) ? BRASERO_METADATA_FLAG_SNAPHOT : 0) |
 						       BRASERO_METADATA_FLAG_FAST,
 						       &metadata);
 
@@ -1186,7 +1205,8 @@
 						       cancel,
 						       child_uri,
 						       info,
-						       (data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0,
+						       ((data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0) |
+						       ((data->job.options & BRASERO_IO_INFO_METADATA_SNAPSHOT) ? BRASERO_METADATA_FLAG_SNAPHOT : 0),
 						       &metadata);
 		if (result)
 			data->total_b += metadata.len;
@@ -1481,6 +1501,7 @@
 						       child_uri,
 						       info,
 						       ((data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0) |
+						       ((data->job.options & BRASERO_IO_INFO_METADATA_SNAPSHOT) ? BRASERO_METADATA_FLAG_SNAPHOT : 0) |
 						       BRASERO_METADATA_FLAG_FAST,
 						       &metadata);
 
@@ -1640,7 +1661,8 @@
 							       cancel,
 							       child_uri,
 							       info,
-							       (data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0,
+							       ((data->job.options & BRASERO_IO_INFO_METADATA_MISSING_CODEC) ? BRASERO_METADATA_FLAG_MISSING : 0) |
+							       ((data->job.options & BRASERO_IO_INFO_METADATA_SNAPSHOT) ? BRASERO_METADATA_FLAG_SNAPHOT : 0),
 							       &metadata);
 
 			if (result)
@@ -1679,7 +1701,7 @@
 		g_object_unref (child);
 	}
 
-	if (data->job.callback_data->ref < 2) {
+	if (data->job.callback_data && data->job.callback_data->ref < 2) {
 		/* No result was returned so we need to return a dummy one to 
 		 * clean the callback_data in the main loop. */
 		brasero_io_return_result (BRASERO_IO (manager),

Modified: trunk/src/brasero-io.h
==============================================================================
--- trunk/src/brasero-io.h	(original)
+++ trunk/src/brasero-io.h	Mon Jul 14 18:07:55 2008
@@ -59,9 +59,10 @@
 	BRASERO_IO_INFO_ICON			= 1,
 	BRASERO_IO_INFO_PERM			= 1 << 1,
 	BRASERO_IO_INFO_METADATA		= 1 << 2,
-	BRASERO_IO_INFO_RECURSIVE		= 1 << 3,
-	BRASERO_IO_INFO_CHECK_PARENT_SYMLINK	= 1 << 4,
-	BRASERO_IO_INFO_METADATA_MISSING_CODEC	= 1 << 5,
+	BRASERO_IO_INFO_METADATA_SNAPSHOT		= 1 << 3,
+	BRASERO_IO_INFO_RECURSIVE		= 1 << 4,
+	BRASERO_IO_INFO_CHECK_PARENT_SYMLINK	= 1 << 5,
+	BRASERO_IO_INFO_METADATA_MISSING_CODEC	= 1 << 6,
 
 	BRASERO_IO_INFO_URGENT			= 1 << 9,
 	BRASERO_IO_INFO_IDLE			= 1 << 10
@@ -83,12 +84,13 @@
 #define BRASERO_IO_COUNT_SIZE		"count::size"
 #define BRASERO_IO_COUNT_INVALID	"count::invalid"
 
+#define BRASERO_IO_SNAPSHOT		"metadata::snapshot"
+
 #define BRASERO_IO_LEN			"metadata::length"
 #define BRASERO_IO_ISRC			"metadata::isrc"
 #define BRASERO_IO_TITLE		"metadata::title"
 #define BRASERO_IO_ARTIST		"metadata::artist"
 #define BRASERO_IO_ALBUM		"metadata::album"
-#define BRASERO_IO_ALBUM		"metadata::album"
 #define BRASERO_IO_GENRE		"metadata::genre"
 #define BRASERO_IO_COMPOSER		"metadata::composer"
 #define BRASERO_IO_HAS_AUDIO		"metadata::has_audio"

Modified: trunk/src/brasero-layout.c
==============================================================================
--- trunk/src/brasero-layout.c	(original)
+++ trunk/src/brasero-layout.c	Mon Jul 14 18:07:55 2008
@@ -138,17 +138,29 @@
 	  "F7", N_(BRASERO_LAYOUT_NONE_TOOLTIP), G_CALLBACK (brasero_layout_empty_toggled_cb), 1 }
 };
 
-const gchar description [] = "<ui>"
-				"<menubar name='menubar' >"
-				"<menu action='ViewMenu'>"
-				"<placeholder name='ViewPlaceholder'>"
+const GtkRadioActionEntry radio_entries [] = {
+	{ "HView", NULL, N_("_Horizontal Layout"),
+	  NULL, N_("Set an horizontal layout"), 0 },
+
+	{ "VView", NULL, N_("_Vertical Layout"),
+	  NULL, N_("Set a vertical layout"), 1 },
+};
+
+const gchar description [] =
+	"<ui>"
+	"<menubar name='menubar' >"
+		"<menu action='ViewMenu'>"
+			"<placeholder name='ViewPlaceholder'>"
 				"<menuitem action='"BRASERO_LAYOUT_NONE_ID"'/>"
 				"<menuitem action='"BRASERO_LAYOUT_PREVIEW_ID"'/>"
 				"<separator/>"
-				"</placeholder>"
-				"</menu>"
-				"</menubar>"
-			     "</ui>";
+				"<menuitem action='VView'/>"
+				"<menuitem action='HView'/>"
+				"<separator/>"
+			"</placeholder>"
+		"</menu>"
+	"</menubar>"
+	"</ui>";
 
 /* GCONF keys */
 #define BRASERO_KEY_DISPLAY_LAYOUT	"/apps/brasero/display/layout"
@@ -158,6 +170,7 @@
 #define BRASERO_KEY_DISPLAY_DIR		"/apps/brasero/display/"
 #define BRASERO_KEY_LAYOUT_AUDIO	BRASERO_KEY_DISPLAY_DIR "audio_pane"
 #define BRASERO_KEY_LAYOUT_DATA		BRASERO_KEY_DISPLAY_DIR "data_pane"
+#define BRASERO_KEY_LAYOUT_VIDEO	BRASERO_KEY_DISPLAY_DIR "video_pane"
 
 static void
 brasero_layout_pack_preview (BraseroLayout *layout)
@@ -560,6 +573,10 @@
 	&&  layout->priv->ctx_type == BRASERO_LAYOUT_DATA)
 		return;
 
+	if (!strcmp (entry->key, BRASERO_KEY_LAYOUT_VIDEO)
+	&&  layout->priv->ctx_type == BRASERO_LAYOUT_VIDEO)
+		return;
+
 	value = gconf_entry_get_value (entry);
 	if (value->type != GCONF_VALUE_STRING)
 		return;
@@ -643,6 +660,25 @@
 								      NULL,
 								      &error);
 	}
+	else if (layout->priv->ctx_type == BRASERO_LAYOUT_VIDEO) {
+		gconf_client_set_string (layout->priv->client,
+					 BRASERO_KEY_LAYOUT_VIDEO,
+					 id,
+					 &error);
+
+		if (error) {
+			g_warning ("Can't set GConf key %s. \n", error->message);
+			g_error_free (error);
+			error = NULL;
+		}
+
+		layout->priv->radio_notify = gconf_client_notify_add (layout->priv->client,
+								      BRASERO_KEY_LAYOUT_VIDEO,
+								      brasero_layout_displayed_item_changed_cb,
+								      layout,
+								      NULL,
+								      &error);
+	}
 
 	if (error) {
 		g_warning ("Can't set GConf notify on key %s. \n", error->message);
@@ -801,6 +837,10 @@
 		layout_id = gconf_client_get_string (layout->priv->client,
 						     BRASERO_KEY_LAYOUT_DATA,
 						     &error);
+	else if (type == BRASERO_LAYOUT_VIDEO)
+		layout_id = gconf_client_get_string (layout->priv->client,
+						     BRASERO_KEY_LAYOUT_VIDEO,
+						     &error);
 
 	if (error) {
 		g_warning ("Can't access GConf key %s. This is probably harmless (first launch of brasero).\n", error->message);
@@ -823,6 +863,13 @@
 								      layout,
 								      NULL,
 								      &error);
+	else if (type == BRASERO_LAYOUT_VIDEO)
+		layout->priv->radio_notify = gconf_client_notify_add (layout->priv->client,
+								      BRASERO_KEY_LAYOUT_VIDEO,
+								      brasero_layout_displayed_item_changed_cb,
+								      layout,
+								      NULL,
+								      &error);
 
 	if (error) {
 		g_warning ("Could not set notify for GConf key %s.\n", error->message);
@@ -903,47 +950,39 @@
 }
 
 static void
-brasero_layout_type_changed_cb (GConfClient *client,
-				guint cxn,
-				GConfEntry *entry,
-				gpointer data)
+brasero_layout_change_type (BraseroLayout *layout,
+			    BraseroLayoutType layout_type)
 {
-	GConfValue *value;
-	GtkWidget *source_pane;
-	GtkWidget *project_pane;
-	BraseroLayoutType layout_type;
-	BraseroLayout *layout = BRASERO_LAYOUT (data);
+	GtkWidget *source_pane = NULL;
+	GtkWidget *project_pane = NULL;
 
-	value = gconf_entry_get_value (entry);
-	if (value->type != GCONF_VALUE_INT)
-		return;
-
-	g_object_ref (layout->priv->preview_pane);
-	if (layout->priv->layout_type == BRASERO_LAYOUT_BOTTOM)
-		gtk_container_remove (GTK_CONTAINER (layout->priv->project), layout->priv->preview_pane);
-	else
-		gtk_container_remove (GTK_CONTAINER (layout->priv->main_box), layout->priv->preview_pane);
+	if (layout->priv->pane) {
+		g_object_ref (layout->priv->preview_pane);
+		if (layout->priv->layout_type == BRASERO_LAYOUT_BOTTOM)
+			gtk_container_remove (GTK_CONTAINER (layout->priv->project), layout->priv->preview_pane);
+		else
+			gtk_container_remove (GTK_CONTAINER (layout->priv->main_box), layout->priv->preview_pane);
 
-	if (layout->priv->layout_type == BRASERO_LAYOUT_TOP
-	||  layout->priv->layout_type == BRASERO_LAYOUT_LEFT) {
-		project_pane = gtk_paned_get_child1 (GTK_PANED (layout->priv->pane));
-		source_pane = gtk_paned_get_child2 (GTK_PANED (layout->priv->pane));
-	}
-	else {
-		source_pane = gtk_paned_get_child1 (GTK_PANED (layout->priv->pane));
-		project_pane = gtk_paned_get_child2 (GTK_PANED (layout->priv->pane));
-	}
+		if (layout->priv->layout_type == BRASERO_LAYOUT_TOP
+		||  layout->priv->layout_type == BRASERO_LAYOUT_LEFT) {
+			project_pane = gtk_paned_get_child1 (GTK_PANED (layout->priv->pane));
+			source_pane = gtk_paned_get_child2 (GTK_PANED (layout->priv->pane));
+		}
+		else {
+			source_pane = gtk_paned_get_child1 (GTK_PANED (layout->priv->pane));
+			project_pane = gtk_paned_get_child2 (GTK_PANED (layout->priv->pane));
+		}
 
-	g_object_ref (source_pane);
-	gtk_container_remove (GTK_CONTAINER (layout->priv->pane), source_pane);
+		g_object_ref (source_pane);
+		gtk_container_remove (GTK_CONTAINER (layout->priv->pane), source_pane);
 
-	g_object_ref (project_pane);
-	gtk_container_remove (GTK_CONTAINER (layout->priv->pane), project_pane);
+		g_object_ref (project_pane);
+		gtk_container_remove (GTK_CONTAINER (layout->priv->pane), project_pane);
 
-	gtk_widget_destroy (layout->priv->pane);
-	layout->priv->pane = NULL;
+		gtk_widget_destroy (layout->priv->pane);
+		layout->priv->pane = NULL;
+	}
 
-	layout_type = gconf_value_get_int (value);
 	if (layout_type > BRASERO_LAYOUT_BOTTOM
 	||  layout_type < BRASERO_LAYOUT_RIGHT)
 		layout_type = BRASERO_LAYOUT_RIGHT;
@@ -966,39 +1005,123 @@
 	gtk_widget_show (layout->priv->pane);
 	gtk_box_pack_end (GTK_BOX (layout), layout->priv->pane, TRUE, TRUE, 0);
 
-	switch (layout_type) {
-		case BRASERO_LAYOUT_TOP:
-		case BRASERO_LAYOUT_LEFT:
-			gtk_paned_pack2 (GTK_PANED (layout->priv->pane), source_pane, TRUE, FALSE);
-			gtk_paned_pack1 (GTK_PANED (layout->priv->pane), project_pane, TRUE, FALSE);
-			break;
-
-		case BRASERO_LAYOUT_BOTTOM:
-		case BRASERO_LAYOUT_RIGHT:
-			gtk_paned_pack2 (GTK_PANED (layout->priv->pane), project_pane, TRUE, FALSE);
-			gtk_paned_pack1 (GTK_PANED (layout->priv->pane), source_pane, TRUE, FALSE);
-			break;
-
-		default:
-			break;
-	}
-
 	g_signal_connect (layout->priv->pane,
 			  "notify::position",
 			  G_CALLBACK (brasero_layout_pane_moved_cb),
 			  layout);
 
 	layout->priv->layout_type = layout_type;
-	g_object_unref (project_pane);
-	g_object_unref (source_pane);
 
-	brasero_layout_pack_preview (layout);
-	g_object_unref (layout->priv->preview_pane);
+	if (source_pane && project_pane) {
+		switch (layout_type) {
+			case BRASERO_LAYOUT_TOP:
+			case BRASERO_LAYOUT_LEFT:
+				gtk_paned_pack2 (GTK_PANED (layout->priv->pane), source_pane, TRUE, FALSE);
+				gtk_paned_pack1 (GTK_PANED (layout->priv->pane), project_pane, TRUE, FALSE);
+				break;
+
+			case BRASERO_LAYOUT_BOTTOM:
+			case BRASERO_LAYOUT_RIGHT:
+				gtk_paned_pack1 (GTK_PANED (layout->priv->pane), source_pane, TRUE, FALSE);
+				gtk_paned_pack2 (GTK_PANED (layout->priv->pane), project_pane, TRUE, FALSE);
+				break;
+
+			default:
+				break;
+		}
+
+		g_object_unref (project_pane);
+		g_object_unref (source_pane);
+	}
+
+	if (layout->priv->preview_pane) {
+		brasero_layout_pack_preview (layout);
+		g_object_unref (layout->priv->preview_pane);
+	}
 
 	brasero_layout_size_reallocate (layout);
 }
 
 static void
+brasero_layout_HV_radio_button_toggled_cb (GtkRadioAction *radio,
+					   GtkRadioAction *current,
+					   BraseroLayout *layout);
+
+static void
+brasero_layout_type_changed_cb (GConfClient *client,
+				guint cxn,
+				GConfEntry *entry,
+				gpointer data)
+{
+	GSList *iter;
+	GSList *radios;
+	GtkAction *action;
+	GConfValue *value;
+	BraseroLayoutType layout_type;
+	BraseroLayout *layout = BRASERO_LAYOUT (data);
+
+	value = gconf_entry_get_value (entry);
+	if (value->type != GCONF_VALUE_INT)
+		return;
+
+	layout_type = gconf_value_get_int (value);
+	brasero_layout_change_type (layout, layout_type);
+
+	/* make sure our radio actions reflect the change */
+	action = gtk_action_group_get_action (layout->priv->action_group, "HView");
+
+	radios = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
+	for (iter = radios; iter; iter = iter->next)
+		g_signal_handlers_block_by_func (iter->data,
+						 brasero_layout_HV_radio_button_toggled_cb,
+						 layout);
+
+	gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action),
+					    GTK_IS_VPANED (layout->priv->pane));
+
+	for (iter = radios; iter; iter = iter->next)
+		g_signal_handlers_unblock_by_func (iter->data,
+						   brasero_layout_HV_radio_button_toggled_cb,
+						   layout);
+
+	g_slist_free (radios);
+}
+
+static void
+brasero_layout_HV_radio_button_toggled_cb (GtkRadioAction *radio,
+					   GtkRadioAction *current,
+					   BraseroLayout *layout)
+{
+	guint layout_type;
+
+	if (gtk_radio_action_get_current_value (current))
+		layout_type = BRASERO_LAYOUT_BOTTOM;
+	else
+		layout_type = BRASERO_LAYOUT_RIGHT;
+
+	brasero_layout_change_type (layout, layout_type);
+
+	/* update the GConf key */
+	gconf_client_notify_remove (layout->priv->client,
+				    layout->priv->layout_notify);
+	layout->priv->layout_notify = 0;
+
+	gconf_client_set_int (layout->priv->client,
+			      BRASERO_KEY_DISPLAY_LAYOUT,
+			      layout_type,
+			      NULL);
+
+	/* This is to avoid a notification for change */
+	gconf_client_clear_cache (layout->priv->client);
+	layout->priv->layout_notify = gconf_client_notify_add (layout->priv->client,
+							       BRASERO_KEY_DISPLAY_LAYOUT,
+							       brasero_layout_type_changed_cb,
+							       layout,
+							       NULL,
+							       NULL);
+}
+
+static void
 brasero_layout_close_button_clicked_cb (GtkWidget *button,
 					BraseroLayout *layout)
 {
@@ -1184,6 +1307,14 @@
 	gtk_widget_show (obj->priv->pane);
 	gtk_box_pack_end (GTK_BOX (obj), obj->priv->pane, TRUE, TRUE, 0);
 
+	/* reflect that layout in the menus */
+	gtk_action_group_add_radio_actions (obj->priv->action_group,
+					    radio_entries,
+					    sizeof (radio_entries) / sizeof (GtkRadioActionEntry),
+					    GTK_IS_VPANED (obj->priv->pane),
+					    G_CALLBACK (brasero_layout_HV_radio_button_toggled_cb),
+					    obj);
+
 	/* remember the position */
 	position = gconf_client_get_int (obj->priv->client,
 					 BRASERO_KEY_DISPLAY_POSITION,

Modified: trunk/src/brasero-layout.h
==============================================================================
--- trunk/src/brasero-layout.h	(original)
+++ trunk/src/brasero-layout.h	Mon Jul 14 18:07:55 2008
@@ -50,6 +50,7 @@
 	BRASERO_LAYOUT_NONE		= 0,
 	BRASERO_LAYOUT_AUDIO		= 1,
 	BRASERO_LAYOUT_DATA		= 1 << 1,
+	BRASERO_LAYOUT_VIDEO		= 1 << 2
 } BraseroLayoutType;
 
 typedef struct {

Modified: trunk/src/brasero-metadata.c
==============================================================================
--- trunk/src/brasero-metadata.c	(original)
+++ trunk/src/brasero-metadata.c	Mon Jul 14 18:07:55 2008
@@ -32,6 +32,8 @@
 #include <glib/gi18n-lib.h>
 #include <glib-object.h>
 
+#include <gdk/gdkpixbuf.h>
+
 #include <gst/gst.h>
 #include <gst/base/gstbasesink.h>
 #include <gst/pbutils/install-plugins.h>
@@ -42,6 +44,8 @@
 #include "brasero-utils.h"
 #include "burn-debug.h"
 
+#define BRASERO_METADATA_INITIAL_STATE		GST_STATE_PAUSED
+
 
 G_DEFINE_TYPE(BraseroMetadata, brasero_metadata, G_TYPE_OBJECT)
 
@@ -54,7 +58,11 @@
 	GstElement *convert;
 	GstElement *level;
 	GstElement *sink;
-	GstElement *first;
+
+	GstElement *audio;
+	GstElement *video;
+
+	GstElement *snapshot;
 
 	GMainLoop *loop;
 	GError *error;
@@ -77,6 +85,9 @@
 	guint started:1;
 	guint moved_forward:1;
 	guint prev_level_mes:1;
+	guint video_linked:1;
+	guint audio_linked:1;
+	guint snapshot_started:1;
 };
 typedef struct BraseroMetadataPrivate BraseroMetadataPrivate;
 #define BRASERO_METADATA_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), BRASERO_TYPE_METADATA, BraseroMetadataPrivate))
@@ -117,6 +128,11 @@
 	if (!info)
 		return;
 
+	if (info->snapshot) {
+		g_object_unref (info->snapshot);
+		info->snapshot = NULL;
+	}
+
 	if (info->uri)
 		g_free (info->uri);
 
@@ -225,6 +241,26 @@
 	}
 }
 
+static gboolean
+brasero_metadata_completed (BraseroMetadata *self)
+{
+	BraseroMetadataPrivate *priv;
+
+	priv = BRASERO_METADATA_PRIVATE (self);
+	if ((!priv->loop || !g_main_loop_is_running (priv->loop)) && !priv->cond) {
+		/* we send a message only if we haven't got a loop (= async mode) */
+		g_object_ref (self);
+		g_signal_emit (G_OBJECT (self),
+			       brasero_metadata_signals [COMPLETED_SIGNAL],
+			       0,
+			       priv->error);
+		g_object_unref (self);
+	}
+
+	brasero_metadata_stop (self);
+	return TRUE;
+}
+
 static gint
 brasero_metadata_report_progress (BraseroMetadata *self)
 {
@@ -250,6 +286,42 @@
 	return TRUE;
 }
 
+static gboolean
+brasero_metadata_thumbnail (BraseroMetadata *self)
+{
+	BraseroMetadataPrivate *priv;
+	gint64 position;
+	gboolean res;
+
+	priv = BRASERO_METADATA_PRIVATE (self);
+
+	/* find the right position and move forward */
+	position = 15 * GST_SECOND;
+	while (position >= priv->info->len)
+		position -= 5 * GST_SECOND;
+
+	gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+
+	priv->snapshot_started = 1;
+	if (position < GST_SECOND)
+		position = GST_SECOND;
+
+	res = gst_element_seek_simple (priv->pipeline,
+				       GST_FORMAT_TIME,
+				       GST_SEEK_FLAG_FLUSH,
+				       position);
+
+	BRASERO_BURN_LOG ("Seeking forward %i for %s", res, priv->info->uri);
+	if (!res)
+		return brasero_metadata_completed (self);
+
+	g_object_set (priv->snapshot,
+		      "send-messages", TRUE,
+		      NULL);
+
+	return TRUE;
+}
+
 static void
 brasero_metadata_is_seekable (BraseroMetadata *self)
 {
@@ -338,26 +410,6 @@
 	return FALSE;
 }
 
-static gboolean
-brasero_metadata_completed (BraseroMetadata *self)
-{
-	BraseroMetadataPrivate *priv;
-
-	priv = BRASERO_METADATA_PRIVATE (self);
-	if ((!priv->loop || !g_main_loop_is_running (priv->loop)) && !priv->cond) {
-		/* we send a message only if we haven't got a loop (= async mode) */
-		g_object_ref (self);
-		g_signal_emit (G_OBJECT (self),
-			       brasero_metadata_signals [COMPLETED_SIGNAL],
-			       0,
-			       priv->error);
-		g_object_unref (self);
-	}
-
-	brasero_metadata_stop (self);
-	return TRUE;
-}
-
 static void
 foreach_tag (const GstTagList *list,
 	     const gchar *tag,
@@ -436,6 +488,8 @@
 
 	priv = BRASERO_METADATA_PRIVATE (self);
 
+	BRASERO_BURN_LOG ("Metadata retrieval successfully completed for %s", priv->info->uri);
+
 	/* find the type of the file */
 	brasero_metadata_get_mime_type (self);
 
@@ -461,7 +515,7 @@
 		return brasero_metadata_completed (self);
 	}
 
-	BRASERO_BURN_LOG ("found duration %lli", duration);
+	BRASERO_BURN_LOG ("found duration %lli for %s", duration, priv->info->uri);
 
 	priv->info->len = duration;
 
@@ -477,6 +531,12 @@
 	/* empty the bus of any pending message */
 	brasero_metadata_process_pending_tag_messages (self);
 
+	/* before leaving, check if we need a snapshot */
+	if (priv->snapshot
+	&&  priv->video_linked
+	&& !priv->snapshot_started)
+		return brasero_metadata_thumbnail (self);
+
 	return brasero_metadata_completed (self);
 }
 
@@ -735,10 +795,27 @@
 	priv = BRASERO_METADATA_PRIVATE (self);
 
 	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_ASYNC_DONE:
+		BRASERO_BURN_LOG ("Async state change done for %s", priv->info->uri);
+		break;
 	case GST_MESSAGE_ELEMENT:
+		if (!strcmp (gst_structure_get_name (msg->structure), "preroll-pixbuf")
+		||  !strcmp (gst_structure_get_name (msg->structure), "pixbuf")) {
+			const GValue *value;
+
+			value = gst_structure_get_value (msg->structure, "pixbuf");
+			priv->info->snapshot = g_value_get_object (value);
+			g_object_ref (priv->info->snapshot);
+
+			BRASERO_BURN_LOG ("Received pixbuf snapshot sink (%p) for %s", priv->info->snapshot, priv->info->uri);
+
+			/* Now we can stop */
+			brasero_metadata_completed (self);
+			return TRUE;
+		}
 		/* here we just want to check if that's a missing codec */
-		if ((priv->flags & BRASERO_METADATA_FLAG_MISSING)
-		&&   gst_is_missing_plugin_message (msg))
+		else if ((priv->flags & BRASERO_METADATA_FLAG_MISSING)
+		     &&   gst_is_missing_plugin_message (msg))
 			priv->missing_plugins = g_slist_prepend (priv->missing_plugins, gst_message_ref (msg));
 		else if (!strcmp (gst_structure_get_name (msg->structure), "level")
 		     &&   gst_structure_has_field (msg->structure, "peak")) {
@@ -810,6 +887,7 @@
 		break;
 
 	case GST_MESSAGE_EOS:
+		BRASERO_BURN_LOG ("End of stream reached for %s", priv->info->uri);
 		brasero_metadata_success (self);
 		break;
 
@@ -825,6 +903,7 @@
 						&newstate,
 						NULL,
 						0);
+
 		if (result != GST_STATE_CHANGE_SUCCESS)
 			break;
 
@@ -872,6 +951,109 @@
 	return TRUE;
 }
 
+static gboolean
+brasero_metadata_create_audio_pipeline (BraseroMetadata *self)
+{
+	BraseroMetadataPrivate *priv;
+	GstPad *audio_pad;
+
+	priv = BRASERO_METADATA_PRIVATE (self);
+
+	priv->audio = gst_bin_new (NULL);
+
+	/* set up the pipeline according to flags */
+	if (priv->flags & BRASERO_METADATA_FLAG_SILENCES) {
+		priv->prev_level_mes = 0;
+		gst_object_ref (priv->convert);
+		gst_object_ref (priv->level);
+		gst_object_ref (priv->sink);
+
+		gst_bin_add_many (GST_BIN (priv->audio),
+				  priv->convert,
+				  priv->level,
+				  priv->sink,
+				  NULL);
+		gst_element_link_many (priv->convert,
+				       priv->level,
+				       priv->sink,
+				       NULL);
+		audio_pad = gst_element_get_static_pad (priv->convert, "sink");
+	}
+	else if (priv->flags & BRASERO_METADATA_FLAG_SNAPHOT) {
+		GstElement *queue;
+
+		queue = gst_element_factory_make ("queue", NULL);
+		gst_object_ref (priv->convert);
+		gst_object_ref (priv->sink);
+
+		gst_bin_add_many (GST_BIN (priv->audio),
+				  queue,
+				  priv->convert,
+				  priv->sink,
+				  NULL);
+		gst_element_link_many (queue,
+				       priv->convert,
+				       priv->sink,
+				       NULL);
+		audio_pad = gst_element_get_static_pad (queue, "sink");
+	}
+	else {
+		gst_object_ref (priv->sink);
+		gst_bin_add (GST_BIN (priv->audio), priv->sink);
+		audio_pad = gst_element_get_static_pad (priv->sink, "sink");
+	}
+
+	gst_element_add_pad (priv->audio, gst_ghost_pad_new ("sink", audio_pad));
+	gst_object_unref (audio_pad);
+
+	gst_bin_add (GST_BIN (priv->pipeline), priv->audio);
+	BRASERO_BURN_LOG ("Adding audio pipeline for %s", priv->info->uri);
+
+	return TRUE;
+}
+
+static gboolean
+brasero_metadata_create_video_pipeline (BraseroMetadata *self)
+{
+	BraseroMetadataPrivate *priv;
+	GstElement *colorspace;
+	GstPad *video_pad;
+	GstElement *queue;
+
+	priv = BRASERO_METADATA_PRIVATE (self);
+
+	priv->video = gst_bin_new (NULL);
+
+	priv->snapshot = gst_element_factory_make ("gdkpixbufsink", NULL);
+	colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+	queue = gst_element_factory_make ("queue", NULL);
+
+	g_object_set (priv->snapshot,
+		      "qos", FALSE,
+		      "send-messages", FALSE,
+		      "max-lateness", (gint64) - 1,
+		      NULL);
+
+	gst_bin_add_many (GST_BIN (priv->video),
+			  queue,
+			  colorspace,
+			  priv->snapshot,
+			  NULL);
+	gst_element_link_many (queue,
+			       colorspace,
+			       priv->snapshot,
+			       NULL);
+
+	video_pad = gst_element_get_static_pad (queue, "sink");
+	gst_element_add_pad (priv->video, gst_ghost_pad_new ("sink", video_pad));
+	gst_object_unref (video_pad);
+
+	gst_bin_add (GST_BIN (priv->pipeline), priv->video);
+	BRASERO_BURN_LOG ("Adding pixbuf snapshot sink for %s", priv->info->uri);
+
+	return TRUE;
+}
+
 static void
 brasero_metadata_new_decoded_pad_cb (GstElement *decode,
 				     GstPad *pad,
@@ -880,6 +1062,9 @@
 {
 	GstPad *sink;
 	GstCaps *caps;
+	const gchar *name;
+	gboolean has_audio;
+	gboolean has_video;
 	GstPadLinkReturn res;
 	GstStructure *structure;
 	BraseroMetadataPrivate *priv;
@@ -887,26 +1072,55 @@
 	priv = BRASERO_METADATA_PRIVATE (self);
 
 	res = GST_PAD_LINK_REFUSED;
-	BRASERO_BURN_LOG ("new pad");
-	sink = gst_element_get_pad (priv->first, "sink");
-	if (!sink || GST_PAD_IS_LINKED (sink))
-		return;
+
+	BRASERO_BURN_LOG ("New pad for %s", priv->info->uri);
 
 	/* make sure that this is audio / video */
 	caps = gst_pad_get_caps (pad);
 	structure = gst_caps_get_structure (caps, 0);
-	if (structure) {
-		const gchar *name;
+	if (!structure)
+		return;
+
+	name = gst_structure_get_name (structure);
+	has_audio = (g_strrstr (name, "audio") != NULL);
+	has_video = (g_strrstr (name, "video") != NULL);
+
+	priv->info->has_audio |= has_audio;
+	priv->info->has_video |= has_video;
+
+	if (has_audio && !priv->audio_linked) {
+		brasero_metadata_create_audio_pipeline (self);
+		sink = gst_element_get_static_pad (priv->audio, "sink");
+		if (sink && !GST_PAD_IS_LINKED (sink)) {
+			res = gst_pad_link (pad, sink);
+			BRASERO_BURN_LOG ("Audio stream link %i for %s", res, priv->info->uri);
+			gst_object_unref (sink);
 
-		name = gst_structure_get_name (structure);
-		priv->info->has_audio = (g_strrstr (name, "audio") != NULL);
-		priv->info->has_video = (g_strrstr (name, "video") != NULL);
+			priv->audio_linked = (res == GST_PAD_LINK_OK);
+			gst_element_set_state (priv->audio, BRASERO_METADATA_INITIAL_STATE);
+		}
+	}
+
+	if (g_strrstr (name, "video/x-raw-") && !priv->video_linked) {
+		if (priv->flags & BRASERO_METADATA_FLAG_SNAPHOT) {
+			brasero_metadata_create_video_pipeline (self);
+			sink = gst_element_get_static_pad (priv->video, "sink");
+			if (!sink || GST_PAD_IS_LINKED (sink)) {
+				gst_object_unref (sink);
+				gst_caps_unref (caps);
+				return;
+			}
 
-		if (priv->info->has_audio || priv->info->has_video)
 			res = gst_pad_link (pad, sink);
+			priv->video_linked = (res == GST_PAD_LINK_OK);
+			gst_object_unref (sink);
+
+			gst_element_set_state (priv->video, BRASERO_METADATA_INITIAL_STATE);
+
+			BRASERO_BURN_LOG ("Video stream link %i for %s", res, priv->info->uri);
+		}
 	}
 
-	gst_object_unref (sink);
 	gst_caps_unref (caps);
 }
 
@@ -940,6 +1154,7 @@
 					   "Can't create audioconvert");
 		return FALSE;
 	}
+	gst_object_ref (priv->convert);
 
 	priv->level = gst_element_factory_make ("level", NULL);
 	if (!priv->level) {
@@ -948,6 +1163,7 @@
 					   "Can't create level");
 		return FALSE;
 	}
+	gst_object_ref (priv->level);
 	g_object_set (priv->level,
 		      "message", TRUE,
 		      "interval", (guint64) BRASERO_METADATA_SILENCE_INTERVAL,
@@ -960,7 +1176,7 @@
 					   "Can't create fake sink");
 		return FALSE;
 	}
-	gst_bin_add (GST_BIN (priv->pipeline), priv->sink);
+	gst_object_ref (priv->sink);
 
 	return TRUE;
 }
@@ -974,6 +1190,8 @@
 
 	priv = BRASERO_METADATA_PRIVATE (self);
 
+	BRASERO_BURN_LOG ("New retrieval for %s", uri);
+
 	brasero_metadata_info_free (priv->info);
 	priv->info = NULL;
 
@@ -996,6 +1214,17 @@
 			gst_bin_remove (GST_BIN (priv->pipeline), priv->source);
 			priv->source = NULL;
 		}
+
+		if (priv->audio) {
+			gst_bin_remove (GST_BIN (priv->pipeline), priv->audio);
+			priv->audio = NULL;
+		}
+
+		if (priv->video) {
+			gst_bin_remove (GST_BIN (priv->pipeline), priv->video);
+			priv->snapshot = NULL;
+			priv->video = NULL;
+		}
 	}
 	else if (!brasero_metadata_create_pipeline (self))
 		return FALSE;
@@ -1003,36 +1232,9 @@
 	if (!gst_uri_is_valid (uri))
 		return FALSE;
 
-	/* set up the pipeline according to flags */
-	if (priv->flags & BRASERO_METADATA_FLAG_SILENCES) {
-		priv->prev_level_mes = 0;
-		if (priv->first != priv->convert) {
-			gst_bin_add_many (GST_BIN (priv->pipeline),
-					  priv->convert,
-					  priv->level,
-					  NULL);
-			gst_element_link_many (priv->convert,
-					       priv->level,
-					       priv->sink,
-					       NULL);
-
-			priv->first = priv->convert;
-		}
-	}
-	else {
-		if (priv->first == priv->convert) {
-			gst_object_ref (priv->convert);
-			gst_object_ref (priv->level);
-
-			gst_bin_remove_many (GST_BIN (priv->pipeline),
-					     priv->convert,
-					     priv->level,
-					     NULL);
-		}
-
-		if (priv->first != priv->sink)
-			priv->first = priv->sink;
-	}
+	priv->video_linked = 0;
+	priv->audio_linked = 0;
+	priv->snapshot_started = 0;
 
 	/* create a necessary source */
 	priv->source = gst_element_make_from_uri (GST_URI_SRC,
@@ -1113,7 +1315,7 @@
 	}
 
 	priv->started = 1;
-	gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PLAYING);
+	gst_element_set_state (GST_ELEMENT (priv->pipeline), BRASERO_METADATA_INITIAL_STATE);
 	g_cond_wait (priv->cond, priv->mutex);
 	g_mutex_unlock (priv->mutex);
 
@@ -1159,7 +1361,7 @@
 	}
 
 	priv->started = 1;
-	gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PLAYING);
+	gst_element_set_state (GST_ELEMENT (priv->pipeline), BRASERO_METADATA_INITIAL_STATE);
 
 	/* run the loop until it's finished */
 	priv->loop = g_main_loop_new (NULL, FALSE);
@@ -1211,7 +1413,7 @@
 	}
 
 	priv->started = 1;
-	gst_element_set_state (GST_ELEMENT (priv->pipeline), GST_STATE_PLAYING);
+	gst_element_set_state (GST_ELEMENT (priv->pipeline), BRASERO_METADATA_INITIAL_STATE);
 
 	return TRUE;
 }
@@ -1252,6 +1454,11 @@
 	if (src->musicbrainz_id)
 		dest->musicbrainz_id = g_strdup (src->musicbrainz_id);
 
+	if (src->snapshot) {
+		dest->snapshot = src->snapshot;
+		g_object_ref (dest->snapshot);
+	}
+
 	for (iter = src->silences; iter; iter = iter->next) {
 		BraseroMetadataSilence *silence, *copy;
 
@@ -1336,16 +1543,34 @@
 	if (change == GST_STATE_CHANGE_FAILURE)
 		g_warning ("State change failure\n");
 
+	if (priv->audio) {
+		gst_bin_remove (GST_BIN (priv->pipeline), priv->audio);
+		priv->audio = NULL;
+	}
+
+	if (priv->video) {
+		gst_bin_remove (GST_BIN (priv->pipeline), priv->video);
+		priv->snapshot = NULL;
+		priv->video = NULL;
+	}
+
 	gst_object_unref (GST_OBJECT (priv->pipeline));
 	priv->pipeline = NULL;
 
-	if (priv->first == priv->sink) {
-		gst_object_unref (GST_OBJECT (priv->convert));
-		priv->convert = NULL;
-
+	if (priv->level) {
 		gst_object_unref (GST_OBJECT (priv->level));
 		priv->level = NULL;
 	}
+
+	if (priv->sink) {
+		gst_object_unref (GST_OBJECT (priv->sink));
+		priv->sink = NULL;
+	}
+
+	if (priv->convert) {
+		gst_object_unref (GST_OBJECT (priv->convert));
+		priv->convert = NULL;
+	}
 }
 
 static void

Modified: trunk/src/brasero-metadata.h
==============================================================================
--- trunk/src/brasero-metadata.h	(original)
+++ trunk/src/brasero-metadata.h	Mon Jul 14 18:07:55 2008
@@ -29,6 +29,8 @@
 #include <glib-object.h>
 #include <gio/gio.h>
 
+#include <gdk/gdkpixbuf.h>
+
 #include <gst/gst.h>
 
 G_BEGIN_DECLS
@@ -37,7 +39,8 @@
 	BRASERO_METADATA_FLAG_NONE			= 0,
 	BRASERO_METADATA_FLAG_FAST			= 1,
 	BRASERO_METADATA_FLAG_SILENCES			= 1 << 1,
-	BRASERO_METADATA_FLAG_MISSING			= 1 << 2
+	BRASERO_METADATA_FLAG_MISSING			= 1 << 2,
+	BRASERO_METADATA_FLAG_SNAPHOT			= 1 << 3
 } BraseroMetadataFlag;
 
 #define BRASERO_TYPE_METADATA         (brasero_metadata_get_type ())
@@ -66,6 +69,8 @@
 
 	GSList *silences;
 
+	GdkPixbuf *snapshot;
+
 	guint is_seekable:1;
 	guint has_audio:1;
 	guint has_video:1;

Modified: trunk/src/brasero-multi-song-props.c
==============================================================================
--- trunk/src/brasero-multi-song-props.c	(original)
+++ trunk/src/brasero-multi-song-props.c	Mon Jul 14 18:07:55 2008
@@ -42,6 +42,8 @@
 	GtkWidget *artist;
 	GtkWidget *composer;
 	GtkWidget *isrc;
+
+	GtkWidget *gap_box;
 	GtkWidget *gap;
 };
 
@@ -169,6 +171,18 @@
 
 	return FALSE;
 }
+void
+brasero_multi_song_props_set_show_gap (BraseroMultiSongProps *self,
+				       gboolean show)
+{
+	BraseroMultiSongPropsPrivate *priv;
+
+	priv = BRASERO_MULTI_SONG_PROPS_PRIVATE (self);
+	if (show)
+		gtk_widget_show (priv->gap_box);
+	else
+		gtk_widget_hide (priv->gap_box);
+}
 
 static void
 brasero_multi_song_props_init (BraseroMultiSongProps *object)
@@ -280,6 +294,8 @@
 	gtk_widget_show (box);
 
 	frame = brasero_utils_pack_properties (_("<b>Options</b>"), box, NULL);
+	priv->gap_box = frame;
+
 	gtk_widget_show (frame);
 	gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox), frame, FALSE, FALSE, 0);

Modified: trunk/src/brasero-multi-song-props.h
==============================================================================
--- trunk/src/brasero-multi-song-props.h	(original)
+++ trunk/src/brasero-multi-song-props.h	Mon Jul 14 18:07:55 2008
@@ -56,7 +56,11 @@
 brasero_multi_song_props_new (void);
 
 void
-brasero_multi_song_props_set_rename_callback (BraseroMultiSongProps *self,
+brasero_multi_song_props_set_show_gap (BraseroMultiSongProps *props,
+				       gboolean show);
+
+void
+brasero_multi_song_props_set_rename_callback (BraseroMultiSongProps *props,
 					      GtkTreeSelection *selection,
 					      gint column_num,
 					      BraseroRenameCallback callback);

Modified: trunk/src/brasero-project-manager.c
==============================================================================
--- trunk/src/brasero-project-manager.c	(original)
+++ trunk/src/brasero-project-manager.c	Mon Jul 14 18:07:55 2008
@@ -86,6 +86,8 @@
 static void
 brasero_project_manager_new_data_prj_cb (GtkAction *action, BraseroProjectManager *manager);
 static void
+brasero_project_manager_new_video_prj_cb (GtkAction *action, BraseroProjectManager *manager);
+static void
 brasero_project_manager_new_copy_prj_cb (GtkAction *action, BraseroProjectManager *manager);
 static void
 brasero_project_manager_new_iso_prj_cb (GtkAction *action, BraseroProjectManager *manager);
@@ -115,6 +117,8 @@
 	 N_("Create a new audio project"), G_CALLBACK (brasero_project_manager_new_audio_prj_cb)},
 	{"NewData", "media-optical-data-new", N_("New _Data Project"), NULL,
 	 N_("Create a new data project"), G_CALLBACK (brasero_project_manager_new_data_prj_cb)},
+	{"NewVideo", "media-optical-video-new", N_("New _Video Project"), NULL,
+	 N_("Create a new video project"), G_CALLBACK (brasero_project_manager_new_video_prj_cb)},
 	{"NewCopy", "media-optical-copy", N_("Copy _Disc..."), NULL,
 	 N_("Copy a disc"), G_CALLBACK (brasero_project_manager_new_copy_prj_cb)},
 	{"NewIso", "iso-image-burn", N_("_Burn Image..."), NULL,
@@ -132,6 +136,7 @@
 				"<menu action='New'>"
 					"<menuitem action='NewAudio'/>"
 					"<menuitem action='NewData'/>"
+					"<menuitem action='NewVideo'/>"
 					"<menuitem action='NewCopy'/>"	
 					"<menuitem action='NewIso'/>"	
 				"</menu>"
@@ -516,7 +521,8 @@
 	GtkAction *action;
 
 	if ((manager->priv->type == BRASERO_PROJECT_TYPE_AUDIO
-	||   manager->priv->type == BRASERO_PROJECT_TYPE_DATA)
+	||   manager->priv->type == BRASERO_PROJECT_TYPE_DATA
+	||   manager->priv->type == BRASERO_PROJECT_TYPE_VIDEO)
 	&&  !brasero_project_confirm_switch (BRASERO_PROJECT (manager->priv->project)))
 		return;
 
@@ -566,6 +572,20 @@
 		if (toplevel)
 			gtk_window_set_title (GTK_WINDOW (toplevel), _("Brasero - New Data Disc Project"));
 	}
+	else if (type == BRASERO_PROJECT_TYPE_VIDEO) {
+		brasero_layout_load (BRASERO_LAYOUT (manager->priv->layout), BRASERO_LAYOUT_VIDEO);
+
+		gtk_notebook_set_current_page (GTK_NOTEBOOK (manager), 1);
+		gtk_action_set_sensitive (action, TRUE);
+
+		if (reset) {
+			/* tell the BraseroProject object that we want a data selection */
+			brasero_project_set_video (BRASERO_PROJECT (manager->priv->project), uris);
+		}
+
+		if (toplevel)
+			gtk_window_set_title (GTK_WINDOW (toplevel), _("Brasero - New Video disc project"));
+	}
 	else if (type == BRASERO_PROJECT_TYPE_ISO) {
 		brasero_layout_load (BRASERO_LAYOUT (manager->priv->layout), BRASERO_LAYOUT_NONE);
 		brasero_project_set_none (BRASERO_PROJECT (manager->priv->project));
@@ -618,6 +638,12 @@
 }
 
 static void
+brasero_project_manager_new_video_prj_cb (GtkAction *action, BraseroProjectManager *manager)
+{
+	brasero_project_manager_switch (manager, BRASERO_PROJECT_TYPE_VIDEO, NULL, NULL, TRUE);
+}
+
+static void
 brasero_project_manager_new_copy_prj_cb (GtkAction *action, BraseroProjectManager *manager)
 {
 	brasero_project_manager_switch (manager, BRASERO_PROJECT_TYPE_COPY, NULL, NULL, TRUE);
@@ -650,6 +676,16 @@
 }
 
 void
+brasero_project_manager_video (BraseroProjectManager *manager, GSList *uris)
+{
+	brasero_project_manager_switch (manager,
+					BRASERO_PROJECT_TYPE_VIDEO,
+					uris,
+					NULL,
+					TRUE);
+}
+
+void
 brasero_project_manager_copy (BraseroProjectManager *manager)
 {
 	brasero_project_manager_switch (manager, BRASERO_PROJECT_TYPE_COPY, NULL, NULL, TRUE);
@@ -951,7 +987,7 @@
 				   _("Browse the file system"),
 				   _("Display File Browser"),
 				   GTK_STOCK_DIRECTORY,
-				   BRASERO_LAYOUT_AUDIO|BRASERO_LAYOUT_DATA);
+				   BRASERO_LAYOUT_AUDIO|BRASERO_LAYOUT_DATA|BRASERO_LAYOUT_VIDEO);
 
 #ifdef BUILD_PREVIEW
 	brasero_preview_add_source (BRASERO_PREVIEW (preview),
@@ -975,7 +1011,7 @@
 				   _("Search files using keywords"),
 				   _("Display Search"),
 				   GTK_STOCK_FIND,
-				   BRASERO_LAYOUT_AUDIO|BRASERO_LAYOUT_DATA);
+				   BRASERO_LAYOUT_AUDIO|BRASERO_LAYOUT_DATA|BRASERO_LAYOUT_VIDEO);
 
 #ifdef BUILD_PREVIEW
 	brasero_preview_add_source (BRASERO_PREVIEW (preview),

Modified: trunk/src/brasero-project-manager.h
==============================================================================
--- trunk/src/brasero-project-manager.h	(original)
+++ trunk/src/brasero-project-manager.h	Mon Jul 14 18:07:55 2008
@@ -61,6 +61,8 @@
 void
 brasero_project_manager_data (BraseroProjectManager *manager, GSList *uris);
 void
+brasero_project_manager_video (BraseroProjectManager *manager, GSList *uris);
+void
 brasero_project_manager_copy (BraseroProjectManager *manager);
 void
 brasero_project_manager_iso (BraseroProjectManager *manager, const gchar *uri);

Modified: trunk/src/brasero-project-type-chooser.c
==============================================================================
--- trunk/src/brasero-project-type-chooser.c	(original)
+++ trunk/src/brasero-project-type-chooser.c	Mon Jul 14 18:07:55 2008
@@ -79,6 +79,11 @@
 	N_("Create a CD/DVD containing any type of data that can only be read on a computer"),
 	"media-optical-data-new",
 	BRASERO_PROJECT_TYPE_DATA},
+       {N_("<big>_Video project</big>"),
+	N_("Create a video DVD or a SVCD"),
+	N_("Create a video DVD or a SVCD that are readable on TV readers"),
+	"media-optical-copy",
+	BRASERO_PROJECT_TYPE_VIDEO},
        {N_("<big>Disc _copy</big>"),
 	N_("Create 1:1 copy of a CD/DVD"),
 	N_("Create a 1:1 copy of an audio CD or a data CD/DVD on your hardisk or on another CD/DVD"),

Modified: trunk/src/brasero-project-type-chooser.h
==============================================================================
--- trunk/src/brasero-project-type-chooser.h	(original)
+++ trunk/src/brasero-project-type-chooser.h	Mon Jul 14 18:07:55 2008
@@ -31,6 +31,7 @@
 #include <gtk/gtkeventbox.h>
 
 G_BEGIN_DECLS
+
 #define BRASERO_TYPE_PROJECT_TYPE_CHOOSER         (brasero_project_type_chooser_get_type ())
 #define BRASERO_PROJECT_TYPE_CHOOSER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), BRASERO_TYPE_PROJECT_TYPE_CHOOSER, BraseroProjectTypeChooser))
 #define BRASERO_PROJECT_TYPE_CHOOSER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k),BRASERO_TYPE_PROJECT_TYPE_CHOOSER, BraseroProjectTypeChooserClass))
@@ -51,6 +52,7 @@
 	BRASERO_PROJECT_TYPE_ISO,
 	BRASERO_PROJECT_TYPE_AUDIO,
 	BRASERO_PROJECT_TYPE_DATA,
+	BRASERO_PROJECT_TYPE_VIDEO
 } BraseroProjectType;
 
 typedef struct {

Modified: trunk/src/brasero-project.c
==============================================================================
--- trunk/src/brasero-project.c	(original)
+++ trunk/src/brasero-project.c	Mon Jul 14 18:07:55 2008
@@ -71,6 +71,7 @@
 #include "brasero-disc.h"
 #include "brasero-data-disc.h"
 #include "brasero-audio-disc.h"
+#include "brasero-video-disc.h"
 #include "brasero-disc-option-dialog.h"
 #include "brasero-burn-dialog.h"
 #include "brasero-utils.h"
@@ -157,6 +158,7 @@
 	GtkWidget *discs;
 	GtkWidget *audio;
 	GtkWidget *data;
+	GtkWidget *video;
 
 	GtkWidget *message;
 
@@ -438,7 +440,7 @@
 	gtk_container_add (GTK_CONTAINER (alignment), obj->priv->burn);
 	gtk_box_pack_end (GTK_BOX (box), alignment, FALSE, FALSE, 0);
 
-	/* The two panes to put into the notebook */
+	/* The three panes to put into the notebook */
 	obj->priv->audio = brasero_audio_disc_new ();
 	gtk_widget_show (obj->priv->audio);
 	g_signal_connect (G_OBJECT (obj->priv->audio),
@@ -474,10 +476,28 @@
 			  G_CALLBACK (brasero_project_selection_changed_cb),
 			  obj);
 
+	obj->priv->video = brasero_video_disc_new ();
+	gtk_widget_show (obj->priv->video);
+	g_signal_connect (G_OBJECT (obj->priv->video),
+			  "contents-changed",
+			  G_CALLBACK (brasero_project_contents_changed_cb),
+			  obj);
+	g_signal_connect (G_OBJECT (obj->priv->video),
+			  "size-changed",
+			  G_CALLBACK (brasero_project_size_changed_cb),
+			  obj);
+	g_signal_connect (G_OBJECT (obj->priv->video),
+			  "selection-changed",
+			  G_CALLBACK (brasero_project_selection_changed_cb),
+			  obj);
+
 	obj->priv->discs = gtk_notebook_new ();
 	gtk_widget_show (obj->priv->discs);
 	gtk_notebook_set_show_border (GTK_NOTEBOOK (obj->priv->discs), FALSE);
 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (obj->priv->discs), FALSE);
+
+	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
+				   obj->priv->video, NULL);
 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
 				   obj->priv->data, NULL);
 	gtk_notebook_prepend_page (GTK_NOTEBOOK (obj->priv->discs),
@@ -1069,7 +1089,7 @@
 
 /********************************     ******************************************/
 static void
-brasero_project_switch (BraseroProject *project, gboolean audio)
+brasero_project_switch (BraseroProject *project, BraseroProjectType type)
 {
 	GtkAction *action;
 	GConfClient *client;
@@ -1100,7 +1120,7 @@
 		gtk_ui_manager_remove_ui (project->priv->manager,
 					  project->priv->merge_id);
 
-	if (audio) {
+	if (type == BRASERO_PROJECT_TYPE_AUDIO) {
 		project->priv->current = BRASERO_DISC (project->priv->audio);
 		project->priv->merge_id = brasero_disc_add_ui (project->priv->current,
 							       project->priv->manager,
@@ -1109,7 +1129,7 @@
 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 0);
 		brasero_project_size_set_context (BRASERO_PROJECT_SIZE (project->priv->size_display), TRUE);
 	}
-	else {
+	else if (type == BRASERO_PROJECT_TYPE_DATA) {
 		project->priv->current = BRASERO_DISC (project->priv->data);
 		project->priv->merge_id = brasero_disc_add_ui (project->priv->current,
 							       project->priv->manager,
@@ -1118,6 +1138,15 @@
 		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 1);
 		brasero_project_size_set_context (BRASERO_PROJECT_SIZE (project->priv->size_display), FALSE);
 	}
+	else if (type == BRASERO_PROJECT_TYPE_VIDEO) {
+		project->priv->current = BRASERO_DISC (project->priv->video);
+		project->priv->merge_id = brasero_disc_add_ui (project->priv->current,
+							       project->priv->manager,
+							       project->priv->message);
+
+		gtk_notebook_set_current_page (GTK_NOTEBOOK (project->priv->discs), 2);
+		brasero_project_size_set_context (BRASERO_PROJECT_SIZE (project->priv->size_display), TRUE);
+	}
 
 	brasero_notify_message_remove (BRASERO_NOTIFY (project->priv->message), BRASERO_NOTIFY_CONTEXT_SIZE);
 
@@ -1140,7 +1169,7 @@
 void
 brasero_project_set_audio (BraseroProject *project, GSList *uris)
 {
-	brasero_project_switch (project, TRUE);
+	brasero_project_switch (project, BRASERO_PROJECT_TYPE_AUDIO);
 
 	for (; uris; uris = uris->next) {
 		gchar *uri;
@@ -1153,7 +1182,20 @@
 void
 brasero_project_set_data (BraseroProject *project, GSList *uris)
 {
-	brasero_project_switch (project, FALSE);
+	brasero_project_switch (project, BRASERO_PROJECT_TYPE_DATA);
+
+	for (; uris; uris = uris->next) {
+		gchar *uri;
+
+	    	uri = uris->data;
+		brasero_disc_add_uri (project->priv->current, uri);
+	}
+}
+
+void
+brasero_project_set_video (BraseroProject *project, GSList *uris)
+{
+	brasero_project_switch (project, BRASERO_PROJECT_TYPE_VIDEO);
 
 	for (; uris; uris = uris->next) {
 		gchar *uri;
@@ -1700,9 +1742,11 @@
     	BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
 	if (type == BRASERO_PROJECT_TYPE_DATA)
 		title = g_strdup_printf (_("Brasero - %s (Data Disc)"), name);
-	else
+	else if (type == BRASERO_PROJECT_TYPE_AUDIO)
 		title = g_strdup_printf (_("Brasero - %s (Audio Disc)"), name);
-    	g_free (name);
+	else if (type == BRASERO_PROJECT_TYPE_AUDIO)
+		title = g_strdup_printf (_("Brasero - %s (Video Disc)"), name);
+	g_free (name);
 
 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (project));
 	gtk_window_set_title (GTK_WINDOW (toplevel), title);
@@ -1859,8 +1903,6 @@
 	BraseroDiscSong *song;
 
 	track = g_new0 (BraseroDiscTrack, 1);
-	track->type = BRASERO_DISC_TRACK_AUDIO;
-
 	song = NULL;
 
 	while (uris) {
@@ -1964,6 +2006,8 @@
 						      track_node->xmlChildrenNode);
 			if (!newtrack)
 				goto error;
+
+			newtrack->type = BRASERO_DISC_TRACK_AUDIO;
 		}
 		else if (!xmlStrcmp (track_node->name, (const xmlChar *) "data")) {
 			if (newtrack)
@@ -1975,6 +2019,18 @@
 			if (!newtrack)
 				goto error;
 		}
+		else if (!xmlStrcmp (track_node->name, (const xmlChar *) "video")) {
+			if (newtrack)
+				goto error;
+
+			newtrack = _read_audio_track (project,
+						      track_node->xmlChildrenNode);
+
+			if (!newtrack)
+				goto error;
+
+			newtrack->type = BRASERO_DISC_TRACK_VIDEO;
+		}
 		else if (track_node->type == XML_ELEMENT_NODE)
 			goto error;
 
@@ -2087,19 +2143,19 @@
 	brasero_project_size_set_sectors (BRASERO_PROJECT_SIZE (project->priv->size_display),
 					  0);
 
-	if (track->type == BRASERO_DISC_TRACK_AUDIO) {
-		brasero_project_switch (project, TRUE);
+	if (track->type == BRASERO_DISC_TRACK_AUDIO)
 		type = BRASERO_PROJECT_TYPE_AUDIO;
-	}
-	else if (track->type == BRASERO_DISC_TRACK_DATA) {
-		brasero_project_switch (project, FALSE);
+	else if (track->type == BRASERO_DISC_TRACK_DATA)
 		type = BRASERO_PROJECT_TYPE_DATA;
-	}
+	else if (track->type == BRASERO_DISC_TRACK_VIDEO)
+		type = BRASERO_PROJECT_TYPE_VIDEO;
 	else {
 		brasero_track_free (track);
 		return BRASERO_PROJECT_TYPE_INVALID;
 	}
 
+	brasero_project_switch (project, type);
+
 	brasero_disc_load_track (project->priv->current, track);
 	brasero_track_free (track);
 
@@ -2205,19 +2261,19 @@
 	if (!brasero_project_open_project_xml (project, uri, &track, FALSE))
 		return BRASERO_PROJECT_TYPE_INVALID;
 
-	if (track->type == BRASERO_DISC_TRACK_AUDIO) {
-		brasero_project_switch (project, TRUE);
+	if (track->type == BRASERO_DISC_TRACK_AUDIO)
 		type = BRASERO_PROJECT_TYPE_AUDIO;
-	}
-	else if (track->type == BRASERO_DISC_TRACK_DATA) {
-		brasero_project_switch (project, FALSE);
+	else if (track->type == BRASERO_DISC_TRACK_DATA)
 		type = BRASERO_PROJECT_TYPE_DATA;
-	}
+	else if (track->type == BRASERO_DISC_TRACK_VIDEO)
+		type = BRASERO_PROJECT_TYPE_VIDEO;
 	else {
 	    	brasero_track_free (track);
 		return BRASERO_PROJECT_TYPE_INVALID;
 	}
 
+	brasero_project_switch (project, type);
+
 	brasero_disc_load_track (project->priv->current, track);
 	brasero_track_free (track);
 
@@ -2500,7 +2556,20 @@
 		if (success < 0)
 			goto error;
 	}
-	else 
+	else  if (track->type == BRASERO_DISC_TRACK_VIDEO) {
+		success = xmlTextWriterStartElement (project, (xmlChar *) "video");
+		if (success < 0)
+			goto error;
+
+		retval = _save_audio_track_xml (project, track);
+		if (!retval)
+			goto error;
+
+		success = xmlTextWriterEndElement (project); /* audio */
+		if (success < 0)
+			goto error;
+	}
+	else
 		retval = FALSE;
 
 	success = xmlTextWriterEndElement (project); /* track */

Modified: trunk/src/brasero-project.h
==============================================================================
--- trunk/src/brasero-project.h	(original)
+++ trunk/src/brasero-project.h	Mon Jul 14 18:07:55 2008
@@ -70,6 +70,8 @@
 void
 brasero_project_set_data (BraseroProject *project, GSList *uris);
 void
+brasero_project_set_video (BraseroProject *project, GSList *uris);
+void
 brasero_project_set_none (BraseroProject *project);
 
 void

Modified: trunk/src/brasero-song-properties.c
==============================================================================
--- trunk/src/brasero-song-properties.c	(original)
+++ trunk/src/brasero-song-properties.c	Mon Jul 14 18:07:55 2008
@@ -57,7 +57,9 @@
 	GtkWidget *length;
 	GtkWidget *start;
 	GtkWidget *end;
+
 	GtkWidget *gap;
+	GtkWidget *gap_label;
 };
 
 static GObjectClass *parent_class = NULL;
@@ -201,6 +203,7 @@
 	gtk_table_attach (GTK_TABLE (table), obj->priv->end, 1, 2, 1, 2, 0, 0, 0, 0);
 
 	label = gtk_label_new (_("Pause length:\t"));
+	obj->priv->gap_label = label;
 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 	obj->priv->gap = gtk_spin_button_new_with_range (0.0, 100.0, 1.0);
 	alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
@@ -242,6 +245,21 @@
 	gtk_window_set_title (GTK_WINDOW (obj), _("Song Information"));
 }
 
+static gchar *
+brasero_song_props_get_entry_value (GtkEntry *entry)
+{
+	const gchar *text;
+
+	text = gtk_entry_get_text (entry);
+	if (!text)
+		return NULL;
+
+	if (text [0] == '\0')
+		return NULL;
+
+	return g_strdup (text);
+}
+
 void
 brasero_song_props_get_properties (BraseroSongProps *self,
 				   gchar **artist,
@@ -253,16 +271,20 @@
 				   gint64 *gap)
 {
 	if (artist)
-		*artist = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->priv->artist)));
+		*artist = brasero_song_props_get_entry_value (GTK_ENTRY (self->priv->artist));
 	if (title)
-		*title = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->priv->title)));
+		*title = brasero_song_props_get_entry_value (GTK_ENTRY (self->priv->title));
 	if (composer)
-		*composer = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->priv->composer)));
+		*composer = brasero_song_props_get_entry_value (GTK_ENTRY (self->priv->composer));
+
 	if (isrc) {
 		const gchar *string;
 
-		string = gtk_entry_get_text (GTK_ENTRY (self->priv->isrc));
-		*isrc = (gint) g_strtod (string, NULL);
+		string = brasero_song_props_get_entry_value (GTK_ENTRY (self->priv->isrc));
+		if (string)
+			*isrc = (gint) g_strtod (string, NULL);
+		else
+			*isrc = 0;
 	}
 
 	if (start)
@@ -288,9 +310,19 @@
 	gchar *string;
 	gdouble secs;
 
-	string = g_strdup_printf (_("<b>Song information for track %02i</b>"), track_num);
-	gtk_label_set_markup (GTK_LABEL (self->priv->label), string);
-	g_free (string);
+	if (track_num >= 0) {
+		string = g_strdup_printf (_("<b>Song information for track %02i</b>"), track_num);
+		gtk_label_set_markup (GTK_LABEL (self->priv->label), string);
+		g_free (string);
+	}
+	else {
+		brasero_time_button_set_show_frames (BRASERO_TIME_BUTTON (self->priv->start), FALSE);
+		brasero_time_button_set_show_frames (BRASERO_TIME_BUTTON (self->priv->end), FALSE);
+
+		gtk_widget_hide (self->priv->gap_label);
+		gtk_widget_hide (self->priv->label);
+		gtk_widget_hide (self->priv->gap);
+	}
 
 	if (artist)
 		gtk_entry_set_text (GTK_ENTRY (self->priv->artist), artist);
@@ -304,8 +336,14 @@
 		g_free (string);
 	}
 
-	secs = gap / GST_SECOND;
-	gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->priv->gap), secs);
+	if (gap > 0) {
+		secs = gap / GST_SECOND;
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->priv->gap), secs);
+	}
+	else {
+		gtk_widget_hide (self->priv->gap);
+		gtk_widget_hide (self->priv->gap_label);
+	}
 
 	brasero_time_button_set_max (BRASERO_TIME_BUTTON (self->priv->start), end - 1);
 	brasero_time_button_set_value (BRASERO_TIME_BUTTON (self->priv->start), start);

Modified: trunk/src/brasero-time-button.c
==============================================================================
--- trunk/src/brasero-time-button.c	(original)
+++ trunk/src/brasero-time-button.c	Mon Jul 14 18:07:55 2008
@@ -162,6 +162,20 @@
 }
 
 void
+brasero_time_button_set_show_frames (BraseroTimeButton *self,
+				     gboolean show)
+{
+	BraseroTimeButtonPrivate *priv;
+
+	priv = BRASERO_TIME_BUTTON_PRIVATE (self);
+
+	if (show)
+		gtk_widget_show (priv->frame);
+	else
+		gtk_widget_hide (priv->frame);
+}
+
+void
 brasero_time_button_set_max (BraseroTimeButton *self,
 			     gint64 max)
 {

Modified: trunk/src/brasero-time-button.h
==============================================================================
--- trunk/src/brasero-time-button.h	(original)
+++ trunk/src/brasero-time-button.h	Mon Jul 14 18:07:55 2008
@@ -59,14 +59,19 @@
 brasero_time_button_new (void);
 
 gint64
-brasero_time_button_get_value (BraseroTimeButton *self);
+brasero_time_button_get_value (BraseroTimeButton *time);
 
 void
-brasero_time_button_set_value (BraseroTimeButton *self,
+brasero_time_button_set_value (BraseroTimeButton *time,
 			       gint64 value);
 void
-brasero_time_button_set_max (BraseroTimeButton *self,
+brasero_time_button_set_max (BraseroTimeButton *time,
 			     gint64 max);
+
+void
+brasero_time_button_set_show_frames (BraseroTimeButton *time,
+				     gboolean show);
+
 G_END_DECLS
 
 #endif /* _BRASERO_TIME_BUTTON_H_ */

Added: trunk/src/brasero-video-disc.c
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-disc.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,1480 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include <gtk/gtk.h>
+
+#include "eggtreemultidnd.h"
+
+#include "burn-debug.h"
+#include "brasero-disc.h"
+#include "brasero-io.h"
+#include "brasero-utils.h"
+#include "brasero-video-disc.h"
+#include "brasero-video-project.h"
+#include "brasero-video-tree-model.h"
+#include "brasero-multi-song-props.h"
+#include "brasero-song-properties.h"
+
+typedef struct _BraseroVideoDiscPrivate BraseroVideoDiscPrivate;
+struct _BraseroVideoDiscPrivate
+{
+	GtkWidget *notebook;
+	GtkWidget *tree;
+
+	GtkWidget *message;
+	GtkUIManager *manager;
+	GtkActionGroup *disc_group;
+
+	guint reject_files:1;
+	guint editing:1;
+	guint loading:1;
+};
+
+#define BRASERO_VIDEO_DISC_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VIDEO_DISC, BraseroVideoDiscPrivate))
+
+static void
+brasero_video_disc_iface_disc_init (BraseroDiscIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (BraseroVideoDisc,
+			 brasero_video_disc,
+			 GTK_TYPE_VBOX,
+			 G_IMPLEMENT_INTERFACE (BRASERO_TYPE_DISC,
+					        brasero_video_disc_iface_disc_init));
+
+enum {
+	PROP_NONE,
+	PROP_REJECT_FILE,
+};
+
+static void
+brasero_video_disc_edit_information_cb (GtkAction *action,
+					BraseroVideoDisc *disc);
+static void
+brasero_video_disc_open_activated_cb (GtkAction *action,
+				      BraseroVideoDisc *disc);
+static void
+brasero_video_disc_delete_activated_cb (GtkAction *action,
+					BraseroVideoDisc *disc);
+static void
+brasero_video_disc_paste_activated_cb (GtkAction *action,
+				       BraseroVideoDisc *disc);
+
+static GtkActionEntry entries[] = {
+	{"ContextualMenu", NULL, N_("Menu")},
+	{"OpenVideo", GTK_STOCK_OPEN, NULL, NULL, N_("Open the selected video"),
+	 G_CALLBACK (brasero_video_disc_open_activated_cb)},
+	{"EditVideo", GTK_STOCK_PROPERTIES, N_("_Edit Information..."), NULL, N_("Edit the video information (start, end, author, ...)"),
+	 G_CALLBACK (brasero_video_disc_edit_information_cb)},
+	{"DeleteVideo", GTK_STOCK_REMOVE, NULL, NULL, N_("Remove the selected videos from the project"),
+	 G_CALLBACK (brasero_video_disc_delete_activated_cb)},
+	{"PasteVideo", GTK_STOCK_PASTE, NULL, NULL, N_("Add the files stored in the clipboard"),
+	 G_CALLBACK (brasero_video_disc_paste_activated_cb)},
+/*	{"Split", "transform-crop-and-resize", N_("_Split Track..."), NULL, N_("Split the selected track"),
+	 G_CALLBACK (brasero_video_disc_split_cb)} */
+};
+
+static const gchar *description = {
+	"<ui>"
+	"<menubar name='menubar' >"
+		"<menu action='EditMenu'>"
+/*		"<placeholder name='EditPlaceholder'>"
+			"<menuitem action='Split'/>"
+		"</placeholder>"
+*/		"</menu>"
+	"</menubar>"
+	"<popup action='ContextMenu'>"
+		"<menuitem action='OpenVideo'/>"
+		"<menuitem action='DeleteVideo'/>"
+		"<separator/>"
+		"<menuitem action='PasteVideo'/>"
+/*		"<separator/>"
+		"<menuitem action='Split'/>"
+*/		"<separator/>"
+		"<menuitem action='EditVideo'/>"
+	"</popup>"
+/*	"<toolbar name='Toolbar'>"
+		"<placeholder name='DiscButtonPlaceholder'>"
+			"<separator/>"
+			"<toolitem action='Split'/>"
+		"</placeholder>"
+	"</toolbar>"
+*/	"</ui>"
+};
+
+enum {
+	TREE_MODEL_ROW		= 150,
+	TARGET_URIS_LIST,
+};
+
+static GtkTargetEntry ntables_cd [] = {
+	{BRASERO_DND_TARGET_SELF_FILE_NODES, GTK_TARGET_SAME_WIDGET, TREE_MODEL_ROW},
+	{"text/uri-list", 0, TARGET_URIS_LIST}
+};
+static guint nb_targets_cd = sizeof (ntables_cd) / sizeof (ntables_cd[0]);
+
+static GtkTargetEntry ntables_source [] = {
+	{BRASERO_DND_TARGET_SELF_FILE_NODES, GTK_TARGET_SAME_WIDGET, TREE_MODEL_ROW},
+};
+
+static guint nb_targets_source = sizeof (ntables_source) / sizeof (ntables_source[0]);
+
+
+/**
+ * Row name edition
+ */
+
+static void
+brasero_video_disc_name_editing_started_cb (GtkCellRenderer *renderer,
+					    GtkCellEditable *editable,
+					    gchar *path,
+					    BraseroVideoDisc *disc)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+	priv->editing = 1;
+}
+
+static void
+brasero_video_disc_name_editing_canceled_cb (GtkCellRenderer *renderer,
+					     BraseroVideoDisc *disc)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+	priv->editing = 0;
+}
+
+static void
+brasero_video_disc_name_edited_cb (GtkCellRendererText *cellrenderertext,
+				   gchar *path_string,
+				   gchar *text,
+				   BraseroVideoDisc *self)
+{
+	BraseroVideoDiscPrivate *priv;
+	BraseroVideoProject *project;
+	BraseroVideoFile *file;
+	GtkTreePath *path;
+	GtkTreeIter row;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	priv->editing = 0;
+
+	path = gtk_tree_path_new_from_string (path_string);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+
+	/* see if this is still a valid path. It can happen a user removes it
+	 * while the name of the row is being edited */
+	if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (project), &row, path)) {
+		gtk_tree_path_free (path);
+		return;
+	}
+
+	file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (project), path);
+	gtk_tree_path_free (path);
+
+	brasero_video_project_rename (project, file, text);
+}
+
+static void
+brasero_video_disc_vfs_activity_changed (BraseroVideoProject *project,
+					 gboolean activity,
+					 BraseroVideoDisc *self)
+{
+	GdkCursor *cursor;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	if (!GTK_WIDGET (self)->window)
+		return;
+
+	if (activity) {
+		cursor = gdk_cursor_new (GDK_WATCH);
+		gdk_window_set_cursor (GTK_WIDGET (self)->window, cursor);
+		gdk_cursor_unref (cursor);
+	}
+	else
+		gdk_window_set_cursor (GTK_WIDGET (self)->window, NULL);
+}
+
+static gboolean
+brasero_video_disc_directory_dialog (BraseroVideoProject *project,
+				     const gchar *uri,
+				     BraseroVideoDisc *self)
+{
+	gint answer;
+	GtkWidget *dialog;
+	GtkWidget *toplevel;
+
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+	dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
+					 GTK_DIALOG_DESTROY_WITH_PARENT |
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_WARNING,
+					 GTK_BUTTONS_NONE,
+					 _("Do you want to search for video files inside the directory?"));
+
+	gtk_window_set_title (GTK_WINDOW (dialog), _("Directory Search"));
+
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+						  _("Directories can't be added to video disc."));
+
+	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+				_("Search directory"), GTK_RESPONSE_OK,
+				NULL);
+
+	gtk_widget_show_all (dialog);
+	answer = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+
+	if (answer != GTK_RESPONSE_OK)
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+brasero_video_disc_unreadable_uri_dialog (BraseroVideoProject *project,
+					  GError *error,
+					  const gchar *uri,
+					  BraseroVideoDisc *self)
+{
+	GtkWidget *dialog, *toplevel;
+	gchar *name;
+
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+	if (toplevel == NULL) {
+		g_warning ("Can't open file %s : %s\n",
+			   uri,
+			   error->message);
+		return;
+	}
+
+	name = g_filename_display_basename (uri);
+	dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
+					 GTK_DIALOG_DESTROY_WITH_PARENT|
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_ERROR,
+					 GTK_BUTTONS_CLOSE,
+					 _("File \"%s\" can't be opened."),
+					 name);
+	g_free (name);
+
+	gtk_window_set_title (GTK_WINDOW (dialog), _("Unreadable file"));
+
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+						  error->message);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+}
+
+static void
+brasero_video_disc_not_video_dialog (BraseroVideoProject *project,
+				     const gchar *uri,
+				     BraseroVideoDisc *self)
+{
+	GtkWidget *dialog, *toplevel;
+	gchar *name;
+
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+	if (toplevel == NULL) {
+		g_warning ("Content widget error : can't handle \"%s\".\n", uri);
+		return ;
+	}
+
+    	BRASERO_GET_BASENAME_FOR_DISPLAY (uri, name);
+	dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel),
+					 GTK_DIALOG_DESTROY_WITH_PARENT|
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_ERROR,
+					 GTK_BUTTONS_CLOSE,
+					 _("\"%s\" does not have a suitable type for video projects."),
+					 name);
+	g_free (name);
+
+	gtk_window_set_title (GTK_WINDOW (dialog), _("Unhandled file"));
+
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+						  _("Please only add files with video contents."));
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+}
+
+static BraseroDiscResult
+brasero_video_disc_add_uri_real (BraseroVideoDisc *self,
+				 const gchar *uri,
+				 gint pos,
+				 gint64 start,
+				 gint64 end,
+				 GtkTreePath **path_return)
+{
+	BraseroVideoFile *file;
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+	BraseroVideoFile *sibling = NULL;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	if (priv->reject_files)
+		return BRASERO_DISC_NOT_READY;
+
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+
+	if (pos > 0) {
+		GtkTreePath *treepath;
+
+		treepath = gtk_tree_path_new ();
+		gtk_tree_path_append_index (treepath, pos);
+		sibling = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (project), treepath);
+		gtk_tree_path_free (treepath);
+	}
+
+	file = brasero_video_project_add_uri (project,
+					      uri,
+					      sibling,
+					      start,
+					      end);
+	if (path_return && file)
+		*path_return = brasero_video_tree_model_file_to_path (BRASERO_VIDEO_TREE_MODEL (project), file);
+
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 1);
+
+	return BRASERO_DISC_OK;
+}
+
+static BraseroDiscResult
+brasero_video_disc_add_uri (BraseroDisc *self,
+			    const gchar *uri)
+{
+	BraseroVideoDiscPrivate *priv;
+	GtkTreePath *treepath = NULL;
+	BraseroDiscResult result;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	result = brasero_video_disc_add_uri_real (BRASERO_VIDEO_DISC (self),
+						  uri,
+						  -1,
+						  -1,
+						  -1,
+						  &treepath);
+
+	if (treepath) {
+		gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->tree),
+					      treepath,
+					      NULL,
+					      TRUE,
+					      0.5,
+					      0.5);
+		gtk_tree_path_free (treepath);
+	}
+
+	return result;
+}
+
+static void
+brasero_video_disc_delete_selected (BraseroDisc *self)
+{
+	BraseroVideoDiscPrivate *priv;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *selected;
+	GList *iter;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+
+	selected = gtk_tree_selection_get_selected_rows (selection, &model);
+	selected = g_list_reverse (selected);
+	for (iter = selected; iter; iter = iter->next) {
+		BraseroVideoFile *file;
+		GtkTreePath *treepath;
+
+		treepath = iter->data;
+
+		file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+		gtk_tree_path_free (treepath);
+
+		if (!file)
+			continue;
+
+		brasero_video_project_remove_file (BRASERO_VIDEO_PROJECT (model), file);
+	}
+	g_list_free (selected);
+}
+
+static gboolean
+brasero_video_disc_get_selected_uri (BraseroDisc *self,
+				     gchar **uri)
+{
+	GList *selected;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+	selected = gtk_tree_selection_get_selected_rows (selection, &model);
+	if (!selected)
+		return FALSE;
+
+	if (uri) {
+		BraseroVideoFile *file;
+		GtkTreePath *treepath;
+
+		treepath = selected->data;
+		file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+		if (file)
+			*uri = g_strdup (file->uri);
+		else
+			*uri = NULL;
+	}
+
+	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+	g_list_free (selected);
+
+	return TRUE;
+}
+
+static void
+brasero_video_disc_selection_changed_cb (GtkTreeSelection *selection,
+					 BraseroVideoDisc *self)
+{
+	brasero_disc_selection_changed (BRASERO_DISC (self));
+}
+
+static gboolean
+brasero_video_disc_selection_function (GtkTreeSelection *selection,
+				       GtkTreeModel *model,
+				       GtkTreePath *treepath,
+				       gboolean path_currently_selected,
+				       gpointer NULL_data)
+{
+	BraseroVideoFile *file;
+
+	file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+	if (file)
+		file->editable = !path_currently_selected;
+
+	return TRUE;
+}
+
+
+/**
+ * Callback for menu
+ */
+
+static gboolean
+brasero_video_disc_rename_songs (GtkTreeModel *model,
+				 GtkTreeIter *iter,
+				 GtkTreePath *treepath,
+				 const gchar *old_name,
+				 const gchar *new_name)
+{
+	BraseroVideoFile *file;
+
+	file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+	if (!file)
+		return FALSE;
+
+	if (file->name)
+		g_free (file->name);
+
+	file->name = g_strdup (new_name);
+	return TRUE;
+}
+
+static void
+brasero_video_disc_edit_song_properties_list (BraseroVideoDisc *self,
+					      GList *list)
+{
+	GList *item;
+	gint isrc;
+	GList *copy;
+	GtkWidget *props;
+	GtkWidget *toplevel;
+	GtkTreeModel *model;
+	gchar *artist = NULL;
+	gchar *composer = NULL;
+	GtkResponseType result;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	if (!g_list_length (list))
+		return;
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree));
+
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+	props = brasero_multi_song_props_new ();
+	brasero_multi_song_props_set_show_gap (BRASERO_MULTI_SONG_PROPS (props), FALSE);
+
+	gtk_window_set_transient_for (GTK_WINDOW (props),
+				      GTK_WINDOW (toplevel));
+	gtk_window_set_modal (GTK_WINDOW (props), TRUE);
+	gtk_window_set_position (GTK_WINDOW (props),
+				 GTK_WIN_POS_CENTER_ON_PARENT);
+
+	gtk_widget_show (GTK_WIDGET (props));
+	result = gtk_dialog_run (GTK_DIALOG (props));
+	gtk_widget_hide (GTK_WIDGET (props));
+	if (result != GTK_RESPONSE_ACCEPT)
+		goto end;
+
+	brasero_multi_song_props_set_rename_callback (BRASERO_MULTI_SONG_PROPS (props),
+						      gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree)),
+						      BRASERO_VIDEO_TREE_MODEL_NAME,
+						      brasero_video_disc_rename_songs);
+
+	brasero_multi_song_props_get_properties (BRASERO_MULTI_SONG_PROPS (props),
+						 &artist,
+						 &composer,
+						 &isrc,
+						 NULL);
+
+	/* start by the end in case we add silences since then the next
+	 * treepaths will be wrong */
+	copy = g_list_copy (list);
+	copy = g_list_reverse (copy);
+
+	for (item = copy; item; item = item->next) {
+		GtkTreePath *treepath;
+		BraseroVideoFile *file;
+
+		treepath = item->data;
+		file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+		if (!file)
+			continue;
+
+		if (artist) {
+			g_free (file->info->artist);
+			file->info->artist = g_strdup (artist);
+		}
+
+		if (composer) {
+			g_free (file->info->composer);
+			file->info->composer = g_strdup (composer);
+		}
+
+		if (isrc > 0)
+			file->info->isrc = isrc;
+	}
+
+	g_list_free (copy);
+	g_free (artist);
+	g_free (composer);
+end:
+
+	gtk_widget_destroy (props);
+}
+
+static void
+brasero_video_disc_edit_song_properties_file (BraseroVideoDisc *self,
+					      BraseroVideoFile *file)
+{
+	gint64 end;
+	gint64 start;
+	GtkWidget *props;
+	GtkWidget *toplevel;
+	GtkTreeModel *model;
+	GtkResponseType result;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree));
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+
+	props = brasero_song_props_new ();
+	brasero_song_props_set_properties (BRASERO_SONG_PROPS (props),
+					   -1,
+					   file->info->artist,
+					   file->info->title,
+					   file->info->composer,
+					   file->info->isrc,
+					   file->end - file->start,
+					   file->start,
+					   file->end,
+					   -1);
+
+	gtk_window_set_transient_for (GTK_WINDOW (props),
+				      GTK_WINDOW (toplevel));
+	gtk_window_set_modal (GTK_WINDOW (props), TRUE);
+	gtk_window_set_position (GTK_WINDOW (props),
+				 GTK_WIN_POS_CENTER_ON_PARENT);
+
+	gtk_widget_show (GTK_WIDGET (props));
+	result = gtk_dialog_run (GTK_DIALOG (props));
+	gtk_widget_hide (GTK_WIDGET (props));
+	if (result != GTK_RESPONSE_ACCEPT)
+		goto end;
+
+	brasero_song_info_free (file->info);
+	file->info = g_new0 (BraseroSongInfo, 1);
+
+	brasero_song_props_get_properties (BRASERO_SONG_PROPS (props),
+					   &file->info->artist,
+					   &file->info->title,
+					   &file->info->composer,
+					   &file->info->isrc,
+					   &start,
+					   &end,
+					   NULL);
+
+	brasero_video_project_resize_file (BRASERO_VIDEO_PROJECT (model), file, start, end);
+
+end:
+
+	gtk_widget_destroy (props);
+}
+static void
+brasero_video_disc_edit_information_cb (GtkAction *action,
+					BraseroVideoDisc *self)
+{
+	GList *list;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+	list = gtk_tree_selection_get_selected_rows (selection, &model);
+
+	if (!list)
+		return;
+
+	if (g_list_length (list) == 1) {
+		BraseroVideoFile *file;
+		GtkTreePath *treepath;
+
+		treepath = list->data;
+
+		file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+		if (file)
+			brasero_video_disc_edit_song_properties_file (self, file);
+	}
+	else
+		brasero_video_disc_edit_song_properties_list (self, list);
+
+	g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+	g_list_free (list);
+}
+
+static void
+brasero_video_disc_open_file (BraseroVideoDisc *self)
+{
+	GList *item, *list;
+	GSList *uris = NULL;
+	GtkTreeModel *model;
+	GtkTreePath *treepath;
+	GtkTreeSelection *selection;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+	list = gtk_tree_selection_get_selected_rows (selection, &model);
+
+	for (item = list; item; item = item->next) {
+		BraseroVideoFile *file;
+
+		treepath = item->data;
+		file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+		gtk_tree_path_free (treepath);
+
+		if (!file)
+			continue;
+
+		if (file->uri)
+			uris = g_slist_prepend (uris, file->uri);
+	}
+	g_list_free (list);
+
+	brasero_utils_launch_app (GTK_WIDGET (self), uris);
+	g_slist_free (uris);
+}
+
+static void
+brasero_video_disc_open_activated_cb (GtkAction *action,
+				      BraseroVideoDisc *self)
+{
+	brasero_video_disc_open_file (self);
+}
+
+static void
+brasero_video_disc_clipboard_text_cb (GtkClipboard *clipboard,
+				      const gchar *text,
+				      BraseroVideoDisc *self)
+{
+	gchar **array;
+	gchar **item;
+
+	array = g_strsplit_set (text, "\n\r", 0);
+	item = array;
+	while (*item) {
+		if (**item != '\0') {
+			GFile *file;
+			gchar *uri;
+
+			file = g_file_new_for_commandline_arg (*item);
+			uri = g_file_get_uri (file);
+			g_object_unref (file);
+
+			brasero_video_disc_add_uri_real (self,
+							 uri,
+							 -1,
+							 -1,
+							 -1,
+							 NULL);
+			g_free (uri);
+		}
+
+		item++;
+	}
+}
+
+static void
+brasero_video_disc_clipboard_targets_cb (GtkClipboard *clipboard,
+					 GdkAtom *atoms,
+					 gint n_atoms,
+					 BraseroVideoDisc *self)
+{
+	GdkAtom *iter;
+	gchar *target;
+
+	iter = atoms;
+	while (n_atoms) {
+		target = gdk_atom_name (*iter);
+
+		if (!strcmp (target, "x-special/gnome-copied-files")
+		||  !strcmp (target, "UTF8_STRING")) {
+			gtk_clipboard_request_text (clipboard,
+						    (GtkClipboardTextReceivedFunc) brasero_video_disc_clipboard_text_cb,
+						    self);
+			g_free (target);
+			return;
+		}
+
+		g_free (target);
+		iter++;
+		n_atoms--;
+	}
+}
+
+static void
+brasero_video_disc_paste_activated_cb (GtkAction *action,
+				       BraseroVideoDisc *self)
+{
+	GtkClipboard *clipboard;
+
+	clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+	gtk_clipboard_request_targets (clipboard,
+				       (GtkClipboardTargetsReceivedFunc) brasero_video_disc_clipboard_targets_cb,
+				       self);
+}
+
+static void
+brasero_video_disc_delete_activated_cb (GtkAction *action,
+					BraseroVideoDisc *self)
+{
+	brasero_video_disc_delete_selected (BRASERO_DISC (self));
+}
+
+static gboolean
+brasero_video_disc_button_pressed_cb (GtkTreeView *tree,
+				      GdkEventButton *event,
+				      BraseroVideoDisc *self)
+{
+	GtkWidgetClass *widget_class;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	widget_class = GTK_WIDGET_GET_CLASS (tree);
+
+	if (event->button == 3) {
+		GtkTreeSelection *selection;
+		GtkTreePath *path = NULL;
+		GtkWidget *widget;
+
+		gtk_tree_view_get_path_at_pos (tree,
+					       event->x,
+					       event->y,
+					       &path,
+					       NULL,
+					       NULL,
+					       NULL);
+
+		selection = gtk_tree_view_get_selection (tree);
+
+		/* Don't update the selection if the right click was on one of
+		 * the already selected rows */
+		if (!path || !gtk_tree_selection_path_is_selected (selection, path))
+			widget_class->button_press_event (GTK_WIDGET (tree), event);
+
+		widget = gtk_ui_manager_get_widget (priv->manager, "/ContextMenu/PasteAudio");
+		if (widget) {
+			if (gtk_clipboard_wait_is_text_available (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)))
+				gtk_widget_set_sensitive (widget, TRUE);
+			else
+				gtk_widget_set_sensitive (widget, FALSE);
+		}
+
+		widget = gtk_ui_manager_get_widget (priv->manager,"/ContextMenu");
+		gtk_menu_popup (GTK_MENU (widget),
+				NULL,
+				NULL,
+				NULL,
+				NULL,
+				event->button,
+				event->time);
+		return TRUE;
+	}
+	else if (event->button == 1) {
+		gboolean result;
+		GtkTreePath *treepath = NULL;
+
+		result = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (tree),
+							event->x,
+							event->y,
+							&treepath,
+							NULL,
+							NULL,
+							NULL);
+
+		/* we call the default handler for the treeview before everything else
+		 * so it can update itself (paticularly its selection) before we have
+		 * a look at it */
+		widget_class->button_press_event (GTK_WIDGET (tree), event);
+		
+		if (!treepath) {
+			GtkTreeSelection *selection;
+
+			/* This is to deselect any row when selecting a 
+			 * row that cannot be selected or in an empty
+			 * part */
+			selection = gtk_tree_view_get_selection (tree);
+			gtk_tree_selection_unselect_all (selection);
+			return FALSE;
+		}
+	
+		if (!result)
+			return FALSE;
+
+		brasero_disc_selection_changed (BRASERO_DISC (self));
+		if (event->type == GDK_2BUTTON_PRESS) {
+			BraseroVideoFile *file;
+			GtkTreeModel *model;
+
+			model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree));
+			file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (model), treepath);
+			if (file)
+				brasero_video_disc_edit_song_properties_file (self, file);
+		}
+	}
+
+	return TRUE;
+}
+
+static guint
+brasero_video_disc_add_ui (BraseroDisc *disc,
+			   GtkUIManager *manager,
+			   GtkWidget *message)
+{
+	BraseroVideoDiscPrivate *priv;
+	GError *error = NULL;
+	guint merge_id;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+
+	if (priv->message) {
+		g_object_unref (priv->message);
+		priv->message = NULL;
+	}
+
+	priv->message = message;
+	g_object_ref (message);
+
+	if (!priv->disc_group) {
+		priv->disc_group = gtk_action_group_new (BRASERO_DISC_ACTION);
+		gtk_action_group_set_translation_domain (priv->disc_group, GETTEXT_PACKAGE);
+		gtk_action_group_add_actions (priv->disc_group,
+					      entries,
+					      G_N_ELEMENTS (entries),
+					      disc);
+/*		gtk_action_group_add_toggle_actions (priv->disc_group,
+						     toggle_entries,
+						     G_N_ELEMENTS (toggle_entries),
+						     disc);	*/
+		gtk_ui_manager_insert_action_group (manager,
+						    priv->disc_group,
+						    0);
+	}
+
+	merge_id = gtk_ui_manager_add_ui_from_string (manager,
+						      description,
+						      -1,
+						      &error);
+	if (!merge_id) {
+		BRASERO_BURN_LOG ("Adding ui elements failed: %s", error->message);
+		g_error_free (error);
+		return 0;
+	}
+
+	priv->manager = manager;
+	g_object_ref (manager);
+	return merge_id;
+}
+
+static void
+brasero_video_disc_rename_activated (BraseroVideoDisc *self)
+{
+	BraseroVideoDiscPrivate *priv;
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *column;
+	GtkTreePath *treepath;
+	GtkTreeModel *model;
+	GList *list;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+	list = gtk_tree_selection_get_selected_rows (selection, &model);
+
+	for (; list; list = g_list_remove (list, treepath)) {
+		treepath = list->data;
+
+		gtk_widget_grab_focus (priv->tree);
+		column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->tree), 0);
+		gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->tree),
+					      treepath,
+					      NULL,
+					      TRUE,
+					      0.5,
+					      0.5);
+		gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->tree),
+					  treepath,
+					  column,
+					  TRUE);
+
+		gtk_tree_path_free (treepath);
+	}
+}
+
+static gboolean
+brasero_video_disc_key_released_cb (GtkTreeView *tree,
+				    GdkEventKey *event,
+				    BraseroVideoDisc *self)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	if (priv->editing)
+		return FALSE;
+
+	if (event->keyval == GDK_KP_Delete || event->keyval == GDK_Delete) {
+		brasero_video_disc_delete_selected (BRASERO_DISC (self));
+	}
+	else if (event->keyval == GDK_F2)
+		brasero_video_disc_rename_activated (self);
+
+	return FALSE;
+}
+
+static void
+brasero_video_disc_row_deleted_cb (GtkTreeModel *model,
+				   GtkTreePath *path,
+				   BraseroVideoDisc *self)
+{
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	brasero_disc_contents_changed (BRASERO_DISC (self),
+				       brasero_video_project_get_file_num (BRASERO_VIDEO_PROJECT (model)));
+}
+
+static void
+brasero_video_disc_row_inserted_cb (GtkTreeModel *model,
+				    GtkTreePath *path,
+				    GtkTreeIter *iter,
+				    BraseroVideoDisc *self)
+{
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	brasero_disc_contents_changed (BRASERO_DISC (self),
+				       brasero_video_project_get_file_num (BRASERO_VIDEO_PROJECT (model)));
+}
+
+static void
+brasero_video_disc_row_changed_cb (GtkTreeModel *model,
+				   GtkTreePath *path,
+				   GtkTreeIter *iter,
+				   BraseroVideoDisc *self)
+{
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	brasero_disc_contents_changed (BRASERO_DISC (self),
+				       brasero_video_project_get_file_num (BRASERO_VIDEO_PROJECT (model)));
+}
+
+static void
+brasero_video_disc_size_changed_cb (BraseroVideoProject *project,
+				    BraseroVideoDisc *self)
+{
+	brasero_disc_size_changed (BRASERO_DISC (self), brasero_video_project_get_size (project));
+}
+
+static void
+brasero_video_disc_init (BraseroVideoDisc *object)
+{
+	BraseroVideoDiscPrivate *priv;
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	GtkTreeModel *model;
+	GtkWidget *mainbox;
+	GtkWidget *scroll;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (object);
+
+	/* the information displayed about how to use this tree */
+	priv->notebook = brasero_disc_get_use_info_notebook ();
+	gtk_widget_show (priv->notebook);
+	gtk_box_pack_start (GTK_BOX (object), priv->notebook, TRUE, TRUE, 0);
+
+	mainbox = gtk_vbox_new (FALSE, 12);
+	gtk_widget_show (mainbox);
+	gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), mainbox, NULL);
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 0);
+
+	/* Tree */
+	model = GTK_TREE_MODEL (brasero_video_tree_model_new ());
+
+	g_signal_connect (G_OBJECT (model),
+			  "row-deleted",
+			  G_CALLBACK (brasero_video_disc_row_deleted_cb),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "row-inserted",
+			  G_CALLBACK (brasero_video_disc_row_inserted_cb),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "row-changed",
+			  G_CALLBACK (brasero_video_disc_row_changed_cb),
+			  object);
+
+	g_signal_connect (G_OBJECT (model),
+			  "size-changed",
+			  G_CALLBACK (brasero_video_disc_size_changed_cb),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "not-video-uri",
+			  G_CALLBACK (brasero_video_disc_not_video_dialog),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "directory-uri",
+			  G_CALLBACK (brasero_video_disc_directory_dialog),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "unreadable-uri",
+			  G_CALLBACK (brasero_video_disc_unreadable_uri_dialog),
+			  object);
+	g_signal_connect (G_OBJECT (model),
+			  "vfs-activity",
+			  G_CALLBACK (brasero_video_disc_vfs_activity_changed),
+			  object);
+
+	priv->tree = gtk_tree_view_new_with_model (model);
+	egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (priv->tree));
+	g_object_unref (G_OBJECT (model));
+	gtk_widget_show (priv->tree);
+
+	g_signal_connect (priv->tree,
+			  "button-press-event",
+			  G_CALLBACK (brasero_video_disc_button_pressed_cb),
+			  object);
+	g_signal_connect (priv->tree,
+			  "key-release-event",
+			  G_CALLBACK (brasero_video_disc_key_released_cb),
+			  object);
+
+	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->tree), TRUE);
+	gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (priv->tree), TRUE);
+
+	/* columns */
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_resizable (column, TRUE);
+	gtk_tree_view_column_set_min_width (column, 200);
+
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer,
+					    "pixbuf", BRASERO_VIDEO_TREE_MODEL_MIME_ICON);
+
+	renderer = gtk_cell_renderer_text_new ();
+	g_signal_connect (G_OBJECT (renderer), "edited",
+			  G_CALLBACK (brasero_video_disc_name_edited_cb), object);
+	g_signal_connect (G_OBJECT (renderer), "editing-started",
+			  G_CALLBACK (brasero_video_disc_name_editing_started_cb), object);
+	g_signal_connect (G_OBJECT (renderer), "editing-canceled",
+			  G_CALLBACK (brasero_video_disc_name_editing_canceled_cb), object);
+
+	g_object_set (G_OBJECT (renderer),
+		      "mode", GTK_CELL_RENDERER_MODE_EDITABLE,
+		      "ellipsize-set", TRUE,
+		      "ellipsize", PANGO_ELLIPSIZE_END,
+		      NULL);
+
+	gtk_tree_view_column_pack_end (column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute (column, renderer,
+					    "markup", BRASERO_VIDEO_TREE_MODEL_NAME);
+	gtk_tree_view_column_add_attribute (column, renderer,
+					    "editable", BRASERO_VIDEO_TREE_MODEL_EDITABLE);
+	gtk_tree_view_column_set_title (column, _("Title"));
+	g_object_set (G_OBJECT (column),
+		      "expand", TRUE,
+		      "spacing", 4,
+		      NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree),
+				     column);
+
+	gtk_tree_view_set_expander_column (GTK_TREE_VIEW (priv->tree),
+					   column);
+
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+
+	gtk_tree_view_column_add_attribute (column, renderer,
+					    "text", BRASERO_VIDEO_TREE_MODEL_SIZE);
+	gtk_tree_view_column_set_title (column, _("Size"));
+
+	gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree), column);
+	gtk_tree_view_column_set_resizable (column, TRUE);
+	gtk_tree_view_column_set_expand (column, FALSE);
+
+	/* selection */
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+	g_signal_connect (selection,
+			  "changed",
+			  G_CALLBACK (brasero_video_disc_selection_changed_cb),
+			  object);
+	gtk_tree_selection_set_select_function (selection,
+						brasero_video_disc_selection_function,
+						NULL,
+						NULL);
+
+	/* scroll */
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_widget_show (scroll);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
+					     GTK_SHADOW_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	gtk_container_add (GTK_CONTAINER (scroll), priv->tree);
+	gtk_box_pack_start (GTK_BOX (mainbox), scroll, TRUE, TRUE, 0);
+
+	/* dnd */
+	gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW
+					      (priv->tree),
+					      ntables_cd, nb_targets_cd,
+					      GDK_ACTION_COPY |
+					      GDK_ACTION_MOVE);
+
+	gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (priv->tree),
+						GDK_BUTTON1_MASK,
+						ntables_source,
+						nb_targets_source,
+						GDK_ACTION_MOVE);
+}
+
+static void
+brasero_video_disc_reset_real (BraseroVideoDisc *self)
+{
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	brasero_video_project_reset (project);
+	brasero_video_disc_vfs_activity_changed (project, FALSE, self);
+}
+
+static void
+brasero_video_disc_clear (BraseroDisc *disc)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+
+	brasero_video_disc_reset_real (BRASERO_VIDEO_DISC (disc));
+
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 0);
+	brasero_disc_size_changed (disc, 0);
+}
+
+static void
+brasero_video_disc_reset (BraseroDisc *disc)
+{
+	brasero_video_disc_reset_real (BRASERO_VIDEO_DISC (disc));
+}
+
+static void
+brasero_video_disc_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (brasero_video_disc_parent_class)->finalize (object);
+}
+
+static void
+brasero_video_disc_get_property (GObject * object,
+				 guint prop_id,
+				 GValue * value,
+				 GParamSpec * pspec)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_REJECT_FILE:
+		g_value_set_boolean (value, priv->reject_files);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+brasero_video_disc_set_property (GObject * object,
+				 guint prop_id,
+				 const GValue * value,
+				 GParamSpec * pspec)
+{
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_REJECT_FILE:
+		priv->reject_files = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static BraseroDiscResult
+brasero_video_disc_get_status (BraseroDisc *self)
+{
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	return brasero_video_project_get_status (project);
+}
+
+BraseroDiscResult
+brasero_video_disc_set_session_param (BraseroDisc *self,
+				      BraseroBurnSession *session)
+{
+	BraseroTrackType type;
+
+	type.type = BRASERO_TRACK_TYPE_AUDIO;
+	type.subtype.audio_format = BRASERO_AUDIO_FORMAT_UNDEFINED|BRASERO_VIDEO_FORMAT_UNDEFINED;
+	brasero_burn_session_set_input_type (session, &type);
+	return BRASERO_BURN_OK;
+}
+
+BraseroDiscResult
+brasero_video_disc_set_session_contents (BraseroDisc *self,
+					 BraseroBurnSession *session)
+{
+	GSList *tracks, *iter;
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (self);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	tracks = brasero_video_project_get_contents (project);
+
+	if (!tracks)
+		return BRASERO_DISC_ERROR_EMPTY_SELECTION;
+
+	for (iter = tracks; iter; iter = iter->next) {
+		BraseroTrack *track;
+
+		track = iter->data;
+		brasero_burn_session_add_track (session, track);
+
+		/* It's good practice to unref the track afterwards as we don't
+		 * need it anymore. BraseroBurnSession refs it. */
+		brasero_track_unref (track);
+
+	}
+	g_slist_free (tracks);
+	return BRASERO_DISC_OK;
+}
+
+static BraseroDiscResult
+brasero_video_disc_get_track (BraseroDisc *disc,
+			      BraseroDiscTrack *disc_track)
+{
+	GSList *iter;
+	GSList *tracks;
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	disc_track->type = BRASERO_DISC_TRACK_VIDEO;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	tracks = brasero_video_project_get_contents (project);
+
+	for (iter = tracks; iter; iter = iter->next) {
+		BraseroDiscSong *song;
+		BraseroTrack *track;
+
+		track = iter->data;
+
+		song = g_new0 (BraseroDiscSong, 1);
+		song->uri = brasero_track_get_audio_source (track, TRUE);;
+		song->start = brasero_track_get_audio_start (track);
+		song->end = brasero_track_get_audio_end (track);
+		song->info = brasero_song_info_copy (brasero_track_get_audio_info (track));
+		disc_track->contents.tracks = g_slist_append (disc_track->contents.tracks, song);
+	}
+
+	g_slist_foreach (tracks, (GFunc) brasero_track_unref, NULL);
+	g_slist_free (tracks);
+
+	return BRASERO_DISC_OK;
+}
+
+static BraseroDiscResult
+brasero_video_disc_load_track (BraseroDisc *disc,
+			       BraseroDiscTrack *track)
+{
+	GSList *iter;
+	BraseroVideoProject *project;
+	BraseroVideoDiscPrivate *priv;
+
+	g_return_val_if_fail (track->type == BRASERO_DISC_TRACK_VIDEO, FALSE);
+
+	if (track->contents.tracks == NULL)
+		return BRASERO_DISC_ERROR_EMPTY_SELECTION;
+
+	priv = BRASERO_VIDEO_DISC_PRIVATE (disc);
+	project = BRASERO_VIDEO_PROJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree)));
+	priv->loading = g_slist_length (track->contents.tracks);
+
+	for (iter = track->contents.tracks; iter; iter = iter->next) {
+		BraseroDiscSong *song;
+
+		song = iter->data;
+
+		brasero_video_project_add_uri (BRASERO_VIDEO_PROJECT (project),
+					       song->uri,
+					       NULL,
+					       song->start,
+					       song->end);
+	}
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 1);
+
+	return BRASERO_DISC_OK;
+}
+
+static void
+brasero_video_disc_iface_disc_init (BraseroDiscIface *iface)
+{
+	iface->add_uri = brasero_video_disc_add_uri;
+	iface->delete_selected = brasero_video_disc_delete_selected;
+	iface->clear = brasero_video_disc_clear;
+	iface->reset = brasero_video_disc_reset;
+
+	iface->get_status = brasero_video_disc_get_status;
+	iface->set_session_param = brasero_video_disc_set_session_param;
+	iface->set_session_contents = brasero_video_disc_set_session_contents;
+
+	iface->get_track = brasero_video_disc_get_track;
+	iface->load_track = brasero_video_disc_load_track;
+
+	iface->get_selected_uri = brasero_video_disc_get_selected_uri;
+	iface->add_ui = brasero_video_disc_add_ui;
+}
+
+static void
+brasero_video_disc_class_init (BraseroVideoDiscClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVideoDiscPrivate));
+
+	object_class->finalize = brasero_video_disc_finalize;
+	object_class->set_property = brasero_video_disc_set_property;
+	object_class->get_property = brasero_video_disc_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_REJECT_FILE,
+					 g_param_spec_boolean
+					 ("reject-file",
+					  "Whether it accepts files",
+					  "Whether it accepts files",
+					  FALSE,
+					  G_PARAM_READWRITE));
+}
+
+GtkWidget *
+brasero_video_disc_new (void)
+{
+	return g_object_new (BRASERO_TYPE_VIDEO_DISC, NULL);
+}
+

Added: trunk/src/brasero-video-disc.h
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-disc.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,56 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BRASERO_VIDEO_DISC_H_
+#define _BRASERO_VIDEO_DISC_H_
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VIDEO_DISC             (brasero_video_disc_get_type ())
+#define BRASERO_VIDEO_DISC(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VIDEO_DISC, BraseroVideoDisc))
+#define BRASERO_VIDEO_DISC_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VIDEO_DISC, BraseroVideoDiscClass))
+#define BRASERO_IS_VIDEO_DISC(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VIDEO_DISC))
+#define BRASERO_IS_VIDEO_DISC_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VIDEO_DISC))
+#define BRASERO_VIDEO_DISC_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VIDEO_DISC, BraseroVideoDiscClass))
+
+typedef struct _BraseroVideoDiscClass BraseroVideoDiscClass;
+typedef struct _BraseroVideoDisc BraseroVideoDisc;
+
+struct _BraseroVideoDiscClass
+{
+	GtkVBoxClass parent_class;
+};
+
+struct _BraseroVideoDisc
+{
+	GtkVBox parent_instance;
+};
+
+GType brasero_video_disc_get_type (void) G_GNUC_CONST;
+
+GtkWidget *
+brasero_video_disc_new (void);
+
+G_END_DECLS
+
+#endif /* _BRASERO_VIDEO_DISC_H_ */

Added: trunk/src/brasero-video-project.c
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-project.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,1154 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "brasero-video-project.h"
+#include "brasero-file-monitor.h"
+#include "brasero-io.h"
+#include "brasero-marshal.h"
+
+typedef struct _BraseroVideoProjectPrivate BraseroVideoProjectPrivate;
+struct _BraseroVideoProjectPrivate
+{
+	guint ref_count;
+	GHashTable *references;
+
+	BraseroIO *io;
+	BraseroIOJobBase *load_uri;
+	BraseroIOJobBase *load_dir;
+
+	BraseroVideoFile *first;
+
+	guint loading;
+};
+
+#define BRASERO_VIDEO_PROJECT_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VIDEO_PROJECT, BraseroVideoProjectPrivate))
+
+#ifdef BUILD_INOTIFY
+
+#include "brasero-file-monitor.h"
+
+G_DEFINE_TYPE (BraseroVideoProject, brasero_video_project, BRASERO_TYPE_FILE_MONITOR);
+
+#else
+
+G_DEFINE_TYPE (BraseroVideoProject, brasero_video_project, G_TYPE_OBJECT);
+
+#endif
+
+enum {
+	PROJECT_LOADED_SIGNAL,
+	SIZE_CHANGED_SIGNAL,
+	DIRECTORY_URI_SIGNAL,
+	UNREADABLE_SIGNAL,
+	NOT_VIDEO_SIGNAL,
+	ACTIVITY_SIGNAL,
+	LAST_SIGNAL
+};
+
+static guint brasero_video_project_signals [LAST_SIGNAL] = {0};
+
+/**
+ * Used to send signals with a default answer
+ */
+
+static gboolean
+brasero_video_project_file_signal (BraseroVideoProject *self,
+				  guint signal,
+				  const gchar *name)
+{
+	GValue instance_and_params [2];
+	GValue return_value;
+	GValue *params;
+
+	/* object which signalled */
+	instance_and_params->g_type = 0;
+	g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (self));
+	g_value_set_instance (instance_and_params, self);
+
+	/* arguments of signal (name) */
+	params = instance_and_params + 1;
+	params->g_type = 0;
+	g_value_init (params, G_TYPE_STRING);
+	g_value_set_string (params, name);
+
+	/* default to FALSE */
+	return_value.g_type = 0;
+	g_value_init (&return_value, G_TYPE_BOOLEAN);
+	g_value_set_boolean (&return_value, FALSE);
+
+	g_signal_emitv (instance_and_params,
+			brasero_video_project_signals [signal],
+			0,
+			&return_value);
+
+	g_value_unset (instance_and_params);
+	g_value_unset (params);
+
+	return g_value_get_boolean (&return_value);
+}
+
+/**
+ * Manages the references to a node
+ */
+
+guint
+brasero_video_project_reference_new (BraseroVideoProject *self,
+				    BraseroVideoFile *node)
+{
+	BraseroVideoProjectPrivate *priv;
+	guint retval;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	if (!priv->references)
+		priv->references = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	retval = priv->ref_count;
+	while (g_hash_table_lookup (priv->references, GINT_TO_POINTER (retval))) {
+		retval ++;
+
+		if (retval == G_MAXINT)
+			retval = 1;
+
+		/* this means there is no more room for reference */
+		if (retval == priv->ref_count)
+			return 0;
+	}
+
+	g_hash_table_insert (priv->references,
+			     GINT_TO_POINTER (retval),
+			     node);
+	priv->ref_count = retval + 1;
+	if (priv->ref_count == G_MAXINT)
+		priv->ref_count = 1;
+
+	return retval;
+}
+
+void
+brasero_video_project_reference_free (BraseroVideoProject *self,
+				     guint reference)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	g_hash_table_remove (priv->references, GINT_TO_POINTER (reference));
+}
+
+BraseroVideoFile *
+brasero_video_project_reference_get (BraseroVideoProject *self,
+				    guint reference)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	/* if it was invalidated then the node returned is NULL */
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	return g_hash_table_lookup (priv->references, GINT_TO_POINTER (reference));
+}
+
+static gboolean
+brasero_video_project_reference_remove_children_cb (gpointer key,
+						   gpointer data,
+						   gpointer callback_data)
+{
+	BraseroVideoFile *node = data;
+	BraseroVideoFile *removable = callback_data;
+
+	if (node == removable)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+brasero_video_project_reference_invalidate (BraseroVideoProject *self,
+					   BraseroVideoFile *node)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	/* used internally to invalidate reference whose node was removed */
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	g_hash_table_foreach_remove (priv->references,
+				     (GHRFunc) brasero_video_project_reference_remove_children_cb,
+				     node);
+}
+
+/**
+ * Move functions
+ */
+
+void
+brasero_video_project_rename (BraseroVideoProject *self,
+			      BraseroVideoFile *file,
+			      const gchar *name)
+{
+	gchar *tmp;
+	BraseroVideoProjectClass *klass;
+
+	tmp = file->name;
+	file->name = g_strdup (name);
+	g_free (tmp);
+
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_changed)
+		klass->node_changed (self, file);
+}
+
+void
+brasero_video_project_move (BraseroVideoProject *self,
+			    BraseroVideoFile *file,
+			    BraseroVideoFile *next_file)
+{
+	BraseroVideoFile *prev, *next;
+	BraseroVideoProjectClass *klass;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	if (!file)
+		return;
+
+	if (file == next_file)
+		return;
+
+	/* unlink it */
+	prev = file->prev;
+	next = file->next;
+
+	if (next)
+		next->prev = prev;
+
+	if (prev)
+		prev->next = next;
+	else
+		priv->first = next;
+
+	/* tell the model */
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_removed)
+		klass->node_removed (self, file);
+
+	/* relink it */
+	if (next_file) {
+		file->next = next_file;
+		file->prev = next_file->prev;
+		next_file->prev = file;
+
+		if (file->prev)
+			file->prev->next = file;
+		else
+			priv->first = file;
+	}
+	else if (priv->first) {
+		BraseroVideoFile *last;
+
+		/* Put it at the end */
+		last = priv->first;
+		while (last->next) last = last->next;
+
+		file->next = NULL;
+		file->prev = last;
+		last->next = file;
+	}
+	else {
+		priv->first = file;
+		file->next = NULL;
+		file->prev = NULL;
+	}
+
+	/* tell the model */
+	if (klass->node_added)
+		klass->node_added (self, file);
+}
+
+/**
+ * Remove functions
+ */
+
+void
+brasero_video_file_free (BraseroVideoFile *file)
+{
+	if (file->uri)
+		g_free (file->uri);
+
+	if (file->snapshot)
+		g_object_unref (file->snapshot);
+
+	if (file->info)
+		brasero_song_info_free (file->info);
+
+	g_free (file);
+}
+
+static gboolean
+brasero_video_project_foreach_monitor_cancel_cb (gpointer data,
+						 gpointer user_data)
+{
+	BraseroVideoFile *node = data;
+	BraseroVideoFile *file = user_data;
+
+	if (node == file)
+		return TRUE;
+
+	return FALSE;
+}
+
+void
+brasero_video_project_remove_file (BraseroVideoProject *self,
+				   BraseroVideoFile *file)
+{
+	BraseroVideoFile *prev, *next;
+	BraseroVideoProjectClass *klass;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	if (!file)
+		return;
+
+	/* Unlink it */
+	prev = file->prev;
+	next = file->next;
+
+	if (next)
+		next->prev = prev;
+
+	if (prev)
+		prev->next = next;
+	else
+		priv->first = next;
+
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_removed)
+		klass->node_removed (self, file);
+
+	brasero_video_project_reference_invalidate (self, file);
+
+#ifdef BUILD_INOTIFY
+
+	/* Stop monitoring */
+	if (file->is_monitored)
+		brasero_file_monitor_foreach_cancel (BRASERO_FILE_MONITOR (self),
+						     brasero_video_project_foreach_monitor_cancel_cb,
+						     file);
+
+#endif
+
+	/* Free data */
+	brasero_video_file_free (file);
+
+	g_signal_emit (self,
+		       brasero_video_project_signals [SIZE_CHANGED_SIGNAL],
+		       0);
+}
+
+void
+brasero_video_project_reset (BraseroVideoProject *self)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoProjectClass *klass;
+	BraseroVideoFile *iter, *next;
+	guint num_nodes = 0;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	/* cancel all VFS operations */
+	if (priv->io) {
+		brasero_io_cancel_by_base (priv->io, priv->load_uri);
+		brasero_io_cancel_by_base (priv->io, priv->load_dir);
+
+		g_free (priv->load_uri);
+		priv->load_uri = NULL;
+
+		g_free (priv->load_dir);
+		priv->load_dir = NULL;
+	}
+
+	/* destroy all references */
+	if (priv->references) {
+		g_hash_table_destroy (priv->references);
+		priv->references = g_hash_table_new (g_direct_hash, g_direct_equal);
+	}
+
+#ifdef BUILD_INOTIFY
+
+	brasero_file_monitor_reset (BRASERO_FILE_MONITOR (self));
+
+#endif
+
+	/* empty tree */
+	for (iter = priv->first; iter; iter = next) {
+		next = iter->next;
+		brasero_video_project_remove_file (self, iter);
+	}
+	priv->first = NULL;
+
+	priv->loading = 0;
+
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->reset)
+		klass->reset (self, num_nodes);
+}
+
+/**
+ * Add functions
+ */
+
+static BraseroVideoFile *
+brasero_video_project_add_video_file (BraseroVideoProject *self,
+				      const gchar *uri,
+				      BraseroVideoFile *sibling,
+				      guint64 start,
+				      guint64 end)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoFile *file;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	/* create new file and insert it */
+	file = g_new0 (BraseroVideoFile, 1);
+	file->uri = g_strdup (uri);
+
+	if (start > -1)
+		file->start = start;
+
+	if (end > -1)
+		file->end = end;
+
+	if (sibling) {
+		file->next = sibling;
+		file->prev = sibling->prev;
+
+		if (sibling->prev)
+			sibling->prev->next = file;
+		else
+			priv->first = file;
+
+		sibling->prev = file;
+	}
+	else if (priv->first) {
+		BraseroVideoFile *last;
+
+		/* Put it at the end */
+		last = priv->first;
+		while (last->next) last = last->next;
+
+		file->prev = last;
+		file->next = NULL;
+		last->next = file;
+	}
+	else {
+		priv->first = file;
+		file->next = NULL;
+		file->prev = NULL;
+	}
+
+	return file;
+}
+
+static void
+brasero_video_project_set_file_information (BraseroVideoProject *self,
+					    BraseroVideoFile *file,
+					    GFileInfo *info)
+{
+	guint64 len;
+	GdkPixbuf *snapshot;
+	BraseroSongInfo *song;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	/* For reloading files no need to go further, we just want to check that
+	 * they are still readable and still holds video. */
+	if (file->is_reloading) {
+		file->is_reloading = FALSE;
+		return;
+	}
+
+	file->is_loading = FALSE;
+
+	if (g_file_info_get_is_symlink (info)) {
+		gchar *sym_uri;
+
+		sym_uri = g_strconcat ("file://", g_file_info_get_symlink_target (info), NULL);
+		g_free (file->uri);
+
+		file->uri = sym_uri;
+	}
+
+	/* Set the snapshot */
+	snapshot = GDK_PIXBUF (g_file_info_get_attribute_object (info, BRASERO_IO_SNAPSHOT));
+	if (snapshot) {
+		GdkPixbuf *scaled;
+
+		scaled = gdk_pixbuf_scale_simple (snapshot,
+						  96 * gdk_pixbuf_get_width (snapshot) / gdk_pixbuf_get_height (snapshot),
+						  96,
+						  GDK_INTERP_BILINEAR);
+		file->snapshot = scaled;
+	}
+
+	/* size */
+	len = g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN);
+	if (file->end > len)
+		file->end = len;
+	else if (file->end <= 0)
+		file->end = len;
+
+	/* Get the song info */
+	song = g_new0 (BraseroSongInfo, 1);
+	song->title = g_strdup (g_file_info_get_attribute_string (info, BRASERO_IO_TITLE));
+	song->artist = g_strdup (g_file_info_get_attribute_string (info, BRASERO_IO_ARTIST));
+	song->composer = g_strdup (g_file_info_get_attribute_string (info, BRASERO_IO_COMPOSER));
+	song->isrc = g_file_info_get_attribute_int32 (info, BRASERO_IO_ISRC);
+	file->info = song;
+
+#ifdef BUILD_INOTIFY
+
+	/* Start monitoring */
+	file->is_monitored = TRUE;
+	brasero_file_monitor_single_file (BRASERO_FILE_MONITOR (self),
+					  file->uri,
+					  file);
+
+#endif
+}
+
+static void
+brasero_video_project_vfs_operation_finished (GObject *object,
+					      gboolean cancelled,
+					      gpointer null_data)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (object);
+
+	priv->loading --;
+	g_signal_emit (object,
+		       brasero_video_project_signals [ACTIVITY_SIGNAL],
+		       0,
+		       priv->loading > 0);
+}
+
+static void
+brasero_video_project_add_directory_contents_result (GObject *obj,
+						     GError *error,
+						     const gchar *uri,
+						     GFileInfo *info,
+						     gpointer user_data)
+{
+	BraseroVideoFile *file;
+	BraseroVideoFile *sibling;
+	BraseroVideoProjectClass *klass;
+	guint ref = GPOINTER_TO_INT (user_data);
+
+	/* Check the return status for this file */
+	if (error)
+		return;
+
+	if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR
+	|| !g_file_info_get_attribute_boolean (info, BRASERO_IO_HAS_VIDEO))
+		return;
+
+	sibling = brasero_video_project_reference_get (BRASERO_VIDEO_PROJECT (obj), ref);
+
+	/* Add a video file and set all information */
+	file = brasero_video_project_add_video_file (BRASERO_VIDEO_PROJECT (obj),
+						     uri,
+						     sibling,
+						     -1,
+						     -1);
+						     
+	brasero_video_project_set_file_information (BRASERO_VIDEO_PROJECT (obj),
+						    file,
+						    info);
+
+	/* Tell model we added a node */
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (obj);
+	if (klass->node_added)
+		klass->node_added (BRASERO_VIDEO_PROJECT (obj), file);
+
+	/* update size */
+	g_signal_emit (BRASERO_VIDEO_PROJECT (obj),
+		       brasero_video_project_signals [SIZE_CHANGED_SIGNAL],
+		       0,
+		       error,
+		       uri);
+}
+
+static void
+brasero_video_project_add_directory_contents (BraseroVideoProject *self,
+					      const gchar *uri,
+					      BraseroVideoFile *sibling)
+{
+	BraseroVideoProjectPrivate *priv;
+	guint ref;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	if (!priv->io)
+		priv->io = brasero_io_get_default ();
+
+	if (!priv->load_dir)
+		priv->load_dir = brasero_io_register (G_OBJECT (self),
+						      brasero_video_project_add_directory_contents_result,
+						      brasero_video_project_vfs_operation_finished,
+						      NULL);
+
+	priv->loading ++;
+	g_signal_emit (self,
+		       brasero_video_project_signals [ACTIVITY_SIGNAL],
+		       0,
+		       priv->loading != 0);
+
+	ref = brasero_video_project_reference_new (self, sibling);
+
+	brasero_io_load_directory (priv->io,
+				   uri,
+				   priv->load_dir,
+				   BRASERO_IO_INFO_MIME|
+				   BRASERO_IO_INFO_PERM|
+				   BRASERO_IO_INFO_METADATA|
+				   BRASERO_IO_INFO_METADATA_MISSING_CODEC|
+				   BRASERO_IO_INFO_RECURSIVE|
+				   BRASERO_IO_INFO_METADATA_SNAPSHOT,
+				   GINT_TO_POINTER (ref));
+}
+
+static void
+brasero_video_project_result_cb (GObject *obj,
+				 GError *error,
+				 const gchar *uri,
+				 GFileInfo *info,
+				 gpointer user_data)
+{
+	BraseroVideoFile *file;
+	BraseroVideoProject *self;
+	BraseroVideoProjectClass *klass;
+	BraseroVideoProjectPrivate *priv;
+	guint ref = GPOINTER_TO_INT (user_data);
+
+	self = BRASERO_VIDEO_PROJECT (obj);
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (obj);
+
+	/* Get the reference for the node */
+	file = brasero_video_project_reference_get (self, ref);
+	if (!file)
+		return;
+
+	/* Check the return status for this file */
+	if (error) {
+		g_signal_emit (self,
+			       brasero_video_project_signals [UNREADABLE_SIGNAL],
+			       0,
+			       error,
+			       uri);
+
+		brasero_video_project_remove_file (self, file);
+		return;
+	}
+
+	if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+		gboolean result;
+
+		/* Ask the user */
+		result = brasero_video_project_file_signal (self,
+							   DIRECTORY_URI_SIGNAL,
+							   uri);
+
+		/* NOTE: we need to pass a sibling here even if that the file
+		 * that's going to be deleted just after. */
+		if (result)
+			brasero_video_project_add_directory_contents (self,
+								      uri,
+								      file->next?file->next:file);
+
+		/* remove the file */
+		brasero_video_project_remove_file (self, file);
+		return;
+	}
+
+	if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR
+	|| !g_file_info_get_attribute_boolean (info, BRASERO_IO_HAS_VIDEO)) {
+		g_signal_emit (self,
+			       brasero_video_project_signals [NOT_VIDEO_SIGNAL],
+			       0,
+			       error,
+			       uri);
+
+		brasero_video_project_remove_file (self, file);
+		return;
+	}
+
+	brasero_video_project_set_file_information (BRASERO_VIDEO_PROJECT (obj),
+						    file,
+						    info);
+
+	/* Tell upper object that the node status and information changed */
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_changed)
+		klass->node_changed (self, file);
+
+	/* update size */
+	g_signal_emit (self,
+		       brasero_video_project_signals [SIZE_CHANGED_SIGNAL],
+		       0);
+}
+
+BraseroVideoFile *
+brasero_video_project_add_uri (BraseroVideoProject *self,
+			       const gchar *uri,
+			       BraseroVideoFile *sibling,
+			       gint64 start,
+			       gint64 end)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoProjectClass *klass;
+	BraseroVideoFile *file;
+	guint ref;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	/* create new file and insert it */
+	file = g_new0 (BraseroVideoFile, 1);
+	file->uri = g_strdup (uri);
+
+	if (start > -1)
+		file->start = start;
+
+	if (end > -1)
+		file->end = end;
+
+	if (sibling) {
+		file->next = sibling;
+		file->prev = sibling->prev;
+
+		if (sibling->prev)
+			sibling->prev->next = file;
+		else
+			priv->first = file;
+
+		sibling->prev = file;
+	}
+	else if (priv->first) {
+		BraseroVideoFile *last;
+
+		/* Put it at the end */
+		last = priv->first;
+		while (last->next) last = last->next;
+
+		file->prev = last;
+		file->next = NULL;
+		last->next = file;
+	}
+	else {
+		priv->first = file;
+		file->next = NULL;
+		file->prev = NULL;
+	}
+
+	/* Tell model we added a node */
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_added)
+		klass->node_added (self, file);
+
+	/* get info async for the file */
+	if (!priv->io)
+		priv->io = brasero_io_get_default ();
+
+	if (!priv->load_uri)
+		priv->load_uri = brasero_io_register (G_OBJECT (self),
+						      brasero_video_project_result_cb,
+						      brasero_video_project_vfs_operation_finished,
+						      NULL);
+
+	file->is_loading = 1;
+	priv->loading ++;
+
+	ref = brasero_video_project_reference_new (self, file);
+	brasero_io_get_file_info (priv->io,
+				  uri,
+				  priv->load_uri,
+				  BRASERO_IO_INFO_PERM|
+				  BRASERO_IO_INFO_MIME|
+				  BRASERO_IO_INFO_URGENT|
+				  BRASERO_IO_INFO_METADATA|
+				  BRASERO_IO_INFO_METADATA_MISSING_CODEC|
+				  BRASERO_IO_INFO_METADATA_SNAPSHOT,
+				  GINT_TO_POINTER (ref));
+
+	g_signal_emit (self,
+		       brasero_video_project_signals [ACTIVITY_SIGNAL],
+		       0,
+		       (priv->loading > 0));
+
+	return file;
+}
+
+void
+brasero_video_project_resize_file (BraseroVideoProject *self,
+				   BraseroVideoFile *file,
+				   gint64 start,
+				   gint64 end)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoProjectClass *klass;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	file->start = start;
+	file->end = end;
+
+	klass = BRASERO_VIDEO_PROJECT_GET_CLASS (self);
+	if (klass->node_changed)
+		klass->node_changed (self, file);
+
+	/* update size */
+	g_signal_emit (self,
+		       brasero_video_project_signals [SIZE_CHANGED_SIGNAL],
+		       0);
+}
+
+guint64
+brasero_video_project_get_size (BraseroVideoProject *self)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoFile *iter;
+	guint size = 0;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	/* FIXME: duration to sectors is not correct here, that's not audio... */
+	for (iter = priv->first; iter; iter = iter->next)
+		size += BRASERO_DURATION_TO_SECTORS (iter->end - iter->start);
+
+	return size;
+}
+
+guint
+brasero_video_project_get_file_num (BraseroVideoProject *self)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoFile *item;
+	guint num = 0;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	for (item = priv->first; item; item = item->next)
+		num ++;
+
+	return num;
+}
+
+BraseroVideoFile *
+brasero_video_project_get_nth_item (BraseroVideoProject *self,
+				    guint nth)
+{
+	BraseroVideoFile *item;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	if (!nth)
+		return priv->first;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	for (item = priv->first; item; item = item->next) {
+		if (nth <= 0)
+			return item;
+
+		nth --;
+	}
+
+	return NULL;
+}
+
+guint
+brasero_video_project_get_item_index (BraseroVideoProject *self,
+				      BraseroVideoFile *file)
+{
+	guint nth = 0;
+	BraseroVideoFile *item;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	for (item = priv->first; item; item = item->next) {
+		if (item == file)
+			return nth;
+
+		nth ++;
+	}
+
+	return nth;
+}
+
+BraseroDiscResult
+brasero_video_project_get_status (BraseroVideoProject *self)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+
+	if (priv->loading)
+		return BRASERO_DISC_LOADING;
+
+	if (!priv->first)
+		return BRASERO_DISC_ERROR_EMPTY_SELECTION;
+
+	return BRASERO_DISC_OK;
+}
+
+GSList *
+brasero_video_project_get_contents (BraseroVideoProject *self)
+{
+	GSList *tracks = NULL;
+	BraseroVideoFile *file;
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (self);
+	if (!priv->first)
+		return NULL;
+
+	for (file = priv->first; file; file = file->next) {
+		BraseroSongInfo *info = NULL;
+		BraseroTrack *track;
+
+		if (file->info)
+			info = brasero_song_info_copy (file->info);
+		else
+			info = NULL;
+
+		track = brasero_track_new (BRASERO_TRACK_TYPE_AUDIO);
+		brasero_track_set_audio_source (track,
+						file->uri,
+						BRASERO_AUDIO_FORMAT_UNDEFINED|
+						BRASERO_VIDEO_FORMAT_UNDEFINED);
+
+		brasero_track_set_audio_boundaries (track, file->start, file->end, -1);
+		brasero_track_set_audio_info (track, info);
+		tracks = g_slist_prepend (tracks, track);
+	}
+
+	return tracks;
+}
+
+static void
+brasero_video_project_init (BraseroVideoProject *object)
+{
+	BraseroVideoProjectPrivate *priv;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (object);
+	priv->ref_count = 1;
+}
+
+static void
+brasero_video_project_finalize (GObject *object)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoFile *iter, *next;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (object);
+
+	for (iter = priv->first; iter; iter = next) {
+		next = iter->next;
+		g_free (iter->uri);
+		brasero_song_info_free (iter->info);
+		g_free (iter);
+	}
+
+	if (priv->references) {
+		g_hash_table_destroy (priv->references);
+		priv->references = NULL;
+	}
+
+	G_OBJECT_CLASS (brasero_video_project_parent_class)->finalize (object);
+}
+/**
+ * Callbacks for inotify backend
+ */
+
+#ifdef BUILD_INOTIFY
+
+static void
+brasero_video_project_file_renamed (BraseroFileMonitor *monitor,
+				    BraseroFileMonitorType type,
+				    gpointer callback_data,
+				    const gchar *old_name,
+				    const gchar *new_name)
+{
+	brasero_video_project_rename (BRASERO_VIDEO_PROJECT (monitor),
+				      callback_data,
+				      new_name);
+}
+
+static void
+brasero_video_project_file_removed (BraseroFileMonitor *monitor,
+				    BraseroFileMonitorType type,
+				    gpointer callback_data,
+				    const gchar *name)
+{
+	brasero_video_project_remove_file (BRASERO_VIDEO_PROJECT (monitor),
+					   callback_data);
+}
+
+static void
+brasero_video_project_file_modified (BraseroFileMonitor *monitor,
+				     gpointer callback_data,
+				     const gchar *name)
+{
+	BraseroVideoProjectPrivate *priv;
+	BraseroVideoFile *file;
+	guint ref;
+
+	priv = BRASERO_VIDEO_PROJECT_PRIVATE (monitor);
+
+	/* priv->load_uri has already been initialized otherwise the tree would
+	 * be empty. But who knows... */
+	if (!priv->io || !priv->load_uri)
+		return;
+
+	file = callback_data;
+	file->is_reloading = TRUE;
+
+	ref = brasero_video_project_reference_new (BRASERO_VIDEO_PROJECT (monitor), file);
+	brasero_io_get_file_info (priv->io,
+				  file->uri,
+				  priv->load_uri,
+				  BRASERO_IO_INFO_PERM|
+				  BRASERO_IO_INFO_MIME|
+				  BRASERO_IO_INFO_URGENT|
+				  BRASERO_IO_INFO_METADATA|
+				  BRASERO_IO_INFO_METADATA_MISSING_CODEC|
+				  BRASERO_IO_INFO_METADATA_SNAPSHOT,
+				  GINT_TO_POINTER (ref));
+}
+
+static void
+brasero_video_project_file_moved (BraseroFileMonitor *monitor,
+				  BraseroFileMonitorType type,
+				  gpointer callback_src,
+				  const gchar *name_src,
+				  gpointer callback_dest,
+				  const gchar *name_dest)
+{
+	/* This is a file removed since we won't monitor all folders to get its
+	 * new path */
+	/* FIXME: what about files moved to one of the URI in the list ? */
+	brasero_video_project_remove_file (BRASERO_VIDEO_PROJECT (monitor),
+					   callback_src);
+}
+
+#endif
+
+static void
+brasero_video_project_class_init (BraseroVideoProjectClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVideoProjectPrivate));
+
+	object_class->finalize = brasero_video_project_finalize;
+
+	brasero_video_project_signals [SIZE_CHANGED_SIGNAL] = 
+	    g_signal_new ("size_changed",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_LAST|G_SIGNAL_NO_RECURSE,
+			  0,
+			  NULL, NULL,
+			  g_cclosure_marshal_VOID__VOID,
+			  G_TYPE_NONE,
+			  0,
+			  G_TYPE_NONE);
+
+	brasero_video_project_signals [PROJECT_LOADED_SIGNAL] = 
+	    g_signal_new ("project-loaded",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_LAST|G_SIGNAL_NO_RECURSE,
+			  0,
+			  NULL, NULL,
+			  g_cclosure_marshal_VOID__INT,
+			  G_TYPE_NONE,
+			  1,
+			  G_TYPE_INT);
+
+	brasero_video_project_signals [UNREADABLE_SIGNAL] = 
+	    g_signal_new ("unreadable_uri",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_FIRST,
+			  0,
+			  NULL, NULL,
+			  brasero_marshal_VOID__POINTER_STRING,
+			  G_TYPE_NONE,
+			  2,
+			  G_TYPE_POINTER,
+			  G_TYPE_STRING);
+
+	brasero_video_project_signals [NOT_VIDEO_SIGNAL] = 
+	    g_signal_new ("not_video_uri",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_FIRST,
+			  0,
+			  NULL, NULL,
+			  g_cclosure_marshal_VOID__STRING,
+			  G_TYPE_NONE,
+			  1,
+			  G_TYPE_STRING);
+
+	brasero_video_project_signals [DIRECTORY_URI_SIGNAL] = 
+	    g_signal_new ("directory_uri",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_LAST|G_SIGNAL_NO_RECURSE,
+			  0,
+			  NULL, NULL,
+			  brasero_marshal_BOOLEAN__STRING,
+			  G_TYPE_BOOLEAN,
+			  1,
+			  G_TYPE_STRING);
+
+	brasero_video_project_signals [ACTIVITY_SIGNAL] = 
+	    g_signal_new ("vfs_activity",
+			  G_TYPE_FROM_CLASS (klass),
+			  G_SIGNAL_RUN_FIRST|G_SIGNAL_NO_RECURSE,
+			  0,
+			  NULL, NULL,
+			  g_cclosure_marshal_VOID__BOOLEAN,
+			  G_TYPE_NONE,
+			  1,
+			  G_TYPE_BOOLEAN);
+
+#ifdef BUILD_INOTIFY
+
+	BraseroFileMonitorClass *monitor_class = BRASERO_FILE_MONITOR_CLASS (klass);
+
+	/* NOTE: file_added is not needed here since there aren't any directory */
+	monitor_class->file_moved = brasero_video_project_file_moved;
+	monitor_class->file_removed = brasero_video_project_file_removed;
+	monitor_class->file_renamed = brasero_video_project_file_renamed;
+	monitor_class->file_modified = brasero_video_project_file_modified;
+
+#endif
+}

Added: trunk/src/brasero-video-project.h
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-project.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,176 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifndef _BRASERO_VIDEO_PROJECT_H_
+#define _BRASERO_VIDEO_PROJECT_H_
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+#ifdef BUILD_INOTIFY
+
+#include "brasero-file-monitor.h"
+
+#endif
+
+#include "burn-track.h"
+#include "brasero-disc.h"
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VIDEO_PROJECT             (brasero_video_project_get_type ())
+#define BRASERO_VIDEO_PROJECT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VIDEO_PROJECT, BraseroVideoProject))
+#define BRASERO_VIDEO_PROJECT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VIDEO_PROJECT, BraseroVideoProjectClass))
+#define BRASERO_IS_VIDEO_PROJECT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VIDEO_PROJECT))
+#define BRASERO_IS_VIDEO_PROJECT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VIDEO_PROJECT))
+#define BRASERO_VIDEO_PROJECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VIDEO_PROJECT, BraseroVideoProjectClass))
+
+typedef struct _BraseroVideoProjectClass BraseroVideoProjectClass;
+typedef struct _BraseroVideoProject BraseroVideoProject;
+
+typedef struct _BraseroVideoFile BraseroVideoFile;
+struct _BraseroVideoFile {
+	BraseroVideoFile *prev;
+	BraseroVideoFile *next;
+
+	gchar *name;
+	gchar *uri;
+
+	BraseroSongInfo *info;
+
+	guint64 start;
+	guint64 end;
+
+	GdkPixbuf *snapshot;
+
+	guint editable:1;
+	guint is_loading:1;
+	guint is_reloading:1;
+	guint is_monitored:1;
+};
+
+struct _BraseroVideoProjectClass
+{
+#ifdef BUILD_INOTIFY
+	BraseroFileMonitorClass parent_class;
+#else
+	GObjectClass parent_class;
+#endif
+
+	/* virtual functions */
+
+	/**
+	 * num_nodes is the number of nodes that were at the root of the 
+	 * project.
+	 */
+	void		(*reset)		(BraseroVideoProject *project,
+						 guint num_nodes);
+
+	/* NOTE: node_added is also called when there is a moved node;
+	 * in this case a node_removed is first called and then the
+	 * following function is called (mostly to match GtkTreeModel
+	 * API). To detect such a case look at uri which will then be
+	 * set to NULL.
+	 * NULL uri can also happen when it's a created directory.
+	 * if return value is FALSE, node was invalidated during call */
+	gboolean	(*node_added)		(BraseroVideoProject *project,
+						 BraseroVideoFile *node);
+
+	/* This is more an unparent signal. It shouldn't be assumed that the
+	 * node was destroyed or not destroyed. Like the above function, it is
+	 * also called when a node is moved. */
+	void		(*node_removed)		(BraseroVideoProject *project,
+						 BraseroVideoFile *node);
+
+	void		(*node_changed)		(BraseroVideoProject *project,
+						 BraseroVideoFile *node);
+
+	/* NOTE: there is no node reordered as this list order cannot be changed */
+};
+
+struct _BraseroVideoProject
+{
+#ifdef BUILD_INOTIFY
+	BraseroFileMonitor parent_instance;
+#else
+	GObject parent_instance;
+#endif
+};
+
+GType brasero_video_project_get_type (void) G_GNUC_CONST;
+
+void
+brasero_video_file_free (BraseroVideoFile *file);
+
+guint64
+brasero_video_project_get_size (BraseroVideoProject *project);
+
+guint
+brasero_video_project_get_file_num (BraseroVideoProject *project);
+
+void
+brasero_video_project_reset (BraseroVideoProject *project);
+
+void
+brasero_video_project_move (BraseroVideoProject *project,
+			    BraseroVideoFile *file,
+			    BraseroVideoFile *next);
+
+void
+brasero_video_project_rename (BraseroVideoProject *project,
+			      BraseroVideoFile *file,
+			      const gchar *name);
+
+void
+brasero_video_project_remove_file (BraseroVideoProject *project,
+				   BraseroVideoFile *file);
+
+BraseroVideoFile *
+brasero_video_project_add_uri (BraseroVideoProject *project,
+			       const gchar *uri,
+			       BraseroVideoFile *sibling,
+			       gint64 start,
+			       gint64 end);
+
+void
+brasero_video_project_resize_file (BraseroVideoProject *project,
+				   BraseroVideoFile *file,
+				   gint64 start,
+				   gint64 end);
+
+BraseroDiscResult
+brasero_video_project_get_status (BraseroVideoProject *project);
+
+GSList *
+brasero_video_project_get_contents (BraseroVideoProject *project);
+
+BraseroVideoFile *
+brasero_video_project_get_nth_item (BraseroVideoProject *project,
+				    guint nth);
+guint
+brasero_video_project_get_item_index (BraseroVideoProject *project,
+				      BraseroVideoFile *file);
+
+G_END_DECLS
+
+#endif /* _BRASERO_VIDEO_PROJECT_H_ */

Added: trunk/src/brasero-video-tree-model.c
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-tree-model.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,727 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2007 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtktreednd.h>
+#include <gtk/gtkicontheme.h>
+
+#include "burn-basics.h"
+#include "brasero-utils.h"
+#include "brasero-video-project.h"
+#include "brasero-video-tree-model.h"
+
+#include "eggtreemultidnd.h"
+
+typedef struct _BraseroVideoTreeModelPrivate BraseroVideoTreeModelPrivate;
+struct _BraseroVideoTreeModelPrivate
+{
+	guint stamp;
+	GtkIconTheme *theme;
+};
+
+#define BRASERO_VIDEO_TREE_MODEL_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VIDEO_TREE_MODEL, BraseroVideoTreeModelPrivate))
+
+static void
+brasero_video_tree_model_multi_drag_source_iface_init (gpointer g_iface, gpointer data);
+static void
+brasero_video_tree_model_drag_source_iface_init (gpointer g_iface, gpointer data);
+static void
+brasero_video_tree_model_drag_dest_iface_init (gpointer g_iface, gpointer data);
+static void
+brasero_video_tree_model_iface_init (gpointer g_iface, gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (BraseroVideoTreeModel,
+			 brasero_video_tree_model,
+			 BRASERO_TYPE_VIDEO_PROJECT,
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+					        brasero_video_tree_model_iface_init)
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
+					        brasero_video_tree_model_drag_dest_iface_init)
+			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+					        brasero_video_tree_model_drag_source_iface_init)
+			 G_IMPLEMENT_INTERFACE (EGG_TYPE_TREE_MULTI_DRAG_SOURCE,
+					        brasero_video_tree_model_multi_drag_source_iface_init));
+
+
+/**
+ * This is mainly a list so the following functions are not implemented.
+ * But we may need them for AUDIO models when we display GAPs
+ */
+static gboolean
+brasero_video_tree_model_iter_parent (GtkTreeModel *model,
+				      GtkTreeIter *iter,
+				      GtkTreeIter *child)
+{
+	return FALSE;
+}
+
+static gboolean
+brasero_video_tree_model_iter_nth_child (GtkTreeModel *model,
+					 GtkTreeIter *iter,
+					 GtkTreeIter *parent,
+					 gint n)
+{
+	return FALSE;
+}
+
+static gint
+brasero_video_tree_model_iter_n_children (GtkTreeModel *model,
+					  GtkTreeIter *iter)
+{
+	return 0;
+}
+
+static gboolean
+brasero_video_tree_model_iter_has_child (GtkTreeModel *model,
+					 GtkTreeIter *iter)
+{
+	return FALSE;
+}
+
+static gboolean
+brasero_video_tree_model_iter_children (GtkTreeModel *model,
+				        GtkTreeIter *iter,
+				        GtkTreeIter *parent)
+{
+	return FALSE;
+}
+
+static void
+brasero_video_tree_model_get_value (GtkTreeModel *model,
+				    GtkTreeIter *iter,
+				    gint column,
+				    GValue *value)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	BraseroVideoTreeModel *self;
+	BraseroVideoFile *file;
+	GdkPixbuf *pixbuf;
+	gchar *text;
+
+	self = BRASERO_VIDEO_TREE_MODEL (model);
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (model);
+
+	/* make sure that iter comes from us */
+	g_return_if_fail (priv->stamp == iter->stamp);
+	g_return_if_fail (iter->user_data != NULL);
+
+	file = iter->user_data;
+
+	switch (column) {
+	case BRASERO_VIDEO_TREE_MODEL_NAME:
+		g_value_init (value, G_TYPE_STRING);
+
+		if (file->name)
+			g_value_set_string (value, file->name);
+		else if (file->info && file->info->title)
+			g_value_set_string (value, file->info->title);
+		else {
+			gchar *name;
+			gchar *path;
+			gchar *unescaped;
+
+			unescaped = g_uri_unescape_string (file->uri, NULL);
+			path = g_filename_from_uri (unescaped, NULL, NULL);
+			g_free (unescaped);
+
+			name = g_path_get_basename (path);
+			g_free (path);
+
+			g_value_set_string (value, name);
+			g_free (name);
+		}
+
+		return;
+
+	case BRASERO_VIDEO_TREE_MODEL_MIME_ICON:
+		g_value_init (value, GDK_TYPE_PIXBUF);
+
+		if (file->snapshot) {
+			pixbuf = file->snapshot;
+			g_object_ref (file->snapshot);
+		}
+		else if (file->is_loading) {
+			pixbuf = gtk_icon_theme_load_icon (priv->theme,
+							   "image-loading",
+							   96,
+							   0,
+							   NULL);
+		}
+		else {
+			pixbuf = gtk_icon_theme_load_icon (priv->theme,
+							   "image-missing",
+							   96,
+							   0,
+							   NULL);
+		}
+
+		g_value_set_object (value, pixbuf);
+		g_object_unref (pixbuf);
+
+		return;
+
+	case BRASERO_VIDEO_TREE_MODEL_SIZE:
+		g_value_init (value, G_TYPE_STRING);
+
+		if (!file->is_loading) {
+			text = brasero_utils_get_time_string (file->end - file->start, TRUE, FALSE);
+			g_value_set_string (value, text);
+			g_free (text);
+		}
+		else
+			g_value_set_string (value, _("loading"));
+
+		return;
+
+	case BRASERO_VIDEO_TREE_MODEL_EDITABLE:
+		g_value_init (value, G_TYPE_BOOLEAN);
+		g_value_set_boolean (value, file->editable);
+
+		return;
+
+	default:
+		return;
+	}
+
+	return;
+}
+
+GtkTreePath *
+brasero_video_tree_model_file_to_path (BraseroVideoTreeModel *self,
+				       BraseroVideoFile *file)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	GtkTreePath *path;
+	guint nth;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (self);
+
+	path = gtk_tree_path_new ();
+	nth = brasero_video_project_get_item_index (BRASERO_VIDEO_PROJECT (self), file);
+	gtk_tree_path_prepend_index (path, nth);
+
+	return path;
+}
+
+static GtkTreePath *
+brasero_video_tree_model_get_path (GtkTreeModel *model,
+				   GtkTreeIter *iter)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	BraseroVideoFile *file;
+	GtkTreePath *path;
+	guint nth;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (model);
+
+	/* make sure that iter comes from us */
+	g_return_val_if_fail (priv->stamp == iter->stamp, NULL);
+	g_return_val_if_fail (iter->user_data != NULL, NULL);
+
+	file = iter->user_data;
+
+	/* NOTE: there is only one single file without a name: root */
+	path = gtk_tree_path_new ();
+	nth = brasero_video_project_get_item_index (BRASERO_VIDEO_PROJECT (model), file);
+	gtk_tree_path_prepend_index (path, nth);
+
+	return path;
+}
+
+BraseroVideoFile *
+brasero_video_tree_model_path_to_file (BraseroVideoTreeModel *self,
+				       GtkTreePath *path)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	const gint *indices;
+	guint depth;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (self);
+
+	indices = gtk_tree_path_get_indices (path);
+	depth = gtk_tree_path_get_depth (path);
+
+	/* NOTE: it can happen that paths are depth 2 when there is DND but then
+	 * only the first index is relevant. */
+	if (depth > 2)
+		return NULL;
+
+	return brasero_video_project_get_nth_item (BRASERO_VIDEO_PROJECT (self), indices  [0]);
+}
+
+static gboolean
+brasero_video_tree_model_get_iter (GtkTreeModel *model,
+				   GtkTreeIter *iter,
+				   GtkTreePath *path)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	BraseroVideoFile *file;
+	const gint *indices;
+	guint depth;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (model);
+
+	depth = gtk_tree_path_get_depth (path);
+	if (depth > 2)
+		return FALSE;
+
+	indices = gtk_tree_path_get_indices (path);
+	file = brasero_video_project_get_nth_item (BRASERO_VIDEO_PROJECT (model),
+						   indices [0]);
+	if (!file)
+		return FALSE;
+
+	iter->user_data = file;
+	iter->stamp = priv->stamp;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_iter_next (GtkTreeModel *model,
+				    GtkTreeIter *iter)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	BraseroVideoFile *file;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (model);
+
+	/* make sure that iter comes from us */
+	g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
+	g_return_val_if_fail (iter->user_data != NULL, FALSE);
+
+	file = iter->user_data;
+	if (!file || !file->next)
+		return FALSE;
+
+	iter->user_data = file->next;
+	return TRUE;
+}
+
+static GType
+brasero_video_tree_model_get_column_type (GtkTreeModel *model,
+					 gint index)
+{
+	switch (index) {
+	case BRASERO_VIDEO_TREE_MODEL_NAME:
+		return G_TYPE_STRING;
+
+	case BRASERO_VIDEO_TREE_MODEL_MIME_ICON:
+		return GDK_TYPE_PIXBUF;
+
+	case BRASERO_VIDEO_TREE_MODEL_SIZE:
+		return G_TYPE_STRING;
+
+	case BRASERO_VIDEO_TREE_MODEL_EDITABLE:
+		return G_TYPE_BOOLEAN;
+
+	default:
+		break;
+	}
+
+	return G_TYPE_INVALID;
+}
+
+static gint
+brasero_video_tree_model_get_n_columns (GtkTreeModel *model)
+{
+	return BRASERO_VIDEO_TREE_MODEL_COL_NUM;
+}
+
+static GtkTreeModelFlags
+brasero_video_tree_model_get_flags (GtkTreeModel *model)
+{
+	return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gboolean
+brasero_video_tree_model_multi_row_draggable (EggTreeMultiDragSource *drag_source,
+					      GList *path_list)
+{
+	/* All rows are draggable so return TRUE */
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_multi_drag_data_get (EggTreeMultiDragSource *drag_source,
+					      GList *path_list,
+					      GtkSelectionData *selection_data)
+{
+	if (selection_data->target == gdk_atom_intern (BRASERO_DND_TARGET_SELF_FILE_NODES, TRUE)) {
+		BraseroDNDVideoContext context;
+
+		context.model = GTK_TREE_MODEL (drag_source);
+		context.references = path_list;
+
+		gtk_selection_data_set (selection_data,
+					gdk_atom_intern_static_string (BRASERO_DND_TARGET_SELF_FILE_NODES),
+					8,
+					(void *) &context,
+					sizeof (context));
+	}
+	else
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_multi_drag_data_delete (EggTreeMultiDragSource *drag_source,
+						 GList *path_list)
+{
+	/* NOTE: it's not the data in the selection_data here that should be
+	 * deleted but rather the rows selected when there is a move. FALSE
+	 * here means that we didn't delete anything. */
+	/* return TRUE to stop other handlers */
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_drag_data_received (GtkTreeDragDest *drag_dest,
+					     GtkTreePath *dest_path,
+					     GtkSelectionData *selection_data)
+{
+	BraseroVideoFile *file;
+	BraseroVideoFile *sibling;
+	BraseroVideoTreeModel *self;
+
+	self = BRASERO_VIDEO_TREE_MODEL (drag_dest);
+
+	/* The new row(s) must be before dest_path but after our sibling */
+	sibling = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (drag_dest), dest_path);
+		
+	/* Received data: see where it comes from:
+	 * - from us, then that's a simple move
+	 * - from another widget then it's going to be URIS and we add
+	 *   them to VideoProject */
+	if (selection_data->target == gdk_atom_intern (BRASERO_DND_TARGET_SELF_FILE_NODES, TRUE)) {
+		BraseroDNDVideoContext *context;
+		GList *iter;
+
+		context = (BraseroDNDVideoContext *) selection_data->data;
+		if (context->model != GTK_TREE_MODEL (drag_dest))
+			return TRUE;
+
+		/* That's us: move the row and its children. */
+		for (iter = context->references; iter; iter = iter->next) {
+			GtkTreeRowReference *reference;
+			GtkTreePath *treepath;
+
+			reference = iter->data;
+			treepath = gtk_tree_row_reference_get_path (reference);
+
+			file = brasero_video_tree_model_path_to_file (BRASERO_VIDEO_TREE_MODEL (drag_dest), treepath);
+			gtk_tree_path_free (treepath);
+
+			brasero_video_project_move (BRASERO_VIDEO_PROJECT (self), file, sibling);
+		}
+	}
+	else if (selection_data->target == gdk_atom_intern ("text/uri-list", TRUE)) {
+		gint i;
+		gchar **uris;
+		gboolean success = FALSE;
+
+		/* NOTE: there can be many URIs at the same time. One
+		 * success is enough to return TRUE. */
+		success = FALSE;
+		uris = gtk_selection_data_get_uris (selection_data);
+		if (!uris)
+			return TRUE;
+
+		for (i = 0; uris [i]; i ++) {
+			/* Add the URIs to the project */
+			brasero_video_project_add_uri (BRASERO_VIDEO_PROJECT (self),
+						       uris [i],
+						       sibling,
+						       -1,
+						       -1);
+		}
+		g_strfreev (uris);
+	}
+	else
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_row_drop_possible (GtkTreeDragDest *drag_dest,
+					    GtkTreePath *dest_path,
+					    GtkSelectionData *selection_data)
+{
+	/* It's always possible */
+	return TRUE;
+}
+
+static gboolean
+brasero_video_tree_model_drag_data_delete (GtkTreeDragSource *source,
+					   GtkTreePath *treepath)
+{
+	return TRUE;
+}
+
+static void
+brasero_video_tree_model_clear (BraseroVideoTreeModel *self,
+				guint num_files)
+{
+	GtkTreePath *treepath;
+	BraseroVideoTreeModelPrivate *priv;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (self);
+
+	/* NOTE: no need to move to the next row since previous one was deleted */
+	treepath = gtk_tree_path_new_first ();
+	while (num_files > 0) {
+		num_files --;
+		gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), treepath);
+	}
+	gtk_tree_path_free (treepath);
+}
+
+static void
+brasero_video_tree_model_reset (BraseroVideoProject *project,
+				guint num_files)
+{
+	brasero_video_tree_model_clear (BRASERO_VIDEO_TREE_MODEL (project), num_files);
+
+	/* chain up this function except if we invalidated the file */
+	if (BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->reset)
+		BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->reset (project, num_files);
+}
+
+static gboolean
+brasero_video_tree_model_file_added (BraseroVideoProject *project,
+				     BraseroVideoFile *file)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (project);
+
+	iter.stamp = priv->stamp;
+	iter.user_data = file;
+
+	path = brasero_video_tree_model_file_to_path (BRASERO_VIDEO_TREE_MODEL (project), file);
+
+	/* if the file is reloading (because of a file system change or because
+	 * it was a file that was a tmp folder) then no need to signal an added
+	 * signal but a changed one */
+	if (file->is_reloading) {
+		gtk_tree_model_row_changed (GTK_TREE_MODEL (project),
+					    path,
+					    &iter);
+		gtk_tree_path_free (path);
+		goto end;
+	}
+
+	/* Add the row itself */
+	gtk_tree_model_row_inserted (GTK_TREE_MODEL (project),
+				     path,
+				     &iter);
+	gtk_tree_path_free (path);
+
+end:
+	/* chain up this function */
+	if (BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_added)
+		return BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_added (project,
+													file);
+
+	return TRUE;
+}
+
+static void
+brasero_video_tree_model_file_removed (BraseroVideoProject *project,
+				       BraseroVideoFile *file)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	BraseroVideoFile *next;
+	GtkTreePath *path;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (project);
+
+	/* remove the file. */
+	next = file->next;
+	path = brasero_video_tree_model_file_to_path (BRASERO_VIDEO_TREE_MODEL (project), next);
+	gtk_tree_model_row_deleted (GTK_TREE_MODEL (project), path);
+	gtk_tree_path_free (path);
+
+	/* chain up this function */
+	if (BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_removed)
+		BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_removed (project,
+												   file);
+}
+
+static void
+brasero_video_tree_model_file_changed (BraseroVideoProject *project,
+				       BraseroVideoFile *file)
+{
+	BraseroVideoTreeModelPrivate *priv;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (project);
+
+	/* Get the iter for the file */
+	iter.stamp = priv->stamp;
+	iter.user_data = file;
+
+	path = brasero_video_tree_model_file_to_path (BRASERO_VIDEO_TREE_MODEL (project), file);
+	gtk_tree_model_row_changed (GTK_TREE_MODEL (project),
+				    path,
+				    &iter);
+	gtk_tree_path_free (path);
+
+	/* chain up this function */
+	if (BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_changed)
+		BRASERO_VIDEO_PROJECT_CLASS (brasero_video_tree_model_parent_class)->node_changed (project, file);
+}
+
+static void
+brasero_video_tree_model_init (BraseroVideoTreeModel *object)
+{
+	BraseroVideoTreeModelPrivate *priv;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (object);
+
+	priv->theme = gtk_icon_theme_get_default ();
+
+	do {
+		priv->stamp = g_random_int ();
+	} while (!priv->stamp);
+}
+
+static void
+brasero_video_tree_model_finalize (GObject *object)
+{
+	BraseroVideoTreeModelPrivate *priv;
+
+	priv = BRASERO_VIDEO_TREE_MODEL_PRIVATE (object);
+
+	if (priv->theme) {
+		g_object_unref (priv->theme);
+		priv->theme = NULL;
+	}
+
+	G_OBJECT_CLASS (brasero_video_tree_model_parent_class)->finalize (object);
+}
+
+static void
+brasero_video_tree_model_iface_init (gpointer g_iface, gpointer data)
+{
+	GtkTreeModelIface *iface = g_iface;
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	initialized = TRUE;
+
+	iface->get_flags = brasero_video_tree_model_get_flags;
+	iface->get_n_columns = brasero_video_tree_model_get_n_columns;
+	iface->get_column_type = brasero_video_tree_model_get_column_type;
+	iface->get_iter = brasero_video_tree_model_get_iter;
+	iface->get_path = brasero_video_tree_model_get_path;
+	iface->get_value = brasero_video_tree_model_get_value;
+	iface->iter_next = brasero_video_tree_model_iter_next;
+	iface->iter_children = brasero_video_tree_model_iter_children;
+	iface->iter_has_child = brasero_video_tree_model_iter_has_child;
+	iface->iter_n_children = brasero_video_tree_model_iter_n_children;
+	iface->iter_nth_child = brasero_video_tree_model_iter_nth_child;
+	iface->iter_parent = brasero_video_tree_model_iter_parent;
+}
+
+static void
+brasero_video_tree_model_multi_drag_source_iface_init (gpointer g_iface, gpointer data)
+{
+	EggTreeMultiDragSourceIface *iface = g_iface;
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	initialized = TRUE;
+
+	iface->row_draggable = brasero_video_tree_model_multi_row_draggable;
+	iface->drag_data_get = brasero_video_tree_model_multi_drag_data_get;
+	iface->drag_data_delete = brasero_video_tree_model_multi_drag_data_delete;
+}
+
+static void
+brasero_video_tree_model_drag_source_iface_init (gpointer g_iface, gpointer data)
+{
+	GtkTreeDragSourceIface *iface = g_iface;
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	initialized = TRUE;
+
+	iface->drag_data_delete = brasero_video_tree_model_drag_data_delete;
+}
+
+static void
+brasero_video_tree_model_drag_dest_iface_init (gpointer g_iface, gpointer data)
+{
+	GtkTreeDragDestIface *iface = g_iface;
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	initialized = TRUE;
+
+	iface->drag_data_received = brasero_video_tree_model_drag_data_received;
+	iface->row_drop_possible = brasero_video_tree_model_row_drop_possible;
+}
+
+static void
+brasero_video_tree_model_class_init (BraseroVideoTreeModelClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroVideoProjectClass *video_class = BRASERO_VIDEO_PROJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVideoTreeModelPrivate));
+
+	object_class->finalize = brasero_video_tree_model_finalize;
+
+	video_class->reset = brasero_video_tree_model_reset;
+	video_class->node_added = brasero_video_tree_model_file_added;
+	video_class->node_removed = brasero_video_tree_model_file_removed;
+	video_class->node_changed = brasero_video_tree_model_file_changed;
+}
+
+BraseroVideoTreeModel *
+brasero_video_tree_model_new (void)
+{
+	return g_object_new (BRASERO_TYPE_VIDEO_TREE_MODEL, NULL);
+}

Added: trunk/src/brasero-video-tree-model.h
==============================================================================
--- (empty file)
+++ trunk/src/brasero-video-tree-model.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,83 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2007 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_VIDEO_TREE_MODEL_H_
+#define _BRASERO_VIDEO_TREE_MODEL_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* This DND target when moving nodes inside ourselves */
+#define BRASERO_DND_TARGET_SELF_FILE_NODES	"GTK_TREE_MODEL_ROW"
+
+struct _BraseroDNDVideoContext {
+	GtkTreeModel *model;
+	GList *references;
+};
+typedef struct _BraseroDNDVideoContext BraseroDNDVideoContext;
+
+typedef enum {
+	BRASERO_VIDEO_TREE_MODEL_NAME		= 0,
+	BRASERO_VIDEO_TREE_MODEL_MIME_ICON,
+	BRASERO_VIDEO_TREE_MODEL_SIZE,
+	BRASERO_VIDEO_TREE_MODEL_EDITABLE,
+	BRASERO_VIDEO_TREE_MODEL_COL_NUM
+} BraseroVideoProjectColumn;
+
+#define BRASERO_TYPE_VIDEO_TREE_MODEL             (brasero_video_tree_model_get_type ())
+#define BRASERO_VIDEO_TREE_MODEL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VIDEO_TREE_MODEL, BraseroVideoTreeModel))
+#define BRASERO_VIDEO_TREE_MODEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VIDEO_TREE_MODEL, BraseroVideoTreeModelClass))
+#define BRASERO_IS_VIDEO_TREE_MODEL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VIDEO_TREE_MODEL))
+#define BRASERO_IS_VIDEO_TREE_MODEL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VIDEO_TREE_MODEL))
+#define BRASERO_VIDEO_TREE_MODEL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VIDEO_TREE_MODEL, BraseroVideoTreeModelClass))
+
+typedef struct _BraseroVideoTreeModelClass BraseroVideoTreeModelClass;
+typedef struct _BraseroVideoTreeModel BraseroVideoTreeModel;
+
+struct _BraseroVideoTreeModelClass
+{
+	BraseroVideoProjectClass parent_class;
+};
+
+struct _BraseroVideoTreeModel
+{
+	BraseroVideoProject parent_instance;
+};
+
+GType brasero_video_tree_model_get_type (void) G_GNUC_CONST;
+
+BraseroVideoTreeModel *
+brasero_video_tree_model_new (void);
+
+BraseroVideoFile *
+brasero_video_tree_model_path_to_file (BraseroVideoTreeModel *self,
+				       GtkTreePath *path);
+GtkTreePath *
+brasero_video_tree_model_file_to_path (BraseroVideoTreeModel *self,
+				       BraseroVideoFile *file);
+
+G_END_DECLS
+
+#endif /* _BRASERO_VIDEO_TREE_MODEL_H_ */

Modified: trunk/src/burn-basics.h
==============================================================================
--- trunk/src/burn-basics.h	(original)
+++ trunk/src/burn-basics.h	Mon Jul 14 18:07:55 2008
@@ -155,7 +155,7 @@
 	BRASERO_BURN_FLAG_LAST
 } BraseroBurnFlag;
 
-#define BRASERO_BURN_FLAG_ALL			0x7FFF
+#define BRASERO_BURN_FLAG_ALL			0xFFFF
 
 #define BRASERO_PLUGIN_KEY		"/apps/brasero/config/plugins"
 
@@ -180,6 +180,47 @@
 void
 brasero_burn_library_shutdown (void);
 
+/**
+ * Some defined and usable tags for a session
+ */
+
+/**
+ * Define the audio streams for a DVD
+ */
+#define BRASERO_DVD_AUDIO_STREAMS		"DVD-audio-format"
+
+/**
+ * Define the format: whether VCD or SVCD
+ */
+enum {
+	BRASERO_VCD_NONE,
+	BRASERO_VCD_V1,
+	BRASERO_VCD_V2,
+	BRASERO_SVCD
+};
+#define BRASERO_VCD_TYPE			"VCD-format"
+
+/**
+ * This is the video format that should be used.
+ */
+enum {
+	BRASERO_VIDEO_FRAMERATE_NATIVE,
+	BRASERO_VIDEO_FRAMERATE_NTSC,
+	BRASERO_VIDEO_FRAMERATE_PAL_SECAM
+};
+#define BRASERO_VIDEO_OUTPUT_FRAMERATE		"video-framerate"
+
+/**
+ * Aspect ratio
+ */
+enum {
+	BRASERO_VIDEO_ASPECT_NATIVE,
+	BRASERO_VIDEO_ASPECT_4_3,
+	BRASERO_VIDEO_ASPECT_16_9
+};
+#define BRASERO_VIDEO_OUTPUT_ASPECT		"video-aspect"
+
+
 G_END_DECLS
 
 #endif /* _BURN_BASICS_H */

Modified: trunk/src/burn-caps.c
==============================================================================
--- trunk/src/burn-caps.c	(original)
+++ trunk/src/burn-caps.c	Mon Jul 14 18:07:55 2008
@@ -801,6 +801,29 @@
 	return FALSE;
 }
 
+static gboolean
+brasero_caps_link_check_media_restrictions (BraseroCapsLink *link,
+					    BraseroMedia media)
+{
+	GSList *iter;
+
+	/* Go through all plugins: at least one must support record flags */
+	for (iter = link->plugins; iter; iter = iter->next) {
+		gboolean result;
+		BraseroPlugin *plugin;
+
+		plugin = iter->data;
+		if (!brasero_plugin_get_active (plugin))
+			continue;
+
+		result = brasero_plugin_check_media_restrictions (plugin, media);
+		if (result)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 static BraseroPlugin *
 brasero_caps_link_find_plugin (BraseroCapsLink *link,
 			       gint group_id,
@@ -844,6 +867,8 @@
 			if (!result)
 				continue;
 		}
+		else if (!brasero_plugin_check_media_restrictions (plugin, media))
+			continue;
 
 		if (group_id > 0 && candidate) {
 			/* the candidate must be in the favourite group as much as possible */
@@ -1700,8 +1725,11 @@
 		/* first see if that's the perfect fit:
 		 * - it must have the same caps (type + subtype)
 		 * - it must have the proper IO */
-		if (link->caps->type.type == BRASERO_TRACK_TYPE_DATA
-		&& !brasero_caps_link_check_data_flags (link, session_flags, media))
+		if (link->caps->type.type == BRASERO_TRACK_TYPE_DATA) {
+			if (!brasero_caps_link_check_data_flags (link, session_flags, media))
+				continue;
+		}
+		else if (!brasero_caps_link_check_media_restrictions (link, media))
 			continue;
 
 		if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
@@ -2178,6 +2206,8 @@
 			if ((tmp & data_supported) != tmp)
 				continue;
 		}
+		else if (!brasero_caps_link_check_media_restrictions (link, media))
+			continue;
 
 		/* see if that's the perfect fit */
 		if ((link->caps->flags & BRASERO_PLUGIN_IO_ACCEPT_FILE)
@@ -2208,7 +2238,6 @@
 						   flags,
 						   supported,
 						   compulsory);
-
 		if (io_flags == BRASERO_PLUGIN_IO_NONE)
 			continue;
 
@@ -2910,6 +2939,8 @@
 		BraseroCaps *caps;
 		BraseroAudioFormat common;
 		BraseroPluginIOFlag common_io;
+		BraseroAudioFormat common_audio;
+		BraseroAudioFormat common_video;
 
 		caps = iter->data;
 
@@ -2927,11 +2958,21 @@
 			continue;
 		}
 
-		/* search caps strictly encompassed or encompassing our format */
-		common = caps->type.subtype.audio_format & format;
-		if (common == BRASERO_AUDIO_FORMAT_NONE)
+		/* Search caps strictly encompassed or encompassing our format
+		 * NOTE: make sure that if there is a VIDEO stream in one of
+		 * them, the other does have a VIDEO stream too. */
+		common_audio = BRASERO_AUDIO_CAPS_AUDIO (caps->type.subtype.audio_format) & 
+			       BRASERO_AUDIO_CAPS_AUDIO (format);
+		if (common_audio == BRASERO_AUDIO_FORMAT_NONE)
 			continue;
 
+		common_video = BRASERO_AUDIO_CAPS_VIDEO (caps->type.subtype.audio_format) & 
+			       BRASERO_AUDIO_CAPS_VIDEO (format);
+		if (common_video == BRASERO_AUDIO_FORMAT_NONE)
+			continue;
+
+		common = common_audio|common_video;
+
 		/* encompassed caps just add it to retval */
 		if (caps->type.subtype.audio_format == common)
 			retval = g_slist_prepend (retval, caps);
@@ -3523,7 +3564,8 @@
 
 		caps = iter->data;
 		if (caps->type.type != BRASERO_TRACK_TYPE_IMAGE
-		&&  caps->type.type != BRASERO_TRACK_TYPE_AUDIO)
+		&&  caps->type.type != BRASERO_TRACK_TYPE_AUDIO
+		&&  caps->type.type != BRASERO_TRACK_TYPE_DATA)
 			continue;
 
 		destination = caps->type.type;

Modified: trunk/src/burn-debug.c
==============================================================================
--- trunk/src/burn-debug.c	(original)
+++ trunk/src/burn-debug.c	Mon Jul 14 18:07:55 2008
@@ -268,10 +268,31 @@
 		strcat (buffer, "RAW ");
 
 	if (format & BRASERO_AUDIO_FORMAT_UNDEFINED)
-		strcat (buffer, "UNDEFINED ");
+		strcat (buffer, "AUDIO UNDEFINED ");
 
 	if (format & BRASERO_AUDIO_FORMAT_4_CHANNEL)
 		strcat (buffer, "4 CHANNELS ");
+
+	if (format & BRASERO_AUDIO_FORMAT_MP2)
+		strcat (buffer, "MP2 ");
+
+	if (format & BRASERO_AUDIO_FORMAT_AC3)
+		strcat (buffer, "AC3 ");
+
+	if (format & BRASERO_AUDIO_FORMAT_44100)
+		strcat (buffer, "44100 ");
+
+	if (format & BRASERO_AUDIO_FORMAT_48000)
+		strcat (buffer, "48000 ");
+
+	if (format & BRASERO_VIDEO_FORMAT_UNDEFINED)
+		strcat (buffer, "VIDEO UNDEFINED ");
+
+	if (format & BRASERO_VIDEO_FORMAT_VCD)
+		strcat (buffer, "VCD ");
+
+	if (format & BRASERO_VIDEO_FORMAT_VCD)
+		strcat (buffer, "Video DVD ");
 }
 
 void

Modified: trunk/src/burn-job.c
==============================================================================
--- trunk/src/burn-job.c	(original)
+++ trunk/src/burn-job.c	Mon Jul 14 18:07:55 2008
@@ -617,8 +617,7 @@
 		}
 	}
 	else
-		BRASERO_JOB_LOG (self, "linked to %s",
-				 G_OBJECT_TYPE_NAME (priv->linked));
+		BRASERO_JOB_LOG (self, "linked to %s", G_OBJECT_TYPE_NAME (priv->linked));
 
 	if (!brasero_job_is_first_active (self)) {
 		int fd [2];
@@ -1657,8 +1656,7 @@
 {
 	BraseroJobPrivate *priv;
 
-	BRASERO_JOB_DEBUG (self);
-
+	BRASERO_JOB_LOG (self, "Called brasero_job_set_progress (%lf)", progress);
 	priv = BRASERO_JOB_PRIVATE (self);
 	if (priv->next)
 		return BRASERO_BURN_ERR;

Modified: trunk/src/burn-medium.c
==============================================================================
--- trunk/src/burn-medium.c	(original)
+++ trunk/src/burn-medium.c	Mon Jul 14 18:07:55 2008
@@ -873,6 +873,7 @@
 	g_free (data);
 	return BRASERO_BURN_OK;
 }
+ 
 /**
  * Functions to get information about disc contents
  */

Modified: trunk/src/burn-plugin-private.h
==============================================================================
--- trunk/src/burn-plugin-private.h	(original)
+++ trunk/src/burn-plugin-private.h	Mon Jul 14 18:07:55 2008
@@ -91,6 +91,9 @@
 brasero_plugin_check_record_flags (BraseroPlugin *plugin,
 				   BraseroMedia media,
 				   BraseroBurnFlag current);
+gboolean
+brasero_plugin_check_media_restrictions (BraseroPlugin *plugin,
+					 BraseroMedia media);
 
 gboolean
 brasero_plugin_get_image_flags (BraseroPlugin *plugin,

Modified: trunk/src/burn-plugin.c
==============================================================================
--- trunk/src/burn-plugin.c	(original)
+++ trunk/src/burn-plugin.c	Mon Jul 14 18:07:55 2008
@@ -605,6 +605,7 @@
 	BraseroPluginPrivate *priv;
 
 	priv = BRASERO_PLUGIN_PRIVATE (self);
+
 	current &= BRASERO_PLUGIN_IMAGE_FLAG_MASK;
 
 	/* If there is no flag that's no use checking anything. If there is no
@@ -623,6 +624,21 @@
 }
 
 gboolean
+brasero_plugin_check_media_restrictions (BraseroPlugin *self,
+					 BraseroMedia media)
+{
+	BraseroPluginPrivate *priv;
+
+	priv = BRASERO_PLUGIN_PRIVATE (self);
+
+	/* no restrictions */
+	if (!priv->flags)
+		return TRUE;
+
+	return (brasero_plugin_get_flags (priv->flags, media) != NULL);
+}
+
+gboolean
 brasero_plugin_get_record_flags (BraseroPlugin *self,
 				 BraseroMedia media,
 				 BraseroBurnFlag current,

Modified: trunk/src/burn-process.c
==============================================================================
--- trunk/src/burn-process.c	(original)
+++ trunk/src/burn-process.c	Mon Jul 14 18:07:55 2008
@@ -285,11 +285,13 @@
 		g_free (uri);
 	}
 
-	brasero_job_add_track (BRASERO_JOB (self), track);
+	if (track) {
+		brasero_job_add_track (BRASERO_JOB (self), track);
 
-	/* It's good practice to unref the track afterwards as we don't need it
-	 * anymore. BraseroTaskCtx refs it. */
-	brasero_track_unref (track);
+		/* It's good practice to unref the track afterwards as we don't
+		 * need it anymore. BraseroTaskCtx refs it. */
+		brasero_track_unref (track);
+	}
 
 	klass->post (BRASERO_JOB (self));
 	return BRASERO_BURN_OK;

Modified: trunk/src/burn-session.c
==============================================================================
--- trunk/src/burn-session.c	(original)
+++ trunk/src/burn-session.c	Mon Jul 14 18:07:55 2008
@@ -1095,6 +1095,22 @@
 }
 
 BraseroBurnResult
+brasero_burn_session_tag_remove (BraseroBurnSession *self,
+				 const gchar *tag)
+{
+	BraseroBurnSessionPrivate *priv;
+
+	g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
+
+	priv = BRASERO_BURN_SESSION_PRIVATE (self);
+	if (!priv->tags)
+		return BRASERO_BURN_ERR;
+
+	g_hash_table_remove (priv->tags, tag);
+	return BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
 brasero_burn_session_tag_add (BraseroBurnSession *self,
 			      const gchar *tag,
 			      GValue *value)

Modified: trunk/src/burn-session.h
==============================================================================
--- trunk/src/burn-session.h	(original)
+++ trunk/src/burn-session.h	Mon Jul 14 18:07:55 2008
@@ -104,6 +104,11 @@
 brasero_burn_session_tag_add (BraseroBurnSession *session,
 			      const gchar *tag,
 			      GValue *value);
+
+BraseroBurnResult
+brasero_burn_session_tag_remove (BraseroBurnSession *session,
+				 const gchar *tag);
+
 /**
  * 
  */

Modified: trunk/src/burn-track.h
==============================================================================
--- trunk/src/burn-track.h	(original)
+++ trunk/src/burn-track.h	Mon Jul 14 18:07:55 2008
@@ -63,9 +63,19 @@
 	BRASERO_AUDIO_FORMAT_NONE		= 0,
 	BRASERO_AUDIO_FORMAT_UNDEFINED		= 1,
 	BRASERO_AUDIO_FORMAT_4_CHANNEL		= 1 << 1,
-	BRASERO_AUDIO_FORMAT_RAW		= 1 << 2
+	BRASERO_AUDIO_FORMAT_RAW		= 1 << 2,
+	BRASERO_AUDIO_FORMAT_AC3		= 1 << 3,
+	BRASERO_AUDIO_FORMAT_MP2		= 1 << 4,
+	BRASERO_AUDIO_FORMAT_44100		= 1 << 5,
+	BRASERO_AUDIO_FORMAT_48000		= 1 << 6,
+	BRASERO_VIDEO_FORMAT_UNDEFINED		= 1 << 7,
+	BRASERO_VIDEO_FORMAT_VCD		= 1 << 8,
+	BRASERO_VIDEO_FORMAT_VIDEO_DVD		= 1 << 9
 } BraseroAudioFormat;
 
+#define BRASERO_AUDIO_CAPS_AUDIO(caps_FORMAT)	((caps_FORMAT) & 0x007F)
+#define BRASERO_AUDIO_CAPS_VIDEO(caps_FORMAT)	((caps_FORMAT) & 0x0180)
+
 typedef enum {
 	BRASERO_CHECKSUM_NONE			= 0,
 	BRASERO_CHECKSUM_MD5			= 1,

Modified: trunk/src/plugins/Makefile.am
==============================================================================
--- trunk/src/plugins/Makefile.am	(original)
+++ trunk/src/plugins/Makefile.am	Mon Jul 14 18:07:55 2008
@@ -1,4 +1,4 @@
-SUBDIRS = cdrdao transcode dvdcss growisofs checksum local-track
+SUBDIRS = cdrdao transcode dvdcss growisofs checksum local-track dvdauthor vcdimager
 
 if BUILD_LIBBURNIA
 SUBDIRS += libburnia

Modified: trunk/src/plugins/cdrdao/burn-toc2cue.c
==============================================================================
--- trunk/src/plugins/cdrdao/burn-toc2cue.c	(original)
+++ trunk/src/plugins/cdrdao/burn-toc2cue.c	Mon Jul 14 18:07:55 2008
@@ -263,7 +263,7 @@
 		priv->output = NULL;
 	}
 
-	return BRASERO_BURN_OK;
+	return brasero_job_finished_session (job);
 }
 
 static void

Modified: trunk/src/plugins/cdrkit/burn-wodim.c
==============================================================================
--- trunk/src/plugins/cdrkit/burn-wodim.c	(original)
+++ trunk/src/plugins/cdrkit/burn-wodim.c	Mon Jul 14 18:07:55 2008
@@ -1087,7 +1087,8 @@
 
 	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
 					BRASERO_PLUGIN_IO_ACCEPT_FILE,
-					BRASERO_AUDIO_FORMAT_RAW);
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
 
 	brasero_plugin_link_caps (plugin, output, input);
 	g_slist_free (output);

Modified: trunk/src/plugins/cdrtools/burn-cdrecord.c
==============================================================================
--- trunk/src/plugins/cdrtools/burn-cdrecord.c	(original)
+++ trunk/src/plugins/cdrtools/burn-cdrecord.c	Mon Jul 14 18:07:55 2008
@@ -1082,7 +1082,8 @@
 
 	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
 					BRASERO_PLUGIN_IO_ACCEPT_FILE,
-					BRASERO_AUDIO_FORMAT_RAW);
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
 
 	brasero_plugin_link_caps (plugin, output, input);
 	g_slist_free (output);

Added: trunk/src/plugins/dvdauthor/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/plugins/dvdauthor/Makefile.am	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,24 @@
+DISABLE_DEPRECATED = -DG_DISABLE_DEPRECATED
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_builddir)				\
+	-I$(top_srcdir)/src				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_BASE_CFLAGS)				\
+	$(BRASERO_LIBXML_CFLAGS)
+
+AM_CFLAGS = -g
+
+dvdauthordir = $(libdir)/brasero/plugins
+dvdauthor_LTLIBRARIES = libbrasero-dvdauthor.la
+
+libbrasero_dvdauthor_la_SOURCES = burn-dvdauthor.c burn-dvdauthor.h
+libbrasero_dvdauthor_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_LIBXML_LIBS)
+libbrasero_dvdauthor_la_LDFLAGS = -module -avoid-version
+

Added: trunk/src/plugins/dvdauthor/burn-dvdauthor.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/dvdauthor/burn-dvdauthor.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,404 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * burn-dvdauthor.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * burn-dvdauthor.c 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "burn-basics.h"
+#include "burn-plugin.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-dvdauthor.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroDvdAuthor, brasero_dvd_author, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroDvdAuthorPrivate BraseroDvdAuthorPrivate;
+struct _BraseroDvdAuthorPrivate
+{
+	gchar *output;
+};
+
+#define BRASERO_DVD_AUTHOR_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_dvd_author_add_track (BraseroJob *job)
+{
+	gchar *path;
+	BraseroTrack *track;
+	GSList *grafts = NULL;
+	BraseroGraftPt *graft;
+	BraseroDvdAuthorPrivate *priv;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+	/* create the track */
+	track = brasero_track_new (BRASERO_TRACK_TYPE_DATA);
+
+	/* audio */
+	graft = g_new (BraseroGraftPt, 1);
+	path = g_build_path (G_DIR_SEPARATOR_S,
+			     priv->output,
+			     "AUDIO_TS",
+			     NULL);
+	graft->uri = g_filename_to_uri (path, NULL, NULL);
+	g_free (path);
+
+	graft->path = g_strdup ("/AUDIO_TS");
+	grafts = g_slist_prepend (grafts, graft);
+
+	BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+	/* video */
+	graft = g_new (BraseroGraftPt, 1);
+	path = g_build_path (G_DIR_SEPARATOR_S,
+			     priv->output,
+			     "VIDEO_TS",
+			     NULL);
+	graft->uri = g_filename_to_uri (path, NULL, NULL);
+	g_free (path);
+
+	graft->path = g_strdup ("/VIDEO_TS");
+	grafts = g_slist_prepend (grafts, graft);
+
+	BRASERO_JOB_LOG (job, "Adding graft point for %s", graft->uri);
+
+	brasero_track_add_data_fs (track,
+				   BRASERO_IMAGE_FS_ISO|
+				   BRASERO_IMAGE_FS_UDF|
+				   BRASERO_IMAGE_FS_VIDEO);
+	brasero_track_set_data_source (track,
+				       grafts,
+				       NULL);
+	brasero_job_add_track (job, track);
+	brasero_track_unref (track);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stdout (BraseroProcess *process,
+				const gchar *line)
+{
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_read_stderr (BraseroProcess *process,
+				const gchar *line)
+{
+	if (!strstr (line, ""))
+		return BRASERO_BURN_OK;
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_generate_xml_file (BraseroProcess *process,
+				      const gchar *path,
+				      GError **error)
+{
+	BraseroDvdAuthorPrivate *priv;
+	BraseroBurnResult result;
+	GSList *tracks = NULL;
+	xmlTextWriter *xml;
+	gint success;
+	GSList *iter;
+
+	BRASERO_JOB_LOG (process, "Creating DVD layout xml file(%s)", path);
+
+	xml = xmlNewTextWriterFilename (path, 0);
+	if (!xml)
+		return BRASERO_BURN_ERR;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+	xmlTextWriterSetIndent (xml, 1);
+	xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+	success = xmlTextWriterStartDocument (xml,
+					      NULL,
+					      "UTF8",
+					      NULL);
+	if (success < 0)
+		goto error;
+
+	result = brasero_job_get_tmp_dir (BRASERO_JOB (process),
+					  &priv->output,
+					  error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	/* let's start */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "dvdauthor");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteAttribute (xml,
+					       (xmlChar *) "dest",
+					       (xmlChar *) priv->output);
+	if (success < 0)
+		goto error;
+
+	/* This is needed to finalize */
+	success = xmlTextWriterWriteElement (xml, (xmlChar *) "vmgm", (xmlChar *) "");
+	if (success < 0)
+		goto error;
+
+	/* the tracks */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "titleset");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "titles");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	for (iter = tracks; iter; iter = iter->next) {
+		BraseroTrack *track;
+		gchar *video;
+
+		track = iter->data;
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "pgc");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "vob");
+		if (success < 0)
+			goto error;
+
+		video = brasero_track_get_audio_source (track, FALSE);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "file",
+						       (xmlChar *) video);
+		g_free (video);
+
+		if (success < 0)
+			goto error;
+
+		/* vob */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+
+		/* pgc */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* titles */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* titleset */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* close dvdauthor */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	return BRASERO_BURN_OK;
+
+error:
+
+	BRASERO_JOB_LOG (process, "Error");
+
+	/* close everything */
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	/* FIXME: get the error */
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_set_argv (BraseroProcess *process,
+			     GPtrArray *argv,
+			     GError **error)
+{
+	BraseroDvdAuthorPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	gchar *output;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (process);
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		BRASERO_JOB_NOT_SUPPORTED (process);
+
+	g_ptr_array_add (argv, g_strdup ("dvdauthor"));
+	
+	/* get all arguments to write XML file */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+					   NULL,
+					   &output,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	g_ptr_array_add (argv, g_strdup ("-x"));
+	g_ptr_array_add (argv, output);
+
+	result = brasero_dvd_author_generate_xml_file (process, output, error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	brasero_job_set_current_action (BRASERO_JOB (process),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					_("Creating file layout"),
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_post (BraseroJob *job)
+{
+	BraseroDvdAuthorPrivate *priv;
+
+	priv = BRASERO_DVD_AUTHOR_PRIVATE (job);
+
+	brasero_dvd_author_add_track (job);
+
+	if (priv->output) {
+		g_free (priv->output);
+		priv->output = NULL;
+	}
+
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_dvd_author_init (BraseroDvdAuthor *object)
+{}
+
+static void
+brasero_dvd_author_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_dvd_author_class_init (BraseroDvdAuthorClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroDvdAuthorPrivate));
+
+	object_class->finalize = brasero_dvd_author_finalize;
+
+	process_class->stdout_func = brasero_dvd_author_read_stdout;
+	process_class->stderr_func = brasero_dvd_author_read_stderr;
+	process_class->set_argv = brasero_dvd_author_set_argv;
+	process_class->post = brasero_dvd_author_post;
+}
+
+static BraseroBurnResult
+brasero_dvd_author_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "dvdauthor",
+			       _("use dvdauthor to convert a set of files to burn to Video DVDs"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("dvdauthor", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_AC3|
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_AUDIO_FORMAT_48000|
+					BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+	output = brasero_caps_data_new (BRASERO_IMAGE_FS_ISO|
+					BRASERO_IMAGE_FS_UDF|
+					BRASERO_IMAGE_FS_VIDEO);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* we only support DVDs */
+	brasero_plugin_set_flags (plugin,
+  				  BRASERO_MEDIUM_FILE|
+				  BRASERO_MEDIUM_DVDR|
+				  BRASERO_MEDIUM_DVDR_PLUS|
+				  BRASERO_MEDIUM_DVD_DL|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_DVDRW|
+				  BRASERO_MEDIUM_DVDRW_PLUS|
+				  BRASERO_MEDIUM_DVDRW_RESTRICTED|
+				  BRASERO_MEDIUM_DVD_DL|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	return BRASERO_BURN_OK;
+}

Added: trunk/src/plugins/dvdauthor/burn-dvdauthor.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/dvdauthor/burn-dvdauthor.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * burn-dvdauthor.c
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * burn-dvdauthor.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * burn-dvdauthor.c 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with burn-dvdauthor.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_DVD_AUTHOR_H_
+#define _BRASERO_DVD_AUTHOR_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_DVD_AUTHOR             (brasero_dvd_author_get_type ())
+#define BRASERO_DVD_AUTHOR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthor))
+#define BRASERO_DVD_AUTHOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+#define BRASERO_IS_DVD_AUTHOR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_IS_DVD_AUTHOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_DVD_AUTHOR))
+#define BRASERO_DVD_AUTHOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_DVD_AUTHOR, BraseroDvdAuthorClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_DVD_AUTHOR_H_ */

Modified: trunk/src/plugins/libburnia/burn-libburn.c
==============================================================================
--- trunk/src/plugins/libburnia/burn-libburn.c	(original)
+++ trunk/src/plugins/libburnia/burn-libburn.c	Mon Jul 14 18:07:55 2008
@@ -883,7 +883,8 @@
 	/* audio support for CDs only */
 	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_PIPE|
 					BRASERO_PLUGIN_IO_ACCEPT_FILE,
-					BRASERO_AUDIO_FORMAT_RAW);
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
 	
 	output = brasero_caps_disc_new (media_cd);
 	brasero_plugin_link_caps (plugin, output, input);

Modified: trunk/src/plugins/local-track/burn-local-image.c
==============================================================================
--- trunk/src/plugins/local-track/burn-local-image.c	(original)
+++ trunk/src/plugins/local-track/burn-local-image.c	Mon Jul 14 18:07:55 2008
@@ -965,7 +965,14 @@
 	caps = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
 				       BRASERO_AUDIO_FORMAT_UNDEFINED|
 				       BRASERO_AUDIO_FORMAT_4_CHANNEL|
-				       BRASERO_AUDIO_FORMAT_RAW);
+				       BRASERO_AUDIO_FORMAT_RAW|
+				       BRASERO_VIDEO_FORMAT_UNDEFINED|
+				       BRASERO_VIDEO_FORMAT_VCD|
+				       BRASERO_VIDEO_FORMAT_VIDEO_DVD|
+				       BRASERO_AUDIO_FORMAT_AC3|
+				       BRASERO_AUDIO_FORMAT_MP2|
+				       BRASERO_AUDIO_FORMAT_44100|
+				       BRASERO_AUDIO_FORMAT_48000);
 	brasero_plugin_process_caps (plugin, caps);
 	g_slist_free (caps);
 

Modified: trunk/src/plugins/transcode/Makefile.am
==============================================================================
--- trunk/src/plugins/transcode/Makefile.am	(original)
+++ trunk/src/plugins/transcode/Makefile.am	Mon Jul 14 18:07:55 2008
@@ -28,3 +28,10 @@
 libbrasero_normalize_la_SOURCES = burn-normalize.c burn-normalize.h
 libbrasero_normalize_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_GSTREAMER_CFLAGS)
 libbrasero_normalize_la_LDFLAGS = -module -avoid-version
+
+vobdir = $(libdir)/brasero/plugins
+vob_LTLIBRARIES = libbrasero-vob.la
+
+libbrasero_vob_la_SOURCES = burn-vob.c burn-vob.h
+libbrasero_vob_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_GSTREAMER_CFLAGS)
+libbrasero_vob_la_LDFLAGS = -module -avoid-version

Modified: trunk/src/plugins/transcode/burn-transcode.c
==============================================================================
--- trunk/src/plugins/transcode/burn-transcode.c	(original)
+++ trunk/src/plugins/transcode/burn-transcode.c	Mon Jul 14 18:07:55 2008
@@ -243,11 +243,11 @@
 	||  brasero_track_tag_lookup (track, BRASERO_TRACK_GAIN_VALUE, NULL) == BRASERO_BURN_OK) {
 		BRASERO_JOB_LOG (transcode, "Found audio levels tags");
 		volume = gst_element_factory_make ("rgvolume", NULL);
-		g_object_set (volume,
-			      "album-mode", FALSE,
-			      NULL);
-
-		if (!volume)
+		if (volume)
+			g_object_set (volume,
+				      "album-mode", FALSE,
+				      NULL);
+		else
 			BRASERO_JOB_LOG (transcode, "rgvolume object couldn't be created");
 	}
 
@@ -585,7 +585,10 @@
 	}
 
 	dest = brasero_track_new (BRASERO_TRACK_TYPE_AUDIO);
-	brasero_track_set_audio_source (dest, path_dest, BRASERO_AUDIO_FORMAT_RAW);
+	brasero_track_set_audio_source (dest,
+					path_dest,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
 
 	/* NOTE: there is no gap and start = 0 since these tracks are the result
 	 * of the transformation of previous ones */
@@ -860,7 +863,10 @@
 	brasero_job_get_output_type (BRASERO_JOB (transcode), &type);
 	track = brasero_track_new (BRASERO_TRACK_TYPE_AUDIO);
 
-	brasero_track_set_audio_source (track, output, BRASERO_AUDIO_FORMAT_RAW);
+	brasero_track_set_audio_source (track,
+					output,
+					BRASERO_AUDIO_FORMAT_RAW|
+					BRASERO_AUDIO_FORMAT_44100);
 	brasero_track_set_audio_boundaries (track, 0, length, 0);
 	brasero_track_set_audio_info (track, info);
 
@@ -1011,7 +1017,7 @@
 
 	output = NULL;
 	brasero_job_get_audio_output (BRASERO_JOB (transcode), &output);
-	fd = open (output, O_WRONLY | O_CREAT | O_APPEND, S_IRWXU | S_IRWXG | S_IROTH);
+	fd = open (output, O_WRONLY | O_CREAT | O_APPEND, S_IRWXU | S_IRGRP | S_IROTH);
 	g_free (output);
 
 	if (fd == -1) {
@@ -1438,7 +1444,8 @@
 
 	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE|
 					 BRASERO_PLUGIN_IO_ACCEPT_PIPE,
-					 BRASERO_AUDIO_FORMAT_RAW);
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100);
 
 	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
 					BRASERO_AUDIO_FORMAT_UNDEFINED);

Added: trunk/src/plugins/transcode/burn-vob.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/transcode/burn-vob.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,1084 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-vob.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-vob.c 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include <gst/gst.h>
+
+#include "burn-basics.h"
+#include "burn-job.h"
+#include "burn-plugin.h"
+#include "burn-vob.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVob, brasero_vob, BRASERO_TYPE_JOB, BraseroJob);
+
+typedef struct _BraseroVobPrivate BraseroVobPrivate;
+struct _BraseroVobPrivate
+{
+	GstElement *pipeline;
+
+	GstElement *audio;
+	GstElement *video;
+
+	BraseroAudioFormat format;
+
+	guint svcd:1;
+	guint is_video_dvd:1;
+};
+
+#define BRASERO_VOB_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VOB, BraseroVobPrivate))
+
+static GObjectClass *parent_class = NULL;
+
+
+static void
+brasero_vob_stop_pipeline (BraseroVob *vob)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+	if (!priv->pipeline)
+		return;
+
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+	gst_object_unref (GST_OBJECT (priv->pipeline));
+	priv->pipeline = NULL;
+}
+
+static BraseroBurnResult
+brasero_vob_stop (BraseroJob *job,
+		  GError **error)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	brasero_vob_stop_pipeline (BRASERO_VOB (job));
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_finished (BraseroVob *vob)
+{
+	BraseroVobPrivate *priv;
+	BraseroTrackType type;
+	gchar *output = NULL;
+	BraseroTrack *track;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	memset (&type, 0, sizeof (BraseroTrackType));
+	brasero_job_get_output_type (BRASERO_JOB (vob), &type);
+	brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+
+	track = brasero_track_new (BRASERO_TRACK_TYPE_AUDIO);
+	brasero_track_set_audio_source (track,
+					output,
+					type.subtype.audio_format);
+
+	brasero_job_add_track (BRASERO_JOB (vob), track);
+	brasero_track_unref (track);
+	g_free (output);
+
+	brasero_job_finished_track (BRASERO_JOB (vob));
+}
+
+static gboolean
+brasero_vob_bus_messages (GstBus *bus,
+			  GstMessage *msg,
+			  BraseroVob *vob)
+{
+	BraseroVobPrivate *priv;
+	GError *error = NULL;
+	gchar *debug;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_TAG:
+		return TRUE;
+
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (msg, &error, &debug);
+		BRASERO_JOB_LOG (vob, debug);
+		g_free (debug);
+
+	        brasero_job_error (BRASERO_JOB (vob), error);
+		return FALSE;
+
+	case GST_MESSAGE_EOS:
+		BRASERO_JOB_LOG (vob, "Transcoding finished");
+
+		/* add a new track and terminate */
+		brasero_vob_finished (vob);
+		return FALSE;
+
+	case GST_MESSAGE_STATE_CHANGED:
+		break;
+
+	default:
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+static void
+brasero_vob_new_decoded_pad_cb (GstElement *decode,
+				GstPad *pad,
+				gboolean arg2,
+				BraseroVob *vob)
+{
+	GstPad *sink;
+	GstCaps *caps;
+	GstStructure *structure;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* make sure we only have audio */
+	caps = gst_pad_get_caps (pad);
+	if (!caps)
+		return;
+
+	structure = gst_caps_get_structure (caps, 0);
+	if (structure) {
+		if (g_strrstr (gst_structure_get_name (structure), "video")) {
+			sink = gst_element_get_pad (priv->video, "sink");
+			gst_pad_link (pad, sink);
+			gst_object_unref (sink);
+
+			gst_element_set_state (priv->video, GST_STATE_PLAYING);
+		}
+
+		if (g_strrstr (gst_structure_get_name (structure), "audio")) {
+			sink = gst_element_get_pad (priv->audio, "sink");
+			gst_pad_link (pad, sink);
+			gst_object_unref (sink);
+
+			gst_element_set_state (priv->audio, GST_STATE_PLAYING);
+		}
+	}
+
+	gst_caps_unref (caps);
+}
+
+static gboolean
+brasero_vob_link_audio (BraseroVob *vob,
+			GstElement *start,
+			GstElement *end,
+			GstElement *tee,
+			GstElement *muxer)
+{
+	GstPad *srcpad;
+	GstPad *sinkpad;
+	GstPadLinkReturn res;
+
+	srcpad = gst_element_get_request_pad (tee, "src%d");
+	sinkpad = gst_element_get_static_pad (start, "sink");
+	res = gst_pad_link (srcpad, sinkpad);
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	BRASERO_JOB_LOG (vob, "Linked audio bin to tee == %d", res);
+	if (res != GST_PAD_LINK_OK)
+		return FALSE;
+
+	sinkpad = gst_element_get_request_pad (muxer, "audio_%d");
+	srcpad = gst_element_get_static_pad (end, "src");
+	res = gst_pad_link (srcpad, sinkpad);
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	BRASERO_JOB_LOG (vob, "Linked audio bin to muxer == %d", res);
+	if (res != GST_PAD_LINK_OK)
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+brasero_vob_build_audio_pcm (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *convert;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("queue element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+	g_object_set (queue,
+		      "max-size-bytes", 0,
+		      "max-size-buffers", 0,
+		      "max-size-time", (gint64) 0,
+		      NULL);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioresample can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioconvert can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	gst_element_link_many (queue, resample, convert, NULL);
+	brasero_vob_link_audio (vob, queue, convert, tee, muxer);
+
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_mp2 (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *queue1;
+	GstElement *encode;
+	GstElement *convert;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("queue element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+	g_object_set (queue,
+		      "max-size-bytes", 0,
+		      "max-size-buffers", 0,
+		      "max-size-time", (gint64) 0,
+		      NULL);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioconvert can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioresample can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	encode = gst_element_factory_make ("ffenc_mp2", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("ffenc_mp2 can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	/* another queue */
+	queue1 = gst_element_factory_make ("queue", NULL);
+	if (queue1 == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("queue1 element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue1);
+	g_object_set (queue1,
+		      "max-size-bytes", 0,
+		      "max-size-buffers", 0,
+		      "max-size-time", (gint64) 0,
+		      NULL);
+
+	if (!priv->is_video_dvd) {
+		GstElement *filter;
+		GstCaps *filtercaps;
+
+		/* This is for (S)VCD which need to have audio at 44100 khz */
+
+		/* create a filter */
+		filter = gst_element_factory_make ("capsfilter", NULL);
+		if (filter == NULL) {
+			g_set_error (error,
+				     BRASERO_BURN_ERROR,
+				     BRASERO_BURN_ERROR_GENERAL,
+				     _("filter can't be created"));
+			goto error;
+		}
+		gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+		BRASERO_JOB_LOG (vob, "Setting rate to 44100");
+
+		filtercaps = gst_caps_new_full (gst_structure_new ("audio/x-raw-int",
+								   "channels", G_TYPE_INT, 2,
+								   "width", G_TYPE_INT, 16,
+								   "depth", G_TYPE_INT, 16,
+								   "endianness", G_TYPE_INT, 1234,
+								   "rate", G_TYPE_INT, 44100,
+								   "signed", G_TYPE_BOOLEAN, TRUE,
+								   NULL),
+						NULL);
+
+		g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+		gst_caps_unref (filtercaps);
+
+		gst_element_link_many (queue, convert, resample, filter, encode, queue1, NULL);
+	}
+	else
+		gst_element_link_many (queue, convert, resample, encode, queue1, NULL);
+
+	brasero_vob_link_audio (vob, queue, queue1, tee, muxer);
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static gboolean
+brasero_vob_build_audio_ac3 (BraseroVob *vob,
+			     GstElement *tee,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GstElement *queue;
+	GstElement *encode;
+	GstElement *convert;
+	GstElement *resample;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* queue */
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("queue element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+	g_object_set (queue,
+		      "max-size-bytes", 0,
+		      "max-size-buffers", 0,
+		      "max-size-time", (gint64) 0,
+		      NULL);
+
+	/* audioconvert */
+	convert = gst_element_factory_make ("audioconvert", NULL);
+	if (convert == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioconvert can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), convert);
+
+	/* audioresample */
+	resample = gst_element_factory_make ("audioresample", NULL);
+	if (resample == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("audioresample can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), resample);
+
+	encode = gst_element_factory_make ("ffenc_ac3", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("ffenc_ac3 can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	gst_element_link_many (queue, convert, resample, encode, NULL);
+	brasero_vob_link_audio (vob, queue, encode, tee, muxer);
+
+	return TRUE;
+
+error:
+
+	return FALSE;
+}
+
+static GstElement *
+brasero_vob_build_audio_bins (BraseroVob *vob,
+			      GstElement *muxer,
+			      GError **error)
+{
+	GValue *value;
+	GstElement *tee;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	/* queue */
+	tee = gst_element_factory_make ("tee", NULL);
+	if (tee == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("tee element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), tee);
+
+	if (priv->is_video_dvd) {
+		/* Get output format */
+		value = NULL;
+		brasero_job_tag_lookup (BRASERO_JOB (vob),
+					BRASERO_DVD_AUDIO_STREAMS,
+					&value);
+
+		if (value)
+			priv->format = g_value_get_int (value);
+
+		if (priv->format == BRASERO_AUDIO_FORMAT_NONE)
+			priv->format = BRASERO_AUDIO_FORMAT_RAW;
+
+		if (priv->format & BRASERO_AUDIO_FORMAT_RAW) {
+			/* PCM : on demand */
+			BRASERO_JOB_LOG (vob, "Adding PCM audio stream");
+			if (!brasero_vob_build_audio_pcm (vob, tee, muxer, error))
+				goto error;
+		}
+
+		if (priv->format & BRASERO_AUDIO_FORMAT_AC3) {
+			/* AC3 : on demand */
+			BRASERO_JOB_LOG (vob, "Adding AC3 audio stream");
+			if (!brasero_vob_build_audio_ac3 (vob, tee, muxer, error))
+				goto error;
+		}
+
+		if (priv->format & BRASERO_AUDIO_FORMAT_MP2) {
+			/* MP2 : on demand */
+			BRASERO_JOB_LOG (vob, "Adding MP2 audio stream");
+			if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+				goto error;
+		}
+	}
+	else if (!brasero_vob_build_audio_mp2 (vob, tee, muxer, error))
+		goto error;
+
+	return tee;
+
+error:
+	return NULL;
+}
+
+static GstElement *
+brasero_vob_build_video_bin (BraseroVob *vob,
+			     GstElement *muxer,
+			     GError **error)
+{
+	GValue *value;
+	GstPad *srcpad;
+	GstPad *sinkpad;
+	GstElement *scale;
+	GstElement *queue;
+	GstElement *filter;
+	GstElement *encode;
+	GstPadLinkReturn res;
+	GstElement *framerate;
+	GstElement *colorspace;
+	BraseroVobPrivate *priv;
+	BraseroBurnResult result;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("queue element can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), queue);
+	g_object_set (queue,
+		      "max-size-bytes", 0,
+		      "max-size-buffers", 0,
+		      "max-size-time", (gint64) 0,
+		      NULL);
+
+	/* framerate and video type control */
+	framerate = gst_element_factory_make ("videorate", NULL);
+	if (framerate == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("framerate can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), framerate);
+	g_object_set (framerate,
+		      "silent", TRUE,
+		      NULL);
+
+	/* size scaling */
+	scale = gst_element_factory_make ("videoscale", NULL);
+	if (scale == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("scale can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), scale);
+
+	/* create a filter */
+	filter = gst_element_factory_make ("capsfilter", NULL);
+	if (filter == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("filter can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), filter);
+
+	colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+	if (colorspace == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("ffmpegcolorspace can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), colorspace);
+
+	encode = gst_element_factory_make ("mpeg2enc", NULL);
+	if (encode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("mpeg2enc can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (priv->pipeline), encode);
+
+	if (priv->is_video_dvd)
+		g_object_set (encode,
+			      "format", 8,
+			      NULL);
+	/* NOTE: there is another option to improve compatibility with vcdimager
+	 * but that would mean be sure that it's the next. */
+	else if (priv->svcd)
+		g_object_set (encode,
+			      "format", 4,
+			      NULL);
+	else
+		g_object_set (encode,
+			      "format", 1,
+			      NULL);
+
+	/* settings */
+	value = NULL;
+	result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+					 BRASERO_VIDEO_OUTPUT_FRAMERATE,
+					 &value);
+
+	if (result == BRASERO_BURN_OK && value) {
+		gint rate;
+		GstCaps *filtercaps = NULL;
+
+		rate = g_value_get_int (value);
+
+		if (rate == BRASERO_VIDEO_FRAMERATE_NTSC) {
+			g_object_set (encode,
+				      "norm", 110,
+				      "framerate", 4,
+				      NULL);
+
+			if (priv->is_video_dvd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								NULL);
+			else if (priv->svcd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 480,
+										   NULL),
+								NULL);
+			else
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 240,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 30000, 1001,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 240,
+										   NULL),
+								NULL);
+		}
+		else if (rate == BRASERO_VIDEO_FRAMERATE_PAL_SECAM) {
+			g_object_set (encode,
+				      "norm", 112,
+				      "framerate", 3,
+				      NULL);
+
+			if (priv->is_video_dvd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 720,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								NULL);
+			else if (priv->svcd)
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 480,
+										   "height", G_TYPE_INT, 576,
+										   NULL),
+								NULL);
+			else
+				filtercaps = gst_caps_new_full (gst_structure_new ("video/x-raw-yuv",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 288,
+										   NULL),
+								gst_structure_new ("video/x-raw-rgb",
+										   "framerate", GST_TYPE_FRACTION, 25, 1,
+										   "width", G_TYPE_INT, 352,
+										   "height", G_TYPE_INT, 288,
+										   NULL),
+								NULL);
+		}
+
+		if (filtercaps) {
+			g_object_set (GST_OBJECT (filter), "caps", filtercaps, NULL);
+			gst_caps_unref (filtercaps);
+		}
+	}
+
+	value = NULL;
+	result = brasero_job_tag_lookup (BRASERO_JOB (vob),
+					 BRASERO_VIDEO_OUTPUT_ASPECT,
+					 &value);
+	if (result == BRASERO_BURN_OK && value) {
+		gint aspect;
+
+		aspect = g_value_get_int (value);
+		if (aspect == BRASERO_VIDEO_ASPECT_4_3) {
+			g_object_set (encode,
+				      "aspect", 2,
+				      NULL);
+		}
+		else if (aspect == BRASERO_VIDEO_ASPECT_16_9) {
+			g_object_set (encode,
+				      "aspect", 3,
+				      NULL);	
+		}
+	}
+
+	gst_element_link_many (queue, framerate, scale, colorspace, filter, encode, NULL);
+
+	srcpad = gst_element_get_static_pad (encode, "src");
+	sinkpad = gst_element_get_request_pad (muxer, "video_%d");
+	res = gst_pad_link (srcpad, sinkpad);
+	BRASERO_JOB_LOG (vob, "Linked video bin to muxer == %d", res)
+	gst_object_unref (sinkpad);
+	gst_object_unref (srcpad);
+
+	return queue;
+
+error:
+
+	return NULL;
+}
+
+static gboolean
+brasero_vob_build_pipeline (BraseroVob *vob,
+			    GError **error)
+{
+	gchar *uri;
+	GstBus *bus;
+	gchar *output;
+	GstElement *sink;
+	GstElement *muxer;
+	GstElement *source;
+	GstElement *decode;
+	BraseroTrack *track;
+	GstElement *pipeline;
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (vob);
+
+	BRASERO_JOB_LOG (vob, "Creating new pipeline");
+
+	pipeline = gst_pipeline_new (NULL);
+	priv->pipeline = pipeline;
+
+	/* source */
+	brasero_job_get_current_track (BRASERO_JOB (vob), &track);
+	uri = brasero_track_get_audio_source (track, TRUE);
+	source = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
+	if (source == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("source can't be created"));
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (pipeline), source);
+	g_object_set (source,
+		      "typefind", FALSE,
+		      NULL);
+
+	/* decode */
+	decode = gst_element_factory_make ("decodebin", NULL);
+	if (decode == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("decode can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), decode);
+	gst_element_link_many (source, decode, NULL);
+
+	/* muxer: "mplex" */
+	muxer = gst_element_factory_make ("mplex", NULL);
+	if (muxer == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("mplex can't be created"));
+		goto error;
+	}
+	gst_bin_add (GST_BIN (pipeline), muxer);
+
+	if (priv->is_video_dvd)
+		g_object_set (muxer,
+			      "format", 8,
+			      NULL);
+	else if (priv->svcd)
+		g_object_set (muxer,
+			      "format", 4,
+			      NULL);
+	else
+		g_object_set (muxer,
+			      "format", 1,
+			      NULL);
+
+	/* create sink */
+	output = NULL;
+	brasero_job_get_audio_output (BRASERO_JOB (vob), &output);
+	sink = gst_element_factory_make ("filesink", NULL);
+	if (sink == NULL) {
+		g_set_error (error,
+			     BRASERO_BURN_ERROR,
+			     BRASERO_BURN_ERROR_GENERAL,
+			     _("sink can't be created"));
+		return FALSE;
+	}
+	g_object_set (sink,
+		      "location", output,
+		      NULL);
+
+	gst_bin_add (GST_BIN (pipeline), sink);
+	gst_element_link (muxer, sink);
+
+	/* video encoding */
+	priv->video = brasero_vob_build_video_bin (vob, muxer, error);
+	if (!priv->video)
+		goto error;
+
+	/* audio encoding */
+	priv->audio = brasero_vob_build_audio_bins (vob, muxer, error);
+	if (!priv->audio)
+		goto error;
+
+	/* to be able to link everything */
+	g_signal_connect (G_OBJECT (decode),
+			  "new-decoded-pad",
+			  G_CALLBACK (brasero_vob_new_decoded_pad_cb),
+			  vob);
+
+	/* connect to the bus */	
+	bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+	gst_bus_add_watch (bus,
+			   (GstBusFunc) brasero_vob_bus_messages,
+			   vob);
+	gst_object_unref (bus);
+
+	return TRUE;
+
+error:
+
+	if (error && (*error))
+		BRASERO_JOB_LOG (vob,
+				 "can't create object : %s \n",
+				 (*error)->message);
+
+	gst_object_unref (GST_OBJECT (pipeline));
+	return FALSE;
+}
+
+static BraseroBurnResult
+brasero_vob_start (BraseroJob *job,
+		   GError **error)
+{
+	BraseroVobPrivate *priv;
+	BraseroJobAction action;
+	BraseroTrackType output;
+
+	brasero_job_get_action (job, &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		return BRASERO_BURN_NOT_SUPPORTED;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	/* get destination medium type */
+	memset (&output, 0, sizeof (BraseroTrackType));
+	brasero_job_get_output_type (job, &output);
+	if (output.subtype.audio_format & BRASERO_VIDEO_FORMAT_VCD) {
+		GValue *value = NULL;
+
+		priv->is_video_dvd = FALSE;
+		brasero_job_tag_lookup (job,
+					BRASERO_VCD_TYPE,
+					&value);
+		if (value)
+			priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+	}
+	else
+		priv->is_video_dvd = TRUE;
+
+	BRASERO_JOB_LOG (job,
+			 "Got output type (is DVD %i, is SVCD %i",
+			 priv->is_video_dvd,
+			 priv->svcd);
+
+	if (!brasero_vob_build_pipeline (BRASERO_VOB (job), error))
+		return BRASERO_BURN_ERR;
+
+	/* ready to go */
+	brasero_job_set_current_action (job,
+					BRASERO_BURN_ACTION_ANALYSING,
+					_("Converting video file to MPEG2"),
+					FALSE);
+	gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vob_clock_tick (BraseroJob *job)
+{
+	gint64 position = 0.0;
+	gint64 duration = 0.0;
+	BraseroVobPrivate *priv;
+	GstFormat format = GST_FORMAT_TIME;
+
+	priv = BRASERO_VOB_PRIVATE (job);
+
+	gst_element_query_duration (priv->pipeline, &format, &duration);
+	gst_element_query_position (priv->pipeline, &format, &position);
+
+	if (duration > 0.0) {
+		gdouble progress;
+
+		progress = (gdouble) position / (gdouble) duration;
+		brasero_job_set_progress (job, progress);
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+static void
+brasero_vob_init (BraseroVob *object)
+{}
+
+static void
+brasero_vob_finalize (GObject *object)
+{
+	BraseroVobPrivate *priv;
+
+	priv = BRASERO_VOB_PRIVATE (object);
+
+	if (priv->pipeline) {
+		gst_object_unref (priv->pipeline);
+		priv->pipeline = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vob_class_init (BraseroVobClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroJobClass* job_class = BRASERO_JOB_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVobPrivate));
+
+	object_class->finalize = brasero_vob_finalize;
+
+	job_class->start = brasero_vob_start;
+	job_class->clock_tick = brasero_vob_clock_tick;
+	job_class->stop = brasero_vob_stop;
+}
+
+static BraseroBurnResult
+brasero_vob_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	GSList *input;
+	GSList *output;
+	GstElement *element;
+
+	/* Let's see if we've got the plugins we need */
+	element = gst_element_factory_make ("ffenc_mpeg2video", NULL);
+	if (!element)
+		return BRASERO_BURN_ERR;
+
+	element = gst_element_factory_make ("ffenc_ac3", NULL);
+	if (!element)
+		return BRASERO_BURN_ERR;
+
+	element = gst_element_factory_make ("ffenc_mp2", NULL);
+	if (!element)
+		return BRASERO_BURN_ERR;
+
+	element = gst_element_factory_make ("mplex", NULL);
+	if (!element)
+		return BRASERO_BURN_ERR;
+
+	gst_object_unref (element);
+
+	brasero_plugin_define (plugin,
+			       "transcode2vob",
+			       _("Vob allows to transcode any video file to a format suitable for video DVDs"),
+			       "Philippe Rouquier",
+			       0);
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_UNDEFINED|
+					BRASERO_VIDEO_FORMAT_UNDEFINED);
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_VIDEO_FORMAT_VCD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+
+	output = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_AUDIO_FORMAT_AC3|
+					 BRASERO_AUDIO_FORMAT_MP2|
+					 BRASERO_AUDIO_FORMAT_RAW|
+					 BRASERO_AUDIO_FORMAT_44100|
+					 BRASERO_AUDIO_FORMAT_48000|
+					 BRASERO_VIDEO_FORMAT_VIDEO_DVD);
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	return BRASERO_BURN_OK;
+}

Added: trunk/src/plugins/transcode/burn-vob.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/transcode/burn-vob.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,41 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero-vob.c
+ * Copyright (C) Rouquier Philippe 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero-vob.c is free software.
+ * 
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * brasero-vob.c 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with brasero-vob.c.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_VOB_H_
+#define _BRASERO_VOB_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VOB             (brasero_vob_get_type ())
+#define BRASERO_VOB(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VOB, BraseroVob))
+#define BRASERO_VOB_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VOB, BraseroVobClass))
+#define BRASERO_IS_VOB(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VOB))
+#define BRASERO_IS_VOB_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VOB))
+#define BRASERO_VOB_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VOB, BraseroVobClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VOB_H_ */

Added: trunk/src/plugins/vcdimager/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/plugins/vcdimager/Makefile.am	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,24 @@
+DISABLE_DEPRECATED = -DG_DISABLE_DEPRECATED
+
+INCLUDES = \
+	-I$(top_srcdir)					\
+	-I$(top_builddir)				\
+	-I$(top_srcdir)/src				\
+	-DBRASERO_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" 	\
+	-DBRASERO_PREFIX=\"$(prefix)\"           		\
+	-DBRASERO_SYSCONFDIR=\"$(sysconfdir)\"   		\
+	-DBRASERO_DATADIR=\"$(datadir)/brasero\"     	    	\
+	-DBRASERO_LIBDIR=\"$(libdir)\"  	         	\
+	$(DISABLE_DEPRECATED)				\
+	$(BRASERO_BASE_CFLAGS)				\
+	$(BRASERO_LIBXML_CFLAGS)
+
+AM_CFLAGS = -g
+
+vcdimagerdir = $(libdir)/brasero/plugins
+vcdimager_LTLIBRARIES = libbrasero-vcdimager.la
+
+libbrasero_vcdimager_la_SOURCES = burn-vcdimager.c burn-vcdimager.h
+libbrasero_vcdimager_la_LIBADD = $(BRASERO_BASE_LIBS) $(BRASERO_LIBXML_LIBS)
+libbrasero_vcdimager_la_LDFLAGS = -module -avoid-version
+

Added: trunk/src/plugins/vcdimager/burn-vcdimager.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/vcdimager/burn-vcdimager.c	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,482 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gmodule.h>
+
+#include <libxml/xmlerror.h>
+#include <libxml/xmlwriter.h>
+#include <libxml/parser.h>
+#include <libxml/xmlstring.h>
+#include <libxml/uri.h>
+
+#include "burn-basics.h"
+#include "burn-plugin.h"
+#include "burn-job.h"
+#include "burn-process.h"
+#include "burn-vcdimager.h"
+
+BRASERO_PLUGIN_BOILERPLATE (BraseroVcdImager, brasero_vcd_imager, BRASERO_TYPE_PROCESS, BraseroProcess);
+
+typedef struct _BraseroVcdImagerPrivate BraseroVcdImagerPrivate;
+struct _BraseroVcdImagerPrivate
+{
+	guint svcd:1;
+};
+
+#define BRASERO_VCD_IMAGER_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerPrivate))
+
+static BraseroProcessClass *parent_class = NULL;
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stdout (BraseroProcess *process,
+				const gchar *line)
+{
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_read_stderr (BraseroProcess *process,
+				const gchar *line)
+{
+	if (!strstr (line, ""))
+		return BRASERO_BURN_OK;
+
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_generate_xml_file (BraseroProcess *process,
+				      const gchar *path,
+				      GError **error)
+{
+	BraseroVcdImagerPrivate *priv;
+	GSList *tracks = NULL;
+	xmlTextWriter *xml;
+	gchar buffer [64];
+	gint success;
+	GSList *iter;
+	gchar *name;
+	gint i;
+
+	BRASERO_JOB_LOG (process, "Creating DVD layout xml file(%s)", path);
+
+	xml = xmlNewTextWriterFilename (path, 0);
+	if (!xml)
+		return BRASERO_BURN_ERR;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+	xmlTextWriterSetIndent (xml, 1);
+	xmlTextWriterSetIndentString (xml, (xmlChar *) "\t");
+
+	success = xmlTextWriterStartDocument (xml,
+					      NULL,
+					      "UTF8",
+					      NULL);
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteDTD (xml,
+					(xmlChar *) "videocd",
+					(xmlChar *) "-//GNU//DTD VideoCD//EN",
+					(xmlChar *) "http://www.gnu.org/software/vcdimager/videocd.dtd";,
+					(xmlChar *) NULL);
+	if (success < 0)
+		goto error;
+
+	/* let's start */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "videocd");
+	if (success < 0)
+		goto error;
+
+	success = xmlTextWriterWriteAttribute (xml,
+					       (xmlChar *) "xmlns",
+					       (xmlChar *) "http://www.gnu.org/software/vcdimager/1.0/";);
+	if (success < 0)
+		goto error;
+
+	if (priv->svcd)
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "class",
+						       (xmlChar *) "svcd");
+	else
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "class",
+						       (xmlChar *) "vcd");
+
+	if (success < 0)
+		goto error;
+
+	if (priv->svcd)
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "version",
+						       (xmlChar *) "1.0");
+	else
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "version",
+						       (xmlChar *) "2.0");
+	if (success < 0)
+		goto error;
+
+	/* info part */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "info");
+	if (success < 0)
+		goto error;
+
+	/* name of the volume */
+	name = NULL;
+	brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "album-id",
+					     (xmlChar *) name);
+	g_free (name);
+	if (success < 0)
+		goto error;
+
+	/* number of CDs */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-count",
+					     (xmlChar *) "1");
+	if (success < 0)
+		goto error;
+
+	/* CD number */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-number",
+					     (xmlChar *) "1");
+	if (success < 0)
+		goto error;
+
+	/* close info part */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* Primary Volume descriptor */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "pvd");
+	if (success < 0)
+		goto error;
+
+	name = NULL;
+	brasero_job_get_audio_title (BRASERO_JOB (process), &name);
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "volume-id",
+					     (xmlChar *) name);
+	g_free (name);
+	if (success < 0)
+		goto error;
+
+	/* Makes it CD-i compatible */
+	success = xmlTextWriterWriteElement (xml,
+					     (xmlChar *) "system-id",
+					     (xmlChar *) "CD-RTOS CD-BRIDGE");
+	if (success < 0)
+		goto error;
+
+	/* Close Primary Volume descriptor */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* the tracks */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-items");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+		BraseroTrack *track;
+		gchar *video;
+
+		track = iter->data;
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "sequence-item");
+		if (success < 0)
+			goto error;
+
+		video = brasero_track_get_audio_source (track, FALSE);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "src",
+						       (xmlChar *) video);
+		g_free (video);
+
+		if (success < 0)
+			goto error;
+
+		sprintf (buffer, "track-%i", i);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "id",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		/* close sequence-item */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* sequence-items */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* the navigation */
+	success = xmlTextWriterStartElement (xml, (xmlChar *) "pbc");
+	if (success < 0)
+		goto error;
+
+	/* get all tracks */
+	brasero_job_get_tracks (BRASERO_JOB (process), &tracks);
+	for (i = 0, iter = tracks; iter; iter = iter->next, i++) {
+		BraseroTrack *track;
+
+		track = iter->data;
+
+		sprintf (buffer, "playlist-%i", i);
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "playlist");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "id",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterWriteElement (xml,
+						     (xmlChar *) "wait",
+						     (xmlChar *) "0");
+		if (success < 0)
+			goto error;
+
+		success = xmlTextWriterStartElement (xml, (xmlChar *) "play-item");
+		if (success < 0)
+			goto error;
+
+		sprintf (buffer, "track-%i", i);
+		success = xmlTextWriterWriteAttribute (xml,
+						       (xmlChar *) "ref",
+						       (xmlChar *) buffer);
+		if (success < 0)
+			goto error;
+
+		/* play-item */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+
+		/* playlist */
+		success = xmlTextWriterEndElement (xml);
+		if (success < 0)
+			goto error;
+	}
+
+	/* pbc */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	/* close videocd */
+	success = xmlTextWriterEndElement (xml);
+	if (success < 0)
+		goto error;
+
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	return BRASERO_BURN_OK;
+
+error:
+
+	BRASERO_JOB_LOG (process, "Error");
+
+	/* close everything */
+	xmlTextWriterEndDocument (xml);
+	xmlFreeTextWriter (xml);
+
+	/* FIXME: get the error */
+
+	return BRASERO_BURN_ERR;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_set_argv (BraseroProcess *process,
+			     GPtrArray *argv,
+			     GError **error)
+{
+	BraseroVcdImagerPrivate *priv;
+	BraseroBurnResult result;
+	BraseroJobAction action;
+	BraseroMedia medium;
+	gchar *output;
+	gchar *image;
+	gchar *toc;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (process);
+
+	brasero_job_get_action (BRASERO_JOB (process), &action);
+	if (action != BRASERO_JOB_ACTION_IMAGE)
+		BRASERO_JOB_NOT_SUPPORTED (process);
+
+	g_ptr_array_add (argv, g_strdup ("vcdxbuild"));
+
+	g_ptr_array_add (argv, g_strdup ("--progress"));
+	g_ptr_array_add (argv, g_strdup ("-v"));
+
+	/* specifies output */
+	image = toc = NULL;
+	brasero_job_get_image_output (BRASERO_JOB (process),
+				      &image,
+				      &toc);
+
+	g_ptr_array_add (argv, g_strdup ("-c"));
+	g_ptr_array_add (argv, toc);
+	g_ptr_array_add (argv, g_strdup ("-b"));
+	g_ptr_array_add (argv, image);
+
+	/* get temporary file to write XML */
+	result = brasero_job_get_tmp_file (BRASERO_JOB (process),
+					   NULL,
+					   &output,
+					   error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	g_ptr_array_add (argv, output);
+
+	brasero_job_get_media (BRASERO_JOB (process), &medium);
+	if (medium & BRASERO_MEDIUM_CD) {
+		GValue *value = NULL;
+
+		brasero_job_tag_lookup (BRASERO_JOB (process),
+					BRASERO_VCD_TYPE,
+					&value);
+		if (value)
+			priv->svcd = (g_value_get_int (value) == BRASERO_SVCD);
+	}
+
+	result = brasero_vcd_imager_generate_xml_file (process, output, error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+	
+	brasero_job_set_current_action (BRASERO_JOB (process),
+					BRASERO_BURN_ACTION_CREATING_IMAGE,
+					_("Creating file layout"),
+					FALSE);
+	return BRASERO_BURN_OK;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_post (BraseroJob *job)
+{
+	BraseroVcdImagerPrivate *priv;
+
+	priv = BRASERO_VCD_IMAGER_PRIVATE (job);
+	return brasero_job_finished_session (job);
+}
+
+static void
+brasero_vcd_imager_init (BraseroVcdImager *object)
+{}
+
+static void
+brasero_vcd_imager_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+brasero_vcd_imager_class_init (BraseroVcdImagerClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	BraseroProcessClass* process_class = BRASERO_PROCESS_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroVcdImagerPrivate));
+
+	object_class->finalize = brasero_vcd_imager_finalize;
+	process_class->stdout_func = brasero_vcd_imager_read_stdout;
+	process_class->stderr_func = brasero_vcd_imager_read_stderr;
+	process_class->set_argv = brasero_vcd_imager_set_argv;
+	process_class->post = brasero_vcd_imager_post;
+}
+
+static BraseroBurnResult
+brasero_vcd_imager_export_caps (BraseroPlugin *plugin, gchar **error)
+{
+	BraseroBurnResult result;
+	GSList *output;
+	GSList *input;
+
+	/* NOTE: it seems that cdrecord can burn cue files on the fly */
+	brasero_plugin_define (plugin,
+			       "vcdimager",
+			       _("use vcdimager to convert a set of files to burn to SVCDs"),
+			       "Philippe Rouquier",
+			       1);
+
+	/* First see if this plugin can be used */
+	result = brasero_process_check_path ("vcdimager", error);
+	if (result != BRASERO_BURN_OK)
+		return result;
+
+	input = brasero_caps_audio_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					BRASERO_AUDIO_FORMAT_MP2|
+					BRASERO_AUDIO_FORMAT_44100|
+					BRASERO_VIDEO_FORMAT_VCD);
+	output = brasero_caps_image_new (BRASERO_PLUGIN_IO_ACCEPT_FILE,
+					 BRASERO_IMAGE_FORMAT_CUE);
+
+	brasero_plugin_link_caps (plugin, output, input);
+	g_slist_free (output);
+	g_slist_free (input);
+
+	/* we only support CDs they must be blank */
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_CDRW|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_CLOSED|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA|
+				  BRASERO_MEDIUM_HAS_AUDIO,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+
+	brasero_plugin_set_flags (plugin,
+				  BRASERO_MEDIUM_FILE|
+				  BRASERO_MEDIUM_CDR|
+				  BRASERO_MEDIUM_BLANK|
+				  BRASERO_MEDIUM_APPENDABLE|
+				  BRASERO_MEDIUM_HAS_DATA|
+				  BRASERO_MEDIUM_HAS_AUDIO,
+				  BRASERO_BURN_FLAG_NONE,
+				  BRASERO_BURN_FLAG_NONE);
+	return BRASERO_BURN_OK;
+}
+

Added: trunk/src/plugins/vcdimager/burn-vcdimager.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/vcdimager/burn-vcdimager.h	Mon Jul 14 18:07:55 2008
@@ -0,0 +1,36 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * brasero
+ * Copyright (C) Philippe Rouquier 2008 <bonfire-app wanadoo fr>
+ * 
+ * brasero is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * brasero 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BRASERO_VCD_IMAGER_H_
+#define _BRASERO_VCD_IMAGER_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_VCD_IMAGER             (brasero_vcd_imager_get_type ())
+#define BRASERO_VCD_IMAGER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImager))
+#define BRASERO_VCD_IMAGER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+#define BRASERO_IS_VCD_IMAGER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_IS_VCD_IMAGER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_VCD_IMAGER))
+#define BRASERO_VCD_IMAGER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_VCD_IMAGER, BraseroVcdImagerClass))
+
+G_END_DECLS
+
+#endif /* _BRASERO_VCD_IMAGER_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]