Fri Jul 24 00:41:06 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: 130733 $
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: 130733 $")
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 static void *grab_x11_close(void *desc);  /* forward declaration */
00073 
00074 /*! \brief open the grabber.
00075  * We use the special name 'X11' to indicate this grabber.
00076  */
00077 static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
00078 {
00079    XImage *im;
00080    int screen_num;
00081    struct grab_x11_desc *v;
00082    struct fbuf_t *b;
00083 
00084    /* all names starting with X11 identify this grabber */
00085    if (strncasecmp(name, "X11", 3))
00086       return NULL;   /* not us */
00087    v = ast_calloc(1, sizeof(*v));
00088    if (v == NULL)
00089       return NULL;   /* no memory */
00090 
00091    /* init the connection with the X server */
00092    v->dpy = XOpenDisplay(NULL);
00093    if (v->dpy == NULL) {
00094       ast_log(LOG_WARNING, "error opening display\n");
00095       goto error;
00096    }
00097 
00098    v->b = *geom;  /* copy geometry */
00099    b = &v->b;  /* shorthand */
00100    /* find width and height of the screen */
00101    screen_num = DefaultScreen(v->dpy);
00102    v->screen_width = DisplayWidth(v->dpy, screen_num);
00103    v->screen_height = DisplayHeight(v->dpy, screen_num);
00104 
00105    v->image = im = XGetImage(v->dpy,
00106       RootWindow(v->dpy, DefaultScreen(v->dpy)),
00107       b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
00108    if (v->image == NULL) {
00109       ast_log(LOG_WARNING, "error creating Ximage\n");
00110       goto error;
00111    }
00112    switch (im->bits_per_pixel) {
00113    case 32:
00114       b->pix_fmt = PIX_FMT_RGBA32;
00115       break;
00116    case 16:
00117       b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
00118       break;
00119    }
00120 
00121    ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
00122       im->data,
00123       im->bits_per_pixel,
00124       b->pix_fmt,
00125       im->red_mask, im->green_mask, im->blue_mask);
00126 
00127    /* set the pointer but not the size as this is not malloc'ed */
00128    b->data = (uint8_t *)im->data;
00129    return v;
00130 
00131 error:
00132    return grab_x11_close(v);
00133 }
00134 
00135 static struct fbuf_t *grab_x11_read(void *desc)
00136 {
00137    /* read frame from X11 */
00138    struct grab_x11_desc *v = desc;
00139    struct fbuf_t *b = &v->b;
00140 
00141    XGetSubImage(v->dpy,
00142       RootWindow(v->dpy, DefaultScreen(v->dpy)),
00143          b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
00144 
00145    b->data = (uint8_t *)v->image->data;
00146    return b;
00147 }
00148 
00149 static int boundary_checks(int x, int limit)
00150 {
00151         return (x <= 0) ? 0 : (x > limit ? limit : x);
00152 }
00153 
00154 /*! \brief move the origin for the grabbed area, making sure we do not
00155  * overflow the screen.
00156  */
00157 static void grab_x11_move(void *desc, int dx, int dy)
00158 {
00159    struct grab_x11_desc *v = desc;
00160 
00161         v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w);
00162         v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h);
00163 }
00164 
00165 /*! \brief disconnect from the server and release memory */
00166 static void *grab_x11_close(void *desc)
00167 {
00168    struct grab_x11_desc *v = desc;
00169 
00170    if (v->dpy)
00171       XCloseDisplay(v->dpy);
00172    v->dpy = NULL;
00173    v->image = NULL;
00174    ast_free(v);
00175    return NULL;
00176 }
00177 
00178 static struct grab_desc grab_x11_desc = {
00179    .name = "X11",
00180    .open = grab_x11_open,
00181    .read = grab_x11_read,
00182    .move = grab_x11_move,
00183    .close = grab_x11_close,
00184 };
00185 #endif   /* HAVE_X11 */
00186 
00187 #ifdef HAVE_VIDEODEV_H
00188 #include <linux/videodev.h>   /* Video4Linux stuff is only used in grab_v4l1_open() */
00189 
00190 struct grab_v4l1_desc {
00191    int fd;        /* device handle */
00192    struct fbuf_t  b; /* buffer (allocated) with grabbed image */
00193 };
00194 
00195 /*! \brief
00196  * Open the local video source and allocate a buffer
00197  * for storing the image.
00198  */
00199 static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
00200 {
00201    struct video_window vw = { 0 };  /* camera attributes */
00202    struct video_picture vp;
00203    int fd, i;
00204    struct grab_v4l1_desc *v;
00205    struct fbuf_t *b;
00206 
00207    /* name should be something under /dev/ */
00208    if (strncmp(dev, "/dev/", 5)) 
00209       return NULL;
00210    fd = open(dev, O_RDONLY | O_NONBLOCK);
00211    if (fd < 0) {
00212       ast_log(LOG_WARNING, "error opening camera %s\n", dev);
00213       return NULL;
00214    }
00215 
00216    v = ast_calloc(1, sizeof(*v));
00217    if (v == NULL) {
00218       ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
00219       close(fd);
00220       return NULL;   /* no memory */
00221    }
00222    v->fd = fd;
00223    v->b = *geom;
00224    b = &v->b;  /* shorthand */
00225 
00226    i = fcntl(fd, F_GETFL);
00227    if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
00228       /* non fatal, just emit a warning */
00229       ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
00230          dev, strerror(errno));
00231    }
00232    /* set format for the camera.
00233     * In principle we could retry with a different format if the
00234     * one we are asking for is not supported.
00235     */
00236    vw.width = b->w;
00237    vw.height = b->h;
00238    vw.flags = fps << 16;
00239    if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
00240       ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
00241          dev, strerror(errno));
00242       goto error;
00243    }
00244    if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
00245       ast_log(LOG_WARNING, "error reading picture info\n");
00246       goto error;
00247    }
00248    ast_log(LOG_WARNING,
00249       "contrast %d bright %d colour %d hue %d white %d palette %d\n",
00250       vp.contrast, vp.brightness,
00251       vp.colour, vp.hue,
00252       vp.whiteness, vp.palette);
00253    /* set the video format. Here again, we don't necessary have to
00254     * fail if the required format is not supported, but try to use
00255     * what the camera gives us.
00256     */
00257    b->pix_fmt = vp.palette;
00258    vp.palette = VIDEO_PALETTE_YUV420P;
00259    if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
00260       ast_log(LOG_WARNING, "error setting palette, using %d\n",
00261          b->pix_fmt);
00262    } else
00263       b->pix_fmt = vp.palette;
00264    /* allocate the source buffer.
00265     * XXX, the code here only handles yuv411, for other formats
00266     * we need to look at pix_fmt and set size accordingly
00267     */
00268    b->size = (b->w * b->h * 3)/2;   /* yuv411 */
00269    ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
00270       dev, b->w, b->h, b->size);
00271    b->data = ast_calloc(1, b->size);
00272    if (!b->data) {
00273       ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
00274          b->size);
00275       goto error;
00276    }
00277    ast_log(LOG_WARNING, "success opening camera\n");
00278    return v;
00279 
00280 error:
00281    close(v->fd);
00282    fbuf_free(b);
00283    ast_free(v);
00284    return NULL;
00285 }
00286 
00287 /*! \brief read until error, no data or buffer full.
00288  * This might be blocking but no big deal since we are in the
00289  * display thread.
00290  */
00291 static struct fbuf_t *grab_v4l1_read(void *desc)
00292 {
00293    struct grab_v4l1_desc *v = desc;
00294    struct fbuf_t *b = &v->b;
00295    for (;;) {
00296       int r, l = b->size - b->used;
00297       r = read(v->fd, b->data + b->used, l);
00298       // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
00299       if (r < 0)  /* read error */
00300          break;
00301       if (r == 0) /* no data */
00302          break;
00303       b->used += r;
00304       if (r == l) {
00305          b->used = 0; /* prepare for next frame */
00306          return b;
00307       }
00308    }
00309    return NULL;
00310 }
00311 
00312 static void *grab_v4l1_close(void *desc)
00313 {
00314    struct grab_v4l1_desc *v = desc;
00315 
00316    close(v->fd);
00317    v->fd = -1;
00318    fbuf_free(&v->b);
00319    ast_free(v);
00320    return NULL;
00321 }
00322 
00323 /*! \brief our descriptor. We don't have .move */
00324 static struct grab_desc grab_v4l1_desc = {
00325    .name = "v4l1",
00326    .open = grab_v4l1_open,
00327    .read = grab_v4l1_read,
00328    .close = grab_v4l1_close,
00329 };
00330 #endif /* HAVE_VIDEODEV_H */
00331 
00332 /*
00333  * Here you can add more grabbers, e.g. V4L2, firewire,
00334  * a file, a still image...
00335  */
00336 
00337 /*! \brief The list of grabbers supported, with a NULL at the end */
00338 struct grab_desc *console_grabbers[] = {
00339 #ifdef HAVE_X11
00340    &grab_x11_desc,
00341 #endif
00342 #ifdef HAVE_VIDEODEV_H
00343    &grab_v4l1_desc,
00344 #endif
00345    NULL
00346 };
00347 
00348 #endif /* HAVE_VIDEO_CONSOLE */

Generated on Fri Jul 24 00:41:06 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7