Added the possibility to take pictures (untested)

This commit is contained in:
Pierre Pronchery 2012-12-22 03:08:04 +01:00
parent 548caa5d5c
commit 8a37018d0c

View File

@ -47,8 +47,10 @@ struct _Camera
int fd; int fd;
struct v4l2_format format; struct v4l2_format format;
char * buffer; char * raw_buffer;
size_t buffer_cnt; size_t raw_buffer_cnt;
unsigned char * rgb_buffer;
size_t rgb_buffer_cnt;
guint source; guint source;
@ -81,11 +83,11 @@ static gboolean _camera_on_drawing_area_configure(GtkWidget * widget,
GdkEventConfigure * event, gpointer data); GdkEventConfigure * event, gpointer data);
static gboolean _camera_on_drawing_area_expose(GtkWidget * widget, static gboolean _camera_on_drawing_area_expose(GtkWidget * widget,
GdkEventExpose * event, gpointer data); GdkEventExpose * event, gpointer data);
static gboolean _camera_on_open(gpointer data);
static gboolean _camera_on_refresh(gpointer data);
static void _camera_on_file_close(gpointer data); static void _camera_on_file_close(gpointer data);
static void _camera_on_help_about(gpointer data); static void _camera_on_help_about(gpointer data);
static gboolean _camera_on_open(gpointer data);
static gboolean _camera_on_refresh(gpointer data);
static void _camera_on_snapshot(gpointer data);
/* constants */ /* constants */
@ -115,6 +117,15 @@ static const DesktopMenubar _camera_menubar[] =
}; };
/* variables */
static DesktopToolbar _camera_toolbar[] =
{
{ "Snapshot", G_CALLBACK(_camera_on_snapshot), "camera-photo", 0, 0,
NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
/* public */ /* public */
/* functions */ /* functions */
/* camera_new */ /* camera_new */
@ -131,8 +142,10 @@ Camera * camera_new(char const * device)
device = "/dev/video0"; device = "/dev/video0";
camera->device = string_new(device); camera->device = string_new(device);
camera->fd = -1; camera->fd = -1;
camera->buffer = NULL; camera->raw_buffer = NULL;
camera->buffer_cnt = 0; camera->raw_buffer_cnt = 0;
camera->rgb_buffer = NULL;
camera->rgb_buffer_cnt = 0;
camera->source = 0; camera->source = 0;
camera->yuv_amp = 255; camera->yuv_amp = 255;
camera->gc = NULL; camera->gc = NULL;
@ -160,8 +173,12 @@ Camera * camera_new(char const * device)
/* menubar */ /* menubar */
widget = desktop_menubar_create(_camera_menubar, camera, group); widget = desktop_menubar_create(_camera_menubar, camera, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
/* toolbar */
widget = desktop_toolbar_create(_camera_toolbar, camera, group);
gtk_widget_set_sensitive(GTK_WIDGET(_camera_toolbar[0].widget), FALSE);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
#if GTK_CHECK_VERSION(2, 18, 0) #if GTK_CHECK_VERSION(2, 18, 0)
/* errors */ /* infobar */
camera->infobar = gtk_info_bar_new_with_buttons(GTK_STOCK_CLOSE, camera->infobar = gtk_info_bar_new_with_buttons(GTK_STOCK_CLOSE,
GTK_RESPONSE_CLOSE, NULL); GTK_RESPONSE_CLOSE, NULL);
gtk_info_bar_set_message_type(GTK_INFO_BAR(camera->infobar), gtk_info_bar_set_message_type(GTK_INFO_BAR(camera->infobar),
@ -205,7 +222,8 @@ void camera_delete(Camera * camera)
g_source_remove(camera->source); g_source_remove(camera->source);
if(camera->fd >= 0) if(camera->fd >= 0)
close(camera->fd); close(camera->fd);
free(camera->buffer); free(camera->raw_buffer);
free(camera->rgb_buffer);
string_delete(camera->device); string_delete(camera->device);
object_delete(camera); object_delete(camera);
} }
@ -276,7 +294,8 @@ static gboolean _camera_on_can_read(gpointer data)
#endif #endif
camera->source = 0; camera->source = 0;
/* FIXME no longer block on read() */ /* FIXME no longer block on read() */
if((s = read(camera->fd, camera->buffer, camera->buffer_cnt)) <= 0) if((s = read(camera->fd, camera->raw_buffer, camera->raw_buffer_cnt))
<= 0)
{ {
/* this error can be ignored */ /* this error can be ignored */
if(errno == EAGAIN) if(errno == EAGAIN)
@ -284,11 +303,13 @@ static gboolean _camera_on_can_read(gpointer data)
close(camera->fd); close(camera->fd);
camera->fd = -1; camera->fd = -1;
_camera_error(camera, strerror(errno), 1); _camera_error(camera, strerror(errno), 1);
gtk_widget_set_sensitive(GTK_WIDGET(_camera_toolbar[0].widget),
FALSE);
return FALSE; return FALSE;
} }
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() %lu %ld\n", __func__, fprintf(stderr, "DEBUG: %s() %lu %ld\n", __func__,
camera->buffer_cnt, s); camera->raw_buffer_cnt, s);
#endif #endif
camera->source = g_idle_add(_camera_on_refresh, camera); camera->source = g_idle_add(_camera_on_refresh, camera);
return FALSE; return FALSE;
@ -411,6 +432,7 @@ static gboolean _camera_on_open(gpointer data)
camera->format.fmt.pix.width, camera->format.fmt.pix.width,
camera->format.fmt.pix.height); camera->format.fmt.pix.height);
#endif #endif
gtk_widget_set_sensitive(GTK_WIDGET(_camera_toolbar[0].widget), TRUE);
gtk_widget_set_size_request(camera->area, camera->format.fmt.pix.width, gtk_widget_set_size_request(camera->area, camera->format.fmt.pix.width,
camera->format.fmt.pix.height); camera->format.fmt.pix.height);
/* FIXME register only if can really be read */ /* FIXME register only if can really be read */
@ -458,18 +480,18 @@ static int _open_setup(Camera * camera)
return -error_set_code(1, "%s: %s", camera->device, return -error_set_code(1, "%s: %s", camera->device,
"Unsupported video capture type"); "Unsupported video capture type");
/* FIXME try to obtain a RGB24 format if possible */ /* FIXME try to obtain a RGB24 format if possible */
if((p = realloc(camera->buffer, camera->format.fmt.pix.sizeimage)) if((p = realloc(camera->raw_buffer, camera->format.fmt.pix.sizeimage))
== NULL) == NULL)
return -error_set_code(1, "%s: %s", camera->device, return -error_set_code(1, "%s: %s", camera->device,
strerror(errno)); strerror(errno));
camera->buffer = p; camera->raw_buffer = p;
camera->buffer_cnt = camera->format.fmt.pix.sizeimage; camera->raw_buffer_cnt = camera->format.fmt.pix.sizeimage;
return 0; return 0;
} }
/* camera_on_refresh */ /* camera_on_refresh */
static void _refresh_convert(Camera * camera, unsigned char * buf); static void _refresh_convert(Camera * camera);
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);
@ -477,19 +499,16 @@ static gboolean _camera_on_refresh(gpointer data)
{ {
Camera * camera = data; Camera * camera = data;
GtkAllocation * allocation = &camera->area_allocation; GtkAllocation * allocation = &camera->area_allocation;
/* XXX pre-allocate this buffer */
unsigned char buf[camera->format.fmt.pix.width
* camera->format.fmt.pix.height * 3];
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__, fprintf(stderr, "DEBUG: %s() 0x%x\n", __func__,
camera->format.fmt.pix.pixelformat); camera->format.fmt.pix.pixelformat);
#endif #endif
camera->source = 0; camera->source = 0;
_refresh_convert(camera, buf); _refresh_convert(camera);
gdk_draw_rgb_image(camera->pixmap, camera->gc, 0, 0, allocation->width, gdk_draw_rgb_image(camera->pixmap, camera->gc, 0, 0, allocation->width,
allocation->height, GDK_RGB_DITHER_NORMAL, allocation->height, GDK_RGB_DITHER_NORMAL,
buf, camera->format.fmt.pix.width * 3); camera->rgb_buffer, camera->format.fmt.pix.width * 3);
gtk_widget_queue_draw_area(camera->area, 0, 0, gtk_widget_queue_draw_area(camera->area, 0, 0,
camera->area_allocation.width, camera->area_allocation.width,
camera->area_allocation.height); camera->area_allocation.height);
@ -497,7 +516,7 @@ static gboolean _camera_on_refresh(gpointer data)
return FALSE; return FALSE;
} }
static void _refresh_convert(Camera * camera, unsigned char * buf) static void _refresh_convert(Camera * camera)
{ {
size_t i; size_t i;
size_t j; size_t j;
@ -505,23 +524,25 @@ static void _refresh_convert(Camera * camera, unsigned char * buf)
switch(camera->format.fmt.pix.pixelformat) switch(camera->format.fmt.pix.pixelformat)
{ {
case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUYV:
for(i = 0, j = 0; i + 3 < camera->buffer_cnt; for(i = 0, j = 0; i + 3 < camera->raw_buffer_cnt;
i += 4, j += 6) i += 4, j += 6)
{ {
/* pixel 0 */ /* pixel 0 */
_refresh_convert_yuv(camera->yuv_amp, _refresh_convert_yuv(camera->yuv_amp,
camera->buffer[i], camera->raw_buffer[i],
camera->buffer[i + 1], camera->raw_buffer[i + 1],
camera->buffer[i + 3], camera->raw_buffer[i + 3],
&buf[j + 2], &buf[j + 1], &camera->rgb_buffer[j + 2],
&buf[j]); &camera->rgb_buffer[j + 1],
&camera->rgb_buffer[j]);
/* pixel 1 */ /* pixel 1 */
_refresh_convert_yuv(camera->yuv_amp, _refresh_convert_yuv(camera->yuv_amp,
camera->buffer[i + 2], camera->raw_buffer[i + 2],
camera->buffer[i + 1], camera->raw_buffer[i + 1],
camera->buffer[i + 3], camera->raw_buffer[i + 3],
&buf[j + 5], &buf[j + 4], &camera->rgb_buffer[j + 5],
&buf[j + 3]); &camera->rgb_buffer[j + 4],
&camera->rgb_buffer[j + 3]);
} }
break; break;
default: default:
@ -547,3 +568,31 @@ 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);
} }
/* camera_on_snapshot */
static void _camera_on_snapshot(gpointer data)
{
Camera * camera = data;
GdkPixbuf * pixbuf;
GError * error = NULL;
if((pixbuf = gdk_pixbuf_new_from_data(camera->rgb_buffer,
GDK_COLORSPACE_RGB, FALSE, 8,
camera->area_allocation.width,
camera->area_allocation.height,
camera->area_allocation.width * 3,
NULL, NULL)) == NULL)
{
_camera_error(camera, "Could not save picture", 1);
return;
}
if(gdk_pixbuf_save(pixbuf, "Snapshot.png", "png", &error, NULL)
!= TRUE)
{
error_set("%s (%s)", "Could not save picture", error->message);
_camera_error(camera, error_get(), 1);
g_error_free(error);
}
g_object_unref(pixbuf);
}