2 * Asterisk -- An open source telephony toolkit.
4 * Copyright 2007, Luigi Rizzo
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
18 * Video grabbers used in console_video.
22 * Each grabber is implemented through open/read/close calls,
23 * plus an additional move() function used e.g. to change origin
24 * for the X grabber (this may be extended in the future to support
25 * more controls e.g. resolution changes etc.).
27 * open() should try to open and initialize the grabber, returning NULL on error.
28 * On success it allocates a descriptor for its private data (including
29 * a buffer for the video) and returns a pointer to the descriptor.
30 * read() will return NULL on failure, or a pointer to a buffer with data
32 * close() should release resources.
34 * For more details look at the X11 grabber below.
36 * NOTE: at the moment we expect uncompressed video frames in YUV format,
37 * because this is what current sources supply and also is a convenient
38 * format for display. It is conceivable that one might want to support
39 * an already compressed stream, in which case we should redesign the
40 * pipeline used for the local source, which at the moment is
43 * [src]-->--[enc_in]--+
48 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49 #include <sys/ioctl.h>
50 #include "asterisk/file.h"
51 #include "asterisk/utils.h" /* ast_calloc */
53 #include "console_video.h"
55 #if defined(HAVE_VIDEO_CONSOLE)
59 /* A simple X11 grabber, supporting only truecolor formats */
63 /*! \brief internal info used by the X11 grabber */
64 struct grab_x11_desc {
67 int screen_width; /* width of X screen */
68 int screen_height; /* height of X screen */
69 struct fbuf_t b; /* geometry and pointer into the XImage */
72 /*! \brief open the grabber.
73 * We use the special name 'X11' to indicate this grabber.
75 static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
79 struct grab_x11_desc *v;
82 /* all names starting with X11 identify this grabber */
83 if (strncasecmp(name, "X11", 3))
84 return NULL; /* not us */
85 v = ast_calloc(1, sizeof(*v));
87 return NULL; /* no memory */
89 /* init the connection with the X server */
90 v->dpy = XOpenDisplay(NULL);
92 ast_log(LOG_WARNING, "error opening display\n");
96 v->b = *geom; /* copy geometry */
97 b = &v->b; /* shorthand */
98 /* find width and height of the screen */
99 screen_num = DefaultScreen(v->dpy);
100 v->screen_width = DisplayWidth(v->dpy, screen_num);
101 v->screen_height = DisplayHeight(v->dpy, screen_num);
103 v->image = im = XGetImage(v->dpy,
104 RootWindow(v->dpy, DefaultScreen(v->dpy)),
105 b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
106 if (v->image == NULL) {
107 ast_log(LOG_WARNING, "error creating Ximage\n");
110 switch (im->bits_per_pixel) {
112 b->pix_fmt = PIX_FMT_RGBA32;
115 b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
119 ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
123 im->red_mask, im->green_mask, im->blue_mask);
125 /* set the pointer but not the size as this is not malloc'ed */
126 b->data = (uint8_t *)im->data;
130 /* XXX maybe XDestroy (v->image) ? */
132 XCloseDisplay(v->dpy);
138 static struct fbuf_t *grab_x11_read(void *desc)
140 /* read frame from X11 */
141 struct grab_x11_desc *v = desc;
142 struct fbuf_t *b = &v->b;
145 RootWindow(v->dpy, DefaultScreen(v->dpy)),
146 b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
148 b->data = (uint8_t *)v->image->data;
152 static int boundary_checks(int x, int limit)
154 return (x <= 0) ? 0 : (x > limit ? limit : x);
157 /*! \brief move the origin for the grabbed area, making sure we do not
158 * overflow the screen.
160 static void grab_x11_move(void *desc, int dx, int dy)
162 struct grab_x11_desc *v = desc;
164 v->b.x = boundary_checks(v->b.x + dx, v->screen_width - v->b.w);
165 v->b.y = boundary_checks(v->b.y + dy, v->screen_height - v->b.h);
168 /*! \brief disconnect from the server and release memory */
169 static void *grab_x11_close(void *desc)
171 struct grab_x11_desc *v = desc;
173 XCloseDisplay(v->dpy);
180 static struct grab_desc grab_x11_desc = {
182 .open = grab_x11_open,
183 .read = grab_x11_read,
184 .move = grab_x11_move,
185 .close = grab_x11_close,
187 #endif /* HAVE_X11 */
189 #ifdef HAVE_VIDEODEV_H
190 #include <linux/videodev.h> /* Video4Linux stuff is only used in grab_v4l1_open() */
192 struct grab_v4l1_desc {
193 int fd; /* device handle */
194 struct fbuf_t b; /* buffer (allocated) with grabbed image */
198 * Open the local video source and allocate a buffer
199 * for storing the image.
201 static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
203 struct video_window vw = { 0 }; /* camera attributes */
204 struct video_picture vp;
206 struct grab_v4l1_desc *v;
209 /* name should be something under /dev/ */
210 if (strncmp(dev, "/dev/", 5))
212 fd = open(dev, O_RDONLY | O_NONBLOCK);
214 ast_log(LOG_WARNING, "error opening camera %s\n", dev);
218 v = ast_calloc(1, sizeof(*v));
220 ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
222 return NULL; /* no memory */
226 b = &v->b; /* shorthand */
228 i = fcntl(fd, F_GETFL);
229 if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
230 /* non fatal, just emit a warning */
231 ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
232 dev, strerror(errno));
234 /* set format for the camera.
235 * In principle we could retry with a different format if the
236 * one we are asking for is not supported.
240 vw.flags = fps << 16;
241 if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
242 ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
243 dev, strerror(errno));
246 if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
247 ast_log(LOG_WARNING, "error reading picture info\n");
251 "contrast %d bright %d colour %d hue %d white %d palette %d\n",
252 vp.contrast, vp.brightness,
254 vp.whiteness, vp.palette);
255 /* set the video format. Here again, we don't necessary have to
256 * fail if the required format is not supported, but try to use
257 * what the camera gives us.
259 b->pix_fmt = vp.palette;
260 vp.palette = VIDEO_PALETTE_YUV420P;
261 if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
262 ast_log(LOG_WARNING, "error setting palette, using %d\n",
265 b->pix_fmt = vp.palette;
266 /* allocate the source buffer.
267 * XXX, the code here only handles yuv411, for other formats
268 * we need to look at pix_fmt and set size accordingly
270 b->size = (b->w * b->h * 3)/2; /* yuv411 */
271 ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
272 dev, b->w, b->h, b->size);
273 b->data = ast_calloc(1, b->size);
275 ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
279 ast_log(LOG_WARNING, "success opening camera\n");
289 /*! \brief read until error, no data or buffer full.
290 * This might be blocking but no big deal since we are in the
293 static struct fbuf_t *grab_v4l1_read(void *desc)
295 struct grab_v4l1_desc *v = desc;
296 struct fbuf_t *b = &v->b;
298 int r, l = b->size - b->used;
299 r = read(v->fd, b->data + b->used, l);
300 // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
301 if (r < 0) /* read error */
303 if (r == 0) /* no data */
307 b->used = 0; /* prepare for next frame */
314 static void *grab_v4l1_close(void *desc)
316 struct grab_v4l1_desc *v = desc;
325 /*! \brief our descriptor. We don't have .move */
326 static struct grab_desc grab_v4l1_desc = {
328 .open = grab_v4l1_open,
329 .read = grab_v4l1_read,
330 .close = grab_v4l1_close,
332 #endif /* HAVE_VIDEODEV_H */
335 * Here you can add more grabbers, e.g. V4L2, firewire,
336 * a file, a still image...
339 /*! \brief The list of grabbers supported, with a NULL at the end */
340 struct grab_desc *console_grabbers[] = {
344 #ifdef HAVE_VIDEODEV_H
350 #endif /* HAVE_VIDEO_CONSOLE */