Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / imagefreeze / gstimagefreeze.c
index 0db2e86..3e122ad 100644 (file)
@@ -135,6 +135,8 @@ gst_image_freeze_init (GstImageFreeze * self, GstImageFreezeClass * g_class)
   gst_pad_use_fixed_caps (self->srcpad);
   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
 
+  self->lock = g_mutex_new ();
+
   gst_image_freeze_reset (self);
 }
 
@@ -145,6 +147,10 @@ gst_image_freeze_finalize (GObject * object)
 
   gst_image_freeze_reset (self);
 
+  if (self->lock)
+    g_mutex_free (self->lock);
+  self->lock = NULL;
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -153,7 +159,7 @@ gst_image_freeze_reset (GstImageFreeze * self)
 {
   GST_DEBUG_OBJECT (self, "Resetting internal state");
 
-  GST_OBJECT_LOCK (self);
+  g_mutex_lock (self->lock);
   gst_buffer_replace (&self->buffer, NULL);
 
   gst_segment_init (&self->segment, GST_FORMAT_TIME);
@@ -162,7 +168,9 @@ gst_image_freeze_reset (GstImageFreeze * self)
 
   self->fps_n = self->fps_d = 0;
   self->offset = 0;
-  GST_OBJECT_UNLOCK (self);
+  g_mutex_unlock (self->lock);
+
+  g_atomic_int_set (&self->seeking, 0);
 }
 
 static gboolean
@@ -222,10 +230,10 @@ gst_image_freeze_sink_setcaps (GstPad * pad, GstCaps * caps)
           gst_structure_fixate_field_nearest_fraction (s, "framerate", 25, 1)) {
         gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
         if (fps_d != 0) {
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           self->fps_n = fps_n;
           self->fps_d = fps_d;
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, candidate);
           gst_pad_set_caps (self->srcpad, candidate);
           gst_caps_unref (candidate);
@@ -322,12 +330,22 @@ gst_image_freeze_sink_bufferalloc (GstPad * pad, guint64 offset, guint size,
 
   *buf = NULL;
 
-  GST_OBJECT_LOCK (self);
+  g_mutex_lock (self->lock);
   do_alloc = self->buffer == NULL;
-  GST_OBJECT_UNLOCK (self);
+  g_mutex_unlock (self->lock);
 
   if (do_alloc) {
-    ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
+    gboolean seeking = FALSE;
+
+    do {
+      GST_PAD_STREAM_LOCK (self->srcpad);
+      ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
+
+      seeking = ret == GST_FLOW_WRONG_STATE
+          && g_atomic_int_get (&self->seeking);
+      GST_PAD_STREAM_UNLOCK (self->srcpad);
+    } while (seeking);
+
     if (G_UNLIKELY (ret != GST_FLOW_OK))
       GST_ERROR_OBJECT (pad, "Allocating buffer failed: %s",
           gst_flow_get_name (ret));
@@ -362,14 +380,14 @@ gst_image_freeze_convert (GstImageFreeze * self,
     case GST_FORMAT_DEFAULT:{
       switch (*dest_format) {
         case GST_FORMAT_TIME:
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           if (self->fps_n == 0)
             *dest_value = -1;
           else
             *dest_value =
                 gst_util_uint64_scale (src_value, GST_SECOND * self->fps_d,
                 self->fps_n);
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
           break;
         default:
@@ -379,11 +397,11 @@ gst_image_freeze_convert (GstImageFreeze * self,
     case GST_FORMAT_TIME:{
       switch (*dest_format) {
         case GST_FORMAT_DEFAULT:
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           *dest_value =
               gst_util_uint64_scale (src_value, self->fps_n,
               self->fps_d * GST_SECOND);
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
           break;
         default:
@@ -443,15 +461,15 @@ gst_image_freeze_src_query (GstPad * pad, GstQuery * query)
       gst_query_parse_position (query, &format, NULL);
       switch (format) {
         case GST_FORMAT_DEFAULT:{
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           position = self->offset;
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
         }
         case GST_FORMAT_TIME:{
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           position = self->segment.last_stop;
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
         }
         default:
@@ -475,19 +493,19 @@ gst_image_freeze_src_query (GstPad * pad, GstQuery * query)
       gst_query_parse_duration (query, &format, NULL);
       switch (format) {
         case GST_FORMAT_TIME:{
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           duration = self->segment.stop;
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
         }
         case GST_FORMAT_DEFAULT:{
-          GST_OBJECT_LOCK (self);
+          g_mutex_lock (self->lock);
           duration = self->segment.stop;
           if (duration != -1)
             duration =
                 gst_util_uint64_scale (duration, self->fps_n,
                 GST_SECOND * self->fps_d);
-          GST_OBJECT_UNLOCK (self);
+          g_mutex_unlock (self->lock);
           ret = TRUE;
         }
         default:
@@ -535,6 +553,13 @@ gst_image_freeze_sink_event (GstPad * pad, GstEvent * event)
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_EOS:
+      if (!self->buffer) {
+        /* if we receive EOS before a buffer arrives, then let it pass */
+        GST_DEBUG_OBJECT (self, "EOS without input buffer, passing on");
+        ret = gst_pad_push_event (self->srcpad, event);
+        break;
+      }
+      /* fall-through */
     case GST_EVENT_NEWSEGMENT:
       GST_DEBUG_OBJECT (pad, "Dropping event");
       gst_event_unref (event);
@@ -583,7 +608,7 @@ gst_image_freeze_src_event (GstPad * pad, GstEvent * event)
           &stop_type, &stop);
       gst_event_unref (event);
 
-      flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+      flush = !!(flags & GST_SEEK_FLAG_FLUSH);
 
       if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
         GST_ERROR_OBJECT (pad, "Seek in invalid format: %s",
@@ -609,6 +634,7 @@ gst_image_freeze_src_event (GstPad * pad, GstEvent * event)
       if (flush) {
         GstEvent *e;
 
+        g_atomic_int_set (&self->seeking, 1);
         e = gst_event_new_flush_start ();
         gst_pad_push_event (self->srcpad, e);
       } else {
@@ -617,7 +643,7 @@ gst_image_freeze_src_event (GstPad * pad, GstEvent * event)
 
       GST_PAD_STREAM_LOCK (self->srcpad);
 
-      GST_OBJECT_LOCK (self);
+      g_mutex_lock (self->lock);
       gst_event_replace (&self->close_segment, NULL);
       if (!flush) {
         if (!self->need_segment && self->segment.rate >= 0) {
@@ -644,13 +670,14 @@ gst_image_freeze_src_event (GstPad * pad, GstEvent * event)
       last_stop = self->segment.last_stop;
 
       start_task = self->buffer != NULL;
-      GST_OBJECT_UNLOCK (self);
+      g_mutex_unlock (self->lock);
 
       if (flush) {
         GstEvent *e;
 
         e = gst_event_new_flush_stop ();
         gst_pad_push_event (self->srcpad, e);
+        g_atomic_int_set (&self->seeking, 0);
       }
 
       if (flags & GST_SEEK_FLAG_SEGMENT) {
@@ -665,9 +692,16 @@ gst_image_freeze_src_event (GstPad * pad, GstEvent * event)
 
       GST_DEBUG_OBJECT (pad, "Seek successful");
 
-      if (start_task)
-        gst_pad_start_task (self->srcpad,
-            (GstTaskFunction) gst_image_freeze_src_loop, self->srcpad);
+      if (start_task) {
+        g_mutex_lock (self->lock);
+
+        if (self->buffer != NULL)
+          gst_pad_start_task (self->srcpad,
+              (GstTaskFunction) gst_image_freeze_src_loop, self->srcpad);
+
+        g_mutex_unlock (self->lock);
+      }
+
       ret = TRUE;
       break;
     }
@@ -688,19 +722,19 @@ gst_image_freeze_sink_chain (GstPad * pad, GstBuffer * buffer)
 {
   GstImageFreeze *self = GST_IMAGE_FREEZE (GST_PAD_PARENT (pad));
 
-  GST_OBJECT_LOCK (self);
+  g_mutex_lock (self->lock);
   if (self->buffer) {
     GST_DEBUG_OBJECT (pad, "Already have a buffer, dropping");
     gst_buffer_unref (buffer);
-    GST_OBJECT_UNLOCK (self);
+    g_mutex_unlock (self->lock);
     return GST_FLOW_UNEXPECTED;
   }
 
   self->buffer = buffer;
-  GST_OBJECT_UNLOCK (self);
 
   gst_pad_start_task (self->srcpad, (GstTaskFunction) gst_image_freeze_src_loop,
       self->srcpad);
+  g_mutex_unlock (self->lock);
   return GST_FLOW_OK;
 }
 
@@ -710,20 +744,20 @@ gst_image_freeze_src_loop (GstPad * pad)
   GstImageFreeze *self = GST_IMAGE_FREEZE (GST_PAD_PARENT (pad));
   GstBuffer *buffer;
   guint64 offset;
-  GstClockTime timestamp, duration;
+  GstClockTime timestamp, timestamp_end;
   gint64 cstart, cstop;
   gboolean in_seg, eos;
 
-  GST_OBJECT_LOCK (self);
+  g_mutex_lock (self->lock);
   if (!self->buffer) {
     GST_ERROR_OBJECT (pad, "Have no buffer yet");
-    GST_OBJECT_UNLOCK (self);
+    g_mutex_unlock (self->lock);
     gst_pad_pause_task (self->srcpad);
     return;
   }
   buffer = gst_buffer_ref (self->buffer);
   buffer = gst_buffer_make_metadata_writable (buffer);
-  GST_OBJECT_UNLOCK (self);
+  g_mutex_unlock (self->lock);
 
   if (self->close_segment) {
     GST_DEBUG_OBJECT (pad, "Closing previous segment");
@@ -740,7 +774,7 @@ gst_image_freeze_src_loop (GstPad * pad)
         self->segment.applied_rate, self->segment.format, self->segment.start,
         self->segment.stop, self->segment.start);
 
-    GST_OBJECT_LOCK (self);
+    g_mutex_lock (self->lock);
     if (self->segment.rate >= 0) {
       self->offset =
           gst_util_uint64_scale (self->segment.start, self->fps_n,
@@ -750,37 +784,39 @@ gst_image_freeze_src_loop (GstPad * pad)
           gst_util_uint64_scale (self->segment.stop, self->fps_n,
           self->fps_d * GST_SECOND);
     }
-    GST_OBJECT_UNLOCK (self);
+    g_mutex_unlock (self->lock);
 
     self->need_segment = FALSE;
 
     gst_pad_push_event (self->srcpad, e);
   }
 
-  GST_OBJECT_LOCK (self);
+  g_mutex_lock (self->lock);
   offset = self->offset;
 
   if (self->fps_n != 0) {
     timestamp =
         gst_util_uint64_scale (offset, self->fps_d * GST_SECOND, self->fps_n);
-    duration = gst_util_uint64_scale_int (GST_SECOND, self->fps_d, self->fps_n);
+    timestamp_end =
+        gst_util_uint64_scale (offset + 1, self->fps_d * GST_SECOND,
+        self->fps_n);
   } else {
     timestamp = self->segment.start;
-    duration = GST_CLOCK_TIME_NONE;
+    timestamp_end = GST_CLOCK_TIME_NONE;
   }
+
   eos = (self->fps_n == 0 && offset > 0) ||
       (self->segment.rate >= 0 && self->segment.stop != -1
       && timestamp > self->segment.stop) || (self->segment.rate < 0
       && offset == 0) || (self->segment.rate < 0
-      && self->segment.start != -1
-      && timestamp + duration < self->segment.start);
+      && self->segment.start != -1 && timestamp_end < self->segment.start);
 
   if (self->fps_n == 0 && offset > 0)
     in_seg = FALSE;
   else
     in_seg =
         gst_segment_clip (&self->segment, GST_FORMAT_TIME, timestamp,
-        timestamp + duration, &cstart, &cstop);
+        timestamp_end, &cstart, &cstop);
 
   if (in_seg)
     gst_segment_set_last_stop (&self->segment, GST_FORMAT_TIME, cstart);
@@ -789,7 +825,7 @@ gst_image_freeze_src_loop (GstPad * pad)
     self->offset++;
   else
     self->offset--;
-  GST_OBJECT_UNLOCK (self);
+  g_mutex_unlock (self->lock);
 
   GST_DEBUG_OBJECT (pad, "Handling buffer with timestamp %" GST_TIME_FORMAT,
       GST_TIME_ARGS (timestamp));