yading@10
|
1 /*
|
yading@10
|
2 * X11 video grab interface
|
yading@10
|
3 *
|
yading@10
|
4 * This file is part of FFmpeg.
|
yading@10
|
5 *
|
yading@10
|
6 * FFmpeg integration:
|
yading@10
|
7 * Copyright (C) 2006 Clemens Fruhwirth <clemens@endorphin.org>
|
yading@10
|
8 * Edouard Gomez <ed.gomez@free.fr>
|
yading@10
|
9 *
|
yading@10
|
10 * This file contains code from grab.c:
|
yading@10
|
11 * Copyright (c) 2000-2001 Fabrice Bellard
|
yading@10
|
12 *
|
yading@10
|
13 * This file contains code from the xvidcap project:
|
yading@10
|
14 * Copyright (C) 1997-1998 Rasca, Berlin
|
yading@10
|
15 * 2003-2004 Karl H. Beckers, Frankfurt
|
yading@10
|
16 *
|
yading@10
|
17 * FFmpeg is free software; you can redistribute it and/or modify
|
yading@10
|
18 * it under the terms of the GNU General Public License as published by
|
yading@10
|
19 * the Free Software Foundation; either version 2 of the License, or
|
yading@10
|
20 * (at your option) any later version.
|
yading@10
|
21 *
|
yading@10
|
22 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
yading@10
|
25 * GNU General Public License for more details.
|
yading@10
|
26 *
|
yading@10
|
27 * You should have received a copy of the GNU General Public License
|
yading@10
|
28 * along with FFmpeg; if not, write to the Free Software
|
yading@10
|
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
30 */
|
yading@10
|
31
|
yading@10
|
32 /**
|
yading@10
|
33 * @file
|
yading@10
|
34 * X11 frame device demuxer
|
yading@10
|
35 * @author Clemens Fruhwirth <clemens@endorphin.org>
|
yading@10
|
36 * @author Edouard Gomez <ed.gomez@free.fr>
|
yading@10
|
37 */
|
yading@10
|
38
|
yading@10
|
39 #include "config.h"
|
yading@10
|
40 #include "libavformat/internal.h"
|
yading@10
|
41 #include "libavutil/log.h"
|
yading@10
|
42 #include "libavutil/opt.h"
|
yading@10
|
43 #include "libavutil/parseutils.h"
|
yading@10
|
44 #include "libavutil/time.h"
|
yading@10
|
45 #include <time.h>
|
yading@10
|
46 #include <X11/cursorfont.h>
|
yading@10
|
47 #include <X11/X.h>
|
yading@10
|
48 #include <X11/Xlib.h>
|
yading@10
|
49 #include <X11/Xlibint.h>
|
yading@10
|
50 #include <X11/Xproto.h>
|
yading@10
|
51 #include <X11/Xutil.h>
|
yading@10
|
52 #include <sys/shm.h>
|
yading@10
|
53 #include <X11/extensions/shape.h>
|
yading@10
|
54 #include <X11/extensions/XShm.h>
|
yading@10
|
55 #include <X11/extensions/Xfixes.h>
|
yading@10
|
56 #include "avdevice.h"
|
yading@10
|
57
|
yading@10
|
58 /**
|
yading@10
|
59 * X11 Device Demuxer context
|
yading@10
|
60 */
|
yading@10
|
61 struct x11grab {
|
yading@10
|
62 const AVClass *class; /**< Class for private options. */
|
yading@10
|
63 int frame_size; /**< Size in bytes of a grabbed frame */
|
yading@10
|
64 AVRational time_base; /**< Time base */
|
yading@10
|
65 int64_t time_frame; /**< Current time */
|
yading@10
|
66
|
yading@10
|
67 int width; /**< Width of the grab frame */
|
yading@10
|
68 int height; /**< Height of the grab frame */
|
yading@10
|
69 int x_off; /**< Horizontal top-left corner coordinate */
|
yading@10
|
70 int y_off; /**< Vertical top-left corner coordinate */
|
yading@10
|
71
|
yading@10
|
72 Display *dpy; /**< X11 display from which x11grab grabs frames */
|
yading@10
|
73 XImage *image; /**< X11 image holding the grab */
|
yading@10
|
74 int use_shm; /**< !0 when using XShm extension */
|
yading@10
|
75 XShmSegmentInfo shminfo; /**< When using XShm, keeps track of XShm infos */
|
yading@10
|
76 int draw_mouse; /**< Set by a private option. */
|
yading@10
|
77 int follow_mouse; /**< Set by a private option. */
|
yading@10
|
78 int show_region; /**< set by a private option. */
|
yading@10
|
79 char *framerate; /**< Set by a private option. */
|
yading@10
|
80
|
yading@10
|
81 Window region_win; /**< This is used by show_region option. */
|
yading@10
|
82 };
|
yading@10
|
83
|
yading@10
|
84 #define REGION_WIN_BORDER 3
|
yading@10
|
85 /**
|
yading@10
|
86 * Draw grabbing region window
|
yading@10
|
87 *
|
yading@10
|
88 * @param s x11grab context
|
yading@10
|
89 */
|
yading@10
|
90 static void
|
yading@10
|
91 x11grab_draw_region_win(struct x11grab *s)
|
yading@10
|
92 {
|
yading@10
|
93 Display *dpy = s->dpy;
|
yading@10
|
94 int screen;
|
yading@10
|
95 Window win = s->region_win;
|
yading@10
|
96 GC gc;
|
yading@10
|
97
|
yading@10
|
98 screen = DefaultScreen(dpy);
|
yading@10
|
99 gc = XCreateGC(dpy, win, 0, 0);
|
yading@10
|
100 XSetForeground(dpy, gc, WhitePixel(dpy, screen));
|
yading@10
|
101 XSetBackground(dpy, gc, BlackPixel(dpy, screen));
|
yading@10
|
102 XSetLineAttributes(dpy, gc, REGION_WIN_BORDER, LineDoubleDash, 0, 0);
|
yading@10
|
103 XDrawRectangle(dpy, win, gc,
|
yading@10
|
104 1, 1,
|
yading@10
|
105 (s->width + REGION_WIN_BORDER * 2) - 1 * 2 - 1,
|
yading@10
|
106 (s->height + REGION_WIN_BORDER * 2) - 1 * 2 - 1);
|
yading@10
|
107 XFreeGC(dpy, gc);
|
yading@10
|
108 }
|
yading@10
|
109
|
yading@10
|
110 /**
|
yading@10
|
111 * Initialize grabbing region window
|
yading@10
|
112 *
|
yading@10
|
113 * @param s x11grab context
|
yading@10
|
114 */
|
yading@10
|
115 static void
|
yading@10
|
116 x11grab_region_win_init(struct x11grab *s)
|
yading@10
|
117 {
|
yading@10
|
118 Display *dpy = s->dpy;
|
yading@10
|
119 int screen;
|
yading@10
|
120 XSetWindowAttributes attribs;
|
yading@10
|
121 XRectangle rect;
|
yading@10
|
122
|
yading@10
|
123 screen = DefaultScreen(dpy);
|
yading@10
|
124 attribs.override_redirect = True;
|
yading@10
|
125 s->region_win = XCreateWindow(dpy, RootWindow(dpy, screen),
|
yading@10
|
126 s->x_off - REGION_WIN_BORDER,
|
yading@10
|
127 s->y_off - REGION_WIN_BORDER,
|
yading@10
|
128 s->width + REGION_WIN_BORDER * 2,
|
yading@10
|
129 s->height + REGION_WIN_BORDER * 2,
|
yading@10
|
130 0, CopyFromParent,
|
yading@10
|
131 InputOutput, CopyFromParent,
|
yading@10
|
132 CWOverrideRedirect, &attribs);
|
yading@10
|
133 rect.x = 0;
|
yading@10
|
134 rect.y = 0;
|
yading@10
|
135 rect.width = s->width;
|
yading@10
|
136 rect.height = s->height;
|
yading@10
|
137 XShapeCombineRectangles(dpy, s->region_win,
|
yading@10
|
138 ShapeBounding, REGION_WIN_BORDER, REGION_WIN_BORDER,
|
yading@10
|
139 &rect, 1, ShapeSubtract, 0);
|
yading@10
|
140 XMapWindow(dpy, s->region_win);
|
yading@10
|
141 XSelectInput(dpy, s->region_win, ExposureMask | StructureNotifyMask);
|
yading@10
|
142 x11grab_draw_region_win(s);
|
yading@10
|
143 }
|
yading@10
|
144
|
yading@10
|
145 /**
|
yading@10
|
146 * Initialize the x11 grab device demuxer (public device demuxer API).
|
yading@10
|
147 *
|
yading@10
|
148 * @param s1 Context from avformat core
|
yading@10
|
149 * @return <ul>
|
yading@10
|
150 * <li>AVERROR(ENOMEM) no memory left</li>
|
yading@10
|
151 * <li>AVERROR(EIO) other failure case</li>
|
yading@10
|
152 * <li>0 success</li>
|
yading@10
|
153 * </ul>
|
yading@10
|
154 */
|
yading@10
|
155 static int
|
yading@10
|
156 x11grab_read_header(AVFormatContext *s1)
|
yading@10
|
157 {
|
yading@10
|
158 struct x11grab *x11grab = s1->priv_data;
|
yading@10
|
159 Display *dpy;
|
yading@10
|
160 AVStream *st = NULL;
|
yading@10
|
161 enum AVPixelFormat input_pixfmt;
|
yading@10
|
162 XImage *image;
|
yading@10
|
163 int x_off = 0;
|
yading@10
|
164 int y_off = 0;
|
yading@10
|
165 int screen;
|
yading@10
|
166 int use_shm;
|
yading@10
|
167 char *dpyname, *offset;
|
yading@10
|
168 int ret = 0;
|
yading@10
|
169 AVRational framerate;
|
yading@10
|
170
|
yading@10
|
171 dpyname = av_strdup(s1->filename);
|
yading@10
|
172 if (!dpyname)
|
yading@10
|
173 goto out;
|
yading@10
|
174
|
yading@10
|
175 offset = strchr(dpyname, '+');
|
yading@10
|
176 if (offset) {
|
yading@10
|
177 sscanf(offset, "%d,%d", &x_off, &y_off);
|
yading@10
|
178 if (strstr(offset, "nomouse")) {
|
yading@10
|
179 av_log(s1, AV_LOG_WARNING,
|
yading@10
|
180 "'nomouse' specification in argument is deprecated: "
|
yading@10
|
181 "use 'draw_mouse' option with value 0 instead\n");
|
yading@10
|
182 x11grab->draw_mouse = 0;
|
yading@10
|
183 }
|
yading@10
|
184 *offset= 0;
|
yading@10
|
185 }
|
yading@10
|
186
|
yading@10
|
187 if ((ret = av_parse_video_rate(&framerate, x11grab->framerate)) < 0) {
|
yading@10
|
188 av_log(s1, AV_LOG_ERROR, "Could not parse framerate: %s.\n", x11grab->framerate);
|
yading@10
|
189 goto out;
|
yading@10
|
190 }
|
yading@10
|
191 av_log(s1, AV_LOG_INFO, "device: %s -> display: %s x: %d y: %d width: %d height: %d\n",
|
yading@10
|
192 s1->filename, dpyname, x_off, y_off, x11grab->width, x11grab->height);
|
yading@10
|
193
|
yading@10
|
194 dpy = XOpenDisplay(dpyname);
|
yading@10
|
195 av_freep(&dpyname);
|
yading@10
|
196 if(!dpy) {
|
yading@10
|
197 av_log(s1, AV_LOG_ERROR, "Could not open X display.\n");
|
yading@10
|
198 ret = AVERROR(EIO);
|
yading@10
|
199 goto out;
|
yading@10
|
200 }
|
yading@10
|
201
|
yading@10
|
202 st = avformat_new_stream(s1, NULL);
|
yading@10
|
203 if (!st) {
|
yading@10
|
204 ret = AVERROR(ENOMEM);
|
yading@10
|
205 goto out;
|
yading@10
|
206 }
|
yading@10
|
207 avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
|
yading@10
|
208
|
yading@10
|
209 screen = DefaultScreen(dpy);
|
yading@10
|
210
|
yading@10
|
211 if (x11grab->follow_mouse) {
|
yading@10
|
212 int screen_w, screen_h;
|
yading@10
|
213 Window w;
|
yading@10
|
214
|
yading@10
|
215 screen_w = DisplayWidth(dpy, screen);
|
yading@10
|
216 screen_h = DisplayHeight(dpy, screen);
|
yading@10
|
217 XQueryPointer(dpy, RootWindow(dpy, screen), &w, &w, &x_off, &y_off, &ret, &ret, &ret);
|
yading@10
|
218 x_off -= x11grab->width / 2;
|
yading@10
|
219 y_off -= x11grab->height / 2;
|
yading@10
|
220 x_off = FFMIN(FFMAX(x_off, 0), screen_w - x11grab->width);
|
yading@10
|
221 y_off = FFMIN(FFMAX(y_off, 0), screen_h - x11grab->height);
|
yading@10
|
222 av_log(s1, AV_LOG_INFO, "followmouse is enabled, resetting grabbing region to x: %d y: %d\n", x_off, y_off);
|
yading@10
|
223 }
|
yading@10
|
224
|
yading@10
|
225 use_shm = XShmQueryExtension(dpy);
|
yading@10
|
226 av_log(s1, AV_LOG_INFO, "shared memory extension%s found\n", use_shm ? "" : " not");
|
yading@10
|
227
|
yading@10
|
228 if(use_shm) {
|
yading@10
|
229 int scr = XDefaultScreen(dpy);
|
yading@10
|
230 image = XShmCreateImage(dpy,
|
yading@10
|
231 DefaultVisual(dpy, scr),
|
yading@10
|
232 DefaultDepth(dpy, scr),
|
yading@10
|
233 ZPixmap,
|
yading@10
|
234 NULL,
|
yading@10
|
235 &x11grab->shminfo,
|
yading@10
|
236 x11grab->width, x11grab->height);
|
yading@10
|
237 x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
|
yading@10
|
238 image->bytes_per_line * image->height,
|
yading@10
|
239 IPC_CREAT|0777);
|
yading@10
|
240 if (x11grab->shminfo.shmid == -1) {
|
yading@10
|
241 av_log(s1, AV_LOG_ERROR, "Fatal: Can't get shared memory!\n");
|
yading@10
|
242 ret = AVERROR(ENOMEM);
|
yading@10
|
243 goto out;
|
yading@10
|
244 }
|
yading@10
|
245 x11grab->shminfo.shmaddr = image->data = shmat(x11grab->shminfo.shmid, 0, 0);
|
yading@10
|
246 x11grab->shminfo.readOnly = False;
|
yading@10
|
247
|
yading@10
|
248 if (!XShmAttach(dpy, &x11grab->shminfo)) {
|
yading@10
|
249 av_log(s1, AV_LOG_ERROR, "Fatal: Failed to attach shared memory!\n");
|
yading@10
|
250 /* needs some better error subroutine :) */
|
yading@10
|
251 ret = AVERROR(EIO);
|
yading@10
|
252 goto out;
|
yading@10
|
253 }
|
yading@10
|
254 } else {
|
yading@10
|
255 image = XGetImage(dpy, RootWindow(dpy, screen),
|
yading@10
|
256 x_off,y_off,
|
yading@10
|
257 x11grab->width, x11grab->height,
|
yading@10
|
258 AllPlanes, ZPixmap);
|
yading@10
|
259 }
|
yading@10
|
260
|
yading@10
|
261 switch (image->bits_per_pixel) {
|
yading@10
|
262 case 8:
|
yading@10
|
263 av_log (s1, AV_LOG_DEBUG, "8 bit palette\n");
|
yading@10
|
264 input_pixfmt = AV_PIX_FMT_PAL8;
|
yading@10
|
265 break;
|
yading@10
|
266 case 16:
|
yading@10
|
267 if ( image->red_mask == 0xf800 &&
|
yading@10
|
268 image->green_mask == 0x07e0 &&
|
yading@10
|
269 image->blue_mask == 0x001f ) {
|
yading@10
|
270 av_log (s1, AV_LOG_DEBUG, "16 bit RGB565\n");
|
yading@10
|
271 input_pixfmt = AV_PIX_FMT_RGB565;
|
yading@10
|
272 } else if (image->red_mask == 0x7c00 &&
|
yading@10
|
273 image->green_mask == 0x03e0 &&
|
yading@10
|
274 image->blue_mask == 0x001f ) {
|
yading@10
|
275 av_log(s1, AV_LOG_DEBUG, "16 bit RGB555\n");
|
yading@10
|
276 input_pixfmt = AV_PIX_FMT_RGB555;
|
yading@10
|
277 } else {
|
yading@10
|
278 av_log(s1, AV_LOG_ERROR, "RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
|
yading@10
|
279 av_log(s1, AV_LOG_ERROR, "color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask);
|
yading@10
|
280 ret = AVERROR(EIO);
|
yading@10
|
281 goto out;
|
yading@10
|
282 }
|
yading@10
|
283 break;
|
yading@10
|
284 case 24:
|
yading@10
|
285 if ( image->red_mask == 0xff0000 &&
|
yading@10
|
286 image->green_mask == 0x00ff00 &&
|
yading@10
|
287 image->blue_mask == 0x0000ff ) {
|
yading@10
|
288 input_pixfmt = AV_PIX_FMT_BGR24;
|
yading@10
|
289 } else if ( image->red_mask == 0x0000ff &&
|
yading@10
|
290 image->green_mask == 0x00ff00 &&
|
yading@10
|
291 image->blue_mask == 0xff0000 ) {
|
yading@10
|
292 input_pixfmt = AV_PIX_FMT_RGB24;
|
yading@10
|
293 } else {
|
yading@10
|
294 av_log(s1, AV_LOG_ERROR,"rgb ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
|
yading@10
|
295 av_log(s1, AV_LOG_ERROR, "color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask);
|
yading@10
|
296 ret = AVERROR(EIO);
|
yading@10
|
297 goto out;
|
yading@10
|
298 }
|
yading@10
|
299 break;
|
yading@10
|
300 case 32:
|
yading@10
|
301 input_pixfmt = AV_PIX_FMT_0RGB32;
|
yading@10
|
302 break;
|
yading@10
|
303 default:
|
yading@10
|
304 av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel);
|
yading@10
|
305 ret = AVERROR(EINVAL);
|
yading@10
|
306 goto out;
|
yading@10
|
307 }
|
yading@10
|
308
|
yading@10
|
309 x11grab->frame_size = x11grab->width * x11grab->height * image->bits_per_pixel/8;
|
yading@10
|
310 x11grab->dpy = dpy;
|
yading@10
|
311 x11grab->time_base = av_inv_q(framerate);
|
yading@10
|
312 x11grab->time_frame = av_gettime() / av_q2d(x11grab->time_base);
|
yading@10
|
313 x11grab->x_off = x_off;
|
yading@10
|
314 x11grab->y_off = y_off;
|
yading@10
|
315 x11grab->image = image;
|
yading@10
|
316 x11grab->use_shm = use_shm;
|
yading@10
|
317
|
yading@10
|
318 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
|
yading@10
|
319 st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
|
yading@10
|
320 st->codec->width = x11grab->width;
|
yading@10
|
321 st->codec->height = x11grab->height;
|
yading@10
|
322 st->codec->pix_fmt = input_pixfmt;
|
yading@10
|
323 st->codec->time_base = x11grab->time_base;
|
yading@10
|
324 st->codec->bit_rate = x11grab->frame_size * 1/av_q2d(x11grab->time_base) * 8;
|
yading@10
|
325
|
yading@10
|
326 out:
|
yading@10
|
327 av_free(dpyname);
|
yading@10
|
328 return ret;
|
yading@10
|
329 }
|
yading@10
|
330
|
yading@10
|
331 /**
|
yading@10
|
332 * Paint a mouse pointer in an X11 image.
|
yading@10
|
333 *
|
yading@10
|
334 * @param image image to paint the mouse pointer to
|
yading@10
|
335 * @param s context used to retrieve original grabbing rectangle
|
yading@10
|
336 * coordinates
|
yading@10
|
337 */
|
yading@10
|
338 static void
|
yading@10
|
339 paint_mouse_pointer(XImage *image, struct x11grab *s)
|
yading@10
|
340 {
|
yading@10
|
341 int x_off = s->x_off;
|
yading@10
|
342 int y_off = s->y_off;
|
yading@10
|
343 int width = s->width;
|
yading@10
|
344 int height = s->height;
|
yading@10
|
345 Display *dpy = s->dpy;
|
yading@10
|
346 XFixesCursorImage *xcim;
|
yading@10
|
347 int x, y;
|
yading@10
|
348 int line, column;
|
yading@10
|
349 int to_line, to_column;
|
yading@10
|
350 int pixstride = image->bits_per_pixel >> 3;
|
yading@10
|
351 /* Warning: in its insanity, xlib provides unsigned image data through a
|
yading@10
|
352 * char* pointer, so we have to make it uint8_t to make things not break.
|
yading@10
|
353 * Anyone who performs further investigation of the xlib API likely risks
|
yading@10
|
354 * permanent brain damage. */
|
yading@10
|
355 uint8_t *pix = image->data;
|
yading@10
|
356 Cursor c;
|
yading@10
|
357 Window w;
|
yading@10
|
358 XSetWindowAttributes attr;
|
yading@10
|
359
|
yading@10
|
360 /* Code doesn't currently support 16-bit or PAL8 */
|
yading@10
|
361 if (image->bits_per_pixel != 24 && image->bits_per_pixel != 32)
|
yading@10
|
362 return;
|
yading@10
|
363
|
yading@10
|
364 c = XCreateFontCursor(dpy, XC_left_ptr);
|
yading@10
|
365 w = DefaultRootWindow(dpy);
|
yading@10
|
366 attr.cursor = c;
|
yading@10
|
367 XChangeWindowAttributes(dpy, w, CWCursor, &attr);
|
yading@10
|
368
|
yading@10
|
369 xcim = XFixesGetCursorImage(dpy);
|
yading@10
|
370
|
yading@10
|
371 x = xcim->x - xcim->xhot;
|
yading@10
|
372 y = xcim->y - xcim->yhot;
|
yading@10
|
373
|
yading@10
|
374 to_line = FFMIN((y + xcim->height), (height + y_off));
|
yading@10
|
375 to_column = FFMIN((x + xcim->width), (width + x_off));
|
yading@10
|
376
|
yading@10
|
377 for (line = FFMAX(y, y_off); line < to_line; line++) {
|
yading@10
|
378 for (column = FFMAX(x, x_off); column < to_column; column++) {
|
yading@10
|
379 int xcim_addr = (line - y) * xcim->width + column - x;
|
yading@10
|
380 int image_addr = ((line - y_off) * width + column - x_off) * pixstride;
|
yading@10
|
381 int r = (uint8_t)(xcim->pixels[xcim_addr] >> 0);
|
yading@10
|
382 int g = (uint8_t)(xcim->pixels[xcim_addr] >> 8);
|
yading@10
|
383 int b = (uint8_t)(xcim->pixels[xcim_addr] >> 16);
|
yading@10
|
384 int a = (uint8_t)(xcim->pixels[xcim_addr] >> 24);
|
yading@10
|
385
|
yading@10
|
386 if (a == 255) {
|
yading@10
|
387 pix[image_addr+0] = r;
|
yading@10
|
388 pix[image_addr+1] = g;
|
yading@10
|
389 pix[image_addr+2] = b;
|
yading@10
|
390 } else if (a) {
|
yading@10
|
391 /* pixel values from XFixesGetCursorImage come premultiplied by alpha */
|
yading@10
|
392 pix[image_addr+0] = r + (pix[image_addr+0]*(255-a) + 255/2) / 255;
|
yading@10
|
393 pix[image_addr+1] = g + (pix[image_addr+1]*(255-a) + 255/2) / 255;
|
yading@10
|
394 pix[image_addr+2] = b + (pix[image_addr+2]*(255-a) + 255/2) / 255;
|
yading@10
|
395 }
|
yading@10
|
396 }
|
yading@10
|
397 }
|
yading@10
|
398
|
yading@10
|
399 XFree(xcim);
|
yading@10
|
400 xcim = NULL;
|
yading@10
|
401 }
|
yading@10
|
402
|
yading@10
|
403
|
yading@10
|
404 /**
|
yading@10
|
405 * Read new data in the image structure.
|
yading@10
|
406 *
|
yading@10
|
407 * @param dpy X11 display to grab from
|
yading@10
|
408 * @param d
|
yading@10
|
409 * @param image Image where the grab will be put
|
yading@10
|
410 * @param x Top-Left grabbing rectangle horizontal coordinate
|
yading@10
|
411 * @param y Top-Left grabbing rectangle vertical coordinate
|
yading@10
|
412 * @return 0 if error, !0 if successful
|
yading@10
|
413 */
|
yading@10
|
414 static int
|
yading@10
|
415 xget_zpixmap(Display *dpy, Drawable d, XImage *image, int x, int y)
|
yading@10
|
416 {
|
yading@10
|
417 xGetImageReply rep;
|
yading@10
|
418 xGetImageReq *req;
|
yading@10
|
419 long nbytes;
|
yading@10
|
420
|
yading@10
|
421 if (!image) {
|
yading@10
|
422 return 0;
|
yading@10
|
423 }
|
yading@10
|
424
|
yading@10
|
425 LockDisplay(dpy);
|
yading@10
|
426 GetReq(GetImage, req);
|
yading@10
|
427
|
yading@10
|
428 /* First set up the standard stuff in the request */
|
yading@10
|
429 req->drawable = d;
|
yading@10
|
430 req->x = x;
|
yading@10
|
431 req->y = y;
|
yading@10
|
432 req->width = image->width;
|
yading@10
|
433 req->height = image->height;
|
yading@10
|
434 req->planeMask = (unsigned int)AllPlanes;
|
yading@10
|
435 req->format = ZPixmap;
|
yading@10
|
436
|
yading@10
|
437 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.length) {
|
yading@10
|
438 UnlockDisplay(dpy);
|
yading@10
|
439 SyncHandle();
|
yading@10
|
440 return 0;
|
yading@10
|
441 }
|
yading@10
|
442
|
yading@10
|
443 nbytes = (long)rep.length << 2;
|
yading@10
|
444 _XReadPad(dpy, image->data, nbytes);
|
yading@10
|
445
|
yading@10
|
446 UnlockDisplay(dpy);
|
yading@10
|
447 SyncHandle();
|
yading@10
|
448 return 1;
|
yading@10
|
449 }
|
yading@10
|
450
|
yading@10
|
451 /**
|
yading@10
|
452 * Grab a frame from x11 (public device demuxer API).
|
yading@10
|
453 *
|
yading@10
|
454 * @param s1 Context from avformat core
|
yading@10
|
455 * @param pkt Packet holding the brabbed frame
|
yading@10
|
456 * @return frame size in bytes
|
yading@10
|
457 */
|
yading@10
|
458 static int
|
yading@10
|
459 x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
|
yading@10
|
460 {
|
yading@10
|
461 struct x11grab *s = s1->priv_data;
|
yading@10
|
462 Display *dpy = s->dpy;
|
yading@10
|
463 XImage *image = s->image;
|
yading@10
|
464 int x_off = s->x_off;
|
yading@10
|
465 int y_off = s->y_off;
|
yading@10
|
466
|
yading@10
|
467 int screen;
|
yading@10
|
468 Window root;
|
yading@10
|
469 int follow_mouse = s->follow_mouse;
|
yading@10
|
470
|
yading@10
|
471 int64_t curtime, delay;
|
yading@10
|
472 struct timespec ts;
|
yading@10
|
473
|
yading@10
|
474 /* Calculate the time of the next frame */
|
yading@10
|
475 s->time_frame += INT64_C(1000000);
|
yading@10
|
476
|
yading@10
|
477 /* wait based on the frame rate */
|
yading@10
|
478 for(;;) {
|
yading@10
|
479 curtime = av_gettime();
|
yading@10
|
480 delay = s->time_frame * av_q2d(s->time_base) - curtime;
|
yading@10
|
481 if (delay <= 0) {
|
yading@10
|
482 if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) {
|
yading@10
|
483 s->time_frame += INT64_C(1000000);
|
yading@10
|
484 }
|
yading@10
|
485 break;
|
yading@10
|
486 }
|
yading@10
|
487 ts.tv_sec = delay / 1000000;
|
yading@10
|
488 ts.tv_nsec = (delay % 1000000) * 1000;
|
yading@10
|
489 nanosleep(&ts, NULL);
|
yading@10
|
490 }
|
yading@10
|
491
|
yading@10
|
492 av_init_packet(pkt);
|
yading@10
|
493 pkt->data = image->data;
|
yading@10
|
494 pkt->size = s->frame_size;
|
yading@10
|
495 pkt->pts = curtime;
|
yading@10
|
496
|
yading@10
|
497 screen = DefaultScreen(dpy);
|
yading@10
|
498 root = RootWindow(dpy, screen);
|
yading@10
|
499 if (follow_mouse) {
|
yading@10
|
500 int screen_w, screen_h;
|
yading@10
|
501 int pointer_x, pointer_y, _;
|
yading@10
|
502 Window w;
|
yading@10
|
503
|
yading@10
|
504 screen_w = DisplayWidth(dpy, screen);
|
yading@10
|
505 screen_h = DisplayHeight(dpy, screen);
|
yading@10
|
506 XQueryPointer(dpy, root, &w, &w, &pointer_x, &pointer_y, &_, &_, &_);
|
yading@10
|
507 if (follow_mouse == -1) {
|
yading@10
|
508 // follow the mouse, put it at center of grabbing region
|
yading@10
|
509 x_off += pointer_x - s->width / 2 - x_off;
|
yading@10
|
510 y_off += pointer_y - s->height / 2 - y_off;
|
yading@10
|
511 } else {
|
yading@10
|
512 // follow the mouse, but only move the grabbing region when mouse
|
yading@10
|
513 // reaches within certain pixels to the edge.
|
yading@10
|
514 if (pointer_x > x_off + s->width - follow_mouse) {
|
yading@10
|
515 x_off += pointer_x - (x_off + s->width - follow_mouse);
|
yading@10
|
516 } else if (pointer_x < x_off + follow_mouse)
|
yading@10
|
517 x_off -= (x_off + follow_mouse) - pointer_x;
|
yading@10
|
518 if (pointer_y > y_off + s->height - follow_mouse) {
|
yading@10
|
519 y_off += pointer_y - (y_off + s->height - follow_mouse);
|
yading@10
|
520 } else if (pointer_y < y_off + follow_mouse)
|
yading@10
|
521 y_off -= (y_off + follow_mouse) - pointer_y;
|
yading@10
|
522 }
|
yading@10
|
523 // adjust grabbing region position if it goes out of screen.
|
yading@10
|
524 s->x_off = x_off = FFMIN(FFMAX(x_off, 0), screen_w - s->width);
|
yading@10
|
525 s->y_off = y_off = FFMIN(FFMAX(y_off, 0), screen_h - s->height);
|
yading@10
|
526
|
yading@10
|
527 if (s->show_region && s->region_win)
|
yading@10
|
528 XMoveWindow(dpy, s->region_win,
|
yading@10
|
529 s->x_off - REGION_WIN_BORDER,
|
yading@10
|
530 s->y_off - REGION_WIN_BORDER);
|
yading@10
|
531 }
|
yading@10
|
532
|
yading@10
|
533 if (s->show_region) {
|
yading@10
|
534 if (s->region_win) {
|
yading@10
|
535 XEvent evt;
|
yading@10
|
536 // clean up the events, and do the initinal draw or redraw.
|
yading@10
|
537 for (evt.type = NoEventMask; XCheckMaskEvent(dpy, ExposureMask | StructureNotifyMask, &evt); );
|
yading@10
|
538 if (evt.type)
|
yading@10
|
539 x11grab_draw_region_win(s);
|
yading@10
|
540 } else {
|
yading@10
|
541 x11grab_region_win_init(s);
|
yading@10
|
542 }
|
yading@10
|
543 }
|
yading@10
|
544
|
yading@10
|
545 if(s->use_shm) {
|
yading@10
|
546 if (!XShmGetImage(dpy, root, image, x_off, y_off, AllPlanes)) {
|
yading@10
|
547 av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n");
|
yading@10
|
548 }
|
yading@10
|
549 } else {
|
yading@10
|
550 if (!xget_zpixmap(dpy, root, image, x_off, y_off)) {
|
yading@10
|
551 av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n");
|
yading@10
|
552 }
|
yading@10
|
553 }
|
yading@10
|
554
|
yading@10
|
555 if (s->draw_mouse) {
|
yading@10
|
556 paint_mouse_pointer(image, s);
|
yading@10
|
557 }
|
yading@10
|
558
|
yading@10
|
559 return s->frame_size;
|
yading@10
|
560 }
|
yading@10
|
561
|
yading@10
|
562 /**
|
yading@10
|
563 * Close x11 frame grabber (public device demuxer API).
|
yading@10
|
564 *
|
yading@10
|
565 * @param s1 Context from avformat core
|
yading@10
|
566 * @return 0 success, !0 failure
|
yading@10
|
567 */
|
yading@10
|
568 static int
|
yading@10
|
569 x11grab_read_close(AVFormatContext *s1)
|
yading@10
|
570 {
|
yading@10
|
571 struct x11grab *x11grab = s1->priv_data;
|
yading@10
|
572
|
yading@10
|
573 /* Detach cleanly from shared mem */
|
yading@10
|
574 if (x11grab->use_shm) {
|
yading@10
|
575 XShmDetach(x11grab->dpy, &x11grab->shminfo);
|
yading@10
|
576 shmdt(x11grab->shminfo.shmaddr);
|
yading@10
|
577 shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
|
yading@10
|
578 }
|
yading@10
|
579
|
yading@10
|
580 /* Destroy X11 image */
|
yading@10
|
581 if (x11grab->image) {
|
yading@10
|
582 XDestroyImage(x11grab->image);
|
yading@10
|
583 x11grab->image = NULL;
|
yading@10
|
584 }
|
yading@10
|
585
|
yading@10
|
586 if (x11grab->region_win) {
|
yading@10
|
587 XDestroyWindow(x11grab->dpy, x11grab->region_win);
|
yading@10
|
588 }
|
yading@10
|
589
|
yading@10
|
590 /* Free X11 display */
|
yading@10
|
591 XCloseDisplay(x11grab->dpy);
|
yading@10
|
592 return 0;
|
yading@10
|
593 }
|
yading@10
|
594
|
yading@10
|
595 #define OFFSET(x) offsetof(struct x11grab, x)
|
yading@10
|
596 #define DEC AV_OPT_FLAG_DECODING_PARAM
|
yading@10
|
597 static const AVOption options[] = {
|
yading@10
|
598 { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
|
yading@10
|
599
|
yading@10
|
600 { "follow_mouse", "move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region",
|
yading@10
|
601 OFFSET(follow_mouse), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, DEC, "follow_mouse" },
|
yading@10
|
602 { "centered", "keep the mouse pointer at the center of grabbing region when following",
|
yading@10
|
603 0, AV_OPT_TYPE_CONST, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "follow_mouse" },
|
yading@10
|
604
|
yading@10
|
605 { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
|
yading@10
|
606 { "show_region", "show the grabbing region", OFFSET(show_region), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
|
yading@10
|
607 { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "vga"}, 0, 0, DEC },
|
yading@10
|
608 { NULL },
|
yading@10
|
609 };
|
yading@10
|
610
|
yading@10
|
611 static const AVClass x11_class = {
|
yading@10
|
612 .class_name = "X11grab indev",
|
yading@10
|
613 .item_name = av_default_item_name,
|
yading@10
|
614 .option = options,
|
yading@10
|
615 .version = LIBAVUTIL_VERSION_INT,
|
yading@10
|
616 };
|
yading@10
|
617
|
yading@10
|
618 /** x11 grabber device demuxer declaration */
|
yading@10
|
619 AVInputFormat ff_x11grab_demuxer = {
|
yading@10
|
620 .name = "x11grab",
|
yading@10
|
621 .long_name = NULL_IF_CONFIG_SMALL("X11grab"),
|
yading@10
|
622 .priv_data_size = sizeof(struct x11grab),
|
yading@10
|
623 .read_header = x11grab_read_header,
|
yading@10
|
624 .read_packet = x11grab_read_packet,
|
yading@10
|
625 .read_close = x11grab_read_close,
|
yading@10
|
626 .flags = AVFMT_NOFILE,
|
yading@10
|
627 .priv_class = &x11_class,
|
yading@10
|
628 };
|