From 9c5863ad3548cec9064b1b3edf04ddded70f1846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 15 Dec 2010 10:39:24 +0000 Subject: [PATCH] camerabin: don't rely on the application running the default GLib main loop Don't use g_idle_add() and friends to schedule things we can't do from the streaming thread in another thread. The app may not be running the default GLib main loop. Instead, just spawn a thread. Also, we need to care for when acessing a pad variable, as another thread might have taken camerabin to NULL while this gst_camerabin_imgbin_finished didn't run. https://bugzilla.gnome.org/show_bug.cgi?id=615655 --- gst/camerabin/gstcamerabin.c | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/gst/camerabin/gstcamerabin.c b/gst/camerabin/gstcamerabin.c index 20676ea691..a54c378adf 100644 --- a/gst/camerabin/gstcamerabin.c +++ b/gst/camerabin/gstcamerabin.c @@ -3931,17 +3931,20 @@ gst_camerabin_provide_clock (GstElement * element) return clock; } -static gboolean +static gpointer gst_camerabin_imgbin_finished (gpointer u_data) { GstCameraBin *camera = GST_CAMERABIN (u_data); gchar *filename = NULL; - /* Get the filename of the finished image */ - g_object_get (G_OBJECT (camera->imgbin), "filename", &filename, NULL); + /* FIXME: should set a flag (and take a lock) when going to NULL, so we + * short-circuit this bit if we got shut down between thread create and now */ GST_DEBUG_OBJECT (camera, "Image encoding finished"); + /* Get the filename of the finished image */ + g_object_get (G_OBJECT (camera->imgbin), "filename", &filename, NULL); + /* Close the file of saved image */ gst_element_set_state (camera->imgbin, GST_STATE_READY); GST_DEBUG_OBJECT (camera, "Image pipeline set to READY"); @@ -3951,26 +3954,35 @@ gst_camerabin_imgbin_finished (gpointer u_data) CAMERABIN_PROCESSING_DEC_UNLOCKED (camera); } else { /* Camerabin state change to READY may have reset processing counter to - * zero. This is possible as this functions is scheduled from g_idle_add + * zero. This is possible as this functions is scheduled from another + * thread. */ GST_WARNING_OBJECT (camera, "camerabin has been forced to idle"); } g_mutex_unlock (camera->capture_mutex); - /* Send image-done signal */ - gst_camerabin_image_capture_continue (camera, filename); - g_free (filename); - /* Set image bin back to PAUSED so that buffer-allocs don't fail */ gst_element_set_state (camera->imgbin, GST_STATE_PAUSED); /* Unblock image queue pad to process next buffer */ - gst_pad_set_blocked_async (camera->pad_src_queue, FALSE, - (GstPadBlockCallback) camerabin_pad_blocked, camera); - GST_DEBUG_OBJECT (camera, "Queue srcpad unblocked"); + GST_STATE_LOCK (camera); + if (camera->pad_src_queue) { + gst_pad_set_blocked_async (camera->pad_src_queue, FALSE, + (GstPadBlockCallback) camerabin_pad_blocked, camera); + GST_DEBUG_OBJECT (camera, "Queue srcpad unblocked"); + } else { + GST_DEBUG_OBJECT (camera, "Queue srcpad unreffed already, doesn't need " + "to unblock"); + } + GST_STATE_UNLOCK (camera); - /* disconnect automatically */ - return FALSE; + /* Send image-done signal */ + gst_camerabin_image_capture_continue (camera, filename); + g_free (filename); + + GST_INFO_OBJECT (camera, "leaving helper thread"); + gst_object_unref (camera); + return NULL; } /* @@ -3998,10 +4010,12 @@ gst_camerabin_handle_message_func (GstBin * bin, GstMessage * msg) } else if (GST_MESSAGE_SRC (msg) == GST_OBJECT (camera->imgbin)) { /* Image eos */ GST_DEBUG_OBJECT (camera, "got image eos message"); - /* Calling callback directly will deadlock in - imagebin state change functions */ - g_idle_add_full (G_PRIORITY_HIGH_IDLE, gst_camerabin_imgbin_finished, - camera, NULL); + /* Can't change state here, since we're in the streaming thread */ + if (!g_thread_create (gst_camerabin_imgbin_finished, + gst_object_ref (camera), FALSE, NULL)) { + /* FIXME: what do do if this fails? */ + gst_object_unref (camera); + } } break; case GST_MESSAGE_ERROR: