changeset 25686:3bf9748fdef0

Preliminary video embedded in the conversation window. It's still kind of buggy.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Tue, 10 Jun 2008 05:18:29 +0000
parents c2231cf3be71
children ddbea813862e
files libpurple/media.c pidgin/gtkconv.c pidgin/gtkconv.h pidgin/gtkmedia.c pidgin/gtkmedia.h
diffstat 5 files changed, 123 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Sun Jun 08 02:47:38 2008 +0000
+++ b/libpurple/media.c	Tue Jun 10 05:18:29 2008 +0000
@@ -676,7 +676,7 @@
 void
 purple_media_video_init_src(GstElement **sendbin)
 {
-	GstElement *src;
+	GstElement *src, *tee, *queue, *local_sink;
 	GstPad *pad;
 	GstPad *ghost;
 	const gchar *video_plugin = purple_prefs_get_string("/purple/media/video/plugin");
@@ -685,17 +685,34 @@
 	purple_debug_info("media", "purple_media_video_init_src\n");
 
 	*sendbin = gst_bin_new("purplesendvideobin");
-	src = gst_element_factory_make(video_plugin, "videosrc");
+	src = gst_element_factory_make(video_plugin, "purplevideosource");
 	gst_bin_add(GST_BIN(*sendbin), src);
 
+	tee = gst_element_factory_make("tee", NULL);
+	gst_bin_add(GST_BIN(*sendbin), tee);
+	gst_element_link(src, tee);
+
+	queue = gst_element_factory_make("queue", NULL);
+	gst_bin_add(GST_BIN(*sendbin), queue);
+	gst_element_link(tee, queue);
+
 	if (!strcmp(video_plugin, "videotestsrc")) {
 		/* unless is-live is set to true it doesn't throttle videotestsrc */
 		g_object_set (G_OBJECT(src), "is-live", TRUE, NULL);
 	}
-	pad = gst_element_get_pad(src, "src");
+
+	pad = gst_element_get_pad(queue, "src");
 	ghost = gst_ghost_pad_new("ghostsrc", pad);
 	gst_element_add_pad(*sendbin, ghost);
 
+	queue = gst_element_factory_make("queue", NULL);
+	gst_bin_add(GST_BIN(*sendbin), queue);
+	gst_element_link(tee, queue);
+
+	local_sink = gst_element_factory_make("autovideosink", "purplelocalvideosink");
+	gst_bin_add(GST_BIN(*sendbin), local_sink);
+	gst_element_link(queue, local_sink);
+
 	/* set current video device on "src"... */
 	if (video_device) {
 		GList *devices = purple_media_get_devices(src);
--- a/pidgin/gtkconv.c	Sun Jun 08 02:47:38 2008 +0000
+++ b/pidgin/gtkconv.c	Tue Jun 10 05:18:29 2008 +0000
@@ -4743,7 +4743,7 @@
 static GtkWidget *
 setup_common_pane(PidginConversation *gtkconv)
 {
-	GtkWidget *vbox, *frame, *imhtml_sw, *event_box;
+	GtkWidget *vbox, *hpaned, *frame, *imhtml_sw, *event_box;
 	GtkCellRenderer *rend;
 	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
@@ -4823,23 +4823,21 @@
 	/* Setup the gtkimhtml widget */
 	frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw);
 	gtk_widget_set_size_request(gtkconv->imhtml, -1, 0);
+
+	/* Add the gtkimhtml frame */
+	gtkconv->middle_hpaned = hpaned = gtk_hpaned_new();
+	gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
+	gtk_widget_show(hpaned);
+	gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE);
+
 	if (chat) {
-		GtkWidget *hpaned;
-
 		/* Add the topic */
 		setup_chat_topic(gtkconv, vbox);
 
-		/* Add the gtkimhtml frame */
-		hpaned = gtk_hpaned_new();
-		gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
-		gtk_widget_show(hpaned);
-		gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE);
-
 		/* Now add the userlist */
 		setup_chat_userlist(gtkconv, hpaned);
-	} else {
-		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	}
+	}
+
 	gtk_widget_show(frame);
 
 	gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml");
@@ -7727,6 +7725,9 @@
 
 	gtkconv->gtkmedia = gtkmedia;
 	g_signal_connect(G_OBJECT(gtkmedia), "destroy", G_CALLBACK(gtk_widget_destroyed), &(gtkconv->gtkmedia));
+
+	gtk_paned_pack2(GTK_PANED(gtkconv->middle_hpaned),
+			pidgin_media_get_display_widget(gtkmedia), FALSE, TRUE);
 }
 
 #endif
--- a/pidgin/gtkconv.h	Sun Jun 08 02:47:38 2008 +0000
+++ b/pidgin/gtkconv.h	Tue Jun 10 05:18:29 2008 +0000
@@ -150,6 +150,7 @@
 	gpointer depr1;
 #endif
 
+	GtkWidget *middle_hpaned;
 	GtkWidget *lower_hbox;
 
 	GtkWidget *toolbar;
--- a/pidgin/gtkmedia.c	Sun Jun 08 02:47:38 2008 +0000
+++ b/pidgin/gtkmedia.c	Tue Jun 10 05:18:29 2008 +0000
@@ -28,11 +28,14 @@
 #include "internal.h"
 #include "connection.h"
 #include "media.h"
+#include "pidgin.h"
 
 #include "gtkmedia.h"
 
 #ifdef USE_VV
 
+#include <gst/interfaces/xoverlay.h>
+
 typedef enum
 {
 	/* Waiting for response */
@@ -60,6 +63,10 @@
 	GtkWidget *recv_progress;
 
 	PidginMediaState state;
+
+	GtkWidget *display;
+	GtkWidget *local_video;
+	GtkWidget *remote_video;
 };
 
 #define PIDGIN_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PIDGIN_TYPE_MEDIA, PidginMediaPrivate))
@@ -178,6 +185,8 @@
 
 	gtk_widget_show_all(media->priv->accept);
 	gtk_widget_show_all(media->priv->reject);
+
+	media->priv->display = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
 }
 
 static gboolean
@@ -246,6 +255,8 @@
 		gst_object_unref(gtkmedia->priv->send_level);
 	if (gtkmedia->priv->recv_level)
 		gst_object_unref(gtkmedia->priv->recv_level);
+	if (gtkmedia->priv->display)
+		gtk_widget_destroy(gtkmedia->priv->display);
 }
 
 static void
@@ -254,6 +265,12 @@
 	g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg);
 }
 
+GtkWidget *
+pidgin_media_get_display_widget(GtkWidget *gtkmedia)
+{
+	return PIDGIN_MEDIA_GET_PRIVATE(gtkmedia)->display;
+}
+
 static gboolean
 media_bus_call(GstBus *bus, GstMessage *msg, gpointer gtkmedia)
 {
@@ -284,30 +301,57 @@
 	return TRUE;
 }
 
+static gboolean
+create_window (GstBus *bus, GstMessage *message, PidginMedia *gtkmedia)
+{
+	char *name;
+
+	if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT)
+		return TRUE;
+
+	if (!gst_structure_has_name(message->structure, "prepare-xwindow-id"))
+		return TRUE;
+
+	name = gst_object_get_name(GST_MESSAGE_SRC (message));
+	purple_debug_info("gtkmedia", "prepare-xwindow-id object name: %s\n", name);
+
+	/* The XOverlay's name is the sink's name with a suffix */
+	if (!strncmp(name, "purplevideosink", strlen("purplevideosink")))
+		gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
+					     GDK_WINDOW_XWINDOW(gtkmedia->priv->remote_video->window));
+	else if (!strncmp(name, "purplelocalvideosink", strlen("purplelocalvideosink")))
+		gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
+					     GDK_WINDOW_XWINDOW(gtkmedia->priv->local_video->window));
+	g_free(name);
+	return TRUE;
+}
+
 static void
 pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia)
 {
 	GstElement *element = purple_media_get_pipeline(media);
 
-	GstElement *audiosendbin, *audiosendlevel;
-	GstElement *audiorecvbin, *audiorecvlevel;
-	GstElement *videosendbin;
-	GstElement *videorecvbin;
+	GstElement *audiosendbin = NULL, *audiosendlevel = NULL;
+	GstElement *audiorecvbin = NULL, *audiorecvlevel = NULL;
+	GstElement *videosendbin = NULL;
+	GstElement *videorecvbin = NULL;
 
 	GList *sessions = purple_media_get_session_names(media);
 	GstBus *bus;
 
-	purple_media_audio_init_src(&audiosendbin, &audiosendlevel);
-	purple_media_audio_init_recv(&audiorecvbin, &audiorecvlevel);
-
-	purple_media_video_init_src(&videosendbin);
-	purple_media_video_init_recv(&videorecvbin);
-
 	for (; sessions; sessions = sessions->next) {
 		if (purple_media_get_session_type(media, sessions->data) & PURPLE_MEDIA_AUDIO) {
+			if (!audiosendbin)
+				purple_media_audio_init_src(&audiosendbin, &audiosendlevel);
+			if (!audiorecvbin)
+				purple_media_audio_init_recv(&audiorecvbin, &audiorecvlevel);
 			purple_media_set_src(media, sessions->data, audiosendbin);
 			purple_media_set_sink(media, sessions->data, audiorecvbin);
 		} else if (purple_media_get_session_type(media, sessions->data) & PURPLE_MEDIA_VIDEO) {
+			if (!videosendbin)
+				purple_media_video_init_src(&videosendbin);
+			if (!videorecvbin)
+				purple_media_video_init_recv(&videorecvbin);
 			purple_media_set_src(media, sessions->data, videosendbin);
 			purple_media_set_sink(media, sessions->data, videorecvbin);
 		}
@@ -320,9 +364,42 @@
 				       NULL);
 	}
 
+	if (videorecvbin || videosendbin) {
+		GtkWidget *aspect;
+		GtkWidget *remote_video;
+		GtkWidget *local_video;
+
+		gtk_widget_show(gtkmedia->priv->display);
+
+		aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE);
+		gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN);
+		gtk_box_pack_start(GTK_BOX(gtkmedia->priv->display), aspect, TRUE, TRUE, 0);
+
+		remote_video = gtk_drawing_area_new();
+		gtk_container_add(GTK_CONTAINER(aspect), remote_video);
+		gtk_widget_set_size_request (GTK_WIDGET(remote_video), 100, -1);
+		gtk_widget_show(remote_video);
+		gtk_widget_show(aspect);
+
+		aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE);
+		gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN);
+		gtk_box_pack_start(GTK_BOX(gtkmedia->priv->display), aspect, TRUE, TRUE, 0);
+
+		local_video = gtk_drawing_area_new();
+		gtk_container_add(GTK_CONTAINER(aspect), local_video);
+		gtk_widget_show(local_video);
+		gtk_widget_show(aspect);
+
+		gtkmedia->priv->local_video = local_video;
+		gtkmedia->priv->remote_video = remote_video;
+	}
+
 	bus = gst_pipeline_get_bus(GST_PIPELINE(element));
 	gst_bus_add_signal_watch(GST_BUS(bus));
-	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", G_CALLBACK(level_message_cb), gtkmedia);
+	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))),
+			 "message", G_CALLBACK(level_message_cb), gtkmedia);
+	if (videorecvbin || videosendbin)
+		gst_bus_set_sync_handler(bus, (GstBusSyncHandler)create_window, gtkmedia);
 	gst_bus_add_watch(bus, media_bus_call, gtkmedia);
 	gst_object_unref(bus);
 }
--- a/pidgin/gtkmedia.h	Sun Jun 08 02:47:38 2008 +0000
+++ b/pidgin/gtkmedia.h	Tue Jun 10 05:18:29 2008 +0000
@@ -60,6 +60,7 @@
 GType pidgin_media_get_type(void);
 
 GtkWidget *pidgin_media_new(PurpleMedia *media);
+GtkWidget *pidgin_media_get_display_widget(GtkWidget *gtkmedia);
 
 G_END_DECLS