From af17cdfcfc67a5056b514f60872fe98a61625a09 Mon Sep 17 00:00:00 2001 From: Andreas Frisch Date: Sat, 30 Apr 2016 02:10:37 +0200 Subject: [PATCH] allow pretriggering --- photobooth.c | 113 ++++++++++++++++++++++++++++++++++----------------- photobooth.h | 10 +++-- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/photobooth.c b/photobooth.c index b9d939c..d014b7f 100644 --- a/photobooth.c +++ b/photobooth.c @@ -64,6 +64,8 @@ struct _PhotoBoothPrivate #define PREVIEW_WIDTH 640 #define PREVIEW_HEIGHT 424 #define MOVIEPIPE "moviepipe.mjpg" +#define CAM_REINIT_BEFORE_SNAPSHOT 1 +#define CAM_REINIT_AFTER_SNAPSHOT 1 enum { @@ -100,11 +102,13 @@ static void photo_booth_video_widget_ready (PhotoBooth *pb); static gboolean photo_booth_preview (PhotoBooth *pb); static void photo_booth_snapshot_start (PhotoBooth *pb); static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb); +static gboolean photo_booth_snapshot_trigger (PhotoBooth *pb); static gboolean photo_booth_snapshot_taken (PhotoBooth *pb); /* libgphoto2 */ static gboolean photo_booth_cam_init (CameraInfo **cam_info); static gboolean photo_booth_cam_close (CameraInfo **cam_info); +static gboolean photo_booth_focus (CameraInfo *cam_info); static gboolean photo_booth_take_photo (CameraInfo *cam_info); static void photo_booth_flush_pipe (int fd); static void photo_booth_capture_thread_func (PhotoBooth *pb); @@ -488,9 +492,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) continue; } else { - g_mutex_lock (&pb->cam_info->mutex); gp_file_get_mime_type (gp_file, &mime); - g_mutex_unlock (&pb->cam_info->mutex); if (strcmp (mime, GP_MIME_JPEG)) { GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime); continue; @@ -500,6 +502,15 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) } } } + else if (ret == 0 && state == CAPTURE_PRETRIGGER) + { + gtk_label_set_text (priv->win->status, _("Focussing...")); +#if CAM_REINIT_BEFORE_SNAPSHOT + photo_booth_cam_close (&pb->cam_info); + photo_booth_cam_init (&pb->cam_info); +#endif + photo_booth_focus (pb->cam_info); + } else if (ret == 0 && state == CAPTURE_PHOTO) { if (pb->cam_info) @@ -509,8 +520,10 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) if (ret) { g_main_context_invoke (NULL, (GSourceFunc) photo_booth_snapshot_taken, pb); +#if CAM_REINIT_AFTER_SNAPSHOT photo_booth_cam_close (&pb->cam_info); photo_booth_cam_init (&pb->cam_info); +#endif } else { gtk_label_set_text (priv->win->status, _("Taking photo failed!")); @@ -538,6 +551,10 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) GST_DEBUG_OBJECT (pb, "CONTROL_VIDEO"); state = CAPTURE_VIDEO; break; + case CONTROL_PRETRIGGER: + GST_DEBUG_OBJECT (pb, "CONTROL_PRETRIGGER"); + state = CAPTURE_PRETRIGGER; + break; case CONTROL_PHOTO: GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO"); state = CAPTURE_PHOTO; @@ -620,7 +637,7 @@ static GstElement *build_video_bin (PhotoBooth *pb) static GstElement *build_photo_bin (PhotoBooth *pb) { GstElement *photo_bin; - GstElement *photo_source, *photo_decoder, *photo_freeze, *photo_scale, *photo_filter, *photo_overlay, *photo_convert, *photo_tee; + GstElement *photo_source, *photo_decoder, *photo_freeze, *photo_scale, *photo_filter, *photo_overlay, *photo_convert, *photo_gamma, *photo_tee; GstCaps *caps; GstPad *ghost, *pad; @@ -641,6 +658,8 @@ static GstElement *build_photo_bin (PhotoBooth *pb) g_object_set (photo_overlay, "overlay-height", PRINT_HEIGHT, NULL); photo_convert = gst_element_factory_make ("videoconvert", "photo-convert"); + photo_gamma = gst_element_factory_make ("gamma", "photo-gamma"); + g_object_set (photo_gamma, "gamma", 1.0, NULL); photo_tee = gst_element_factory_make ("tee", "photo-tee"); if (!(photo_bin && photo_source && photo_decoder && photo_freeze && photo_scale && photo_filter, photo_overlay && photo_convert && photo_tee)) @@ -649,9 +668,9 @@ static GstElement *build_photo_bin (PhotoBooth *pb) return FALSE; } - gst_bin_add_many (GST_BIN (photo_bin), photo_source, photo_decoder, photo_freeze, photo_scale, photo_filter, photo_overlay, photo_convert, photo_tee, NULL); + gst_bin_add_many (GST_BIN (photo_bin), photo_source, photo_decoder, photo_freeze, photo_scale, photo_filter, photo_overlay, photo_convert, photo_gamma, photo_tee, NULL); - if (!gst_element_link_many (photo_source, photo_decoder, photo_freeze, photo_scale, photo_filter, photo_overlay, photo_convert, photo_tee, NULL)) + if (!gst_element_link_many (photo_source, photo_decoder, photo_freeze, photo_scale, photo_filter, photo_overlay, photo_convert, photo_gamma, photo_tee, NULL)) { GST_ERROR_OBJECT (photo_bin, "couldn't link photobin elements!"); return FALSE; @@ -948,15 +967,21 @@ static void photo_booth_snapshot_start (PhotoBooth *pb) { PhotoBoothPrivate *priv; gchar* uri; - guint delay = 1; + guint pretrigger_delay = 1; + guint snapshot_delay = 2; priv = photo_booth_get_instance_private (pb); photo_booth_change_state (pb, PB_STATE_COUNTDOWN); photo_booth_window_start_countdown (priv->win, priv->countdown); if (priv->countdown > 1) - delay = (priv->countdown*1000)-100; - GST_DEBUG_OBJECT (pb, "started countdown of %d seconds, start taking photo in %d ms", priv->countdown, delay); - g_timeout_add (delay, (GSourceFunc) photo_booth_snapshot_prepare, pb); + { + pretrigger_delay = (priv->countdown*1000)-1500; + snapshot_delay = (priv->countdown*1000)-100; + } + GST_DEBUG_OBJECT (pb, "started countdown of %d seconds, pretrigger in %d ms, snapshot in %d ms", priv->countdown, pretrigger_delay, snapshot_delay); + g_timeout_add (pretrigger_delay, (GSourceFunc) photo_booth_snapshot_prepare, pb); + g_timeout_add (snapshot_delay, (GSourceFunc) photo_booth_snapshot_trigger, pb); + uri = g_filename_to_uri (DEFAULT_AUDIOFILE_COUNTDOWN, NULL, NULL); GST_DEBUG_OBJECT (pb, "audio uri: %s", uri); g_object_set (priv->audio_playbin, "uri", uri, NULL); @@ -970,16 +995,30 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb) GstPad *pad; gboolean ret; - GST_DEBUG_OBJECT (pb, "SNAPSHOT!"); + GST_DEBUG_OBJECT (pb, "photo_booth_snapshot_prepare!"); GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_pre_snapshot.dot"); - if (!pb->cam_info) - return FALSE; photo_booth_change_state (pb, PB_STATE_TAKING_PHOTO); priv = photo_booth_get_instance_private (pb); photo_booth_window_set_spinner (priv->win, TRUE); + SEND_COMMAND (pb, CONTROL_PRETRIGGER); + + return FALSE; +} + +static gboolean photo_booth_snapshot_trigger (PhotoBooth *pb) +{ + PhotoBoothPrivate *priv; + GstPad *pad; + gboolean ret; + + GST_DEBUG_OBJECT (pb, "photo_booth_snapshot_trigger"); + GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_snapshot_trigger.dot"); + + priv = photo_booth_get_instance_private (pb); + gst_element_set_state ((priv->audio_pipeline), GST_STATE_READY); SEND_COMMAND (pb, CONTROL_PHOTO); @@ -1010,32 +1049,32 @@ extern int camera_auto_focus (Camera *list, GPContext *context, int onoff); static gboolean photo_booth_focus (CameraInfo *cam_info) { int gpret; -// CameraEventType evttype; -// void *evtdata; + CameraEventType evttype; + void *evtdata; -// do { -// g_mutex_lock (&cam_info->mutex); -// gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); -// g_mutex_unlock (&cam_info->mutex); -// GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); -// } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); -// -// g_mutex_lock (&cam_info->mutex); -// gpret = camera_auto_focus (cam_info->camera, cam_info->context, 1); -// g_mutex_unlock (&cam_info->mutex); -// if (gpret != GP_OK) { -// GST_WARNING ("gphoto error: %s\n", gp_result_as_string(gpret)); -// return FALSE; -// } -// -// do { -// GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); -// g_mutex_lock (&cam_info->mutex); -// gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); -// g_mutex_unlock (&cam_info->mutex); -// } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); -// + do { + g_mutex_lock (&cam_info->mutex); + gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); + g_mutex_unlock (&cam_info->mutex); + GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); + } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); + + g_mutex_lock (&cam_info->mutex); + gpret = camera_auto_focus (cam_info->camera, cam_info->context, 1); + g_mutex_unlock (&cam_info->mutex); + if (gpret != GP_OK) { + GST_WARNING ("gphoto error: %s\n", gp_result_as_string(gpret)); + return FALSE; + } + + do { + GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); + g_mutex_lock (&cam_info->mutex); + gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); + g_mutex_unlock (&cam_info->mutex); + } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); + g_mutex_lock (&cam_info->mutex); gpret = camera_auto_focus (cam_info->camera, cam_info->context, 0); g_mutex_unlock (&cam_info->mutex); @@ -1375,7 +1414,7 @@ static void photo_booth_draw_page (GtkPrintOperation *operation, GtkPrintContext float scale = (float) PT_PER_IN / (float) PRINT_DPI; cairo_scale(cr, scale, scale); - cairo_set_source_surface(cr, cairosurface, -0.0, -0.0); // FIXME offsets? + cairo_set_source_surface(cr, cairosurface, 16.0, 16.0); // FIXME offsets? cairo_paint(cr); cairo_set_matrix(cr, &m); diff --git a/photobooth.h b/photobooth.h index 9a65ad4..b49bf45 100644 --- a/photobooth.h +++ b/photobooth.h @@ -23,10 +23,11 @@ #include #include -#define CONTROL_VIDEO 'V' /* start movie capture */ -#define CONTROL_PHOTO 'T' /* photo capture */ -#define CONTROL_PAUSE 'P' /* pause capture */ -#define CONTROL_STOP 'S' /* stop capture thread */ +#define CONTROL_VIDEO '1' /* start movie capture */ +#define CONTROL_PRETRIGGER '2' /* pretrigger */ +#define CONTROL_PHOTO '3' /* photo capture */ +#define CONTROL_PAUSE '4' /* pause capture */ +#define CONTROL_STOP '0' /* stop capture thread */ #define CONTROL_SOCKETS(src) src->control_sock #define WRITE_SOCKET(src) src->control_sock[1] #define READ_SOCKET(src) src->control_sock[0] @@ -66,6 +67,7 @@ typedef enum { CAPTURE_INIT = 0, CAPTURE_VIDEO, + CAPTURE_PRETRIGGER, CAPTURE_PHOTO, CAPTURE_PAUSED, CAPTURE_STOP,