mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
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.
This commit is contained in:
parent
de76e9fdb6
commit
abdb30c567
2 changed files with 51 additions and 35 deletions
|
@ -26,11 +26,11 @@
|
||||||
#define DEFAULT_DEVICE_INDEX -1
|
#define DEFAULT_DEVICE_INDEX -1
|
||||||
#define DEFAULT_DO_STATS FALSE
|
#define DEFAULT_DO_STATS FALSE
|
||||||
|
|
||||||
#define BUFQUEUE_LOCK(instance) GST_OBJECT_LOCK (instance)
|
#define QUEUE_READY_LOCK(instance) GST_OBJECT_LOCK (instance)
|
||||||
#define BUFQUEUE_UNLOCK(instance) GST_OBJECT_UNLOCK (instance)
|
#define QUEUE_READY_UNLOCK(instance) GST_OBJECT_UNLOCK (instance)
|
||||||
#define BUFQUEUE_WAIT(instance) \
|
#define QUEUE_READY_WAIT(instance) \
|
||||||
g_cond_wait (instance->cond, GST_OBJECT_GET_LOCK (instance))
|
g_cond_wait (instance->ready_cond, GST_OBJECT_GET_LOCK (instance))
|
||||||
#define BUFQUEUE_NOTIFY(instance) g_cond_signal (instance->cond)
|
#define QUEUE_READY_NOTIFY(instance) g_cond_signal (instance->ready_cond)
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_cel_video_src_debug);
|
GST_DEBUG_CATEGORY (gst_cel_video_src_debug);
|
||||||
#define GST_CAT_DEFAULT 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_live (base_src, TRUE);
|
||||||
gst_base_src_set_format (base_src, GST_FORMAT_TIME);
|
gst_base_src_set_format (base_src, GST_FORMAT_TIME);
|
||||||
|
|
||||||
self->cond = g_cond_new ();
|
self->ready_cond = g_cond_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -106,7 +106,7 @@ gst_cel_video_src_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (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);
|
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);
|
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
|
||||||
|
|
||||||
self->running = TRUE;
|
g_atomic_int_set (&self->is_running, TRUE);
|
||||||
self->offset = 0;
|
self->offset = 0;
|
||||||
|
|
||||||
self->last_sampling = GST_CLOCK_TIME_NONE;
|
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);
|
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
|
||||||
|
|
||||||
BUFQUEUE_LOCK (self);
|
g_atomic_int_set (&self->is_running, FALSE);
|
||||||
self->running = FALSE;
|
|
||||||
BUFQUEUE_NOTIFY (self);
|
QUEUE_READY_LOCK (self);
|
||||||
BUFQUEUE_UNLOCK (self);
|
QUEUE_READY_NOTIFY (self);
|
||||||
|
QUEUE_READY_UNLOCK (self);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -349,18 +350,16 @@ gst_cel_video_src_unlock_stop (GstBaseSrc * basesrc)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Boolean
|
static void
|
||||||
gst_cel_video_src_validate (CMBufferQueueRef queue, CMSampleBufferRef buf,
|
gst_cel_video_src_on_queue_ready (void *triggerRefcon,
|
||||||
void *refCon)
|
CMBufferQueueTriggerToken triggerToken)
|
||||||
{
|
{
|
||||||
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (refCon);
|
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (triggerRefcon);
|
||||||
|
|
||||||
BUFQUEUE_LOCK (self);
|
QUEUE_READY_LOCK (self);
|
||||||
self->has_pending = TRUE;
|
self->queue_is_ready = TRUE;
|
||||||
BUFQUEUE_NOTIFY (self);
|
QUEUE_READY_NOTIFY (self);
|
||||||
BUFQUEUE_UNLOCK (self);
|
QUEUE_READY_UNLOCK (self);
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -437,16 +436,24 @@ gst_cel_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (pushsrc);
|
GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (pushsrc);
|
||||||
GstCMApi *cm = self->ctx->cm;
|
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);
|
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;
|
goto shutting_down;
|
||||||
|
|
||||||
*buf = gst_core_media_buffer_new (self->ctx, sbuf);
|
*buf = gst_core_media_buffer_new (self->ctx, sbuf);
|
||||||
|
@ -485,6 +492,7 @@ gst_cel_video_src_open_device (GstCelVideoSrc * self)
|
||||||
FigBaseObjectRef stream_base;
|
FigBaseObjectRef stream_base;
|
||||||
FigBaseVTable *stream_vt;
|
FigBaseVTable *stream_vt;
|
||||||
CMBufferQueueRef queue = NULL;
|
CMBufferQueueRef queue = NULL;
|
||||||
|
CMTime ignored_time;
|
||||||
|
|
||||||
ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
|
ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
|
||||||
| GST_API_MEDIA_TOOLBOX | GST_API_CELESTIAL, &error);
|
| GST_API_MEDIA_TOOLBOX | GST_API_CELESTIAL, &error);
|
||||||
|
@ -532,10 +540,15 @@ gst_cel_video_src_open_device (GstCelVideoSrc * self)
|
||||||
if (status != noErr)
|
if (status != noErr)
|
||||||
goto unexpected_error;
|
goto unexpected_error;
|
||||||
|
|
||||||
self->has_pending = FALSE;
|
self->queue_is_ready = FALSE;
|
||||||
|
|
||||||
cm->CMBufferQueueSetValidationCallback (queue,
|
ignored_time = cm->CMTimeMake (1, 1);
|
||||||
gst_cel_video_src_validate, self);
|
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;
|
self->ctx = ctx;
|
||||||
|
|
||||||
|
@ -619,7 +632,9 @@ gst_cel_video_src_close_device (GstCelVideoSrc * self)
|
||||||
self->device_base = NULL;
|
self->device_base = NULL;
|
||||||
self->device_base_iface = NULL;
|
self->device_base_iface = NULL;
|
||||||
|
|
||||||
|
self->ctx->cm->CMBufferQueueRemoveTrigger (self->queue, self->ready_trigger);
|
||||||
self->ctx->cm->FigBufferQueueRelease (self->queue);
|
self->ctx->cm->FigBufferQueueRelease (self->queue);
|
||||||
|
self->ready_trigger = NULL;
|
||||||
self->queue = NULL;
|
self->queue = NULL;
|
||||||
|
|
||||||
g_object_unref (self->ctx);
|
g_object_unref (self->ctx);
|
||||||
|
|
|
@ -61,15 +61,16 @@ struct _GstCelVideoSrc
|
||||||
FigBaseIface *stream_base_iface;
|
FigBaseIface *stream_base_iface;
|
||||||
|
|
||||||
CMBufferQueueRef queue;
|
CMBufferQueueRef queue;
|
||||||
|
CMBufferQueueTriggerToken ready_trigger;
|
||||||
GstCaps *device_caps;
|
GstCaps *device_caps;
|
||||||
GArray *device_formats;
|
GArray *device_formats;
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
|
|
||||||
volatile gboolean running;
|
volatile gint is_running;
|
||||||
guint64 offset;
|
guint64 offset;
|
||||||
|
|
||||||
GCond *cond;
|
GCond *ready_cond;
|
||||||
volatile gboolean has_pending;
|
volatile gboolean queue_is_ready;
|
||||||
|
|
||||||
GstClockTime last_sampling;
|
GstClockTime last_sampling;
|
||||||
guint count;
|
guint count;
|
||||||
|
|
Loading…
Reference in a new issue