From d35a061a766327933561c0d59605d9c589b05986 Mon Sep 17 00:00:00 2001 From: rizzo Date: Sat, 29 Dec 2007 02:02:03 +0000 Subject: [PATCH] Move grabbers definitions to a separate file, vgrabbers.c, so it is easier to add more entries. This required moving struct grab_desc to the common header, and adding an entry in the Makefile. On passing, cleanup some comments and file headers (some are still missing). git-svn-id: http://svn.digium.com/svn/asterisk/trunk@95313 f38db490-d61c-443f-a65b-d21fe96a405b --- channels/Makefile | 2 +- channels/console_video.c | 321 +++--------------------------------- channels/console_video.h | 17 +- channels/vcodecs.c | 16 ++ channels/vgrabbers.c | 345 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 401 insertions(+), 300 deletions(-) create mode 100644 channels/vgrabbers.c diff --git a/channels/Makefile b/channels/Makefile index 757f20967..1afeebfc9 100644 --- a/channels/Makefile +++ b/channels/Makefile @@ -51,7 +51,7 @@ endif all: _all -chan_oss.so: console_video.o +chan_oss.so: console_video.o vgrabbers.o include $(ASTTOPDIR)/Makefile.moddir_rules diff --git a/channels/console_video.c b/channels/console_video.c index fd2f9fe59..604a58028 100644 --- a/channels/console_video.c +++ b/channels/console_video.c @@ -1,3 +1,19 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright 2007, Marta Carbone, Sergio Fadda, Luigi Rizzo + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + /* * Experimental support for video sessions. We use SDL for rendering, ffmpeg * as the codec library for encoding and decoding, and Video4Linux and X11 @@ -131,7 +147,6 @@ int console_video_formats = static void my_scale(struct fbuf_t *in, AVPicture *p_in, struct fbuf_t *out, AVPicture *p_out); -struct grab_desc; /* grabber description */ struct video_codec_desc; /* forward declaration */ /* * Descriptor of the local source, made of the following pieces: @@ -208,7 +223,7 @@ struct video_desc { static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p); -static void fbuf_free(struct fbuf_t *b) +void fbuf_free(struct fbuf_t *b) { struct fbuf_t x = *b; @@ -224,292 +239,14 @@ static void fbuf_free(struct fbuf_t *b) #include "vcodecs.c" #include "console_gui.c" -/*------ end codec specific code -----*/ - -/* descriptor for a grabber */ -struct grab_desc { - const char *name; - void *(*open)(const char *name, struct fbuf_t *geom, int fps); - struct fbuf_t *(*read)(void *d); - void (*move)(void *d, int dx, int dy); - void *(*close)(void *d); -}; - - -#ifdef HAVE_X11 -struct grab_x11_desc { - Display *dpy; /* x11 grabber info */ - XImage *image; - int screen_width; /* width of X screen */ - int screen_height; /* height of X screen */ - struct fbuf_t b; -}; - -static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps) -{ - XImage *im; - int screen_num; - struct grab_x11_desc *v; - struct fbuf_t *b; - - if (strcasecmp(name, "X11")) - return NULL; /* not us */ - v = ast_calloc(1, sizeof(*v)); - if (v == NULL) - return NULL; /* no memory */ - - /* init the connection with the X server */ - v->dpy = XOpenDisplay(NULL); - if (v->dpy == NULL) { - ast_log(LOG_WARNING, "error opening display\n"); - goto error; - } - - v->b = *geom; /* copy geometry */ - b = &v->b; /* shorthand */ - /* find width and height of the screen */ - screen_num = DefaultScreen(v->dpy); - v->screen_width = DisplayWidth(v->dpy, screen_num); - v->screen_height = DisplayHeight(v->dpy, screen_num); - - v->image = im = XGetImage(v->dpy, - RootWindow(v->dpy, DefaultScreen(v->dpy)), - b->x, b->y, b->w, b->h, AllPlanes, ZPixmap); - if (v->image == NULL) { - ast_log(LOG_WARNING, "error creating Ximage\n"); - goto error; - } - switch (im->bits_per_pixel) { - case 32: - b->pix_fmt = PIX_FMT_RGBA32; - break; - case 16: - b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555; - break; - } - - ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n", - im->data, - im->bits_per_pixel, - b->pix_fmt, - im->red_mask, im->green_mask, im->blue_mask); - - /* set the pointer but not the size as this is not malloc'ed */ - b->data = (uint8_t *)im->data; - return v; - -error: - /* XXX maybe XDestroy (v->image) ? */ - if (v->dpy) - XCloseDisplay(v->dpy); - v->dpy = NULL; - ast_free(v); - return NULL; -} - -static struct fbuf_t *grab_x11_read(void *desc) -{ - /* read frame from X11 */ - struct grab_x11_desc *v = desc; - struct fbuf_t *b = &v->b; - - XGetSubImage(v->dpy, - RootWindow(v->dpy, DefaultScreen(v->dpy)), - b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0); - - b->data = (uint8_t *)v->image->data; - return b; -} - -static int boundary_checks(int x, int limit) -{ - return (x <= 0) ? 0 : (x > limit ? limit : x); -} - -/* move the origin for the grabbed area */ -static void grab_x11_move(void *desc, int dx, int dy) -{ - struct grab_x11_desc *v = desc; - - v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w); - v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h); -} - -static void *grab_x11_close(void *desc) -{ - struct grab_x11_desc *v = desc; - - XCloseDisplay(v->dpy); - v->dpy = NULL; - v->image = NULL; - ast_free(v); - return NULL; -} - -static struct grab_desc grab_x11_desc = { - .name = "X11", - .open = grab_x11_open, - .read = grab_x11_read, - .move = grab_x11_move, - .close = grab_x11_close, -}; - -#endif /* HAVE_X11 */ - -/* Video4Linux stuff is only used in grabber_open() */ -#ifdef HAVE_VIDEODEV_H -#include - -struct grab_v4l1_desc { - int fd; - int fps; - struct fbuf_t b; -}; - -/*! - * Open the local video source and allocate a buffer - * for storing the image. Return 0 on success, -1 on error - */ -static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps) -{ - struct video_window vw = { 0 }; /* camera attributes */ - struct video_picture vp; - int fd, i; - struct grab_v4l1_desc *v; - struct fbuf_t *b; - - fd = open(dev, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - ast_log(LOG_WARNING, "error opening camera %s\n", dev); - return NULL; - } - - v = ast_calloc(1, sizeof(*v)); - if (v == NULL) { - ast_log(LOG_WARNING, "no memory for camera %s\n", dev); - close(fd); - return NULL; /* no memory */ - } - v->fd = fd; - v->b = *geom; - b = &v->b; /* shorthand */ - - i = fcntl(fd, F_GETFL); - if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) { - /* non fatal, just emit a warning */ - ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n", - dev, strerror(errno)); - } - /* set format for the camera. - * In principle we could retry with a different format if the - * one we are asking for is not supported. - */ - vw.width = b->w; - vw.height = b->h; - vw.flags = fps << 16; - if (ioctl(fd, VIDIOCSWIN, &vw) == -1) { - ast_log(LOG_WARNING, "error setting format for %s [%s]\n", - dev, strerror(errno)); - goto error; - } - if (ioctl(fd, VIDIOCGPICT, &vp) == -1) { - ast_log(LOG_WARNING, "error reading picture info\n"); - goto error; - } - ast_log(LOG_WARNING, - "contrast %d bright %d colour %d hue %d white %d palette %d\n", - vp.contrast, vp.brightness, - vp.colour, vp.hue, - vp.whiteness, vp.palette); - /* set the video format. Here again, we don't necessary have to - * fail if the required format is not supported, but try to use - * what the camera gives us. - */ - b->pix_fmt = vp.palette; - vp.palette = VIDEO_PALETTE_YUV420P; - if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) { - ast_log(LOG_WARNING, "error setting palette, using %d\n", - b->pix_fmt); - } else - b->pix_fmt = vp.palette; - /* allocate the source buffer. - * XXX, the code here only handles yuv411, for other formats - * we need to look at pix_fmt and set size accordingly - */ - b->size = (b->w * b->h * 3)/2; /* yuv411 */ - ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n", - dev, b->w, b->h, b->size); - b->data = ast_calloc(1, b->size); - if (!b->data) { - ast_log(LOG_WARNING, "error allocating buffer %d bytes\n", - b->size); - goto error; - } - ast_log(LOG_WARNING, "success opening camera\n"); - return v; - -error: - close(v->fd); - fbuf_free(b); - ast_free(v); - return NULL; -} - -static struct fbuf_t *grab_v4l1_read(void *desc) -{ - struct grab_v4l1_desc *v = desc; - struct fbuf_t *b = &v->b; - for (;;) { - int r, l = b->size - b->used; - r = read(v->fd, b->data + b->used, l); - // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l); - if (r < 0) /* read error */ - break; - if (r == 0) /* no data */ - break; - b->used += r; - if (r == l) { - b->used = 0; /* prepare for next frame */ - return b; - } - } - return NULL; -} - -static void *grab_v4l1_close(void *desc) -{ - struct grab_v4l1_desc *v = desc; - - close(v->fd); - v->fd = -1; - fbuf_free(&v->b); - ast_free(v); - return NULL; -} - -static struct grab_desc grab_v4l1_desc = { - .name = "v4l1", - .open = grab_v4l1_open, - .read = grab_v4l1_read, - .close = grab_v4l1_close, -}; -#endif /* HAVE_VIDEODEV_H */ - -static struct grab_desc *my_grabbers[] = { - &grab_x11_desc, - &grab_v4l1_desc, - NULL -}; - -/* try to open a video source, return 0 on success, 1 on error - */ +/*! \brief Try to open a video source, return 0 on success, 1 on error */ static int grabber_open(struct video_out_desc *v) { struct grab_desc *g; void *g_data; int i; - for (i = 0; (g = my_grabbers[i]); i++) { + for (i = 0; (g = console_grabbers[i]); i++) { g_data = g->open(v->videodevice, &v->loc_src_geometry, v->fps); if (g_data) { v->grabber = g; @@ -539,22 +276,16 @@ static struct fbuf_t *grabber_read(struct video_out_desc *v) return v->grabber->read(v->grabber_data); } +/*! \brief handler run when dragging with the left button on + * the local source window - the effect is to move the offset + * of the captured area. + */ static void grabber_move(struct video_out_desc *v, int dx, int dy) { if (v->grabber && v->grabber->move) v->grabber->move(v->grabber_data, dx, dy); } -/* Helper function to process incoming video. - * For each incoming video call invoke ffmpeg_init() to intialize - * the decoding structure then incoming video frames are processed - * by write_video() which in turn calls pre_process_data(), to extract - * the bitstream; accumulates data into a buffer within video_desc. When - * a frame is complete (determined by the marker bit in the RTP header) - * call decode_video() to decoding and if it successful call show_frame() - * to display the frame. - */ - /* * Map the codec name to the library. If not recognised, use a default. * This is useful in the output path where we decide by name, presumably. @@ -607,8 +338,8 @@ static int video_out_uninit(struct video_desc *env) /* * Initialize the encoder for the local source: - * - AVCodecContext, AVCodec, AVFrame are used by ffmpeg for encoding; - * - encbuf is used to store the encoded frame (to be sent) + * - enc_ctx, codec, enc_in_frame are used by ffmpeg for encoding; + * - enc_out is used to store the encoded frame (to be sent) * - mtu is used to determine the max size of video fragment * NOTE: we enter here with the video source already open. */ @@ -922,7 +653,7 @@ static struct ast_frame *get_video_frames(struct video_desc *env, struct ast_fra if (v->enc_out.data == NULL) { static volatile int a = 0; if (a++ < 2) - ast_log(LOG_WARNING, "fail, no encbuf\n"); + ast_log(LOG_WARNING, "fail, no encoder output buffer\n"); return NULL; } v->enc->enc_run(v); diff --git a/channels/console_video.h b/channels/console_video.h index 4a1ef2be1..beea23cb6 100644 --- a/channels/console_video.h +++ b/channels/console_video.h @@ -28,10 +28,6 @@ "console {device}" #else -#ifdef HAVE_X11 -#include /* this should be conditional */ -#endif - #include #ifndef OLD_FFMPEG #include /* requires a recent ffmpeg */ @@ -66,6 +62,19 @@ struct fbuf_t { /* frame buffers, dynamically allocated */ int pix_fmt; }; +void fbuf_free(struct fbuf_t *); + +/* descriptor for a grabber */ +struct grab_desc { + const char *name; + void *(*open)(const char *name, struct fbuf_t *geom, int fps); + struct fbuf_t *(*read)(void *d); + void (*move)(void *d, int dx, int dy); + void *(*close)(void *d); +}; + +extern struct grab_desc *console_grabbers[]; + struct video_desc; /* opaque type for video support */ struct video_desc *get_video_desc(struct ast_channel *c); diff --git a/channels/vcodecs.c b/channels/vcodecs.c index 8cb1f2099..6eccd63f1 100644 --- a/channels/vcodecs.c +++ b/channels/vcodecs.c @@ -1,3 +1,19 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright 2007, Sergio Fadda, Luigi Rizzo + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + /* * Video codecs support for console_video.c * $Revision$ diff --git a/channels/vgrabbers.c b/channels/vgrabbers.c new file mode 100644 index 000000000..b58979982 --- /dev/null +++ b/channels/vgrabbers.c @@ -0,0 +1,345 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright 2007, Luigi Rizzo + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/* + * Video grabbers used in console_video. + * + * $Revision$ + * + * Each grabber is implemented through open/read/close calls, + * plus an additional move() function used e.g. to change origin + * for the X grabber (this may be extended in the future to support + * more controls e.g. resolution changes etc.). + * + * open() should try to open and initialize the grabber, returning NULL on error. + * On success it allocates a descriptor for its private data (including + * a buffer for the video) and returns a pointer to the descriptor. + * read() will return NULL on failure, or a pointer to a buffer with data + * on success. + * close() should release resources. + * move() is optional. + * For more details look at the X11 grabber below. + * + * NOTE: at the moment we expect uncompressed video frames in YUV format, + * because this is what current sources supply and also is a convenient + * format for display. It is conceivable that one might want to support + * an already compressed stream, in which case we should redesign the + * pipeline used for the local source, which at the moment is + * + * .->--[loc_dpy] + * [src]-->--[enc_in]--+ + * `->--[enc_out] + */ + +#include "asterisk.h" +#include +#include "asterisk/file.h" +#include "asterisk/utils.h" /* ast_calloc */ + +#include "console_video.h" + +#if defined(HAVE_VIDEO_CONSOLE) + +#ifdef HAVE_X11 + +/* A simple X11 grabber, supporting only truecolor formats */ + +#include + +/*! \brief internal info used by the X11 grabber */ +struct grab_x11_desc { + Display *dpy; + XImage *image; + int screen_width; /* width of X screen */ + int screen_height; /* height of X screen */ + struct fbuf_t b; /* geometry and pointer into the XImage */ +}; + +/*! \brief open the grabber. + * We use the special name 'X11' to indicate this grabber. + */ +static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps) +{ + XImage *im; + int screen_num; + struct grab_x11_desc *v; + struct fbuf_t *b; + + if (strcasecmp(name, "X11")) + return NULL; /* not us */ + v = ast_calloc(1, sizeof(*v)); + if (v == NULL) + return NULL; /* no memory */ + + /* init the connection with the X server */ + v->dpy = XOpenDisplay(NULL); + if (v->dpy == NULL) { + ast_log(LOG_WARNING, "error opening display\n"); + goto error; + } + + v->b = *geom; /* copy geometry */ + b = &v->b; /* shorthand */ + /* find width and height of the screen */ + screen_num = DefaultScreen(v->dpy); + v->screen_width = DisplayWidth(v->dpy, screen_num); + v->screen_height = DisplayHeight(v->dpy, screen_num); + + v->image = im = XGetImage(v->dpy, + RootWindow(v->dpy, DefaultScreen(v->dpy)), + b->x, b->y, b->w, b->h, AllPlanes, ZPixmap); + if (v->image == NULL) { + ast_log(LOG_WARNING, "error creating Ximage\n"); + goto error; + } + switch (im->bits_per_pixel) { + case 32: + b->pix_fmt = PIX_FMT_RGBA32; + break; + case 16: + b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555; + break; + } + + ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n", + im->data, + im->bits_per_pixel, + b->pix_fmt, + im->red_mask, im->green_mask, im->blue_mask); + + /* set the pointer but not the size as this is not malloc'ed */ + b->data = (uint8_t *)im->data; + return v; + +error: + /* XXX maybe XDestroy (v->image) ? */ + if (v->dpy) + XCloseDisplay(v->dpy); + v->dpy = NULL; + ast_free(v); + return NULL; +} + +static struct fbuf_t *grab_x11_read(void *desc) +{ + /* read frame from X11 */ + struct grab_x11_desc *v = desc; + struct fbuf_t *b = &v->b; + + XGetSubImage(v->dpy, + RootWindow(v->dpy, DefaultScreen(v->dpy)), + b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0); + + b->data = (uint8_t *)v->image->data; + return b; +} + +static int boundary_checks(int x, int limit) +{ + return (x <= 0) ? 0 : (x > limit ? limit : x); +} + +/*! \brief move the origin for the grabbed area, making sure we do not + * overflow the screen. + */ +static void grab_x11_move(void *desc, int dx, int dy) +{ + struct grab_x11_desc *v = desc; + + v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w); + v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h); +} + +/*! \brief disconnect from the server and release memory */ +static void *grab_x11_close(void *desc) +{ + struct grab_x11_desc *v = desc; + + XCloseDisplay(v->dpy); + v->dpy = NULL; + v->image = NULL; + ast_free(v); + return NULL; +} + +static struct grab_desc grab_x11_desc = { + .name = "X11", + .open = grab_x11_open, + .read = grab_x11_read, + .move = grab_x11_move, + .close = grab_x11_close, +}; +#endif /* HAVE_X11 */ + +#ifdef HAVE_VIDEODEV_H +#include /* Video4Linux stuff is only used in grab_v4l1_open() */ + +struct grab_v4l1_desc { + int fd; /* device handle */ + struct fbuf_t b; /* buffer (allocated) with grabbed image */ +}; + +/*! \brief + * Open the local video source and allocate a buffer + * for storing the image. + */ +static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps) +{ + struct video_window vw = { 0 }; /* camera attributes */ + struct video_picture vp; + int fd, i; + struct grab_v4l1_desc *v; + struct fbuf_t *b; + + fd = open(dev, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + ast_log(LOG_WARNING, "error opening camera %s\n", dev); + return NULL; + } + + v = ast_calloc(1, sizeof(*v)); + if (v == NULL) { + ast_log(LOG_WARNING, "no memory for camera %s\n", dev); + close(fd); + return NULL; /* no memory */ + } + v->fd = fd; + v->b = *geom; + b = &v->b; /* shorthand */ + + i = fcntl(fd, F_GETFL); + if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) { + /* non fatal, just emit a warning */ + ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n", + dev, strerror(errno)); + } + /* set format for the camera. + * In principle we could retry with a different format if the + * one we are asking for is not supported. + */ + vw.width = b->w; + vw.height = b->h; + vw.flags = fps << 16; + if (ioctl(fd, VIDIOCSWIN, &vw) == -1) { + ast_log(LOG_WARNING, "error setting format for %s [%s]\n", + dev, strerror(errno)); + goto error; + } + if (ioctl(fd, VIDIOCGPICT, &vp) == -1) { + ast_log(LOG_WARNING, "error reading picture info\n"); + goto error; + } + ast_log(LOG_WARNING, + "contrast %d bright %d colour %d hue %d white %d palette %d\n", + vp.contrast, vp.brightness, + vp.colour, vp.hue, + vp.whiteness, vp.palette); + /* set the video format. Here again, we don't necessary have to + * fail if the required format is not supported, but try to use + * what the camera gives us. + */ + b->pix_fmt = vp.palette; + vp.palette = VIDEO_PALETTE_YUV420P; + if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) { + ast_log(LOG_WARNING, "error setting palette, using %d\n", + b->pix_fmt); + } else + b->pix_fmt = vp.palette; + /* allocate the source buffer. + * XXX, the code here only handles yuv411, for other formats + * we need to look at pix_fmt and set size accordingly + */ + b->size = (b->w * b->h * 3)/2; /* yuv411 */ + ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n", + dev, b->w, b->h, b->size); + b->data = ast_calloc(1, b->size); + if (!b->data) { + ast_log(LOG_WARNING, "error allocating buffer %d bytes\n", + b->size); + goto error; + } + ast_log(LOG_WARNING, "success opening camera\n"); + return v; + +error: + close(v->fd); + fbuf_free(b); + ast_free(v); + return NULL; +} + +/*! \brief read until error, no data or buffer full. + * This might be blocking but no big deal since we are in the + * display thread. + */ +static struct fbuf_t *grab_v4l1_read(void *desc) +{ + struct grab_v4l1_desc *v = desc; + struct fbuf_t *b = &v->b; + for (;;) { + int r, l = b->size - b->used; + r = read(v->fd, b->data + b->used, l); + // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l); + if (r < 0) /* read error */ + break; + if (r == 0) /* no data */ + break; + b->used += r; + if (r == l) { + b->used = 0; /* prepare for next frame */ + return b; + } + } + return NULL; +} + +static void *grab_v4l1_close(void *desc) +{ + struct grab_v4l1_desc *v = desc; + + close(v->fd); + v->fd = -1; + fbuf_free(&v->b); + ast_free(v); + return NULL; +} + +/*! \brief our descriptor. We don't have .move */ +static struct grab_desc grab_v4l1_desc = { + .name = "v4l1", + .open = grab_v4l1_open, + .read = grab_v4l1_read, + .close = grab_v4l1_close, +}; +#endif /* HAVE_VIDEODEV_H */ + +/* + * Here you can add more grabbers, e.g. V4L2, firewire, + * a file, a still image... + */ + +/*! \brief The list of grabbers supported, with a NULL at the end */ +struct grab_desc *console_grabbers[] = { +#ifdef HAVE_X11 + &grab_x11_desc, +#endif +#ifdef HAVE_VIDEODEV_H + &grab_v4l1_desc, +#endif + NULL +}; + +#endif /* HAVE_VIDEO_CONSOLE */