Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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