Allow the device, image scaling and flipping to be configured

This commit is contained in:
Pierre Pronchery 2014-01-05 23:50:54 -06:00
parent 3c6a1f86f9
commit 968a9353be

View File

@ -1,5 +1,5 @@
/* $Id$ */ /* $Id$ */
/* Copyright (c) 2012-2013 Pierre Pronchery <khorben@defora.org> */ /* Copyright (c) 2012-2014 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Desktop Phone */ /* This file is part of DeforaOS Desktop Phone */
/* This program is free software: you can redistribute it and/or modify /* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -43,6 +43,10 @@ typedef struct _PhonePlugin
PhonePluginHelper * helper; PhonePluginHelper * helper;
String * device; String * device;
gboolean hflip;
gboolean vflip;
gboolean ratio;
GdkInterpType interp;
guint source; guint source;
int fd; int fd;
@ -114,14 +118,25 @@ static int _open_setup(VideoPhonePlugin * video);
static VideoPhonePlugin * _video_init(PhonePluginHelper * helper) static VideoPhonePlugin * _video_init(PhonePluginHelper * helper)
{ {
VideoPhonePlugin * video; VideoPhonePlugin * video;
char const * device = NULL; char const * device;
char const * p;
if((video = object_new(sizeof(*video))) == NULL) if((video = object_new(sizeof(*video))) == NULL)
return NULL; return NULL;
video->helper = helper; video->helper = helper;
/* FIXME let this be configurable */ if((device = helper->config_get(helper->phone, "video", "device"))
if(device == NULL) == NULL)
device = "/dev/video0"; device = "/dev/video0";
p = helper->config_get(helper->phone, "video", "hflip");
video->hflip = (p != NULL && p[0] != '\0' && strtol(p, NULL, 10) > 0)
? TRUE : FALSE;
p = helper->config_get(helper->phone, "video", "vflip");
video->vflip = (p != NULL && p[0] != '\0' && strtol(p, NULL, 10) > 0)
? TRUE : FALSE;
p = helper->config_get(helper->phone, "video", "ratio");
video->ratio = (p == NULL || p[0] == '\0' || strtol(p, NULL, 10) != 0)
? TRUE : FALSE;
video->interp = GDK_INTERP_BILINEAR;
video->source = 0; video->source = 0;
video->fd = -1; video->fd = -1;
memset(&video->cap, 0, sizeof(video->cap)); memset(&video->cap, 0, sizeof(video->cap));
@ -378,6 +393,9 @@ static gboolean _video_on_drawing_area_expose(GtkWidget * widget,
static void _refresh_convert(VideoPhonePlugin * video); static void _refresh_convert(VideoPhonePlugin * video);
static void _refresh_convert_yuv(int amp, uint8_t y, uint8_t u, uint8_t v, static void _refresh_convert_yuv(int amp, uint8_t y, uint8_t u, uint8_t v,
uint8_t * r, uint8_t * g, uint8_t * b); uint8_t * r, uint8_t * g, uint8_t * b);
static void _refresh_hflip(VideoPhonePlugin * video, GdkPixbuf ** pixbuf);
static void _refresh_scale(VideoPhonePlugin * video, GdkPixbuf ** pixbuf);
static void _refresh_vflip(VideoPhonePlugin * video, GdkPixbuf ** pixbuf);
static gboolean _video_on_refresh(gpointer data) static gboolean _video_on_refresh(gpointer data)
{ {
@ -386,14 +404,16 @@ static gboolean _video_on_refresh(gpointer data)
int width = video->format.fmt.pix.width; int width = video->format.fmt.pix.width;
int height = video->format.fmt.pix.height; int height = video->format.fmt.pix.height;
GdkPixbuf * pixbuf; GdkPixbuf * pixbuf;
GdkPixbuf * pixbuf2;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__, fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__,
video->format.fmt.pix.pixelformat); video->format.fmt.pix.pixelformat);
#endif #endif
_refresh_convert(video); _refresh_convert(video);
if(width == allocation->width && height == allocation->height) if(video->hflip == FALSE
&& video->vflip == FALSE
&& width == allocation->width
&& height == allocation->height)
/* render directly */ /* render directly */
gdk_draw_rgb_image(video->pixmap, video->gc, 0, 0, gdk_draw_rgb_image(video->pixmap, video->gc, 0, 0,
width, height, GDK_RGB_DITHER_NORMAL, width, height, GDK_RGB_DITHER_NORMAL,
@ -404,12 +424,12 @@ static gboolean _video_on_refresh(gpointer data)
pixbuf = gdk_pixbuf_new_from_data(video->rgb_buffer, pixbuf = gdk_pixbuf_new_from_data(video->rgb_buffer,
GDK_COLORSPACE_RGB, FALSE, 8, width, height, GDK_COLORSPACE_RGB, FALSE, 8, width, height,
width * 3, NULL, NULL); width * 3, NULL, NULL);
pixbuf2 = gdk_pixbuf_scale_simple(pixbuf, allocation->width, _refresh_hflip(video, &pixbuf);
allocation->height, GDK_INTERP_BILINEAR); _refresh_vflip(video, &pixbuf);
gdk_pixbuf_render_to_drawable(pixbuf2, video->pixmap, _refresh_scale(video, &pixbuf);
gdk_pixbuf_render_to_drawable(pixbuf, video->pixmap,
video->gc, 0, 0, 0, 0, -1, -1, video->gc, 0, 0, 0, 0, -1, -1,
GDK_RGB_DITHER_NORMAL, 0, 0); GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(pixbuf2);
g_object_unref(pixbuf); g_object_unref(pixbuf);
} }
/* force a refresh */ /* force a refresh */
@ -473,3 +493,65 @@ static void _refresh_convert_yuv(int amp, uint8_t y, uint8_t u, uint8_t v,
*g = (dg < 0) ? 0 : ((dg > 255) ? 255 : dg); *g = (dg < 0) ? 0 : ((dg > 255) ? 255 : dg);
*b = (db < 0) ? 0 : ((db > 255) ? 255 : db); *b = (db < 0) ? 0 : ((db > 255) ? 255 : db);
} }
static void _refresh_hflip(VideoPhonePlugin * video, GdkPixbuf ** pixbuf)
{
GdkPixbuf * pixbuf2;
if(video->hflip == FALSE)
return;
/* XXX could probably be more efficient */
pixbuf2 = gdk_pixbuf_flip(*pixbuf, TRUE);
g_object_unref(*pixbuf);
*pixbuf = pixbuf2;
}
static void _refresh_scale(VideoPhonePlugin * video, GdkPixbuf ** pixbuf)
{
GtkAllocation * allocation = &video->area_allocation;
GdkPixbuf * pixbuf2;
gdouble scale;
gint width;
gint height;
gint x;
gint y;
if(video->ratio == FALSE)
pixbuf2 = gdk_pixbuf_scale_simple(*pixbuf, allocation->width,
allocation->height, video->interp);
else
{
if((pixbuf2 = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
allocation->width,
allocation->height)) == NULL)
return;
/* XXX could be more efficient */
gdk_pixbuf_fill(pixbuf2, 0);
scale = (gdouble)allocation->width
/ video->format.fmt.pix.width;
scale = MIN(scale, (gdouble)allocation->height
/ video->format.fmt.pix.height);
width = (gdouble)video->format.fmt.pix.width * scale;
width = MIN(width, allocation->width);
height = (gdouble)video->format.fmt.pix.height * scale;
height = MIN(height, allocation->height);
x = (allocation->width - width) / 2;
y = (allocation->height - height) / 2;
gdk_pixbuf_scale(*pixbuf, pixbuf2, x, y, width, height,
0.0, 0.0, scale, scale, video->interp);
}
g_object_unref(*pixbuf);
*pixbuf = pixbuf2;
}
static void _refresh_vflip(VideoPhonePlugin * video, GdkPixbuf ** pixbuf)
{
GdkPixbuf * pixbuf2;
if(video->vflip == FALSE)
return;
/* XXX could probably be more efficient */
pixbuf2 = gdk_pixbuf_flip(*pixbuf, FALSE);
g_object_unref(*pixbuf);
*pixbuf = pixbuf2;
}