applemedia: don't push synchronously from callback
authorOle André Vadla Ravnås <oravnas@cisco.com>
Wed, 10 Nov 2010 22:16:51 +0000 (23:16 +0100)
committerOle André Vadla Ravnås <oravnas@cisco.com>
Wed, 10 Nov 2010 23:22:31 +0000 (00:22 +0100)
The codec that called us might be holding locks to shared resources, so
we should never push downstream from within its buffer callback.

Note that a GstBufferList is not used here because we need to preserve
the buffer metadata held by our GstBuffer subclasses.

sys/applemedia/vtdec.c
sys/applemedia/vtdec.h
sys/applemedia/vtenc.c
sys/applemedia/vtenc.h

index bd8c050..eb5d2f1 100644 (file)
@@ -146,6 +146,8 @@ gst_vtdec_change_state (GstElement * element, GstStateChange transition)
         | GST_API_VIDEO_TOOLBOX, &error);
     if (error != NULL)
       goto api_error;
+
+    self->cur_outbufs = g_ptr_array_new ();
   }
 
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
@@ -161,6 +163,9 @@ gst_vtdec_change_state (GstElement * element, GstStateChange transition)
     self->caps_width = self->caps_height = 0;
     self->caps_fps_n = self->caps_fps_d = 0;
 
+    g_ptr_array_free (self->cur_outbufs, TRUE);
+    self->cur_outbufs = NULL;
+
     g_object_unref (self->ctx);
     self->ctx = NULL;
   }
@@ -380,10 +385,10 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf)
   GstVTApi *vt = self->ctx->vt;
   CMSampleBufferRef sbuf;
   VTStatus status;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint i;
 
   self->cur_inbuf = buf;
-  self->cur_flowret = GST_FLOW_OK;
-
   sbuf = gst_vtdec_sample_buffer_from (self, buf);
 
   status = vt->VTDecompressionSessionDecodeFrame (self->session, sbuf, 0, 0, 0);
@@ -399,11 +404,20 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf)
   }
 
   self->ctx->cm->FigSampleBufferRelease (sbuf);
-
-  gst_buffer_unref (buf);
   self->cur_inbuf = NULL;
+  gst_buffer_unref (buf);
+
+  for (i = 0; i != self->cur_outbufs->len; i++) {
+    GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i);
 
-  return self->cur_flowret;
+    if (ret == GST_FLOW_OK)
+      ret = gst_pad_push (self->srcpad, buf);
+    else
+      gst_buffer_unref (buf);
+  }
+  g_ptr_array_set_size (self->cur_outbufs, 0);
+
+  return ret;
 }
 
 static void
@@ -413,7 +427,7 @@ gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2,
   GstVTDec *self = GST_VTDEC_CAST (data);
   GstBuffer *buf;
 
-  if (result != kVTSuccess || self->cur_flowret != GST_FLOW_OK)
+  if (result != kVTSuccess)
     goto beach;
 
   if (!gst_vtdec_negotiate_downstream (self))
@@ -424,7 +438,7 @@ gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2,
   gst_buffer_copy_metadata (buf, self->cur_inbuf,
       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
 
-  self->cur_flowret = gst_pad_push (self->srcpad, buf);
+  g_ptr_array_add (self->cur_outbufs, buf);
 
 beach:
   return;
index 4176a09..3ebb26f 100644 (file)
@@ -70,7 +70,7 @@ struct _GstVTDec
   VTDecompressionSessionRef session;
 
   GstBuffer * cur_inbuf;
-  GstFlowReturn cur_flowret;
+  GPtrArray * cur_outbufs;
 };
 
 void gst_vtdec_register_elements (GstPlugin * plugin);
index e286e90..43a1622 100644 (file)
@@ -286,6 +286,8 @@ gst_vtenc_change_state (GstElement * element, GstStateChange transition)
         | GST_API_VIDEO_TOOLBOX, &error);
     if (error != NULL)
       goto api_error;
+
+    self->cur_outbufs = g_ptr_array_new ();
   }
 
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
@@ -307,6 +309,9 @@ gst_vtenc_change_state (GstElement * element, GstStateChange transition)
 
     GST_OBJECT_UNLOCK (self);
 
+    g_ptr_array_free (self->cur_outbufs, TRUE);
+    self->cur_outbufs = NULL;
+
     g_object_unref (self->ctx);
     self->ctx = NULL;
   }
@@ -713,9 +718,10 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf)
   CMTime ts, duration;
   CVPixelBufferRef pbuf = NULL;
   VTStatus vt_status;
+  GstFlowReturn ret = GST_FLOW_OK;
+  guint i;
 
   self->cur_inbuf = buf;
-  self->cur_flowret = GST_FLOW_OK;
 
   ts = self->ctx->cm->CMTimeMake
       (GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buf)), 1000);
@@ -761,16 +767,25 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf)
   GST_OBJECT_UNLOCK (self);
 
   cv->CVPixelBufferRelease (pbuf);
-
-  gst_buffer_unref (buf);
   self->cur_inbuf = NULL;
+  gst_buffer_unref (buf);
+
+  for (i = 0; i != self->cur_outbufs->len; i++) {
+    GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i);
 
-  return self->cur_flowret;
+    if (ret == GST_FLOW_OK)
+      ret = gst_pad_push (self->srcpad, buf);
+    else
+      gst_buffer_unref (buf);
+  }
+  g_ptr_array_set_size (self->cur_outbufs, 0);
+
+  return ret;
 
 cv_error:
   {
-    gst_buffer_unref (buf);
     self->cur_inbuf = NULL;
+    gst_buffer_unref (buf);
 
     return GST_FLOW_ERROR;
   }
@@ -810,9 +825,7 @@ gst_vtenc_output_buffer (void *data, int a2, int a3, int a4,
     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
   }
 
-  GST_OBJECT_UNLOCK (self);
-  self->cur_flowret = gst_pad_push (self->srcpad, buf);
-  GST_OBJECT_LOCK (self);
+  g_ptr_array_add (self->cur_outbufs, buf);
 
 beach:
   return kVTSuccess;
index 19d1c7c..875b2fb 100644 (file)
@@ -76,7 +76,7 @@ struct _GstVTEnc
   CFMutableDictionaryRef options;
 
   GstBuffer * cur_inbuf;
-  GstFlowReturn cur_flowret;
+  GPtrArray * cur_outbufs;
   gboolean expect_keyframe;
 };