00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #ifdef LIBVO_X11
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <X11/Xlib.h>
00031 #include <X11/Xutil.h>
00032 #include <sys/ipc.h>
00033 #include <sys/shm.h>
00034 #include <X11/extensions/XShm.h>
00035 #include <inttypes.h>
00036
00037 int XShmGetEventBase (Display *);
00038
00039 #ifdef LIBVO_XV
00040 #include <string.h>
00041 #include <X11/extensions/Xvlib.h>
00042 #define FOURCC_YV12 0x32315659
00043 #endif
00044
00045 #include "video_out.h"
00046 #include "convert.h"
00047
00048 typedef struct {
00049 void * data;
00050 int wait_completion;
00051 XImage * ximage;
00052 #ifdef LIBVO_XV
00053 XvImage * xvimage;
00054 #endif
00055 } x11_frame_t;
00056
00057 typedef struct {
00058 vo_instance_t vo;
00059 x11_frame_t frame[3];
00060 int index;
00061 int width;
00062 int height;
00063 Display * display;
00064 Window window;
00065 GC gc;
00066 XVisualInfo vinfo;
00067 XShmSegmentInfo shminfo;
00068 int completion_type;
00069 #ifdef LIBVO_XV
00070 XvPortID port;
00071 #endif
00072 } x11_instance_t;
00073
00074 static int open_display (x11_instance_t * instance)
00075 {
00076 int major;
00077 int minor;
00078 Bool pixmaps;
00079 XVisualInfo visualTemplate;
00080 XVisualInfo * XvisualInfoTable;
00081 XVisualInfo * XvisualInfo;
00082 int number;
00083 int i;
00084 XSetWindowAttributes attr;
00085 XGCValues gcValues;
00086
00087 instance->display = XOpenDisplay (NULL);
00088 if (! (instance->display)) {
00089 fprintf (stderr, "Can not open display\n");
00090 return 1;
00091 }
00092
00093 if ((XShmQueryVersion (instance->display, &major, &minor,
00094 &pixmaps) == 0) ||
00095 (major < 1) || ((major == 1) && (minor < 1))) {
00096 fprintf (stderr, "No xshm extension\n");
00097 return 1;
00098 }
00099
00100 instance->completion_type =
00101 XShmGetEventBase (instance->display) + ShmCompletion;
00102
00103
00104 #ifdef __cplusplus
00105 visualTemplate.c_class = TrueColor;
00106 #else
00107 visualTemplate.class = TrueColor;
00108 #endif
00109 visualTemplate.screen = DefaultScreen (instance->display);
00110 XvisualInfoTable = XGetVisualInfo (instance->display,
00111 VisualScreenMask | VisualClassMask,
00112 &visualTemplate, &number);
00113 if (XvisualInfoTable == NULL) {
00114 fprintf (stderr, "No truecolor visual\n");
00115 return 1;
00116 }
00117
00118
00119 XvisualInfo = XvisualInfoTable;
00120 for (i = 1; i < number; i++)
00121 if (XvisualInfoTable[i].depth > XvisualInfo->depth)
00122 XvisualInfo = XvisualInfoTable + i;
00123
00124 instance->vinfo = *XvisualInfo;
00125 XFree (XvisualInfoTable);
00126
00127 attr.background_pixmap = None;
00128 attr.backing_store = NotUseful;
00129 attr.border_pixel = 0;
00130 attr.event_mask = 0;
00131
00132 attr.colormap = XCreateColormap (instance->display,
00133 RootWindow (instance->display,
00134 instance->vinfo.screen),
00135 instance->vinfo.visual, AllocNone);
00136 instance->window =
00137 XCreateWindow (instance->display,
00138 DefaultRootWindow (instance->display),
00139 0 , 0 , instance->width, instance->height,
00140 0 , instance->vinfo.depth,
00141 InputOutput, instance->vinfo.visual,
00142 (CWBackPixmap | CWBackingStore | CWBorderPixel |
00143 CWEventMask | CWColormap), &attr);
00144
00145 instance->gc = XCreateGC (instance->display, instance->window, 0,
00146 &gcValues);
00147
00148 return 0;
00149 }
00150
00151 static int shmerror = 0;
00152
00153 static int handle_error (Display * display, XErrorEvent * error)
00154 {
00155 shmerror = 1;
00156 return 0;
00157 }
00158
00159 static void * create_shm (x11_instance_t * instance, int size)
00160 {
00161 instance->shminfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
00162 if (instance->shminfo.shmid == -1)
00163 goto error;
00164
00165 instance->shminfo.shmaddr = (char *) shmat (instance->shminfo.shmid, 0, 0);
00166 if (instance->shminfo.shmaddr == (char *)-1)
00167 goto error;
00168
00169
00170
00171
00172
00173
00174
00175
00176 XSync (instance->display, False);
00177 XSetErrorHandler (handle_error);
00178
00179 instance->shminfo.readOnly = True;
00180 if (! (XShmAttach (instance->display, &(instance->shminfo))))
00181 shmerror = 1;
00182
00183 XSync (instance->display, False);
00184 XSetErrorHandler (NULL);
00185 if (shmerror) {
00186 error:
00187 fprintf (stderr, "cannot create shared memory\n");
00188 return NULL;
00189 }
00190
00191 return instance->shminfo.shmaddr;
00192 }
00193
00194 static void destroy_shm (x11_instance_t * instance)
00195 {
00196 XShmDetach (instance->display, &(instance->shminfo));
00197 shmdt (instance->shminfo.shmaddr);
00198 shmctl (instance->shminfo.shmid, IPC_RMID, 0);
00199 }
00200
00201 static void x11_event (x11_instance_t * instance)
00202 {
00203 XEvent event;
00204 char * addr;
00205 int i;
00206
00207 XNextEvent (instance->display, &event);
00208 if (event.type == instance->completion_type) {
00209 addr = (instance->shminfo.shmaddr +
00210 ((XShmCompletionEvent *)&event)->offset);
00211 for (i = 0; i < 3; i++)
00212 if (addr == instance->frame[i].data)
00213 instance->frame[i].wait_completion = 0;
00214 }
00215 }
00216
00217 static void x11_start_fbuf (vo_instance_t * _instance,
00218 uint8_t * const * buf, void * id)
00219 {
00220 x11_instance_t * instance = (x11_instance_t *) _instance;
00221 x11_frame_t * frame = (x11_frame_t *) id;
00222
00223 while (frame->wait_completion)
00224 x11_event (instance);
00225 }
00226
00227 static void x11_setup_fbuf (vo_instance_t * _instance,
00228 uint8_t ** buf, void ** id)
00229 {
00230 x11_instance_t * instance = (x11_instance_t *) _instance;
00231
00232 buf[0] = (uint8_t *) instance->frame[instance->index].data;
00233 buf[1] = buf[2] = NULL;
00234 *id = instance->frame + instance->index++;
00235 }
00236
00237 static void x11_draw_frame (vo_instance_t * _instance,
00238 uint8_t * const * buf, void * id)
00239 {
00240 x11_frame_t * frame;
00241 x11_instance_t * instance;
00242
00243 frame = (x11_frame_t *) id;
00244 instance = (x11_instance_t *) _instance;
00245
00246 XShmPutImage (instance->display, instance->window, instance->gc,
00247 frame->ximage, 0, 0, 0, 0, instance->width, instance->height,
00248 True);
00249 XFlush (instance->display);
00250 frame->wait_completion = 1;
00251 }
00252
00253 static int x11_alloc_frames (x11_instance_t * instance)
00254 {
00255 int size;
00256 char * alloc;
00257 int i;
00258
00259 size = 0;
00260 alloc = NULL;
00261 for (i = 0; i < 3; i++) {
00262 instance->frame[i].wait_completion = 0;
00263 instance->frame[i].ximage =
00264 XShmCreateImage (instance->display, instance->vinfo.visual,
00265 instance->vinfo.depth, ZPixmap, NULL ,
00266 &(instance->shminfo),
00267 instance->width, instance->height);
00268 if (instance->frame[i].ximage == NULL) {
00269 fprintf (stderr, "Cannot create ximage\n");
00270 return 1;
00271 } else if (i == 0) {
00272 size = (instance->frame[0].ximage->bytes_per_line *
00273 instance->frame[0].ximage->height);
00274 alloc = (char *) create_shm (instance, 3 * size);
00275 if (alloc == NULL)
00276 return 1;
00277 } else if (size != (instance->frame[0].ximage->bytes_per_line *
00278 instance->frame[0].ximage->height)) {
00279 fprintf (stderr, "unexpected ximage data size\n");
00280 return 1;
00281 }
00282
00283 instance->frame[i].data = instance->frame[i].ximage->data = alloc;
00284 alloc += size;
00285 }
00286 instance->index = 0;
00287 return 0;
00288 }
00289
00290 static void x11_close (vo_instance_t * _instance)
00291 {
00292 x11_instance_t * instance = (x11_instance_t *) _instance;
00293 int i;
00294
00295 for (i = 0; i < 3; i++) {
00296 while (instance->frame[i].wait_completion)
00297 x11_event (instance);
00298 XDestroyImage (instance->frame[i].ximage);
00299 }
00300 destroy_shm (instance);
00301 XFreeGC (instance->display, instance->gc);
00302 XDestroyWindow (instance->display, instance->window);
00303 XCloseDisplay (instance->display);
00304 }
00305
00306 #ifdef LIBVO_XV
00307 static void xv_setup_fbuf (vo_instance_t * _instance,
00308 uint8_t ** buf, void ** id)
00309 {
00310 x11_instance_t * instance = (x11_instance_t *) _instance;
00311 uint8_t * data;
00312
00313 data = (uint8_t *) instance->frame[instance->index].xvimage->data;
00314 buf[0] = data + instance->frame[instance->index].xvimage->offsets[0];
00315 buf[1] = data + instance->frame[instance->index].xvimage->offsets[2];
00316 buf[2] = data + instance->frame[instance->index].xvimage->offsets[1];
00317 *id = instance->frame + instance->index++;
00318 }
00319
00320 static void xv_draw_frame (vo_instance_t * _instance,
00321 uint8_t * const * buf, void * id)
00322 {
00323 x11_frame_t * frame = (x11_frame_t *) id;
00324 x11_instance_t * instance = (x11_instance_t *) _instance;
00325
00326 XvShmPutImage (instance->display, instance->port, instance->window,
00327 instance->gc, frame->xvimage, 0, 0,
00328 instance->width, instance->height, 0, 0,
00329 instance->width, instance->height, True);
00330 XFlush (instance->display);
00331 frame->wait_completion = 1;
00332 }
00333
00334 static int xv_check_yv12 (x11_instance_t * instance, XvPortID port)
00335 {
00336 XvImageFormatValues * formatValues;
00337 int formats;
00338 int i;
00339
00340 formatValues = XvListImageFormats (instance->display, port, &formats);
00341 for (i = 0; i < formats; i++)
00342 if ((formatValues[i].id == FOURCC_YV12) &&
00343 (! (strcmp (formatValues[i].guid, "YV12")))) {
00344 XFree (formatValues);
00345 return 0;
00346 }
00347 XFree (formatValues);
00348 return 1;
00349 }
00350
00351 static int xv_check_extension (x11_instance_t * instance)
00352 {
00353 unsigned int version;
00354 unsigned int release;
00355 unsigned int dummy;
00356 unsigned int adaptors;
00357 unsigned int i;
00358 unsigned long j;
00359 XvAdaptorInfo * adaptorInfo;
00360
00361 if ((XvQueryExtension (instance->display, &version, &release,
00362 &dummy, &dummy, &dummy) != Success) ||
00363 (version < 2) || ((version == 2) && (release < 2))) {
00364 fprintf (stderr, "No xv extension\n");
00365 return 1;
00366 }
00367
00368 XvQueryAdaptors (instance->display, instance->window, &adaptors,
00369 &adaptorInfo);
00370
00371 for (i = 0; i < adaptors; i++)
00372 if (adaptorInfo[i].type & XvImageMask)
00373 for (j = 0; j < adaptorInfo[i].num_ports; j++)
00374 if ((! (xv_check_yv12 (instance,
00375 adaptorInfo[i].base_id + j))) &&
00376 (XvGrabPort (instance->display, adaptorInfo[i].base_id + j,
00377 0) == Success)) {
00378 instance->port = adaptorInfo[i].base_id + j;
00379 XvFreeAdaptorInfo (adaptorInfo);
00380 return 0;
00381 }
00382
00383 XvFreeAdaptorInfo (adaptorInfo);
00384 fprintf (stderr, "Cannot find xv port\n");
00385 return 1;
00386 }
00387
00388 static int xv_alloc_frames (x11_instance_t * instance)
00389 {
00390 int size;
00391 char * alloc;
00392 int i;
00393
00394 size = instance->width * instance->height / 4;
00395 alloc = (char *) create_shm (instance, 18 * size);
00396 if (alloc == NULL)
00397 return 1;
00398
00399 for (i = 0; i < 3; i++) {
00400 instance->frame[i].wait_completion = 0;
00401 instance->frame[i].xvimage =
00402 XvShmCreateImage (instance->display, instance->port, FOURCC_YV12,
00403 alloc, instance->width, instance->height,
00404 &(instance->shminfo));
00405 if ((instance->frame[i].xvimage == NULL) ||
00406 (instance->frame[i].xvimage->data_size != 6 * size)) {
00407 fprintf (stderr, "Cannot create xvimage\n");
00408 return 1;
00409 }
00410 instance->frame[i].data = alloc;
00411 alloc += 6 * size;
00412 }
00413
00414 return 0;
00415 }
00416
00417 static void xv_close (vo_instance_t * _instance)
00418 {
00419 x11_instance_t * instance = (x11_instance_t *) _instance;
00420 int i;
00421
00422 for (i = 0; i < 3; i++) {
00423 while (instance->frame[i].wait_completion)
00424 x11_event (instance);
00425 XFree (instance->frame[i].xvimage);
00426 }
00427 destroy_shm (instance);
00428 XvUngrabPort (instance->display, instance->port, 0);
00429 XFreeGC (instance->display, instance->gc);
00430 XDestroyWindow (instance->display, instance->window);
00431 XCloseDisplay (instance->display);
00432 }
00433 #endif
00434
00435 static int common_setup (x11_instance_t * instance, int width, int height,
00436 vo_setup_result_t * result, int xv)
00437 {
00438 instance->vo.set_fbuf = NULL;
00439 instance->vo.discard = NULL;
00440 instance->vo.start_fbuf = x11_start_fbuf;
00441 instance->width = width;
00442 instance->height = height;
00443
00444 if (open_display (instance))
00445 return 1;
00446
00447 #ifdef LIBVO_XV
00448 if (xv && (! (xv_check_extension (instance)))) {
00449 if (xv_alloc_frames (instance))
00450 return 1;
00451 instance->vo.setup_fbuf = xv_setup_fbuf;
00452 instance->vo.draw = xv_draw_frame;
00453 instance->vo.close = xv_close;
00454 result->convert = NULL;
00455 } else
00456 #endif
00457 {
00458 if (x11_alloc_frames (instance))
00459 return 1;
00460 instance->vo.setup_fbuf = x11_setup_fbuf;
00461 instance->vo.draw = x11_draw_frame;
00462 instance->vo.close = x11_close;
00463
00464 #ifdef WORDS_BIGENDIAN
00465 if (instance->frame[0].ximage->byte_order != MSBFirst) {
00466 fprintf (stderr, "No support for non-native byte order\n");
00467 return 1;
00468 }
00469 #else
00470 if (instance->frame[0].ximage->byte_order != LSBFirst) {
00471 fprintf (stderr, "No support for non-native byte order\n");
00472 return 1;
00473 }
00474 #endif
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 result->convert =
00491 convert_rgb (((instance->frame[0].ximage->blue_mask & 1) ?
00492 CONVERT_RGB : CONVERT_BGR),
00493 ((instance->vinfo.depth == 24) ?
00494 instance->frame[0].ximage->bits_per_pixel :
00495 instance->vinfo.depth));
00496 }
00497
00498 XMapWindow (instance->display, instance->window);
00499
00500 return 0;
00501 }
00502
00503 static int x11_setup (vo_instance_t * instance, int width, int height,
00504 vo_setup_result_t * result)
00505 {
00506 return common_setup ((x11_instance_t *)instance, width, height, result, 0);
00507 }
00508
00509 vo_instance_t * vo_x11_open (void)
00510 {
00511 x11_instance_t * instance;
00512
00513 instance = (x11_instance_t *) malloc (sizeof (x11_instance_t));
00514 if (instance == NULL)
00515 return NULL;
00516
00517 instance->vo.setup = x11_setup;
00518 return (vo_instance_t *) instance;
00519 }
00520
00521 #ifdef LIBVO_XV
00522 static int xv_setup (vo_instance_t * instance, int width, int height,
00523 vo_setup_result_t * result)
00524 {
00525 return common_setup ((x11_instance_t *)instance, width, height, result, 1);
00526 }
00527
00528 vo_instance_t * vo_xv_open (void)
00529 {
00530 x11_instance_t * instance;
00531
00532 instance = (x11_instance_t *) malloc (sizeof (x11_instance_t));
00533 if (instance == NULL)
00534 return NULL;
00535
00536 instance->vo.setup = xv_setup;
00537 return (vo_instance_t *) instance;
00538 }
00539 #endif
00540 #endif