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>
39 typedef struct x11_instance_s
{
49 XShmSegmentInfo shminfo
;
51 unsigned int adaptors
;
52 XvAdaptorInfo
* adaptorInfo
;
55 void (* teardown
) (struct x11_instance_s
* instance
);
58 static int open_display (x11_instance_t
* instance
, int width
, int height
)
63 XVisualInfo visualTemplate
;
64 XVisualInfo
* XvisualInfoTable
;
65 XVisualInfo
* XvisualInfo
;
73 instance
->display
= XOpenDisplay ( dispname
);
74 if (! (instance
->display
)) {
75 fprintf (stderr
, "Can't open display\n");
78 xdisplay
= instance
->display
;
80 if ( (0 == XShmQueryVersion ( instance
->display
,
85 || ((major
== 1) && (minor
< 1)) )
87 fprintf (stderr
, "No XShm extension\n");
91 instance
->completion_type
=
92 XShmGetEventBase (instance
->display
) + ShmCompletion
;
94 /* list truecolor visuals for the default screen */
96 visualTemplate
.c_class
= TrueColor
;
98 visualTemplate
.class = TrueColor
;
100 xscreen
= visualTemplate
.screen
= DefaultScreen (instance
->display
);
102 XvisualInfoTable
= XGetVisualInfo ( instance
->display
,
103 VisualScreenMask
| VisualClassMask
,
106 if (XvisualInfoTable
== NULL
) {
107 fprintf (stderr
, "No TrueColor visual available\n");
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
);
126 // fprintf( stderr, "X bpp %d\n", xbpp );
127 xcolors
= xcolors565
;
128 if (24 == xbpp
) xcolors
= xcolors888
;
129 if (32 == xbpp
) xcolors
= xcolors888
;
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;
140 XCreateColormap( instance
->display
,
141 RootWindow (instance
->display
, instance
->vinfo
.screen
),
142 instance
->vinfo
.visual
,
144 /* create window with background pixel, border pixel and colormap */
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
),
178 xhint
.height
, /* h */
179 0, /* border_width */
180 instance
->vinfo
.depth
,
182 instance
->vinfo
.visual
,
186 xgc
= instance
->gc
= XCreateGC (instance
->display
,
190 instance
->adaptors
= 0;
191 instance
->adaptorInfo
= NULL
;
196 static int shmerror
= 0;
198 static int handle_error (Display
* display
, XErrorEvent
* error
)
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)
212 instance
->shminfo
.shmaddr
= (char *) shmat (instance
->shminfo
.shmid
, 0, 0);
213 if (instance
->shminfo
.shmaddr
== (char *)-1)
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
))))
230 XSync (instance
->display
, False
);
231 XSetErrorHandler (NULL
);
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);
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 */
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
)
307 x11_instance_t
* instance
;
309 if (0 != arg_xmsg
) WHOAMI
;
311 frame
= (x11_frame_t
*) id
;
312 instance
= (x11_instance_t
*) _instance
;
328 XFlush (instance
->display
);
329 frame
->wait_completion
= 1;
332 static int x11_alloc_frames (x11_instance_t
* instance
)
338 if (0 != arg_xmsg
) WHOAMI
;
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");
353 size
= (instance
->frame
[0].ximage
->bytes_per_line
*
354 instance
->frame
[0].ximage
->height
);
355 alloc
= (char *) create_shm (instance
, 3 * size
);
357 XDestroyImage (instance
->frame
[i
].ximage
);
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");
366 instance
->frame
[i
].data
= instance
->frame
[i
].ximage
->data
= alloc
;
373 static void x11_teardown (x11_instance_t
* instance
)
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
);
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
;
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
;
434 instance
->width
, /* source w */
435 instance
->height
, /* source h */
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
;
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
);
463 XFree (formatValues
);
467 static int xv_check_extension (x11_instance_t
* instance
,
468 int fourcc
, const char * fourcc_str
)
473 if (0 != arg_xmsg
) WHOAMI
;
475 if (!instance
->adaptorInfo
) {
476 unsigned int version
;
477 unsigned int release
;
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");
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
,
500 instance
->port
= instance
->adaptorInfo
[i
].base_id
+ j
;
501 xprintf (stdout
, "Found xv %s port\n", fourcc_str
);
505 fprintf (stderr
, "Could not find XVideo %s port\n", fourcc_str
);
509 static int xv_alloc_frames (x11_instance_t
* instance
, int size
,
515 if (0 != arg_xmsg
) WHOAMI
;
517 alloc
= (char *) create_shm (instance
, 3 * size
);
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
;
529 if ((instance
->frame
[i
].xvimage
== NULL
) ||
530 (instance
->frame
[i
++].xvimage
->data_size
!= size
)) {
532 XFree (instance
->frame
[i
].xvimage
);
533 destroy_shm (instance
);
541 static void xv_teardown (x11_instance_t
* instance
)
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
);
572 /* Not setup yet, do the full monty */
573 if (open_display (instance
, width
, height
))
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
;
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
)) {
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");
620 if (instance
->frame
[0].ximage
->byte_order
!= LSBFirst
) {
621 fprintf (stderr
, "No support for non-native byte order\n");
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
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
);
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
);
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
)
666 instance
->vo
.setup
= common_setup
;
667 instance
->vo
.close
= (void (*) (vo_instance_t
*)) free
;
668 instance
->display
= NULL
;
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);