x11grab.c 20.6 KB
Newer Older
1 2
/*
 * X11 video grab interface
3
 *
4
 * This file is part of Libav.
5
 *
6
 * Libav integration:
7 8
 * Copyright (C) 2006 Clemens Fruhwirth <clemens@endorphin.org>
 *                    Edouard Gomez <ed.gomez@free.fr>
9
 *
10
 * This file contains code from grab.c:
11
 * Copyright (c) 2000-2001 Fabrice Bellard
12 13
 *
 * This file contains code from the xvidcap project:
14 15
 * Copyright (C) 1997-1998 Rasca, Berlin
 *               2003-2004 Karl H. Beckers, Frankfurt
16
 *
17
 * Libav is free software; you can redistribute it and/or modify
18 19 20 21
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
22
 * Libav is distributed in the hope that it will be useful,
23 24 25 26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with Libav; if not, write to the Free Software
29
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30
 */
31

E
Edouard Gomez 已提交
32
/**
33
 * @file
E
Edouard Gomez 已提交
34 35 36 37
 * X11 frame device demuxer by Clemens Fruhwirth <clemens@endorphin.org>
 * and Edouard Gomez <ed.gomez@free.fr>.
 */

38
#include "config.h"
39
#include "libavformat/avformat.h"
40 41 42
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
43 44 45 46 47
#include <time.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
48
#include <X11/Xutil.h>
49
#include <sys/shm.h>
Y
Yu-Jie Lin 已提交
50
#include <X11/extensions/shape.h>
51
#include <X11/extensions/XShm.h>
R
Roxis 已提交
52
#include <X11/extensions/Xfixes.h>
53

E
Edouard Gomez 已提交
54 55 56
/**
 * X11 Device Demuxer context
 */
D
Diego Biurrun 已提交
57
struct x11_grab
58
{
59
    const AVClass *class;    /**< Class for private options. */
E
Edouard Gomez 已提交
60 61 62 63
    int frame_size;          /**< Size in bytes of a grabbed frame */
    AVRational time_base;    /**< Time base */
    int64_t time_frame;      /**< Current time */

64
    char *video_size;        /**< String describing video size, set by a private option. */
E
Edouard Gomez 已提交
65 66 67 68 69 70 71 72 73
    int height;              /**< Height of the grab frame */
    int width;               /**< Width of the grab frame */
    int x_off;               /**< Horizontal top-left corner coordinate */
    int y_off;               /**< Vertical top-left corner coordinate */

    Display *dpy;            /**< X11 display from which x11grab grabs frames */
    XImage *image;           /**< X11 image holding the grab */
    int use_shm;             /**< !0 when using XShm extension */
    XShmSegmentInfo shminfo; /**< When using XShm, keeps track of XShm infos */
74
    int  draw_mouse;         /**< Set by a private option. */
Y
Yu-Jie Lin 已提交
75
    int  follow_mouse;       /**< Set by a private option. */
Y
Yu-Jie Lin 已提交
76
    int  show_region;        /**< set by a private option. */
77
    char *framerate;         /**< Set by a private option. */
Y
Yu-Jie Lin 已提交
78 79

    Window region_win;       /**< This is used by show_region option. */
D
Diego Biurrun 已提交
80
};
E
Edouard Gomez 已提交
81

Y
Yu-Jie Lin 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
#define REGION_WIN_BORDER 3
/**
 * Draw grabbing region window
 *
 * @param s x11_grab context
 */
static void
x11grab_draw_region_win(struct x11_grab *s)
{
    Display *dpy = s->dpy;
    int screen;
    Window win = s->region_win;
    GC gc;

    screen = DefaultScreen(dpy);
    gc = XCreateGC(dpy, win, 0, 0);
    XSetForeground(dpy, gc, WhitePixel(dpy, screen));
    XSetBackground(dpy, gc, BlackPixel(dpy, screen));
    XSetLineAttributes(dpy, gc, REGION_WIN_BORDER, LineDoubleDash, 0, 0);
    XDrawRectangle(dpy, win, gc,
                   1, 1,
                   (s->width  + REGION_WIN_BORDER * 2) - 1 * 2 - 1,
                   (s->height + REGION_WIN_BORDER * 2) - 1 * 2 - 1);
    XFreeGC(dpy, gc);
}

/**
 * Initialize grabbing region window
 *
 * @param s x11_grab context
 */
static void
x11grab_region_win_init(struct x11_grab *s)
{
    Display *dpy = s->dpy;
    int screen;
    XSetWindowAttributes attribs;
    XRectangle rect;

    screen = DefaultScreen(dpy);
    attribs.override_redirect = True;
    s->region_win = XCreateWindow(dpy, RootWindow(dpy, screen),
                                  s->x_off  - REGION_WIN_BORDER,
                                  s->y_off  - REGION_WIN_BORDER,
                                  s->width  + REGION_WIN_BORDER * 2,
                                  s->height + REGION_WIN_BORDER * 2,
                                  0, CopyFromParent,
                                  InputOutput, CopyFromParent,
                                  CWOverrideRedirect, &attribs);
    rect.x = 0;
    rect.y = 0;
    rect.width  = s->width;
    rect.height = s->height;
    XShapeCombineRectangles(dpy, s->region_win,
                            ShapeBounding, REGION_WIN_BORDER, REGION_WIN_BORDER,
                            &rect, 1, ShapeSubtract, 0);
    XMapWindow(dpy, s->region_win);
    XSelectInput(dpy, s->region_win, ExposureMask | StructureNotifyMask);
    x11grab_draw_region_win(s);
}

E
Edouard Gomez 已提交
143
/**
144
 * Initialize the x11 grab device demuxer (public device demuxer API).
E
Edouard Gomez 已提交
145 146 147 148
 *
 * @param s1 Context from avformat core
 * @param ap Parameters from avformat core
 * @return <ul>
149
 *          <li>AVERROR(ENOMEM) no memory left</li>
150
 *          <li>AVERROR(EIO) other failure case</li>
E
Edouard Gomez 已提交
151 152 153
 *          <li>0 success</li>
 *         </ul>
 */
154 155
static int
x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
156
{
D
Diego Biurrun 已提交
157
    struct x11_grab *x11grab = s1->priv_data;
158 159
    Display *dpy;
    AVStream *st = NULL;
160
    enum PixelFormat input_pixfmt;
161
    XImage *image;
E
Edouard Gomez 已提交
162 163
    int x_off = 0;
    int y_off = 0;
Y
Yu-Jie Lin 已提交
164
    int screen;
165
    int use_shm;
166
    char *param, *offset;
167
    int ret = 0;
168
    AVRational framerate;
169

170
    param = av_strdup(s1->filename);
171 172 173
    offset = strchr(param, '+');
    if (offset) {
        sscanf(offset, "%d,%d", &x_off, &y_off);
174
        x11grab->draw_mouse = !strstr(offset, "nomouse");
175 176 177
        *offset= 0;
    }

178 179 180 181
    if ((ret = av_parse_video_size(&x11grab->width, &x11grab->height, x11grab->video_size)) < 0) {
        av_log(s1, AV_LOG_ERROR, "Couldn't parse video size.\n");
        goto out;
    }
182 183 184 185
    if ((ret = av_parse_video_rate(&framerate, x11grab->framerate)) < 0) {
        av_log(s1, AV_LOG_ERROR, "Could not parse framerate: %s.\n", x11grab->framerate);
        goto out;
    }
186 187
    av_log(s1, AV_LOG_INFO, "device: %s -> display: %s x: %d y: %d width: %d height: %d\n",
           s1->filename, param, x_off, y_off, x11grab->width, x11grab->height);
188 189 190 191

    dpy = XOpenDisplay(param);
    if(!dpy) {
        av_log(s1, AV_LOG_ERROR, "Could not open X display.\n");
192 193
        ret = AVERROR(EIO);
        goto out;
194
    }
195 196 197

    st = av_new_stream(s1, 0);
    if (!st) {
198 199
        ret = AVERROR(ENOMEM);
        goto out;
200 201 202
    }
    av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */

Y
Yu-Jie Lin 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    screen = DefaultScreen(dpy);

    if (x11grab->follow_mouse) {
        int screen_w, screen_h;
        Window w;

        screen_w = DisplayWidth(dpy, screen);
        screen_h = DisplayHeight(dpy, screen);
        XQueryPointer(dpy, RootWindow(dpy, screen), &w, &w, &x_off, &y_off, &ret, &ret, &ret);
        x_off -= x11grab->width / 2;
        y_off -= x11grab->height / 2;
        x_off = FFMIN(FFMAX(x_off, 0), screen_w - x11grab->width);
        y_off = FFMIN(FFMAX(y_off, 0), screen_h - x11grab->height);
        av_log(s1, AV_LOG_INFO, "followmouse is enabled, resetting grabbing region to x: %d y: %d\n", x_off, y_off);
    }

219
    use_shm = XShmQueryExtension(dpy);
E
Edouard Gomez 已提交
220
    av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not");
221 222 223 224 225 226 227 228 229

    if(use_shm) {
        int scr = XDefaultScreen(dpy);
        image = XShmCreateImage(dpy,
                                DefaultVisual(dpy, scr),
                                DefaultDepth(dpy, scr),
                                ZPixmap,
                                NULL,
                                &x11grab->shminfo,
230
                                x11grab->width, x11grab->height);
231 232 233 234 235
        x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
                                        image->bytes_per_line * image->height,
                                        IPC_CREAT|0777);
        if (x11grab->shminfo.shmid == -1) {
            av_log(s1, AV_LOG_ERROR, "Fatal: Can't get shared memory!\n");
236 237
            ret = AVERROR(ENOMEM);
            goto out;
238 239 240 241 242 243 244
        }
        x11grab->shminfo.shmaddr = image->data = shmat(x11grab->shminfo.shmid, 0, 0);
        x11grab->shminfo.readOnly = False;

        if (!XShmAttach(dpy, &x11grab->shminfo)) {
            av_log(s1, AV_LOG_ERROR, "Fatal: Failed to attach shared memory!\n");
            /* needs some better error subroutine :) */
245 246
            ret = AVERROR(EIO);
            goto out;
247 248
        }
    } else {
Y
Yu-Jie Lin 已提交
249
        image = XGetImage(dpy, RootWindow(dpy, screen),
250
                          x_off,y_off,
251
                          x11grab->width, x11grab->height,
252 253 254 255 256
                          AllPlanes, ZPixmap);
    }

    switch (image->bits_per_pixel) {
    case 8:
D
Diego Biurrun 已提交
257
        av_log (s1, AV_LOG_DEBUG, "8 bit palette\n");
258 259 260
        input_pixfmt = PIX_FMT_PAL8;
        break;
    case 16:
E
Edouard Gomez 已提交
261 262 263
        if (       image->red_mask   == 0xf800 &&
                   image->green_mask == 0x07e0 &&
                   image->blue_mask  == 0x001f ) {
264 265
            av_log (s1, AV_LOG_DEBUG, "16 bit RGB565\n");
            input_pixfmt = PIX_FMT_RGB565;
E
Edouard Gomez 已提交
266 267 268
        } else if (image->red_mask   == 0x7c00 &&
                   image->green_mask == 0x03e0 &&
                   image->blue_mask  == 0x001f ) {
269 270 271 272 273
            av_log(s1, AV_LOG_DEBUG, "16 bit RGB555\n");
            input_pixfmt = PIX_FMT_RGB555;
        } else {
            av_log(s1, AV_LOG_ERROR, "RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
            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);
274 275
            ret = AVERROR(EIO);
            goto out;
276 277 278
        }
        break;
    case 24:
E
Edouard Gomez 已提交
279 280 281
        if (        image->red_mask   == 0xff0000 &&
                    image->green_mask == 0x00ff00 &&
                    image->blue_mask  == 0x0000ff ) {
282
            input_pixfmt = PIX_FMT_BGR24;
E
Edouard Gomez 已提交
283 284 285
        } else if ( image->red_mask   == 0x0000ff &&
                    image->green_mask == 0x00ff00 &&
                    image->blue_mask  == 0xff0000 ) {
286 287 288 289
            input_pixfmt = PIX_FMT_RGB24;
        } else {
            av_log(s1, AV_LOG_ERROR,"rgb ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
            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);
290 291
            ret = AVERROR(EIO);
            goto out;
292 293 294
        }
        break;
    case 32:
295
        input_pixfmt = PIX_FMT_RGB32;
296 297 298
        break;
    default:
        av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel);
299 300
        ret = AVERROR(EINVAL);
        goto out;
301 302
    }

303
    x11grab->frame_size = x11grab->width * x11grab->height * image->bits_per_pixel/8;
304
    x11grab->dpy = dpy;
305 306
    x11grab->time_base  = (AVRational){framerate.den, framerate.num};
    x11grab->time_frame = av_gettime() / av_q2d(x11grab->time_base);
307 308 309 310 311
    x11grab->x_off = x_off;
    x11grab->y_off = y_off;
    x11grab->image = image;
    x11grab->use_shm = use_shm;

312
    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
313
    st->codec->codec_id = CODEC_ID_RAWVIDEO;
314 315
    st->codec->width  = x11grab->width;
    st->codec->height = x11grab->height;
316
    st->codec->pix_fmt = input_pixfmt;
317 318
    st->codec->time_base = x11grab->time_base;
    st->codec->bit_rate = x11grab->frame_size * 1/av_q2d(x11grab->time_base) * 8;
319

320 321
out:
    return ret;
322 323
}

E
Edouard Gomez 已提交
324
/**
325
 * Paint a mouse pointer in an X11 image.
E
Edouard Gomez 已提交
326
 *
D
Diego Biurrun 已提交
327
 * @param image image to paint the mouse pointer to
E
Edouard Gomez 已提交
328 329 330
 * @param s context used to retrieve original grabbing rectangle
 *          coordinates
 */
331
static void
R
Roxis 已提交
332
paint_mouse_pointer(XImage *image, struct x11_grab *s)
333
{
334 335 336 337
    int x_off = s->x_off;
    int y_off = s->y_off;
    int width = s->width;
    int height = s->height;
R
Roxis 已提交
338 339 340 341 342
    Display *dpy = s->dpy;
    XFixesCursorImage *xcim;
    int x, y;
    int line, column;
    int to_line, to_column;
343 344 345 346 347 348 349 350 351 352
    int pixstride = image->bits_per_pixel >> 3;
    /* Warning: in its insanity, xlib provides unsigned image data through a
     * char* pointer, so we have to make it uint8_t to make things not break.
     * Anyone who performs further investigation of the xlib API likely risks
     * permanent brain damage. */
    uint8_t *pix = image->data;

    /* Code doesn't currently support 16-bit or PAL8 */
    if (image->bits_per_pixel != 24 && image->bits_per_pixel != 32)
        return;
353

C
Carl Eugen Hoyos 已提交
354
    xcim = XFixesGetCursorImage(dpy);
355

R
Roxis 已提交
356 357 358 359 360 361 362 363
    x = xcim->x - xcim->xhot;
    y = xcim->y - xcim->yhot;

    to_line = FFMIN((y + xcim->height), (height + y_off));
    to_column = FFMIN((x + xcim->width), (width + x_off));

    for (line = FFMAX(y, y_off); line < to_line; line++) {
        for (column = FFMAX(x, x_off); column < to_column; column++) {
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
            int  xcim_addr = (line - y) * xcim->width + column - x;
            int image_addr = ((line - y_off) * width + column - x_off) * pixstride;
            int r = (uint8_t)(xcim->pixels[xcim_addr] >>  0);
            int g = (uint8_t)(xcim->pixels[xcim_addr] >>  8);
            int b = (uint8_t)(xcim->pixels[xcim_addr] >> 16);
            int a = (uint8_t)(xcim->pixels[xcim_addr] >> 24);

            if (a == 255) {
                pix[image_addr+0] = r;
                pix[image_addr+1] = g;
                pix[image_addr+2] = b;
            } else if (a) {
                /* pixel values from XFixesGetCursorImage come premultiplied by alpha */
                pix[image_addr+0] = r + (pix[image_addr+0]*(255-a) + 255/2) / 255;
                pix[image_addr+1] = g + (pix[image_addr+1]*(255-a) + 255/2) / 255;
                pix[image_addr+2] = b + (pix[image_addr+2]*(255-a) + 255/2) / 255;
380
            }
381 382
        }
    }
R
Roxis 已提交
383 384 385

    XFree(xcim);
    xcim = NULL;
386 387 388
}


E
Edouard Gomez 已提交
389
/**
390
 * Read new data in the image structure.
E
Edouard Gomez 已提交
391 392
 *
 * @param dpy X11 display to grab from
393
 * @param d
E
Edouard Gomez 已提交
394 395 396 397
 * @param image Image where the grab will be put
 * @param x Top-Left grabbing rectangle horizontal coordinate
 * @param y Top-Left grabbing rectangle vertical coordinate
 * @return 0 if error, !0 if successful
398 399
 */
static int
E
Edouard Gomez 已提交
400
xget_zpixmap(Display *dpy, Drawable d, XImage *image, int x, int y)
401
{
402 403 404 405 406
    xGetImageReply rep;
    xGetImageReq *req;
    long nbytes;

    if (!image) {
E
Edouard Gomez 已提交
407
        return 0;
408 409 410 411 412 413 414 415 416 417 418 419 420 421
    }

    LockDisplay(dpy);
    GetReq(GetImage, req);

    /* First set up the standard stuff in the request */
    req->drawable = d;
    req->x = x;
    req->y = y;
    req->width = image->width;
    req->height = image->height;
    req->planeMask = (unsigned int)AllPlanes;
    req->format = ZPixmap;

E
Edouard Gomez 已提交
422
    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.length) {
423 424
        UnlockDisplay(dpy);
        SyncHandle();
E
Edouard Gomez 已提交
425
        return 0;
426 427 428 429 430 431 432
    }

    nbytes = (long)rep.length << 2;
    _XReadPad(dpy, image->data, nbytes);

    UnlockDisplay(dpy);
    SyncHandle();
E
Edouard Gomez 已提交
433
    return 1;
434 435
}

E
Edouard Gomez 已提交
436
/**
437
 * Grab a frame from x11 (public device demuxer API).
E
Edouard Gomez 已提交
438 439 440 441 442
 *
 * @param s1 Context from avformat core
 * @param pkt Packet holding the brabbed frame
 * @return frame size in bytes
 */
443 444
static int
x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
445
{
D
Diego Biurrun 已提交
446
    struct x11_grab *s = s1->priv_data;
447 448 449 450 451
    Display *dpy = s->dpy;
    XImage *image = s->image;
    int x_off = s->x_off;
    int y_off = s->y_off;

Y
Yu-Jie Lin 已提交
452 453 454 455
    int screen;
    Window root;
    int follow_mouse = s->follow_mouse;

456 457 458 459
    int64_t curtime, delay;
    struct timespec ts;

    /* Calculate the time of the next frame */
460
    s->time_frame += INT64_C(1000000);
461 462 463 464

    /* wait based on the frame rate */
    for(;;) {
        curtime = av_gettime();
E
Edouard Gomez 已提交
465
        delay = s->time_frame * av_q2d(s->time_base) - curtime;
466
        if (delay <= 0) {
467 468
            if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) {
                s->time_frame += INT64_C(1000000);
469 470 471 472 473 474 475 476
            }
            break;
        }
        ts.tv_sec = delay / 1000000;
        ts.tv_nsec = (delay % 1000000) * 1000;
        nanosleep(&ts, NULL);
    }

477 478 479
    av_init_packet(pkt);
    pkt->data = image->data;
    pkt->size = s->frame_size;
E
Edouard Gomez 已提交
480
    pkt->pts = curtime;
481

Y
Yu-Jie Lin 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    screen = DefaultScreen(dpy);
    root = RootWindow(dpy, screen);
    if (follow_mouse) {
        int screen_w, screen_h;
        int pointer_x, pointer_y, _;
        Window w;

        screen_w = DisplayWidth(dpy, screen);
        screen_h = DisplayHeight(dpy, screen);
        XQueryPointer(dpy, root, &w, &w, &pointer_x, &pointer_y, &_, &_, &_);
        if (follow_mouse == -1) {
            // follow the mouse, put it at center of grabbing region
            x_off += pointer_x - s->width  / 2 - x_off;
            y_off += pointer_y - s->height / 2 - y_off;
        } else {
            // follow the mouse, but only move the grabbing region when mouse
            // reaches within certain pixels to the edge.
            if (pointer_x > x_off + s->width - follow_mouse) {
                x_off += pointer_x - (x_off + s->width - follow_mouse);
            } else if (pointer_x < x_off + follow_mouse)
                x_off -= (x_off + follow_mouse) - pointer_x;
            if (pointer_y > y_off + s->height - follow_mouse) {
                y_off += pointer_y - (y_off + s->height - follow_mouse);
            } else if (pointer_y < y_off + follow_mouse)
                y_off -= (y_off + follow_mouse) - pointer_y;
        }
        // adjust grabbing region position if it goes out of screen.
        s->x_off = x_off = FFMIN(FFMAX(x_off, 0), screen_w - s->width);
        s->y_off = y_off = FFMIN(FFMAX(y_off, 0), screen_h - s->height);
Y
Yu-Jie Lin 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527

        if (s->show_region && s->region_win)
            XMoveWindow(dpy, s->region_win,
                        s->x_off - REGION_WIN_BORDER,
                        s->y_off - REGION_WIN_BORDER);
    }

    if (s->show_region) {
        if (s->region_win) {
            XEvent evt;
            // clean up the events, and do the initinal draw or redraw.
            for (evt.type = NoEventMask; XCheckMaskEvent(dpy, ExposureMask | StructureNotifyMask, &evt); );
            if (evt.type)
                x11grab_draw_region_win(s);
        } else {
            x11grab_region_win_init(s);
        }
Y
Yu-Jie Lin 已提交
528 529
    }

530
    if(s->use_shm) {
Y
Yu-Jie Lin 已提交
531
        if (!XShmGetImage(dpy, root, image, x_off, y_off, AllPlanes)) {
532 533 534
            av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n");
        }
    } else {
Y
Yu-Jie Lin 已提交
535
        if (!xget_zpixmap(dpy, root, image, x_off, y_off)) {
536 537 538 539
            av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n");
        }
    }

540
    if (s->draw_mouse) {
R
Roxis 已提交
541
        paint_mouse_pointer(image, s);
542 543 544
    }

    return s->frame_size;
545 546
}

E
Edouard Gomez 已提交
547
/**
548
 * Close x11 frame grabber (public device demuxer API).
E
Edouard Gomez 已提交
549 550 551 552
 *
 * @param s1 Context from avformat core
 * @return 0 success, !0 failure
 */
553 554
static int
x11grab_read_close(AVFormatContext *s1)
555
{
D
Diego Biurrun 已提交
556
    struct x11_grab *x11grab = s1->priv_data;
557 558 559 560 561 562 563 564 565 566 567 568 569 570

    /* Detach cleanly from shared mem */
    if (x11grab->use_shm) {
        XShmDetach(x11grab->dpy, &x11grab->shminfo);
        shmdt(x11grab->shminfo.shmaddr);
        shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
    }

    /* Destroy X11 image */
    if (x11grab->image) {
        XDestroyImage(x11grab->image);
        x11grab->image = NULL;
    }

Y
Yu-Jie Lin 已提交
571 572 573 574
    if (x11grab->region_win) {
        XDestroyWindow(x11grab->dpy, x11grab->region_win);
    }

575 576 577
    /* Free X11 display */
    XCloseDisplay(x11grab->dpy);
    return 0;
578 579
}

580 581 582 583
#define OFFSET(x) offsetof(struct x11_grab, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
    { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
584
    { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
585
    { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), FF_OPT_TYPE_INT, { 1 }, 0, 1, DEC },
Y
Yu-Jie Lin 已提交
586 587 588
    { "follow_mouse", "Move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region.",
      OFFSET(follow_mouse), FF_OPT_TYPE_INT, { 0 }, -1, INT_MAX, DEC, "follow_mouse" },
    { "centered", "Keep the mouse pointer at the center of grabbing region when following.", 0, FF_OPT_TYPE_CONST, { -1 }, INT_MIN, INT_MAX, DEC, "follow_mouse" },
Y
Yu-Jie Lin 已提交
589
    { "show_region", "Show the grabbing region.", OFFSET(show_region), FF_OPT_TYPE_INT, { 0 }, 0, 1, DEC },
590 591 592 593 594 595 596 597 598 599
    { NULL },
};

static const AVClass x11_class = {
    .class_name = "X11grab indev",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};

E
Edouard Gomez 已提交
600
/** x11 grabber device demuxer declaration */
601 602 603 604 605 606 607 608 609
AVInputFormat ff_x11_grab_device_demuxer = {
    .name           = "x11grab",
    .long_name      = NULL_IF_CONFIG_SMALL("X11grab"),
    .priv_data_size = sizeof(struct x11_grab),
    .read_header    = x11grab_read_header,
    .read_packet    = x11grab_read_packet,
    .read_close     = x11grab_read_close,
    .flags          = AVFMT_NOFILE,
    .priv_class     = &x11_class,
610
};