Switch preview rendering to cairo

This commit is contained in:
Martijn Braam 2020-09-03 16:39:20 +02:00
parent db131f2cb0
commit 70519058e6
2 changed files with 402 additions and 73 deletions

View File

@ -1,32 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<!-- Generated with glade 3.37.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="window">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Camera</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkStack" id="main_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="page_main">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="preview_box">
<object class="GtkDrawingArea" id="preview">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage" id="preview">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">True</property>
@ -47,59 +43,19 @@
<child>
<object class="GtkBox" id="controls_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">8</property>
<property name="margin_bottom">8</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-preferences</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
</child>
<property name="can-focus">False</property>
<child type="center">
<object class="GtkButton" id="shutter">
<property name="width_request">48</property>
<property name="height_request">48</property>
<property name="width-request">48</property>
<property name="height-request">48</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="always_show_image">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="always-show-image">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="stock">gtk-cdrom</property>
</object>
</child>
@ -117,9 +73,65 @@
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">8</property>
<property name="margin_bottom">8</property>
<property name="can-focus">False</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton" id="settings">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="stock">gtk-preferences</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="switch_camera">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="stock">gtk-refresh</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<property name="spacing">10</property>
<child>
<placeholder/>
@ -135,7 +147,7 @@
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="pack_type">end</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
@ -153,6 +165,274 @@
<property name="title" translatable="yes">page0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="page_settings">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">4</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Photos</property>
<style>
<class name="heading"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkAlignment">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="left-padding">12</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Resolution</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Preview mode</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="preview_simple">
<property name="label" translatable="yes">Full resolution (slowest)</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="preview_downsample">
<property name="label" translatable="yes">Quarter resolution debayered</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">preview_simple</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="preview_grayscale">
<property name="label" translatable="yes">Grayscale</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">preview_simple</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Storage mode</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="store_vng">
<property name="label" translatable="yes">Debayer with VNG (slowest)</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="store_simple">
<property name="label" translatable="yes">Debayer with linear interpolation</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">store_vng</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="store_raw">
<property name="label" translatable="yes">Raw</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">store_vng</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
<style>
<class name="view"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">page1</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>

67
main.c
View File

@ -62,8 +62,12 @@ static int current_height = -1;
static int current_fmt = 0;
static int current_rotate = 0;
static int capture = 0;
static cairo_surface_t *surface = NULL;
static int preview_width = -1;
static int preview_height = -1;
GObject *preview_image;
// Widgets
GObject *preview;
static int
xioctl(int fd, int request, void *arg)
@ -142,7 +146,7 @@ init_mmap(int fd)
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
if (errno == EINVAL) {
fprintf(stderr, "%s does not support memory mapping",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIDIOC_REQBUFS");
@ -151,7 +155,7 @@ init_mmap(int fd)
if (req.count < 2) {
fprintf(stderr, "Insufficient buffer memory on %s\n",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
}
@ -219,7 +223,7 @@ init_device(int fd)
if (xioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
if (errno == EINVAL) {
fprintf(stderr, "%s is no V4L2 device\n",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIDIOC_QUERYCAP");
@ -228,7 +232,7 @@ init_device(int fd)
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "%s is no video capture device\n",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
}
@ -236,7 +240,7 @@ init_device(int fd)
case IO_METHOD_READ:
if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
fprintf(stderr, "%s does not support read i/o\n",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
}
break;
@ -244,7 +248,7 @@ init_device(int fd)
case IO_METHOD_USERPTR:
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf(stderr, "%s does not support streaming i/o\n",
dev_name);
*dev_name);
exit(EXIT_FAILURE);
}
break;
@ -346,6 +350,8 @@ process_image(const int *p, int size)
GdkPixbuf *pixbuf;
GdkPixbuf *pixbufrot;
GError *error = NULL;
double scale;
cairo_t *cr;
t = clock();
dc1394bayer_method_t method = DC1394_BAYER_METHOD_DOWNSAMPLE;
@ -380,7 +386,15 @@ process_image(const int *p, int size)
g_clear_error(&error);
}
} else {
gtk_image_set_from_pixbuf(preview_image, pixbufrot);
scale = (double)preview_width/gdk_pixbuf_get_width(pixbufrot);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0,0,0);
cairo_paint(cr);
gdk_cairo_set_source_pixbuf(cr, pixbufrot, 0, 0);
cairo_scale(cr, scale, scale);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_NONE);
cairo_paint(cr);
gtk_widget_queue_draw_area(preview, 0, 0, preview_width, preview_height);
}
capture = 0;
t = clock() - t;
@ -388,6 +402,37 @@ process_image(const int *p, int size)
printf("%f fps\n", 1.0/time_taken);
}
static gboolean
preview_draw (GtkWidget *widget, cairo_t *cr, gpointer data)
{
cairo_set_source_surface(cr, surface, 0,0);
cairo_paint(cr);
return FALSE;
}
static gboolean
preview_configure (GtkWidget *widget, GdkEventConfigure *event)
{
cairo_t *cr;
if (surface)
cairo_surface_destroy(surface);
surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget),
CAIRO_CONTENT_COLOR,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
preview_width = gtk_widget_get_allocated_width(widget);
preview_height = gtk_widget_get_allocated_height(widget);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
cairo_destroy(cr);
return TRUE;
}
static int
read_frame(int fd)
{
@ -786,6 +831,7 @@ main(int argc, char *argv[])
GError *error = NULL;
gtk_init(&argc, &argv);
g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", TRUE, NULL);
GtkBuilder *builder = gtk_builder_new();
char *glade_file = "/usr/share/camera/ui/camera.glade";
if (access("camera.glade", F_OK) != -1) {
@ -800,9 +846,12 @@ main(int argc, char *argv[])
GObject *window = gtk_builder_get_object(builder, "window");
GObject *preview_box = gtk_builder_get_object(builder, "preview_box");
GObject *shutter = gtk_builder_get_object(builder, "shutter");
preview_image = gtk_builder_get_object(builder, "preview");
GObject *settings_btn = gtk_builder_get_object(builder, "settings");
preview = gtk_builder_get_object(builder, "preview");
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(shutter, "clicked", G_CALLBACK(on_shutter_clicked), NULL);
g_signal_connect(preview, "draw", G_CALLBACK(preview_draw), NULL);
g_signal_connect(preview, "configure-event", G_CALLBACK(preview_configure), NULL);
GtkCssProvider *provider = gtk_css_provider_new();
if (access("camera.css", F_OK) != -1) {