From d3273796b164890083a1a20879df2536b11e4339 Mon Sep 17 00:00:00 2001 From: Andreas Frisch Date: Wed, 25 May 2016 13:30:28 +0200 Subject: [PATCH] implement "screensaver" (a.k.a. camera-saver), interrupt preview after x seconds and show video/audio/photo specified in ini --- default.ini | 11 ++- photobooth.c | 260 +++++++++++++++++++++++++++++++++++++++---------- photobooth.css | 2 +- photobooth.h | 11 ++- 4 files changed, 226 insertions(+), 58 deletions(-) diff --git a/default.ini b/default.ini index d6771e9..d60cf45 100644 --- a/default.ini +++ b/default.ini @@ -5,14 +5,19 @@ template = photobooth.ui stylesheet = photobooth.css overlay_image = overlay_print_rainbows.png +#screensaver_timeout -1 = disable +screensaver_timeout = 7 +#screensaver_file can be image, video, audio (or freezes preview if omitted) +screensaver_file = /home/fraxinas/Desktop/Troye Sivan - Youth (1080p AAC).mkv + [printer] backend = mitsu9550 dpi = 346 -width = 2076 -height = 1384 +width = 2100 +height = 1400 icc_profile = CP955_F.icc offset_x = 12.0 -offset_y = 16.0 +offset_y = 12.0 [camera] preview_width = 640 diff --git a/photobooth.c b/photobooth.c index 7ebfc39..3b26b86 100644 --- a/photobooth.c +++ b/photobooth.c @@ -43,8 +43,7 @@ struct _PhotoBoothPrivate GstVideoRectangle video_size; GThread *capture_thread; - gulong video_block_id; - gulong photo_block_id; + gulong video_block_id, photo_block_id, sink_block_id; guint32 countdown; gchar *overlay_image; @@ -64,13 +63,22 @@ struct _PhotoBoothPrivate GstElement *audio_pipeline; GstElement *audio_playbin; + + GstElement *screensaver_playbin; + gchar *countdown_audio_uri; + + gchar *screensaver_uri; + gint screensaver_timeout; + guint screensaver_timeout_id; + GstClockTime last_play_pos; }; #define MOVIEPIPE "moviepipe.mjpg" #define DEFAULT_CONFIG "default.ini" #define PREVIEW_FPS 24 #define DEFAULT_COUNTDOWN 5 +#define DEFAULT_SCREENSAVER_TIMEOUT -1 #define PRINT_DPI 346 #define PRINT_WIDTH 2076 #define PRINT_HEIGHT 1384 @@ -105,6 +113,8 @@ 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); +static gboolean photo_booth_screensaver (PhotoBooth *pb); +static gboolean photo_booth_screensaver_stop (PhotoBooth *pb); /* libgphoto2 */ static gboolean photo_booth_cam_init (CameraInfo **cam_info); @@ -171,9 +181,10 @@ static void photo_booth_init (PhotoBooth *pb) pb->cam_info = NULL; pb->pipeline = NULL; - photo_booth_change_state (pb, PB_STATE_NONE); + priv->state = PB_STATE_NONE; priv->video_block_id = 0; priv->photo_block_id = 0; + priv->sink_block_id = 0; if (mkfifo(MOVIEPIPE, 0666) == -1 && errno != EEXIST) { @@ -189,7 +200,6 @@ static void photo_booth_init (PhotoBooth *pb) } priv->capture_thread = NULL; - priv->countdown = DEFAULT_COUNTDOWN; priv->preview_fps = PREVIEW_FPS; priv->preview_width = PREVIEW_WIDTH; @@ -204,6 +214,12 @@ static void photo_booth_init (PhotoBooth *pb) priv->printer_backend = NULL; priv->printer_settings = NULL; priv->overlay_image = NULL; + priv->countdown_audio_uri = NULL; + priv->screensaver_uri = NULL; + priv->screensaver_timeout = DEFAULT_SCREENSAVER_TIMEOUT; + priv->screensaver_timeout_id = 0; + priv->last_play_pos = GST_CLOCK_TIME_NONE; + G_stylesheet_filename = NULL; G_template_filename = NULL; @@ -216,6 +232,9 @@ static void photo_booth_change_state (PhotoBooth *pb, PhotoboothState newstate) PhotoBoothPrivate *priv; priv = photo_booth_get_instance_private (pb); GST_DEBUG_OBJECT (pb, "change state %s -> %s", photo_booth_state_get_name (priv->state), photo_booth_state_get_name (newstate)); + gchar *dot_filename = g_strdup_printf ("state_change_%s_to_%s", photo_booth_state_get_name (priv->state), photo_booth_state_get_name (newstate)); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, dot_filename); + g_free (dot_filename); priv->state = newstate; } @@ -249,7 +268,7 @@ static void photo_booth_finalize (GObject *object) PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); GST_INFO_OBJECT (pb, "finalize"); - SEND_COMMAND (pb, CONTROL_STOP); + SEND_COMMAND (pb, CONTROL_QUIT); photo_booth_flush_pipe (pb->video_fd); g_thread_join (priv->capture_thread); if (pb->cam_info) @@ -269,6 +288,7 @@ static void photo_booth_dispose (GObject *object) if (priv->printer_settings != NULL) g_object_unref (priv->printer_settings); g_free (priv->countdown_audio_uri); + g_free (priv->screensaver_uri); g_free (priv->print_icc_profile); g_free (priv->cam_icc_profile); g_free (priv->overlay_image); @@ -334,6 +354,22 @@ void photo_booth_load_settings (PhotoBooth *pb, const gchar *filename) g_free (audioabsfilename); } priv->overlay_image = g_key_file_get_string (gkf, "general", "overlay_image", NULL); + priv->screensaver_timeout = g_key_file_get_integer (gkf, "general", "screensaver_timeout", NULL); + gchar *screensaverfile = g_key_file_get_string (gkf, "general", "screensaver_file", NULL); + if (screensaverfile) + { + gchar *screensaverabsfilename; + if (screensaverfile[0] != '/') + { + gchar *cur = g_get_current_dir (); + screensaverabsfilename = g_strdup_printf ("%s/%s", cur, screensaverfile); + } + else + screensaverabsfilename = g_strdup (screensaverfile); + priv->screensaver_uri = g_filename_to_uri (screensaverabsfilename, NULL, NULL); + g_free (screensaverfile); + g_free (screensaverabsfilename); + } } if (g_key_file_has_group (gkf, "printer")) { @@ -420,11 +456,18 @@ static gboolean photo_booth_cam_close (CameraInfo **cam_info) static void photo_booth_flush_pipe (int fd) { + GST_DEBUG ("flushing"); int rlen = 0; unsigned char buf[1024]; - fcntl (fd, F_SETFL, O_NONBLOCK); + const int flags = fcntl(fd, F_GETFL, 0); + fcntl (fd, F_SETFL, flags | O_NONBLOCK); while (rlen != -1) + { rlen = read (fd, buf, sizeof(buf)); + GST_DEBUG ("flushed %i", rlen); + } + fcntl (fd, F_SETFL, flags ^ O_NONBLOCK); + GST_DEBUG ("finished flushing"); } static void photo_booth_quit_signal (PhotoBooth *pb) @@ -451,12 +494,12 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) if (gp_file_new_from_fd (&gp_file, pb->video_fd) != GP_OK) { GST_ERROR_OBJECT (pb, "couldn't start capture thread because gp_file_new_from_fd (%d) failed!", pb->video_fd); - goto stop_running; + goto quit_thread; } while (TRUE) { - if (state == CAPTURE_STOP) - goto stop_running; + if (state == CAPTURE_QUIT) + goto quit_thread; struct pollfd rfd[2]; int timeout = 0; @@ -479,6 +522,13 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) } timeout = 5000; } + else if (state == CAPTURE_UNPAUSE && !pb->cam_info) + { + if (photo_booth_cam_init (&pb->cam_info)) + state = CAPTURE_VIDEO; + else + state = CAPTURE_INIT; + } else if (state == CAPTURE_PAUSED) timeout = 1000; else @@ -486,10 +536,12 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) int ret = poll(rfd, 1, timeout); + GST_TRACE_OBJECT (pb, "poll ret=%i, state=%i, cam_info@%p", ret, state, pb->cam_info); + if (G_UNLIKELY (ret == -1)) { GST_ERROR_OBJECT (pb, "SELECT ERROR!"); - goto stop_running; + goto quit_thread; } else if (ret == 0 && state == CAPTURE_VIDEO) { @@ -559,14 +611,14 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) char command; READ_COMMAND (pb, command, ret); switch (command) { - case CONTROL_STOP: - GST_DEBUG_OBJECT (pb, "CONTROL_STOP!"); - state = CAPTURE_STOP; - break; case CONTROL_PAUSE: GST_DEBUG_OBJECT (pb, "CONTROL_PAUSE!"); state = CAPTURE_PAUSED; break; + case CONTROL_UNPAUSE: + GST_DEBUG_OBJECT (pb, "CONTROL_UNPAUSE!"); + state = CAPTURE_UNPAUSE; + break; case CONTROL_VIDEO: GST_DEBUG_OBJECT (pb, "CONTROL_VIDEO"); state = CAPTURE_VIDEO; @@ -579,6 +631,10 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO"); state = CAPTURE_PHOTO; break; + case CONTROL_QUIT: + GST_DEBUG_OBJECT (pb, "CONTROL_QUIT!"); + state = CAPTURE_QUIT; + break; default: GST_ERROR_OBJECT (pb, "illegal control socket command %c received!", command); } @@ -586,14 +642,21 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb) } else if (state == CAPTURE_PAUSED) { - GST_LOG_OBJECT (pb, "captured thread paused... timeout. %s", photo_booth_state_get_name (priv->state)); + if (pb->cam_info) + { + GST_LOG_OBJECT (pb, "captured thread paused... close camera! %s", photo_booth_state_get_name (priv->state)); + photo_booth_cam_close (&pb->cam_info); +// photo_booth_flush_pipe (pb->video_fd); + } + else + GST_LOG_OBJECT (pb, "captured thread paused... timeout. %s", photo_booth_state_get_name (priv->state)); } } g_assert_not_reached (); return; - stop_running: + quit_thread: { if (gp_file) gp_file_unref (gp_file); @@ -716,7 +779,6 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb) { PhotoBoothPrivate *priv; GstBus *bus; - GstElement *video_sink; GtkWidget *gtkgstwidget; GstPad *ghost, *pad; @@ -724,40 +786,32 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb) pb->video_bin = build_video_bin (pb); pb->photo_bin = build_photo_bin (pb); - pb->output_bin = gst_element_factory_make ("bin", "output-bin"); pb->pipeline = gst_pipeline_new ("photobooth-pipeline"); - video_sink = gst_element_factory_make ("gtksink", NULL); + pb->video_sink = gst_element_factory_make ("gtksink", "video-sink"); // g_object_set (pb->video_sink, "sync", FALSE, NULL); - if (!(video_sink)) + if (!(pb->video_sink)) { GST_ERROR_OBJECT (pb, "Failed to create gtksink"); return FALSE; } - gst_bin_add (GST_BIN (pb->output_bin), video_sink); - - g_object_get (video_sink, "widget", >kgstwidget, NULL); + g_object_get (pb->video_sink, "widget", >kgstwidget, NULL); photo_booth_window_add_gtkgstwidget (priv->win, gtkgstwidget); g_object_unref (gtkgstwidget); gst_element_set_state (pb->pipeline, GST_STATE_PLAYING); - gst_element_set_state (pb->output_bin, GST_STATE_PLAYING); + gst_element_set_state (pb->video_sink, GST_STATE_PLAYING); - pad = gst_element_get_static_pad (video_sink, "sink"); - ghost = gst_ghost_pad_new ("sink", pad); - gst_object_unref (pad); - gst_pad_set_active (ghost, TRUE); - gst_element_add_pad (pb->output_bin, ghost); - gst_bin_add_many (GST_BIN (pb->pipeline), pb->video_bin, pb->photo_bin, pb->output_bin, NULL); + gst_bin_add_many (GST_BIN (pb->pipeline), pb->video_bin, pb->photo_bin, pb->video_sink, NULL); /* add watch for messages */ bus = gst_pipeline_get_bus (GST_PIPELINE (pb->pipeline)); gst_bus_add_watch (bus, (GstBusFunc) photo_booth_bus_callback, pb); + gst_object_unref (GST_OBJECT (bus)); - GstElement* playbin; priv->audio_pipeline = gst_pipeline_new ("audio-pipeline"); priv->audio_playbin = gst_element_factory_make ("playbin", "audio-playbin"); gst_bin_add (GST_BIN (priv->audio_pipeline), priv->audio_playbin); @@ -767,6 +821,7 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb) static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, PhotoBooth *pb) { + GstObject *src = GST_MESSAGE_SRC (message); PhotoBoothPrivate *priv; priv = photo_booth_get_instance_private (pb); switch (GST_MESSAGE_TYPE (message)) @@ -797,8 +852,11 @@ static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, Phot } case GST_MESSAGE_EOS: { - GST_INFO ("EOS"); - gtk_main_quit (); + if (src == GST_OBJECT (priv->screensaver_playbin)) + { + GST_DEBUG ("screensaver EOS, replay"); + gst_element_seek (priv->screensaver_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } break; } case GST_MESSAGE_STATE_CHANGED: @@ -806,18 +864,23 @@ static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, Phot GstState old_state, new_state; gst_message_parse_state_changed (message, &old_state, &new_state, NULL); GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION (old_state, new_state); - GstElement *src = GST_ELEMENT (GST_MESSAGE_SRC (message)); GST_LOG ("gst %" GST_PTR_FORMAT " state transition %s -> %s. %s", src, gst_element_state_get_name(GST_STATE_TRANSITION_CURRENT(transition)), gst_element_state_get_name(GST_STATE_TRANSITION_NEXT(transition)), photo_booth_state_get_name (priv->state)); - if (src == pb->output_bin && transition == GST_STATE_CHANGE_READY_TO_PAUSED) + if (src == GST_OBJECT (pb->video_sink) && transition == GST_STATE_CHANGE_READY_TO_PAUSED) { photo_booth_video_widget_ready (pb); } - if (src == pb->output_bin && transition == GST_STATE_CHANGE_PAUSED_TO_PLAYING) + if (src == GST_OBJECT (pb->video_sink) && transition == GST_STATE_CHANGE_PAUSED_TO_PLAYING) { - GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_video_start.dot"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_video_start"); GST_DEBUG ("video_bin GST_STATE_CHANGE_PAUSED_TO_PLAYING -> hide spinner!"); photo_booth_window_set_spinner (priv->win, FALSE); } + if (src == GST_OBJECT (priv->screensaver_playbin) && transition == GST_STATE_CHANGE_READY_TO_PAUSED) + { + GST_DEBUG ("screensaver_playbin GST_STATE_CHANGE_READY_TO_PAUSED last_play_pos=%" GST_TIME_FORMAT "", GST_TIME_ARGS (priv->last_play_pos)); + if (priv->last_play_pos != GST_CLOCK_TIME_NONE) + gst_element_seek (priv->screensaver_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, priv->last_play_pos, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } break; } case GST_MESSAGE_STREAM_START: @@ -871,21 +934,32 @@ static gboolean photo_booth_preview (PhotoBooth *pb) { PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); GstPad *pad; - if (priv->video_block_id) + if (!priv->photo_block_id) { - GST_DEBUG_OBJECT (pb, "photo_booth_preview! halt photo_bin..."); gst_element_set_state (pb->photo_bin, GST_STATE_READY); pad = gst_element_get_static_pad (pb->photo_bin, "src"); + GST_DEBUG_OBJECT (pad, "photo_booth_preview! halt photo_bin..."); priv->photo_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_photo_probecb, pb, NULL); gst_object_unref (pad); - gst_element_unlink (pb->photo_bin, pb->output_bin); - - GST_DEBUG_OBJECT (pb, "photo_booth_preview! unblock video_bin..."); + gst_element_unlink (pb->photo_bin, pb->video_sink); + } + if (priv->video_block_id) + { pad = gst_element_get_static_pad (pb->video_bin, "src"); + GST_DEBUG_OBJECT (pad, "photo_booth_preview! unblock video_bin pad@%p...", pad); gst_pad_remove_probe (pad, priv->video_block_id); gst_object_unref (pad); } - int ret = gst_element_link (pb->video_bin, pb->output_bin); + if (priv->sink_block_id) + { + pad = gst_element_get_static_pad (pb->video_sink, "sink"); + GST_DEBUG_OBJECT (pad, "photo_booth_preview! unblock video_sink pad@%p...", pad); + gst_pad_remove_probe (pad, priv->sink_block_id); + gst_object_unref (pad); + gst_element_set_state (pb->video_sink, GST_STATE_PLAYING); + } + int ret = gst_element_link (pb->video_bin, pb->video_sink); + GST_LOG_OBJECT (pb, "linked video-bin ! video-sink ret=%i", ret); gst_element_set_state (pb->video_bin, GST_STATE_PLAYING); int cooldown_delay = 2000; if (priv->state == PB_STATE_NONE) @@ -893,7 +967,7 @@ static gboolean photo_booth_preview (PhotoBooth *pb) photo_booth_change_state (pb, PB_STATE_PREVIEW_COOLDOWN); gtk_label_set_text (priv->win->status, _("Please wait...")); g_timeout_add (cooldown_delay, (GSourceFunc) photo_booth_preview_ready, pb); - GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_preview.dot"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_preview"); SEND_COMMAND (pb, CONTROL_VIDEO); return FALSE; } @@ -903,6 +977,79 @@ static gboolean photo_booth_preview_ready (PhotoBooth *pb) PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); photo_booth_change_state (pb, PB_STATE_PREVIEW); gtk_label_set_text (priv->win->status, _("Touch screen to take a photo!")); + if (priv->screensaver_timeout > 0) + priv->screensaver_timeout_id = g_timeout_add_seconds (priv->screensaver_timeout, (GSourceFunc) photo_booth_screensaver, pb); + return FALSE; +} + +static gboolean photo_booth_screensaver (PhotoBooth *pb) +{ + PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); + photo_booth_change_state (pb, PB_STATE_SCREENSAVER); + + priv->screensaver_timeout_id = 0; + + GstPad *pad; + if (!priv->photo_block_id) + { + gst_element_set_state (pb->photo_bin, GST_STATE_READY); + pad = gst_element_get_static_pad (pb->photo_bin, "src"); + GST_DEBUG_OBJECT (pad, "showing screensaver! halt photo_bin..."); + priv->photo_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_photo_probecb, pb, NULL); + gst_object_unref (pad); + gst_element_unlink (pb->photo_bin, pb->video_sink); + } + if (!priv->video_block_id) + { + pad = gst_element_get_static_pad (pb->video_bin, "src"); + gst_element_set_state (pb->video_bin, GST_STATE_READY); + GST_DEBUG_OBJECT (pad, "showing screensaver! halt video_bin..."); + priv->video_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_video_probecb, pb, NULL); + GST_DEBUG_OBJECT (pad, "pad@%p id = %i", pad, priv->video_block_id); + gst_object_unref (pad); + gst_element_unlink (pb->video_bin, pb->video_sink); + } + + SEND_COMMAND (pb, CONTROL_PAUSE); + + priv->screensaver_playbin = gst_element_factory_make ("playbin", "screensaver-playbin"); + gst_object_ref (pb->video_sink); + gst_bin_remove (GST_BIN (pb->pipeline), pb->video_sink); + g_object_set (priv->screensaver_playbin, "video-sink", pb->video_sink, NULL); + + if (priv->screensaver_uri) + g_object_set (priv->screensaver_playbin, "uri", priv->screensaver_uri, NULL); + gst_element_set_state (priv->screensaver_playbin, GST_STATE_PLAYING); + + GstBus *bus; + bus = gst_pipeline_get_bus (GST_PIPELINE (priv->screensaver_playbin)); + gst_bus_add_watch (bus, (GstBusFunc) photo_booth_bus_callback, pb); + gst_object_unref (GST_OBJECT (bus)); + + gtk_label_set_text (priv->win->status, _("Touch screen to take a photo!")); + return FALSE; +} + +static gboolean photo_booth_screensaver_stop (PhotoBooth *pb) +{ + PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); + + GstPad *pad; + pad = gst_element_get_static_pad (pb->video_sink, "sink"); + priv->sink_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_video_probecb, pb, NULL); + + gst_element_query_position (priv->screensaver_playbin, GST_FORMAT_TIME, &priv->last_play_pos); + GST_DEBUG ("stop screensaver @ %" GST_TIME_FORMAT "", GST_TIME_ARGS (priv->last_play_pos)); + + gst_element_set_state (priv->screensaver_playbin, GST_STATE_NULL); + gst_element_set_state (pb->pipeline, GST_STATE_READY); + + gst_bin_add (GST_BIN (pb->pipeline), pb->video_sink); + gst_object_unref (pb->video_sink); + + SEND_COMMAND (pb, CONTROL_UNPAUSE); + photo_booth_preview (pb); + return FALSE; } @@ -912,6 +1059,12 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); priv = photo_booth_get_instance_private (pb); GST_INFO_OBJECT (pb, "background clicked in state %s", photo_booth_state_get_name (priv->state)); + if (priv->screensaver_timeout_id) + { + int ret = g_source_remove (priv->screensaver_timeout_id); + GST_DEBUG_OBJECT (pb, "removing screensaver_timeout"); + priv->screensaver_timeout_id = 0; + } switch (priv->state) { case PB_STATE_PREVIEW: { @@ -928,9 +1081,15 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P case PB_STATE_WAITING_FOR_ANSWER: { gtk_widget_hide (GTK_WIDGET (priv->win->button_yes)); + SEND_COMMAND (pb, CONTROL_UNPAUSE); photo_booth_preview (pb); break; } + case PB_STATE_SCREENSAVER: + { + photo_booth_screensaver_stop (pb); + break; + } default: break; } @@ -1040,7 +1199,7 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb) gboolean ret; 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_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_pre_snapshot"); photo_booth_change_state (pb, PB_STATE_TAKING_PHOTO); @@ -1059,7 +1218,7 @@ static gboolean photo_booth_snapshot_trigger (PhotoBooth *pb) 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"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_snapshot_trigger"); priv = photo_booth_get_instance_private (pb); @@ -1072,7 +1231,7 @@ static gboolean photo_booth_snapshot_trigger (PhotoBooth *pb) pad = gst_element_get_static_pad (pb->video_bin, "src"); priv->video_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_video_probecb, pb, NULL); gst_object_unref (pad); - gst_element_unlink (pb->video_bin, pb->output_bin); + gst_element_unlink (pb->video_bin, pb->video_sink); if (priv->photo_block_id) { @@ -1082,7 +1241,7 @@ static gboolean photo_booth_snapshot_trigger (PhotoBooth *pb) gst_object_unref (pad); } - ret = gst_element_link (pb->photo_bin, pb->output_bin); + ret = gst_element_link (pb->photo_bin, pb->video_sink); gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING); return FALSE; @@ -1300,7 +1459,7 @@ static gboolean photo_booth_process_photo_plug_elements (PhotoBooth *pb) gst_object_unref (tee); gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING); - GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_process_photo_plug_elements.dot"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_process_photo_plug_elements"); g_mutex_unlock (&priv->processing_mutex); GST_DEBUG_OBJECT (pb, "plugged photo processing elements and unlocked."); @@ -1400,7 +1559,7 @@ static void photo_booth_print (PhotoBooth *pb) { PhotoBoothPrivate *priv; priv = photo_booth_get_instance_private (pb); - GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_photo_print.dot"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_photo_print"); photo_booth_get_printer_status (pb); GST_INFO_OBJECT (pb, "PRINT! prints_remaining=%i", priv->prints_remaining); gtk_widget_hide (GTK_WIDGET (priv->win->button_yes)); @@ -1556,6 +1715,7 @@ const gchar* photo_booth_state_get_name (PhotoboothState state) case PB_STATE_PROCESS_PHOTO: return "PB_STATE_PROCESS_PHOTO";break; case PB_STATE_WAITING_FOR_ANSWER: return "PB_STATE_WAITING_FOR_ANSWER";break; case PB_STATE_PRINTING: return "PB_STATE_PRINTING";break; + case PB_STATE_SCREENSAVER: return "PB_STATE_SCREENSAVER";break; default: return "STATE UNKOWN!";break; } return ""; diff --git a/photobooth.css b/photobooth.css index 385dc3b..3c87855 100644 --- a/photobooth.css +++ b/photobooth.css @@ -25,6 +25,6 @@ .status_label { color: white; font-weight: bold; - font-size: 14px; + font-size: 12px; } diff --git a/photobooth.h b/photobooth.h index 1664603..70f8783 100644 --- a/photobooth.h +++ b/photobooth.h @@ -27,7 +27,8 @@ #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_UNPAUSE '5' /* unpause capture */ +#define CONTROL_QUIT '0' /* quit 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] @@ -67,8 +68,9 @@ typedef enum CAPTURE_PRETRIGGER, CAPTURE_PHOTO, CAPTURE_PAUSED, - CAPTURE_STOP, + CAPTURE_UNPAUSE, CAPTURE_FAILED, + CAPTURE_QUIT, } PhotoboothCaptureThreadState; typedef enum @@ -80,7 +82,8 @@ typedef enum PB_STATE_TAKING_PHOTO, PB_STATE_PROCESS_PHOTO, PB_STATE_WAITING_FOR_ANSWER, - PB_STATE_PRINTING + PB_STATE_PRINTING, + PB_STATE_SCREENSAVER } PhotoboothState; gchar *G_template_filename; @@ -107,7 +110,7 @@ struct _PhotoBooth GstElement *pipeline; GstElement *video_bin; GstElement *photo_bin; - GstElement *output_bin; + GstElement *video_sink; int video_fd; gint timeout_id;