applemedia: only enqueue buffers in the VideoToolbox callbacks
authorOle André Vadla Ravnås <oravnas@cisco.com>
Thu, 9 Dec 2010 23:58:58 +0000 (00:58 +0100)
committerOle André Vadla Ravnås <oravnas@cisco.com>
Fri, 10 Dec 2010 03:07:05 +0000 (04:07 +0100)
These callbacks may fire from any thread, hence we should only enqueue
buffers and let the streaming thread take care of the rest as soon as
the blocking encode or decode operation has finished.

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

index eb5d2f1..22db2e8 100644 (file)
@@ -45,7 +45,7 @@ static VTDecompressionSessionRef gst_vtdec_create_session (GstVTDec * self,
 static void gst_vtdec_destroy_session (GstVTDec * self,
     VTDecompressionSessionRef * session);
 static GstFlowReturn gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf);
-static void gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result,
+static void gst_vtdec_enqueue_frame (void *data, gsize unk1, VTStatus result,
     gsize unk2, CVBufferRef cvbuf);
 
 static CMSampleBufferRef gst_vtdec_sample_buffer_from (GstVTDec * self,
@@ -358,7 +358,7 @@ gst_vtdec_create_session (GstVTDec * self, CMFormatDescriptionRef fmt_desc)
   gst_vtutil_dict_set_i32 (pb_attrs,
       *(cv->kCVPixelBufferBytesPerRowAlignmentKey), 2 * self->negotiated_width);
 
-  callback.func = gst_vtdec_output_frame;
+  callback.func = gst_vtdec_enqueue_frame;
   callback.data = self;
 
   status = self->ctx->vt->VTDecompressionSessionCreate (NULL, fmt_desc,
@@ -407,13 +407,20 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf)
   self->cur_inbuf = NULL;
   gst_buffer_unref (buf);
 
+  if (self->cur_outbufs->len > 0) {
+    if (!gst_vtdec_negotiate_downstream (self))
+      ret = GST_FLOW_NOT_NEGOTIATED;
+  }
+
   for (i = 0; i != self->cur_outbufs->len; i++) {
     GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i);
 
-    if (ret == GST_FLOW_OK)
+    if (ret == GST_FLOW_OK) {
+      gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad));
       ret = gst_pad_push (self->srcpad, buf);
-    else
+    } else {
       gst_buffer_unref (buf);
+    }
   }
   g_ptr_array_set_size (self->cur_outbufs, 0);
 
@@ -421,7 +428,7 @@ gst_vtdec_decode_buffer (GstVTDec * self, GstBuffer * buf)
 }
 
 static void
-gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2,
+gst_vtdec_enqueue_frame (void *data, gsize unk1, VTStatus result, gsize unk2,
     CVBufferRef cvbuf)
 {
   GstVTDec *self = GST_VTDEC_CAST (data);
@@ -430,11 +437,7 @@ gst_vtdec_output_frame (void *data, gsize unk1, VTStatus result, gsize unk2,
   if (result != kVTSuccess)
     goto beach;
 
-  if (!gst_vtdec_negotiate_downstream (self))
-    goto beach;
-
   buf = gst_core_video_buffer_new (self->ctx, cvbuf);
-  gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad));
   gst_buffer_copy_metadata (buf, self->cur_inbuf,
       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
 
index 43a1622..c787848 100644 (file)
@@ -77,7 +77,7 @@ static VTStatus gst_vtenc_session_configure_property_double (GstVTEnc * self,
     VTCompressionSessionRef session, CFStringRef name, gdouble value);
 
 static GstFlowReturn gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf);
-static VTStatus gst_vtenc_output_buffer (void *data, int a2, int a3, int a4,
+static VTStatus gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4,
     CMSampleBufferRef sbuf, int a6, int a7);
 static gboolean gst_vtenc_buffer_is_keyframe (GstVTEnc * self,
     CMSampleBufferRef sbuf);
@@ -411,9 +411,7 @@ gst_vtenc_negotiate_downstream (GstVTEnc * self, CMSampleBufferRef sbuf)
     gst_buffer_unref (codec_data);
   }
 
-  GST_OBJECT_UNLOCK (self);
   result = gst_pad_set_caps (self->srcpad, caps);
-  GST_OBJECT_LOCK (self);
 
   gst_caps_unref (caps);
 
@@ -502,7 +500,7 @@ gst_vtenc_create_session (GstVTEnc * self)
   gst_vtutil_dict_set_i32 (pb_attrs, *(cv->kCVPixelBufferHeightKey),
       self->negotiated_height);
 
-  callback.func = gst_vtenc_output_buffer;
+  callback.func = gst_vtenc_enqueue_buffer;
   callback.data = self;
 
   status = vt->VTCompressionSessionCreate (NULL,
@@ -770,13 +768,22 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf)
   self->cur_inbuf = NULL;
   gst_buffer_unref (buf);
 
+  if (self->cur_outbufs->len > 0) {
+    GstCoreMediaBuffer *cmbuf =
+        GST_CORE_MEDIA_BUFFER_CAST (g_ptr_array_index (self->cur_outbufs, 0));
+    if (!gst_vtenc_negotiate_downstream (self, cmbuf->sample_buf))
+      ret = GST_FLOW_NOT_NEGOTIATED;
+  }
+
   for (i = 0; i != self->cur_outbufs->len; i++) {
     GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i);
 
-    if (ret == GST_FLOW_OK)
+    if (ret == GST_FLOW_OK) {
+      gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad));
       ret = gst_pad_push (self->srcpad, buf);
-    else
+    } else {
       gst_buffer_unref (buf);
+    }
   }
   g_ptr_array_set_size (self->cur_outbufs, 0);
 
@@ -792,7 +799,7 @@ cv_error:
 }
 
 static VTStatus
-gst_vtenc_output_buffer (void *data, int a2, int a3, int a4,
+gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4,
     CMSampleBufferRef sbuf, int a6, int a7)
 {
   GstVTEnc *self = data;
@@ -812,11 +819,7 @@ gst_vtenc_output_buffer (void *data, int a2, int a3, int a4,
   }
   self->expect_keyframe = FALSE;
 
-  if (!gst_vtenc_negotiate_downstream (self, sbuf))
-    goto beach;
-
   buf = gst_core_media_buffer_new (self->ctx, sbuf);
-  gst_buffer_set_caps (buf, GST_PAD_CAPS (self->srcpad));
   gst_buffer_copy_metadata (buf, self->cur_inbuf, GST_BUFFER_COPY_TIMESTAMPS);
   if (is_keyframe) {
     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);