123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- * 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"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include <sys/ioctl.h>
- #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 <X11/Xlib.h>
- /*! \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 */
- };
- static void *grab_x11_close(void *desc); /* forward declaration */
- /*! \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;
- /* all names starting with X11 identify this grabber */
- if (strncasecmp(name, "X11", 3))
- 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:
- return grab_x11_close(v);
- }
- 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;
- if (v->dpy)
- 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 <linux/videodev.h> /* 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;
- /* name should be something under /dev/ */
- if (strncmp(dev, "/dev/", 5))
- return NULL;
- 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 */
|