Skip to content

Commit

Permalink
[droidcamsrc] call droid_media_camera_take_picture from another thread
Browse files Browse the repository at this point in the history
take_picture call in HAL sometimes need to read information from preview
frames for e.g. auto exposure when using flash. If the calling thread
also handles pulling preview frames, this will create a deadlock.

To prevent this, I've moved the actual droid_media_camera_take_picture()
call to a function that will be called in a background thread. The
GstTaskPool is used to execute the function in the glib's thread pool,
so that the new thread doesn't have to be created every time.

This fixed taking a picture with the flash on on Fairphone 2 with
Halium 7.1-based port and Ubuntu Touch.
  • Loading branch information
peat-psuwit committed May 7, 2020
1 parent 95a19dc commit c637485
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
61 changes: 57 additions & 4 deletions gst/droidcamsrc/gstdroidcamsrcdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ GST_DEBUG_CATEGORY_EXTERN (gst_droid_camsrc_debug);

struct _GstDroidCamSrcImageCaptureState
{
gboolean running;
gboolean image_preview_sent;
gboolean image_start_sent;
};
Expand Down Expand Up @@ -542,6 +543,8 @@ gst_droidcamsrc_dev_new (GstDroidCamSrcPad * vfsrc,

dev->viewfinder_format = GST_VIDEO_FORMAT_UNKNOWN;

dev->task_pool = gst_task_pool_new ();

return dev;
}

Expand Down Expand Up @@ -646,6 +649,9 @@ gst_droidcamsrc_dev_destroy (GstDroidCamSrcDev * dev)

gst_droidcamsrc_recorder_destroy (dev->recorder);

gst_task_pool_cleanup (dev->task_pool); // Just in case
gst_object_unref (dev->task_pool);

g_slice_free (GstDroidCamSrcImageCaptureState, dev->img);
g_slice_free (GstDroidCamSrcVideoCaptureState, dev->vid);
g_slice_free (GstDroidCamSrcDev, dev);
Expand All @@ -655,6 +661,8 @@ gst_droidcamsrc_dev_destroy (GstDroidCamSrcDev * dev)
gboolean
gst_droidcamsrc_dev_init (GstDroidCamSrcDev * dev)
{
GError *err = NULL;

GST_DEBUG ("dev init");

g_rec_mutex_lock (dev->lock);
Expand Down Expand Up @@ -690,6 +698,13 @@ gst_droidcamsrc_dev_init (GstDroidCamSrcDev * dev)

g_rec_mutex_unlock (dev->lock);

gst_task_pool_prepare (dev->task_pool, &err);
if (err != NULL) {
GST_ERROR ("Failed to prepare thread pool: %s", err->message);
g_error_free (err);
return FALSE;
}

return TRUE;
}

Expand All @@ -706,6 +721,8 @@ gst_droidcamsrc_dev_deinit (GstDroidCamSrcDev * dev)
}

g_rec_mutex_unlock (dev->lock);

gst_task_pool_cleanup (dev->task_pool);
}

gboolean
Expand Down Expand Up @@ -832,22 +849,58 @@ gst_droidcamsrc_dev_set_params (GstDroidCamSrcDev * dev)
return ret;
}

static void
_take_picture (gpointer user_data)
{
GstDroidCamSrcDev *dev = (GstDroidCamSrcDev *) user_data;
GstDroidCamSrc *src = GST_DROIDCAMSRC (GST_PAD_PARENT (dev->imgsrc->pad));

const int msg_type = dev->c.CAMERA_MSG_SHUTTER | dev->c.CAMERA_MSG_RAW_IMAGE
| dev->c.CAMERA_MSG_POSTVIEW_FRAME | dev->c.CAMERA_MSG_COMPRESSED_IMAGE;

GST_DEBUG ("really calling droid_media_camera_take_picture");

g_rec_mutex_lock (dev->lock);

if (!droid_media_camera_take_picture (dev->cam, msg_type)) {
GST_ERROR ("error capturing image");
GST_ELEMENT_ERROR (src, LIBRARY, FAILED, (NULL), ("take_picture fails"));
}

dev->img->running = FALSE;

g_rec_mutex_unlock (dev->lock);
}

gboolean
gst_droidcamsrc_dev_capture_image (GstDroidCamSrcDev * dev)
{
gboolean ret = FALSE;
int msg_type = dev->c.CAMERA_MSG_SHUTTER | dev->c.CAMERA_MSG_RAW_IMAGE
| dev->c.CAMERA_MSG_POSTVIEW_FRAME | dev->c.CAMERA_MSG_COMPRESSED_IMAGE;
GError *err = NULL;

GST_DEBUG ("dev capture image");

g_rec_mutex_lock (dev->lock);

if (dev->img->running) {
GST_ERROR ("another capture is already in progress (?)");
goto out;
}

dev->img->running = TRUE;
dev->img->image_preview_sent = FALSE;
dev->img->image_start_sent = FALSE;

if (!droid_media_camera_take_picture (dev->cam, msg_type)) {
GST_ERROR ("error capturing image");
/*
* Call droid_media_camera_take_picture from another thread. take_picture
* call in HAL sometimes need to read information from preview frames for
* e.g. auto exposure when using flash. If the calling thread also handles
* pulling preview frames, this will create a deadlock.
*/
gst_task_pool_push (dev->task_pool, _take_picture, dev, &err);
if (err) {
GST_ERROR ("Failed to start take_picture task: %s", err->message);
g_error_free (err);
goto out;
}

Expand Down
2 changes: 2 additions & 0 deletions gst/droidcamsrc/gstdroidcamsrcdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ struct _GstDroidCamSrcDev

gboolean use_recorder;
GstDroidCamSrcRecorder *recorder;

GstTaskPool *task_pool;
};

GstDroidCamSrcDev *gst_droidcamsrc_dev_new (GstDroidCamSrcPad *vfsrc,
Expand Down

0 comments on commit c637485

Please sign in to comment.