Index: configure.in
===================================================================
RCS file: /cvs/gnome/nautilus/configure.in,v
retrieving revision 1.467
diff -u -r1.467 configure.in
--- configure.in	28 Aug 2002 16:41:47 -0000	1.467
+++ configure.in	17 Sep 2002 17:59:09 -0000
@@ -14,6 +14,7 @@
 GNOME_REQUIRED=2.0.1
 GNOME_UI_REQUIRED=2.0
 GNOME_VFS_REQUIRED=1.9
+GSTREAMER_REQUIRED=0.4
 GTK_REQUIRED=2.0.5
 MEDUSA_REQUIRED=0.5.1
 RSVG_REQUIRED=2.0.1
@@ -188,2 +189,2 @@
 
 dnl 
==========================================================================
 
+dnl gstreamer checking
+
+AC_MSG_CHECKING(for GStreamer)
+
+PKG_CHECK_MODULES(GSTREAMER, 
+		  gstreamer >= $GSTREAMER_REQUIRED \
+		  gstreamer-libs >= $GSTREAMER_REQUIRED, 
+		  have_gstreamer=yes, 
+		  have_gstreamer=no)
+if test "x$have_gstreamer" = "xyes"; then
+  AC_DEFINE(HAVE_GSTREAMER,1)
+  LIBGST_EXTRAS="-lgstcontrol -lgstgconf"
+  EXTRA_CORE_MODULES="$EXTRA_CORE_MODULES gstreamer gstreamer-libs 
gstreamer-player"
+fi
+
+dnl 
==========================================================================
+
 dnl libjpeg
 
   if test -z "$LIBJPEG"; then
@@ -270,1 +288,1 @@
 CORE_MODULES="eel-2.0 librsvg-2.0 bonobo-activation-2.0 libbonobo-2.0 
libbonoboui-2.0 esound gnome-desktop-2.0 $EXTRA_CORE_MODULES"
 CORE_CFLAGS="`$PKG_CONFIG --cflags $CORE_MODULES` $x_cflags"
 AC_SUBST(CORE_CFLAGS)
-CORE_LIBS="`$PKG_CONFIG --libs $CORE_MODULES` $CDDA_LIBS $LIBJPEG 
$x_libs"
+CORE_LIBS="`$PKG_CONFIG --libs $CORE_MODULES` $CDDA_LIBS $LIBJPEG 
$LIBGST_EXTRAS $x_libs"
 AC_SUBST(CORE_LIBS)
 CORE_IDL_INCLUDES="`$PKG_CONFIG --variable=idldir $CORE_MODULES | 
$srcdir/add-include-prefix`"
 AC_SUBST(CORE_IDL_INCLUDES)
Index: libnautilus-private/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/Makefile.am,v
retrieving revision 1.219
diff -u -r1.219 Makefile.am
--- libnautilus-private/Makefile.am	26 Jul 2002 22:57:24 -0000	1.219
+++ libnautilus-private/Makefile.am	17 Sep 2002 17:59:09 -0000
@@ -141,6 +141,8 @@
 	nautilus-theme.h \
 	nautilus-thumbnails-jpeg.c \
 	nautilus-thumbnails-jpeg.h \
+	nautilus-thumbnails-video.c \
+	nautilus-thumbnails-video.h \
 	nautilus-thumbnails.c \
 	nautilus-thumbnails.h \
 	nautilus-trash-directory.c \
Index: libnautilus-private/nautilus-icon-canvas-item.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-canvas-item.c,v
retrieving revision 1.154
diff -u -r1.154 nautilus-icon-canvas-item.c
--- libnautilus-private/nautilus-icon-canvas-item.c	14 Aug 2002 
21:55:01 -0000	1.154
+++ libnautilus-private/nautilus-icon-canvas-item.c	17 Sep 2002 
17:59:10 -0000
@@ -1371,6 +1371,90 @@
 
 
 /* handle events */
+static guint enter_timeout_id = 0;
+
+static gboolean 
+handle_enter_event (GnomeCanvasItem *item)
+{
+	NautilusIconCanvasItem *icon_item;
+
+	icon_item = NAUTILUS_ICON_CANVAS_ITEM (item);
+
+	if (!icon_item->details->is_prelit) {
+		icon_item->details->is_prelit = TRUE;
+		update_label_layouts (icon_item);
+		gnome_canvas_item_request_update (item);
+		/* FIXME bugzilla.gnome.org 42473: 
+		 * We should emit our own signal here,
+		 * not one from the container; it could hook
+		 * up to that signal and emit one of its
+		 * own. Doing it this way hard-codes what
+		 * "user_data" is. Also, the two signals
+		 * should be separate. The "unpreview" signal
+		 * does not have a return value.
+		 */
+		icon_item->details->is_active = 
+			nautilus_icon_container_emit_preview_signal (
+				NAUTILUS_ICON_CONTAINER (item->canvas),
+				NAUTILUS_ICON_CANVAS_ITEM (item)->user_data,
+				TRUE);
+	}
+
+	enter_timeout_id = 0;
+	return FALSE;
+}
+
+static gboolean 
+handle_leave_event (GnomeCanvasItem *item)
+{
+	NautilusIconCanvasItem *icon_item;
+	int x, y;
+	double worldx, worldy;
+	GdkWindow *canvas_win;
+
+	icon_item = NAUTILUS_ICON_CANVAS_ITEM (item);
+
+	canvas_win = GTK_LAYOUT (item->canvas)->bin_window;
+	if (gdk_window_at_pointer (&x, &y) == canvas_win) {
+		gnome_canvas_window_to_world (item->canvas, 
+					      x, y, 
+					      &worldx, &worldy);
+	
+		if (gnome_canvas_get_item_at (item->canvas, 
+					      worldx, 
+					      worldy) == item) {
+			g_print ("*** CANCELLING LEAVE EVENT\n");
+			return FALSE;
+		}
+	}
+
+	if (icon_item->details->is_prelit 
+	    || icon_item->details->is_highlighted_for_drop) {
+		/* When leaving, turn of the prelight state and the
+		 * higlighted for drop. The latter gets turned on
+		 * by the drag&drop motion callback.
+		 */
+		/* FIXME bugzilla.gnome.org 42473: 
+		 * We should emit our own signal here,
+		 * not one from the containe; it could hook up
+		 * to that signal and emit one of its
+		 * ownr. Doing it this way hard-codes what
+		 * "user_data" is. Also, the two signals
+		 * should be separate. The "unpreview" signal
+		 * does not have a return value.
+		 */
+		nautilus_icon_container_emit_preview_signal (
+			NAUTILUS_ICON_CONTAINER (item->canvas),
+			NAUTILUS_ICON_CANVAS_ITEM (item)->user_data,
+			FALSE);			
+		icon_item->details->is_prelit = FALSE;
+		icon_item->details->is_active = 0;			
+		icon_item->details->is_highlighted_for_drop = FALSE;
+		update_label_layouts (icon_item);
+		gnome_canvas_item_request_update (item);
+	}
+	return FALSE;
+}
 
 static int
 nautilus_icon_canvas_item_event (GnomeCanvasItem *item, GdkEvent 
*event)
@@ -1381,17 +1465,3 @@
 
 	switch (event->type) {
 	case GDK_ENTER_NOTIFY:
-		if (!icon_item->details->is_prelit) {
-			icon_item->details->is_prelit = TRUE;
-			update_label_layouts (icon_item);
-			gnome_canvas_item_request_update (item);
-			/* FIXME bugzilla.gnome.org 42473: 
-			 * We should emit our own signal here,
-			 * not one from the container; it could hook
-			 * up to that signal and emit one of its
-			 * own. Doing it this way hard-codes what
-			 * "user_data" is. Also, the two signals
-			 * should be separate. The "unpreview" signal
-			 * does not have a return value.
-			 */
-			icon_item->details->is_active = 
nautilus_icon_container_emit_preview_signal
-				(NAUTILUS_ICON_CONTAINER (item->canvas),
-				 NAUTILUS_ICON_CANVAS_ITEM (item)->user_data,
-				 TRUE);
-		}
+		handle_enter_event (item);
 		return TRUE;
 		
 	case GDK_LEAVE_NOTIFY:
-		if (icon_item->details->is_prelit 
-		    || icon_item->details->is_highlighted_for_drop) {
-			/* When leaving, turn of the prelight state and the
-			 * higlighted for drop. The latter gets turned on
-			 * by the drag&drop motion callback.
-			 */
-			/* FIXME bugzilla.gnome.org 42473: 
-			 * We should emit our own signal here,
-			 * not one from the containe; it could hook up
-			 * to that signal and emit one of its
-			 * ownr. Doing it this way hard-codes what
-			 * "user_data" is. Also, the two signals
-			 * should be separate. The "unpreview" signal
-			 * does not have a return value.
-			 */
-			nautilus_icon_container_emit_preview_signal
-				(NAUTILUS_ICON_CONTAINER (item->canvas),
-				 NAUTILUS_ICON_CANVAS_ITEM (item)->user_data,
-				 FALSE);			
-			icon_item->details->is_prelit = FALSE;
-			icon_item->details->is_active = 0;			
-			icon_item->details->is_highlighted_for_drop = FALSE;
-			update_label_layouts (icon_item);
-			gnome_canvas_item_request_update (item);
-		}
+		g_timeout_add (200, (GSourceFunc) handle_leave_event, item);
 		return TRUE;
 		
 	default:
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.297
diff -u -r1.297 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c	10 Sep 2002 21:23:59 
-0000	1.297
+++ libnautilus-private/nautilus-icon-container.c	17 Sep 2002 17:59:11 
-0000
@@ -3332,8 +3332,9 @@
 		                G_STRUCT_OFFSET (NautilusIconContainerClass,
 						 preview),
 		                NULL, NULL,
-		                nautilus_marshal_INT__POINTER_BOOLEAN,
-		                G_TYPE_INT, 2,
+		                nautilus_marshal_INT__POINTER_POINTER_BOOLEAN,
+		                G_TYPE_INT, 3,
+				G_TYPE_POINTER,
 				G_TYPE_POINTER,
 				G_TYPE_BOOLEAN);
 	signals[BAND_SELECT_STARTED]
@@ -5025,10 +5026,11 @@
 	
 	result = FALSE;
 	g_signal_emit (icon_container,
-			 signals[PREVIEW], 0,
-			 icon->data,
-			 start_flag,
-			 &result);
+		       signals[PREVIEW], 0,
+		       icon->item,
+		       icon->data,
+		       start_flag,
+		       &result);
 	
 	return result;
 }
Index: libnautilus-private/nautilus-icon-container.h
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.h,v
retrieving revision 1.71
diff -u -r1.71 nautilus-icon-container.h
--- libnautilus-private/nautilus-icon-container.h	11 Jul 2002 13:43:31 
-0000	1.71
+++ libnautilus-private/nautilus-icon-container.h	17 Sep 2002 17:59:11 
-0000
@@ -28,6 +28,7 @@
 
 #include <libgnomecanvas/gnome-canvas.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
+#include <libnautilus-private/nautilus-icon-canvas-item.h>
 
 #define NAUTILUS_ICON_CONTAINER(obj) \
 	GTK_CHECK_CAST (obj, nautilus_icon_container_get_type (), 
NautilusIconContainer)
@@ -156,6 +157,7 @@
 	void	     (* icon_stretch_ended)       (NautilusIconContainer *container,
 						   NautilusIconData *data);
 	int	     (* preview)		  (NautilusIconContainer *container,
+						   NautilusIconCanvasItem *preview_item,
 						   NautilusIconData *data,
 						   gboolean start_flag);
         void         (* icon_added)               
(NautilusIconContainer *container,
Index: libnautilus-private/nautilus-icon-factory.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-factory.c,v
retrieving revision 1.274
diff -u -r1.274 nautilus-icon-factory.c
--- libnautilus-private/nautilus-icon-factory.c	21 Aug 2002 12:07:25 
-0000	1.274
+++ libnautilus-private/nautilus-icon-factory.c	17 Sep 2002 17:59:11 
-0000
@@ -1214,1 +1214,1 @@
 	/* also, dont make thumbnails for images in the thumbnails directory 
*/  
 	if (uri == NULL) {		
 		file_size = nautilus_file_get_size (file);
-		if (eel_istr_has_prefix (mime_type, "image/")
+		if ((eel_istr_has_prefix (mime_type, "image/") 
+		     || eel_istr_has_prefix (mime_type, "video/"))
 		    && is_supported_mime_type (mime_type)
 		    && should_display_image_file_as_itself (file)) {
 			if (file_size < SELF_THUMBNAIL_SIZE_THRESHOLD && is_local
Index: libnautilus-private/nautilus-marshal.list
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-marshal.list,v
retrieving revision 1.6
diff -u -r1.6 nautilus-marshal.list
--- libnautilus-private/nautilus-marshal.list	25 Jul 2002 20:59:15 
-0000	1.6
+++ libnautilus-private/nautilus-marshal.list	17 Sep 2002 17:59:11 
-0000
@@ -3,6 +3,7 @@
 BOOLEAN:POINTER
 INT:POINTER,INT
 INT:POINTER,BOOLEAN
+INT:POINTER,POINTER,BOOLEAN
 INT:POINTER,POINTER
 POINTER:VOID
 VOID:DOUBLE
Index: libnautilus-private/nautilus-thumbnails.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-thumbnails.c,v
retrieving revision 1.44
diff -u -r1.44 nautilus-thumbnails.c
--- libnautilus-private/nautilus-thumbnails.c	7 Aug 2002 16:08:05 -0000	
1.44
+++ libnautilus-private/nautilus-thumbnails.c	17 Sep 2002 17:59:11 
-0000
@@ -30,6 +30,7 @@
 #include "nautilus-icon-factory-private.h"
 #include "nautilus-theme.h"
 #include "nautilus-thumbnails-jpeg.h"
+#include "nautilus-thumbnails-video.h"
 #include <eel/eel-gdk-pixbuf-extensions.h>
 #include <eel/eel-graphic-effects.h>
 #include <eel/eel-string.h>
@@ -907,6 +908,11 @@
 	} else if (eel_strcasecmp (info->mime_type, "image/jpeg") == 0) {
 		full_size_image = nautilus_thumbnail_load_scaled_jpeg
 			(info->image_uri, 96, 96);
+#endif
+#ifdef HAVE_GSTREAMER
+	} else if (eel_istr_has_prefix (info->mime_type, "video/")) {
+		full_size_image = nautilus_thumbnail_video_load_frame_scaled
+			(info->image_uri, 1, 96, 96);
 #endif
 	} else {
 		full_size_image = eel_gdk_pixbuf_load (info->image_uri);
Index: libnautilus-private/nautilus-thumbnails-video.c
===================================================================
RCS file: libnautilus-private/nautilus-thumbnails-video.c
diff -N libnautilus-private/nautilus-thumbnails-video.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libnautilus-private/nautilus-thumbnails-video.c	17 Sep 2002 
17:59:11 -0000
@@ -0,1 +1,3 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 
-*-
+
+   nautilus-thumbnails-video.c: Loading of video thumbnails using 
GStreamer
+ 
+   Copyright (C) 2002 Ximian, Inc.
+  
+   This program 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 2 of the
+   License, or (at your option) any later version.
+  
+   This program 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, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+  
+   Author: Alex Graveley <alex@ximian.com>
+*/
+
+#include <config.h>
+#include "nautilus-thumbnails-video.h"
+
+#ifdef HAVE_GSTREAMER
+
+#include <unistd.h>
+#include <gdk/gdkpixbuf.h>
+
+#include <gtk/gtksocket.h>
+
+#include <gst/gst.h>
+#include <gst/gconf/gconf.h>
+
+static gboolean gst_inited = FALSE;
+
+static void
+socket_show_callback (GtkWidget *widget, gpointer user_data)
+{
+	GstElement *pipeline;
+	guint idle_id;
+
+	pipeline = GST_ELEMENT (user_data);
+	gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+	g_warning ("PLAYING PIPELINE: %p", pipeline);
+
+	idle_id = g_idle_add ((GSourceFunc) gst_bin_iterate, pipeline);
+
+	g_object_set_data (G_OBJECT (pipeline),
+			   "idle-iterate-id",
+			   GINT_TO_POINTER (idle_id));
+}
+
+static void
+socket_hide_callback (GtkWidget *widget, gpointer user_data)
+{
+	GstElement *pipeline;
+
+	pipeline = GST_ELEMENT (user_data);
+	gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+	g_warning ("PAUSED PIPELINE: %p", pipeline);
+}
+
+static void
+socket_destroy_callback (GtkWidget *dead_socket, gpointer user_data)
+{
+	GstElement *pipeline;
+	guint idle_id;
+
+	pipeline = GST_ELEMENT (user_data);
+
+	idle_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pipeline),
+						      "idle-iterate-id"));
+	if (idle_id) {
+		g_source_remove (idle_id);
+	}
+
+	gst_element_set_state (pipeline, GST_STATE_NULL);
+	g_object_unref (pipeline);
+
+	g_warning ("DESTROYING PIPELINE: %p", pipeline);
+}
+
+static void
+have_xid_callback (GstElement      *video_sink, 
+		   GdkNativeWindow  xid, 
+		   gpointer         user_data)
+{
+	GtkSocket *sock;
+
+	g_warning ("GOT XID: %d\n", xid);
+
+	sock = GTK_SOCKET (user_data);
+	gtk_socket_add_id (sock, xid);
+}
+
+GtkWidget *
+nautilus_thumbnail_video_get_player (const char *uri,
+				     int         target_width,
+				     int         target_height)
+{
+	char *video_name;
+	GstElement *pipeline, *vfssrc, *plugger, *colorspace, *colorspace2;
+	GstElement *scaler, *audio_sink, *video_sink;
+	GtkWidget *socket = NULL;
+
+	if (!gst_inited) {
+		gst_init (NULL, NULL);
+		gst_inited = TRUE;
+	}
+
+	pipeline = gst_pipeline_new ("playback_pipeline");
+	vfssrc = gst_element_factory_make_or_warn ("gnomevfssrc", "source");
+	plugger = gst_element_factory_make_or_warn ("spider", "autoplugger");
+	colorspace = gst_element_factory_make_or_warn ("colorspace", 
"color1");
+	colorspace2 = gst_element_factory_make_or_warn ("colorspace", 
"color2");
+	scaler = gst_element_factory_make_or_warn ("videoscale", "scaler");
+
+	audio_sink = gst_element_factory_make_or_warn ("fakesink", 
"fakesink");
+
+	video_name = gst_gconf_get_string ("default/videosink");
+	video_name = video_name ? video_name : g_strdup ("xvideosink");
+	video_sink = gst_element_factory_make_or_warn (video_name, 
video_name);
+
+	if (vfssrc && plugger && colorspace && scaler && video_sink) {
+		gst_element_set (vfssrc, "location", uri, NULL);
+
+		gst_bin_add (GST_BIN (pipeline), vfssrc);
+		gst_bin_add (GST_BIN (pipeline), plugger);
+		gst_bin_add (GST_BIN (pipeline), audio_sink);
+		gst_bin_add (GST_BIN (pipeline), colorspace);
+		gst_bin_add (GST_BIN (pipeline), scaler);
+		gst_bin_add (GST_BIN (pipeline), colorspace2);
+		gst_bin_add (GST_BIN (pipeline), video_sink);
+
+                /* FIXME: GST Bug -- This crashes everything */
+		g_object_ref (vfssrc);
+
+		gst_element_connect (vfssrc, plugger);
+		gst_element_connect (plugger, audio_sink);
+		gst_element_connect (plugger, colorspace);
+		gst_element_connect (colorspace, scaler);
+		gst_element_connect (scaler, colorspace2);
+		gst_element_connect (colorspace2, video_sink);
+
+		gst_element_set (scaler,
+				 "height", target_height,
+				 "width",  target_width,
+				 NULL);
+
+		gst_element_set (video_sink,
+				 "height",          target_height,
+				 "width",           target_width,
+				 "need_new_window", TRUE,
+				 "toplevel",        FALSE,
+				 NULL);
+
+		socket = gtk_socket_new ();
+		g_signal_connect (G_OBJECT (socket),
+				  "show",
+				  G_CALLBACK (socket_show_callback),
+				  pipeline);
+		g_signal_connect (G_OBJECT (socket),
+				  "hide",
+				  G_CALLBACK (socket_hide_callback),
+				  pipeline);
+		g_signal_connect (G_OBJECT (socket),
+				  "destroy",
+				  G_CALLBACK (socket_destroy_callback),
+				  pipeline);
+
+		g_signal_connect (G_OBJECT (video_sink),
+				  "have_xid",
+				  G_CALLBACK (have_xid_callback),
+				  socket);
+
+		gst_element_set_state (pipeline, GST_STATE_READY);
+	}
+
+	g_free (video_name);
+
+	return socket;
+}
+
+typedef struct {
+	GdkPixbuf *data;
+	gint       frame_to_get;
+	gint       current_frame;
+} SnapshotData;
+
+static void 
+pixbuf_destroy (guchar *pixels, gpointer user_data)
+{
+	GstBuffer *buf = user_data;
+	gst_buffer_unref (buf);
+}
+
+static void
+receive_rgb_data (GstElement   *fakesink, 
+		  GstBuffer    *buf,
+		  SnapshotData *snap_data)
+{
+	GstPad *pad;
+	GstCaps *caps;
+	gint width, height, bpp;
+
+	snap_data->current_frame++;
+
+	g_print ("HANDOFF CALLED!\n");
+
+	if (snap_data->current_frame != snap_data->frame_to_get)
+		return;
+
+	pad = gst_element_get_pad (fakesink, "sink");
+	caps = gst_pad_get_caps (pad);
+	gst_caps_get_int (caps, "width", &width);
+	gst_caps_get_int (caps, "height", &height);
+	gst_caps_get_int (caps, "bpp", &bpp);
+
+	bpp = bpp ? bpp : 24;
+
+	snap_data->data = 
+		gdk_pixbuf_new_from_data (buf->data,
+					  GDK_COLORSPACE_RGB,
+					  FALSE           /*has_alpha*/,
+					  8               /*bits_per_sample*/,
+					  width           /*width*/,
+					  height          /*height*/,
+					  width * (bpp/8) /*rowstride*/,
+					  pixbuf_destroy,
+					  buf);
+	gst_buffer_ref (buf);
+}
+
+GdkPixbuf *
+nautilus_thumbnail_video_load_frame_scaled (const char *uri,
+					    int         frame,
+					    int         target_width,
+					    int         target_height)
+{	
+	GdkPixbuf *ret = NULL;
+	GstElement *pipeline, *vfssrc, *plugger, *colorspace, *fakesink;
+	GstCaps *rgb_caps;
+	SnapshotData snap_data = {
+		NULL,
+		frame == 1 ? 2 : frame, /* First frame is often invalid */
+		0
+	};
+
+	if (!gst_inited) {
+		gst_init (NULL, NULL);
+		gst_inited = TRUE;
+		g_print ("GSTREAMER INITED!\n");
+	}
+
+	pipeline = gst_pipeline_new ("snapshot_pipeline");
+	vfssrc = gst_element_factory_make_or_warn ("gnomevfssrc", "source");
+	plugger = gst_element_factory_make_or_warn ("spider", "autoplugger");
+	colorspace = gst_element_factory_make_or_warn ("colorspace", 
"convert");
+	fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
+
+	if (pipeline && vfssrc && plugger && fakesink && colorspace) {
+		gst_element_set (vfssrc, "location", uri, NULL);
+
+		gst_bin_add (GST_BIN (pipeline), vfssrc);
+		gst_bin_add (GST_BIN (pipeline), plugger);
+		gst_bin_add (GST_BIN (pipeline), colorspace);
+		gst_bin_add (GST_BIN (pipeline), fakesink);
+
+		gst_element_connect (vfssrc, plugger);
+		gst_element_connect (plugger, colorspace);
+		
+		rgb_caps = 
+			GST_CAPS_NEW (
+				"fake_rgb_sink",
+				"video/raw",
+				"format", GST_PROPS_FOURCC (
+						   GST_STR_FOURCC ("RGB ")),
+				"red_mask",   GST_PROPS_INT (0xFF0000),
+				"green_mask", GST_PROPS_INT (0x00FF00),
+				"blue_mask",  GST_PROPS_INT (0x0000FF),
+				"bpp",        GST_PROPS_INT (24) 
+				);
+		gst_element_connect_filtered (colorspace, fakesink, rgb_caps);
+
+		g_signal_connect (fakesink, 
+				  "handoff", 
+				  G_CALLBACK (receive_rgb_data),
+				  &snap_data);
+		
+		gst_element_set_state (pipeline, GST_STATE_PLAYING);
+		g_print ("GSTREAMER PLAYING!\n");
+
+		while (gst_bin_iterate (GST_BIN (pipeline))) {
+			if (snap_data.data != NULL) {
+				ret = snap_data.data;
+				break;
+			}
+		}
+		gst_element_set_state (pipeline, GST_STATE_NULL);
+
+		g_print ("GSTREAMER DONE!\n");
+
+                /* FIXME: GST Bug -- This crashes everything */
+		g_object_ref (vfssrc);
+
+		g_object_unref (pipeline);
+	} else {
+		if (vfssrc)
+			g_object_unref (vfssrc);
+		if (plugger)
+			g_object_unref (plugger);
+		if (colorspace)
+			g_object_unref (colorspace);
+		if (fakesink)
+			g_object_unref (fakesink);
+	}
+
+	return ret;
+}
+
+#else  /* HAVE_GSTREAMER */
+
+GtkWidget *
+nautilus_thumbnail_video_get_player (const char *uri,
+				     int         target_width,
+				     int         target_heigh)
+{
+	return NULL;
+}
+
+GdkPixbuf *
+nautilus_thumbnail_video_load_frame_scaled (const char *uri,
+					    int         frame,
+					    int         target_width,
+					    int         target_height)
+{	
+	return NULL;
+}
+
+#endif /* HAVE_GSTREAMER */
Index: libnautilus-private/nautilus-thumbnails-video.h
===================================================================
RCS file: libnautilus-private/nautilus-thumbnails-video.h
diff -N libnautilus-private/nautilus-thumbnails-video.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libnautilus-private/nautilus-thumbnails-video.h	17 Sep 2002 
17:59:11 -0000
@@ -0,1 +1,3 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 
-*-
+
+   nautilus-thumbnails-video.h: Loading of video thumbnails using 
GStreamer
+ 
+   Copyright (C) 2002 Ximian, Inc.
+  
+   This program 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 2 of the
+   License, or (at your option) any later version.
+  
+   This program 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, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+  
+   Author: Alex Graveley <alex@ximian.com>
+*/
+
+#ifndef NAUTILUS_THUMBNAILS_VIDEO_H
+#define NAUTILUS_THUMBNAILS_VIDEO_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkwidget.h>
+
+GdkPixbuf *nautilus_thumbnail_video_load_frame_scaled (const char 
*uri,
+						       int         frame,
+						       int         target_width,
+						       int         target_heigh);
+
+GtkWidget *nautilus_thumbnail_video_get_player (const char *uri,
+						int         target_width,
+						int         target_height);
+
+#endif /* NAUTILUS_THUMBNAILS_VIDEO_H */
Index: src/file-manager/fm-icon-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
retrieving revision 1.267
diff -u -r1.267 fm-icon-view.c
--- src/file-manager/fm-icon-view.c	25 Jul 2002 20:59:16 -0000	1.267
+++ src/file-manager/fm-icon-view.c	17 Sep 2002 17:59:11 -0000
@@ -48,6 +48,8 @@
 #include <libgnome/gnome-config.h>
 #include <libgnome/gnome-desktop-item.h>
 #include <libgnome/gnome-macros.h>
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-widget.h>
 #include <libgnomevfs/gnome-vfs-ops.h>
 #include <libgnomevfs/gnome-vfs-async-ops.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
@@ -61,11 +63,14 @@
 #include <libnautilus-private/nautilus-file-utilities.h>
 #include <libnautilus-private/nautilus-global-preferences.h>
 #include <libnautilus-private/nautilus-icon-container.h>
+#include <libnautilus-private/nautilus-icon-canvas-item.h>
 #include <libnautilus-private/nautilus-icon-dnd.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
 #include <libnautilus-private/nautilus-link.h>
 #include <libnautilus-private/nautilus-metadata.h>
 #include <libnautilus-private/nautilus-sound.h>
+#include <libnautilus-private/nautilus-theme.h>
+#include <libnautilus-private/nautilus-thumbnails-video.h>
 #include <libnautilus/nautilus-bonobo-ui.h>
 #include <libnautilus/nautilus-clipboard.h>
 #include <locale.h>
@@ -130,6 +135,7 @@
 	BonoboUIComponent *ui;
 	
 	NautilusAudioPlayerData *audio_player_data;
+	GnomeCanvasItem *video_player_data;
 	int audio_preview_timeout;
 	NautilusFile *audio_preview_file;
 };
@@ -1506,1 +1512,1 @@
 /* here's the timer task that actually plays the file using mpg123, 
ogg123 or play. */
 /* FIXME bugzilla.gnome.org 41258: we should get the application from 
our mime-type stuff */
 static gboolean
-play_file (gpointer callback_data)
+play_audio_file (gpointer callback_data)
 {
 #if USE_OLD_AUDIO_PREVIEW	
 	NautilusFile *file;
@@ -1655,4 +1661,3 @@
 	if (start_flag) {
 		icon_view->details->audio_preview_file = file;
 #if USE_OLD_AUDIO_PREVIEW			
-		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_file, icon_view);
+		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_audio_file, icon_view);
 #else
 		/* FIXME: Need to kill the existing timeout if there is one? */
-		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_file, icon_view);
+		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_audio_file, icon_view);
 #endif
 	}
 }
 
 static gboolean
-should_preview_sound (NautilusFile *file)
+show_video_player (gpointer user_data)
+{
+	GnomeCanvasItem *video_item;
+
+	video_item = GNOME_CANVAS_ITEM (user_data);
+
+	gnome_canvas_item_show (video_item);
+	gtk_widget_show (GNOME_CANVAS_WIDGET (video_item)->widget);
+
+	return FALSE;
+}
+
+static void
+adjust_rect_for_frame_offsets (ArtDRect *rect)
+{
+	gboolean got_frame_offsets;
+	char *frame_offset_str;
+	int left_offset, top_offset, right_offset, bottom_offset;
+	char c;
+
+	got_frame_offsets = FALSE;
+	frame_offset_str = nautilus_theme_get_theme_data ("thumbnails", 
+							  "FRAME_OFFSETS");
+	if (frame_offset_str != NULL) {
+		if (sscanf (frame_offset_str, 
+			    " %d , %d , %d , %d %c",
+			    &left_offset, 
+			    &top_offset, 
+			    &right_offset, 
+			    &bottom_offset, 
+			    &c) == 4) {
+			got_frame_offsets = TRUE;
+		}
+		g_free (frame_offset_str);
+	}
+	if (!got_frame_offsets) {
+		/* 
+		 * use nominal values since the info in the theme couldn't be
+		 * found 
+		 */
+		left_offset = 3;
+		top_offset = 3;
+		right_offset = 6;
+		bottom_offset = 6;
+	}
+
+	rect->x0 += left_offset;
+	rect->y0 += top_offset;
+	rect->x1 -= right_offset;
+	rect->y1 -= bottom_offset;
+}
+
+static void
+preview_video (FMIconView             *icon_view, 
+	       NautilusIconContainer  *container,
+	       NautilusIconCanvasItem *item,
+	       NautilusFile           *file, 
+	       gboolean                start_flag)
+{
+	ArtDRect rect;
+	GtkWidget *video_player;
+	GnomeCanvasItem *video_item;
+	gchar *file_uri;
+        int pinned_level;
+	double pixels_per_unit, width, height;
+
+	if (icon_view->details->video_player_data != NULL) {
+		g_warning ("STOPPING CURRENT PLAYBACK!\n");
+
+		video_item = icon_view->details->video_player_data;
+		video_player = GNOME_CANVAS_WIDGET (video_item)->widget;
+
+		gnome_canvas_item_hide (video_item);
+		gtk_widget_hide (video_player);
+
+		gtk_object_destroy (GTK_OBJECT (video_player));
+		icon_view->details->video_player_data = NULL;
+	}
+
+	if (icon_view->details->audio_preview_timeout != 0) {
+		gtk_timeout_remove (icon_view->details->audio_preview_timeout);
+		icon_view->details->audio_preview_timeout = 0;
+	}
+
+	if (!start_flag) {
+		return;
+	}
+
+	rect = nautilus_icon_canvas_item_get_icon_rectangle (item);
+	adjust_rect_for_frame_offsets (&rect);
+
+	pinned_level = nautilus_icon_container_get_zoom_level (container);
+	pixels_per_unit = (double) 
+		nautilus_get_icon_size_for_zoom_level (pinned_level)
+		/ NAUTILUS_ICON_SIZE_STANDARD;
+
+	width  = ((int) (rect.x1 - rect.x0)) * pixels_per_unit;
+	height = ((int) (rect.y1 - rect.y0)) * pixels_per_unit;
+
+	file_uri = nautilus_file_get_uri (file);
+	video_player = nautilus_thumbnail_video_get_player (file_uri,
+							    width,
+							    height);
+	if (video_player != NULL) {
+		video_item = 
+			gnome_canvas_item_new (
+				gnome_canvas_root (GNOME_CANVAS (container)),
+				gnome_canvas_widget_get_type (),
+				"widget",      video_player,
+				"x",           rect.x0,
+				"y",           rect.y0,
+				"width",       width,
+				"height",      height,
+				"size_pixels", TRUE,
+				NULL);
+		if (video_item != NULL) {
+			icon_view->details->video_player_data = video_item;
+			icon_view->details->audio_preview_timeout = 
+				gtk_timeout_add (1000, 
+						 show_video_player, 
+						 video_item);
+		}
+	}
+
+	g_free (file_uri);
+}
+
+static gboolean
+should_preview_media (NautilusFile *file)
 {
 	/* Check gnome config sound preference */
 	if (!gnome_esd_enabled_auto_value) {
@@ -1685,6 +1819,7 @@
 
 static int
 icon_container_preview_callback (NautilusIconContainer *container,
+				 NautilusIconCanvasItem *item,
 				 NautilusFile *file,
 				 gboolean start_flag,
 				 FMIconView *icon_view)
@@ -1696,7 +1831,7 @@
 	
 	/* preview files based on the mime_type. */
 	/* at first, we just handle sounds */
-	if (should_preview_sound (file)) {
+	if (should_preview_media (file)) {
 		mime_type = nautilus_file_get_mime_type (file);
 
 		if ((eel_istr_has_prefix (mime_type, "audio/")
@@ -1706,7 +1841,16 @@
 		    && nautilus_sound_can_play_sound ()) {
 			result = 1;
 			preview_audio (icon_view, file, start_flag);
-		}	
+		}
+		else if (eel_istr_has_prefix (mime_type, "video/")) {
+			result = 1;
+			preview_video (icon_view, 
+				       container, 
+				       item, 
+				       file, 
+				       start_flag);
+		}
+	
 		g_free (mime_type);
 	}
 	



Forwarded Message
Subject:	gstreamer nautilus thumbnailing patch
From:	"Alex Graveley" <alex@ximian.com>
To:	thomas@urgent.rug.ac.be
Date:	11 Sep 2002 16:54:44 -0400



Plain Text Attachment [ Download File ]


-- 
 on the canvass of life, incompetence is my paintbrush.


Index: acconfig.h
===================================================================
RCS file: /cvs/gnome/nautilus/acconfig.h,v
retrieving revision 1.29
diff -u -r1.29 acconfig.h
--- acconfig.h	22 May 2002 21:34:18 -0000	1.29
+++ acconfig.h	11 Sep 2002 21:02:38 -0000
@@ -8,6 +8,7 @@
 #undef HAVE_LIBBZ2
 #undef HAVE_LIBJPEG
 #undef HAVE_MEDUSA
+#undef HAVE_GSTREAMER
 #undef HAVE_STPCPY
 #undef bzclose
 #undef bzCompress
Index: configure.in
===================================================================
RCS file: /cvs/gnome/nautilus/configure.in,v
retrieving revision 1.467
diff -u -r1.467 configure.in
--- configure.in	28 Aug 2002 16:41:47 -0000	1.467
+++ configure.in	11 Sep 2002 21:02:38 -0000
@@ -14,6 +14,7 @@
 GNOME_REQUIRED=2.0.1
 GNOME_UI_REQUIRED=2.0
 GNOME_VFS_REQUIRED=1.9
+GSTREAMER_REQUIRED=0.4
 GTK_REQUIRED=2.0.5
 MEDUSA_REQUIRED=0.5.1
 RSVG_REQUIRED=2.0.1
@@ -188,2 +189,2 @@
 
 dnl 
==========================================================================
 
+dnl gstreamer checking
+
+AC_MSG_CHECKING(for GStreamer)
+
+PKG_CHECK_MODULES(GSTREAMER, 
+		  gstreamer >= $GSTREAMER_REQUIRED \
+		  gstreamer-libs >= $GSTREAMER_REQUIRED, 
+		  have_gstreamer=yes, 
+		  have_gstreamer=no)
+if test "x$have_gstreamer" = "xyes"; then
+  AC_DEFINE(HAVE_GSTREAMER,1)
+  LIBGST_EXTRAS="-lgstcontrol -lgstgconf"
+  EXTRA_CORE_MODULES="$EXTRA_CORE_MODULES gstreamer gstreamer-libs 
gstreamer-player"
+fi
+
+dnl 
==========================================================================
+
 dnl libjpeg
 
   if test -z "$LIBJPEG"; then
@@ -270,1 +288,1 @@
 CORE_MODULES="eel-2.0 librsvg-2.0 bonobo-activation-2.0 libbonobo-2.0 
libbonoboui-2.0 esound gnome-desktop-2.0 $EXTRA_CORE_MODULES"
 CORE_CFLAGS="`$PKG_CONFIG --cflags $CORE_MODULES` $x_cflags"
 AC_SUBST(CORE_CFLAGS)
-CORE_LIBS="`$PKG_CONFIG --libs $CORE_MODULES` $CDDA_LIBS $LIBJPEG 
$x_libs"
+CORE_LIBS="`$PKG_CONFIG --libs $CORE_MODULES` $CDDA_LIBS $LIBJPEG 
$LIBGST_EXTRAS $x_libs"
 AC_SUBST(CORE_LIBS)
 CORE_IDL_INCLUDES="`$PKG_CONFIG --variable=idldir $CORE_MODULES | 
$srcdir/add-include-prefix`"
 AC_SUBST(CORE_IDL_INCLUDES)
Index: libnautilus-private/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/Makefile.am,v
retrieving revision 1.219
diff -u -r1.219 Makefile.am
--- libnautilus-private/Makefile.am	26 Jul 2002 22:57:24 -0000	1.219
+++ libnautilus-private/Makefile.am	11 Sep 2002 21:02:38 -0000
@@ -141,6 +141,8 @@
 	nautilus-theme.h \
 	nautilus-thumbnails-jpeg.c \
 	nautilus-thumbnails-jpeg.h \
+	nautilus-thumbnails-video.c \
+	nautilus-thumbnails-video.h \
 	nautilus-thumbnails.c \
 	nautilus-thumbnails.h \
 	nautilus-trash-directory.c \
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.297
diff -u -r1.297 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c	10 Sep 2002 21:23:59 
-0000	1.297
+++ libnautilus-private/nautilus-icon-container.c	11 Sep 2002 21:02:39 
-0000
@@ -3332,8 +3332,9 @@
 		                G_STRUCT_OFFSET (NautilusIconContainerClass,
 						 preview),
 		                NULL, NULL,
-		                nautilus_marshal_INT__POINTER_BOOLEAN,
-		                G_TYPE_INT, 2,
+		                nautilus_marshal_INT__POINTER_POINTER_BOOLEAN,
+		                G_TYPE_INT, 3,
+				G_TYPE_POINTER,
 				G_TYPE_POINTER,
 				G_TYPE_BOOLEAN);
 	signals[BAND_SELECT_STARTED]
@@ -5025,10 +5026,11 @@
 	
 	result = FALSE;
 	g_signal_emit (icon_container,
-			 signals[PREVIEW], 0,
-			 icon->data,
-			 start_flag,
-			 &result);
+		       signals[PREVIEW], 0,
+		       icon->item,
+		       icon->data,
+		       start_flag,
+		       &result);
 	
 	return result;
 }
Index: libnautilus-private/nautilus-icon-container.h
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.h,v
retrieving revision 1.71
diff -u -r1.71 nautilus-icon-container.h
--- libnautilus-private/nautilus-icon-container.h	11 Jul 2002 13:43:31 
-0000	1.71
+++ libnautilus-private/nautilus-icon-container.h	11 Sep 2002 21:02:39 
-0000
@@ -28,6 +28,7 @@
 
 #include <libgnomecanvas/gnome-canvas.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
+#include <libnautilus-private/nautilus-icon-canvas-item.h>
 
 #define NAUTILUS_ICON_CONTAINER(obj) \
 	GTK_CHECK_CAST (obj, nautilus_icon_container_get_type (), 
NautilusIconContainer)
@@ -156,1 +157,1 @@
 	void	     (* icon_stretch_ended)       (NautilusIconContainer 
*container,
 						   NautilusIconData *data);
 	int	     (* preview)		  (NautilusIconContainer *container,
+						   NautilusIconCanvasItem *preview_item,
 						   NautilusIconData *data,
 						   gboolean start_flag);
         void         (* icon_added)               
(NautilusIconContainer *container,
Index: libnautilus-private/nautilus-icon-factory.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-icon-factory.c,v
retrieving revision 1.274
diff -u -r1.274 nautilus-icon-factory.c
--- libnautilus-private/nautilus-icon-factory.c	21 Aug 2002 12:07:25 
-0000	1.274
+++ libnautilus-private/nautilus-icon-factory.c	11 Sep 2002 21:02:40 
-0000
@@ -1214,1 +1214,1 @@
 	/* also, dont make thumbnails for images in the thumbnails directory 
*/  
 	if (uri == NULL) {		
 		file_size = nautilus_file_get_size (file);
-		if (eel_istr_has_prefix (mime_type, "image/")
+		if ((eel_istr_has_prefix (mime_type, "image/") 
+		     || eel_istr_has_prefix (mime_type, "video/"))
 		    && is_supported_mime_type (mime_type)
 		    && should_display_image_file_as_itself (file)) {
 			if (file_size < SELF_THUMBNAIL_SIZE_THRESHOLD && is_local
Index: libnautilus-private/nautilus-marshal.list
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-marshal.list,v
retrieving revision 1.6
diff -u -r1.6 nautilus-marshal.list
--- libnautilus-private/nautilus-marshal.list	25 Jul 2002 20:59:15 
-0000	1.6
+++ libnautilus-private/nautilus-marshal.list	11 Sep 2002 21:02:40 
-0000
@@ -3,6 +3,7 @@
 BOOLEAN:POINTER
 INT:POINTER,INT
 INT:POINTER,BOOLEAN
+INT:POINTER,POINTER,BOOLEAN
 INT:POINTER,POINTER
 POINTER:VOID
 VOID:DOUBLE
Index: libnautilus-private/nautilus-thumbnails.c
===================================================================
RCS file: 
/cvs/gnome/nautilus/libnautilus-private/nautilus-thumbnails.c,v
retrieving revision 1.44
diff -u -r1.44 nautilus-thumbnails.c
--- libnautilus-private/nautilus-thumbnails.c	7 Aug 2002 16:08:05 -0000	
1.44
+++ libnautilus-private/nautilus-thumbnails.c	11 Sep 2002 21:02:40 
-0000
@@ -30,6 +30,7 @@
 #include "nautilus-icon-factory-private.h"
 #include "nautilus-theme.h"
 #include "nautilus-thumbnails-jpeg.h"
+#include "nautilus-thumbnails-video.h"
 #include <eel/eel-gdk-pixbuf-extensions.h>
 #include <eel/eel-graphic-effects.h>
 #include <eel/eel-string.h>
@@ -907,6 +908,11 @@
 	} else if (eel_strcasecmp (info->mime_type, "image/jpeg") == 0) {
 		full_size_image = nautilus_thumbnail_load_scaled_jpeg
 			(info->image_uri, 96, 96);
+#endif
+#ifdef HAVE_GSTREAMER
+	} else if (eel_istr_has_prefix (info->mime_type, "video/")) {
+		full_size_image = nautilus_thumbnail_video_load_frame_scaled
+			(info->image_uri, 1, 96, 96);
 #endif
 	} else {
 		full_size_image = eel_gdk_pixbuf_load (info->image_uri);
Index: libnautilus-private/nautilus-thumbnails-video.c
===================================================================
RCS file: libnautilus-private/nautilus-thumbnails-video.c
diff -N libnautilus-private/nautilus-thumbnails-video.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libnautilus-private/nautilus-thumbnails-video.c	11 Sep 2002 
21:02:40 -0000
@@ -0,1 +1,3 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 
-*-
+
+   nautilus-thumbnails-video.c: Loading of video thumbnails using 
GStreamer
+ 
+   Copyright (C) 2002 Ximian, Inc.
+  
+   This program 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 2 of the
+   License, or (at your option) any later version.
+  
+   This program 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, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+  
+   Author: Alex Graveley <alex@ximian.com>
+*/
+
+#include <config.h>
+#include "nautilus-thumbnails-video.h"
+
+#ifdef HAVE_GSTREAMER
+
+#include <unistd.h>
+#include <gdk/gdkpixbuf.h>
+
+#include <gtk/gtksocket.h>
+
+#include <gst/gst.h>
+#include <gst/gconf/gconf.h>
+
+static gboolean gst_inited = FALSE;
+
+static void
+socket_show_callback (GtkWidget *widget, gpointer user_data)
+{
+	GstElement *pipeline;
+
+	pipeline = GST_ELEMENT (user_data);
+	gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+	g_warning ("PLAYING PIPELINE: %p", pipeline);
+}
+
+static void
+socket_hide_callback (GtkWidget *widget, gpointer user_data)
+{
+	GstElement *pipeline;
+
+	pipeline = GST_ELEMENT (user_data);
+	gst_element_set_state (pipeline, GST_STATE_NULL);
+
+	g_warning ("STOPPING PIPELINE: %p", pipeline);
+}
+
+static void
+socket_destroy_callback (gpointer user_data, GtkWidget *dead_socket)
+{
+	GstElement *pipeline;
+
+	pipeline = GST_ELEMENT (user_data);
+	g_object_unref (pipeline);
+
+	g_warning ("DESTROYING PIPELINE: %p", pipeline);
+}
+
+static void
+have_xid_callback (GstElement      *video_sink, 
+		   GdkNativeWindow  xid, 
+		   gpointer         user_data)
+{
+	GtkSocket *sock;
+
+	g_warning ("GOT XID: %d\n", xid);
+
+	sock = GTK_SOCKET (user_data);
+	gtk_socket_add_id (sock, xid);
+}
+
+GtkWidget *
+nautilus_thumbnail_video_get_player (const char *uri,
+				     int         target_width,
+				     int         target_height)
+{
+	char *video_name;
+	GstElement *thread, *pipeline, *vfssrc, *plugger, *colorspace;
+	GstElement *audio_sink, *video_sink;
+	GtkWidget *socket = NULL;
+
+	if (!gst_inited) {
+		gst_init (NULL, NULL);
+		gst_inited = TRUE;
+	}
+
+	thread = gst_thread_new ("playback_thread");
+
+	pipeline = gst_pipeline_new ("playback_pipeline");
+	vfssrc = gst_element_factory_make_or_warn ("gnomevfssrc", "source");
+	plugger = gst_element_factory_make_or_warn ("spider", "autoplugger");
+	colorspace = gst_element_factory_make_or_warn ("colorspace", 
"convert");
+	audio_sink = gst_element_factory_make_or_warn ("fakesink", 
"fakesink");
+
+	video_name = gst_gconf_get_string ("default/videosink");
+	video_name = video_name ? video_name : g_strdup ("xvideosink");
+	video_sink = gst_element_factory_make_or_warn (video_name, 
video_name);
+
+	if (pipeline && vfssrc && plugger && colorspace && video_sink) {
+		gst_element_set (vfssrc, "location", uri, NULL);
+
+		gst_bin_add (GST_BIN (pipeline), vfssrc);
+		gst_bin_add (GST_BIN (pipeline), plugger);
+		gst_bin_add (GST_BIN (pipeline), colorspace);
+		gst_bin_add (GST_BIN (pipeline), audio_sink);
+		gst_bin_add (GST_BIN (pipeline), video_sink);
+
+		gst_element_connect (vfssrc, plugger);
+		gst_element_connect (plugger, colorspace);
+		gst_element_connect (plugger, audio_sink);
+		gst_element_connect (colorspace, video_sink);
+
+		gst_bin_add (GST_BIN (thread), pipeline);
+
+		gst_element_set (video_sink,
+				 "height",          target_height,
+				 "width",           target_width,
+				 "need_new_window", TRUE,
+				 "toplevel",        FALSE,
+				 "disable_xv",      TRUE,
+				 NULL);
+
+		socket = gtk_socket_new ();
+		g_signal_connect (G_OBJECT (socket),
+				  "show",
+				  G_CALLBACK (socket_show_callback),
+				  thread);
+		g_signal_connect (G_OBJECT (socket),
+				  "hide",
+				  G_CALLBACK (socket_hide_callback),
+				  thread);
+		g_object_weak_ref (G_OBJECT (socket),
+				   (GWeakNotify) socket_destroy_callback,
+				   thread);
+
+		g_signal_connect (G_OBJECT (video_sink),
+				  "have_xid",
+				  G_CALLBACK (have_xid_callback),
+				  socket);
+
+		gst_element_set_state (thread, GST_STATE_READY);
+	}
+
+	g_free (video_name);
+
+	return socket;
+}
+
+typedef struct {
+	GdkPixbuf *data;
+	gint       frame_to_get;
+	gint       current_frame;
+} SnapshotData;
+
+static void 
+pixbuf_destroy (guchar *pixels, gpointer user_data)
+{
+	GstBuffer *buf = user_data;
+	gst_buffer_unref (buf);
+}
+
+static void
+receive_rgb_data (GstElement   *fakesink, 
+		  GstBuffer    *buf,
+		  SnapshotData *snap_data)
+{
+	GstPad *pad;
+	GstCaps *caps;
+	gint width, height, bpp;
+
+	snap_data->current_frame++;
+
+	g_print ("HANDOFF CALLED!\n");
+
+	if (snap_data->current_frame != snap_data->frame_to_get)
+		return;
+
+	pad = gst_element_get_pad (fakesink, "sink");
+	caps = gst_pad_get_caps (pad);
+	gst_caps_get_int (caps, "width", &width);
+	gst_caps_get_int (caps, "height", &height);
+	gst_caps_get_int (caps, "bpp", &bpp);
+
+	bpp = bpp ? bpp : 24;
+
+	snap_data->data = 
+		gdk_pixbuf_new_from_data (buf->data,
+					  GDK_COLORSPACE_RGB,
+					  FALSE           /*has_alpha*/,
+					  8               /*bits_per_sample*/,
+					  width           /*width*/,
+					  height          /*height*/,
+					  width * (bpp/8) /*rowstride*/,
+					  pixbuf_destroy,
+					  buf);
+	gst_buffer_ref (buf);
+}
+
+GdkPixbuf *
+nautilus_thumbnail_video_load_frame_scaled (const char *uri,
+					    int         frame,
+					    int         target_width,
+					    int         target_height)
+{	
+	GdkPixbuf *ret = NULL;
+	GstElement *pipeline, *vfssrc, *plugger, *colorspace, *fakesink;
+	GstCaps *rgb_caps;
+	SnapshotData snap_data = {
+		NULL,
+		frame == 1 ? 2 : frame, /* First frame is often invalid */
+		0
+	};
+
+	if (!gst_inited) {
+		gst_init (NULL, NULL);
+		gst_inited = TRUE;
+		g_print ("GSTREAMER INITED!\n");
+	}
+
+	pipeline = gst_pipeline_new ("snapshot_pipeline");
+	vfssrc = gst_element_factory_make_or_warn ("gnomevfssrc", "source");
+	plugger = gst_element_factory_make_or_warn ("spider", "autoplugger");
+	colorspace = gst_element_factory_make_or_warn ("colorspace", 
"convert");
+	fakesink = gst_element_factory_make_or_warn ("fakesink", "sink");
+
+	if (pipeline && vfssrc && plugger && fakesink && colorspace) {
+		gst_element_set (vfssrc, "location", uri, NULL);
+
+		gst_bin_add (GST_BIN (pipeline), vfssrc);
+		gst_bin_add (GST_BIN (pipeline), plugger);
+		gst_bin_add (GST_BIN (pipeline), colorspace);
+		gst_bin_add (GST_BIN (pipeline), fakesink);
+
+		gst_element_connect (vfssrc, plugger);
+		gst_element_connect (plugger, colorspace);
+		
+		rgb_caps = 
+			GST_CAPS_NEW (
+				"fake_rgb_sink",
+				"video/raw",
+				"format", GST_PROPS_FOURCC (
+						   GST_STR_FOURCC ("RGB ")),
+				"red_mask",   GST_PROPS_INT (0xFF0000),
+				"green_mask", GST_PROPS_INT (0x00FF00),
+				"blue_mask",  GST_PROPS_INT (0x0000FF),
+				"bpp",        GST_PROPS_INT (24) 
+				);
+		gst_element_connect_filtered (colorspace, fakesink, rgb_caps);
+
+		g_signal_connect (fakesink, 
+				  "handoff", 
+				  G_CALLBACK (receive_rgb_data),
+				  &snap_data);
+		
+		gst_element_set_state (pipeline, GST_STATE_PLAYING);
+		g_print ("GSTREAMER PLAYING!\n");
+
+		while (gst_bin_iterate (GST_BIN (pipeline))) {
+			if (snap_data.data != NULL) {
+				ret = snap_data.data;
+				break;
+			}
+		}
+		gst_element_set_state (pipeline, GST_STATE_NULL);
+
+		g_print ("GSTREAMER DONE!\n");
+
+		gst_element_disconnect (vfssrc, plugger);
+		gst_element_disconnect (plugger, colorspace);
+		gst_element_disconnect (colorspace, fakesink);
+
+                /* FIXME: GST Bug -- This crashes everything */
+		/* gst_bin_remove (GST_BIN (pipeline), vfssrc); */
+		g_object_ref (vfssrc);
+
+		g_print ("GSTREAMER CLEANING UP!\n");
+
+                gst_bin_remove (GST_BIN (pipeline), plugger);
+                gst_bin_remove (GST_BIN (pipeline), colorspace);
+                gst_bin_remove (GST_BIN (pipeline), fakesink);
+
+		g_object_unref (pipeline);
+	} else {
+		if (vfssrc)
+			g_object_unref (vfssrc);
+		if (plugger)
+			g_object_unref (plugger);
+		if (colorspace)
+			g_object_unref (colorspace);
+		if (fakesink)
+			g_object_unref (fakesink);
+	}
+
+	return ret;
+}
+
+#else  /* HAVE_GSTREAMER */
+
+GtkWidget *
+nautilus_thumbnail_video_get_player (const char *uri,
+				     int         target_width,
+				     int         target_heigh)
+{
+	return NULL;
+}
+
+GdkPixbuf *
+nautilus_thumbnail_video_load_frame_scaled (const char *uri,
+					    int         frame,
+					    int         target_width,
+					    int         target_height)
+{	
+	return NULL;
+}
+
+#endif /* HAVE_GSTREAMER */
Index: libnautilus-private/nautilus-thumbnails-video.h
===================================================================
RCS file: libnautilus-private/nautilus-thumbnails-video.h
diff -N libnautilus-private/nautilus-thumbnails-video.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libnautilus-private/nautilus-thumbnails-video.h	11 Sep 2002 
21:02:40 -0000
@@ -0,1 +1,3 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 
-*-
+
+   nautilus-thumbnails-video.h: Loading of video thumbnails using 
GStreamer
+ 
+   Copyright (C) 2002 Ximian, Inc.
+  
+   This program 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 2 of the
+   License, or (at your option) any later version.
+  
+   This program 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, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+  
+   Author: Alex Graveley <alex@ximian.com>
+*/
+
+#ifndef NAUTILUS_THUMBNAILS_VIDEO_H
+#define NAUTILUS_THUMBNAILS_VIDEO_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtkwidget.h>
+
+GdkPixbuf *nautilus_thumbnail_video_load_frame_scaled (const char 
*uri,
+						       int         frame,
+						       int         target_width,
+						       int         target_heigh);
+
+GtkWidget *nautilus_thumbnail_video_get_player (const char *uri,
+						int         target_width,
+						int         target_height);
+
+#endif /* NAUTILUS_THUMBNAILS_VIDEO_H */
Index: src/file-manager/fm-icon-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
retrieving revision 1.267
diff -u -r1.267 fm-icon-view.c
--- src/file-manager/fm-icon-view.c	25 Jul 2002 20:59:16 -0000	1.267
+++ src/file-manager/fm-icon-view.c	11 Sep 2002 21:02:40 -0000
@@ -48,6 +48,8 @@
 #include <libgnome/gnome-config.h>
 #include <libgnome/gnome-desktop-item.h>
 #include <libgnome/gnome-macros.h>
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-widget.h>
 #include <libgnomevfs/gnome-vfs-ops.h>
 #include <libgnomevfs/gnome-vfs-async-ops.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
@@ -61,11 +63,13 @@
 #include <libnautilus-private/nautilus-file-utilities.h>
 #include <libnautilus-private/nautilus-global-preferences.h>
 #include <libnautilus-private/nautilus-icon-container.h>
+#include <libnautilus-private/nautilus-icon-canvas-item.h>
 #include <libnautilus-private/nautilus-icon-dnd.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
 #include <libnautilus-private/nautilus-link.h>
 #include <libnautilus-private/nautilus-metadata.h>
 #include <libnautilus-private/nautilus-sound.h>
+#include <libnautilus-private/nautilus-thumbnails-video.h>
 #include <libnautilus/nautilus-bonobo-ui.h>
 #include <libnautilus/nautilus-clipboard.h>
 #include <locale.h>
@@ -1506,1 +1510,1 @@
 /* here's the timer task that actually plays the file using mpg123, 
ogg123 or play. */
 /* FIXME bugzilla.gnome.org 41258: we should get the application from 
our mime-type stuff */
 static gboolean
-play_file (gpointer callback_data)
+play_audio_file (gpointer callback_data)
 {
 #if USE_OLD_AUDIO_PREVIEW	
 	NautilusFile *file;
@@ -1655,4 +1659,3 @@
 	if (start_flag) {
 		icon_view->details->audio_preview_file = file;
 #if USE_OLD_AUDIO_PREVIEW			
-		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_file, icon_view);
+		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_audio_file, icon_view);
 #else
 		/* FIXME: Need to kill the existing timeout if there is one? */
-		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_file, icon_view);
+		icon_view->details->audio_preview_timeout = gtk_timeout_add (1000, 
play_audio_file, icon_view);
 #endif
 	}
 }
 
+static void
+preview_video (FMIconView             *icon_view, 
+	       NautilusIconContainer  *container,
+	       NautilusIconCanvasItem *item,
+	       NautilusFile           *file, 
+	       gboolean                start_flag)
+{
+	ArtDRect rect;
+	GtkWidget *video_player;
+	GnomeCanvasItem *video_item;
+	gchar *file_uri;
+
+	rect = nautilus_icon_canvas_item_get_icon_rectangle (item);
+
+	file_uri = nautilus_file_get_uri (file);
+	video_player = nautilus_thumbnail_video_get_player (file_uri,
+							    rect.x1 - rect.x0,
+							    rect.y1 - rect.y0);
+	if (video_player) {
+		video_item = 
+			gnome_canvas_item_new (
+				gnome_canvas_root (GNOME_CANVAS (container)),
+				gnome_canvas_widget_get_type (),
+				"widget",      video_player,
+				"x",           rect.x0,
+				"y",           rect.y0,
+				"width",       rect.x1 - rect.x0,
+				"height",      rect.y1 - rect.y0,
+				"size_pixels", TRUE,
+				NULL);
+		if (video_item) {
+			gnome_canvas_item_show (video_item);
+			gtk_widget_show (video_player);
+		}
+	}
+
+	g_free (file_uri);
+}
+
 static gboolean
-should_preview_sound (NautilusFile *file)
+should_preview_media (NautilusFile *file)
 {
 	/* Check gnome config sound preference */
 	if (!gnome_esd_enabled_auto_value) {
@@ -1685,6 +1728,7 @@
 
 static int
 icon_container_preview_callback (NautilusIconContainer *container,
+				 NautilusIconCanvasItem *item,
 				 NautilusFile *file,
 				 gboolean start_flag,
 				 FMIconView *icon_view)
@@ -1696,7 +1740,7 @@
 	
 	/* preview files based on the mime_type. */
 	/* at first, we just handle sounds */
-	if (should_preview_sound (file)) {
+	if (should_preview_media (file)) {
 		mime_type = nautilus_file_get_mime_type (file);
 
 		if ((eel_istr_has_prefix (mime_type, "audio/")
@@ -1706,7 +1750,16 @@
 		    && nautilus_sound_can_play_sound ()) {
 			result = 1;
 			preview_audio (icon_view, file, start_flag);
-		}	
+		}
+		else if (eel_istr_has_prefix (mime_type, "video/")) {
+			result = 1;
+			preview_video (icon_view, 
+				       container, 
+				       item, 
+				       file, 
+				       start_flag);
+		}
+	
 		g_free (mime_type);
 	}
 	
