implement printing (orientation to be fixed)
This commit is contained in:
parent
f215cab262
commit
12a27949ce
3 changed files with 241 additions and 32 deletions
4
Makefile
4
Makefile
|
@ -1,7 +1,7 @@
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
PKGCONFIG = $(shell which pkg-config)
|
PKGCONFIG = $(shell which pkg-config)
|
||||||
CFLAGS = $(shell $(PKGCONFIG) --cflags gtk+-3.0 gstreamer-1.0 gstreamer-video-1.0 libgphoto2) -Wl,--export-dynamic -rdynamic -g
|
CFLAGS = $(shell $(PKGCONFIG) --cflags gtk+-3.0 gstreamer-1.0 gstreamer-video-1.0 gstreamer-app-1.0 libgphoto2) -Wl,--export-dynamic -rdynamic -g
|
||||||
LIBS = $(shell $(PKGCONFIG) --libs gtk+-3.0 gstreamer-1.0 gstreamer-video-1.0 libgphoto2 gmodule-export-2.0)
|
LIBS = $(shell $(PKGCONFIG) --libs gtk+-3.0 gstreamer-1.0 gstreamer-video-1.0 gstreamer-app-1.0 libgphoto2 gmodule-export-2.0)
|
||||||
GLIB_COMPILE_RESOURCES = $(shell $(PKGCONFIG) --variable=glib_compile_resources gio-2.0)
|
GLIB_COMPILE_RESOURCES = $(shell $(PKGCONFIG) --variable=glib_compile_resources gio-2.0)
|
||||||
GLIB_COMPILE_SCHEMAS = $(shell $(PKGCONFIG) --variable=glib_compile_schemas gio-2.0)
|
GLIB_COMPILE_SCHEMAS = $(shell $(PKGCONFIG) --variable=glib_compile_schemas gio-2.0)
|
||||||
|
|
||||||
|
|
267
photobooth.c
267
photobooth.c
|
@ -25,6 +25,7 @@
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <gst/video/videooverlay.h>
|
#include <gst/video/videooverlay.h>
|
||||||
#include <gst/video/gstvideosink.h>
|
#include <gst/video/gstvideosink.h>
|
||||||
|
#include <gst/app/app.h>
|
||||||
#include "photobooth.h"
|
#include "photobooth.h"
|
||||||
#include "photoboothwin.h"
|
#include "photoboothwin.h"
|
||||||
|
|
||||||
|
@ -41,11 +42,14 @@ struct _PhotoBoothPrivate
|
||||||
GstElement *audio_playbin;
|
GstElement *audio_playbin;
|
||||||
GstVideoRectangle video_size;
|
GstVideoRectangle video_size;
|
||||||
GThread *capture_thread;
|
GThread *capture_thread;
|
||||||
|
GstBuffer *print_buffer;
|
||||||
|
GtkPrintSettings *printer_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_AUDIOFILE_COUNTDOWN "/net/home/fraxinas/microcontroller/photobooth/beep.m4a"
|
#define DEFAULT_AUDIOFILE_COUNTDOWN "/net/home/fraxinas/microcontroller/photobooth/beep.m4a"
|
||||||
#define DEFAULT_COUNTDOWN 5
|
#define DEFAULT_COUNTDOWN 5
|
||||||
#define DEFAULT_PRINTER_BACKEND "mitsu9550"
|
#define DEFAULT_PRINTER_BACKEND "mitsu9550"
|
||||||
|
#define PRINT_DPI 346
|
||||||
#define PRINT_WIDTH 2076
|
#define PRINT_WIDTH 2076
|
||||||
#define PRINT_HEIGHT 1384
|
#define PRINT_HEIGHT 1384
|
||||||
#define PREVIEW_WIDTH 640
|
#define PREVIEW_WIDTH 640
|
||||||
|
@ -86,8 +90,6 @@ 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_taken (PhotoBooth *pb);
|
static gboolean photo_booth_snapshot_taken (PhotoBooth *pb);
|
||||||
static void photo_booth_get_printer_status (PhotoBooth *pb);
|
|
||||||
static void photo_booth_print (PhotoBooth *pb);
|
|
||||||
|
|
||||||
/* libgphoto2 */
|
/* libgphoto2 */
|
||||||
static gboolean photo_booth_cam_init (CameraInfo **cam_info);
|
static gboolean photo_booth_cam_init (CameraInfo **cam_info);
|
||||||
|
@ -103,6 +105,17 @@ static GstElement *build_photo_bin (PhotoBooth *pb);
|
||||||
static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb);
|
static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb);
|
||||||
static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, PhotoBooth *pb);
|
static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, PhotoBooth *pb);
|
||||||
static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer user_data);
|
static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadProbeInfo * info, gpointer user_data);
|
||||||
|
static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpointer user_data);
|
||||||
|
static void photo_booth_free_print_buffer (PhotoBooth *pb);
|
||||||
|
|
||||||
|
/* printing functions */
|
||||||
|
static void 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);
|
||||||
|
static void photo_booth_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, int page_nr, gpointer user_data);
|
||||||
|
static void photo_booth_print_done (GtkPrintOperation *operation, GtkPrintOperationResult result, gpointer user_data);
|
||||||
|
static void photo_booth_printing_error_dialog (PhotoBoothWindow *window, GError *print_error);
|
||||||
|
|
||||||
static void photo_booth_class_init (PhotoBoothClass *klass)
|
static void photo_booth_class_init (PhotoBoothClass *klass)
|
||||||
{
|
{
|
||||||
|
@ -173,6 +186,8 @@ static void photo_booth_init (PhotoBooth *pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->capture_thread = NULL;
|
priv->capture_thread = NULL;
|
||||||
|
priv->print_buffer = NULL;
|
||||||
|
priv->printer_settings = NULL;
|
||||||
photo_booth_load_strings();
|
photo_booth_load_strings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +238,7 @@ static void photo_booth_dispose (GObject *object)
|
||||||
PhotoBoothPrivate *priv;
|
PhotoBoothPrivate *priv;
|
||||||
priv = photo_booth_get_instance_private (PHOTO_BOOTH (object));
|
priv = photo_booth_get_instance_private (PHOTO_BOOTH (object));
|
||||||
g_free (priv->printer_backend);
|
g_free (priv->printer_backend);
|
||||||
|
g_object_unref (priv->printer_settings);
|
||||||
G_OBJECT_CLASS (photo_booth_parent_class)->dispose (object);
|
G_OBJECT_CLASS (photo_booth_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,8 +485,11 @@ 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);
|
||||||
else {
|
else {
|
||||||
GST_ERROR_OBJECT (pb, "taking photo failed!");
|
gtk_label_set_text (priv->win->status, _("Taking photo failed!"));
|
||||||
|
GST_ERROR_OBJECT (pb, "Taking photo failed!");
|
||||||
|
pb->state = PB_STATE_NONE;
|
||||||
state = CAPTURE_INIT;
|
state = CAPTURE_INIT;
|
||||||
|
photo_booth_cam_close (&pb->cam_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,7 +789,7 @@ static void photo_booth_video_widget_ready (PhotoBooth *pb)
|
||||||
s2.h = size2.height;
|
s2.h = size2.height;
|
||||||
gst_video_sink_center_rect (s1, s2, &rect, TRUE);
|
gst_video_sink_center_rect (s1, s2, &rect, TRUE);
|
||||||
|
|
||||||
GST_INFO_OBJECT (pb, "gtksink widget is ready. preferred dimensions: %dx%d allocated %dx%d", size.width, size.height, size2.width, size2.height);
|
GST_DEBUG_OBJECT (pb, "gtksink widget is ready. preferred dimensions: %dx%d allocated %dx%d", size.width, size.height, size2.width, size2.height);
|
||||||
|
|
||||||
element = gst_bin_get_by_name (GST_BIN (pb->video_bin), "video-capsfilter");
|
element = gst_bin_get_by_name (GST_BIN (pb->video_bin), "video-capsfilter");
|
||||||
caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, rect.w, "height", G_TYPE_INT, rect.h, NULL);
|
caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, rect.w, "height", G_TYPE_INT, rect.h, NULL);
|
||||||
|
@ -783,7 +802,7 @@ static void photo_booth_video_widget_ready (PhotoBooth *pb)
|
||||||
g_object_set (element, "overlay-height", rect.h, NULL);
|
g_object_set (element, "overlay-height", rect.h, NULL);
|
||||||
gst_object_unref (element);
|
gst_object_unref (element);
|
||||||
|
|
||||||
GST_INFO_OBJECT (pb, "gtksink widget is ready. output dimensions: %dx%d", rect.w, rect.h);
|
GST_DEBUG_OBJECT (pb, "gtksink widget is ready. output dimensions: %dx%d", rect.w, rect.h);
|
||||||
priv->video_size = rect;
|
priv->video_size = rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,8 +827,8 @@ static gboolean photo_booth_preview (PhotoBooth *pb)
|
||||||
int ret = gst_element_link (pb->video_bin, pb->output_bin);
|
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_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);
|
gst_element_set_state (pb->video_bin, GST_STATE_PLAYING);
|
||||||
GST_DEBUG_OBJECT (pb, "photo_booth_preview done");
|
|
||||||
pb->state = PB_STATE_PREVIEW;
|
pb->state = 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!"));
|
gtk_label_set_text (priv->win->status, _("Touch screen to take a photo!"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -818,14 +837,19 @@ void photo_booth_background_clicked (GtkWidget *widget, GdkEventButton *event, P
|
||||||
{
|
{
|
||||||
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
||||||
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
|
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
|
||||||
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
|
||||||
switch (pb->state) {
|
switch (pb->state) {
|
||||||
case PB_STATE_PREVIEW:
|
case PB_STATE_PREVIEW:
|
||||||
{
|
{
|
||||||
photo_booth_snapshot_start (pb);
|
photo_booth_snapshot_start (pb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PB_STATE_COUNTDOWN:
|
||||||
case PB_STATE_TAKING_PHOTO:
|
case PB_STATE_TAKING_PHOTO:
|
||||||
GST_WARNING_OBJECT (pb, "BUSY TAKING A PHOTO, IGNORE CLICK");
|
case PB_STATE_PROCESS_PHOTO:
|
||||||
|
case PB_STATE_PRINTING:
|
||||||
|
GST_INFO_OBJECT (pb, "BUSY in state %i, ignore event!", pb->state);
|
||||||
break;
|
break;
|
||||||
case PB_STATE_WAITING_FOR_ANSWER:
|
case PB_STATE_WAITING_FOR_ANSWER:
|
||||||
{
|
{
|
||||||
|
@ -913,16 +937,17 @@ static void photo_booth_snapshot_start (PhotoBooth *pb)
|
||||||
guint delay = 1;
|
guint delay = 1;
|
||||||
|
|
||||||
priv = photo_booth_get_instance_private (pb);
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
pb->state = 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;
|
delay = (priv->countdown*1000)-100;
|
||||||
GST_INFO_OBJECT (pb, "started countdown of %d seconds, start taking photo in %d ms", priv->countdown, delay);
|
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);
|
g_timeout_add (delay, (GSourceFunc) photo_booth_snapshot_prepare, pb);
|
||||||
uri = g_filename_to_uri (DEFAULT_AUDIOFILE_COUNTDOWN, NULL, NULL);
|
uri = g_filename_to_uri (DEFAULT_AUDIOFILE_COUNTDOWN, NULL, NULL);
|
||||||
GST_INFO_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);
|
||||||
g_free (uri);
|
g_free (uri);
|
||||||
gst_element_set_state (GST_ELEMENT_PARENT (priv->audio_playbin), GST_STATE_PLAYING);
|
// gst_element_set_state (GST_ELEMENT_PARENT (priv->audio_playbin), GST_STATE_PLAYING); //!!TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
||||||
|
@ -931,7 +956,7 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
GST_INFO_OBJECT (pb, "SNAPSHOT!");
|
GST_DEBUG_OBJECT (pb, "SNAPSHOT!");
|
||||||
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)
|
if (!pb->cam_info)
|
||||||
|
@ -946,7 +971,7 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
||||||
SEND_COMMAND (pb, CONTROL_PHOTO);
|
SEND_COMMAND (pb, CONTROL_PHOTO);
|
||||||
|
|
||||||
gst_element_set_state (pb->video_bin, GST_STATE_READY);
|
gst_element_set_state (pb->video_bin, GST_STATE_READY);
|
||||||
GST_DEBUG_OBJECT (pb, "photo_booth_preview! halt video_bin...");
|
GST_DEBUG_OBJECT (pb, "preparing for snapshot! halt video_bin...");
|
||||||
pad = gst_element_get_static_pad (pb->video_bin, "src");
|
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);
|
pb->video_block_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, _gst_video_probecb, pb, NULL);
|
||||||
gst_object_unref (pad);
|
gst_object_unref (pad);
|
||||||
|
@ -954,7 +979,7 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
|
||||||
|
|
||||||
if (pb->photo_block_id)
|
if (pb->photo_block_id)
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (pb, "photo_booth_preview! unblock photo_bin...");
|
GST_DEBUG_OBJECT (pb, "preparing for snapshot! unblock photo_bin...");
|
||||||
pad = gst_element_get_static_pad (pb->photo_bin, "src");
|
pad = gst_element_get_static_pad (pb->photo_bin, "src");
|
||||||
gst_pad_remove_probe (pad, pb->photo_block_id);
|
gst_pad_remove_probe (pad, pb->photo_block_id);
|
||||||
gst_object_unref (pad);
|
gst_object_unref (pad);
|
||||||
|
@ -1020,7 +1045,7 @@ static gboolean photo_booth_take_photo (CameraInfo *cam_info)
|
||||||
gpret = gp_camera_capture (cam_info->camera, GP_CAPTURE_IMAGE, &camera_file_path, cam_info->context);
|
gpret = gp_camera_capture (cam_info->camera, GP_CAPTURE_IMAGE, &camera_file_path, cam_info->context);
|
||||||
GST_DEBUG ("gp_camera_capture gpret=%i Pathname on the camera: %s/%s", gpret, camera_file_path.folder, camera_file_path.name);
|
GST_DEBUG ("gp_camera_capture gpret=%i Pathname on the camera: %s/%s", gpret, camera_file_path.folder, camera_file_path.name);
|
||||||
if (gpret < 0)
|
if (gpret < 0)
|
||||||
return FALSE;
|
goto fail;
|
||||||
|
|
||||||
gpret = gp_file_new (&file);
|
gpret = gp_file_new (&file);
|
||||||
GST_DEBUG ("gp_file_new gpret=%i", gpret);
|
GST_DEBUG ("gp_file_new gpret=%i", gpret);
|
||||||
|
@ -1028,17 +1053,20 @@ static gboolean photo_booth_take_photo (CameraInfo *cam_info)
|
||||||
gpret = gp_camera_file_get (cam_info->camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, cam_info->context);
|
gpret = gp_camera_file_get (cam_info->camera, camera_file_path.folder, camera_file_path.name, GP_FILE_TYPE_NORMAL, file, cam_info->context);
|
||||||
GST_DEBUG ("gp_camera_file_get gpret=%i", gpret);
|
GST_DEBUG ("gp_camera_file_get gpret=%i", gpret);
|
||||||
if (gpret < 0)
|
if (gpret < 0)
|
||||||
return FALSE;
|
goto fail;
|
||||||
gp_file_get_data_and_size (file, (const char**)&(cam_info->data), &(cam_info->size));
|
gp_file_get_data_and_size (file, (const char**)&(cam_info->data), &(cam_info->size));
|
||||||
if (gpret < 0)
|
if (gpret < 0)
|
||||||
return FALSE;
|
goto fail;
|
||||||
|
|
||||||
gpret = gp_camera_file_delete (cam_info->camera, camera_file_path.folder, camera_file_path.name, cam_info->context);
|
gpret = gp_camera_file_delete (cam_info->camera, camera_file_path.folder, camera_file_path.name, cam_info->context);
|
||||||
GST_DEBUG ("gp_camera_file_delete gpret=%i", gpret);
|
GST_DEBUG ("gp_camera_file_delete gpret=%i", gpret);
|
||||||
// gp_file_free(file);
|
// gp_file_free(file);
|
||||||
g_mutex_unlock (&cam_info->mutex);
|
g_mutex_unlock (&cam_info->mutex);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
g_mutex_unlock (&cam_info->mutex);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
|
static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
|
||||||
|
@ -1049,7 +1077,7 @@ static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
|
||||||
GstFlowReturn flowret;
|
GstFlowReturn flowret;
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
|
|
||||||
GST_INFO_OBJECT (pb, "photo_booth_snapshot_taken size=%lu", pb->cam_info->size);
|
GST_DEBUG_OBJECT (pb, "photo_booth_snapshot_taken size=%lu", pb->cam_info->size);
|
||||||
gtk_label_set_text (priv->win->status, _("Processing photo..."));
|
gtk_label_set_text (priv->win->status, _("Processing photo..."));
|
||||||
|
|
||||||
appsrc = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-appsrc");
|
appsrc = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-appsrc");
|
||||||
|
@ -1074,14 +1102,16 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
||||||
{
|
{
|
||||||
PhotoBooth *pb = PHOTO_BOOTH (user_data);
|
PhotoBooth *pb = PHOTO_BOOTH (user_data);
|
||||||
PhotoBoothPrivate *priv;
|
PhotoBoothPrivate *priv;
|
||||||
GstElement *tee, *encoder, *filesink;
|
GstElement *tee, *encoder, *filesink, *convert, *filter, *appsink;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
priv = photo_booth_get_instance_private (pb);
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
|
||||||
if (pb->state == PB_STATE_TAKING_PHOTO)
|
if (pb->state == PB_STATE_TAKING_PHOTO)
|
||||||
{
|
{
|
||||||
pb->state = PB_STATE_PROCESS_PHOTO;
|
pb->state = PB_STATE_PROCESS_PHOTO;
|
||||||
photo_booth_window_set_spinner (priv->win, FALSE);
|
photo_booth_window_set_spinner (priv->win, FALSE);
|
||||||
GST_INFO_OBJECT (priv->win->button_yes, "PB_STATE_TAKING_PHOTO -> PB_STATE_PROCESS_PHOTO. hide spinner, show button");
|
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_widget_show (GTK_WIDGET (priv->win->button_yes));
|
||||||
gtk_label_set_text (priv->win->status, _("Print Photo? Touch background to cancel!"));
|
gtk_label_set_text (priv->win->status, _("Print Photo? Touch background to cancel!"));
|
||||||
return GST_PAD_PROBE_PASS;
|
return GST_PAD_PROBE_PASS;
|
||||||
|
@ -1095,17 +1125,38 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
||||||
return GST_PAD_PROBE_PASS;
|
return GST_PAD_PROBE_PASS;
|
||||||
}
|
}
|
||||||
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
||||||
GST_INFO_OBJECT (priv->win->button_yes, "PB_STATE_PROCESS_PHOTO -> PB_STATE_WAITING_FOR_ANSWER. insert output file encoder and writer elements");
|
|
||||||
|
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");
|
encoder = gst_element_factory_make ("jpegenc", "photo-encoder");
|
||||||
filesink = gst_element_factory_make ("filesink", "photo-filesink");
|
filesink = gst_element_factory_make ("filesink", "photo-filesink");
|
||||||
if (!encoder || !filesink)
|
if (!encoder || !filesink)
|
||||||
GST_ERROR_OBJECT (pb->photo_bin, "Failed to make photo encoder");
|
GST_ERROR_OBJECT (pb->photo_bin, "Failed to make photo encoder");
|
||||||
g_object_set (filesink, "location", "PHOTOBOOTH-PRINT.JPG", NULL);
|
g_object_set (filesink, "location", "PHOTOBOOTH-PRINT.JPG", NULL);
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pb->photo_bin), encoder, filesink, NULL);
|
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");
|
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
||||||
GST_INFO_OBJECT (pb->photo_bin, "linking elements %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT "", tee, encoder, filesink);
|
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))
|
if (!gst_element_link_many (tee, encoder, filesink, NULL))
|
||||||
GST_ERROR_OBJECT (pb->photo_bin, "couldn't link photobin filewrite elements!");
|
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 converter elements");
|
||||||
|
convert = gst_element_factory_make ("videoconvert", "print-videoconvert");
|
||||||
|
filter = gst_element_factory_make ("capsfilter", "print-capsfilter");
|
||||||
|
appsink = gst_element_factory_make ("appsink", "print-appsink");
|
||||||
|
if (!convert || !filter || !appsink)
|
||||||
|
GST_ERROR_OBJECT (pb->photo_bin, "Failed to make print converters");
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (pb->photo_bin), convert, filter, appsink, NULL);
|
||||||
|
caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "BGRx", NULL);
|
||||||
|
g_object_set (G_OBJECT (filter), "caps", caps, NULL);
|
||||||
|
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 " ! %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT "", tee, convert, filter, appsink);
|
||||||
|
if (!gst_element_link_many (tee, convert, filter, appsink, NULL))
|
||||||
|
GST_ERROR_OBJECT (pb->photo_bin, "couldn't link print converter elements!");
|
||||||
|
|
||||||
|
gst_caps_unref (caps);
|
||||||
gst_object_unref (tee);
|
gst_object_unref (tee);
|
||||||
gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING);
|
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");
|
GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_video_snapshot_taken.dot");
|
||||||
|
@ -1113,24 +1164,67 @@ static GstPadProbeReturn photo_booth_catch_photo_buffer (GstPad * pad, GstPadPro
|
||||||
}
|
}
|
||||||
if (pb->state == PB_STATE_WAITING_FOR_ANSWER)
|
if (pb->state == PB_STATE_WAITING_FOR_ANSWER)
|
||||||
{
|
{
|
||||||
GST_INFO_OBJECT (pb, "PB_STATE_WAITING_FOR_ANSWER -> PB_STATE_WAITING_FOR_ANSWER. remove output file encoder and writer elements and PAUSE");
|
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);
|
gst_element_set_state (pb->photo_bin, GST_STATE_PAUSED);
|
||||||
tee = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-tee");
|
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");
|
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");
|
filesink = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "photo-filesink");
|
||||||
|
convert = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "print-videoconvert");
|
||||||
|
filter = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "print-capsfilter");
|
||||||
|
appsink = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "print-appsink");
|
||||||
gst_element_unlink_many (tee, encoder, filesink, NULL);
|
gst_element_unlink_many (tee, encoder, filesink, NULL);
|
||||||
gst_bin_remove_many (GST_BIN (pb->photo_bin), encoder, filesink, NULL);
|
gst_element_unlink_many (tee, convert, filter, appsink, NULL);
|
||||||
|
gst_bin_remove_many (GST_BIN (pb->photo_bin), encoder, filesink, convert, filter, appsink, NULL);
|
||||||
gst_element_set_state (filesink, GST_STATE_NULL);
|
gst_element_set_state (filesink, GST_STATE_NULL);
|
||||||
gst_element_set_state (encoder, GST_STATE_NULL);
|
gst_element_set_state (encoder, GST_STATE_NULL);
|
||||||
|
gst_element_set_state (convert, GST_STATE_NULL);
|
||||||
|
gst_element_set_state (filter, GST_STATE_NULL);
|
||||||
|
gst_element_set_state (appsink, GST_STATE_NULL);
|
||||||
gst_object_unref (tee);
|
gst_object_unref (tee);
|
||||||
gst_object_unref (filesink);
|
|
||||||
gst_object_unref (encoder);
|
gst_object_unref (encoder);
|
||||||
GST_INFO_OBJECT (pb, "PB_STATE_WAITING_FOR_ANSWER -> unreffed encoder and file writer.");
|
gst_object_unref (filesink);
|
||||||
|
gst_object_unref (convert);
|
||||||
|
gst_object_unref (filter);
|
||||||
pb->photo_block_id = 0;
|
pb->photo_block_id = 0;
|
||||||
return GST_PAD_PROBE_REMOVE;
|
return GST_PAD_PROBE_REMOVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn photo_booth_catch_print_buffer (GstElement * appsink, gpointer user_data)
|
||||||
|
{
|
||||||
|
PhotoBooth *pb;
|
||||||
|
PhotoBoothPrivate *priv;
|
||||||
|
GstSample *sample;
|
||||||
|
GstMapInfo map;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
pb = PHOTO_BOOTH (user_data);
|
||||||
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
sample = gst_app_sink_pull_sample (GST_APP_SINK (appsink));
|
||||||
|
priv->print_buffer = gst_buffer_ref( gst_sample_get_buffer (sample));
|
||||||
|
|
||||||
|
pad = gst_element_get_static_pad (appsink, "sink");
|
||||||
|
GstCaps *caps = gst_pad_get_current_caps (pad);
|
||||||
|
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);
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void photo_booth_free_print_buffer (PhotoBooth *pb)
|
||||||
|
{
|
||||||
|
PhotoBoothPrivate *priv;
|
||||||
|
GstElement *appsink;
|
||||||
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
GST_DEBUG_OBJECT (pb, "freeing buffer");
|
||||||
|
if (GST_IS_BUFFER (priv->print_buffer))
|
||||||
|
gst_buffer_unref (priv->print_buffer);
|
||||||
|
appsink = gst_bin_get_by_name (GST_BIN (pb->photo_bin), "print-appsink");
|
||||||
|
if (GST_IS_ELEMENT (appsink))
|
||||||
|
gst_object_unref (appsink);
|
||||||
|
}
|
||||||
|
|
||||||
void photo_booth_button_yes_clicked (GtkButton *button, PhotoBoothWindow *win)
|
void photo_booth_button_yes_clicked (GtkButton *button, PhotoBoothWindow *win)
|
||||||
{
|
{
|
||||||
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
PhotoBooth *pb = PHOTO_BOOTH_FROM_WINDOW (win);
|
||||||
|
@ -1147,13 +1241,53 @@ static void photo_booth_print (PhotoBooth *pb)
|
||||||
priv = photo_booth_get_instance_private (pb);
|
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 (GST_BIN (pb->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "photo_booth_photo_print.dot");
|
||||||
photo_booth_get_printer_status (pb);
|
photo_booth_get_printer_status (pb);
|
||||||
GST_DEBUG_OBJECT (pb, "!!!PRINT!!! prints_remaining=%i", priv->prints_remaining);
|
GST_INFO_OBJECT (pb, "PRINT! prints_remaining=%i", priv->prints_remaining);
|
||||||
|
gtk_widget_hide (GTK_WIDGET (priv->win->button_yes));
|
||||||
|
|
||||||
if (priv->prints_remaining > 1)
|
if (priv->prints_remaining > 1)
|
||||||
{
|
{
|
||||||
|
gtk_label_set_text (priv->win->status, _("Printing..."));
|
||||||
|
pb->state = PB_STATE_PRINTING;
|
||||||
|
PhotoBoothPrivate *priv;
|
||||||
|
GtkPrintOperation *print;
|
||||||
|
GtkPrintOperationResult res;
|
||||||
|
GError *print_error;
|
||||||
|
GtkPrintOperationAction action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
|
||||||
|
|
||||||
priv = photo_booth_get_instance_private (pb);
|
priv = photo_booth_get_instance_private (pb);
|
||||||
gtk_widget_hide (GTK_WIDGET (priv->win->button_yes));
|
print = gtk_print_operation_new ();
|
||||||
gtk_label_set_text (priv->win->status, "PRINTING................");
|
|
||||||
|
if (priv->printer_settings != NULL)
|
||||||
|
{
|
||||||
|
action = GTK_PRINT_OPERATION_ACTION_PRINT;
|
||||||
|
gtk_print_operation_set_print_settings (print, priv->printer_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
gtk_print_operation_set_use_full_page (print, TRUE);
|
||||||
|
gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
|
||||||
|
|
||||||
|
res = gtk_print_operation_run (print, action, GTK_WINDOW (priv->win), &print_error);
|
||||||
|
if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
|
||||||
|
{
|
||||||
|
photo_booth_printing_error_dialog (priv->win, print_error);
|
||||||
|
g_error_free (print_error);
|
||||||
|
}
|
||||||
|
else if (res == GTK_PRINT_OPERATION_RESULT_CANCEL)
|
||||||
|
{
|
||||||
|
gtk_label_set_text (priv->win->status, _("Printing cancelled"));
|
||||||
|
GST_INFO_OBJECT (pb, "print cancelled");
|
||||||
|
}
|
||||||
|
else if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
|
||||||
|
{
|
||||||
|
if (priv->printer_settings != NULL)
|
||||||
|
g_object_unref (priv->printer_settings);
|
||||||
|
priv->printer_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
|
||||||
|
}
|
||||||
|
g_object_unref (print);
|
||||||
}
|
}
|
||||||
else if (priv->prints_remaining == -1) {
|
else if (priv->prints_remaining == -1) {
|
||||||
gtk_label_set_text (priv->win->status, _("Can't print, no printer connected!"));
|
gtk_label_set_text (priv->win->status, _("Can't print, no printer connected!"));
|
||||||
|
@ -1162,6 +1296,79 @@ static void photo_booth_print (PhotoBooth *pb)
|
||||||
gtk_label_set_text (priv->win->status, _("Can't print, out of paper!"));
|
gtk_label_set_text (priv->win->status, _("Can't print, out of paper!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void photo_booth_begin_print (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
|
||||||
|
{
|
||||||
|
gtk_print_operation_set_n_pages (operation, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void photo_booth_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, int page_nr, gpointer user_data)
|
||||||
|
{
|
||||||
|
PhotoBooth *pb;
|
||||||
|
PhotoBoothPrivate *priv;
|
||||||
|
GstMapInfo map;
|
||||||
|
|
||||||
|
pb = PHOTO_BOOTH (user_data);
|
||||||
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
|
||||||
|
if (!GST_IS_BUFFER (priv->print_buffer))
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (context, "can't draw because we have no photo buffer!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GST_DEBUG_OBJECT (context, "draw_page no. %i . %" GST_PTR_FORMAT "", page_nr, priv->print_buffer);
|
||||||
|
|
||||||
|
gst_buffer_map(priv->print_buffer, &map, GST_MAP_READ);
|
||||||
|
guint8 *h = map.data;
|
||||||
|
guint l = map.size;
|
||||||
|
|
||||||
|
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, PRINT_WIDTH);
|
||||||
|
cairo_surface_t *cairosurface = cairo_image_surface_create_for_data (map.data, CAIRO_FORMAT_RGB24, PRINT_WIDTH, PRINT_HEIGHT, stride);
|
||||||
|
cairo_t *cr = gtk_print_context_get_cairo_context (context);
|
||||||
|
cairo_matrix_t m;
|
||||||
|
cairo_get_matrix(cr, &m);
|
||||||
|
|
||||||
|
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_paint(cr);
|
||||||
|
cairo_set_matrix(cr, &m);
|
||||||
|
|
||||||
|
gst_buffer_unmap (priv->print_buffer, &map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void photo_booth_printing_error_dialog (PhotoBoothWindow *window, GError *print_error)
|
||||||
|
{
|
||||||
|
GtkWidget *error_dialog;
|
||||||
|
gchar *error_string;
|
||||||
|
error_string = g_strdup_printf(_("Failed to print! Error message: %s"), print_error->message);
|
||||||
|
GST_ERROR_OBJECT (window, error_string);
|
||||||
|
error_dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error_string);
|
||||||
|
g_signal_connect (error_dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);
|
||||||
|
gtk_widget_show (error_dialog);
|
||||||
|
g_free (error_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void photo_booth_print_done (GtkPrintOperation *operation, GtkPrintOperationResult result, gpointer user_data)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (user_data, "print_done!");
|
||||||
|
PhotoBooth *pb;
|
||||||
|
PhotoBoothPrivate *priv;
|
||||||
|
GstMapInfo map;
|
||||||
|
|
||||||
|
pb = PHOTO_BOOTH (user_data);
|
||||||
|
priv = photo_booth_get_instance_private (pb);
|
||||||
|
|
||||||
|
GError *print_error;
|
||||||
|
if (result == GTK_PRINT_OPERATION_RESULT_ERROR)
|
||||||
|
{
|
||||||
|
gtk_print_operation_get_error (operation, &print_error);
|
||||||
|
photo_booth_printing_error_dialog (priv->win, print_error);
|
||||||
|
g_error_free (print_error);
|
||||||
|
}
|
||||||
|
photo_booth_preview (pb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PhotoBooth *photo_booth_new (void)
|
PhotoBooth *photo_booth_new (void)
|
||||||
{
|
{
|
||||||
return g_object_new (PHOTO_BOOTH_TYPE,
|
return g_object_new (PHOTO_BOOTH_TYPE,
|
||||||
|
@ -1181,7 +1388,7 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
g_unix_signal_add (SIGINT, (GSourceFunc) photo_booth_quit_signal, pb);
|
g_unix_signal_add (SIGINT, (GSourceFunc) photo_booth_quit_signal, pb);
|
||||||
ret = g_application_run (G_APPLICATION (pb), argc, argv);
|
ret = g_application_run (G_APPLICATION (pb), argc, argv);
|
||||||
GST_INFO_OBJECT (pb, "g_application_run returned %i", ret);
|
|
||||||
g_object_unref (pb);
|
g_object_unref (pb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ G_STMT_START { \
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define PREVIEW_FPS 24
|
#define PREVIEW_FPS 24
|
||||||
|
#define PT_PER_IN 72
|
||||||
|
|
||||||
struct _CameraInfo {
|
struct _CameraInfo {
|
||||||
Camera *camera;
|
Camera *camera;
|
||||||
|
@ -74,6 +75,7 @@ typedef enum
|
||||||
{
|
{
|
||||||
PB_STATE_NONE = 0,
|
PB_STATE_NONE = 0,
|
||||||
PB_STATE_PREVIEW,
|
PB_STATE_PREVIEW,
|
||||||
|
PB_STATE_COUNTDOWN,
|
||||||
PB_STATE_TAKING_PHOTO,
|
PB_STATE_TAKING_PHOTO,
|
||||||
PB_STATE_PROCESS_PHOTO,
|
PB_STATE_PROCESS_PHOTO,
|
||||||
PB_STATE_WAITING_FOR_ANSWER,
|
PB_STATE_WAITING_FOR_ANSWER,
|
||||||
|
|
Loading…
Add table
Reference in a new issue