allow pretriggering

This commit is contained in:
Andreas Frisch 2016-04-30 02:10:37 +02:00
parent ffe5bd6f69
commit af17cdfcfc
2 changed files with 82 additions and 41 deletions

View file

@ -64,6 +64,8 @@ struct _PhotoBoothPrivate
#define PREVIEW_WIDTH 640 #define PREVIEW_WIDTH 640
#define PREVIEW_HEIGHT 424 #define PREVIEW_HEIGHT 424
#define MOVIEPIPE "moviepipe.mjpg" #define MOVIEPIPE "moviepipe.mjpg"
#define CAM_REINIT_BEFORE_SNAPSHOT 1
#define CAM_REINIT_AFTER_SNAPSHOT 1
enum enum
{ {
@ -100,11 +102,13 @@ static void photo_booth_video_widget_ready (PhotoBooth *pb);
static gboolean photo_booth_preview (PhotoBooth *pb); static gboolean photo_booth_preview (PhotoBooth *pb);
static void photo_booth_snapshot_start (PhotoBooth *pb); static void photo_booth_snapshot_start (PhotoBooth *pb);
static gboolean photo_booth_snapshot_prepare (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); static gboolean photo_booth_snapshot_taken (PhotoBooth *pb);
/* libgphoto2 */ /* libgphoto2 */
static gboolean photo_booth_cam_init (CameraInfo **cam_info); static gboolean photo_booth_cam_init (CameraInfo **cam_info);
static gboolean photo_booth_cam_close (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 gboolean photo_booth_take_photo (CameraInfo *cam_info);
static void photo_booth_flush_pipe (int fd); static void photo_booth_flush_pipe (int fd);
static void photo_booth_capture_thread_func (PhotoBooth *pb); static void photo_booth_capture_thread_func (PhotoBooth *pb);
@ -488,9 +492,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
continue; continue;
} }
else { else {
g_mutex_lock (&pb->cam_info->mutex);
gp_file_get_mime_type (gp_file, &mime); gp_file_get_mime_type (gp_file, &mime);
g_mutex_unlock (&pb->cam_info->mutex);
if (strcmp (mime, GP_MIME_JPEG)) { if (strcmp (mime, GP_MIME_JPEG)) {
GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime); GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime);
continue; 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) else if (ret == 0 && state == CAPTURE_PHOTO)
{ {
if (pb->cam_info) if (pb->cam_info)
@ -509,8 +520,10 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
if (ret) if (ret)
{ {
g_main_context_invoke (NULL, (GSourceFunc) photo_booth_snapshot_taken, pb); 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_close (&pb->cam_info);
photo_booth_cam_init (&pb->cam_info); photo_booth_cam_init (&pb->cam_info);
#endif
} }
else { else {
gtk_label_set_text (priv->win->status, _("Taking photo failed!")); 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"); GST_DEBUG_OBJECT (pb, "CONTROL_VIDEO");
state = CAPTURE_VIDEO; state = CAPTURE_VIDEO;
break; break;
case CONTROL_PRETRIGGER:
GST_DEBUG_OBJECT (pb, "CONTROL_PRETRIGGER");
state = CAPTURE_PRETRIGGER;
break;
case CONTROL_PHOTO: case CONTROL_PHOTO:
GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO"); GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO");
state = CAPTURE_PHOTO; state = CAPTURE_PHOTO;
@ -620,7 +637,7 @@ static GstElement *build_video_bin (PhotoBooth *pb)
static GstElement *build_photo_bin (PhotoBooth *pb) static GstElement *build_photo_bin (PhotoBooth *pb)
{ {
GstElement *photo_bin; 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; GstCaps *caps;
GstPad *ghost, *pad; GstPad *ghost, *pad;
@ -641,6 +658,8 @@ static GstElement *build_photo_bin (PhotoBooth *pb)
g_object_set (photo_overlay, "overlay-height", PRINT_HEIGHT, NULL); g_object_set (photo_overlay, "overlay-height", PRINT_HEIGHT, NULL);
photo_convert = gst_element_factory_make ("videoconvert", "photo-convert"); 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"); 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)) 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; 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!"); GST_ERROR_OBJECT (photo_bin, "couldn't link photobin elements!");
return FALSE; return FALSE;
@ -948,15 +967,21 @@ static void photo_booth_snapshot_start (PhotoBooth *pb)
{ {
PhotoBoothPrivate *priv; PhotoBoothPrivate *priv;
gchar* uri; gchar* uri;
guint delay = 1; guint pretrigger_delay = 1;
guint snapshot_delay = 2;
priv = photo_booth_get_instance_private (pb); priv = photo_booth_get_instance_private (pb);
photo_booth_change_state (pb, PB_STATE_COUNTDOWN); photo_booth_change_state (pb, PB_STATE_COUNTDOWN);
photo_booth_window_start_countdown (priv->win, priv->countdown); photo_booth_window_start_countdown (priv->win, priv->countdown);
if (priv->countdown > 1) 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); pretrigger_delay = (priv->countdown*1000)-1500;
g_timeout_add (delay, (GSourceFunc) photo_booth_snapshot_prepare, pb); 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); uri = g_filename_to_uri (DEFAULT_AUDIOFILE_COUNTDOWN, NULL, NULL);
GST_DEBUG_OBJECT (pb, "audio uri: %s", uri); GST_DEBUG_OBJECT (pb, "audio uri: %s", uri);
g_object_set (priv->audio_playbin, "uri", uri, NULL); g_object_set (priv->audio_playbin, "uri", uri, NULL);
@ -970,16 +995,30 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
GstPad *pad; GstPad *pad;
gboolean ret; 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"); 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); photo_booth_change_state (pb, PB_STATE_TAKING_PHOTO);
priv = photo_booth_get_instance_private (pb); priv = photo_booth_get_instance_private (pb);
photo_booth_window_set_spinner (priv->win, TRUE); 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); gst_element_set_state ((priv->audio_pipeline), GST_STATE_READY);
SEND_COMMAND (pb, CONTROL_PHOTO); 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) static gboolean photo_booth_focus (CameraInfo *cam_info)
{ {
int gpret; int gpret;
// CameraEventType evttype; CameraEventType evttype;
// void *evtdata; void *evtdata;
// do { do {
// g_mutex_lock (&cam_info->mutex); g_mutex_lock (&cam_info->mutex);
// gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context);
// g_mutex_unlock (&cam_info->mutex); g_mutex_unlock (&cam_info->mutex);
// GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret);
// } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT));
//
// g_mutex_lock (&cam_info->mutex); g_mutex_lock (&cam_info->mutex);
// gpret = camera_auto_focus (cam_info->camera, cam_info->context, 1); gpret = camera_auto_focus (cam_info->camera, cam_info->context, 1);
// g_mutex_unlock (&cam_info->mutex); g_mutex_unlock (&cam_info->mutex);
// if (gpret != GP_OK) { if (gpret != GP_OK) {
// GST_WARNING ("gphoto error: %s\n", gp_result_as_string(gpret)); GST_WARNING ("gphoto error: %s\n", gp_result_as_string(gpret));
// return FALSE; return FALSE;
// } }
//
// do { do {
// GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret); GST_DEBUG ("gp_camera_wait_for_event gpret=%i", gpret);
// g_mutex_lock (&cam_info->mutex); g_mutex_lock (&cam_info->mutex);
// gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context); gpret = gp_camera_wait_for_event (cam_info->camera, 10, &evttype, &evtdata, cam_info->context);
// g_mutex_unlock (&cam_info->mutex); g_mutex_unlock (&cam_info->mutex);
// } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT)); } while ((gpret == GP_OK) && (evttype != GP_EVENT_TIMEOUT));
//
g_mutex_lock (&cam_info->mutex); g_mutex_lock (&cam_info->mutex);
gpret = camera_auto_focus (cam_info->camera, cam_info->context, 0); gpret = camera_auto_focus (cam_info->camera, cam_info->context, 0);
g_mutex_unlock (&cam_info->mutex); 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; float scale = (float) PT_PER_IN / (float) PRINT_DPI;
cairo_scale(cr, scale, scale); 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_paint(cr);
cairo_set_matrix(cr, &m); cairo_set_matrix(cr, &m);

View file

@ -23,10 +23,11 @@
#include <gphoto2/gphoto2.h> #include <gphoto2/gphoto2.h>
#include <gphoto2/gphoto2-camera.h> #include <gphoto2/gphoto2-camera.h>
#define CONTROL_VIDEO 'V' /* start movie capture */ #define CONTROL_VIDEO '1' /* start movie capture */
#define CONTROL_PHOTO 'T' /* photo capture */ #define CONTROL_PRETRIGGER '2' /* pretrigger */
#define CONTROL_PAUSE 'P' /* pause capture */ #define CONTROL_PHOTO '3' /* photo capture */
#define CONTROL_STOP 'S' /* stop capture thread */ #define CONTROL_PAUSE '4' /* pause capture */
#define CONTROL_STOP '0' /* stop capture thread */
#define CONTROL_SOCKETS(src) src->control_sock #define CONTROL_SOCKETS(src) src->control_sock
#define WRITE_SOCKET(src) src->control_sock[1] #define WRITE_SOCKET(src) src->control_sock[1]
#define READ_SOCKET(src) src->control_sock[0] #define READ_SOCKET(src) src->control_sock[0]
@ -66,6 +67,7 @@ typedef enum
{ {
CAPTURE_INIT = 0, CAPTURE_INIT = 0,
CAPTURE_VIDEO, CAPTURE_VIDEO,
CAPTURE_PRETRIGGER,
CAPTURE_PHOTO, CAPTURE_PHOTO,
CAPTURE_PAUSED, CAPTURE_PAUSED,
CAPTURE_STOP, CAPTURE_STOP,