[longomatch/camera_capturer] Almost everything working



commit e0dd3c43013febe4e45d4b5de63038ee4238db00
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Tue Oct 2 21:54:33 2012 +0200

    Almost everything working

 libcesarplayer/gst-camera-capturer.c |  588 ++++++++++++++++++----------------
 libcesarplayer/main.c                |    2 +-
 2 files changed, 316 insertions(+), 274 deletions(-)
---
diff --git a/libcesarplayer/gst-camera-capturer.c b/libcesarplayer/gst-camera-capturer.c
index 01dd87f..0ec13af 100644
--- a/libcesarplayer/gst-camera-capturer.c
+++ b/libcesarplayer/gst-camera-capturer.c
@@ -100,8 +100,6 @@ 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;
@@ -136,7 +134,6 @@ struct GstCameraCapturerPrivate
   GstElement *audio_enc;
   GstElement *muxer;
   GstElement *filesink;
-  guint source_probe_id;
 
   /* Recording */
   gboolean is_recording;
@@ -146,6 +143,8 @@ struct GstCameraCapturerPrivate
   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 */
@@ -186,152 +185,6 @@ static void gst_camera_capturer_link_encoder_bin (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->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->is_recording = FALSE;
-  priv->recording_lock = g_mutex_new();
-  //priv->audio_enabled = TRUE;
-
-  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);
-
-  /* FIXME */
-}
-
-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 :\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->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 :\n%d",
-      gcc->priv->audio_bitrate);
-
-}
-
-static void
-gst_camera_capturer_set_audio_enabled (GstCameraCapturer * gcc,
-    gboolean enabled)
-{
-  /* FIXME */
-}
-
-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 :\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
@@ -645,10 +498,10 @@ gst_camera_capturer_expose_event (GtkWidget * widget, GdkEventExpose * event)
 
   g_mutex_lock (gcc->priv->lock);
   xoverlay = gcc->priv->xoverlay;
-  if (xoverlay == NULL) {
-    //gcc_update_interface_implementations (gcc);
-    //resize_video_window (gcc);
-    //xoverlay = gcc->priv->xoverlay;
+  if (xoverlay == NULL && gcc->priv->preview_bin != NULL) {
+    gcc_update_interface_implementations (gcc);
+    resize_video_window (gcc);
+    xoverlay = gcc->priv->xoverlay;
   }
   if (xoverlay != NULL)
     gst_object_ref (xoverlay);
@@ -740,6 +593,148 @@ 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)
+{
+  gcc->priv->device_id = g_strdup (device_id);
+  GST_INFO_OBJECT (gcc, "Changed device id/name to: %s", device_id);
+}
+
 static void
 gst_camera_capturer_set_property (GObject * object, guint property_id,
     const GValue * value, GParamSpec * pspec)
@@ -751,11 +746,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));
@@ -886,6 +879,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)
 {
@@ -920,93 +919,6 @@ gst_camera_capture_videosrc_buffer_probe (GstPad * pad, GstBuffer * buf,
   return TRUE;
 }
 
-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");
-}
-
-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);
-  }
-}
-
 static void
 gst_camera_capturer_update_device_id(GstCameraCapturer *gcc)
 {
@@ -1043,7 +955,9 @@ 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");
@@ -1054,6 +968,14 @@ gst_camera_capturer_create_encoder_bin (GstCameraCapturer *gcc)
   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,
@@ -1287,11 +1209,13 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
     } 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, "Waitin for a keyframe, dropping buffer on %s pad", is_video ? "video": "audio");
+          GST_LOG_OBJECT (gcc, "Waiting for a keyframe, "
+              "dropping buffer on %s pad", is_video ? "video": "audio");
           ret = FALSE;
           goto done;
         }
@@ -1302,6 +1226,8 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
       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;
@@ -1309,22 +1235,39 @@ gst_camera_capturer_encoding_retimestamper (GstCameraCapturer *gcc,
             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;
-          gcc->priv->accum_recorded_ts = new_buf_ts;
-        }
       } else {
-        /* h264parse only sets the timestamp on the first buffer */
-        new_buf_ts = gcc->priv->accum_recorded_ts;
+        /* 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
@@ -1530,10 +1473,10 @@ gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
   GstElement *v_decoder, *video_bin;
   GstPad *video_pad;
 
-  v_decoder = gst_element_factory_make("decodebin2", NULL);
+  v_decoder = gst_element_factory_make("decodebin2", "preview-decoder");
 
   video_bin = gst_parse_bin_from_description(
-      "videorate ! videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, NULL);
+      "videoscale ! ffmpegcolorspace ! autovideosink name=videosink", TRUE, 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);
@@ -1569,32 +1512,32 @@ gst_camera_capturer_create_preview(GstCameraCapturer *gcc)
 }
 
 static gboolean
-gst_camera_capturer_source_pad_probe (GstPad *pad, GstBuffer *buf, GstCameraCapturer *gcc)
+gst_camera_capturer_have_type_cb (GstElement *typefind, guint prob,
+    GstCaps *caps, GstCameraCapturer *gcc)
 {
-  GstCaps *src_caps, *media_caps;
+  GstCaps *media_caps;
   GstElement *decoder_bin = NULL;
 
-  src_caps = gst_buffer_get_caps(buf);
-  GST_INFO_OBJECT (gcc, "Got first buffer from the source with caps %s", gst_caps_to_string(src_caps));
+  GST_INFO_OBJECT (gcc, "Found type with caps %s", gst_caps_to_string(caps));
 
   /* Check for DV streams */
   media_caps = gst_caps_from_string("video/x-dv, systemstream=true");
 
-  if (gst_caps_can_intersect(src_caps, media_caps)) {
+  if (gst_caps_can_intersect(caps, media_caps)) {
     decoder_bin = gst_camera_capturer_prepare_dv_source(gcc);
     gst_caps_unref(media_caps);
   }
 
   /* Check for MPEG-TS streams */
   media_caps = gst_caps_from_string("video/mpegts");
-  if (gst_caps_can_intersect(src_caps, media_caps)) {
+  if (gst_caps_can_intersect(caps, media_caps)) {
     decoder_bin = gst_camera_capturer_prepare_mpegts_source(gcc);
     gst_caps_unref(media_caps);
   }
 
   /* Check for Raw streams */
   media_caps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
-  if (gst_caps_can_intersect(src_caps, media_caps)) {
+  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);
@@ -1606,7 +1549,6 @@ gst_camera_capturer_source_pad_probe (GstPad *pad, GstBuffer *buf, GstCameraCapt
 
     gst_camera_capturer_link_preview(gcc);
     gst_element_set_state(gcc->priv->main_pipeline, GST_STATE_PLAYING);
-    gst_pad_remove_buffer_probe(pad, gcc->priv->source_probe_id);
   } else {
     /* FIXME: post error */
   }
@@ -1617,8 +1559,9 @@ static gboolean
 gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
     GstCameraCaptureSourceType type, GError ** err)
 {
-  GstPad *pad;
-  gchar *name = NULL;
+  GstElement *typefind;
+  const gchar *source_desc = "";
+  gchar *source_str;
 
   g_return_val_if_fail (gcc != NULL, FALSE);
   g_return_val_if_fail (GST_IS_CAMERA_CAPTURER (gcc), FALSE);
@@ -1626,37 +1569,37 @@ gst_camera_capturer_create_video_source (GstCameraCapturer * gcc,
   switch (type) {
     case GST_CAMERA_CAPTURE_SOURCE_TYPE_DV:
       GST_INFO_OBJECT(gcc, "Creating dv video source");
-      gcc->priv->source =
-          gst_element_factory_make (DVVIDEOSRC, "source");
-      name = DVVIDEOSRC;
+      source_desc = DVVIDEOSRC;
       break;
     case GST_CAMERA_CAPTURE_SOURCE_TYPE_SYSTEM:
       GST_INFO_OBJECT(gcc, "Creating system video source");
-      gcc->priv->source =
-          gst_element_factory_make (SYSVIDEOSRC, "source");
-      //gcc->priv->source = gst_parse_bin_from_description("filesrc location=/home/andoni/test.dv ! typefind", TRUE, NULL);
-      name = SYSVIDEOSRC;
+      source_desc = SYSVIDEOSRC;
+      //source_desc = "filesrc location=/home/andoni/test.ts";
       break;
     default:
       g_assert_not_reached();
   }
+
+  source_str = g_strdup_printf("%s name=source ! typefind name=typefind", source_desc);
+  gcc->priv->source = gst_parse_bin_from_description(source_str, TRUE, NULL);
+  g_free(source_str);
   if (!gcc->priv->source) {
     g_set_error (err,
         GCC_ERROR,
         GST_ERROR_PLUGIN_LOAD,
         "Failed to create the %s element. "
-        "Please check your GStreamer installation.", name);
+        "Please check your GStreamer installation.", source_desc);
     return FALSE;
   }
   gcc->priv->source_type = type;
 
-  pad = gst_element_get_static_pad(gcc->priv->source, "src");
-  gcc->priv->source_probe_id = gst_pad_add_buffer_probe(pad,
-      (GCallback) gst_camera_capturer_source_pad_probe, gcc);
+  typefind = gst_bin_get_by_name (GST_BIN(gcc->priv->source), "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", name);
+  GST_INFO_OBJECT(gcc, "Created video source %s", source_desc);
 
   return TRUE;
 }
@@ -2029,6 +1972,12 @@ gcc_get_video_stream_info (GstCameraCapturer * gcc)
   return 1;
 }
 
+/*****************************************************
+ *
+ *             Device Probe
+ *
+ * **************************************************/
+
 GList *
 gst_camera_capturer_enum_devices (gchar * device_name)
 {
@@ -2089,6 +2038,65 @@ 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)
 {
@@ -2218,6 +2226,41 @@ 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)
@@ -2286,4 +2329,3 @@ missing_plugin:
     return NULL;
   }
 }
-
diff --git a/libcesarplayer/main.c b/libcesarplayer/main.c
index 4eaabda..0f1dad6 100644
--- a/libcesarplayer/main.c
+++ b/libcesarplayer/main.c
@@ -39,7 +39,7 @@ window_state_event (GtkWidget * widget, GdkEventWindowState * event,
 
   }
   if (i == 5)
-    gst_camera_capturer_toggle_pause (GST_CAMERA_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)



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