Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Sun, 16 Oct 2011 13:28:31 +0000 (15:28 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Sun, 16 Oct 2011 13:28:31 +0000 (15:28 +0200)
gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c
gst/camerabin/camerabinvideo.c
gst/camerabin/gstcamerabin.c
gst/camerabin2/gstcamerabin2.c
gst/camerabin2/gstcamerabin2.h
sys/shm/gstshmsink.c
sys/shm/gstshmsink.h
sys/shm/shmpipe.c
sys/shm/shmpipe.h

index d5b8ed772808992a671a16c683be657f299ca3e3..7d159e04dbb79fb0e9adae45bb555e3c1f91ebff 100644 (file)
@@ -474,6 +474,9 @@ gst_base_camera_src_change_state (GstElement * element,
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_READY);
+      break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL);
       break;
index b54e9abdffc62ab591aab103983944b2118faf6f..d88d1f4dee4c23351369147de2b28b2ace6c9a7a 100644 (file)
@@ -638,6 +638,13 @@ gst_camerabin_video_create_elements (GstCameraBinVideo * vid)
       G_CALLBACK (gst_camerabin_drop_eos_probe), vid);
   gst_object_unref (vid_srcpad);
 
+  /* audio source is not always present and might be set to NULL during operation */
+  if (vid->aud_src
+      && g_object_class_find_property (G_OBJECT_GET_CLASS (vid->aud_src),
+          "provide-clock")) {
+    g_object_set (vid->aud_src, "provide-clock", FALSE, NULL);
+  }
+
   GST_DEBUG ("created video elements");
 
   return TRUE;
index fe41e38199655be463c1e9bc872fb409537c09c0..1a2b05f76a4c51dfd9240ceb41fd81a70089bc63 100644 (file)
@@ -1641,6 +1641,7 @@ static void
 gst_camerabin_start_video_recording (GstCameraBin * camera)
 {
   GstStateChangeReturn state_ret;
+  GstCameraBinVideo *vidbin = (GstCameraBinVideo *) camera->vidbin;
   /* FIXME: how to ensure resolution and fps is supported by CPU?
    * use a queue overrun signal?
    */
@@ -1654,9 +1655,14 @@ gst_camerabin_start_video_recording (GstCameraBin * camera)
   gst_camerabin_rewrite_tags (camera);
 
   /* Pause the pipeline in order to distribute new clock in paused_to_playing */
+  /* Audio source needs to go to null to reset the ringbuffer */
+  if (vidbin->aud_src)
+    gst_element_set_state (vidbin->aud_src, GST_STATE_NULL);
   state_ret = gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PAUSED);
 
   if (state_ret != GST_STATE_CHANGE_FAILURE) {
+    GstClock *clock = gst_element_get_clock (GST_ELEMENT (camera));
+
     g_mutex_lock (camera->capture_mutex);
     camera->capturing = TRUE;
     g_mutex_unlock (camera->capture_mutex);
@@ -1672,6 +1678,11 @@ gst_camerabin_start_video_recording (GstCameraBin * camera)
       g_object_set (G_OBJECT (camera->src_vid_src), "capture-mode", 2, NULL);
     }
 
+    /* Clock might be distributed as NULL to audiosrc, messing timestamping */
+    if (vidbin->aud_src)
+      gst_element_set_clock (vidbin->aud_src, clock);
+    gst_object_unref (clock);
+
     /* videobin will not go to playing if file is not writable */
     if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
         GST_STATE_CHANGE_FAILURE) {
index a91f109c7679be2afde8e9b43aa7e56c034f684a..8d1de914085b1ac5979655ecac93c6cf79c8ee15 100644 (file)
@@ -406,8 +406,10 @@ gst_camera_bin_start_capture (GstCameraBin2 * camerabin)
   }
 
   /* store the next preview filename */
+  g_mutex_lock (camerabin->preview_list_mutex);
   camerabin->preview_location_list =
       g_slist_append (camerabin->preview_location_list, location);
+  g_mutex_unlock (camerabin->preview_list_mutex);
 
   g_signal_emit_by_name (camerabin->src, "start-capture", NULL);
   if (camerabin->mode == MODE_VIDEO && camerabin->audio_src)
@@ -518,6 +520,7 @@ gst_camera_bin_dispose (GObject * object)
   GstCameraBin2 *camerabin = GST_CAMERA_BIN2_CAST (object);
 
   g_free (camerabin->location);
+  g_mutex_free (camerabin->preview_list_mutex);
 
   if (camerabin->src_capture_notify_id)
     g_signal_handler_disconnect (camerabin->src,
@@ -873,6 +876,7 @@ gst_camera_bin_init (GstCameraBin2 * camera)
   camera->zoom = DEFAULT_ZOOM;
   camera->max_zoom = MAX_ZOOM;
   camera->flags = DEFAULT_FLAGS;
+  camera->preview_list_mutex = g_mutex_new ();
 
   /* capsfilters are created here as we proxy their caps properties and
    * this way we avoid having to store the caps while on NULL state to 
@@ -945,20 +949,31 @@ gst_camera_bin_handle_message (GstBin * bin, GstMessage * message)
         }
       } else if (gst_structure_has_name (structure, "preview-image")) {
         GValue *value;
-        gchar *location;
-
-        location = camerabin->preview_location_list->data;
-        camerabin->preview_location_list =
-            g_slist_delete_link (camerabin->preview_location_list,
-            camerabin->preview_location_list);
-        GST_DEBUG_OBJECT (camerabin, "Adding preview location to preview "
-            "message '%s'", location);
-
-        value = g_new0 (GValue, 1);
-        g_value_init (value, G_TYPE_STRING);
-        g_value_take_string (value, location);
-        gst_structure_take_value ((GstStructure *) structure, "location",
-            value);
+        gchar *location = NULL;
+
+        g_mutex_lock (camerabin->preview_list_mutex);
+        if (camerabin->preview_location_list) {
+          location = camerabin->preview_location_list->data;
+          camerabin->preview_location_list =
+              g_slist_delete_link (camerabin->preview_location_list,
+              camerabin->preview_location_list);
+          GST_DEBUG_OBJECT (camerabin, "Adding preview location to preview "
+              "message '%s'", location);
+        } else {
+          GST_WARNING_OBJECT (camerabin, "Unexpected preview message received, "
+              "won't be able to put location field into the message. This can "
+              "happen if the source is posting previews while camerabin2 is "
+              "shutting down");
+        }
+        g_mutex_unlock (camerabin->preview_list_mutex);
+
+        if (location) {
+          value = g_new0 (GValue, 1);
+          g_value_init (value, G_TYPE_STRING);
+          g_value_take_string (value, location);
+          gst_structure_take_value ((GstStructure *) structure, "location",
+              value);
+        }
       }
     }
       break;
@@ -1725,9 +1740,11 @@ gst_camera_bin_change_state (GstElement * element, GstStateChange trans)
       g_slist_free (camera->image_location_list);
       camera->image_location_list = NULL;
 
+      g_mutex_lock (camera->preview_list_mutex);
       g_slist_foreach (camera->preview_location_list, (GFunc) g_free, NULL);
       g_slist_free (camera->preview_location_list);
       camera->preview_location_list = NULL;
+      g_mutex_unlock (camera->preview_list_mutex);
 
       /* explicitly set to READY as they might be outside of the bin */
       gst_element_set_state (camera->audio_volume, GST_STATE_READY);
index 05af34f4de8f514485b4961e5638735d031d9500..3b4c9c92fd17fc1c31ce45d72be6052e49c6ee19 100644 (file)
@@ -94,8 +94,22 @@ struct _GstCameraBin2
    * each buffer capture */
   GSList *image_location_list;
 
-  /* similar to above, but used for giving names to previews */
+  /*
+   * Similar to above, but used for giving names to previews
+   *
+   * Need to protect with a mutex as this list is used when the
+   * camera-source posts a preview image. As we have no control
+   * on how the camera-source will behave (we can only tell how
+   * it should), the preview location list might be used in an
+   * inconsistent way.
+   * One example is the camera-source posting a preview image after
+   * camerabin2 was put to ready, when this preview list will be
+   * freed and set to NULL. Concurrent access might lead to crashes in
+   * this situation. (Concurrency from the state-change freeing the
+   * list and the message handling function looking at preview names)
+   */
   GSList *preview_location_list;
+  GMutex *preview_list_mutex;
 
   gboolean video_profile_switch;
   gboolean image_profile_switch;
index a7d7e52073f8f2ad0c212d1995356d6916acf082..cb6c92bfa6cf7ed8609f08a0c9566459421bfdc7 100644 (file)
@@ -45,7 +45,8 @@ enum
   PROP_SOCKET_PATH,
   PROP_PERMS,
   PROP_SHM_SIZE,
-  PROP_WAIT_FOR_CONNECTION
+  PROP_WAIT_FOR_CONNECTION,
+  PROP_BUFFER_TIME
 };
 
 struct GstShmClient
@@ -162,6 +163,13 @@ gst_shm_sink_class_init (GstShmSinkClass * klass)
           DEFAULT_WAIT_FOR_CONNECTION,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
+      g_param_spec_uint64 ("buffer-time",
+          "Buffer Time of the shm buffer",
+          "Maximum Size of the shm buffer in nanoseconds (-1 to disable)",
+          0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   signals[SIGNAL_CLIENT_CONNECTED] = g_signal_new ("client-connected",
       GST_TYPE_SHM_SINK, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
       g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
@@ -229,6 +237,12 @@ gst_shm_sink_set_property (GObject * object, guint prop_id,
       GST_OBJECT_UNLOCK (object);
       g_cond_broadcast (self->cond);
       break;
+    case PROP_BUFFER_TIME:
+      GST_OBJECT_LOCK (object);
+      self->buffer_time = g_value_get_uint64 (value);
+      GST_OBJECT_UNLOCK (object);
+      g_cond_broadcast (self->cond);
+      break;
     default:
       break;
   }
@@ -263,6 +277,9 @@ gst_shm_sink_get_property (GObject * object, guint prop_id,
     case PROP_WAIT_FOR_CONNECTION:
       g_value_set_boolean (value, self->wait_for_connection);
       break;
+    case PROP_BUFFER_TIME:
+      g_value_set_uint64 (value, self->buffer_time);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -358,6 +375,24 @@ gst_shm_sink_stop (GstBaseSink * bsink)
   return TRUE;
 }
 
+static gboolean
+gst_shm_sink_can_render (GstShmSink * self, GstClockTime time)
+{
+  ShmBuffer *b;
+
+  if (time == GST_CLOCK_TIME_NONE || self->buffer_time == GST_CLOCK_TIME_NONE)
+    return TRUE;
+
+  b = sp_writer_get_pending_buffers (self->pipe);
+  for (; b != NULL; b = sp_writer_get_next_buffer (b)) {
+    GstClockTime t = sp_writer_buf_get_tag (b);
+    if (GST_CLOCK_DIFF (time, t) > self->buffer_time)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
 {
@@ -373,8 +408,16 @@ gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
     }
   }
 
+  while (!gst_shm_sink_can_render (self, GST_BUFFER_TIMESTAMP (buf))) {
+    g_cond_wait (self->cond, GST_OBJECT_GET_LOCK (self));
+    if (self->unlock) {
+      GST_OBJECT_UNLOCK (self);
+      return GST_FLOW_WRONG_STATE;
+    }
+  }
+
   rv = sp_writer_send_buf (self->pipe, (char *) GST_BUFFER_DATA (buf),
-      GST_BUFFER_SIZE (buf));
+      GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
 
   if (rv == -1) {
     ShmBlock *block = NULL;
@@ -396,10 +439,10 @@ gst_shm_sink_render (GstBaseSink * bsink, GstBuffer * buf)
       }
     }
 
-
     shmbuf = sp_writer_block_get_buf (block);
     memcpy (shmbuf, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
-    sp_writer_send_buf (self->pipe, shmbuf, GST_BUFFER_SIZE (buf));
+    sp_writer_send_buf (self->pipe, shmbuf, GST_BUFFER_SIZE (buf),
+        GST_BUFFER_TIMESTAMP (buf));
     sp_writer_free_block (block);
   }
 
index bc6da74bc7b8d736a40b98415042d604750df199..83dad393e56a134c760a11b6bd868c4ec04b8017 100644 (file)
@@ -61,6 +61,7 @@ struct _GstShmSink
   gboolean wait_for_connection;
   gboolean stop;
   gboolean unlock;
+  GstClockTime buffer_time;
 
   GCond *cond;
 };
index c629ea05c2cc3dfdbaa53645faf35df53438fe72..583aa3846afbc84e6f43ec8687c505dfd5d3bdf2 100644 (file)
@@ -78,7 +78,6 @@ enum
 };
 
 typedef struct _ShmArea ShmArea;
-typedef struct _ShmBuffer ShmBuffer;
 
 struct _ShmArea
 {
@@ -112,6 +111,8 @@ struct _ShmBuffer
 
   int num_clients;
   int clients[0];
+
+  uint64_t tag;
 };
 
 
@@ -542,7 +543,7 @@ sp_writer_free_block (ShmBlock * block)
 /* Returns the number of client this has successfully been sent to */
 
 int
-sp_writer_send_buf (ShmPipe * self, char *buf, size_t size)
+sp_writer_send_buf (ShmPipe * self, char *buf, size_t size, uint64_t tag)
 {
   ShmArea *area = NULL;
   unsigned long offset = 0;
@@ -577,6 +578,7 @@ sp_writer_send_buf (ShmPipe * self, char *buf, size_t size)
   sb->size = size;
   sb->num_clients = self->num_clients;
   sb->ablock = ablock;
+  sb->tag = tag;
 
   for (client = self->clients; client; client = client->next) {
     struct CommandBuffer cb = { 0 };
@@ -892,3 +894,21 @@ sp_writer_get_path (ShmPipe * pipe)
 {
   return pipe->socket_path;
 }
+
+ShmBuffer *
+sp_writer_get_pending_buffers (ShmPipe * self)
+{
+  return self->buffers;
+}
+
+ShmBuffer *
+sp_writer_get_next_buffer (ShmBuffer * buffer)
+{
+  return buffer->next;
+}
+
+uint64_t
+sp_writer_buf_get_tag (ShmBuffer * buffer)
+{
+  return buffer->tag;
+}
index 9cf0d6c61c5cb9a654deb90f723b3625e5a2f576..eef8877d14ed2389c46b5a96dfca8eea303a27aa 100644 (file)
@@ -63,6 +63,7 @@
 #define __SHMPIPE_H__
 
 #include <stdlib.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -75,6 +76,7 @@ extern "C" {
 typedef struct _ShmClient ShmClient;
 typedef struct _ShmPipe ShmPipe;
 typedef struct _ShmBlock ShmBlock;
+typedef struct _ShmBuffer ShmBuffer;
 
 ShmPipe *sp_writer_create (const char *path, size_t size, mode_t perms);
 const char *sp_writer_get_path (ShmPipe *pipe);
@@ -90,7 +92,7 @@ int sp_writer_get_client_fd (ShmClient * client);
 
 ShmBlock *sp_writer_alloc_block (ShmPipe * self, size_t size);
 void sp_writer_free_block (ShmBlock *block);
-int sp_writer_send_buf (ShmPipe * self, char *buf, size_t size);
+int sp_writer_send_buf (ShmPipe * self, char *buf, size_t size, uint64_t tag);
 char *sp_writer_block_get_buf (ShmBlock *block);
 ShmPipe *sp_writer_block_get_pipe (ShmBlock *block);
 
@@ -104,6 +106,10 @@ ShmPipe *sp_client_open (const char *path);
 long int sp_client_recv (ShmPipe * self, char **buf);
 int sp_client_recv_finish (ShmPipe * self, char *buf);
 
+ShmBuffer *sp_writer_get_pending_buffers (ShmPipe * self);
+ShmBuffer *sp_writer_get_next_buffer (ShmBuffer * buffer);
+uint64_t sp_writer_buf_get_tag (ShmBuffer * buffer);
+
 #ifdef __cplusplus
 }
 #endif