Set the cut path properly when a non-default output path is specified
[atscap.git] / xtc_libvo.c
blobc2e3e6baf1f9bade33d620a9b5bc14f077dbff3f
1 /*
2 * video_out_x11.c
3 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
4 * Copyright (C) 2003 Regis Duchesne <hpreg@zoy.org>
5 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
7 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
8 * See http://libmpeg2.sourceforge.net/ for updates.
10 * mpeg2dec is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * mpeg2dec is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 /* December 2007 - Janary 2008, for xtscut 1.3.3 and later:
27 Edited some slight changes to make it work with xtscut.
28 Copyright (C) 2007-2008 <inkling@users.sourceforge.net>
32 typedef struct {
33 void * data;
34 int wait_completion;
35 XImage * ximage;
36 XvImage * xvimage;
37 } x11_frame_t;
39 typedef struct x11_instance_s {
40 vo_instance_t vo;
41 x11_frame_t frame[3];
42 int index;
43 int width;
44 int height;
45 Display * display;
46 Window window;
47 GC gc;
48 XVisualInfo vinfo;
49 XShmSegmentInfo shminfo;
50 int completion_type;
51 unsigned int adaptors;
52 XvAdaptorInfo * adaptorInfo;
53 XvPortID port;
54 int xv;
55 void (* teardown) (struct x11_instance_s * instance);
56 } x11_instance_t;
58 static int open_display (x11_instance_t * instance, int width, int height)
60 int major;
61 int minor;
62 Bool pixmaps;
63 XVisualInfo visualTemplate;
64 XVisualInfo * XvisualInfoTable;
65 XVisualInfo * XvisualInfo;
66 int number;
67 int i;
69 XGCValues gcValues;
71 WHOAMI;
73 instance->display = XOpenDisplay ( dispname );
74 if (! (instance->display)) {
75 fprintf (stderr, "Can't open display\n");
76 return 1;
78 xdisplay = instance->display;
80 if ( (0 == XShmQueryVersion ( instance->display,
81 &major,
82 &minor,
83 &pixmaps))
84 || (major < 1)
85 || ((major == 1) && (minor < 1)) )
87 fprintf (stderr, "No XShm extension\n");
88 return 1;
91 instance->completion_type =
92 XShmGetEventBase (instance->display) + ShmCompletion;
94 /* list truecolor visuals for the default screen */
95 #ifdef __cplusplus
96 visualTemplate.c_class = TrueColor;
97 #else
98 visualTemplate.class = TrueColor;
99 #endif
100 xscreen = visualTemplate.screen = DefaultScreen (instance->display);
102 XvisualInfoTable = XGetVisualInfo ( instance->display,
103 VisualScreenMask | VisualClassMask,
104 &visualTemplate,
105 &number );
106 if (XvisualInfoTable == NULL) {
107 fprintf (stderr, "No TrueColor visual available\n");
108 return 1;
111 /* find the visual with the highest depth */
112 XvisualInfo = XvisualInfoTable;
113 for (i = 1; i < number; i++)
114 if (XvisualInfoTable[i].depth > XvisualInfo->depth)
115 XvisualInfo = XvisualInfoTable + i;
117 instance->vinfo = *XvisualInfo;
118 XFree (XvisualInfoTable);
120 xbg = BlackPixel( xdisplay, xscreen );
121 xfg = WhitePixel( xdisplay, xscreen );
123 XGetWindowAttributes(xdisplay, DefaultRootWindow( xdisplay ), &xattr );
125 xbpp = xattr.depth;
126 // fprintf( stderr, "X bpp %d\n", xbpp );
127 xcolors = xcolors565;
128 if (24 == xbpp) xcolors = xcolors888;
129 if (32 == xbpp) xcolors = xcolors888;
131 // xbg = COLOR_F;
133 sattr.border_pixel = xfg;
134 sattr.background_pixel = xbg;
135 sattr.background_pixmap = None;
136 sattr.backing_store = Always;
137 sattr.event_mask = 0;
139 sattr.colormap =
140 XCreateColormap( instance->display,
141 RootWindow (instance->display, instance->vinfo.screen),
142 instance->vinfo.visual,
143 AllocNone );
144 /* create window with background pixel, border pixel and colormap */
145 sattrmask = 0
146 // | CWBorderPixel
147 // | CWBackPixel
148 | CWBackPixmap
149 | CWBackingStore
150 // | CWEventMask
151 // | CWColormap
154 #if 0
155 sattrmask = 0
156 | CWBorderPixel
157 | CWBackPixel
158 | CWColormap
161 sattrmask = 0
162 | CWBackPixmap
163 | CWBackingStore
164 | CWBorderPixel
165 | CWEventMask
166 | CWColormap
168 #endif
170 xprintf(stdout, "%s XCreateWindow: w %d h %d\n", WHO, vw.w, vw.h);
172 xwindow = instance->window =
173 XCreateWindow ( instance->display,
174 RootWindow (instance->display, instance->vinfo.screen),
175 xhint.x, /* x */
176 xhint.y, /* y */
177 xhint.width, /* w */
178 xhint.height, /* h */
179 0, /* border_width */
180 instance->vinfo.depth,
181 InputOutput,
182 instance->vinfo.visual,
183 sattrmask,
184 &sattr);
186 xgc = instance->gc = XCreateGC (instance->display,
187 instance->window,
189 &gcValues );
190 instance->adaptors = 0;
191 instance->adaptorInfo = NULL;
193 return 0;
196 static int shmerror = 0;
198 static int handle_error (Display * display, XErrorEvent * error)
200 shmerror = 1;
201 return 0;
204 static void * create_shm (x11_instance_t * instance, int size)
206 if (0 != arg_xmsg) WHOAMI;
208 instance->shminfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
209 if (instance->shminfo.shmid == -1)
210 goto error;
212 instance->shminfo.shmaddr = (char *) shmat (instance->shminfo.shmid, 0, 0);
213 if (instance->shminfo.shmaddr == (char *)-1)
214 goto error;
216 /* on linux the IPC_RMID only kicks off once everyone detaches the shm */
217 /* doing this early avoids shm leaks when we are interrupted. */
218 /* this would break the solaris port though :-/ */
219 /* shmctl (instance->shminfo.shmid, IPC_RMID, 0); */
221 /* XShmAttach fails on remote displays, so we have to catch this event */
223 XSync (instance->display, False);
224 XSetErrorHandler (handle_error);
226 instance->shminfo.readOnly = True;
227 if (! (XShmAttach (instance->display, &(instance->shminfo))))
228 shmerror = 1;
230 XSync (instance->display, False);
231 XSetErrorHandler (NULL);
232 if (shmerror) {
233 error:
234 fprintf (stderr, "Can't create shared memory\n");
235 if (instance->shminfo.shmid != -1) {
236 shmdt (instance->shminfo.shmaddr);
237 shmctl (instance->shminfo.shmid, IPC_RMID, 0);
239 return NULL;
242 return instance->shminfo.shmaddr;
245 static void destroy_shm (x11_instance_t * instance)
247 if (0 != arg_xmsg) WHOAMI;
249 XShmDetach (instance->display, &(instance->shminfo));
250 shmdt (instance->shminfo.shmaddr);
251 shmctl (instance->shminfo.shmid, IPC_RMID, 0);
255 static void x11_event (x11_instance_t * instance) /* XXXXXXXXXXX */
257 XEvent event;
258 char * addr;
259 int i;
261 if (0 != arg_xmsg) WHOAMI;
263 XNextEvent (instance->display, &event);
264 if (event.type == instance->completion_type) {
265 xprintf( stdout, "%s event.type %d\n", WHO, event.type);
267 addr = (instance->shminfo.shmaddr
268 + ((XShmCompletionEvent *)&event)->offset);
270 for (i = 0; i < 3; i++)
271 if (addr == instance->frame[i].data)
272 instance->frame[i].wait_completion = 0;
277 static void x11_start_fbuf (vo_instance_t * _instance,
278 uint8_t * const * buf, void * id)
281 x11_instance_t * instance = (x11_instance_t *) _instance;
282 x11_frame_t * frame = (x11_frame_t *) id;
284 if (0 != arg_xmsg) WHOAMI;
286 while (frame->wait_completion)
287 x11_event (instance);
290 static void x11_setup_fbuf (vo_instance_t * _instance,
291 uint8_t ** buf, void ** id)
294 x11_instance_t * instance = (x11_instance_t *) _instance;
296 if (0 != arg_xmsg) WHOAMI;
298 buf[0] = (uint8_t *) instance->frame[instance->index].data;
299 buf[1] = buf[2] = NULL;
300 *id = instance->frame + instance->index++;
303 static void x11_draw_frame (vo_instance_t * _instance,
304 uint8_t * const * buf, void * id)
306 x11_frame_t * frame;
307 x11_instance_t * instance;
309 if (0 != arg_xmsg) WHOAMI;
311 frame = (x11_frame_t *) id;
312 instance = (x11_instance_t *) _instance;
314 XShmPutImage (
315 instance->display,
316 instance->window,
317 instance->gc,
318 frame->ximage,
323 instance->width,
324 instance->height,
325 True
328 XFlush (instance->display);
329 frame->wait_completion = 1;
332 static int x11_alloc_frames (x11_instance_t * instance)
334 int size;
335 char * alloc;
336 int i;
338 if (0 != arg_xmsg) WHOAMI;
340 size = 0;
341 alloc = NULL;
342 for (i = 0; i < 3; i++) {
343 instance->frame[i].wait_completion = 0;
344 instance->frame[i].ximage =
345 XShmCreateImage (instance->display, instance->vinfo.visual,
346 instance->vinfo.depth, ZPixmap, NULL /* data */,
347 &(instance->shminfo),
348 instance->width, instance->height);
349 if (instance->frame[i].ximage == NULL) {
350 fprintf (stderr, "Can't create ximage\n");
351 return 1;
352 } else if (i == 0) {
353 size = (instance->frame[0].ximage->bytes_per_line *
354 instance->frame[0].ximage->height);
355 alloc = (char *) create_shm (instance, 3 * size);
356 if (alloc == NULL) {
357 XDestroyImage (instance->frame[i].ximage);
358 return 1;
360 } else if (size != (instance->frame[i].ximage->bytes_per_line *
361 instance->frame[i].ximage->height)) {
362 fprintf (stderr, "unexpected ximage data size\n");
363 return 1;
366 instance->frame[i].data = instance->frame[i].ximage->data = alloc;
367 alloc += size;
370 return 0;
373 static void x11_teardown (x11_instance_t * instance)
375 int i;
377 if (0 != arg_xmsg) WHOAMI;
379 for (i = 0; i < 3; i++) {
380 while (instance->frame[i].wait_completion)
381 x11_event (instance);
382 XDestroyImage (instance->frame[i].ximage);
384 destroy_shm (instance);
387 static void x11_close (vo_instance_t * _instance)
389 if (0 != arg_xmsg) WHOAMI;
391 x11_instance_t * instance = (x11_instance_t *) _instance;
393 if (instance->teardown != NULL)
394 instance->teardown (instance);
395 XFreeGC (instance->display, instance->gc);
396 XDestroyWindow (instance->display, instance->window);
397 if (instance->adaptors)
398 XvFreeAdaptorInfo (instance->adaptorInfo);
399 XCloseDisplay (instance->display);
400 free (instance);
403 static void xv_setup_fbuf (vo_instance_t * _instance,
404 uint8_t ** buf, void ** id)
406 if (0 != arg_xmsg) WHOAMI;
408 x11_instance_t * instance = (x11_instance_t *) _instance;
409 uint8_t * data;
411 data = (uint8_t *) instance->frame[instance->index].xvimage->data;
412 buf[0] = data + instance->frame[instance->index].xvimage->offsets[0];
413 buf[1] = data + instance->frame[instance->index].xvimage->offsets[2];
414 buf[2] = data + instance->frame[instance->index].xvimage->offsets[1];
415 *id = instance->frame + instance->index++;
418 static void xv_draw_frame (vo_instance_t * _instance,
419 uint8_t * const * buf, void * id)
421 x11_frame_t * frame = (x11_frame_t *) id;
422 x11_instance_t * instance = (x11_instance_t *) _instance;
424 if (0 != arg_xmsg) WHOAMI;
426 XvShmPutImage (
427 instance->display,
428 instance->port,
429 instance->window,
430 instance->gc,
431 frame->xvimage,
432 0, /* source x */
433 0, /* source y */
434 instance->width, /* source w */
435 instance->height, /* source h */
436 0, /* target x */
437 0, /* target y */
438 vw.w, /* target w */
439 vw.h, /* target h */
440 True
443 XFlush (instance->display);
444 frame->wait_completion = 1;
447 static int xv_check_fourcc (x11_instance_t * instance, XvPortID port,
448 int fourcc, const char * fourcc_str)
450 XvImageFormatValues * formatValues;
451 int formats;
452 int i;
454 if (0 != arg_xmsg) WHOAMI;
456 formatValues = XvListImageFormats (instance->display, port, &formats);
457 for (i = 0; i < formats; i++)
458 if ((formatValues[i].id == fourcc) &&
459 (! (strcmp (formatValues[i].guid, fourcc_str)))) {
460 XFree (formatValues);
461 return 0;
463 XFree (formatValues);
464 return 1;
467 static int xv_check_extension (x11_instance_t * instance,
468 int fourcc, const char * fourcc_str)
470 unsigned int i;
471 unsigned long j;
473 if (0 != arg_xmsg) WHOAMI;
475 if (!instance->adaptorInfo) {
476 unsigned int version;
477 unsigned int release;
478 unsigned int dummy;
480 if ((XvQueryExtension (instance->display, &version, &release,
481 &dummy, &dummy, &dummy) != Success) ||
482 (version < 2) || ((version == 2) && (release < 2))) {
483 fprintf (stderr, "No XVideo extension\n");
484 return 1;
487 XvQueryAdaptors (instance->display, instance->window,
488 &instance->adaptors, &instance->adaptorInfo);
491 for (i = 0; i < instance->adaptors; i++)
492 if (instance->adaptorInfo[i].type & XvImageMask)
493 for (j = 0; j < instance->adaptorInfo[i].num_ports; j++)
494 if ((! (xv_check_fourcc (instance,
495 instance->adaptorInfo[i].base_id + j,
496 fourcc, fourcc_str))) &&
497 (XvGrabPort (instance->display,
498 instance->adaptorInfo[i].base_id + j,
499 0) == Success)) {
500 instance->port = instance->adaptorInfo[i].base_id + j;
501 xprintf (stdout, "Found xv %s port\n", fourcc_str);
502 return 0;
505 fprintf (stderr, "Could not find XVideo %s port\n", fourcc_str);
506 return 1;
509 static int xv_alloc_frames (x11_instance_t * instance, int size,
510 int fourcc)
512 char * alloc;
513 int i = 0;
515 if (0 != arg_xmsg) WHOAMI;
517 alloc = (char *) create_shm (instance, 3 * size);
518 if (alloc == NULL)
519 return 1;
521 while (i < 3) {
522 instance->frame[i].wait_completion = 0;
523 instance->frame[i].xvimage =
524 XvShmCreateImage (instance->display, instance->port, fourcc,
525 alloc, instance->width, instance->height,
526 &(instance->shminfo));
527 instance->frame[i].data = alloc;
528 alloc += size;
529 if ((instance->frame[i].xvimage == NULL) ||
530 (instance->frame[i++].xvimage->data_size != size)) {
531 while (--i >= 0)
532 XFree (instance->frame[i].xvimage);
533 destroy_shm (instance);
534 return 1;
538 return 0;
541 static void xv_teardown (x11_instance_t * instance)
543 int i;
545 if (0 != arg_xmsg) WHOAMI;
547 for (i = 0; i < 3; i++) {
548 while (instance->frame[i].wait_completion)
549 x11_event (instance);
550 XFree (instance->frame[i].xvimage);
552 destroy_shm (instance);
553 XvUngrabPort (instance->display, instance->port, 0);
556 static int common_setup (vo_instance_t * _instance, unsigned int width,
557 unsigned int height, unsigned int chroma_width,
558 unsigned int chroma_height,
559 vo_setup_result_t * result)
561 x11_instance_t * instance = (x11_instance_t *) _instance;
563 if (0 != arg_xmsg) WHOAMI;
565 if (instance->display != NULL) {
566 /* Already setup, just adjust to the new size */
567 if (instance->teardown != NULL)
568 instance->teardown (instance);
569 // XResizeWindow (instance->display, instance->window, width, height);
570 XResizeWindow (instance->display, instance->window, vw.w, vw.h);
571 } else {
572 /* Not setup yet, do the full monty */
573 if (open_display (instance, width, height))
574 return 1;
575 XMapWindow (instance->display, instance->window);
577 instance->vo.setup_fbuf = NULL;
578 instance->vo.start_fbuf = NULL;
579 instance->vo.set_fbuf = NULL;
580 instance->vo.draw = NULL;
581 instance->vo.discard = NULL;
582 instance->vo.close = x11_close;
583 instance->width = width;
584 instance->height = height;
585 instance->index = 0;
586 instance->teardown = NULL;
587 result->convert = NULL;
589 if (instance->xv == 1 &&
590 (chroma_width == width >> 1) && (chroma_height == height >> 1) &&
591 !xv_check_extension (instance, FOURCC_YV12, "YV12") &&
592 // !xv_check_extension (instance, FOURCC_YV12, "I420") &&
593 !xv_alloc_frames (instance, 3 * width * height / 2, FOURCC_YV12)) {
594 instance->vo.setup_fbuf = xv_setup_fbuf;
595 instance->vo.start_fbuf = x11_start_fbuf;
596 instance->vo.draw = xv_draw_frame;
597 instance->teardown = xv_teardown;
598 } else if (instance->xv && (chroma_width == width >> 1) &&
599 !xv_check_extension (instance, FOURCC_UYVY, "UYVY") &&
600 !xv_alloc_frames (instance, 2 * width * height, FOURCC_UYVY)) {
601 instance->vo.setup_fbuf = x11_setup_fbuf;
602 instance->vo.start_fbuf = x11_start_fbuf;
603 instance->vo.draw = xv_draw_frame;
604 instance->teardown = xv_teardown;
605 result->convert = mpeg2convert_uyvy;
606 } else if (!x11_alloc_frames (instance)) {
607 int bpp;
609 instance->vo.setup_fbuf = x11_setup_fbuf;
610 instance->vo.start_fbuf = x11_start_fbuf;
611 instance->vo.draw = x11_draw_frame;
612 instance->teardown = x11_teardown;
614 #ifdef WORDS_BIGENDIAN
615 if (instance->frame[0].ximage->byte_order != MSBFirst) {
616 fprintf (stderr, "No support for non-native byte order\n");
617 return 1;
619 #else
620 if (instance->frame[0].ximage->byte_order != LSBFirst) {
621 fprintf (stderr, "No support for non-native byte order\n");
622 return 1;
624 #endif
627 * depth in X11 terminology land is the number of bits used to
628 * actually represent the colour.
630 * bpp in X11 land means how many bits in the frame buffer per
631 * pixel.
633 * ex. 15 bit color is 15 bit depth and 16 bpp. Also 24 bit
634 * color is 24 bit depth, but can be 24 bpp or 32 bpp.
636 * If we have blue in the lowest bit then "obviously" RGB
637 * (the guy who wrote this convention never heard of endianness ?)
640 bpp = ((instance->vinfo.depth == 24) ?
641 instance->frame[0].ximage->bits_per_pixel :
642 instance->vinfo.depth);
643 result->convert =
644 mpeg2convert_rgb (((instance->frame[0].ximage->blue_mask & 1) ?
645 MPEG2CONVERT_RGB : MPEG2CONVERT_BGR), bpp);
646 if (result->convert == NULL) {
647 fprintf (stderr, "%dbpp not supported\n", bpp);
648 return 1;
652 return 0;
655 static vo_instance_t * common_open (int xv)
657 x11_instance_t * instance;
659 if (0 != arg_xmsg) WHOAMI;
661 instance = (x11_instance_t *) malloc (sizeof (x11_instance_t));
663 if (instance == NULL)
664 return NULL;
666 instance->vo.setup = common_setup;
667 instance->vo.close = (void (*) (vo_instance_t *)) free;
668 instance->display = NULL;
669 instance->xv = xv;
670 return (vo_instance_t *) instance;
673 vo_instance_t * vo_x11_open (void)
675 if (0 != arg_xmsg) WHOAMI;
677 return common_open (0);
680 vo_instance_t * vo_xv_open (void)
682 if (0 != arg_xmsg) WHOAMI;
684 return common_open (1);
687 vo_instance_t * vo_xv2_open (void)
689 if (0 != arg_xmsg) WHOAMI;
691 return common_open (2);