fix print orientation, move post-processing into seperate mutex-protected main-thread functions, fix preview after snapshot, fix audio after snapshot, cleanup privat structure layout, implement change_state and get_state_name functions
This commit is contained in:
parent
c13627dbf3
commit
782dcda299
2 changed files with 211 additions and 141 deletions
258
photobooth.c
258
photobooth.c
|
@ -35,15 +35,24 @@ typedef struct _PhotoBoothPrivate PhotoBoothPrivate;
|
|||
|
||||
struct _PhotoBoothPrivate
|
||||
{
|
||||
PhotoboothState state;
|
||||
PhotoBoothWindow *win;
|
||||
GstVideoRectangle video_size;
|
||||
|
||||
GThread *capture_thread;
|
||||
gulong video_block_id;
|
||||
gulong photo_block_id;
|
||||
|
||||
guint32 countdown;
|
||||
|
||||
gchar *printer_backend;
|
||||
gint prints_remaining;
|
||||
GstElement *audio_playbin;
|
||||
GstVideoRectangle video_size;
|
||||
GThread *capture_thread;
|
||||
GstBuffer *print_buffer;
|
||||
GtkPrintSettings *printer_settings;
|
||||
GMutex processing_mutex;
|
||||
|
||||
GstElement *audio_pipeline;
|
||||
GstElement *audio_playbin;
|
||||
};
|
||||
|
||||
#define DEFAULT_AUDIOFILE_COUNTDOWN "/net/home/fraxinas/microcontroller/photobooth/beep.m4a"
|
||||
|
@ -82,6 +91,8 @@ void photo_booth_button_yes_clicked (GtkButton *button, PhotoBoothWindow *win);
|
|||
|
||||
/* general private functions */
|
||||
static void photo_booth_load_strings ();
|
||||
const gchar* photo_booth_state_get_name (PhotoboothState state);
|
||||
static void photo_booth_change_state (PhotoBooth *pb, PhotoboothState state);
|
||||
static void photo_booth_quit_signal (PhotoBooth *pb);
|
||||
static void photo_booth_window_destroyed_signal (PhotoBoothWindow *win, PhotoBooth *pb);
|
||||
static void photo_booth_setup_window (PhotoBooth *pb);
|
||||
|
@ -109,7 +120,7 @@ static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpoin
|
|||
static void photo_booth_free_print_buffer (PhotoBooth *pb);
|
||||
|
||||
/* printing functions */
|
||||
static void photo_booth_get_printer_status (PhotoBooth *pb);
|
||||
static gboolean photo_booth_get_printer_status (PhotoBooth *pb);
|
||||
static void photo_booth_print (PhotoBooth *pb);
|
||||
void photo_booth_button_yes_clicked (GtkButton *button, PhotoBoothWindow *win);
|
||||
static void photo_booth_begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data);
|
||||
|
@ -168,9 +179,9 @@ static void photo_booth_init (PhotoBooth *pb)
|
|||
pb->cam_info = NULL;
|
||||
|
||||
pb->pipeline = NULL;
|
||||
pb->state = PB_STATE_NONE;
|
||||
pb->video_block_id = 0;
|
||||
pb->photo_block_id = 0;
|
||||
photo_booth_change_state (pb, PB_STATE_NONE);
|
||||
priv->video_block_id = 0;
|
||||
priv->photo_block_id = 0;
|
||||
|
||||
if (mkfifo(MOVIEPIPE, 0666) == -1 && errno != EEXIST)
|
||||
{
|
||||
|
@ -188,9 +199,18 @@ static void photo_booth_init (PhotoBooth *pb)
|
|||
priv->capture_thread = NULL;
|
||||
priv->print_buffer = NULL;
|
||||
priv->printer_settings = NULL;
|
||||
g_mutex_init (&priv->processing_mutex);
|
||||
photo_booth_load_strings();
|
||||
}
|
||||
|
||||
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));
|
||||
priv->state = newstate;
|
||||
}
|
||||
|
||||
static void photo_booth_setup_window (PhotoBooth *pb)
|
||||
{
|
||||
PhotoBoothPrivate *priv;
|
||||
|
@ -240,6 +260,7 @@ static void photo_booth_dispose (GObject *object)
|
|||
g_free (priv->printer_backend);
|
||||
if (priv->printer_settings != NULL)
|
||||
g_object_unref (priv->printer_settings);
|
||||
g_mutex_clear (&priv->processing_mutex);
|
||||
G_OBJECT_CLASS (photo_booth_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -459,7 +480,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
|
|||
if (gpret == -7)
|
||||
{
|
||||
state = CAPTURE_INIT;
|
||||
pb->state = PB_STATE_NONE;
|
||||
photo_booth_change_state (pb, PB_STATE_NONE);
|
||||
photo_booth_cam_close (&pb->cam_info);
|
||||
}
|
||||
continue;
|
||||
|
@ -493,7 +514,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
|
|||
gtk_label_set_text (priv->win->status, _("Taking photo failed!"));
|
||||
GST_ERROR_OBJECT (pb, "Taking photo failed!");
|
||||
photo_booth_cam_close (&pb->cam_info);
|
||||
pb->state = PB_STATE_NONE;
|
||||
photo_booth_change_state (pb, PB_STATE_NONE);
|
||||
state = CAPTURE_INIT;
|
||||
}
|
||||
}
|
||||
|
@ -526,7 +547,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
|
|||
}
|
||||
else if (state == CAPTURE_PAUSED)
|
||||
{
|
||||
GST_DEBUG_OBJECT (pb, "captured thread paused... timeout");
|
||||
GST_DEBUG_OBJECT (pb, "captured thread paused... timeout. %s", photo_booth_state_get_name (priv->state));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,7 +629,7 @@ static GstElement *build_photo_bin (PhotoBooth *pb)
|
|||
photo_scale = gst_element_factory_make ("videoscale", "photo-scale");
|
||||
|
||||
photo_filter = gst_element_factory_make ("capsfilter", "photo-capsfilter");
|
||||
caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, PRINT_WIDTH, "height", G_TYPE_INT, PRINT_HEIGHT, "framerate", GST_TYPE_FRACTION, 1, 5, NULL);
|
||||
caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, PRINT_WIDTH, "height", G_TYPE_INT, PRINT_HEIGHT, "framerate", GST_TYPE_FRACTION, 10, 1, NULL);
|
||||
g_object_set (G_OBJECT (photo_filter), "caps", caps, NULL);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
|
@ -687,11 +708,10 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb)
|
|||
bus = gst_pipeline_get_bus (GST_PIPELINE (pb->pipeline));
|
||||
gst_bus_add_watch (bus, (GstBusFunc) photo_booth_bus_callback, pb);
|
||||
|
||||
GstElement* audio_pipeline;
|
||||
audio_pipeline = gst_pipeline_new ("audio-pipeline");
|
||||
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 (audio_pipeline), priv->audio_playbin);
|
||||
GST_LOG ("added %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT "", priv->audio_playbin, audio_pipeline);
|
||||
gst_bin_add (GST_BIN (priv->audio_pipeline), priv->audio_playbin);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -699,6 +719,7 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb)
|
|||
static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, PhotoBooth *pb)
|
||||
{
|
||||
PhotoBoothPrivate *priv;
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
switch (GST_MESSAGE_TYPE (message))
|
||||
{
|
||||
case GST_MESSAGE_WARNING:
|
||||
|
@ -737,29 +758,22 @@ static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, Phot
|
|||
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_PTR_FORMAT " state transition %s -> %s", src, gst_element_state_get_name(GST_STATE_TRANSITION_CURRENT(transition)), gst_element_state_get_name(GST_STATE_TRANSITION_NEXT(transition)));
|
||||
if (src == pb->video_bin && transition == GST_STATE_CHANGE_PAUSED_TO_PLAYING && pb->state != PB_STATE_WAITING_FOR_ANSWER)
|
||||
{
|
||||
GST_DEBUG ("video_bin GST_STATE_CHANGE_READY_TO_PAUSED -> CAPTURE VIDEO!");
|
||||
SEND_COMMAND (pb, CONTROL_VIDEO);
|
||||
}
|
||||
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)
|
||||
{
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
photo_booth_video_widget_ready (pb);
|
||||
}
|
||||
if (src == pb->output_bin && 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 ("video_bin GST_STATE_CHANGE_PAUSED_TO_PLAYING -> hide spinner!");
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
photo_booth_window_set_spinner (priv->win, FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_MESSAGE_STREAM_START:
|
||||
{
|
||||
GST_DEBUG ("GST_MESSAGE_STREAM_START! state=%i", pb->state);
|
||||
GST_DEBUG ("GST_MESSAGE_STREAM_START! state=%s", photo_booth_state_get_name (priv->state));
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
@ -808,26 +822,26 @@ static gboolean photo_booth_preview (PhotoBooth *pb)
|
|||
{
|
||||
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
|
||||
GstPad *pad;
|
||||
if (pb->video_block_id)
|
||||
if (priv->video_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");
|
||||
pb->photo_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_photo_probecb, pb, NULL);
|
||||
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...");
|
||||
pad = gst_element_get_static_pad (pb->video_bin, "src");
|
||||
gst_pad_remove_probe (pad, pb->video_block_id);
|
||||
gst_pad_remove_probe (pad, priv->video_block_id);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
int ret = gst_element_link (pb->video_bin, pb->output_bin);
|
||||
GST_DEBUG_OBJECT (pb, "linking %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ret=%i", pb->video_bin, pb->output_bin, ret);
|
||||
gst_element_set_state (pb->video_bin, GST_STATE_PLAYING);
|
||||
pb->state = PB_STATE_PREVIEW;
|
||||
photo_booth_change_state (pb, PB_STATE_PREVIEW);
|
||||
GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_preview.dot");
|
||||
gtk_label_set_text (priv->win->status, _("Touch screen to take a photo!"));
|
||||
SEND_COMMAND (pb, CONTROL_VIDEO);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -836,8 +850,8 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P
|
|||
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
||||
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
|
||||
switch (pb->state) {
|
||||
GST_INFO_OBJECT (pb, "background clicked in state %s", photo_booth_state_get_name (priv->state));
|
||||
switch (priv->state) {
|
||||
case PB_STATE_PREVIEW:
|
||||
{
|
||||
photo_booth_snapshot_start (pb);
|
||||
|
@ -847,7 +861,7 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P
|
|||
case PB_STATE_TAKING_PHOTO:
|
||||
case PB_STATE_PROCESS_PHOTO:
|
||||
case PB_STATE_PRINTING:
|
||||
GST_INFO_OBJECT (pb, "BUSY in state %i, ignore event!", pb->state);
|
||||
GST_DEBUG_OBJECT (pb, "BUSY... ignore event!");
|
||||
break;
|
||||
case PB_STATE_WAITING_FOR_ANSWER:
|
||||
{
|
||||
|
@ -862,7 +876,7 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P
|
|||
photo_booth_get_printer_status (pb);
|
||||
}
|
||||
|
||||
static void photo_booth_get_printer_status (PhotoBooth *pb)
|
||||
static gboolean photo_booth_get_printer_status (PhotoBooth *pb)
|
||||
{
|
||||
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
|
||||
gchar *label_string;
|
||||
|
@ -883,7 +897,7 @@ static void photo_booth_get_printer_status (PhotoBooth *pb)
|
|||
regex = g_regex_new ("INFO: Media type\\s.*?: (?<code>\\d+) \\((?<size>.*?)\\)\nINFO: Media remaining\\s.*?: (?<remain>\\d{3})/(?<total>\\d{3})\n", G_REGEX_MULTILINE|G_REGEX_DOTALL, 0, &error);
|
||||
if (error) {
|
||||
g_critical ("%s\n", error->message);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
if (g_regex_match (regex, output, 0, &match_info))
|
||||
{
|
||||
|
@ -925,7 +939,7 @@ static void photo_booth_get_printer_status (PhotoBooth *pb)
|
|||
gtk_label_set_text (priv->win->status_printer, label_string);
|
||||
g_free (label_string);
|
||||
g_free (backend_environment);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void photo_booth_snapshot_start (PhotoBooth *pb)
|
||||
|
@ -935,7 +949,7 @@ static void photo_booth_snapshot_start (PhotoBooth *pb)
|
|||
guint delay = 1;
|
||||
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
pb->state = PB_STATE_COUNTDOWN;
|
||||
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;
|
||||
|
@ -945,7 +959,7 @@ static void photo_booth_snapshot_start (PhotoBooth *pb)
|
|||
GST_DEBUG_OBJECT (pb, "audio uri: %s", uri);
|
||||
g_object_set (priv->audio_playbin, "uri", uri, NULL);
|
||||
g_free (uri);
|
||||
// gst_element_set_state (GST_ELEMENT_PARENT (priv->audio_playbin), GST_STATE_PLAYING); //!!TODO
|
||||
gst_element_set_state (priv->audio_pipeline, GST_STATE_PLAYING);
|
||||
}
|
||||
|
||||
static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
||||
|
@ -959,32 +973,31 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
|||
|
||||
if (!pb->cam_info)
|
||||
return FALSE;
|
||||
pb->state = PB_STATE_TAKING_PHOTO;
|
||||
photo_booth_change_state (pb, PB_STATE_TAKING_PHOTO);
|
||||
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
photo_booth_window_set_spinner (priv->win, TRUE);
|
||||
|
||||
gst_element_set_state (priv->audio_playbin, GST_STATE_READY);
|
||||
gst_element_set_state ((priv->audio_pipeline), GST_STATE_READY);
|
||||
|
||||
SEND_COMMAND (pb, CONTROL_PHOTO);
|
||||
|
||||
gst_element_set_state (pb->video_bin, GST_STATE_READY);
|
||||
GST_DEBUG_OBJECT (pb, "preparing for snapshot! halt video_bin...");
|
||||
pad = gst_element_get_static_pad (pb->video_bin, "src");
|
||||
pb->video_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_video_probecb, pb, NULL);
|
||||
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);
|
||||
|
||||
if (pb->photo_block_id)
|
||||
if (priv->photo_block_id)
|
||||
{
|
||||
GST_DEBUG_OBJECT (pb, "preparing for snapshot! unblock photo_bin...");
|
||||
pad = gst_element_get_static_pad (pb->photo_bin, "src");
|
||||
gst_pad_remove_probe (pad, pb->photo_block_id);
|
||||
gst_pad_remove_probe (pad, priv->photo_block_id);
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
ret = gst_element_link (pb->photo_bin, pb->output_bin);
|
||||
GST_DEBUG_OBJECT (pb, "linking %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ret=%i", pb->photo_bin, pb->output_bin, ret);
|
||||
gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING);
|
||||
|
||||
return FALSE;
|
||||
|
@ -1090,40 +1103,22 @@ static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
|
|||
|
||||
gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING);
|
||||
pad = gst_element_get_static_pad (pb->photo_bin, "src");
|
||||
pb->photo_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, photo_booth_catch_photo_buffer, pb, NULL);
|
||||
GST_DEBUG_OBJECT (pb, "probe id = %lu", pb->photo_block_id);
|
||||
priv->photo_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, photo_booth_catch_photo_buffer, pb, NULL);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||
static gboolean photo_booth_process_photo_plug_elements (PhotoBooth *pb)
|
||||
{
|
||||
PhotoBooth *pb = PHOTO_BOOTH (user_data);
|
||||
PhotoBoothPrivate *priv;
|
||||
GstElement *tee, *encoder, *filesink, *appsink;
|
||||
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
|
||||
if (pb->state == PB_STATE_TAKING_PHOTO)
|
||||
{
|
||||
pb->state = PB_STATE_PROCESS_PHOTO;
|
||||
photo_booth_window_set_spinner (priv->win, FALSE);
|
||||
GST_DEBUG_OBJECT (pb, "PB_STATE_TAKING_PHOTO -> PB_STATE_PROCESS_PHOTO. hide spinner, show button");
|
||||
gtk_widget_show (GTK_WIDGET (priv->win->button_yes));
|
||||
gtk_label_set_text (priv->win->status, _("Print Photo? Touch background to cancel!"));
|
||||
return GST_PAD_PROBE_PASS;
|
||||
}
|
||||
if (pb->state == PB_STATE_PROCESS_PHOTO)
|
||||
{
|
||||
GST_DEBUG_OBJECT (pb, "plugging photo processing elements. locking...");
|
||||
g_mutex_lock (&priv->processing_mutex);
|
||||
encoder = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-encoder");
|
||||
if (GST_IS_ELEMENT (encoder))
|
||||
{
|
||||
pb->state = PB_STATE_WAITING_FOR_ANSWER;
|
||||
return GST_PAD_PROBE_PASS;
|
||||
}
|
||||
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
||||
|
||||
GST_DEBUG_OBJECT (pb, "PB_STATE_PROCESS_PHOTO -> PB_STATE_WAITING_FOR_ANSWER. insert output file encoder and writer elements");
|
||||
encoder = gst_element_factory_make ("jpegenc", "photo-encoder");
|
||||
filesink = gst_element_factory_make ("filesink", "photo-filesink");
|
||||
if (!encoder || !filesink)
|
||||
|
@ -1132,11 +1127,9 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
|||
|
||||
gst_bin_add_many (GST_BIN (pb->photo_bin), encoder, filesink, NULL);
|
||||
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
||||
GST_DEBUG_OBJECT (pb->photo_bin, "linking elements %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT "", tee, encoder, filesink);
|
||||
if (!gst_element_link_many (tee, encoder, filesink, NULL))
|
||||
GST_ERROR_OBJECT (pb->photo_bin, "couldn't link photobin filewrite elements!");
|
||||
|
||||
GST_DEBUG_OBJECT (pb, "PB_STATE_PROCESS_PHOTO -> PB_STATE_WAITING_FOR_ANSWER. insert print surface sink");
|
||||
appsink = gst_element_factory_make ("appsink", "print-appsink");
|
||||
if (!appsink)
|
||||
GST_ERROR_OBJECT (pb->photo_bin, "Failed to make appsink");
|
||||
|
@ -1145,19 +1138,28 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
|||
g_object_set (G_OBJECT (appsink), "emit-signals", TRUE, NULL);
|
||||
g_object_set (G_OBJECT (appsink), "enable-last-sample", FALSE, NULL);
|
||||
g_signal_connect (appsink, "new-sample", G_CALLBACK (photo_booth_catch_print_buffer), pb);
|
||||
GST_DEBUG_OBJECT (pb->photo_bin, "linking elements %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT "", tee, appsink);
|
||||
if (!gst_element_link (tee, appsink))
|
||||
GST_ERROR_OBJECT (pb->photo_bin, "couldn't link appsink!");
|
||||
|
||||
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_video_snapshot_taken.dot");
|
||||
return GST_PAD_PROBE_PASS;
|
||||
GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_process_photo_plug_elements.dot");
|
||||
|
||||
g_mutex_unlock (&priv->processing_mutex);
|
||||
GST_DEBUG_OBJECT (pb, "plugged photo processing elements and unlocked.");
|
||||
return FALSE;
|
||||
}
|
||||
if (pb->state == PB_STATE_WAITING_FOR_ANSWER)
|
||||
|
||||
static gboolean photo_booth_process_photo_remove_elements (PhotoBooth *pb)
|
||||
{
|
||||
GST_DEBUG_OBJECT (pb, "PB_STATE_WAITING_FOR_ANSWER -> PB_STATE_WAITING_FOR_ANSWER. remove output file encoder and writer elements and PAUSE");
|
||||
gst_element_set_state (pb->photo_bin, GST_STATE_PAUSED);
|
||||
PhotoBoothPrivate *priv;
|
||||
GstElement *tee, *encoder, *filesink, *appsink;
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
|
||||
GST_DEBUG_OBJECT (pb, "remove output file encoder and writer elements and pause. locking...");
|
||||
g_mutex_lock (&priv->processing_mutex);
|
||||
|
||||
gst_element_set_state (pb->photo_bin, GST_STATE_READY);
|
||||
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
||||
encoder = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-encoder");
|
||||
filesink = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-filesink");
|
||||
|
@ -1171,9 +1173,52 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
|||
gst_object_unref (tee);
|
||||
gst_object_unref (encoder);
|
||||
gst_object_unref (filesink);
|
||||
pb->photo_block_id = 0;
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
priv->photo_block_id = 0;
|
||||
|
||||
g_mutex_unlock (&priv->processing_mutex);
|
||||
GST_DEBUG_OBJECT (pb, "removed output file encoder and writer elements and paused and unlocked.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||
{
|
||||
PhotoBooth *pb = PHOTO_BOOTH (user_data);
|
||||
PhotoBoothPrivate *priv;
|
||||
GstPadProbeReturn ret = GST_PAD_PROBE_PASS;
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
|
||||
GST_LOG_OBJECT (pb, "probe function in state %s... locking", photo_booth_state_get_name (priv->state));
|
||||
g_mutex_lock (&priv->processing_mutex);
|
||||
switch (priv->state) {
|
||||
case PB_STATE_TAKING_PHOTO:
|
||||
{
|
||||
photo_booth_change_state (pb, PB_STATE_PROCESS_PHOTO);
|
||||
GST_DEBUG_OBJECT (pb, "first buffer caught -> display in sink, invoke processing");
|
||||
gtk_widget_show (GTK_WIDGET (priv->win->button_yes));
|
||||
gtk_label_set_text (priv->win->status, _("Print Photo? Touch background to cancel!"));
|
||||
g_main_context_invoke (NULL, (GSourceFunc) photo_booth_process_photo_plug_elements, pb);
|
||||
break;
|
||||
}
|
||||
case PB_STATE_PROCESS_PHOTO:
|
||||
{
|
||||
photo_booth_change_state (pb, PB_STATE_WAITING_FOR_ANSWER);
|
||||
GST_DEBUG_OBJECT (pb, "second buffer caught -> will be caught for printing. waiting for answer, hide spinner");
|
||||
photo_booth_window_set_spinner (priv->win, FALSE);
|
||||
break;
|
||||
}
|
||||
case PB_STATE_WAITING_FOR_ANSWER:
|
||||
{
|
||||
GST_DEBUG_OBJECT (pb, "third buffer caught -> okay this is enough, remove processing elements and probe");
|
||||
g_main_context_invoke (NULL, (GSourceFunc) photo_booth_process_photo_remove_elements, pb);
|
||||
ret = GST_PAD_PROBE_REMOVE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
g_mutex_unlock (&priv->processing_mutex);
|
||||
GST_LOG_OBJECT (pb, "probe function in state %s... unlocked", photo_booth_state_get_name (priv->state));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpointer user_data)
|
||||
|
@ -1186,6 +1231,7 @@ static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpoin
|
|||
|
||||
pb = PHOTO_BOOTH (user_data);
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
g_mutex_lock (&priv->processing_mutex);
|
||||
sample = gst_app_sink_pull_sample (GST_APP_SINK (appsink));
|
||||
priv->print_buffer = gst_buffer_ref( gst_sample_get_buffer (sample));
|
||||
|
||||
|
@ -1194,7 +1240,7 @@ static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpoin
|
|||
GST_DEBUG_OBJECT (pb, "got photo for printer: %" GST_PTR_FORMAT ". caps = %" GST_PTR_FORMAT "", priv->print_buffer, caps);
|
||||
gst_caps_unref (caps);
|
||||
gst_sample_unref (sample);
|
||||
|
||||
g_mutex_unlock (&priv->processing_mutex);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
|
@ -1214,8 +1260,10 @@ static void photo_booth_free_print_buffer (PhotoBooth *pb)
|
|||
void photo_booth_button_yes_clicked (GtkButton *button, PhotoBoothWindow *win)
|
||||
{
|
||||
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
||||
PhotoBoothPrivate *priv;
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
GST_DEBUG_OBJECT (pb, "on_button_yes_clicked");
|
||||
if (pb->state == PB_STATE_WAITING_FOR_ANSWER)
|
||||
if (priv->state == PB_STATE_WAITING_FOR_ANSWER)
|
||||
{
|
||||
photo_booth_print (pb);
|
||||
}
|
||||
|
@ -1233,30 +1281,40 @@ static void photo_booth_print (PhotoBooth *pb)
|
|||
if (priv->prints_remaining > 1)
|
||||
{
|
||||
gtk_label_set_text (priv->win->status, _("Printing..."));
|
||||
pb->state = PB_STATE_PRINTING;
|
||||
photo_booth_change_state (pb, PB_STATE_PRINTING);
|
||||
PhotoBoothPrivate *priv;
|
||||
GtkPrintOperation *print;
|
||||
GtkPrintOperation *printop;
|
||||
GtkPrintOperationResult res;
|
||||
GtkPageSetup *page_setup;
|
||||
GtkPaperSize *paper_size;
|
||||
GError *print_error;
|
||||
GtkPrintOperationAction action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
|
||||
GtkPrintOperationAction action;
|
||||
|
||||
priv = photo_booth_get_instance_private (pb);
|
||||
print = gtk_print_operation_new ();
|
||||
printop = gtk_print_operation_new ();
|
||||
|
||||
if (priv->printer_settings != NULL)
|
||||
{
|
||||
action = GTK_PRINT_OPERATION_ACTION_PRINT;
|
||||
gtk_print_operation_set_print_settings (print, priv->printer_settings);
|
||||
// action = GTK_PRINT_OPERATION_ACTION_PRINT;
|
||||
gtk_print_operation_set_print_settings (printop, priv->printer_settings);
|
||||
}
|
||||
else
|
||||
action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
|
||||
|
||||
g_signal_connect (print, "begin_print", G_CALLBACK (photo_booth_begin_print), NULL);
|
||||
g_signal_connect (print, "draw_page", G_CALLBACK (photo_booth_draw_page), pb);
|
||||
g_signal_connect (print, "done", G_CALLBACK (photo_booth_print_done), pb);
|
||||
g_signal_connect (printop, "begin_print", G_CALLBACK (photo_booth_begin_print), NULL);
|
||||
g_signal_connect (printop, "draw_page", G_CALLBACK (photo_booth_draw_page), pb);
|
||||
g_signal_connect (printop, "done", G_CALLBACK (photo_booth_print_done), pb);
|
||||
|
||||
gtk_print_operation_set_use_full_page (print, TRUE);
|
||||
gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
|
||||
page_setup = gtk_page_setup_new();
|
||||
paper_size = gtk_paper_size_new_custom("custom", "custom", PT_PER_IN*4.0, PT_PER_IN*6.0, GTK_UNIT_POINTS);
|
||||
gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
|
||||
|
||||
res = gtk_print_operation_run (print, action, GTK_WINDOW (priv->win), &print_error);
|
||||
gtk_page_setup_set_paper_size (page_setup, paper_size);
|
||||
gtk_print_operation_set_default_page_setup (printop, page_setup);
|
||||
gtk_print_operation_set_use_full_page (printop, TRUE);
|
||||
gtk_print_operation_set_unit (printop, GTK_UNIT_POINTS);
|
||||
|
||||
res = gtk_print_operation_run (printop, action, GTK_WINDOW (priv->win), &print_error);
|
||||
if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
|
||||
{
|
||||
photo_booth_printing_error_dialog (priv->win, print_error);
|
||||
|
@ -1271,9 +1329,9 @@ static void photo_booth_print (PhotoBooth *pb)
|
|||
{
|
||||
if (priv->printer_settings != NULL)
|
||||
g_object_unref (priv->printer_settings);
|
||||
priv->printer_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
|
||||
priv->printer_settings = g_object_ref (gtk_print_operation_get_print_settings (printop));
|
||||
}
|
||||
g_object_unref (print);
|
||||
g_object_unref (printop);
|
||||
}
|
||||
else if (priv->prints_remaining == -1) {
|
||||
gtk_label_set_text (priv->win->status, _("Can't print, no printer connected!"));
|
||||
|
@ -1315,7 +1373,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, -16.0, -16.0); // FIXME offsets?
|
||||
cairo_set_source_surface(cr, cairosurface, -0.0, -0.0); // FIXME offsets?
|
||||
cairo_paint(cr);
|
||||
cairo_set_matrix(cr, &m);
|
||||
|
||||
|
@ -1351,10 +1409,26 @@ static void photo_booth_print_done (GtkPrintOperation *operation, GtkPrintOperat
|
|||
photo_booth_printing_error_dialog (priv->win, print_error);
|
||||
g_error_free (print_error);
|
||||
}
|
||||
g_timeout_add_seconds (15, (GSourceFunc) photo_booth_get_printer_status, pb);
|
||||
photo_booth_preview (pb);
|
||||
return;
|
||||
}
|
||||
|
||||
const gchar* photo_booth_state_get_name (PhotoboothState state)
|
||||
{
|
||||
switch (state) {
|
||||
case PB_STATE_NONE: return "PB_STATE_NONE";break;
|
||||
case PB_STATE_PREVIEW: return "PB_STATE_PREVIEW";break;
|
||||
case PB_STATE_COUNTDOWN: return "PB_STATE_COUNTDOWN";break;
|
||||
case PB_STATE_TAKING_PHOTO: return "PB_STATE_TAKING_PHOTO";break;
|
||||
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;
|
||||
default: return "STATE UNKOWN!";break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
PhotoBooth *photo_booth_new (void)
|
||||
{
|
||||
return g_object_new (PHOTO_BOOTH_TYPE,
|
||||
|
|
|
@ -111,11 +111,7 @@ struct _PhotoBooth
|
|||
gint timeout_id;
|
||||
CameraInfo *cam_info;
|
||||
|
||||
gulong video_block_id;
|
||||
gulong photo_block_id;
|
||||
|
||||
int control_sock[2];
|
||||
PhotoboothState state;
|
||||
};
|
||||
|
||||
struct _PhotoBoothClass
|
||||
|
|
Loading…
Add table
Reference in a new issue