00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00038 #define _XOPEN_SOURCE 600
00039
00040 #include "config.h"
00041 #include "libavformat/avformat.h"
00042 #include <time.h>
00043 #include <X11/X.h>
00044 #include <X11/Xlib.h>
00045 #include <X11/Xlibint.h>
00046 #include <X11/Xproto.h>
00047 #include <X11/Xutil.h>
00048 #include <sys/shm.h>
00049 #include <X11/extensions/XShm.h>
00050 #include <X11/extensions/Xfixes.h>
00051
00055 struct x11_grab
00056 {
00057 int frame_size;
00058 AVRational time_base;
00059 int64_t time_frame;
00061 int height;
00062 int width;
00063 int x_off;
00064 int y_off;
00066 Display *dpy;
00067 XImage *image;
00068 int use_shm;
00069 XShmSegmentInfo shminfo;
00070 int nomouse;
00071 };
00072
00084 static int
00085 x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
00086 {
00087 struct x11_grab *x11grab = s1->priv_data;
00088 Display *dpy;
00089 AVStream *st = NULL;
00090 enum PixelFormat input_pixfmt;
00091 XImage *image;
00092 int x_off = 0;
00093 int y_off = 0;
00094 int use_shm;
00095 char *param, *offset;
00096
00097 param = av_strdup(s1->filename);
00098 offset = strchr(param, '+');
00099 if (offset) {
00100 sscanf(offset, "%d,%d", &x_off, &y_off);
00101 x11grab->nomouse= strstr(offset, "nomouse");
00102 *offset= 0;
00103 }
00104
00105 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);
00106
00107 dpy = XOpenDisplay(param);
00108 if(!dpy) {
00109 av_log(s1, AV_LOG_ERROR, "Could not open X display.\n");
00110 return AVERROR(EIO);
00111 }
00112
00113 if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) {
00114 av_log(s1, AV_LOG_ERROR, "AVParameters don't have video size and/or rate. Use -s and -r.\n");
00115 return AVERROR(EIO);
00116 }
00117
00118 st = av_new_stream(s1, 0);
00119 if (!st) {
00120 return AVERROR(ENOMEM);
00121 }
00122 av_set_pts_info(st, 64, 1, 1000000);
00123
00124 use_shm = XShmQueryExtension(dpy);
00125 av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not");
00126
00127 if(use_shm) {
00128 int scr = XDefaultScreen(dpy);
00129 image = XShmCreateImage(dpy,
00130 DefaultVisual(dpy, scr),
00131 DefaultDepth(dpy, scr),
00132 ZPixmap,
00133 NULL,
00134 &x11grab->shminfo,
00135 ap->width, ap->height);
00136 x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
00137 image->bytes_per_line * image->height,
00138 IPC_CREAT|0777);
00139 if (x11grab->shminfo.shmid == -1) {
00140 av_log(s1, AV_LOG_ERROR, "Fatal: Can't get shared memory!\n");
00141 return AVERROR(ENOMEM);
00142 }
00143 x11grab->shminfo.shmaddr = image->data = shmat(x11grab->shminfo.shmid, 0, 0);
00144 x11grab->shminfo.readOnly = False;
00145
00146 if (!XShmAttach(dpy, &x11grab->shminfo)) {
00147 av_log(s1, AV_LOG_ERROR, "Fatal: Failed to attach shared memory!\n");
00148
00149 return AVERROR(EIO);
00150 }
00151 } else {
00152 image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
00153 x_off,y_off,
00154 ap->width,ap->height,
00155 AllPlanes, ZPixmap);
00156 }
00157
00158 switch (image->bits_per_pixel) {
00159 case 8:
00160 av_log (s1, AV_LOG_DEBUG, "8 bit palette\n");
00161 input_pixfmt = PIX_FMT_PAL8;
00162 break;
00163 case 16:
00164 if ( image->red_mask == 0xf800 &&
00165 image->green_mask == 0x07e0 &&
00166 image->blue_mask == 0x001f ) {
00167 av_log (s1, AV_LOG_DEBUG, "16 bit RGB565\n");
00168 input_pixfmt = PIX_FMT_RGB565;
00169 } else if (image->red_mask == 0x7c00 &&
00170 image->green_mask == 0x03e0 &&
00171 image->blue_mask == 0x001f ) {
00172 av_log(s1, AV_LOG_DEBUG, "16 bit RGB555\n");
00173 input_pixfmt = PIX_FMT_RGB555;
00174 } else {
00175 av_log(s1, AV_LOG_ERROR, "RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
00176 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);
00177 return AVERROR(EIO);
00178 }
00179 break;
00180 case 24:
00181 if ( image->red_mask == 0xff0000 &&
00182 image->green_mask == 0x00ff00 &&
00183 image->blue_mask == 0x0000ff ) {
00184 input_pixfmt = PIX_FMT_BGR24;
00185 } else if ( image->red_mask == 0x0000ff &&
00186 image->green_mask == 0x00ff00 &&
00187 image->blue_mask == 0xff0000 ) {
00188 input_pixfmt = PIX_FMT_RGB24;
00189 } else {
00190 av_log(s1, AV_LOG_ERROR,"rgb ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
00191 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);
00192 return AVERROR(EIO);
00193 }
00194 break;
00195 case 32:
00196 #if 0
00197 GetColorInfo (image, &c_info);
00198 if ( c_info.alpha_mask == 0xff000000 && image->green_mask == 0x0000ff00) {
00199
00200
00201
00202
00203
00204
00205 input_pixfmt = PIX_FMT_ARGB32;
00206 } else {
00207 av_log(s1, AV_LOG_ERROR,"image depth %i not supported ... aborting\n", image->bits_per_pixel);
00208 return AVERROR(EIO);
00209 }
00210 #endif
00211 input_pixfmt = PIX_FMT_RGB32;
00212 break;
00213 default:
00214 av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel);
00215 return -1;
00216 }
00217
00218 x11grab->frame_size = ap->width * ap->height * image->bits_per_pixel/8;
00219 x11grab->dpy = dpy;
00220 x11grab->width = ap->width;
00221 x11grab->height = ap->height;
00222 x11grab->time_base = ap->time_base;
00223 x11grab->time_frame = av_gettime() / av_q2d(ap->time_base);
00224 x11grab->x_off = x_off;
00225 x11grab->y_off = y_off;
00226 x11grab->image = image;
00227 x11grab->use_shm = use_shm;
00228
00229 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00230 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00231 st->codec->width = ap->width;
00232 st->codec->height = ap->height;
00233 st->codec->pix_fmt = input_pixfmt;
00234 st->codec->time_base = ap->time_base;
00235 st->codec->bit_rate = x11grab->frame_size * 1/av_q2d(ap->time_base) * 8;
00236
00237 return 0;
00238 }
00239
00249 static void
00250 paint_mouse_pointer(XImage *image, struct x11_grab *s)
00251 {
00252 int x_off = s->x_off;
00253 int y_off = s->y_off;
00254 int width = s->width;
00255 int height = s->height;
00256 Display *dpy = s->dpy;
00257 XFixesCursorImage *xcim;
00258 int x, y;
00259 int line, column;
00260 int to_line, to_column;
00261 int image_addr, xcim_addr;
00262
00263 xcim = XFixesGetCursorImage(dpy);;
00264
00265 x = xcim->x - xcim->xhot;
00266 y = xcim->y - xcim->yhot;
00267
00268 to_line = FFMIN((y + xcim->height), (height + y_off));
00269 to_column = FFMIN((x + xcim->width), (width + x_off));
00270
00271 for (line = FFMAX(y, y_off); line < to_line; line++) {
00272 for (column = FFMAX(x, x_off); column < to_column; column++) {
00273 xcim_addr = (line - y) * xcim->width + column - x;
00274
00275 if ((unsigned char)(xcim->pixels[xcim_addr] >> 24) != 0) {
00276 image_addr = ((line - y_off) * width + column - x_off) * 4;
00277
00278 image->data[image_addr] = (unsigned char)(xcim->pixels[xcim_addr] >> 0);
00279 image->data[image_addr+1] = (unsigned char)(xcim->pixels[xcim_addr] >> 8);
00280 image->data[image_addr+2] = (unsigned char)(xcim->pixels[xcim_addr] >> 16);
00281 }
00282 }
00283 }
00284
00285 XFree(xcim);
00286 xcim = NULL;
00287 }
00288
00289
00300 static int
00301 xget_zpixmap(Display *dpy, Drawable d, XImage *image, int x, int y)
00302 {
00303 xGetImageReply rep;
00304 xGetImageReq *req;
00305 long nbytes;
00306
00307 if (!image) {
00308 return 0;
00309 }
00310
00311 LockDisplay(dpy);
00312 GetReq(GetImage, req);
00313
00314
00315 req->drawable = d;
00316 req->x = x;
00317 req->y = y;
00318 req->width = image->width;
00319 req->height = image->height;
00320 req->planeMask = (unsigned int)AllPlanes;
00321 req->format = ZPixmap;
00322
00323 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.length) {
00324 UnlockDisplay(dpy);
00325 SyncHandle();
00326 return 0;
00327 }
00328
00329 nbytes = (long)rep.length << 2;
00330 _XReadPad(dpy, image->data, nbytes);
00331
00332 UnlockDisplay(dpy);
00333 SyncHandle();
00334 return 1;
00335 }
00336
00344 static int
00345 x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
00346 {
00347 struct x11_grab *s = s1->priv_data;
00348 Display *dpy = s->dpy;
00349 XImage *image = s->image;
00350 int x_off = s->x_off;
00351 int y_off = s->y_off;
00352
00353 int64_t curtime, delay;
00354 struct timespec ts;
00355
00356
00357 s->time_frame += INT64_C(1000000);
00358
00359
00360 for(;;) {
00361 curtime = av_gettime();
00362 delay = s->time_frame * av_q2d(s->time_base) - curtime;
00363 if (delay <= 0) {
00364 if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) {
00365 s->time_frame += INT64_C(1000000);
00366 }
00367 break;
00368 }
00369 ts.tv_sec = delay / 1000000;
00370 ts.tv_nsec = (delay % 1000000) * 1000;
00371 nanosleep(&ts, NULL);
00372 }
00373
00374 if (av_new_packet(pkt, s->frame_size) < 0) {
00375 return AVERROR(EIO);
00376 }
00377
00378 pkt->pts = curtime;
00379
00380 if(s->use_shm) {
00381 if (!XShmGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off, AllPlanes)) {
00382 av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n");
00383 }
00384 } else {
00385 if (!xget_zpixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off)) {
00386 av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n");
00387 }
00388 }
00389
00390 if(!s->nomouse){
00391 paint_mouse_pointer(image, s);
00392 }
00393
00394
00395
00396 memcpy(pkt->data, image->data, s->frame_size);
00397 return s->frame_size;
00398 }
00399
00406 static int
00407 x11grab_read_close(AVFormatContext *s1)
00408 {
00409 struct x11_grab *x11grab = s1->priv_data;
00410
00411
00412 if (x11grab->use_shm) {
00413 XShmDetach(x11grab->dpy, &x11grab->shminfo);
00414 shmdt(x11grab->shminfo.shmaddr);
00415 shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
00416 }
00417
00418
00419 if (x11grab->image) {
00420 XDestroyImage(x11grab->image);
00421 x11grab->image = NULL;
00422 }
00423
00424
00425 XCloseDisplay(x11grab->dpy);
00426 return 0;
00427 }
00428
00430 AVInputFormat x11_grab_device_demuxer =
00431 {
00432 "x11grab",
00433 NULL_IF_CONFIG_SMALL("X11grab"),
00434 sizeof(struct x11_grab),
00435 NULL,
00436 x11grab_read_header,
00437 x11grab_read_packet,
00438 x11grab_read_close,
00439 .flags = AVFMT_NOFILE,
00440 };