Asterisk - The Open Source Telephony Project GIT-master-a358458
vgrabbers.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright 2007, Luigi Rizzo
5 *
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.
11 *
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.
15 */
16
17/*
18 * Video grabbers used in console_video.
19 *
20 * $Revision$
21 *
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.).
26 *
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
31 * on success.
32 * close() should release resources.
33 * move() is optional.
34 * For more details look at the X11 grabber below.
35 *
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
41 *
42 * .->--[loc_dpy]
43 * [src]-->--[enc_in]--+
44 * `->--[enc_out]
45 */
46
47/*** MODULEINFO
48 <support_level>extended</support_level>
49 ***/
50
51#include "asterisk.h"
52#include <sys/ioctl.h>
53#include "asterisk/file.h"
54#include "asterisk/utils.h" /* ast_calloc */
55
56#include "console_video.h"
57
58#if defined(HAVE_VIDEO_CONSOLE)
59
60#ifdef HAVE_X11
61
62/* A simple X11 grabber, supporting only truecolor formats */
63
64#include <X11/Xlib.h>
65
66/*! \brief internal info used by the X11 grabber */
67struct grab_x11_desc {
68 Display *dpy;
69 XImage *image;
70 int screen_width; /* width of X screen */
71 int screen_height; /* height of X screen */
72 struct fbuf_t b; /* geometry and pointer into the XImage */
73};
74
75static void *grab_x11_close(void *desc); /* forward declaration */
76
77/*! \brief open the grabber.
78 * We use the special name 'X11' to indicate this grabber.
79 */
80static void *grab_x11_open(const char *name, struct fbuf_t *geom, int fps)
81{
82 XImage *im;
83 int screen_num;
84 struct grab_x11_desc *v;
85 struct fbuf_t *b;
86
87 /* all names starting with X11 identify this grabber */
88 if (strncasecmp(name, "X11", 3))
89 return NULL; /* not us */
90 v = ast_calloc(1, sizeof(*v));
91 if (v == NULL)
92 return NULL; /* no memory */
93
94 /* init the connection with the X server */
95 v->dpy = XOpenDisplay(NULL);
96 if (v->dpy == NULL) {
97 ast_log(LOG_WARNING, "error opening display\n");
98 goto error;
99 }
100
101 v->b = *geom; /* copy geometry */
102 b = &v->b; /* shorthand */
103 /* find width and height of the screen */
104 screen_num = DefaultScreen(v->dpy);
105 v->screen_width = DisplayWidth(v->dpy, screen_num);
106 v->screen_height = DisplayHeight(v->dpy, screen_num);
107
108 v->image = im = XGetImage(v->dpy,
109 RootWindow(v->dpy, DefaultScreen(v->dpy)),
110 b->x, b->y, b->w, b->h, AllPlanes, ZPixmap);
111 if (v->image == NULL) {
112 ast_log(LOG_WARNING, "error creating Ximage\n");
113 goto error;
114 }
115 switch (im->bits_per_pixel) {
116 case 32:
117 b->pix_fmt = PIX_FMT_RGBA32;
118 break;
119 case 16:
120 b->pix_fmt = (im->green_mask == 0x7e0) ? PIX_FMT_RGB565 : PIX_FMT_RGB555;
121 break;
122 }
123
124 ast_log(LOG_NOTICE, "image: data %p %d bpp fmt %d, mask 0x%lx 0x%lx 0x%lx\n",
125 im->data,
126 im->bits_per_pixel,
127 b->pix_fmt,
128 im->red_mask, im->green_mask, im->blue_mask);
129
130 /* set the pointer but not the size as this is not malloc'ed */
131 b->data = (uint8_t *)im->data;
132 return v;
133
134error:
135 return grab_x11_close(v);
136}
137
138static struct fbuf_t *grab_x11_read(void *desc)
139{
140 /* read frame from X11 */
141 struct grab_x11_desc *v = desc;
142 struct fbuf_t *b = &v->b;
143
144 XGetSubImage(v->dpy,
145 RootWindow(v->dpy, DefaultScreen(v->dpy)),
146 b->x, b->y, b->w, b->h, AllPlanes, ZPixmap, v->image, 0, 0);
147
148 b->data = (uint8_t *)v->image->data;
149 return b;
150}
151
152static int boundary_checks(int x, int limit)
153{
154 return (x <= 0) ? 0 : (x > limit ? limit : x);
155}
156
157/*! \brief move the origin for the grabbed area, making sure we do not
158 * overflow the screen.
159 */
160static void grab_x11_move(void *desc, int dx, int dy)
161{
162 struct grab_x11_desc *v = desc;
163
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);
166}
167
168/*! \brief disconnect from the server and release memory */
169static void *grab_x11_close(void *desc)
170{
171 struct grab_x11_desc *v = desc;
172
173 if (v->dpy)
174 XCloseDisplay(v->dpy);
175 v->dpy = NULL;
176 v->image = NULL;
177 ast_free(v);
178 return NULL;
179}
180
181static struct grab_desc grab_x11_desc = {
182 .name = "X11",
183 .open = grab_x11_open,
184 .read = grab_x11_read,
185 .move = grab_x11_move,
186 .close = grab_x11_close,
187};
188#endif /* HAVE_X11 */
189
190#ifdef HAVE_VIDEODEV_H
191#include <linux/videodev.h> /* Video4Linux stuff is only used in grab_v4l1_open() */
192
193struct grab_v4l1_desc {
194 int fd; /* device handle */
195 struct fbuf_t b; /* buffer (allocated) with grabbed image */
196};
197
198/*! \brief
199 * Open the local video source and allocate a buffer
200 * for storing the image.
201 */
202static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
203{
204 struct video_window vw = { 0 }; /* camera attributes */
205 struct video_picture vp;
206 int fd, i;
207 struct grab_v4l1_desc *v;
208 struct fbuf_t *b;
209
210 /* name should be something under /dev/ */
211 if (strncmp(dev, "/dev/", 5))
212 return NULL;
213 fd = open(dev, O_RDONLY | O_NONBLOCK);
214 if (fd < 0) {
215 ast_log(LOG_WARNING, "error opening camera %s\n", dev);
216 return NULL;
217 }
218
219 v = ast_calloc(1, sizeof(*v));
220 if (v == NULL) {
221 ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
222 close(fd);
223 return NULL; /* no memory */
224 }
225 v->fd = fd;
226 v->b = *geom;
227 b = &v->b; /* shorthand */
228
229 ast_fd_set_flags(fd, O_NONBLOCK);
230
231 /* set format for the camera.
232 * In principle we could retry with a different format if the
233 * one we are asking for is not supported.
234 */
235 vw.width = b->w;
236 vw.height = b->h;
237 vw.flags = fps << 16;
238 if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
239 ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
240 dev, strerror(errno));
241 goto error;
242 }
243 if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
244 ast_log(LOG_WARNING, "error reading picture info\n");
245 goto error;
246 }
248 "contrast %d bright %d colour %d hue %d white %d palette %d\n",
249 vp.contrast, vp.brightness,
250 vp.colour, vp.hue,
251 vp.whiteness, vp.palette);
252 /* set the video format. Here again, we don't necessary have to
253 * fail if the required format is not supported, but try to use
254 * what the camera gives us.
255 */
256 b->pix_fmt = vp.palette;
257 vp.palette = VIDEO_PALETTE_YUV420P;
258 if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
259 ast_log(LOG_WARNING, "error setting palette, using %d\n",
260 b->pix_fmt);
261 } else
262 b->pix_fmt = vp.palette;
263 /* allocate the source buffer.
264 * XXX, the code here only handles yuv411, for other formats
265 * we need to look at pix_fmt and set size accordingly
266 */
267 b->size = (b->w * b->h * 3)/2; /* yuv411 */
268 ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
269 dev, b->w, b->h, b->size);
270 b->data = ast_calloc(1, b->size);
271 if (!b->data) {
272 ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
273 b->size);
274 goto error;
275 }
276 ast_log(LOG_WARNING, "success opening camera\n");
277 return v;
278
279error:
280 close(v->fd);
281 fbuf_free(b);
282 ast_free(v);
283 return NULL;
284}
285
286/*! \brief read until error, no data or buffer full.
287 * This might be blocking but no big deal since we are in the
288 * display thread.
289 */
290static struct fbuf_t *grab_v4l1_read(void *desc)
291{
292 struct grab_v4l1_desc *v = desc;
293 struct fbuf_t *b = &v->b;
294 for (;;) {
295 int r, l = b->size - b->used;
296 r = read(v->fd, b->data + b->used, l);
297 // ast_log(LOG_WARNING, "read %d of %d bytes from webcam\n", r, l);
298 if (r < 0) /* read error */
299 break;
300 if (r == 0) /* no data */
301 break;
302 b->used += r;
303 if (r == l) {
304 b->used = 0; /* prepare for next frame */
305 return b;
306 }
307 }
308 return NULL;
309}
310
311static void *grab_v4l1_close(void *desc)
312{
313 struct grab_v4l1_desc *v = desc;
314
315 close(v->fd);
316 v->fd = -1;
317 fbuf_free(&v->b);
318 ast_free(v);
319 return NULL;
320}
321
322/*! \brief our descriptor. We don't have .move */
323static struct grab_desc grab_v4l1_desc = {
324 .name = "v4l1",
325 .open = grab_v4l1_open,
326 .read = grab_v4l1_read,
327 .close = grab_v4l1_close,
328};
329#endif /* HAVE_VIDEODEV_H */
330
331/*
332 * Here you can add more grabbers, e.g. V4L2, firewire,
333 * a file, a still image...
334 */
335
336/*! \brief The list of grabbers supported, with a NULL at the end */
337struct grab_desc *console_grabbers[] = {
338#ifdef HAVE_X11
339 &grab_x11_desc,
340#endif
341#ifdef HAVE_VIDEODEV_H
342 &grab_v4l1_desc,
343#endif
344 NULL
345};
346
347#endif /* HAVE_VIDEO_CONSOLE */
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static const char desc[]
Definition: cdr_radius.c:84
struct grab_desc * console_grabbers[]
void fbuf_free(struct fbuf_t *)
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
#define LOG_NOTICE
#define LOG_WARNING
int errno
#define NULL
Definition: resample.c:96
const char * name
Definition: console_video.h:81
static struct test_val b
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1039