[longomatch/livecapture2: 1/31] Rework on the camera capturer: merged camerabin API changes, embeded video widget and fixed indentat



commit 9ec8adb00b8e033587158a5873fb3a28b5abaf39
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Mon Mar 29 00:10:21 2010 +0200

    Rework on the camera capturer: merged camerabin API changes, embeded video
    widget and fixed indentation

 CesarPlayer/Capturer/GstCameraCapturer.cs |   48 +-
 libcesarplayer/src/gst-camera-capturer.c  | 1138 +++++++++++++++++++----------
 libcesarplayer/src/gst-camera-capturer.h  |   48 +-
 3 files changed, 806 insertions(+), 428 deletions(-)
---
diff --git a/CesarPlayer/Capturer/GstCameraCapturer.cs b/CesarPlayer/Capturer/GstCameraCapturer.cs
index 7b4d9ac..206159a 100644
--- a/CesarPlayer/Capturer/GstCameraCapturer.cs
+++ b/CesarPlayer/Capturer/GstCameraCapturer.cs
@@ -237,25 +237,6 @@ namespace LongoMatch.Video.Capturer {
 		}
 
 		[DllImport("libcesarplayer.dll")]
-		static extern bool gst_camera_capturer_set_video_muxer(IntPtr raw, int type);
-
-		public bool SetVideoMuxer(LongoMatch.Video.Capturer.GccVideoMuxerType type) {
-			bool raw_ret = gst_camera_capturer_set_video_muxer(Handle, (int) type);
-			bool ret = raw_ret;
-			return ret;
-		}
-
-		
-		[DllImport("libcesarplayer.dll")]
-		static extern bool gst_camera_capturer_set_video_encoder(IntPtr raw, int type);
-
-		public bool SetVideoEncoder(LongoMatch.Video.Capturer.GccVideoEncoderType type) {
-			bool raw_ret = gst_camera_capturer_set_video_encoder(Handle, (int) type);
-			bool ret = raw_ret;
-			return ret;
-		}
-
-		[DllImport("libcesarplayer.dll")]
 		static extern void gst_camera_capturer_init_backend(out int argc, IntPtr argv);
 
 		public static int InitBackend(string argv) {
@@ -293,12 +274,37 @@ namespace LongoMatch.Video.Capturer {
 		public void Run() {
 			gst_camera_capturer_run(Handle);
 		}
+		
+		[DllImport("libcesarplayer.dll")]
+		static extern bool gst_camera_capturer_set_video_muxer(IntPtr raw, int type, out IntPtr error);
 
+		public bool SetVideoMuxer(LongoMatch.Video.Capturer.GccVideoMuxerType type) {
+			IntPtr error = IntPtr.Zero;
+			bool raw_ret = gst_camera_capturer_set_video_muxer(Handle, (int) type, out error);
+			if (error != IntPtr.Zero) throw new GLib.GException (error);
+			bool ret = raw_ret;
+			return ret;
+		}
+
+		
 		[DllImport("libcesarplayer.dll")]
-		static extern bool gst_camera_capturer_set_audio_encoder(IntPtr raw, int type);
+		static extern bool gst_camera_capturer_set_video_encoder(IntPtr raw, int type, out IntPtr error);
+
+		public bool SetVideoEncoder(LongoMatch.Video.Capturer.GccVideoEncoderType type) {
+			IntPtr error = IntPtr.Zero;
+			bool raw_ret = gst_camera_capturer_set_video_encoder(Handle, (int) type, out error);
+			if (error != IntPtr.Zero) throw new GLib.GException (error);
+			bool ret = raw_ret;
+			return ret;
+		}
+
+		[DllImport("libcesarplayer.dll")]
+		static extern bool gst_camera_capturer_set_audio_encoder(IntPtr raw, int type, out IntPtr error);
 
 		public bool SetAudioEncoder(LongoMatch.Video.Capturer.GccAudioEncoderType type) {
-			bool raw_ret = gst_camera_capturer_set_audio_encoder(Handle, (int) type);
+			IntPtr error = IntPtr.Zero;			
+			bool raw_ret = gst_camera_capturer_set_audio_encoder(Handle, (int) type, out error);
+			if (error != IntPtr.Zero) throw new GLib.GException (error);
 			bool ret = raw_ret;
 			return ret;
 		}
diff --git a/libcesarplayer/src/gst-camera-capturer.c b/libcesarplayer/src/gst-camera-capturer.c
index b78d9f9..9f8590c 100644
--- a/libcesarplayer/src/gst-camera-capturer.c
+++ b/libcesarplayer/src/gst-camera-capturer.c
@@ -17,15 +17,16 @@
 * 
 * You should have received a copy of the GNU General Public License
 * along with foob.  If not, write to:
-* 	The Free Software Foundation, Inc.,
-* 	51 Franklin Street, Fifth Floor
-* 	Boston, MA  02110-1301, USA.
+*       The Free Software Foundation, Inc.,
+*       51 Franklin Street, Fifth Floor
+*       Boston, MA  02110-1301, USA.
 */
 
 #include <string.h>
 #include <stdio.h>
 
 #include <gst/interfaces/xoverlay.h>
+#include <gst/interfaces/propertyprobe.h>
 #include <gst/gst.h>
 #include <gst/video/video.h>
 
@@ -35,9 +36,11 @@
 
 /*Default video source*/
 #ifdef WIN32
-#define VIDEOSRC "ksvideosrc"
+#define VIDEOSRC "dshowvideosrc"
+#define AUDIOSRC "dshowaudiosrc"
 #else
-#define VIDEOSRC "v4l2src"
+#define VIDEOSRC "gconfvideosrc"
+#define AUDIOSRC "gconfaudiosrc"
 #endif
 
 /* gtk+/gnome */
@@ -61,8 +64,8 @@ enum
 enum
 {
   PROP_0,
-  PROP_ENCODE_HEIGHT,
-  PROP_ENCODE_WIDTH,
+  PROP_OUTPUT_HEIGHT,
+  PROP_OUTPUT_WIDTH,
   PROP_VIDEO_BITRATE,
   PROP_AUDIO_BITRATE,
   PROP_OUTPUT_FILE,
@@ -74,19 +77,21 @@ struct GstCameraCapturerPrivate
 
   /*Encoding properties */
   gchar *output_file;
-  guint encode_height;
-  guint encode_width;
+  guint output_height;
+  guint output_width;
+  guint output_fps_n;
+  guint output_fps_d;
   guint audio_bitrate;
   guint video_bitrate;
   GccVideoEncoderType video_encoder_type;
   GccAudioEncoderType audio_encoder_type;
 
   /*Video input info */
-  gint video_width;		/* Movie width */
-  gint video_height;		/* Movie height */
-  const GValue *movie_par;	/* Movie pixel aspect ratio */
-  gint video_width_pixels;	/* Scaled movie width */
-  gint video_height_pixels;	/* Scaled movie height */
+  gint video_width;             /* Movie width */
+  gint video_height;            /* Movie height */
+  const GValue *movie_par;      /* Movie pixel aspect ratio */
+  gint video_width_pixels;      /* Scaled movie width */
+  gint video_height_pixels;     /* Scaled movie height */
   gint video_fps_n;
   gint video_fps_d;
   gboolean media_has_video;
@@ -103,13 +108,15 @@ struct GstCameraCapturerPrivate
   GstElement *videomux;
 
   /*Overlay */
-  GstXOverlay *xoverlay;	/* protect with lock */
+  GstXOverlay *xoverlay;        /* protect with lock */
+  guint interface_update_id;    /* protect with lock */
   GMutex *lock;
 
   /*Videobox */
-  GtkWidget *video_window;
+  GdkWindow *video_window;
   gboolean logo_mode;
   GdkPixbuf *logo_pixbuf;
+  float zoom;
 
   /*GStreamer bus */
   GstBus *bus;
@@ -117,28 +124,26 @@ struct GstCameraCapturerPrivate
   gulong sig_bus_sync;
 };
 
+static GtkWidgetClass *parent_class = NULL;
+
+static GThread *gui_thread;
+
 static int gcc_signals[LAST_SIGNAL] = { 0 };
 
 static void gcc_error_msg (GstCameraCapturer * gcc, GstMessage * msg);
 static void gcc_bus_message_cb (GstBus * bus, GstMessage * message,
-				gpointer data);
+    gpointer data);
 static void gst_camera_capturer_get_property (GObject * object,
-					      guint property_id,
-					      GValue * value,
-					      GParamSpec * pspec);
+    guint property_id, GValue * value, GParamSpec * pspec);
 static void gst_camera_capturer_set_property (GObject * object,
-					      guint property_id,
-					      const GValue * value,
-					      GParamSpec * pspec);
+    guint property_id, const GValue * value, GParamSpec * pspec);
 static void gcc_element_msg_sync (GstBus * bus, GstMessage * msg,
-				  gpointer data);
+    gpointer data);
 static void gcc_update_interface_implementations (GstCameraCapturer * gcc);
 static int gcc_parse_video_stream_info (GstCaps * caps,
-					GstCameraCapturer * gcc);
-
-G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_HBOX);
-
+    GstCameraCapturer * gcc);
 
+G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_EVENT_BOX);
 
 
 static void
@@ -146,8 +151,20 @@ gst_camera_capturer_init (GstCameraCapturer * object)
 {
   GstCameraCapturerPrivate *priv;
   object->priv = priv =
-    G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
-				 GstCameraCapturerPrivate);
+      G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_CAMERA_CAPTURER,
+      GstCameraCapturerPrivate);
+
+  GTK_WIDGET_SET_FLAGS (GTK_WIDGET (object), GTK_CAN_FOCUS);
+  GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (object), GTK_DOUBLE_BUFFERED);
+
+  priv->zoom = 1.0;
+  priv->output_height = 576;
+  priv->output_width = 720;
+  priv->output_fps_n = 25;
+  priv->output_fps_d = 1;
+  priv->audio_bitrate = 128;
+  priv->video_bitrate = 5000;
+
   priv->lock = g_mutex_new ();
 }
 
@@ -156,131 +173,516 @@ gst_camera_capturer_finalize (GObject * object)
 {
   GstCameraCapturer *gcc = (GstCameraCapturer *) object;
 
-  gtk_widget_destroy (gcc->priv->video_window);
-  gtk_widget_unref (gcc->priv->video_window);
-  gcc->priv->video_window = NULL;
+  if (gcc->priv->bus) {
+    /* make bus drop all messages to make sure none of our callbacks is ever
+     * called again (main loop might be run again to display error dialog) */
+    gst_bus_set_flushing (gcc->priv->bus, TRUE);
 
-  if (gcc->priv->bus)
-    {
-      /* make bus drop all messages to make sure none of our callbacks is ever
-       * called again (main loop might be run again to display error dialog) */
-      gst_bus_set_flushing (gcc->priv->bus, TRUE);
-
-      if (gcc->priv->sig_bus_async)
-	g_signal_handler_disconnect (gcc->priv->bus,
-				     gcc->priv->sig_bus_async);
-      gst_object_unref (gcc->priv->bus);
-      gcc->priv->bus = NULL;
-    }
+    if (gcc->priv->sig_bus_async)
+      g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_async);
+    gst_object_unref (gcc->priv->bus);
+    gcc->priv->bus = NULL;
+  }
 
   g_free (gcc->priv->output_file);
   gcc->priv->output_file = NULL;
 
+  if (gcc->priv->interface_update_id) {
+    g_source_remove (gcc->priv->interface_update_id);
+    gcc->priv->interface_update_id = 0;
+  }
 
   if (gcc->priv->main_pipeline != NULL
-      && GST_IS_ELEMENT (gcc->priv->main_pipeline))
-    {
-      gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
-      gst_object_unref (gcc->priv->main_pipeline);
-      gcc->priv->main_pipeline = NULL;
-    }
+      && GST_IS_ELEMENT (gcc->priv->main_pipeline)) {
+    gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+    gst_object_unref (gcc->priv->main_pipeline);
+    gcc->priv->main_pipeline = NULL;
+  }
 
-  if (gcc->priv->camerabin != NULL && GST_IS_ELEMENT (gcc->priv->camerabin))
-    {
-      gst_object_unref (gcc->priv->camerabin);
-      gcc->priv->camerabin = NULL;
+  g_mutex_free (gcc->priv->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_camera_capturer_apply_resolution (GstCameraCapturer * gcc)
+{
+  GstCaps *caps;
+  gchar * caps_string;
+  
+  GST_INFO_OBJECT(gcc, "Changed video resolution to %dx%d %d/%dfps",
+      gcc->priv->output_width, gcc->priv->output_height,
+      gcc->priv->output_fps_n, gcc->priv->output_fps_d);
+  
+  caps_string = g_strdup_printf("video/x-raw-yuv, format=(fourcc)I420,width=(int)%d,height=(int)%d", 
+      gcc->priv->output_width, gcc->priv->output_height);
+  caps = gst_caps_from_string(caps_string);
+  g_object_set (gcc->priv->camerabin, "filter-caps", caps, NULL);
+  gst_caps_unref(caps);
+  g_free(caps_string);
+}
+
+static void
+gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+  gcc->priv->video_bitrate = bitrate;
+  g_object_set (gcc->priv->videoenc, "bitrate", gcc->priv->video_bitrate, NULL);
+  GST_INFO_OBJECT (gcc,"Changed video bitrate to :\n%d", gcc->priv->video_bitrate);
+
+}
+
+static void
+gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+
+  gcc->priv->audio_bitrate = bitrate;
+  g_object_set (gcc->priv->audioenc, "bitrate", bitrate, NULL);
+  GST_INFO_OBJECT (gcc,"Changed audio bitrate to :\n%d", gcc->priv->audio_bitrate);
+
+}
+
+static void
+gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
+    const gchar * file)
+{
+  gcc->priv->output_file = g_strdup (file);
+  g_object_set (gcc->priv->camerabin, "filename", file, NULL);
+  GST_INFO_OBJECT (gcc,"Changed output filename to :\n%s", file);
+
+}
+
+/***********************************
+*           
+*           GTK Widget
+*
+************************************/
+
+static void
+gst_camera_capturer_size_request (GtkWidget * widget,
+    GtkRequisition * requisition)
+{
+  requisition->width = 320;
+  requisition->height = 240;
+}
+
+static void
+get_media_size (GstCameraCapturer * gcc, gint * width, gint * height)
+{
+  if (gcc->priv->logo_mode) {
+    if (gcc->priv->logo_pixbuf) {
+      *width = gdk_pixbuf_get_width (gcc->priv->logo_pixbuf);
+      *height = gdk_pixbuf_get_height (gcc->priv->logo_pixbuf);
+    } else {
+      *width = 0;
+      *height = 0;
     }
+  } else {
 
-  if (gcc->priv->videosrc != NULL && GST_IS_ELEMENT (gcc->priv->videosrc))
-    {
-      gst_object_unref (gcc->priv->videosrc);
-      gcc->priv->videosrc = NULL;
+    GValue *disp_par = NULL;
+    guint movie_par_n, movie_par_d, disp_par_n, disp_par_d, num, den;
+
+    /* Create and init the fraction value */
+    disp_par = g_new0 (GValue, 1);
+    g_value_init (disp_par, GST_TYPE_FRACTION);
+
+    /* Square pixel is our default */
+    gst_value_set_fraction (disp_par, 1, 1);
+
+    /* Now try getting display's pixel aspect ratio */
+    if (gcc->priv->xoverlay) {
+      GObjectClass *klass;
+      GParamSpec *pspec;
+
+      klass = G_OBJECT_GET_CLASS (gcc->priv->xoverlay);
+      pspec = g_object_class_find_property (klass, "pixel-aspect-ratio");
+
+      if (pspec != NULL) {
+        GValue disp_par_prop = { 0, };
+
+        g_value_init (&disp_par_prop, pspec->value_type);
+        g_object_get_property (G_OBJECT (gcc->priv->xoverlay),
+            "pixel-aspect-ratio", &disp_par_prop);
+
+        if (!g_value_transform (&disp_par_prop, disp_par)) {
+          GST_WARNING ("Transform failed, assuming pixel-aspect-ratio = 1/1");
+          gst_value_set_fraction (disp_par, 1, 1);
+        }
+
+        g_value_unset (&disp_par_prop);
+      }
     }
 
-  if (gcc->priv->audiosrc != NULL && GST_IS_ELEMENT (gcc->priv->audiosrc))
-    {
-      gst_object_unref (gcc->priv->audiosrc);
-      gcc->priv->audiosrc = NULL;
+    disp_par_n = gst_value_get_fraction_numerator (disp_par);
+    disp_par_d = gst_value_get_fraction_denominator (disp_par);
+
+    GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
+
+    /* Use the movie pixel aspect ratio if any */
+    if (gcc->priv->movie_par) {
+      movie_par_n = gst_value_get_fraction_numerator (gcc->priv->movie_par);
+      movie_par_d = gst_value_get_fraction_denominator (gcc->priv->movie_par);
+    } else {
+      /* Square pixels */
+      movie_par_n = 1;
+      movie_par_d = 1;
     }
 
-  if (gcc->priv->videoenc != NULL && GST_IS_ELEMENT (gcc->priv->videoenc))
-    {
-      gst_object_unref (gcc->priv->videoenc);
-      gcc->priv->videoenc = NULL;
+    GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
+
+    if (gcc->priv->video_width == 0 || gcc->priv->video_height == 0) {
+      GST_DEBUG ("width and/or height 0, assuming 1/1 ratio");
+      num = 1;
+      den = 1;
+    } else if (!gst_video_calculate_display_ratio (&num, &den,
+            gcc->priv->video_width,
+            gcc->priv->video_height,
+            movie_par_n, movie_par_d, disp_par_n, disp_par_d)) {
+      GST_WARNING ("overflow calculating display aspect ratio!");
+      num = 1;                  /* FIXME: what values to use here? */
+      den = 1;
     }
 
-  if (gcc->priv->audioenc != NULL && GST_IS_ELEMENT (gcc->priv->audioenc))
-    {
-      gst_object_unref (gcc->priv->audioenc);
-      gcc->priv->audioenc = NULL;
+    GST_DEBUG ("calculated scaling ratio %d/%d for video %dx%d", num,
+        den, gcc->priv->video_width, gcc->priv->video_height);
+
+    /* now find a width x height that respects this display ratio.
+     * prefer those that have one of w/h the same as the incoming video
+     * using wd / hd = num / den */
+
+    /* start with same height, because of interlaced video */
+    /* check hd / den is an integer scale factor, and scale wd with the PAR */
+    if (gcc->priv->video_height % den == 0) {
+      GST_DEBUG ("keeping video height");
+      gcc->priv->video_width_pixels =
+          (guint) gst_util_uint64_scale (gcc->priv->video_height, num, den);
+      gcc->priv->video_height_pixels = gcc->priv->video_height;
+    } else if (gcc->priv->video_width % num == 0) {
+      GST_DEBUG ("keeping video width");
+      gcc->priv->video_width_pixels = gcc->priv->video_width;
+      gcc->priv->video_height_pixels =
+          (guint) gst_util_uint64_scale (gcc->priv->video_width, den, num);
+    } else {
+      GST_DEBUG ("approximating while keeping video height");
+      gcc->priv->video_width_pixels =
+          (guint) gst_util_uint64_scale (gcc->priv->video_height, num, den);
+      gcc->priv->video_height_pixels = gcc->priv->video_height;
     }
+    GST_DEBUG ("scaling to %dx%d", gcc->priv->video_width_pixels,
+        gcc->priv->video_height_pixels);
 
-  g_mutex_free (gcc->priv->lock);
+    *width = gcc->priv->video_width_pixels;
+    *height = gcc->priv->video_height_pixels;
 
-  G_OBJECT_CLASS (gst_camera_capturer_parent_class)->finalize (object);
+    /* Free the PAR fraction */
+    g_value_unset (disp_par);
+    g_free (disp_par);
+
+  }
 }
 
+static void
+resize_video_window (GstCameraCapturer * gcc)
+{
+  const GtkAllocation *allocation;
+  gfloat width, height, ratio, x, y;
+  int w, h;
+
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+  allocation = &GTK_WIDGET (gcc)->allocation;
 
+  get_media_size (gcc, &w, &h);
+
+  if (!w || !h) {
+    w = allocation->width;
+    h = allocation->height;
+  }
+  width = w;
+  height = h;
+
+  /* calculate ratio for fitting video into the available space */
+  if ((gfloat) allocation->width / width > (gfloat) allocation->height / height) {
+    ratio = (gfloat) allocation->height / height;
+  } else {
+    ratio = (gfloat) allocation->width / width;
+  }
+
+  /* apply zoom factor */
+  ratio = ratio * gcc->priv->zoom;
+
+  width *= ratio;
+  height *= ratio;
+  x = (allocation->width - width) / 2;
+  y = (allocation->height - height) / 2;
+
+  gdk_window_move_resize (gcc->priv->video_window, x, y, width, height);
+  gtk_widget_queue_draw (GTK_WIDGET (gcc));
+}
 
 static void
-gst_camera_capturer_set_encode_width (GstCameraCapturer * gcc, gint width)
+gst_camera_capturer_size_allocate (GtkWidget * widget,
+    GtkAllocation * allocation)
 {
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
 
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (widget));
+
+  widget->allocation = *allocation;
+
+  if (GTK_WIDGET_REALIZED (widget)) {
+    gdk_window_move_resize (gtk_widget_get_window (widget),
+        allocation->x, allocation->y, allocation->width, allocation->height);
+    resize_video_window (gcc);
+  }
 }
 
-static void
-gst_camera_capturer_set_encode_height (GstCameraCapturer * gcc, gint height)
+static gboolean
+gst_camera_capturer_configure_event (GtkWidget * widget,
+    GdkEventConfigure * event, GstCameraCapturer * gcc)
 {
+  GstXOverlay *xoverlay = NULL;
+
+  g_return_val_if_fail (gcc != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+
+  xoverlay = gcc->priv->xoverlay;
 
+  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
+    gst_x_overlay_expose (xoverlay);
+  }
+
+  return FALSE;
 }
 
 static void
-gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+gst_camera_capturer_realize (GtkWidget * widget)
 {
-  gcc->priv->video_bitrate = bitrate;
-  g_object_set (gcc->priv->videoenc, "bitrate", gcc->priv->video_bitrate,
-		NULL);
-  GST_INFO ("Changed video bitrate to :\n%d", gcc->priv->video_bitrate);
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+  GdkWindowAttr attributes;
+  gint attributes_mask, w, h;
+  GdkColor colour;
+  GdkWindow *window;
+  GdkEventMask event_mask;
+
+  event_mask = gtk_widget_get_events (widget)
+      | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK;
+  gtk_widget_set_events (widget, event_mask);
+
+  GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+  window = gtk_widget_get_window (widget);
+
+  /* Creating our video window */
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = 0;
+  attributes.y = 0;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= GDK_EXPOSURE_MASK |
+      GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK;
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  gcc->priv->video_window = gdk_window_new (window,
+      &attributes, attributes_mask);
+  gdk_window_set_user_data (gcc->priv->video_window, widget);
+
+  gdk_color_parse ("black", &colour);
+  gdk_colormap_alloc_color (gtk_widget_get_colormap (widget),
+      &colour, TRUE, TRUE);
+  gdk_window_set_background (window, &colour);
+  gtk_widget_set_style (widget,
+      gtk_style_attach (gtk_widget_get_style (widget), window));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+  /* Connect to configure event on the top level window */
+  g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
+      "configure-event", G_CALLBACK (gst_camera_capturer_configure_event), gcc);
+
+  /* nice hack to show the logo fullsize, while still being resizable */
+  get_media_size (GST_CAMERA_CAPTURER (widget), &w, &h);
+}
+
+static void
+gst_camera_capturer_unrealize (GtkWidget * widget)
+{
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+
+  gdk_window_set_user_data (gcc->priv->video_window, NULL);
+  gdk_window_destroy (gcc->priv->video_window);
+  gcc->priv->video_window = NULL;
 
+  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
 }
 
 static void
-gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+gst_camera_capturer_show (GtkWidget * widget)
 {
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+  GdkWindow *window;
 
-  gcc->priv->audio_bitrate = bitrate;
-  g_object_set (gcc->priv->audioenc, "bitrate", bitrate, NULL);
-  GST_INFO ("Changed audio bitrate to :\n%d", gcc->priv->audio_bitrate);
+  window = gtk_widget_get_window (widget);
+  if (window)
+    gdk_window_show (window);
+  if (gcc->priv->video_window)
+    gdk_window_show (gcc->priv->video_window);
 
+  if (GTK_WIDGET_CLASS (parent_class)->show)
+    GTK_WIDGET_CLASS (parent_class)->show (widget);
 }
 
 static void
-gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
-				     const gchar * file)
+gst_camera_capturer_hide (GtkWidget * widget)
 {
-  gcc->priv->output_file = g_strdup (file);
-  g_object_set (gcc->priv->camerabin, "filename", file, NULL);
-  GST_INFO ("Changed output filename to :\n%s", file);
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+  GdkWindow *window;
+
+  window = gtk_widget_get_window (widget);
+  if (window)
+    gdk_window_hide (window);
+  if (gcc->priv->video_window)
+    gdk_window_hide (gcc->priv->video_window);
 
+  if (GTK_WIDGET_CLASS (parent_class)->hide)
+    GTK_WIDGET_CLASS (parent_class)->hide (widget);
 }
 
+static gboolean
+gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
+{
+  GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (widget);
+  GstCaps *caps = NULL;
+  GstXOverlay *xoverlay;
+  gboolean draw_logo;
+  GdkWindow *win;
+
+  if (event && event->count > 0)
+    return TRUE;
+
+  g_mutex_lock (gcc->priv->lock);
+  xoverlay = gcc->priv->xoverlay;
+  if (xoverlay == NULL) {
+    gcc_update_interface_implementations (gcc);
+    g_object_get (gcc->priv->camerabin, "filter-caps", &caps, NULL);
+    gcc_parse_video_stream_info (caps, gcc);
+    gst_caps_unref (caps);
+    xoverlay = gcc->priv->xoverlay;
+  }
+  if (xoverlay != NULL)
+    gst_object_ref (xoverlay);
+
+  g_mutex_unlock (gcc->priv->lock);
+
+  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
+#ifdef WIN32
+    gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
+        GDK_WINDOW_HWND (gcc->priv->video_window));
+#else
+    gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
+        GDK_WINDOW_XID (gcc->priv->video_window));
+#endif
+  }
+
+  /* Start with a nice black canvas */
+  win = gtk_widget_get_window (widget);
+  gdk_draw_rectangle (win, gtk_widget_get_style (widget)->black_gc, TRUE, 0,
+      0, widget->allocation.width, widget->allocation.height);
+
+  /* if there's only audio and no visualisation, draw the logo as well */
+  draw_logo = gcc->priv->media_has_audio && !gcc->priv->media_has_video;
+
+  if (gcc->priv->logo_mode || draw_logo) {
+    if (gcc->priv->logo_pixbuf != NULL) {
+      GdkPixbuf *frame;
+      guchar *pixels;
+      int rowstride;
+      gint width, height, alloc_width, alloc_height, logo_x, logo_y;
+      gfloat ratio;
+
+      /* Checking if allocated space is smaller than our logo */
+      width = gdk_pixbuf_get_width (gcc->priv->logo_pixbuf);
+      height = gdk_pixbuf_get_height (gcc->priv->logo_pixbuf);
+      alloc_width = widget->allocation.width;
+      alloc_height = widget->allocation.height;
+
+      if ((gfloat) alloc_width / width > (gfloat) alloc_height / height) {
+        ratio = (gfloat) alloc_height / height;
+      } else {
+        ratio = (gfloat) alloc_width / width;
+      }
+
+      width *= ratio;
+      height *= ratio;
+
+      logo_x = (alloc_width / 2) - (width / 2);
+      logo_y = (alloc_height / 2) - (height / 2);
+
+      /* Drawing our frame */
+      /* Scaling to available space */
+      frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+          FALSE, 8, widget->allocation.width, widget->allocation.height);
+
+      gdk_pixbuf_composite (gcc->priv->logo_pixbuf,
+          frame,
+          0, 0,
+          alloc_width, alloc_height,
+          logo_x, logo_y, ratio, ratio, GDK_INTERP_BILINEAR, 255);
+
+      rowstride = gdk_pixbuf_get_rowstride (frame);
+
+      pixels = gdk_pixbuf_get_pixels (frame) +
+          rowstride * event->area.y + event->area.x * 3;
+
+      gdk_draw_rgb_image_dithalign (widget->window,
+          widget->style->black_gc,
+          event->area.x, event->area.y,
+          event->area.width,
+          event->area.height,
+          GDK_RGB_DITHER_NORMAL, pixels,
+          rowstride, event->area.x, event->area.y);
+
+      g_object_unref (frame);
+    } else if (win) {
+      /* No pixbuf, just draw a black background then */
+      gdk_window_clear_area (win,
+          0, 0, widget->allocation.width, widget->allocation.height);
+    }
+  } else {
+    /* no logo, pass the expose to gst */
+    if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
+      gst_x_overlay_expose (xoverlay);
+    } else {
+      /* No xoverlay to expose yet */
+      gdk_window_clear_area (win,
+          0, 0, widget->allocation.width, widget->allocation.height);
+    }
+  }
+  if (xoverlay != NULL)
+    gst_object_unref (xoverlay);
 
+  return TRUE;
+}
 
 static void
 gst_camera_capturer_set_property (GObject * object, guint property_id,
-				  const GValue * value, GParamSpec * pspec)
+    const GValue * value, GParamSpec * pspec)
 {
   GstCameraCapturer *gcc;
 
   gcc = GST_CAMERA_CAPTURER (object);
 
-  switch (property_id)
-    {
-    case PROP_ENCODE_HEIGHT:
-      gst_camera_capturer_set_encode_height (gcc, g_value_get_uint (value));
+  switch (property_id) {
+    case PROP_OUTPUT_HEIGHT:
+      gcc->priv->output_height = g_value_get_uint (value);
+      gst_camera_capturer_apply_resolution (gcc);
       break;
-    case PROP_ENCODE_WIDTH:
-      gst_camera_capturer_set_encode_width (gcc, g_value_get_uint (value));
+    case PROP_OUTPUT_WIDTH:
+      gcc->priv->output_width = g_value_get_uint (value);
+      gst_camera_capturer_apply_resolution (gcc);
       break;
     case PROP_VIDEO_BITRATE:
       gst_camera_capturer_set_video_bit_rate (gcc, g_value_get_uint (value));
@@ -294,24 +696,23 @@ gst_camera_capturer_set_property (GObject * object, guint property_id,
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
-    }
+  }
 }
 
 static void
 gst_camera_capturer_get_property (GObject * object, guint property_id,
-				  GValue * value, GParamSpec * pspec)
+    GValue * value, GParamSpec * pspec)
 {
   GstCameraCapturer *gcc;
 
   gcc = GST_CAMERA_CAPTURER (object);
 
-  switch (property_id)
-    {
-    case PROP_ENCODE_HEIGHT:
-      g_value_set_uint (value, gcc->priv->encode_height);
+  switch (property_id) {
+    case PROP_OUTPUT_HEIGHT:
+      g_value_set_uint (value, gcc->priv->output_height);
       break;
-    case PROP_ENCODE_WIDTH:
-      g_value_set_uint (value, gcc->priv->encode_width);
+    case PROP_OUTPUT_WIDTH:
+      g_value_set_uint (value, gcc->priv->output_width);
       break;
     case PROP_AUDIO_BITRATE:
       g_value_set_uint (value, gcc->priv->audio_bitrate);
@@ -325,65 +726,68 @@ gst_camera_capturer_get_property (GObject * object, guint property_id,
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
-    }
+  }
 }
 
 static void
 gst_camera_capturer_class_init (GstCameraCapturerClass * klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GObjectClass *object_class;
+  GtkWidgetClass *widget_class;
 
-  object_class->finalize = gst_camera_capturer_finalize;
+  object_class = (GObjectClass *) klass;
+  widget_class = (GtkWidgetClass *) klass;
+  parent_class = g_type_class_peek_parent (klass);
 
   g_type_class_add_private (object_class, sizeof (GstCameraCapturerPrivate));
 
+  /* GtkWidget */
+  widget_class->size_request = gst_camera_capturer_size_request;
+  widget_class->size_allocate = gst_camera_capturer_size_allocate;
+  widget_class->realize = gst_camera_capturer_realize;
+  widget_class->unrealize = gst_camera_capturer_unrealize;
+  widget_class->show = gst_camera_capturer_show;
+  widget_class->hide = gst_camera_capturer_hide;
+  widget_class->expose_event = gst_camera_capturer_expose_event;
+
   /* GObject */
   object_class->set_property = gst_camera_capturer_set_property;
   object_class->get_property = gst_camera_capturer_get_property;
   object_class->finalize = gst_camera_capturer_finalize;
 
   /* Properties */
-  g_object_class_install_property (object_class, PROP_ENCODE_HEIGHT,
-				   g_param_spec_uint ("encode_height", NULL,
-						      NULL, 180, 5600, 576,
-						      G_PARAM_READWRITE));
-  g_object_class_install_property (object_class, PROP_ENCODE_WIDTH,
-				   g_param_spec_uint ("encode_width", NULL,
-						      NULL, 180, 5600, 720,
-						      G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_OUTPUT_HEIGHT,
+      g_param_spec_uint ("output_height", NULL,
+          NULL, 180, 5600, 576, G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_OUTPUT_WIDTH,
+      g_param_spec_uint ("output_width", NULL,
+          NULL, 180, 5600, 720, G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_VIDEO_BITRATE,
-				   g_param_spec_uint ("video_bitrate", NULL,
-						      NULL, 100, G_MAXUINT,
-						      1000,
-						      G_PARAM_READWRITE));
+      g_param_spec_uint ("video_bitrate", NULL,
+          NULL, 100, G_MAXUINT, 1000, G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_AUDIO_BITRATE,
-				   g_param_spec_uint ("audio_bitrate", NULL,
-						      NULL, 12, G_MAXUINT,
-						      128,
-						      G_PARAM_READWRITE));
+      g_param_spec_uint ("audio_bitrate", NULL,
+          NULL, 12, G_MAXUINT, 128, G_PARAM_READWRITE));
   g_object_class_install_property (object_class, PROP_OUTPUT_FILE,
-				   g_param_spec_string ("output_file", NULL,
-							NULL, FALSE,
-							G_PARAM_READWRITE));
+      g_param_spec_string ("output_file", NULL,
+          NULL, FALSE, G_PARAM_READWRITE));
 
 
   /* Signals */
   gcc_signals[SIGNAL_ERROR] =
-    g_signal_new ("error",
-		  G_TYPE_FROM_CLASS (object_class),
-		  G_SIGNAL_RUN_LAST,
-		  G_STRUCT_OFFSET (GstCameraCapturerClass, error),
-		  NULL, NULL,
-		  g_cclosure_marshal_VOID__STRING,
-		  G_TYPE_NONE, 1, G_TYPE_STRING);
+      g_signal_new ("error",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstCameraCapturerClass, error),
+      NULL, NULL,
+      g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
 
   gcc_signals[SIGNAL_EOS] =
-    g_signal_new ("eos",
-		  G_TYPE_FROM_CLASS (object_class),
-		  G_SIGNAL_RUN_LAST,
-		  G_STRUCT_OFFSET (GstCameraCapturerClass, eos),
-		  NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
+      g_signal_new ("eos",
+      G_TYPE_FROM_CLASS (object_class),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstCameraCapturerClass, eos),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 }
 
 void
@@ -392,52 +796,14 @@ gst_camera_capturer_init_backend (int *argc, char ***argv)
   gst_init (argc, argv);
 }
 
-static gboolean
-gcc_expose_event (GtkWidget * widget, GdkEventExpose * event,
-		  gpointer user_data)
-{
-  GstCameraCapturer *gcc;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_VIDEO_WIDGET (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  gcc = GST_CAMERA_CAPTURER (user_data);
-
-  //Delegate the expose to the widget
-  gst_video_widget_force_expose (widget, event);
-  if (gcc->priv->xoverlay != NULL && !gcc->priv->logo_mode)
-    {
-      gst_x_overlay_expose (gcc->priv->xoverlay);
-    }
-  return TRUE;
-}
-
-static void
-gcc_window_construct (int width, int height, GstCameraCapturer * gcc)
-{
-
-  //Create the Video Widget
-  gcc->priv->video_window = gst_video_widget_new ();
-  gtk_container_add (GTK_CONTAINER (gcc), gcc->priv->video_window);
-  gst_video_widget_set_minimum_size (GST_VIDEO_WIDGET
-				     (gcc->priv->video_window), 120, 80);
-  gst_video_widget_set_source_size (GST_VIDEO_WIDGET
-				    (gcc->priv->video_window), 720, 576);
-  gtk_widget_show (gcc->priv->video_window);
-  g_signal_connect (G_OBJECT (gcc->priv->video_window), "expose_event",
-		    G_CALLBACK (gcc_expose_event), gcc);
-}
-
 GQuark
 gst_camera_capturer_error_quark (void)
 {
-  static GQuark q;		/* 0 */
+  static GQuark q;              /* 0 */
 
-  if (G_UNLIKELY (q == 0))
-    {
-      q = g_quark_from_static_string ("gcc-error-quark");
-    }
+  if (G_UNLIKELY (q == 0)) {
+    q = g_quark_from_static_string ("gcc-error-quark");
+  }
   return q;
 }
 
@@ -445,92 +811,65 @@ GstCameraCapturer *
 gst_camera_capturer_new (gchar * filename, GError ** err)
 {
   GstCameraCapturer *gcc = NULL;
-  GstState state;
 
   gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
 
-  /*Handled by Properties? */
-  gcc->priv->encode_height = 576;
-  gcc->priv->encode_width = 720;
-  gcc->priv->audio_bitrate = 128;
-  gcc->priv->video_bitrate = 5000;
-
-  gcc_window_construct (720, 576, gcc);
-
   gcc->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
 
-  if (!gcc->priv->main_pipeline)
-    {
-      g_set_error (err, GCC_ERROR, GCC_ERROR_PLUGIN_LOAD,
-		   ("Failed to create a GStreamer Bin. "
-		    "Please check your GStreamer installation."));
-      g_object_ref_sink (gcc);
-      g_object_unref (gcc);
-      return NULL;
-    }
+  if (!gcc->priv->main_pipeline) {
+    g_set_error (err, GCC_ERROR, GCC_ERROR_PLUGIN_LOAD,
+        ("Failed to create a GStreamer Bin. "
+            "Please check your GStreamer installation."));
+    g_object_ref_sink (gcc);
+    g_object_unref (gcc);
+    return NULL;
+  }
 
   /* Setup */
-  GST_INFO ("Initializing camerabin");
+  GST_INFO_OBJECT (gcc,"Initializing camerabin");
   gcc->priv->camerabin = gst_element_factory_make ("camerabin", "camerabin");
   gst_bin_add (GST_BIN (gcc->priv->main_pipeline), gcc->priv->camerabin);
 
-  GST_INFO ("Setting capture mode to \"video\"");
+  GST_INFO_OBJECT (gcc,"Setting capture mode to \"video\"");
   g_object_set (gcc->priv->camerabin, "mode", 1, NULL);
 
-  GST_INFO ("Setting video source ");
+  GST_INFO_OBJECT (gcc,"Setting video source ");
   gcc->priv->videosrc = gst_element_factory_make (VIDEOSRC, "videosource");
-  g_object_set (gcc->priv->camerabin, "videosrc", gcc->priv->videosrc, NULL);
+  g_object_set (gcc->priv->camerabin, "video-source", gcc->priv->videosrc,
+      NULL);
   g_object_set (gcc->priv->videosrc, "do-timestamp", TRUE, NULL);
 
-  GST_INFO ("Setting audio source ");
-  gcc->priv->audiosrc =
-    gst_element_factory_make ("dshowaudiosrc", "audiosource");
-  g_object_set (gcc->priv->camerabin, "audiosrc", gcc->priv->audiosrc, NULL);
-
-  /*gcc->priv->videoenc = gst_element_factory_make ("ffenc_mpeg4","videoenc");
-     g_object_set (gcc->priv->camerabin,"videoenc",gcc->priv->videoenc,NULL);
-     gcc->priv->audioenc = gst_element_factory_make ("faac","audioenc");
-     g_object_set (gcc->priv->camerabin,"audioenc",gcc->priv->audioenc,NULL);
-     gcc->priv->videomux = gst_element_factory_make ("avimux","videomux");
-     g_object_set (gcc->priv->camerabin,"videomux",gcc->priv->videomux,NULL); */
-
-
+  GST_INFO_OBJECT (gcc,"Setting audio source ");
+  gcc->priv->audiosrc = gst_element_factory_make (AUDIOSRC, "audiosource");
+  g_object_set (gcc->priv->camerabin, "audio-source", gcc->priv->audiosrc,
+      NULL);
 
-  GST_INFO ("Setting capture mode to \"video\"");
+  GST_INFO_OBJECT (gcc,"Setting capture mode to \"video\"");
   g_object_set (gcc->priv->camerabin, "mode", 1, NULL);
 
   g_object_set (gcc->priv->camerabin, "mute", TRUE, NULL);
 
+  /* assume we're always called from the main Gtk+ GUI thread */
+  gui_thread = g_thread_self ();
+
   /*Connect bus signals */
-  GST_INFO ("Connecting bus signals");
-  gcc->priv->bus =
-    gst_element_get_bus (GST_ELEMENT (gcc->priv->main_pipeline));
+  GST_INFO_OBJECT (gcc,"Connecting bus signals");
+  gcc->priv->bus = gst_element_get_bus (GST_ELEMENT (gcc->priv->main_pipeline));
   gst_bus_add_signal_watch (gcc->priv->bus);
   gcc->priv->sig_bus_async =
-    g_signal_connect (gcc->priv->bus, "message",
-		      G_CALLBACK (gcc_bus_message_cb), gcc);
+      g_signal_connect (gcc->priv->bus, "message",
+      G_CALLBACK (gcc_bus_message_cb), gcc);
 
   /* we want to catch "prepare-xwindow-id" element messages synchronously */
   gst_bus_set_sync_handler (gcc->priv->bus, gst_bus_sync_signal_handler, gcc);
 
   gcc->priv->sig_bus_sync =
-    g_signal_connect (gcc->priv->bus, "sync-message::element",
-		      G_CALLBACK (gcc_element_msg_sync), gcc);
-
+      g_signal_connect (gcc->priv->bus, "sync-message::element",
+      G_CALLBACK (gcc_element_msg_sync), gcc);
 
-  /*gst_element_set_state (gcc->priv->camerabin, GST_STATE_NULL);
-     do
-     {
-     gst_element_get_state(gcc->priv->camerabin, &state, NULL, 
-     GST_CLOCK_TIME_NONE);
-     
-     }
-     while(state != GST_STATE_NULL);      */
-
-  return gcc;
+  return gcc;
 }
 
-
 void
 gst_camera_capturer_run (GstCameraCapturer * gcc)
 {
@@ -538,130 +877,177 @@ gst_camera_capturer_run (GstCameraCapturer * gcc)
 }
 
 void
+gst_camera_capturer_close (GstCameraCapturer * gcc)
+{
+  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+}
+
+void
 gst_camera_capturer_start (GstCameraCapturer * gcc)
 {
   g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "user-start", 0, 0);
+  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-start", 0,
+      0);
 }
 
-
 void
 gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
 {
   g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "user-pause", 0, 0);
+  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-pause", 0,
+      0);
 }
 
 void
 gst_camera_capturer_stop (GstCameraCapturer * gcc)
 {
   g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "user-stop", 0, 0);
+  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-stop", 0, 0);
 }
 
-
 gboolean
 gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
-				       GccVideoEncoderType type)
+    GccVideoEncoderType type, GError ** err)
 {
+  gchar *name = NULL;
+
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
-  switch (type)
-    {
+
+  switch (type) {
     case GCC_VIDEO_ENCODER_TYPE_MPEG4:
       gcc->priv->videoenc =
-	gst_element_factory_make ("ffenc_mpeg4", "videoenc");
-      g_object_set (gcc->priv->camerabin, "videoenc", gcc->priv->videoenc,
-		    NULL);
+          gst_element_factory_make ("ffenc_mpeg4", "video-encoder");
+      name = "FFmpeg mpeg4 video encoder";
       break;
 
     case GCC_VIDEO_ENCODER_TYPE_XVID:
-      gcc->priv->videoenc = gst_element_factory_make ("xvid_enc", "videoenc");
-      g_object_set (gcc->priv->camerabin, "videoenc", gcc->priv->videoenc,
-		    NULL);
+      gcc->priv->videoenc =
+          gst_element_factory_make ("xvidenc", "video-encoder");
+      name = "Xvid video encoder";
       break;
 
     case GCC_VIDEO_ENCODER_TYPE_THEORA:
       gcc->priv->videoenc =
-	gst_element_factory_make ("theoraenc", "videoenc");
-      g_object_set (gcc->priv->camerabin, "videoenc", gcc->priv->videoenc,
-		    NULL);
+          gst_element_factory_make ("theoraenc", "video-encoder");
+      name = "Theora video encoder";
       break;
 
     case GCC_VIDEO_ENCODER_TYPE_H264:
-      gcc->priv->videoenc = gst_element_factory_make ("x264enc", "videoenc");
-      g_object_set (gcc->priv->camerabin, "videoenc", gcc->priv->videoenc,
-		    NULL);
+      gcc->priv->videoenc =
+          gst_element_factory_make ("x264enc", "video-encoder");
+      name = "X264 video encoder";
       break;
-
-    }
+  }
+  if (!gcc->priv->videoenc) {
+    g_set_error (err,
+        GCC_ERROR,
+        GCC_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+  } else {
+    g_object_set (gcc->priv->camerabin, "video-encoder", gcc->priv->videoenc,
+        NULL);
+  }
   return TRUE;
 }
 
 gboolean
 gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
-				       GccAudioEncoderType type)
+    GccAudioEncoderType type, GError ** err)
 {
+  gchar *name = NULL;
+
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
 
-  switch (type)
-    {
+  switch (type) {
     case GCC_AUDIO_ENCODER_MP3:
       gcc->priv->audioenc =
-	gst_element_factory_make ("ffenc_libmp3lame", "audioenc");
-      g_object_set (gcc->priv->camerabin, "audioenc", gcc->priv->audioenc,
-		    NULL);
+          gst_element_factory_make ("lame", "audio-encoder");
+      name = "Mp3 audio encoder";
       break;
 
     case GCC_AUDIO_ENCODER_AAC:
-      gcc->priv->audioenc = gst_element_factory_make ("faac", "audioenc");
-      g_object_set (gcc->priv->camerabin, "audioenc", gcc->priv->audioenc,
-		    NULL);
+      gcc->priv->audioenc = gst_element_factory_make ("faac", "audio-encoder");
+      name = "AAC audio encoder";
       break;
 
     case GCC_AUDIO_ENCODER_VORBIS:
       gcc->priv->audioenc =
-	gst_element_factory_make ("vorbisenc", "audioenc");
-      g_object_set (gcc->priv->camerabin, "audioenc", gcc->priv->audioenc,
-		    NULL);
+          gst_element_factory_make ("vorbisenc", "audio-encoder");
+      name = "Vorbis audio encoder";
       break;
-    }
+  }
+
+  if (!gcc->priv->audioenc) {
+    g_set_error (err,
+        GCC_ERROR,
+        GCC_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+  } else {
+    g_object_set (gcc->priv->camerabin, "audio-encoder", gcc->priv->audioenc,
+        NULL);
+  }
 
   return TRUE;
-
 }
 
 gboolean
 gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
-				     GccVideoMuxerType type)
+    GccVideoMuxerType type, GError ** err)
 {
+  gchar *name = NULL;
+
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
 
-  switch (type)
-    {
+  switch (type) {
     case GCC_VIDEO_MUXER_OGG:
-      gcc->priv->videomux = gst_element_factory_make ("oggmux", "videomux");
-      g_object_set (gcc->priv->camerabin, "videomux", gcc->priv->audioenc,
-		    NULL);
+      name = "OGG muxer";
+      gcc->priv->videomux = gst_element_factory_make ("oggmux", "video-muxer");
       break;
     case GCC_VIDEO_MUXER_AVI:
-      gcc->priv->videomux = gst_element_factory_make ("avimux", "videomux");
-      g_object_set (gcc->priv->camerabin, "videomux", gcc->priv->audioenc,
-		    NULL);
+      name = "AVI muxer";
+      gcc->priv->videomux = gst_element_factory_make ("avimux", "video-muxer");
+      break;
+    case GCC_VIDEO_MUXER_MP4:
+      name = "MP4 muxer";
+      gcc->priv->videomux = gst_element_factory_make ("qtmux", "video-muxer");
       break;
     case GCC_VIDEO_MUXER_MATROSKA:
+      name = "Matroska muxer";
       gcc->priv->videomux =
-	gst_element_factory_make ("matroskamux", "videomux");
-      g_object_set (gcc->priv->camerabin, "videomux", gcc->priv->audioenc,
-		    NULL);
+          gst_element_factory_make ("matroskamux", "video-muxer");
       break;
-    }
+  }
+
+  if (!gcc->priv->videomux) {
+    g_set_error (err,
+        GCC_ERROR,
+        GCC_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", name);
+  } else {
+    g_object_set (gcc->priv->camerabin, "video-muxer", gcc->priv->videomux,
+        NULL);
+  }
 
   return TRUE;
 }
 
-
-
-
+GValueArray *
+gst_camera_capture_enum_devices (GstCameraCapturer * gcc)
+{
+  GstElement *videodevicesrc;
+  GstPropertyProbe *probe;
+  GValueArray *va;
+
+  videodevicesrc = gst_element_factory_make (VIDEOSRC, "source");
+  probe = GST_PROPERTY_PROBE (videodevicesrc);
+  va = gst_property_probe_get_values_name (probe, "device-name");
+  gst_element_set_state (videodevicesrc, GST_STATE_NULL);
+  gst_object_unref (GST_OBJECT (videodevicesrc));
+  return va;
+}
 
 static void
 gcc_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
@@ -674,33 +1060,32 @@ gcc_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
 
   msg_type = GST_MESSAGE_TYPE (message);
 
-  switch (msg_type)
-    {
+  switch (msg_type) {
     case GST_MESSAGE_ERROR:
-      {
-	gcc_error_msg (gcc, message);
-	if (gcc->priv->main_pipeline)
-	  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
-	break;
-      }
+    {
+      gcc_error_msg (gcc, message);
+      if (gcc->priv->main_pipeline)
+        gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+      break;
+    }
 
     case GST_MESSAGE_WARNING:
-      {
-	GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
-	break;
-      }
+    {
+      GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
+      break;
+    }
 
     case GST_MESSAGE_EOS:
-      {
-	GST_INFO ("EOS message");
-	g_signal_emit (gcc, gcc_signals[SIGNAL_EOS], 0);
-	break;
-      }
+    {
+      GST_INFO_OBJECT (gcc,"EOS message");
+      g_signal_emit (gcc, gcc_signals[SIGNAL_EOS], 0);
+      break;
+    }
 
     default:
       GST_LOG ("Unhandled message: %" GST_PTR_FORMAT, message);
       break;
-    }
+  }
 }
 
 static void
@@ -710,59 +1095,66 @@ gcc_error_msg (GstCameraCapturer * gcc, GstMessage * msg)
   gchar *dbg = NULL;
 
   gst_message_parse_error (msg, &err, &dbg);
-  if (err)
-    {
-      GST_ERROR ("message = %s", GST_STR_NULL (err->message));
-      GST_ERROR ("domain  = %d (%s)", err->domain,
-		 GST_STR_NULL (g_quark_to_string (err->domain)));
-      GST_ERROR ("code    = %d", err->code);
-      GST_ERROR ("debug   = %s", GST_STR_NULL (dbg));
-      GST_ERROR ("source  = %" GST_PTR_FORMAT, msg->src);
-
-
-      g_message ("Error: %s\n%s\n", GST_STR_NULL (err->message),
-		 GST_STR_NULL (dbg));
-      g_signal_emit (gcc, gcc_signals[SIGNAL_ERROR], 0, err->message);
-      g_error_free (err);
-    }
+  if (err) {
+    GST_ERROR ("message = %s", GST_STR_NULL (err->message));
+    GST_ERROR ("domain  = %d (%s)", err->domain,
+        GST_STR_NULL (g_quark_to_string (err->domain)));
+    GST_ERROR ("code    = %d", err->code);
+    GST_ERROR ("debug   = %s", GST_STR_NULL (dbg));
+    GST_ERROR ("source  = %" GST_PTR_FORMAT, msg->src);
+
+
+    g_message ("Error: %s\n%s\n", GST_STR_NULL (err->message),
+        GST_STR_NULL (dbg));
+    g_signal_emit (gcc, gcc_signals[SIGNAL_ERROR], 0, err->message);
+    g_error_free (err);
+  }
   g_free (dbg);
 }
 
+static gboolean
+gcc_update_interfaces_delayed (GstCameraCapturer * gcc)
+{
+  GST_DEBUG ("Delayed updating interface implementations");
+  g_mutex_lock (gcc->priv->lock);
+  gcc_update_interface_implementations (gcc);
+  gcc->priv->interface_update_id = 0;
+  g_mutex_unlock (gcc->priv->lock);
+
+  return FALSE;
+}
 
 static void
 gcc_update_interface_implementations (GstCameraCapturer * gcc)
 {
 
-  GstXOverlay *old_xoverlay = gcc->priv->xoverlay;
   GstElement *element = NULL;
 
-  GST_INFO ("Retrieving xoverlay from bin ...");
-  element = gst_bin_get_by_interface (GST_BIN (gcc->priv->camerabin),
-				      GST_TYPE_X_OVERLAY);
+  if (g_thread_self () != gui_thread) {
+    if (gcc->priv->interface_update_id)
+      g_source_remove (gcc->priv->interface_update_id);
+    gcc->priv->interface_update_id =
+        g_idle_add ((GSourceFunc) gcc_update_interfaces_delayed, gcc);
+    return;
+  }
 
-  if (GST_IS_X_OVERLAY (element))
-    {
-      gcc->priv->xoverlay = GST_X_OVERLAY (element);
-    }
-  else
-    {
-      gcc->priv->xoverlay = NULL;
-    }
-  if (old_xoverlay)
-    gst_object_unref (GST_OBJECT (old_xoverlay));
+  GST_INFO_OBJECT (gcc,"Retrieving xoverlay from bin ...");
+  element = gst_bin_get_by_interface (GST_BIN (gcc->priv->camerabin),
+      GST_TYPE_X_OVERLAY);
 
+  if (GST_IS_X_OVERLAY (element)) {
+    gcc->priv->xoverlay = GST_X_OVERLAY (element);
+  } else {
+    gcc->priv->xoverlay = NULL;
+  }
 }
 
 static void
 gcc_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
 {
-
   GstCameraCapturer *gcc = GST_CAMERA_CAPTURER (data);
-  GstElement *video_sink = NULL;
   GstCaps *caps = NULL;
 
-  g_object_get (gcc->priv->camerabin, "vfsink", &video_sink, NULL);
-
   g_assert (msg->type == GST_MESSAGE_ELEMENT);
 
   if (msg->structure == NULL)
@@ -770,42 +1162,28 @@ gcc_element_msg_sync (GstBus * bus, GstMessage * msg, gpointer data)
 
   /* This only gets sent if we haven't set an ID yet. This is our last
    * chance to set it before the video sink will create its own window */
-  if (gst_structure_has_name (msg->structure, "prepare-xwindow-id"))
-    {
-      GdkWindow *window;
-      g_object_get (gcc->priv->camerabin, "filter-caps", &caps, NULL);
-      gcc_parse_video_stream_info (caps, gcc);
-      gst_caps_unref (caps);
+  if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
+    g_object_get (gcc->priv->camerabin, "filter-caps", &caps, NULL);
+    gcc_parse_video_stream_info (caps, gcc);
+    gst_caps_unref (caps);
 
-      g_mutex_lock (gcc->priv->lock);
-      gcc_update_interface_implementations (gcc);
-      g_mutex_unlock (gcc->priv->lock);
+    g_mutex_lock (gcc->priv->lock);
+    gcc_update_interface_implementations (gcc);
+    g_mutex_unlock (gcc->priv->lock);
 
-      g_return_if_fail (gcc->priv->xoverlay != NULL);
-      g_return_if_fail (gcc->priv->video_window != NULL);
+    g_return_if_fail (gcc->priv->xoverlay != NULL);
+    g_return_if_fail (gcc->priv->video_window != NULL);
 
-      GST_INFO ("Setting xwindow: %d", gcc->priv->video_width);
-
-      window =
-	gst_video_widget_get_video_window (GST_VIDEO_WIDGET
-					   (gcc->priv->video_window));
 #ifdef WIN32
-      gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
-				    GDK_WINDOW_HWND (window));
+    gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
+        GDK_WINDOW_HWND (gcc->priv->video_window));
 #else
-      gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
-				    GDK_WINDOW_XID (window));
+    gst_x_overlay_set_xwindow_id (gcc->priv->xoverlay,
+        GDK_WINDOW_XID (gcc->priv->video_window));
 #endif
-
-      GST_INFO ("\nSetting Source size: %d", gcc->priv->video_width);
-      gst_video_widget_set_source_size (GST_VIDEO_WIDGET
-					(gcc->priv->video_window),
-					gcc->priv->video_width,
-					gcc->priv->video_height);
-    }
+  }
 }
 
-
 static int
 gcc_parse_video_stream_info (GstCaps * caps, GstCameraCapturer * gcc)
 {
@@ -816,18 +1194,16 @@ gcc_parse_video_stream_info (GstCaps * caps, GstCameraCapturer * gcc)
 
   /* Get video decoder caps */
   s = gst_caps_get_structure (caps, 0);
-  if (s)
-    {
-      /* We need at least width/height and framerate */
-      if (!
-	  (gst_structure_get_fraction
-	   (s, "framerate", &gcc->priv->video_fps_n, &gcc->priv->video_fps_d)
-	   && gst_structure_get_int (s, "width", &gcc->priv->video_width)
-	   && gst_structure_get_int (s, "height", &gcc->priv->video_height)))
-	return -1;
-      /* Get the movie PAR if available */
-      gcc->priv->movie_par =
-	gst_structure_get_value (s, "pixel-aspect-ratio");
-    }
+  if (s) {
+    /* We need at least width/height and framerate */
+    if (!
+        (gst_structure_get_fraction
+            (s, "framerate", &gcc->priv->video_fps_n, &gcc->priv->video_fps_d)
+            && gst_structure_get_int (s, "width", &gcc->priv->video_width)
+            && gst_structure_get_int (s, "height", &gcc->priv->video_height)))
+      return -1;
+    /* Get the movie PAR if available */
+    gcc->priv->movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
+  }
   return 1;
 }
diff --git a/libcesarplayer/src/gst-camera-capturer.h b/libcesarplayer/src/gst-camera-capturer.h
index 0b2b13d..f6af702 100644
--- a/libcesarplayer/src/gst-camera-capturer.h
+++ b/libcesarplayer/src/gst-camera-capturer.h
@@ -59,7 +59,7 @@ struct _GstCameraCapturerClass
 
 struct _GstCameraCapturer
 {
-  GtkHBox parent_instance;
+  GtkEventBox parent;
   GstCameraCapturerPrivate *priv;
 };
 
@@ -112,36 +112,32 @@ typedef enum
 typedef enum
 {
   GCC_VIDEO_MUXER_AVI,
+  GCC_VIDEO_MUXER_MP4,
   GCC_VIDEO_MUXER_MATROSKA,
   GCC_VIDEO_MUXER_OGG
 } GccVideoMuxerType;
 
 
-EXPORT GType
-gst_camera_capturer_get_type (void)
-  G_GNUC_CONST;
-
-     EXPORT void gst_camera_capturer_init_backend (int *argc, char ***argv);
-     EXPORT GstCameraCapturer *gst_camera_capturer_new (gchar * filename,
-							GError ** err);
-     EXPORT void gst_camera_capturer_run (GstCameraCapturer * gcc);
-     EXPORT void gst_camera_capturer_start (GstCameraCapturer * gcc);
-     EXPORT void gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc);
-     EXPORT void gst_camera_capturer_stop (GstCameraCapturer * gcc);
-     EXPORT gboolean gst_camera_capturer_set_video_encoder (GstCameraCapturer
-							    * gcc,
-							    GccVideoEncoderType
-							    type);
-     EXPORT gboolean gst_camera_capturer_set_audio_encoder (GstCameraCapturer
-							    * gcc,
-							    GccAudioEncoderType
-							    type);
-     EXPORT gboolean gst_camera_capturer_set_video_muxer (GstCameraCapturer *
-							  gcc,
-							  GccVideoMuxerType
-							  type);
-
-
+EXPORT GType gst_camera_capturer_get_type (void)  G_GNUC_CONST;
+
+EXPORT void gst_camera_capturer_init_backend (int *argc, char ***argv);
+EXPORT GstCameraCapturer *gst_camera_capturer_new (gchar * filename,
+                                                  GError ** err);
+EXPORT void gst_camera_capturer_run (GstCameraCapturer * gcc);
+EXPORT void gst_camera_capturer_close (GstCameraCapturer * gcc);
+EXPORT void gst_camera_capturer_start (GstCameraCapturer * gcc);
+EXPORT void gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc);
+EXPORT void gst_camera_capturer_stop (GstCameraCapturer * gcc);
+EXPORT gboolean gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
+                                                      GccVideoEncoderType type,
+                                                      GError ** err);
+EXPORT gboolean gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
+                                                      GccAudioEncoderType type,
+                                                      GError ** err);
+EXPORT gboolean gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
+                                                    GccVideoMuxerType type,
+                                                    GError ** err);
+EXPORT GValueArray gst_camera_capturer_enum_devices (GstCameraCapturer * gcc);
 
 G_END_DECLS
 #endif /* _GST_CAMERA_CAPTURER_H_ */



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