x11grab.c File Reference

#include "config.h"
#include "libavformat/avformat.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <time.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>

Go to the source code of this file.

Data Structures

struct  x11_grab_s

Defines

#define _LINUX_TIME_H   1

Typedefs

typedef x11_grab_s x11_grab_t

Functions

static int x11grab_read_header (AVFormatContext *s1, AVFormatParameters *ap)
static void get_pointer_coordinates (int *x, int *y, Display *dpy, AVFormatContext *s1)
static void apply_masks (uint8_t *dst, int and, int or, int bits_per_pixel)
static void paint_mouse_pointer (XImage *image, x11_grab_t *s, int x, int y)
static int xget_zpixmap (Display *dpy, Drawable d, XImage *image, int x, int y)
static int x11grab_read_packet (AVFormatContext *s1, AVPacket *pkt)
static int x11grab_read_close (AVFormatContext *s1)

Variables

AVInputFormat x11_grab_device_demuxer


Detailed Description

X11 frame device demuxer by Clemens Fruhwirth <clemens@endorphin.org> and Edouard Gomez <ed.gomez@free.fr>.

Definition in file x11grab.c.


Define Documentation

#define _LINUX_TIME_H   1

Definition at line 44 of file x11grab.c.


Typedef Documentation

typedef struct x11_grab_s x11_grab_t

X11 Device Demuxer context


Function Documentation

static void apply_masks ( uint8_t *  dst,
int  and,
int  or,
int  bits_per_pixel 
) [inline, static]

Mouse painting helper function that applies an 'and' and 'or' mask pair to '*dst' pixel. It actually draws a mouse pointer pixel to grabbed frame.

Parameters:
dst Destination pixel
and Part of the mask that must be applied using a bitwise 'and' operator
or Part of the mask that must be applied using a bitwise 'or' operator
bits_per_pixel Bits per pixel used in the grabbed image

Definition at line 284 of file x11grab.c.

Referenced by paint_mouse_pointer().

00285 {
00286     switch (bits_per_pixel) {
00287     case 32:
00288         *(uint32_t*)dst = (*(uint32_t*)dst & and) | or;
00289         break;
00290     case 16:
00291         *(uint16_t*)dst = (*(uint16_t*)dst & and) | or;
00292         break;
00293     case 8:
00294         *dst = !!or;
00295         break;
00296     }
00297 }

static void get_pointer_coordinates ( int *  x,
int *  y,
Display *  dpy,
AVFormatContext s1 
) [static]

Get pointer coordinates from X11.

Parameters:
x Integer where horizontal coordinate will be returned
y Integer where vertical coordinate will be returned
dpy X11 display from where pointer coordinates are retrieved
s1 Context used for logging errors if necessary

Definition at line 252 of file x11grab.c.

References av_log(), AV_LOG_INFO, dummy, x11_grab_s::mouse_warning_shown, and s1.

Referenced by x11grab_read_packet().

00253 {
00254     Window mrootwindow, childwindow;
00255     int dummy;
00256 
00257     mrootwindow = DefaultRootWindow(dpy);
00258 
00259     if (XQueryPointer(dpy, mrootwindow, &mrootwindow, &childwindow,
00260                       x, y, &dummy, &dummy, (unsigned int*)&dummy)) {
00261     } else {
00262         x11_grab_t *s = s1->priv_data;
00263         if (!s->mouse_warning_shown) {
00264             av_log(s1, AV_LOG_INFO, "couldn't find mouse pointer\n");
00265             s->mouse_warning_shown = 1;
00266         }
00267         *x = -1;
00268         *y = -1;
00269     }
00270 }

static void paint_mouse_pointer ( XImage *  image,
x11_grab_t s,
int  x,
int  y 
) [static]

Paints a mouse pointer in an X11 image.

Parameters:
image image to paint the mouse pointer to
s context used to retrieve original grabbing rectangle coordinates
x Mouse pointer coordinate
y Mouse pointer coordinate

Definition at line 309 of file x11grab.c.

References apply_masks(), FFMIN, x11_grab_s::height, height, x11_grab_s::width, width, x11_grab_s::x_off, and x11_grab_s::y_off.

Referenced by x11grab_read_packet().

00310 {
00311     /* 16x20x1bpp bitmap for the black channel of the mouse pointer */
00312     static const uint16_t const mousePointerBlack[] =
00313         {
00314             0x0000, 0x0003, 0x0005, 0x0009, 0x0011,
00315             0x0021, 0x0041, 0x0081, 0x0101, 0x0201,
00316             0x03c1, 0x0049, 0x0095, 0x0093, 0x0120,
00317             0x0120, 0x0240, 0x0240, 0x0380, 0x0000
00318         };
00319 
00320     /* 16x20x1bpp bitmap for the white channel of the mouse pointer */
00321     static const uint16_t const mousePointerWhite[] =
00322         {
00323             0x0000, 0x0000, 0x0002, 0x0006, 0x000e,
00324             0x001e, 0x003e, 0x007e, 0x00fe, 0x01fe,
00325             0x003e, 0x0036, 0x0062, 0x0060, 0x00c0,
00326             0x00c0, 0x0180, 0x0180, 0x0000, 0x0000
00327         };
00328 
00329     int x_off = s->x_off;
00330     int y_off = s->y_off;
00331     int width = s->width;
00332     int height = s->height;
00333 
00334     if (   x - x_off >= 0 && x < width + x_off
00335         && y - y_off >= 0 && y < height + y_off) {
00336         uint8_t *im_data = (uint8_t*)image->data;
00337         int bytes_per_pixel;
00338         int line;
00339         int masks;
00340 
00341         /* Select correct masks and pixel size */
00342         if (image->bits_per_pixel == 8) {
00343             masks = 1;
00344         } else {
00345             masks = (image->red_mask|image->green_mask|image->blue_mask);
00346         }
00347         bytes_per_pixel = image->bits_per_pixel>>3;
00348 
00349         /* Shift to right line */
00350         im_data += image->bytes_per_line * (y - y_off);
00351         /* Shift to right pixel in the line */
00352         im_data += bytes_per_pixel * (x - x_off);
00353 
00354         /* Draw the cursor - proper loop */
00355         for (line = 0; line < FFMIN(20, (y_off + height) - y); line++) {
00356             uint8_t *cursor = im_data;
00357             int column;
00358             uint16_t bm_b;
00359             uint16_t bm_w;
00360 
00361             bm_b = mousePointerBlack[line];
00362             bm_w = mousePointerWhite[line];
00363 
00364             for (column = 0; column < FFMIN(16, (x_off + width) - x); column++) {
00365                 apply_masks(cursor, ~(masks*(bm_b&1)), masks*(bm_w&1),
00366                             image->bits_per_pixel);
00367                 cursor += bytes_per_pixel;
00368                 bm_b >>= 1;
00369                 bm_w >>= 1;
00370             }
00371             im_data += image->bytes_per_line;
00372         }
00373     }
00374 }

static int x11grab_read_close ( AVFormatContext s1  )  [static]

Closes x11 frame grabber (public device demuxer API).

Parameters:
s1 Context from avformat core
Returns:
0 success, !0 failure

Definition at line 496 of file x11grab.c.

References x11_grab_s::dpy, x11_grab_s::image, NULL, s1, x11_grab_s::shminfo, and x11_grab_s::use_shm.

00497 {
00498     x11_grab_t *x11grab = s1->priv_data;
00499 
00500     /* Detach cleanly from shared mem */
00501     if (x11grab->use_shm) {
00502         XShmDetach(x11grab->dpy, &x11grab->shminfo);
00503         shmdt(x11grab->shminfo.shmaddr);
00504         shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
00505     }
00506 
00507     /* Destroy X11 image */
00508     if (x11grab->image) {
00509         XDestroyImage(x11grab->image);
00510         x11grab->image = NULL;
00511     }
00512 
00513     /* Free X11 display */
00514     XCloseDisplay(x11grab->dpy);
00515     return 0;
00516 }

static int x11grab_read_header ( AVFormatContext s1,
AVFormatParameters ap 
) [static]

Initializes the x11 grab device demuxer (public device demuxer API).

Parameters:
s1 Context from avformat core
ap Parameters from avformat core
Returns:

Definition at line 88 of file x11grab.c.

References av_gettime(), av_log(), AV_LOG_DEBUG, AV_LOG_ERROR, AV_LOG_INFO, av_new_stream(), av_q2d(), av_set_pts_info(), av_strdup(), AVERROR, AVCodecContext::bit_rate, AVStream::codec, AVCodecContext::codec_id, CODEC_ID_RAWVIDEO, AVCodecContext::codec_type, CODEC_TYPE_VIDEO, AVRational::den, x11_grab_s::dpy, x11_grab_s::frame_size, AVCodecContext::height, x11_grab_s::height, AVFormatParameters::height, x11_grab_s::image, x11_grab_s::mouse_warning_shown, NULL, offset, AVCodecContext::pix_fmt, PIX_FMT_BGR24, PIX_FMT_PAL8, PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_RGB555, PIX_FMT_RGB565, s1, x11_grab_s::shminfo, AVCodecContext::time_base, x11_grab_s::time_base, AVFormatParameters::time_base, x11_grab_s::time_frame, x11_grab_s::use_shm, AVCodecContext::width, x11_grab_s::width, AVFormatParameters::width, x11_grab_s::x_off, and x11_grab_s::y_off.

00089 {
00090     x11_grab_t *x11grab = s1->priv_data;
00091     Display *dpy;
00092     AVStream *st = NULL;
00093     int input_pixfmt;
00094     XImage *image;
00095     int x_off = 0;
00096     int y_off = 0;
00097     int use_shm;
00098     char *param, *offset;
00099 
00100     param = av_strdup(s1->filename);
00101     offset = strchr(param, '+');
00102     if (offset) {
00103         sscanf(offset, "%d,%d", &x_off, &y_off);
00104         *offset= 0;
00105     }
00106 
00107     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, ap->width, ap->height);
00108 
00109     dpy = XOpenDisplay(param);
00110     if(!dpy) {
00111         av_log(s1, AV_LOG_ERROR, "Could not open X display.\n");
00112         return AVERROR(EIO);
00113     }
00114 
00115     if (!ap || ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) {
00116         av_log(s1, AV_LOG_ERROR, "AVParameters don't have video size and/or rate. Use -s and -r.\n");
00117         return AVERROR(EIO);
00118     }
00119 
00120     st = av_new_stream(s1, 0);
00121     if (!st) {
00122         return AVERROR(ENOMEM);
00123     }
00124     av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
00125 
00126     use_shm = XShmQueryExtension(dpy);
00127     av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not");
00128 
00129     if(use_shm) {
00130         int scr = XDefaultScreen(dpy);
00131         image = XShmCreateImage(dpy,
00132                                 DefaultVisual(dpy, scr),
00133                                 DefaultDepth(dpy, scr),
00134                                 ZPixmap,
00135                                 NULL,
00136                                 &x11grab->shminfo,
00137                                 ap->width, ap->height);
00138         x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
00139                                         image->bytes_per_line * image->height,
00140                                         IPC_CREAT|0777);
00141         if (x11grab->shminfo.shmid == -1) {
00142             av_log(s1, AV_LOG_ERROR, "Fatal: Can't get shared memory!\n");
00143             return AVERROR(ENOMEM);
00144         }
00145         x11grab->shminfo.shmaddr = image->data = shmat(x11grab->shminfo.shmid, 0, 0);
00146         x11grab->shminfo.readOnly = False;
00147 
00148         if (!XShmAttach(dpy, &x11grab->shminfo)) {
00149             av_log(s1, AV_LOG_ERROR, "Fatal: Failed to attach shared memory!\n");
00150             /* needs some better error subroutine :) */
00151             return AVERROR(EIO);
00152         }
00153     } else {
00154         image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
00155                           x_off,y_off,
00156                           ap->width,ap->height,
00157                           AllPlanes, ZPixmap);
00158     }
00159 
00160     switch (image->bits_per_pixel) {
00161     case 8:
00162         av_log (s1, AV_LOG_DEBUG, "8 bit palette\n");
00163         input_pixfmt = PIX_FMT_PAL8;
00164         break;
00165     case 16:
00166         if (       image->red_mask   == 0xf800 &&
00167                    image->green_mask == 0x07e0 &&
00168                    image->blue_mask  == 0x001f ) {
00169             av_log (s1, AV_LOG_DEBUG, "16 bit RGB565\n");
00170             input_pixfmt = PIX_FMT_RGB565;
00171         } else if (image->red_mask   == 0x7c00 &&
00172                    image->green_mask == 0x03e0 &&
00173                    image->blue_mask  == 0x001f ) {
00174             av_log(s1, AV_LOG_DEBUG, "16 bit RGB555\n");
00175             input_pixfmt = PIX_FMT_RGB555;
00176         } else {
00177             av_log(s1, AV_LOG_ERROR, "RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
00178             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);
00179             return AVERROR(EIO);
00180         }
00181         break;
00182     case 24:
00183         if (        image->red_mask   == 0xff0000 &&
00184                     image->green_mask == 0x00ff00 &&
00185                     image->blue_mask  == 0x0000ff ) {
00186             input_pixfmt = PIX_FMT_BGR24;
00187         } else if ( image->red_mask   == 0x0000ff &&
00188                     image->green_mask == 0x00ff00 &&
00189                     image->blue_mask  == 0xff0000 ) {
00190             input_pixfmt = PIX_FMT_RGB24;
00191         } else {
00192             av_log(s1, AV_LOG_ERROR,"rgb ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
00193             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);
00194             return AVERROR(EIO);
00195         }
00196         break;
00197     case 32:
00198 #if 0
00199         GetColorInfo (image, &c_info);
00200         if ( c_info.alpha_mask == 0xff000000 && image->green_mask == 0x0000ff00) {
00201             /* byte order is relevant here, not endianness
00202              * endianness is handled by avcodec, but atm no such thing
00203              * as having ABGR, instead of ARGB in a word. Since we
00204              * need this for Solaris/SPARC, but need to do the conversion
00205              * for every frame we do it outside of this loop, cf. below
00206              * this matches both ARGB32 and ABGR32 */
00207             input_pixfmt = PIX_FMT_ARGB32;
00208         }  else {
00209             av_log(s1, AV_LOG_ERROR,"image depth %i not supported ... aborting\n", image->bits_per_pixel);
00210             return AVERROR(EIO);
00211         }
00212 #endif
00213         input_pixfmt = PIX_FMT_RGB32;
00214         break;
00215     default:
00216         av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel);
00217         return -1;
00218     }
00219 
00220     x11grab->frame_size = ap->width * ap->height * image->bits_per_pixel/8;
00221     x11grab->dpy = dpy;
00222     x11grab->width = ap->width;
00223     x11grab->height = ap->height;
00224     x11grab->time_base  = ap->time_base;
00225     x11grab->time_frame = av_gettime() / av_q2d(ap->time_base);
00226     x11grab->x_off = x_off;
00227     x11grab->y_off = y_off;
00228     x11grab->image = image;
00229     x11grab->use_shm = use_shm;
00230     x11grab->mouse_warning_shown = 0;
00231 
00232     st->codec->codec_type = CODEC_TYPE_VIDEO;
00233     st->codec->codec_id = CODEC_ID_RAWVIDEO;
00234     st->codec->width = ap->width;
00235     st->codec->height = ap->height;
00236     st->codec->pix_fmt = input_pixfmt;
00237     st->codec->time_base = ap->time_base;
00238     st->codec->bit_rate = x11grab->frame_size * 1/av_q2d(ap->time_base) * 8;
00239 
00240     return 0;
00241 }

static int x11grab_read_packet ( AVFormatContext s1,
AVPacket pkt 
) [static]

Grabs a frame from x11 (public device demuxer API).

Parameters:
s1 Context from avformat core
pkt Packet holding the brabbed frame
Returns:
frame size in bytes

Definition at line 432 of file x11grab.c.

References av_gettime(), av_log(), AV_LOG_INFO, av_new_packet(), av_q2d(), AVERROR, AVPacket::data, x11_grab_s::dpy, x11_grab_s::frame_size, get_pointer_coordinates(), x11_grab_s::image, NULL, paint_mouse_pointer(), AVPacket::pts, s1, x11_grab_s::time_base, x11_grab_s::time_frame, x11_grab_s::use_shm, x11_grab_s::x_off, xget_zpixmap(), and x11_grab_s::y_off.

00433 {
00434     x11_grab_t *s = s1->priv_data;
00435     Display *dpy = s->dpy;
00436     XImage *image = s->image;
00437     int x_off = s->x_off;
00438     int y_off = s->y_off;
00439 
00440     int64_t curtime, delay;
00441     struct timespec ts;
00442 
00443     /* Calculate the time of the next frame */
00444     s->time_frame += INT64_C(1000000);
00445 
00446     /* wait based on the frame rate */
00447     for(;;) {
00448         curtime = av_gettime();
00449         delay = s->time_frame * av_q2d(s->time_base) - curtime;
00450         if (delay <= 0) {
00451             if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) {
00452                 s->time_frame += INT64_C(1000000);
00453             }
00454             break;
00455         }
00456         ts.tv_sec = delay / 1000000;
00457         ts.tv_nsec = (delay % 1000000) * 1000;
00458         nanosleep(&ts, NULL);
00459     }
00460 
00461     if (av_new_packet(pkt, s->frame_size) < 0) {
00462         return AVERROR(EIO);
00463     }
00464 
00465     pkt->pts = curtime;
00466 
00467     if(s->use_shm) {
00468         if (!XShmGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off, AllPlanes)) {
00469             av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n");
00470         }
00471     } else {
00472         if (!xget_zpixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off)) {
00473             av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n");
00474         }
00475     }
00476 
00477     {
00478         int pointer_x, pointer_y;
00479         get_pointer_coordinates(&pointer_x, &pointer_y, dpy, s1);
00480         paint_mouse_pointer(image, s, pointer_x, pointer_y);
00481     }
00482 
00483 
00484     /* XXX: avoid memcpy */
00485     memcpy(pkt->data, image->data, s->frame_size);
00486     return s->frame_size;
00487 }

static int xget_zpixmap ( Display *  dpy,
Drawable  d,
XImage *  image,
int  x,
int  y 
) [static]

Reads new data in the image structure.

Parameters:
dpy X11 display to grab from
d 
image Image where the grab will be put
x Top-Left grabbing rectangle horizontal coordinate
y Top-Left grabbing rectangle vertical coordinate
Returns:
0 if error, !0 if successful

Definition at line 388 of file x11grab.c.

Referenced by x11grab_read_packet().

00389 {
00390     xGetImageReply rep;
00391     xGetImageReq *req;
00392     long nbytes;
00393 
00394     if (!image) {
00395         return 0;
00396     }
00397 
00398     LockDisplay(dpy);
00399     GetReq(GetImage, req);
00400 
00401     /* First set up the standard stuff in the request */
00402     req->drawable = d;
00403     req->x = x;
00404     req->y = y;
00405     req->width = image->width;
00406     req->height = image->height;
00407     req->planeMask = (unsigned int)AllPlanes;
00408     req->format = ZPixmap;
00409 
00410     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.length) {
00411         UnlockDisplay(dpy);
00412         SyncHandle();
00413         return 0;
00414     }
00415 
00416     nbytes = (long)rep.length << 2;
00417     _XReadPad(dpy, image->data, nbytes);
00418 
00419     UnlockDisplay(dpy);
00420     SyncHandle();
00421     return 1;
00422 }


Variable Documentation

AVInputFormat x11_grab_device_demuxer

Initial value:

x11 grabber device demuxer declaration

Definition at line 519 of file x11grab.c.


Generated on Thu Dec 4 11:46:54 2008 for libextractor by  doxygen 1.5.1