Thu Jul 9 13:40:42 2009

Asterisk developer's documentation


vgrabbers.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright 2007, Luigi Rizzo 
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*
00018  * Video grabbers used in console_video.
00019  *
00020  * $Revision: 97656 $
00021  *
00022  * Each grabber is implemented through open/read/close calls,
00023  * plus an additional move() function used e.g. to change origin
00024  * for the X grabber (this may be extended in the future to support
00025  * more controls e.g. resolution changes etc.).
00026  *
00027  * open() should try to open and initialize the grabber, returning NULL on error.
00028  * On success it allocates a descriptor for its private data (including
00029  * a buffer for the video) and returns a pointer to the descriptor.
00030  * read() will return NULL on failure, or a pointer to a buffer with data
00031  * on success.
00032  * close() should release resources.
00033  * move() is optional.
00034  * For more details look at the X11 grabber below.
00035  *
00036  * NOTE: at the moment we expect uncompressed video frames in YUV format,
00037  * because this is what current sources supply and also is a convenient
00038  * format for display. It is conceivable that one might want to support
00039  * an already compressed stream, in which case we should redesign the
00040  * pipeline used for the local source, which at the moment is
00041  *
00042  *                        .->--[loc_dpy]
00043  *   [src]-->--[enc_in]--+
00044  *                        `->--[enc_out]
00045  */
00046 
00047 #include "asterisk.h"
00048 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 97656 $")
00049 #include <sys/ioctl.h>
00050 #include "asterisk/file.h"
00051 #include "asterisk/utils.h"   /* ast_calloc */
00052 
00053 #include "console_video.h"
00054 
00055 #if defined(HAVE_VIDEO_CONSOLE)
00056 
00057 #ifdef HAVE_X11
00058 
00059 /* A simple X11 grabber, supporting only truecolor formats */
00060 
00061 #include <X11/Xlib.h>
00062 
00063 /*! \brief internal info used by the X11 grabber */
00064 struct grab_x11_desc {
00065    Display     *dpy;
00066    XImage      *image;
00067    int      screen_width;  /* width of X screen */
00068    int      screen_height; /* height of X screen */
00069    struct fbuf_t  b;    /* geometry and pointer into the XImage */
00070 };
00071 
00072 /*! \brief open the grabber.
00073  * We use the special name 'X11' to indicate this grabber.
00074  */
00075 static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
00076 {
00077    XImage *im;
00078    int screen_num;
00079    struct grab_x11_desc *v;
00080    struct fbuf_t *b;
00081 
00082    if (strcasecmp(name, "X11"))
00083       return NULL;   /* not us */
00084    v = ast_calloc(1, sizeof(*v));
00085    if (v == NULL)
00086       return NULL;   /* no memory */
00087 
00088    /* init the connection with the X server */
00089    v->dpy = XOpenDisplay(NULL);
00090    if (v->dpy == NULL) {
00091       ast_log(LOG_WARNING, "error opening display\n");
00092       goto error;
00093    }
00094 
00095    v->b = *geom;  /* copy geometry */
00096    b = &v->b;  /* shorthand */
00097    /* find width and height of the screen */
00098    screen_num = DefaultScreen(v->dpy);
00099    v->screen_width = DisplayWidth(v->dpy, screen_num);
00100    v->screen_height = DisplayHeight(v->dpy, screen_num);
00101 
00102    v->image = im = XGetImage(v->dpy,
00103       RootWindow(v->dpy, DefaultScreen(v->dpy)),
00104       b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
00105    if (v->image == NULL) {
00106       ast_log(LOG_WARNING, "error creating Ximage\n");
00107       goto error;
00108    }
00109    switch (im->bits_per_pixel) {
00110    case 32:
00111       b->pix_fmt = PIX_FMT_RGBA32;
00112       break;
00113    case 16:
00114       b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
00115       break;
00116    }
00117 
00118    ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
00119       im->data,
00120       im->bits_per_pixel,
00121       b->pix_fmt,
00122       im->red_mask, im->green_mask, im->blue_mask);
00123 
00124    /* set the pointer but not the size as this is not malloc'ed */
00125    b->data = (uint8_t *)im->data;
00126    return v;
00127 
00128 error:
00129    /* XXX maybe XDestroy (v->image) ? */
00130    if (v->dpy)
00131       XCloseDisplay(v->dpy);
00132    v->dpy = NULL;
00133    ast_free(v);
00134    return NULL;
00135 }
00136 
00137 static struct fbuf_t *grab_x11_read(void *desc)
00138 {
00139    /* read frame from X11 */
00140    struct grab_x11_desc *v = desc;
00141    struct fbuf_t *b = &v->b;
00142 
00143    XGetSubImage(v->dpy,
00144       RootWindow(v->dpy, DefaultScreen(v->dpy)),
00145          b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
00146 
00147    b->data = (uint8_t *)v->image->data;
00148    return b;
00149 }
00150 
00151 static int boundary_checks(int x, int limit)
00152 {
00153         return (x <= 0) ? 0 : (x > limit ? limit : x);
00154 }
00155 
00156 /*! \brief move the origin for the grabbed area, making sure we do not
00157  * overflow the screen.
00158  */
00159 static void grab_x11_move(void *desc, int dx, int dy)
00160 {
00161    struct grab_x11_desc *v = desc;
00162 
00163         v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w);
00164         v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h);
00165 }
00166 
00167 /*! \brief disconnect from the server and release memory */
00168 static void *grab_x11_close(void *desc)
00169 {
00170    struct grab_x11_desc *v = desc;
00171 
00172    XCloseDisplay(v->dpy);
00173    v->dpy = NULL;
00174    v->image = NULL;
00175    ast_free(v);
00176    return NULL;
00177 }
00178 
00179 static struct grab_desc grab_x11_desc = {
00180    .name = "X11",
00181    .open = grab_x11_open,
00182    .read = grab_x11_read,
00183    .move = grab_x11_move,
00184    .close = grab_x11_close,
00185 };
00186 #endif   /* HAVE_X11 */
00187 
00188 #ifdef HAVE_VIDEODEV_H
00189 #include <linux/videodev.h>   /* Video4Linux stuff is only used in grab_v4l1_open() */
00190 
00191 struct grab_v4l1_desc {
00192    int fd;        /* device handle */
00193    struct fbuf_t  b; /* buffer (allocated) with grabbed image */
00194 };
00195 
00196 /*! \brief
00197  * Open the local video source and allocate a buffer
00198  * for storing the image.
00199  */
00200 static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
00201 {
00202    struct video_window vw = { 0 };  /* camera attributes */
00203    struct video_picture vp;
00204    int fd, i;
00205    struct grab_v4l1_desc *v;
00206    struct fbuf_t *b;
00207 
00208    fd = open(dev, O_RDONLY | O_NONBLOCK);
00209    if (fd < 0) {
00210       ast_log(LOG_WARNING, "error opening camera %s\n", dev);
00211       return NULL;
00212    }
00213 
00214    v = ast_calloc(1, sizeof(*v));
00215    if (v == NULL) {
00216       ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
00217       close(fd);
00218       return NULL;   /* no memory */
00219    }
00220    v->fd = fd;
00221    v->b = *geom;
00222    b = &v->b;  /* shorthand */
00223 
00224    i = fcntl(fd, F_GETFL);
00225    if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
00226       /* non fatal, just emit a warning */
00227       ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
00228          dev, strerror(errno));
00229    }
00230    /* set format for the camera.
00231     * In principle we could retry with a different format if the
00232     * one we are asking for is not supported.
00233     */
00234    vw.width = b->w;
00235    vw.height = b->h;
00236    vw.flags = fps << 16;
00237    if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
00238       ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
00239          dev, strerror(errno));
00240       goto error;
00241    }
00242    if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
00243       ast_log(LOG_WARNING, "error reading picture info\n");
00244       goto error;
00245    }
00246    ast_log(LOG_WARNING,
00247       "contrast %d bright %d colour %d hue %d white %d palette %d\n",
00248       vp.contrast, vp.brightness,
00249       vp.colour, vp.hue,
00250       vp.whiteness, vp.palette);
00251    /* set the video format. Here again, we don't necessary have to
00252     * fail if the required format is not supported, but try to use
00253     * what the camera gives us.
00254     */
00255    b->pix_fmt = vp.palette;
00256    vp.palette = VIDEO_PALETTE_YUV420P;
00257    if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
00258       ast_log(LOG_WARNING, "error setting palette, using %d\n",
00259          b->pix_fmt);
00260    } else
00261       b->pix_fmt = vp.palette;
00262    /* allocate the source buffer.
00263     * XXX, the code here only handles yuv411, for other formats
00264     * we need to look at pix_fmt and set size accordingly
00265     */
00266    b->size = (b->w * b->h * 3)/2;   /* yuv411 */
00267    ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
00268       dev, b->w, b->h, b->size);
00269    b->data = ast_calloc(1, b->size);
00270    if (!b->data) {
00271       ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
00272          b->size);
00273       goto error;
00274    }
00275    ast_log(LOG_WARNING, "success opening camera\n");
00276    return v;
00277 
00278 error:
00279    close(v->fd);
00280    fbuf_free(b);
00281    ast_free(v);
00282    return NULL;
00283 }
00284 
00285 /*! \brief read until error, no data or buffer full.
00286  * This might be blocking but no big deal since we are in the
00287  * display thread.
00288  */
00289 static struct fbuf_t *grab_v4l1_read(void *desc)
00290 {
00291    struct grab_v4l1_desc *v = desc;
00292    struct fbuf_t *b = &v->b;
00293    for (;;) {
00294       int r, l = b->size - b->used;
00295       r = read(v->fd, b->data + b->used, l);
00296       // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
00297       if (r < 0)  /* read error */
00298          break;
00299       if (r == 0) /* no data */
00300          break;
00301       b->used += r;
00302       if (r == l) {
00303          b->used = 0; /* prepare for next frame */
00304          return b;
00305       }
00306    }
00307    return NULL;
00308 }
00309 
00310 static void *grab_v4l1_close(void *desc)
00311 {
00312    struct grab_v4l1_desc *v = desc;
00313 
00314    close(v->fd);
00315    v->fd = -1;
00316    fbuf_free(&v->b);
00317    ast_free(v);
00318    return NULL;
00319 }
00320 
00321 /*! \brief our descriptor. We don't have .move */
00322 static struct grab_desc grab_v4l1_desc = {
00323    .name = "v4l1",
00324    .open = grab_v4l1_open,
00325    .read = grab_v4l1_read,
00326    .close = grab_v4l1_close,
00327 };
00328 #endif /* HAVE_VIDEODEV_H */
00329 
00330 /*
00331  * Here you can add more grabbers, e.g. V4L2, firewire,
00332  * a file, a still image...
00333  */
00334 
00335 /*! \brief The list of grabbers supported, with a NULL at the end */
00336 struct grab_desc *console_grabbers[] = {
00337 #ifdef HAVE_X11
00338    &grab_x11_desc,
00339 #endif
00340 #ifdef HAVE_VIDEODEV_H
00341    &grab_v4l1_desc,
00342 #endif
00343    NULL
00344 };
00345 
00346 #endif /* HAVE_VIDEO_CONSOLE */

Generated on Thu Jul 9 13:40:42 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7