From abdb30c567f02fd899210831f5f5e8e06ff712eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Fri, 12 Nov 2010 00:40:33 +0100 Subject: [PATCH] celvideosrc: fix nasty deadlock We cannot call any CMBufferQueue functions while holding the lock that our callback also depends on. So now we make use of CMBufferQueue's trigger API in order to get notified when the queue has data. --- sys/applemedia/celvideosrc.c | 79 ++++++++++++++++++++++++++------------------ sys/applemedia/celvideosrc.h | 7 ++-- 2 files changed, 51 insertions(+), 35 deletions(-) diff --git a/sys/applemedia/celvideosrc.c b/sys/applemedia/celvideosrc.c index e5118c5..6ea15e8 100644 --- a/sys/applemedia/celvideosrc.c +++ b/sys/applemedia/celvideosrc.c @@ -26,11 +26,11 @@ #define DEFAULT_DEVICE_INDEX -1 #define DEFAULT_DO_STATS FALSE -#define BUFQUEUE_LOCK(instance) GST_OBJECT_LOCK (instance) -#define BUFQUEUE_UNLOCK(instance) GST_OBJECT_UNLOCK (instance) -#define BUFQUEUE_WAIT(instance) \ - g_cond_wait (instance->cond, GST_OBJECT_GET_LOCK (instance)) -#define BUFQUEUE_NOTIFY(instance) g_cond_signal (instance->cond) +#define QUEUE_READY_LOCK(instance) GST_OBJECT_LOCK (instance) +#define QUEUE_READY_UNLOCK(instance) GST_OBJECT_UNLOCK (instance) +#define QUEUE_READY_WAIT(instance) \ + g_cond_wait (instance->ready_cond, GST_OBJECT_GET_LOCK (instance)) +#define QUEUE_READY_NOTIFY(instance) g_cond_signal (instance->ready_cond) GST_DEBUG_CATEGORY (gst_cel_video_src_debug); #define GST_CAT_DEFAULT gst_cel_video_src_debug @@ -92,7 +92,7 @@ gst_cel_video_src_init (GstCelVideoSrc * self, GstCelVideoSrcClass * gclass) gst_base_src_set_live (base_src, TRUE); gst_base_src_set_format (base_src, GST_FORMAT_TIME); - self->cond = g_cond_new (); + self->ready_cond = g_cond_new (); } static void @@ -106,7 +106,7 @@ gst_cel_video_src_finalize (GObject * object) { GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object); - g_cond_free (self->cond); + g_cond_free (self->ready_cond); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -282,7 +282,7 @@ gst_cel_video_src_start (GstBaseSrc * basesrc) { GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc); - self->running = TRUE; + g_atomic_int_set (&self->is_running, TRUE); self->offset = 0; self->last_sampling = GST_CLOCK_TIME_NONE; @@ -335,10 +335,11 @@ gst_cel_video_src_unlock (GstBaseSrc * basesrc) { GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc); - BUFQUEUE_LOCK (self); - self->running = FALSE; - BUFQUEUE_NOTIFY (self); - BUFQUEUE_UNLOCK (self); + g_atomic_int_set (&self->is_running, FALSE); + + QUEUE_READY_LOCK (self); + QUEUE_READY_NOTIFY (self); + QUEUE_READY_UNLOCK (self); return TRUE; } @@ -349,18 +350,16 @@ gst_cel_video_src_unlock_stop (GstBaseSrc * basesrc) return TRUE; } -static Boolean -gst_cel_video_src_validate (CMBufferQueueRef queue, CMSampleBufferRef buf, - void *refCon) +static void +gst_cel_video_src_on_queue_ready (void *triggerRefcon, + CMBufferQueueTriggerToken triggerToken) { - GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (refCon); - - BUFQUEUE_LOCK (self); - self->has_pending = TRUE; - BUFQUEUE_NOTIFY (self); - BUFQUEUE_UNLOCK (self); + GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (triggerRefcon); - return FALSE; + QUEUE_READY_LOCK (self); + self->queue_is_ready = TRUE; + QUEUE_READY_NOTIFY (self); + QUEUE_READY_UNLOCK (self); } static void @@ -437,16 +436,24 @@ gst_cel_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf) { GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (pushsrc); GstCMApi *cm = self->ctx->cm; - CMSampleBufferRef sbuf = NULL; + CMSampleBufferRef sbuf; - BUFQUEUE_LOCK (self); - while (self->running && !self->has_pending) - BUFQUEUE_WAIT (self); sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue); - self->has_pending = !cm->CMBufferQueueIsEmpty (self->queue); - BUFQUEUE_UNLOCK (self); - if (G_UNLIKELY (!self->running)) + while (sbuf == NULL) { + QUEUE_READY_LOCK (self); + while (!self->queue_is_ready && g_atomic_int_get (&self->is_running)) + QUEUE_READY_WAIT (self); + self->queue_is_ready = FALSE; + QUEUE_READY_UNLOCK (self); + + if (G_UNLIKELY (!g_atomic_int_get (&self->is_running))) + goto shutting_down; + + sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue); + } + + if (G_UNLIKELY (!g_atomic_int_get (&self->is_running))) goto shutting_down; *buf = gst_core_media_buffer_new (self->ctx, sbuf); @@ -485,6 +492,7 @@ gst_cel_video_src_open_device (GstCelVideoSrc * self) FigBaseObjectRef stream_base; FigBaseVTable *stream_vt; CMBufferQueueRef queue = NULL; + CMTime ignored_time; ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA | GST_API_MEDIA_TOOLBOX | GST_API_CELESTIAL, &error); @@ -532,10 +540,15 @@ gst_cel_video_src_open_device (GstCelVideoSrc * self) if (status != noErr) goto unexpected_error; - self->has_pending = FALSE; + self->queue_is_ready = FALSE; - cm->CMBufferQueueSetValidationCallback (queue, - gst_cel_video_src_validate, self); + ignored_time = cm->CMTimeMake (1, 1); + status = cm->CMBufferQueueInstallTrigger (queue, + gst_cel_video_src_on_queue_ready, self, + kCMBufferQueueTrigger_WhenDataBecomesReady, ignored_time, + &self->ready_trigger); + if (status != noErr) + goto unexpected_error; self->ctx = ctx; @@ -619,7 +632,9 @@ gst_cel_video_src_close_device (GstCelVideoSrc * self) self->device_base = NULL; self->device_base_iface = NULL; + self->ctx->cm->CMBufferQueueRemoveTrigger (self->queue, self->ready_trigger); self->ctx->cm->FigBufferQueueRelease (self->queue); + self->ready_trigger = NULL; self->queue = NULL; g_object_unref (self->ctx); diff --git a/sys/applemedia/celvideosrc.h b/sys/applemedia/celvideosrc.h index 0b8ff67..f314b93 100644 --- a/sys/applemedia/celvideosrc.h +++ b/sys/applemedia/celvideosrc.h @@ -61,15 +61,16 @@ struct _GstCelVideoSrc FigBaseIface *stream_base_iface; CMBufferQueueRef queue; + CMBufferQueueTriggerToken ready_trigger; GstCaps *device_caps; GArray *device_formats; GstClockTime duration; - volatile gboolean running; + volatile gint is_running; guint64 offset; - GCond *cond; - volatile gboolean has_pending; + GCond *ready_cond; + volatile gboolean queue_is_ready; GstClockTime last_sampling; guint count; -- 2.7.4