Fri Aug 17 00:17:20 2018

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

Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1