[longomatch/camera_capturer: 1/3] rewrite the camera capturerer to support more sources



commit b03117d3d9e51015ba38bc6e21c14d00b50fa824
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Mon Oct 1 02:20:29 2012 +0200

    rewrite the camera capturerer to support more sources

 libcesarplayer/bacon-video-widget-gst-0.10.c |   20 -
 libcesarplayer/common.h                      |   31 +
 libcesarplayer/gst-camera-capturer.c         | 1515 +++++++++++++++++---------
 libcesarplayer/gst-camera-capturer.h         |   39 +-
 libcesarplayer/gstscreenshot.c               |    3 +-
 libcesarplayer/main.c                        |   32 +-
 libcesarplayer/video-utils.c                 |   29 +-
 libcesarplayer/video-utils.h                 |   33 +-
 8 files changed, 1144 insertions(+), 558 deletions(-)
---
diff --git a/libcesarplayer/bacon-video-widget-gst-0.10.c b/libcesarplayer/bacon-video-widget-gst-0.10.c
index be259d9..2f0aa6f 100644
--- a/libcesarplayer/bacon-video-widget-gst-0.10.c
+++ b/libcesarplayer/bacon-video-widget-gst-0.10.c
@@ -67,16 +67,6 @@
 #include <gtk/gtk.h>
 
 
-#if defined(OSTYPE_WINDOWS)
-#define DEFAULT_VIDEO_SINK "autovideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#elif defined(OSTYPE_OS_X)
-#define DEFAULT_VIDEO_SINK "autovideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#elif defined(OSTYPE_LINUX)
-#define DEFAULT_VIDEO_SINK "gsettingsvideosink"
-#define BACKUP_VIDEO_SINK "autovideosink"
-#endif
 #include <gio/gio.h>
 #include <glib/gi18n.h>
 
@@ -259,9 +249,6 @@ static GThread *gui_thread;
 
 static int bvw_signals[LAST_SIGNAL] = { 0 };
 
-GST_DEBUG_CATEGORY (_totem_gst_debug_cat);
-#define GST_CAT_DEFAULT _totem_gst_debug_cat
-
 
 typedef gchar *(*MsgToStrFunc) (GstMessage * msg);
 
@@ -5405,13 +5392,6 @@ bacon_video_widget_new (int width, int height, BvwUseType type, GError ** err)
   GstElement *audio_sink = NULL, *video_sink = NULL;
   gchar *version_str;
 
-#ifndef GST_DISABLE_GST_INFO
-  if (_totem_gst_debug_cat == NULL) {
-    GST_DEBUG_CATEGORY_INIT (_totem_gst_debug_cat, "totem", 0,
-        "Totem GStreamer Backend");
-  }
-#endif
-
   version_str = gst_version_string ();
   GST_INFO ("Initialised %s", version_str);
   g_free (version_str);
diff --git a/libcesarplayer/common.h b/libcesarplayer/common.h
index cb3ed97..de7999b 100644
--- a/libcesarplayer/common.h
+++ b/libcesarplayer/common.h
@@ -17,6 +17,35 @@
  *
  */
 
+#ifndef __LIBCESARPLAYER_COMMON_H__
+#define __LIBCESARPLAYER_COMMON_H__
+
+/* Default video/audio sinks */
+#if defined(OSTYPE_WINDOWS)
+#define DEFAULT_VIDEO_SINK "autovideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#elif defined(OSTYPE_OS_X)
+#define DEFAULT_VIDEO_SINK "autovideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#elif defined(OSTYPE_LINUX)
+#define DEFAULT_VIDEO_SINK "gsettingsvideosink"
+#define BACKUP_VIDEO_SINK "autovideosink"
+#endif
+
+/*Default video/audio source*/
+#if defined(OSTYPE_WINDOWS)
+#define DVVIDEOSRC "dshowvideosrc"
+#define SYSVIDEOSRC "dshowvideosrc"
+#define AUDIOSRC "dshowaudiosrc"
+#elif defined(OSTYPE_OS_X)
+#define DVVIDEOSRC "dv1394src"
+#define SYSVIDEOSRC "osxvideosrc"
+#define AUDIOSRC "osxaudiosrc"
+#elif defined(OSTYPE_LINUX)
+#define DVVIDEOSRC "dv1394src"
+#define SYSVIDEOSRC "gsettingsvideosrc"
+#define AUDIOSRC "gsettingsaudiosrc"
+#endif
 
 /**
  * Error:
@@ -104,3 +133,5 @@ typedef enum
   VIDEO_MUXER_MPEG_PS,
   VIDEO_MUXER_WEBM
 } VideoMuxerType;
+
+#endif
diff --git a/libcesarplayer/gst-camera-capturer.c b/libcesarplayer/gst-camera-capturer.c
index 58f7f9b..823781e 100644
--- a/libcesarplayer/gst-camera-capturer.c
+++ b/libcesarplayer/gst-camera-capturer.c
@@ -32,23 +32,9 @@
 
 #include "gst-camera-capturer.h"
 #include "gstscreenshot.h"
+#include "common.h"
+#include "video-utils.h"
 
-/*Default video source*/
-#if defined(OSTYPE_WINDOWS)
-#define DVVIDEOSRC "dshowvideosrc"
-#define RAWVIDEOSRC "dshowvideosrc"
-#define AUDIOSRC "dshowaudiosrc"
-#elif defined(OSTYPE_OS_X)
-#define DVVIDEOSRC "osxvideosrc"
-#define RAWVIDEOSRC "osxvideosrc"
-#define AUDIOSRC "osxaudiosrc"
-#elif defined(OSTYPE_LINUX)
-#define DVVIDEOSRC "dv1394src"
-#define RAWVIDEOSRC "gsettingsvideosrc"
-#define AUDIOSRC "gsettingsaudiosrc"
-#define RAWVIDEOSRC_GCONF "gconfvideosrc"
-#define AUDIOSRC_GCONF "gconfaudiosrc"
-#endif
 
 /* gtk+/gnome */
 #include <gdk/gdk.h>
@@ -61,22 +47,8 @@
 #endif
 #include <gtk/gtk.h>
 
-#ifdef WIN32
-#define DEFAULT_SOURCE_TYPE  GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW
-#else
-#define DEFAULT_SOURCE_TYPE  GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW
-#endif
-
-typedef enum
-{
-  GST_CAMERABIN_FLAG_SOURCE_RESIZE = (1 << 0),
-  GST_CAMERABIN_FLAG_SOURCE_COLOR_CONVERSION = (1 << 1),
-  GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION = (1 << 2),
-  GST_CAMERABIN_FLAG_VIEWFINDER_SCALE = (1 << 3),
-  GST_CAMERABIN_FLAG_AUDIO_CONVERSION = (1 << 4),
-  GST_CAMERABIN_FLAG_DISABLE_AUDIO = (1 << 5),
-  GST_CAMERABIN_FLAG_IMAGE_COLOR_CONVERSION = (1 << 6)
-} GstCameraBinFlags;
+GST_DEBUG_CATEGORY (_cesarplayer_gst_debug_cat);
+#define GST_CAT_DEFAULT _cesarplayer_gst_debug_cat
 
 /* Signals */
 enum
@@ -109,13 +81,13 @@ struct GstCameraCapturerPrivate
   gchar *device_id;
   guint output_height;
   guint output_width;
-  guint output_fps_n;
-  guint output_fps_d;
   guint audio_bitrate;
   guint video_bitrate;
   gboolean audio_enabled;
   VideoEncoderType video_encoder_type;
   AudioEncoderType audio_encoder_type;
+  VideoMuxerType video_muxer_type;
+  GstCameraCaptureSourceType source_type;
 
   /*Video input info */
   gint video_width;             /* Movie width */
@@ -127,21 +99,36 @@ struct GstCameraCapturerPrivate
   gint video_fps_d;
   gboolean media_has_video;
   gboolean media_has_audio;
-  GstCameraCaptureSourceType source_type;
 
   /* Snapshots */
   GstBuffer *last_buffer;
 
   /*GStreamer elements */
   GstElement *main_pipeline;
-  GstElement *camerabin;
-  GstElement *videosrc;
-  GstElement *device_source;
-  GstElement *videofilter;
-  GstElement *audiosrc;
-  GstElement *videoenc;
-  GstElement *audioenc;
-  GstElement *videomux;
+  GstElement *source_bin;
+  GstElement *source_decoder_bin;
+  GstElement *decoder_bin;
+  GstElement *preview_bin;
+  GstElement *encoder_bin;
+  GstElement *source;
+  GstElement *video_filter;
+  GstElement *video_enc;
+  GstElement *audio_enc;
+  GstElement *muxer;
+  GstElement *filesink;
+  const gchar *source_element_name;
+
+  /* Recording */
+  gboolean is_recording;
+  gboolean closing_recording;
+  gboolean video_needs_keyframe_sync;
+  gboolean video_synced;
+  GstClockTime accum_recorded_ts;
+  GstClockTime last_accum_recorded_ts;
+  GstClockTime current_recording_start_ts;
+  GstClockTime last_video_buf_ts;
+  GstClockTime last_audio_buf_ts;
+  GMutex *recording_lock;
 
   /*Overlay */
   GstXOverlay *xoverlay;        /* protect with lock */
@@ -180,164 +167,8 @@ static int gcc_get_video_stream_info (GstCameraCapturer * gcc);
 
 G_DEFINE_TYPE (GstCameraCapturer, gst_camera_capturer, GTK_TYPE_EVENT_BOX);
 
-static void
-gst_camera_capturer_init (GstCameraCapturer * object)
-{
-  GstCameraCapturerPrivate *priv;
-  object->priv = priv =
-      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->last_buffer = NULL;
-  priv->source_type = GST_CAMERA_CAPTURE_SOURCE_TYPE_NONE;
-
-  priv->lock = g_mutex_new ();
-}
-
-void
-gst_camera_capturer_finalize (GObject * object)
-{
-  GstCameraCapturer *gcc = (GstCameraCapturer *) object;
-
-  GST_DEBUG_OBJECT (gcc, "Finalizing.");
-  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);
-
-    if (gcc->priv->sig_bus_sync)
-      g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
-
-    gst_object_unref (gcc->priv->bus);
-    gcc->priv->bus = NULL;
-  }
-
-  if (gcc->priv->output_file) {
-    g_free (gcc->priv->output_file);
-    gcc->priv->output_file = NULL;
-  }
-
-  if (gcc->priv->device_id) {
-    g_free (gcc->priv->device_id);
-    gcc->priv->device_id = NULL;
-  }
-
-  if (gcc->priv->logo_pixbuf) {
-    g_object_unref (gcc->priv->logo_pixbuf);
-    gcc->priv->logo_pixbuf = NULL;
-  }
-
-  if (gcc->priv->interface_update_id) {
-    g_source_remove (gcc->priv->interface_update_id);
-    gcc->priv->interface_update_id = 0;
-  }
-
-  if (gcc->priv->last_buffer != NULL)
-    gst_buffer_unref (gcc->priv->last_buffer);
-
-  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;
-  }
-
-  g_mutex_free (gcc->priv->lock);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_camera_capturer_apply_resolution (GstCameraCapturer * gcc)
-{
-  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);
-
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin),
-      "set-video-resolution-fps", gcc->priv->output_width,
-      gcc->priv->output_height, gcc->priv->output_fps_n,
-      gcc->priv->output_fps_d);
-}
-
-static void
-gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
-{
-  gcc->priv->video_bitrate = bitrate;
-  if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
-      gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
-    g_object_set (gcc->priv->videoenc, "bitrate", bitrate * 1000, NULL);
-  else
-    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;
-  if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
-    g_object_set (gcc->priv->audioenc, "bitrate", bitrate, NULL);
-  else
-    g_object_set (gcc->priv->audioenc, "bitrate", 1000 * bitrate, NULL);
-  GST_INFO_OBJECT (gcc, "Changed audio bitrate to :\n%d",
-      gcc->priv->audio_bitrate);
-
-}
-
-static void
-gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
-    gboolean enabled)
-{
-  gint flags;
-  gcc->priv->audio_enabled = enabled;
-
-  g_object_get (gcc->priv->main_pipeline, "flags", &flags, NULL);
-  if (!enabled) {
-    flags &= ~GST_CAMERABIN_FLAG_DISABLE_AUDIO;
-    GST_INFO_OBJECT (gcc, "Audio disabled");
-  } else {
-    flags |= GST_CAMERABIN_FLAG_DISABLE_AUDIO;
-    GST_INFO_OBJECT (gcc, "Audio enabled");
-  }
-}
-
-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);
-
-}
-
-static void
-gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
-    const gchar * device_id)
-{
-  gcc->priv->device_id = g_strdup (device_id);
-  GST_INFO_OBJECT (gcc, "Changed device id/name to :\n%s", device_id);
-}
-
 /***********************************
-*           
+*
 *           GTK Widget
 *
 ************************************/
@@ -649,7 +480,7 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
 
   g_mutex_lock (gcc->priv->lock);
   xoverlay = gcc->priv->xoverlay;
-  if (xoverlay == NULL) {
+  if (xoverlay == NULL && gcc->priv->preview_bin != NULL) {
     gcc_update_interface_implementations (gcc);
     resize_video_window (gcc);
     xoverlay = gcc->priv->xoverlay;
@@ -744,6 +575,157 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
   return TRUE;
 }
 
+/***********************************
+*
+*     Class, Object and Properties
+*
+************************************/
+
+static void
+gst_camera_capturer_init (GstCameraCapturer * object)
+{
+  GstCameraCapturerPrivate *priv;
+  object->priv = priv =
+      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 = 480;
+  priv->output_width = 640;
+  priv->audio_bitrate = 128;
+  priv->video_bitrate = 5000;
+  priv->last_buffer = NULL;
+  priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+  priv->accum_recorded_ts = GST_CLOCK_TIME_NONE;
+  priv->last_accum_recorded_ts = GST_CLOCK_TIME_NONE;
+  priv->last_video_buf_ts = GST_CLOCK_TIME_NONE;
+  priv->last_audio_buf_ts = GST_CLOCK_TIME_NONE;
+  priv->is_recording = FALSE;
+  priv->recording_lock = g_mutex_new();
+
+  priv->lock = g_mutex_new ();
+}
+
+void
+gst_camera_capturer_finalize (GObject * object)
+{
+  GstCameraCapturer *gcc = (GstCameraCapturer *) object;
+
+  GST_DEBUG_OBJECT (gcc, "Finalizing.");
+  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);
+
+    if (gcc->priv->sig_bus_sync)
+      g_signal_handler_disconnect (gcc->priv->bus, gcc->priv->sig_bus_sync);
+
+    gst_object_unref (gcc->priv->bus);
+    gcc->priv->bus = NULL;
+  }
+
+  if (gcc->priv->output_file) {
+    g_free (gcc->priv->output_file);
+    gcc->priv->output_file = NULL;
+  }
+
+  if (gcc->priv->device_id) {
+    g_free (gcc->priv->device_id);
+    gcc->priv->device_id = NULL;
+  }
+
+  if (gcc->priv->logo_pixbuf) {
+    g_object_unref (gcc->priv->logo_pixbuf);
+    gcc->priv->logo_pixbuf = NULL;
+  }
+
+  if (gcc->priv->interface_update_id) {
+    g_source_remove (gcc->priv->interface_update_id);
+    gcc->priv->interface_update_id = 0;
+  }
+
+  if (gcc->priv->last_buffer != NULL)
+    gst_buffer_unref (gcc->priv->last_buffer);
+
+  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;
+  }
+
+  g_mutex_free (gcc->priv->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_camera_capturer_set_video_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+  gcc->priv->video_bitrate = bitrate;
+  if (gcc->priv->video_encoder_type == VIDEO_ENCODER_MPEG4 ||
+      gcc->priv->video_encoder_type == VIDEO_ENCODER_XVID)
+    g_object_set (gcc->priv->video_enc, "bitrate", bitrate * 1000, NULL);
+  else
+    g_object_set (gcc->priv->video_enc, "bitrate", gcc->priv->video_bitrate,
+        NULL);
+  GST_INFO_OBJECT (gcc, "Changed video bitrate to: %d",
+      gcc->priv->video_bitrate);
+}
+
+static void
+gst_camera_capturer_set_audio_bit_rate (GstCameraCapturer * gcc, gint bitrate)
+{
+
+  gcc->priv->audio_bitrate = bitrate;
+  if (gcc->priv->audio_encoder_type == AUDIO_ENCODER_MP3)
+    g_object_set (gcc->priv->audio_enc, "bitrate", bitrate, NULL);
+  else
+    g_object_set (gcc->priv->audio_enc, "bitrate", 1000 * bitrate, NULL);
+  GST_INFO_OBJECT (gcc, "Changed audio bitrate to: %d",
+      gcc->priv->audio_bitrate);
+
+}
+
+static void
+gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
+    gboolean enabled)
+{
+  gcc->priv->audio_enabled = enabled;
+  GST_INFO_OBJECT (gcc, "Audio is %s", enabled ? "enabled": "disabled");
+}
+
+static void
+gst_camera_capturer_set_output_file (GstCameraCapturer * gcc,
+    const gchar * file)
+{
+  gcc->priv->output_file = g_strdup (file);
+  GST_INFO_OBJECT (gcc, "Changed output filename to: %s", file);
+}
+
+static void
+gst_camera_capturer_set_device_id (GstCameraCapturer * gcc,
+    const gchar * device_id)
+{
+  gchar *prop_name;
+
+  gcc->priv->device_id = g_strdup (device_id);
+  if (!g_strcmp0 (gcc->priv->source_element_name, "dv1394src"))
+    prop_name = "guid";
+  else if (!g_strcmp0 (gcc->priv->source_element_name, "v4l2src"))
+    prop_name = "device";
+  else
+    prop_name = "device-name";
+  g_object_set(gcc->priv->source, prop_name, gcc->priv->device_id, NULL);
+  GST_INFO_OBJECT (gcc, "Changed device id/name to: %s", gcc->priv->device_id);
+}
+
 static void
 gst_camera_capturer_set_property (GObject * object, guint property_id,
     const GValue * value, GParamSpec * pspec)
@@ -755,11 +737,9 @@ gst_camera_capturer_set_property (GObject * object, guint property_id,
   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_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));
@@ -890,6 +870,12 @@ gst_camera_capturer_class_init (GstCameraCapturerClass * klass)
       NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
 }
 
+/***********************************
+*
+*           GStreamer
+*
+************************************/
+
 void
 gst_camera_capturer_init_backend (int *argc, char ***argv)
 {
@@ -925,314 +911,694 @@ gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
 }
 
 static void
-cb_new_pad (GstElement * element, GstPad * pad, gpointer data)
+gst_camera_capturer_update_device_id (GstCameraCapturer *gcc)
+{
+  /*FIXME */
+}
+
+static void
+cb_new_pad (GstElement * element, GstPad * pad, GstCameraCapturer *gcc)
 {
   GstCaps *caps;
   const gchar *mime;
-  GstElement *sink;
-  GstBin *bin = GST_BIN (data);
+  GstElement *sink = NULL;
+  GstPad *epad;
+  GstBin *bin = GST_BIN(gcc->priv->source_decoder_bin);
 
-  caps = gst_pad_get_caps (pad);
+  caps = gst_pad_get_caps_reffed (pad);
   mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
   if (g_strrstr (mime, "video")) {
-    sink = gst_bin_get_by_name (bin, "source_video_sink");
-    gst_pad_link (pad, gst_element_get_pad (sink, "sink"));
+    sink = gst_bin_get_by_name (bin, "video-pad");
+  }
+  if (g_strrstr (mime, "audio") && gcc->priv->audio_enabled) {
+    sink = gst_bin_get_by_name (bin, "audio-pad");
+  }
+
+  if (sink != NULL) {
+    epad = gst_element_get_static_pad(sink, "sink");
+    gst_pad_link (pad, epad);
+    gst_object_unref(epad);
+  }
+  gst_caps_unref(caps);
+}
+
+static void
+gst_camera_capturer_create_encoder_bin (GstCameraCapturer *gcc)
+{
+  GstElement *colorspace, *videoscale, *videorate;
+  GstCaps *caps;
+  GstPad *v_sink_pad;
+  gchar *caps_str;
+
+  GST_INFO_OBJECT (gcc, "Creating encoder bin");
+  gcc->priv->encoder_bin = gst_bin_new ("encoder_bin");
+
+  colorspace = gst_element_factory_make("ffmpegcolorspace", NULL);
+  videoscale = gst_element_factory_make("videoscale", NULL);
+  videorate = gst_element_factory_make("videorate", NULL);
+  gcc->priv->video_filter = gst_element_factory_make("capsfilter", NULL);
+  gcc->priv->filesink = gst_element_factory_make("filesink", NULL);
+
+  /* Set caps for the encoding resolution */
+  caps_str = g_strdup_printf("video/x-raw-yuv, width=%d, height=%d",
+      gcc->priv->output_width, gcc->priv->output_height);
+  caps = gst_caps_from_string(caps_str);
+  g_object_set(gcc->priv->video_filter, "caps", caps, NULL);
+  gst_caps_unref(caps);
+  g_free(caps_str);
+
+  g_object_set(videorate, "skip-to-first", TRUE, NULL);
+
+  gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), videoscale, videorate,
+      colorspace, gcc->priv->video_filter, gcc->priv->video_enc,
+      gcc->priv->muxer, gcc->priv->filesink, NULL);
+
+  gst_element_link_many(videoscale, videorate, colorspace, gcc->priv->video_filter,
+      gcc->priv->video_enc, gcc->priv->muxer, NULL);
+  gst_element_link(gcc->priv->muxer, gcc->priv->filesink);
+
+  g_object_set (gcc->priv->filesink, "location", gcc->priv->output_file, NULL);
+
+  /* Create ghost pads */
+  v_sink_pad = gst_element_get_static_pad (videoscale, "sink");
+  gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("video", v_sink_pad));
+  gst_object_unref (GST_OBJECT (v_sink_pad));
+
+  if (gcc->priv->audio_enabled)
+  {
+    GstElement *audioconvert, *audioresample;
+    GstPad *a_sink_pad;
+
+    audioconvert = gst_element_factory_make("audioconvert", NULL);
+    audioresample = gst_element_factory_make("audioresample", NULL);
+
+    gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), audioconvert, audioresample,
+        audioresample, gcc->priv->audio_enc, NULL);
+
+    gst_element_link_many(audioconvert, audioresample, gcc->priv->audio_enc,
+        gcc->priv->muxer, NULL);
+
+    a_sink_pad = gst_element_get_static_pad (audioconvert, "sink");
+    gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("audio", a_sink_pad));
+    gst_object_unref (GST_OBJECT (a_sink_pad));
   }
-  if (g_strrstr (mime, "audio")) {
-    /* Not implemented yet */
+
+  GST_INFO_OBJECT (gcc, "Encoder bin created successfully");
+}
+
+static void
+gst_camera_capturer_create_remuxer_bin (GstCameraCapturer *gcc)
+{
+  GstElement *muxer;
+  GstPad *v_sink_pad;
+
+  GST_INFO_OBJECT (gcc, "Creating remuxer bin");
+  gcc->priv->encoder_bin = gst_bin_new ("encoder_bin");
+  muxer = gst_element_factory_make("qtmux", NULL);
+  gcc->priv->filesink = gst_element_factory_make("filesink", NULL);
+  g_object_set (gcc->priv->filesink, "location", gcc->priv->output_file, NULL);
+
+  gst_bin_add_many(GST_BIN(gcc->priv->encoder_bin), muxer, gcc->priv->filesink, NULL);
+  gst_element_link(muxer, gcc->priv->filesink);
+
+  /* Create ghost pads */
+  v_sink_pad = gst_element_get_request_pad (muxer, "video_%d");
+  gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("video", v_sink_pad));
+  gst_object_unref (v_sink_pad);
+
+  if (gcc->priv->audio_enabled) {
+    GstPad *a_sink_pad;
+
+    /* Create ghost pads */
+    a_sink_pad = gst_element_get_request_pad (muxer, "audio_%d");
+    gst_element_add_pad (gcc->priv->encoder_bin, gst_ghost_pad_new ("audio", a_sink_pad));
+    gst_object_unref (GST_OBJECT (v_sink_pad));
   }
 }
 
-/* On linux GStreamer packages provided by distributions might still have the
- * dv1394src clock bug and the dvdemuxer buffers duration bug. That's why we
- * can't use decodebin2 and we need to force the use of ffdemux_dv */
 static GstElement *
-gst_camera_capture_create_dv1394_source_bin (GstCameraCapturer * gcc)
-{
-  GstElement *bin;
-  GstElement *demuxer;
-  GstElement *queue1;
-  GstElement *decoder;
-  GstElement *queue2;
-  GstElement *deinterlacer;
-  GstElement *colorspace;
-  GstElement *videorate;
-  GstElement *videoscale;
-  GstPad *src_pad;
-
-  bin = gst_bin_new ("videosource");
-  gcc->priv->device_source =
-      gst_element_factory_make (DVVIDEOSRC, "source_device");
-  demuxer = gst_element_factory_make ("ffdemux_dv", NULL);
-  queue1 = gst_element_factory_make ("queue", "source_video_sink");
-  decoder = gst_element_factory_make ("ffdec_dvvideo", NULL);
-  queue2 = gst_element_factory_make ("queue", NULL);
-  deinterlacer = gst_element_factory_make ("ffdeinterlace", NULL);
-  videorate = gst_element_factory_make ("videorate", NULL);
-  colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
-  videoscale = gst_element_factory_make ("videoscale", NULL);
-
-  /* this property needs to be set before linking the element, where the device
-   * id configured in get_caps() */
-  g_object_set (G_OBJECT (gcc->priv->device_source), "guid",
-      g_ascii_strtoull (gcc->priv->device_id, NULL, 0), NULL);
-
-  gst_bin_add_many (GST_BIN (bin), gcc->priv->device_source, demuxer, queue1,
-      decoder, queue2, deinterlacer, colorspace, videorate, videoscale, NULL);
-  gst_element_link (gcc->priv->device_source, demuxer);
-  gst_element_link_many (queue1, decoder, queue2, deinterlacer, videorate,
-      colorspace, videoscale, NULL);
-
-  g_signal_connect (demuxer, "pad-added", G_CALLBACK (cb_new_pad), bin);
+gst_camera_capturer_prepare_raw_source (GstCameraCapturer *gcc)
+{
+  GstElement *bin, *v_identity;
+  GstPad *video_pad, *src_pad;
+
+  GST_INFO_OBJECT (gcc, "Creating raw source");
+
+  gcc->priv->video_needs_keyframe_sync = FALSE;
+
+  gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+  bin = gcc->priv->source_decoder_bin;
+  v_identity = gst_element_factory_make ("identity", NULL);
+
+  gst_bin_add_many (GST_BIN (bin), v_identity, NULL);
+
+  /* add ghostpad */
+  video_pad = gst_element_get_static_pad (v_identity, "src");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+  gst_object_unref (GST_OBJECT (video_pad));
+  src_pad = gst_element_get_static_pad (v_identity, "sink");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
+  gst_object_unref (GST_OBJECT (src_pad));
+
+  gst_camera_capturer_create_encoder_bin(gcc);
+
+  return bin;
+}
+
+static GstElement *
+gst_camera_capturer_prepare_dv_source (GstCameraCapturer *gcc)
+{
+  GstElement *bin, *decodebin, *deinterlacer;
+  GstPad *video_pad, *src_pad;
+
+  GST_INFO_OBJECT (gcc, "Creating dv source");
+
+  gcc->priv->video_needs_keyframe_sync = FALSE;
+
+  gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+  bin = gcc->priv->source_decoder_bin;
+  decodebin = gst_element_factory_make ("decodebin2", NULL);
+  deinterlacer = gst_element_factory_make ("ffdeinterlace", "video-pad");
+
+  gst_bin_add_many (GST_BIN (bin), decodebin, deinterlacer, NULL);
 
   /* add ghostpad */
-  src_pad = gst_element_get_static_pad (videoscale, "src");
-  gst_element_add_pad (bin, gst_ghost_pad_new ("src", src_pad));
+  video_pad = gst_element_get_static_pad (deinterlacer, "src");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+  gst_object_unref (GST_OBJECT (video_pad));
+  src_pad = gst_element_get_static_pad (decodebin, "sink");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
   gst_object_unref (GST_OBJECT (src_pad));
 
+  if (gcc->priv->audio_enabled) {
+    GstElement *audio;
+    GstPad *audio_pad;
+
+    audio = gst_element_factory_make ("identity", "audio-pad");
+
+    gst_bin_add_many (GST_BIN (bin), audio, NULL);
+
+    /* add ghostpad */
+    audio_pad = gst_element_get_static_pad (audio, "src");
+    gst_element_add_pad (bin, gst_ghost_pad_new ("audio", audio_pad));
+    gst_object_unref (GST_OBJECT (audio_pad));
+  }
+
+  g_signal_connect (decodebin, "pad-added", G_CALLBACK (cb_new_pad), gcc);
+
+  gst_camera_capturer_create_encoder_bin(gcc);
+
   return bin;
 }
 
 static GstElement *
-gst_camera_capture_create_dshow_source_bin (GstCameraCapturer * gcc)
-{
-  GstElement *bin;
-  GstElement *decoder;
-  GstElement *deinterlacer;
-  GstElement *colorspace;
-  GstElement *videorate;
-  GstElement *videoscale;
-  GstPad *src_pad;
-  GstCaps *source_caps;
-
-  bin = gst_bin_new ("videosource");
-  gcc->priv->device_source =
-      gst_element_factory_make (DVVIDEOSRC, "source_device");
-  decoder = gst_element_factory_make ("decodebin2", NULL);
-  colorspace = gst_element_factory_make ("ffmpegcolorspace",
-      "source_video_sink");
-  deinterlacer = gst_element_factory_make ("ffdeinterlace", NULL);
-  videorate = gst_element_factory_make ("videorate", NULL);
-  videoscale = gst_element_factory_make ("videoscale", NULL);
-
-  /* this property needs to be set before linking the element, where the device
-   * id configured in get_caps() */
-  g_object_set (G_OBJECT (gcc->priv->device_source), "device-name",
-      gcc->priv->device_id, NULL);
-
-  gst_bin_add_many (GST_BIN (bin), gcc->priv->device_source, decoder,
-      colorspace, deinterlacer, videorate, videoscale, NULL);
-  source_caps =
-      gst_caps_from_string ("video/x-dv, systemstream=true;"
-      "video/x-raw-rgb; video/x-raw-yuv");
-  gst_element_link_filtered (gcc->priv->device_source, decoder, source_caps);
-  gst_element_link_many (colorspace, deinterlacer, videorate, videoscale, NULL);
-
-  g_signal_connect (decoder, "pad-added", G_CALLBACK (cb_new_pad), bin);
+gst_camera_capturer_prepare_mpegts_source (GstCameraCapturer *gcc)
+{
+  GstElement *bin, *demuxer,  *video, *video_parser;
+  GstPad *video_pad, *src_pad;
+
+  GST_INFO_OBJECT (gcc, "Creating mpegts source");
+
+  gcc->priv->video_needs_keyframe_sync = TRUE;
+  gcc->priv->video_synced = FALSE;
+
+  /* We don't want to reencode, only remux */
+  gcc->priv->source_decoder_bin = gst_bin_new ("decoder");
+  bin = gcc->priv->source_decoder_bin;
+  demuxer = gst_element_factory_make ("mpegtsdemux", NULL);
+  video_parser = gst_element_factory_make ("h264parse", "video-pad");
+  video = gst_element_factory_make ("capsfilter", NULL);
+  g_object_set(video, "caps", gst_caps_from_string("video/x-h264, stream-format=avc, alignment=au"), NULL);
+
+  gst_bin_add_many (GST_BIN (bin), demuxer, video_parser, video, NULL);
+  gst_element_link(video_parser, video);
 
   /* add ghostpad */
-  src_pad = gst_element_get_static_pad (videoscale, "src");
-  gst_element_add_pad (bin, gst_ghost_pad_new ("src", src_pad));
+  video_pad = gst_element_get_static_pad (video, "src");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("video", video_pad));
+  gst_object_unref (GST_OBJECT (video_pad));
+  src_pad = gst_element_get_static_pad (demuxer, "sink");
+  gst_element_add_pad (bin, gst_ghost_pad_new ("sink", src_pad));
   gst_object_unref (GST_OBJECT (src_pad));
 
-  return bin;
-}
+  if (gcc->priv->audio_enabled) {
+    GstElement *audio;
+    GstPad *audio_pad;
+
+    audio = gst_element_factory_make ("identity", "audio-pad");
+
+    gst_bin_add_many (GST_BIN (bin), audio, NULL);
+
+    /* add ghostpad */
+    audio_pad = gst_element_get_static_pad (audio, "src");
+    gst_element_add_pad (bin, gst_ghost_pad_new ("audio", audio_pad));
+    gst_object_unref (GST_OBJECT (audio_pad));
+  }
+
+  g_signal_connect (demuxer, "pad-added", G_CALLBACK (cb_new_pad), gcc);
+
+  gst_camera_capturer_create_remuxer_bin(gcc);
+
+  return bin;
+}
+
+static gboolean
+gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
+    GstMiniObject *data, gboolean is_video)
+{
+  GstClockTime buf_ts, new_buf_ts;
+  gboolean ret = FALSE;
+
+  g_mutex_lock(gcc->priv->recording_lock);
+
+  /* Event handling, forward everything except new segment events since we are
+   * encoding and we need continuous timestamps on segment starting from 0 */
+  if (GST_IS_EVENT(data)) {
+    GstEvent *event = (GstEvent*) data;
+
+    if (!gcc->priv->is_recording && !gcc->priv->closing_recording) {
+      GST_LOG_OBJECT (gcc, "Dropping event on %s pad", is_video ? "video": "audio");
+      ret = FALSE;
+      goto done;
+    }
+
+    GST_DEBUG_OBJECT (gcc, "Received new event on the %s pad", is_video ? "video": "audio");
+    if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
+      GST_DEBUG_OBJECT (gcc, "Dropping NEWSEGMENT event");
+      ret = FALSE;
+    } else {
+      GST_DEBUG_OBJECT (gcc, "Forwarding event");
+      ret = TRUE;
+    }
+  } else {
+    GstBuffer *buf = (GstBuffer*) data;
+
+    if (!gcc->priv->is_recording) {
+      /* Drop buffers if we are not recording */
+      GST_LOG_OBJECT (gcc, "Dropping buffer on %s pad", is_video ? "video": "audio");
+      ret = FALSE;
+    } else {
+      GstClockTime duration;
+
+      /* If we are just remuxing, drop everything until we see a keyframe */
+      if (gcc->priv->video_needs_keyframe_sync && !gcc->priv->video_synced) {
+        if (is_video && !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+          gcc->priv->video_synced = TRUE;
+        } else {
+          GST_LOG_OBJECT (gcc, "Waiting for a keyframe, "
+              "dropping buffer on %s pad", is_video ? "video": "audio");
+          ret = FALSE;
+          goto done;
+        }
+      }
+
+      buf_ts = GST_BUFFER_TIMESTAMP(buf);
+      duration = GST_BUFFER_DURATION(buf);
+      if (duration == GST_CLOCK_TIME_NONE)
+        duration = 0;
+
+      /* Check if it's the first buffer after starting or restarting the capture
+       * and update the timestamps accordingly */
+      if (G_UNLIKELY(gcc->priv->current_recording_start_ts == GST_CLOCK_TIME_NONE)) {
+        gcc->priv->current_recording_start_ts = buf_ts;
+        gcc->priv->last_accum_recorded_ts = gcc->priv->accum_recorded_ts;
+        GST_INFO_OBJECT (gcc, "Starting recording at %" GST_TIME_FORMAT,
+            GST_TIME_ARGS(gcc->priv->last_accum_recorded_ts));
+      }
+
+      /* Clip buffers that are not in the segment */
+      if (buf_ts < gcc->priv->current_recording_start_ts) {
+        ret = FALSE;
+        goto done;
+      }
+
+      if (buf_ts != GST_CLOCK_TIME_NONE) {
+        /* Get the buffer timestamp with respect of the encoding time and not
+         * the playing time for a continous stream in the encoders input */
+        new_buf_ts = buf_ts - gcc->priv->current_recording_start_ts + gcc->priv->last_accum_recorded_ts;
+
+        /* Store the last timestamp seen on this pad */
+        if (is_video)
+          gcc->priv->last_video_buf_ts = new_buf_ts;
+        else
+          gcc->priv->last_audio_buf_ts = new_buf_ts;
+
+        /* Update the highest encoded timestamp */
+        if (new_buf_ts + duration > gcc->priv->accum_recorded_ts)
+          gcc->priv->accum_recorded_ts = new_buf_ts + duration;
+      } else {
+        /* h264parse only sets the timestamp on the first buffer if a frame is
+         * split in several ones. Other parsers might do the same. We only set
+         * the last timestamp seen on the pad */
+        if (is_video)
+          new_buf_ts = gcc->priv->last_video_buf_ts;
+        else
+          new_buf_ts = gcc->priv->last_audio_buf_ts;
+      }
+
+      /* We don't want to overwrite timestamps of the preview branch */
+      buf = gst_buffer_make_metadata_writable(buf);
+      data = (GstMiniObject*) buf;
+      GST_BUFFER_TIMESTAMP(buf) = new_buf_ts;
+
+      GST_LOG_OBJECT(gcc, "Pushing %s frame to the encoder in ts:% " GST_TIME_FORMAT
+          " out ts: %" GST_TIME_FORMAT, is_video ? "video": "audio",
+          GST_TIME_ARGS(buf_ts), GST_TIME_ARGS(new_buf_ts));
+      ret = TRUE;
+    }
+  }
+
+done:
+  {
+    g_mutex_unlock(gcc->priv->recording_lock);
+    return ret;
+  }
+}
+
+static gboolean
+gst_camera_capturer_audio_encoding_probe (GstPad *pad, GstMiniObject *data,
+    GstCameraCapturer *gcc)
+{
+  return gst_camera_capturer_encoding_retimestamper(gcc, data, FALSE);
+}
+
+static gboolean
+gst_camera_capturer_video_encoding_probe (GstPad *pad, GstMiniObject *data,
+    GstCameraCapturer *gcc)
+{
+  return gst_camera_capturer_encoding_retimestamper(gcc, data, TRUE);
+}
+
+static void
+gst_camera_capturer_create_decoder_bin (GstCameraCapturer *gcc, GstElement *decoder_bin)
+{
+  /*    decoder --> atee --> audio_queue
+   *            |        |
+   *            |        --> audio_preview_queue
+   *            |
+   *            --> vtee --> video_queue
+   *                     \
+   *                     --> video_preview_queue
+   */
+
+  GstElement *video_tee, *v_queue, *v_prev_queue;
+  GstPad *v_dec_pad, *v_tee_pad;
+  GstPad *v_queue_pad, *v_prev_queue_pad;
+  GstPad *dec_sink_pad;
+
+  GST_INFO_OBJECT(gcc, "Creating decoder bin");
+  /* Create elements */
+  gcc->priv->decoder_bin = gst_bin_new("decoder_bin");
+  video_tee = gst_element_factory_make("tee", NULL);
+  v_queue = gst_element_factory_make("queue2", "video-queue");
+  v_prev_queue = gst_element_factory_make("queue2", "video-preview-queue");
+
+  g_object_set(v_queue, "max-size-time", 1 * GST_SECOND, NULL);
+  g_object_set(v_prev_queue, "max-size-bytes", 0,  NULL);
+
+  gst_bin_add_many(GST_BIN(gcc->priv->decoder_bin), decoder_bin, video_tee, v_queue,
+      v_prev_queue, NULL);
+
+  /* Link tees to queues */
+  gst_element_link(video_tee, v_prev_queue);
+  gst_element_link(video_tee, v_queue);
+
+  /* link decoder to the tees */
+  v_dec_pad = gst_element_get_static_pad(decoder_bin, "video");
+  v_tee_pad = gst_element_get_static_pad(video_tee, "sink");
+  gst_pad_link(v_dec_pad, v_tee_pad);
+  gst_object_unref(v_dec_pad);
+  gst_object_unref(v_tee_pad);
+
+  /* Create ghost pads */
+  v_queue_pad = gst_element_get_static_pad(v_queue, "src");
+  v_prev_queue_pad = gst_element_get_static_pad(v_prev_queue, "src");
+  dec_sink_pad = gst_element_get_static_pad(decoder_bin, "sink");
+  gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("video", v_queue_pad));
+  gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("video_preview", v_prev_queue_pad));
+  gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("sink", dec_sink_pad));
+  gst_object_unref(v_queue_pad);
+  gst_object_unref(v_prev_queue_pad);
+  gst_object_unref(dec_sink_pad);
+
+  /* Add pad probes for the encoding branch */
+  v_queue_pad = gst_element_get_static_pad(v_queue, "sink");
+  gst_pad_add_data_probe(v_queue_pad, (GCallback) gst_camera_capturer_video_encoding_probe, gcc);
+  gst_object_unref(v_queue_pad);
+
+  if (gcc->priv->audio_enabled) {
+    GstElement *audio_tee, *a_queue, *a_prev_queue;
+    GstPad *a_dec_pad, *a_tee_pad;
+    GstPad *a_queue_pad, *a_prev_queue_pad;
+
+    /* Create elements */
+    audio_tee = gst_element_factory_make("tee", NULL);
+    a_queue = gst_element_factory_make("queue2", "audio-queue");
+    a_prev_queue = gst_element_factory_make("queue2", "audio-preview-queue");
+
+    g_object_set(a_queue, "max-size-time", 1 * GST_SECOND,  NULL);
+
+    gst_bin_add_many(GST_BIN(gcc->priv->decoder_bin), audio_tee, a_queue,
+        a_prev_queue, NULL);
+
+    /* Link tees to queues */
+    gst_element_link(audio_tee, a_prev_queue);
+    gst_element_link(audio_tee, a_queue);
+
+    /* link decoder to the tees */
+    a_dec_pad = gst_element_get_static_pad(decoder_bin, "audio");
+    a_tee_pad = gst_element_get_static_pad(audio_tee, "sink");
+    gst_pad_link(a_dec_pad, a_tee_pad);
+    gst_object_unref(a_dec_pad);
+    gst_object_unref(a_tee_pad);
+
+    /* Create ghost pads */
+    a_queue_pad = gst_element_get_static_pad(a_queue, "src");
+    a_prev_queue_pad = gst_element_get_static_pad(a_prev_queue, "src");
+    gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("audio", a_queue_pad));
+    gst_element_add_pad (gcc->priv->decoder_bin, gst_ghost_pad_new ("audio_preview", a_prev_queue_pad));
+    gst_object_unref(a_queue_pad);
+    gst_object_unref(a_prev_queue_pad);
+
+    /* Add pad probes for the encoding branch */
+    a_queue_pad = gst_element_get_static_pad(a_queue, "sink");
+    gst_pad_add_data_probe(a_queue_pad, (GCallback) gst_camera_capturer_audio_encoding_probe, gcc);
+    gst_object_unref(a_queue_pad);
+  }
+}
+
+static void
+gst_camera_capturer_link_encoder_bin (GstCameraCapturer *gcc)
+{
+  GstPad *v_dec_pad, *v_enc_pad;
+
+  GST_INFO_OBJECT(gcc, "Linking encoder bin");
+
+  gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->encoder_bin);
+
+  v_dec_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "video");
+  v_enc_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
+  gst_pad_link(v_dec_pad, v_enc_pad);
+  gst_object_unref(v_dec_pad);
+  gst_object_unref(v_enc_pad);
+
+  if (gcc->priv->audio_enabled) {
+    GstPad *a_dec_pad, *a_enc_pad;
+
+    a_dec_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "audio");
+    a_enc_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
+    gst_pad_link(a_dec_pad, a_enc_pad);
+    gst_object_unref(a_dec_pad);
+    gst_object_unref(a_enc_pad);
+  }
+
+  gst_element_set_state(gcc->priv->encoder_bin, GST_STATE_PLAYING);
+}
+
+static void
+gst_camera_capturer_link_preview (GstCameraCapturer *gcc)
+{
+  GstPad *v_dec_prev_pad, *v_prev_pad;
+
+  GST_INFO_OBJECT(gcc, "Linking preview bin");
+
+  gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->decoder_bin);
+
+  gst_element_link(gcc->priv->source_bin, gcc->priv->decoder_bin);
+
+  v_dec_prev_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "video_preview");
+  v_prev_pad = gst_element_get_static_pad(gcc->priv->preview_bin, "video");
+
+  gst_pad_link(v_dec_prev_pad, v_prev_pad);
 
-gboolean
-gst_camera_capturer_set_source (GstCameraCapturer * gcc,
-    GstCameraCaptureSourceType source_type, GError ** err)
-{
-  GstPad *videosrcpad;
+  gst_object_unref(v_dec_prev_pad);
+  gst_object_unref(v_prev_pad);
 
-  g_return_val_if_fail (gcc != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
+  if (gcc->priv->audio_enabled) {
+    GstPad *a_dec_prev_pad, *a_prev_pad;
 
-  if (gcc->priv->source_type == source_type)
-    return TRUE;
-  gcc->priv->source_type = source_type;
+    a_dec_prev_pad = gst_element_get_static_pad(gcc->priv->decoder_bin, "audio_preview");
+    a_prev_pad = gst_element_get_static_pad(gcc->priv->preview_bin, "audio");
 
-  switch (gcc->priv->source_type) {
-    case GST_CAMERA_CAPTURE_SOURCE_TYPE_DV:
-    {
-      gcc->priv->videosrc = gst_camera_capture_create_dv1394_source_bin (gcc);
-      /*gcc->priv->audiosrc = gcc->priv->videosrc; */
-      break;
-    }
-    case GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW:
-    {
-      gcc->priv->videosrc = gst_camera_capture_create_dshow_source_bin (gcc);
-      /*gcc->priv->audiosrc = gcc->priv->videosrc; */
-      break;
-    }
-    case GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW:
-    default:
-    {
-      gchar *videosrc = RAWVIDEOSRC;
-
-#if defined(OSTYPE_LINUX)
-      GstElementFactory *fact = gst_element_factory_find(RAWVIDEOSRC);
-      if (fact == NULL)
-        videosrc = RAWVIDEOSRC_GCONF;
-      else
-        gst_object_unref (fact);
-#endif
+    gst_pad_link(a_dec_prev_pad, a_prev_pad);
 
-      gchar *bin =
-          g_strdup_printf ("%s name=device_source ! videorate ! "
-          "ffmpegcolorspace ! videoscale", videosrc);
-      gcc->priv->videosrc = gst_parse_bin_from_description (bin, TRUE, err);
-      gcc->priv->device_source =
-          gst_bin_get_by_name (GST_BIN (gcc->priv->videosrc), "device_source");
-      gcc->priv->audiosrc = gst_element_factory_make (AUDIOSRC, "audiosource");
-      break;
-    }
-  }
-  if (*err) {
-    GST_ERROR_OBJECT (gcc, "Error changing source: %s", (*err)->message);
-    return FALSE;
+    gst_object_unref(a_dec_prev_pad);
+    gst_object_unref(a_prev_pad);
   }
+  gst_element_set_state(gcc->priv->decoder_bin, GST_STATE_PLAYING);
+}
 
-  g_object_set (gcc->priv->camerabin, "video-source", gcc->priv->videosrc,
-      NULL);
+static void
+cb_new_prev_pad (GstElement * element, GstPad * pad, GstElement *bin)
+{
+  GstPad *sink_pad;
 
-  /* Install pad probe to store the last buffer */
-  videosrcpad = gst_element_get_pad (gcc->priv->videosrc, "src");
-  gst_pad_add_buffer_probe (videosrcpad,
-      G_CALLBACK (gst_camera_capture_videosrc_buffer_probe), gcc);
-  return TRUE;
+  sink_pad = gst_element_get_static_pad(bin, "sink");
+  gst_pad_link(pad, sink_pad);
+  gst_object_unref(sink_pad);
 }
 
-GstCameraCapturer *
-gst_camera_capturer_new (gchar * filename, GError ** err)
+static void
+gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
 {
-  GstCameraCapturer *gcc = NULL;
-  gchar *plugin;
-  gint flags = 0;
+  GstElement *v_decoder, *video_bin;
+  GstPad *video_pad;
 
-  gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
-
-  gcc->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
+  v_decoder = gst_element_factory_make("decodebin2", "preview-decoder");
 
-  if (!gcc->priv->main_pipeline) {
-    plugin = "pipeline";
-    goto missing_plugin;
-  }
+  video_bin = gst_parse_bin_from_description(
+      "videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, NULL);
 
-  /* Setup */
-  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);
-  if (!gcc->priv->camerabin) {
-    plugin = "camerabin";
-    goto missing_plugin;
-  }
-  GST_INFO_OBJECT (gcc, "Setting capture mode to \"video\"");
-  g_object_set (gcc->priv->camerabin, "mode", 1, NULL);
+  gcc->priv->preview_bin = gst_bin_new("preview_bin");
+  gst_bin_add_many (GST_BIN(gcc->priv->preview_bin), v_decoder, video_bin, NULL);
 
+  g_signal_connect (v_decoder, "pad-added", G_CALLBACK (cb_new_prev_pad), video_bin);
 
-  GST_INFO_OBJECT (gcc, "Disabling audio");
-  flags = GST_CAMERABIN_FLAG_DISABLE_AUDIO;
-#ifdef WIN32
-  flags |= GST_CAMERABIN_FLAG_VIEWFINDER_COLOR_CONVERSION;
-#endif
-  g_object_set (gcc->priv->camerabin, "flags", flags, NULL);
+  /* Create ghost pads */
+  video_pad = gst_element_get_static_pad (v_decoder, "sink");
+  gst_element_add_pad (gcc->priv->preview_bin, gst_ghost_pad_new ("video", video_pad));
+  gst_object_unref (GST_OBJECT (video_pad));
 
-  /* assume we're always called from the main Gtk+ GUI thread */
-  gui_thread = g_thread_self ();
+  if (gcc->priv->audio_enabled) {
+    GstElement *a_decoder, *audio_bin;
+    GstPad *audio_pad;
 
-  /*Connect bus signals */
-  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);
+    a_decoder = gst_element_factory_make("decodebin2", NULL);
 
-  /* we want to catch "prepare-xwindow-id" element messages synchronously */
-  gst_bus_set_sync_handler (gcc->priv->bus, gst_bus_sync_signal_handler, gcc);
+    audio_bin = gst_parse_bin_from_description(
+        "audioconvert ! audioresample ! autoaudiosink name=audiosink", TRUE, NULL);
 
-  gcc->priv->sig_bus_sync =
-      g_signal_connect (gcc->priv->bus, "sync-message::element",
-      G_CALLBACK (gcc_element_msg_sync), gcc);
+    gst_bin_add_many (GST_BIN(gcc->priv->preview_bin), a_decoder, audio_bin, NULL);
 
-  return gcc;
+    g_signal_connect (a_decoder, "pad-added", G_CALLBACK (cb_new_prev_pad), audio_bin);
 
-/* Missing plugin */
-missing_plugin:
-  {
-    g_set_error (err, GCC_ERROR, GST_ERROR_PLUGIN_LOAD,
-        ("Failed to create a GStreamer element. "
-            "The element \"%s\" is missing. "
-            "Please check your GStreamer installation."), plugin);
-    g_object_ref_sink (gcc);
-    g_object_unref (gcc);
-    return NULL;
+    /* Create ghost pads */
+    audio_pad = gst_element_get_static_pad (a_decoder, "sink");
+    gst_element_add_pad (gcc->priv->preview_bin, gst_ghost_pad_new ("audio", audio_pad));
+    gst_object_unref (GST_OBJECT (audio_pad));
   }
+
+  gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->preview_bin);
+  gst_element_set_state(gcc->priv->preview_bin, GST_STATE_PLAYING);
 }
 
-void
-gst_camera_capturer_run (GstCameraCapturer * gcc)
+static gboolean
+gst_camera_capturer_have_type_cb (GstElement *typefind, guint prob,
+    GstCaps *caps, GstCameraCapturer *gcc)
 {
-  GError *err = NULL;
+  GstCaps *media_caps;
+  GstElement *decoder_bin = NULL;
 
-  g_return_if_fail (gcc != NULL);
-  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+  GST_INFO_OBJECT (gcc, "Found type with caps %s", gst_caps_to_string(caps));
 
-  /* the source needs to be created before the 'device-is' is set
-   * because dshowsrcwrapper can't change the device-name after
-   * it has been linked for the first time */
-  if (!gcc->priv->videosrc)
-    gst_camera_capturer_set_source (gcc, gcc->priv->source_type, &err);
-  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
-}
+  /* Check for DV streams */
+  media_caps = gst_caps_from_string("video/x-dv, systemstream=true");
 
-void
-gst_camera_capturer_close (GstCameraCapturer * gcc)
-{
-  g_return_if_fail (gcc != NULL);
-  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+  if (gst_caps_can_intersect(caps, media_caps)) {
+    decoder_bin = gst_camera_capturer_prepare_dv_source(gcc);
+    gst_caps_unref(media_caps);
+  }
 
-  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
-}
+  /* Check for MPEG-TS streams */
+  media_caps = gst_caps_from_string("video/mpegts");
+  if (gst_caps_can_intersect(caps, media_caps)) {
+    decoder_bin = gst_camera_capturer_prepare_mpegts_source(gcc);
+    gst_caps_unref(media_caps);
+  }
 
-void
-gst_camera_capturer_start (GstCameraCapturer * gcc)
-{
-  g_return_if_fail (gcc != NULL);
-  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+  /* Check for Raw streams */
+  media_caps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
+  if (gst_caps_can_intersect(caps, media_caps)) {
+    gcc->priv->audio_enabled = FALSE;
+    decoder_bin = gst_camera_capturer_prepare_raw_source(gcc);
+    gst_caps_unref(media_caps);
+  }
 
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-start", 0,
-      0);
+  if (decoder_bin != NULL) {
+    gst_camera_capturer_create_decoder_bin(gcc, decoder_bin);
+    gst_camera_capturer_create_preview(gcc);
+
+    gst_camera_capturer_link_preview(gcc);
+    gst_element_set_state(gcc->priv->main_pipeline, GST_STATE_PLAYING);
+  } else {
+    /* FIXME: post error */
+  }
+  return TRUE;
 }
 
-void
-gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
+static gboolean
+gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
+    GstCameraCaptureSourceType type, GError ** err)
 {
-  g_return_if_fail (gcc != NULL);
-  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+  GstElement *typefind;
+  const gchar *source_desc = "";
+  gchar *source_str;
 
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-pause", 0,
-      0);
-}
+  g_return_val_if_fail (gcc != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
 
-void
-gst_camera_capturer_stop (GstCameraCapturer * gcc)
-{
-  g_return_if_fail (gcc != NULL);
-  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+  switch (type) {
+    case GST_CAMERA_CAPTURE_SOURCE_TYPE_DV:
+      GST_INFO_OBJECT(gcc, "Creating dv video source");
+      source_desc = DVVIDEOSRC;
+      gcc->priv->source_element_name = source_desc;
+      break;
+    case GST_CAMERA_CAPTURE_SOURCE_TYPE_SYSTEM:
+      GST_INFO_OBJECT(gcc, "Creating system video source");
+      source_desc = SYSVIDEOSRC;
+      gcc->priv->source_element_name = source_desc;
+      //source_desc = "filesrc location=/home/andoni/test.ts";
+      break;
+    default:
+      g_assert_not_reached();
+  }
 
-#ifdef WIN32
-  //On windows we can't handle device disconnections until dshowvideosrc
-  //supports it. When a device is disconnected, the source is locked
-  //in ::create(), blocking the streaming thread. We need to change its
-  //state to null, this way camerabin doesn't block in ::do_stop().
-  gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
-#endif
-  g_signal_emit_by_name (G_OBJECT (gcc->priv->camerabin), "capture-stop", 0, 0);
+  source_str = g_strdup_printf("%s name=source ! typefind name=typefind", source_desc);
+  gcc->priv->source_bin = gst_parse_bin_from_description(source_str, TRUE, NULL);
+  g_free(source_str);
+  if (!gcc->priv->source_bin) {
+    g_set_error (err,
+        GCC_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the %s element. "
+        "Please check your GStreamer installation.", source_desc);
+    return FALSE;
+  }
+  gcc->priv->source_type = type;
+
+  typefind = gst_bin_get_by_name (GST_BIN(gcc->priv->source_bin), "typefind");
+  g_signal_connect (typefind, "have-type",
+      G_CALLBACK (gst_camera_capturer_have_type_cb), gcc);
+
+  gst_camera_capturer_update_device_id(gcc);
+
+  GST_INFO_OBJECT(gcc, "Created video source %s", source_desc);
+
+  return TRUE;
 }
 
-gboolean
-gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_create_video_encoder (GstCameraCapturer * gcc,
     VideoEncoderType type, GError ** err)
 {
   gchar *name = NULL;
@@ -1242,63 +1608,63 @@ gst_camera_capturer_set_video_encoder (GstCameraCapturer * gcc,
 
   switch (type) {
     case VIDEO_ENCODER_MPEG4:
-      gcc->priv->videoenc =
+      gcc->priv->video_enc =
           gst_element_factory_make ("ffenc_mpeg4", "video-encoder");
-      g_object_set (gcc->priv->videoenc, "pass", 512,
+      g_object_set (gcc->priv->video_enc, "pass", 512,
           "max-key-interval", -1, NULL);
       name = "FFmpeg mpeg4 video encoder";
       break;
 
     case VIDEO_ENCODER_XVID:
-      gcc->priv->videoenc =
+      gcc->priv->video_enc =
           gst_element_factory_make ("xvidenc", "video-encoder");
-      g_object_set (gcc->priv->videoenc, "pass", 1,
+      g_object_set (gcc->priv->video_enc, "pass", 1,
           "profile", 146, "max-key-interval", -1, NULL);
       name = "Xvid video encoder";
       break;
 
     case VIDEO_ENCODER_H264:
-      gcc->priv->videoenc =
+      gcc->priv->video_enc =
           gst_element_factory_make ("x264enc", "video-encoder");
-      g_object_set (gcc->priv->videoenc, "key-int-max", 25, "pass", 17,
+      g_object_set (gcc->priv->video_enc, "key-int-max", 25, "pass", 17,
           "speed-preset", 3, NULL);
       name = "X264 video encoder";
       break;
 
     case VIDEO_ENCODER_THEORA:
-      gcc->priv->videoenc =
+      gcc->priv->video_enc =
           gst_element_factory_make ("theoraenc", "video-encoder");
-      g_object_set (gcc->priv->videoenc, "keyframe-auto", FALSE,
+      g_object_set (gcc->priv->video_enc, "keyframe-auto", FALSE,
           "keyframe-force", 25, NULL);
       name = "Theora video encoder";
       break;
 
     case VIDEO_ENCODER_VP8:
     default:
-      gcc->priv->videoenc =
+      gcc->priv->video_enc =
           gst_element_factory_make ("vp8enc", "video-encoder");
-      g_object_set (gcc->priv->videoenc, "speed", 2, "threads", 8,
+      g_object_set (gcc->priv->video_enc, "speed", 2, "threads", 8,
           "max-keyframe-distance", 25, NULL);
       name = "VP8 video encoder";
       break;
 
   }
-  if (!gcc->priv->videoenc) {
+  if (!gcc->priv->video_enc) {
     g_set_error (err,
         GCC_ERROR,
         GST_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);
-    gcc->priv->video_encoder_type = type;
+    return FALSE;
   }
+
+  GST_INFO_OBJECT(gcc, "Video encoder %s created", name);
+  gcc->priv->video_encoder_type = type;
   return TRUE;
 }
 
-gboolean
-gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_create_audio_encoder (GstCameraCapturer * gcc,
     AudioEncoderType type, GError ** err)
 {
   gchar *name = NULL;
@@ -1308,42 +1674,41 @@ gst_camera_capturer_set_audio_encoder (GstCameraCapturer * gcc,
 
   switch (type) {
     case AUDIO_ENCODER_MP3:
-      gcc->priv->audioenc =
+      gcc->priv->audio_enc =
           gst_element_factory_make ("lamemp3enc", "audio-encoder");
-      g_object_set (gcc->priv->audioenc, "target", 0, NULL);
+      g_object_set (gcc->priv->audio_enc, "target", 0, NULL);
       name = "Mp3 audio encoder";
       break;
 
     case AUDIO_ENCODER_AAC:
-      gcc->priv->audioenc = gst_element_factory_make ("faac", "audio-encoder");
+      gcc->priv->audio_enc = gst_element_factory_make ("faac", "audio-encoder");
       name = "AAC audio encoder";
       break;
 
     case AUDIO_ENCODER_VORBIS:
     default:
-      gcc->priv->audioenc =
+      gcc->priv->audio_enc =
           gst_element_factory_make ("vorbisenc", "audio-encoder");
       name = "Vorbis audio encoder";
       break;
   }
 
-  if (!gcc->priv->audioenc) {
+  if (!gcc->priv->audio_enc) {
     g_set_error (err,
         GCC_ERROR,
         GST_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);
-    gcc->priv->audio_encoder_type = type;
+    return FALSE;
   }
 
+  GST_INFO_OBJECT(gcc, "Audio encoder %s created", name);
+  gcc->priv->audio_encoder_type = type;
   return TRUE;
 }
 
-gboolean
-gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
+static gboolean
+gst_camera_capturer_create_video_muxer (GstCameraCapturer * gcc,
     VideoMuxerType type, GError ** err)
 {
   gchar *name = NULL;
@@ -1354,39 +1719,38 @@ gst_camera_capturer_set_video_muxer (GstCameraCapturer * gcc,
   switch (type) {
     case VIDEO_MUXER_OGG:
       name = "OGG muxer";
-      gcc->priv->videomux = gst_element_factory_make ("oggmux", "video-muxer");
+      gcc->priv->muxer = gst_element_factory_make ("oggmux", "video-muxer");
       break;
     case VIDEO_MUXER_AVI:
       name = "AVI muxer";
-      gcc->priv->videomux = gst_element_factory_make ("avimux", "video-muxer");
+      gcc->priv->muxer = gst_element_factory_make ("avimux", "video-muxer");
       break;
     case VIDEO_MUXER_MATROSKA:
       name = "Matroska muxer";
-      gcc->priv->videomux =
+      gcc->priv->muxer =
           gst_element_factory_make ("matroskamux", "video-muxer");
       break;
     case VIDEO_MUXER_MP4:
       name = "MP4 muxer";
-      gcc->priv->videomux = gst_element_factory_make ("qtmux", "video-muxer");
+      gcc->priv->muxer = gst_element_factory_make ("qtmux", "video-muxer");
       break;
     case VIDEO_MUXER_WEBM:
     default:
       name = "WebM muxer";
-      gcc->priv->videomux = gst_element_factory_make ("webmmux", "video-muxer");
+      gcc->priv->muxer = gst_element_factory_make ("webmmux", "video-muxer");
       break;
   }
 
-  if (!gcc->priv->videomux) {
+  if (!gcc->priv->muxer) {
     g_set_error (err,
         GCC_ERROR,
         GST_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);
   }
 
+  GST_INFO_OBJECT(gcc, "Muxer %s created", name);
+  gcc->priv->video_muxer_type = type;
   return TRUE;
 }
 
@@ -1452,7 +1816,7 @@ gcc_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
       gint device_change = 0;
 
       /* We only care about messages sent by the device source */
-      if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->device_source))
+      if (GST_MESSAGE_SRC (message) != GST_OBJECT (gcc->priv->source))
         break;
 
       s = gst_message_get_structure (message);
@@ -1529,8 +1893,8 @@ gcc_update_interface_implementations (GstCameraCapturer * gcc)
     return;
   }
 
-  GST_INFO_OBJECT (gcc, "Retrieving xoverlay from bin ...");
-  element = gst_bin_get_by_interface (GST_BIN (gcc->priv->camerabin),
+  GST_DEBUG_OBJECT (gcc, "Retrieving xoverlay from bin ...");
+  element = gst_bin_get_by_interface (GST_BIN (gcc->priv->preview_bin),
       GST_TYPE_X_OVERLAY);
 
   if (GST_IS_X_OVERLAY (element)) {
@@ -1577,7 +1941,7 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
   GstCaps *caps;
   GstStructure *s;
 
-  sourcepad = gst_element_get_pad (gcc->priv->videosrc, "src");
+  sourcepad = gst_element_get_pad (gcc->priv->source, "src");
   caps = gst_pad_get_negotiated_caps (sourcepad);
 
   if (!(caps)) {
@@ -1601,6 +1965,12 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
   return 1;
 }
 
+/*****************************************************
+ *
+ *             Device Probe
+ *
+ * **************************************************/
+
 GList *
 gst_camera_capturer_enum_devices (gchar * device_name)
 {
@@ -1661,12 +2031,70 @@ gst_camera_capturer_enum_audio_devices (void)
   return gst_camera_capturer_enum_devices (AUDIOSRC);
 }
 
+/*******************************************
+ *
+ *         Public methods
+ *
+ * ****************************************/
+
+void
+gst_camera_capturer_run (GstCameraCapturer * gcc)
+{
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_PLAYING);
+}
+
+void
+gst_camera_capturer_close (GstCameraCapturer * gcc)
+{
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+  gst_element_set_state (gcc->priv->main_pipeline, GST_STATE_NULL);
+}
+
+void
+gst_camera_capturer_start (GstCameraCapturer * gcc)
+{
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+  GST_INFO_OBJECT(gcc, "Started capture");
+  g_mutex_lock(gcc->priv->recording_lock);
+  if (!gcc->priv->is_recording && gcc->priv->accum_recorded_ts == GST_CLOCK_TIME_NONE) {
+    gcc->priv->accum_recorded_ts = 0;
+    gcc->priv->is_recording = TRUE;
+    gst_camera_capturer_link_encoder_bin (gcc);
+  }
+  g_mutex_unlock(gcc->priv->recording_lock);
+}
+
+void
+gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc)
+{
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+  g_mutex_lock(gcc->priv->recording_lock);
+  if (!gcc->priv->is_recording) {
+    gcc->priv->current_recording_start_ts = GST_CLOCK_TIME_NONE;
+    gcc->priv->is_recording = TRUE;
+  } else {
+    gcc->priv->is_recording = FALSE;
+    gcc->priv->video_synced = FALSE;
+  }
+  g_mutex_unlock(gcc->priv->recording_lock);
+
+  GST_INFO_OBJECT(gcc, "Capture state changed to %s", gcc->priv->is_recording ? "recording": "paused");
+}
+
 gboolean
 gst_camera_capturer_can_get_frames (GstCameraCapturer * gcc, GError ** error)
 {
   g_return_val_if_fail (gcc != NULL, FALSE);
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), FALSE);
 
   /* check for video */
   if (!gcc->priv->media_has_video) {
@@ -1702,9 +2130,8 @@ gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
 
   g_return_val_if_fail (gcc != NULL, NULL);
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (gcc->priv->camerabin), NULL);
 
-  gst_element_get_state (gcc->priv->camerabin, NULL, NULL, -1);
+  gst_element_get_state (gcc->priv->main_pipeline, NULL, NULL, -1);
 
   /* no video info */
   if (!gcc->priv->video_width || !gcc->priv->video_height) {
@@ -1791,3 +2218,107 @@ gst_camera_capturer_get_current_frame (GstCameraCapturer * gcc)
 
   return pixbuf;
 }
+
+
+void
+gst_camera_capturer_stop (GstCameraCapturer * gcc)
+{
+  GstPad *video_pad;
+
+  g_return_if_fail (gcc != NULL);
+  g_return_if_fail (GST_IS_CAMERA_CAPTURER (gcc));
+
+#ifdef WIN32
+  //On windows we can't handle device disconnections until dshowvideosrc
+  //supports it. When a device is disconnected, the source is locked
+  //in ::create(), blocking the streaming thread. We need to change its
+  //state to null, this way camerabin doesn't block in ::do_stop().
+  gst_element_set_state(gcc->priv->device_source, GST_STATE_NULL);
+#endif
+
+  GST_INFO_OBJECT(gcc, "Closing capture");
+  g_mutex_lock(gcc->priv->recording_lock);
+  gcc->priv->closing_recording = TRUE;
+  g_mutex_unlock(gcc->priv->recording_lock);
+
+  video_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "video");
+  gst_pad_send_event(video_pad, gst_event_new_eos());
+  gst_object_unref(video_pad);
+
+  if (gcc->priv->audio_enabled) {
+    GstPad *audio_pad;
+
+    audio_pad = gst_element_get_static_pad(gcc->priv->encoder_bin, "audio");
+    gst_pad_send_event(audio_pad, gst_event_new_eos());
+    gst_object_unref(audio_pad);
+  }
+}
+
+GstCameraCapturer *
+gst_camera_capturer_new (gchar * filename, GstCameraCaptureSourceType source,
+     VideoEncoderType venc, AudioEncoderType aenc, VideoMuxerType muxer, GError ** err)
+{
+  GstCameraCapturer *gcc = NULL;
+
+#ifndef GST_DISABLE_GST_INFO
+  if (_cesarplayer_gst_debug_cat == NULL) {
+    GST_DEBUG_CATEGORY_INIT (_cesarplayer_gst_debug_cat, "longomatch", 0,
+        "LongoMatch GStreamer Backend");
+  }
+#endif
+
+  gcc = g_object_new (GST_TYPE_CAMERA_CAPTURER, NULL);
+
+  gcc->priv->main_pipeline = gst_pipeline_new ("main_pipeline");
+
+  if (!gcc->priv->main_pipeline) {
+    g_set_error (err,
+        GCC_ERROR,
+        GST_ERROR_PLUGIN_LOAD,
+        "Failed to create the pipeline element. "
+        "Please check your GStreamer installation.");
+    goto missing_plugin;
+  }
+
+  /* Setup */
+  GST_INFO_OBJECT (gcc, "Initializing encoders");
+  if (!gst_camera_capturer_create_video_encoder(gcc, venc, err))
+    goto missing_plugin;
+  if (!gst_camera_capturer_create_audio_encoder(gcc, aenc, err))
+    goto missing_plugin;
+  if (!gst_camera_capturer_create_video_muxer(gcc, muxer, err))
+    goto missing_plugin;
+  if (!gst_camera_capturer_create_video_source(gcc, source, err))
+    goto missing_plugin;
+
+  /* add the source element */
+  gst_bin_add(GST_BIN(gcc->priv->main_pipeline), gcc->priv->source_bin);
+
+  /* assume we're always called from the main Gtk+ GUI thread */
+  gui_thread = g_thread_self ();
+
+  /*Connect bus signals */
+  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);
+
+  /* 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);
+
+  return gcc;
+
+/* Missing plugin */
+missing_plugin:
+  {
+    g_object_ref_sink (gcc);
+    g_object_unref (gcc);
+    return NULL;
+  }
+}
diff --git a/libcesarplayer/gst-camera-capturer.h b/libcesarplayer/gst-camera-capturer.h
index 0e83bb5..c1227e3 100644
--- a/libcesarplayer/gst-camera-capturer.h
+++ b/libcesarplayer/gst-camera-capturer.h
@@ -68,36 +68,27 @@ typedef enum
 {
   GST_CAMERA_CAPTURE_SOURCE_TYPE_NONE = 0,
   GST_CAMERA_CAPTURE_SOURCE_TYPE_DV = 1,
-  GST_CAMERA_CAPTURE_SOURCE_TYPE_RAW = 2,
-  GST_CAMERA_CAPTURE_SOURCE_TYPE_DSHOW = 3
+  GST_CAMERA_CAPTURE_SOURCE_TYPE_SYSTEM = 2,
 } GstCameraCaptureSourceType;
 
 EXPORT GType
 gst_camera_capturer_get_type (void)
-    G_GNUC_CONST;
+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, VideoEncoderType type, GError ** err);
-     EXPORT gboolean gst_camera_capturer_set_audio_encoder (GstCameraCapturer *
-    gcc, AudioEncoderType type, GError ** err);
-     EXPORT gboolean gst_camera_capturer_set_video_muxer (GstCameraCapturer *
-    gcc, VideoMuxerType type, GError ** err);
-     EXPORT gboolean gst_camera_capturer_set_source (GstCameraCapturer * gcc,
-    GstCameraCaptureSourceType type, GError ** err);
-     EXPORT GList *gst_camera_capturer_enum_audio_devices (void);
-     EXPORT GList *gst_camera_capturer_enum_video_devices (void);
-     EXPORT GdkPixbuf *gst_camera_capturer_get_current_frame (GstCameraCapturer
+void gst_camera_capturer_init_backend (int *argc, char ***argv);
+GstCameraCapturer *gst_camera_capturer_new (gchar * filename, GstCameraCaptureSourceType source,
+     VideoEncoderType venc, AudioEncoderType aenc, VideoMuxerType muxer, GError ** err);
+void gst_camera_capturer_run (GstCameraCapturer * gcc);
+void gst_camera_capturer_close (GstCameraCapturer * gcc);
+void gst_camera_capturer_start (GstCameraCapturer * gcc);
+void gst_camera_capturer_toggle_pause (GstCameraCapturer * gcc);
+void gst_camera_capturer_stop (GstCameraCapturer * gcc);
+GList *gst_camera_capturer_enum_audio_devices (void);
+GList *gst_camera_capturer_enum_video_devices (void);
+GdkPixbuf *gst_camera_capturer_get_current_frame (GstCameraCapturer
     * gcc);
-     EXPORT void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
-     EXPORT void gst_camera_capturer_finalize (GObject * object);
+void gst_camera_capturer_unref_pixbuf (GdkPixbuf * pixbuf);
+void gst_camera_capturer_finalize (GObject * object);
 
 G_END_DECLS
 #endif /* _GST_CAMERA_CAPTURER_H_ */
diff --git a/libcesarplayer/gstscreenshot.c b/libcesarplayer/gstscreenshot.c
index f1df208..03f67a8 100644
--- a/libcesarplayer/gstscreenshot.c
+++ b/libcesarplayer/gstscreenshot.c
@@ -25,9 +25,8 @@
 #include <string.h>
 
 #include "gstscreenshot.h"
+#include "video-utils.h"
 
-GST_DEBUG_CATEGORY_EXTERN (_totem_gst_debug_cat);
-#define GST_CAT_DEFAULT _totem_gst_debug_cat
 
 static void
 feed_fakesrc (GstElement * src, GstBuffer * buf, GstPad * pad, gpointer data)
diff --git a/libcesarplayer/main.c b/libcesarplayer/main.c
index a2726fc..0f1dad6 100644
--- a/libcesarplayer/main.c
+++ b/libcesarplayer/main.c
@@ -17,13 +17,14 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-
-
+/* Compile with:
+ * gcc -o test main.c gst-camera-capturer.c video-utils.c gstscreenshot.c `pkg-config --cflags --libs gstreamer-0.10 gstreamer-interfaces-0.10 gstreamer-video-0.10 gtk+-2.0` -DOSTYPE_LINUX -O0
+ */
 
 #include <gtk/gtk.h>
-#include "gst-video-capturer.h"
 #include <stdlib.h>
 #include <unistd.h>
+#include "gst-camera-capturer.h"
 
 
 static int i = 0;
@@ -34,22 +35,24 @@ window_state_event (GtkWidget * widget, GdkEventWindowState * event,
   i++;
   g_print ("%d\n", i);
   if (i == 3) {
-    gst_video_capturer_rec (GST_VIDEO_CAPTURER (gvc));
+    gst_camera_capturer_start (GST_CAMERA_CAPTURER (gvc));
 
   }
   if (i == 5)
-    gst_video_capturer_stop (GST_VIDEO_CAPTURER (gvc));
+    gst_camera_capturer_stop (GST_CAMERA_CAPTURER (gvc));
+  if (i == 6)
+    gst_camera_capturer_toggle_pause (GST_CAMERA_CAPTURER (gvc));
+  if (i == 7)
+    gst_camera_capturer_stop (GST_CAMERA_CAPTURER (gvc));
   return TRUE;
 }
 
 GtkWidget *
-create_window (GstVideoCapturer * gvc)
+create_window (GstCameraCapturer * gvc)
 {
   GtkWidget *window;
 
 
-
-
   /* Create a new window */
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title (GTK_WINDOW (window), "Capturer");
@@ -66,19 +69,16 @@ int
 main (int argc, char *argv[])
 {
   GtkWidget *window;
-  GstVideoCapturer *gvc;
+  GstCameraCapturer *gvc;
   GError *error = NULL;
 
 
   gtk_init (&argc, &argv);
 
   /*Create GstVideoCapturer */
-  gst_video_capturer_init_backend (&argc, &argv);
-  gvc = gst_video_capturer_new (GVC_USE_TYPE_DEVICE_CAPTURE, &error);
-  //gvc = gst_video_capturer_new (GVC_USE_TYPE_VIDEO_TRANSCODE, &error );
-  //g_object_set(gvc,"input_file","/home/andoni/Escritorio/RC Polo vs CD Complutense.avi",NULL);
+  gst_camera_capturer_init_backend (&argc, &argv);
+  gvc = gst_camera_capturer_new ("test", 2, 3, 1, 1, &error);
   g_object_set (gvc, "output_file", "/home/andoni/jander.avi", NULL);
-  //gvc = gst_video_capturer_new (GVC_USE_TYPE_TEST, &error );
 
   window = create_window (gvc);
 
@@ -86,9 +86,7 @@ main (int argc, char *argv[])
   gtk_widget_show (GTK_WIDGET (gvc));
   gtk_widget_show (window);
 
-
-
-
+  gst_camera_capturer_run(gvc);
   gtk_main ();
 
   return 0;
diff --git a/libcesarplayer/video-utils.c b/libcesarplayer/video-utils.c
index d6fc907..43cdf35 100644
--- a/libcesarplayer/video-utils.c
+++ b/libcesarplayer/video-utils.c
@@ -1,4 +1,31 @@
-
+/* 
+ * Copyright (C) 2003-2007 the GStreamer project
+ *      Julien Moutte <julien moutte net>
+ *      Ronald Bultje <rbultje ronald bitfreak net>
+ * Copyright (C) 2005-2008 Tim-Philipp MÃller <tim centricular net>
+ * Copyright (C) 2009 Sebastian DrÃge <sebastian droege collabora co uk>
+ * Copyright (C) 2009  Andoni Morales Alastruey <ylatuya gmail com> 
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission is above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ */
 
 #include "video-utils.h"
 
diff --git a/libcesarplayer/video-utils.h b/libcesarplayer/video-utils.h
index def2d38..ee87196 100644
--- a/libcesarplayer/video-utils.h
+++ b/libcesarplayer/video-utils.h
@@ -1,3 +1,31 @@
+/* 
+ * Copyright (C) 2003-2007 the GStreamer project
+ *      Julien Moutte <julien moutte net>
+ *      Ronald Bultje <rbultje ronald bitfreak net>
+ * Copyright (C) 2005-2008 Tim-Philipp MÃller <tim centricular net>
+ * Copyright (C) 2009 Sebastian DrÃge <sebastian droege collabora co uk>
+ * Copyright (C) 2009  Andoni Morales Alastruey <ylatuya gmail com> 
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Totem project hereby grant permission for non-gpl compatible GStreamer
+ * plugins to be used and distributed together with GStreamer and Totem. This
+ * permission is above and beyond the permissions granted by the GPL license
+ * Totem is covered by.
+ *
+ */
 
 #include <gst/gst.h>
 #include <gst/interfaces/xoverlay.h>
@@ -34,7 +62,8 @@ void totem_widget_set_preferred_size (GtkWidget * widget, gint width,
 gboolean totem_ratio_fits_screen (GdkWindow * window, int video_width,
     int video_height, gfloat ratio);
 
-EXPORT void init_backend (int argc, char **argv);
-EXPORT void gst_set_window_handle (GstXOverlay *overlay, GdkWindow *window);
+void init_backend (int argc, char **argv);
+void gst_set_window_handle (GstXOverlay *overlay, GdkWindow *window);
+void init_debug();
 
 



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