4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 // Number of buffers _FOR_DOUBLEBUFFERING_MODE_
22 // Use option -double to enable double buffering! (default: single buffer)
44 #include "video_out.h"
45 #include "video_out_internal.h"
49 #include <X11/Xutil.h>
52 #include "x11_common.h"
54 #include "fastmemcpy.h"
58 #include "subopt-helper.h"
60 #include "input/input.h"
63 #include "gui/interface.h"
66 #include "libavutil/common.h"
68 static const vo_info_t info
= {
71 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
75 const LIBVO_EXTERN(xv
)
79 #include <X11/extensions/XShm.h>
81 static XShmSegmentInfo Shminfo
[NUM_BUFFERS
];
82 static int Shmem_Flag
;
85 // Note: depends on the inclusion of X11/extensions/XShm.h
86 #include <X11/extensions/Xv.h>
87 #include <X11/extensions/Xvlib.h>
89 // FIXME: dynamically allocate this stuff
90 static void allocate_xvimage(int);
91 static unsigned int ver
, rel
, req
, ev
, err
;
92 static unsigned int formats
, adaptors
, xv_format
;
93 static XvAdaptorInfo
*ai
= NULL
;
94 static XvImageFormatValues
*fo
=NULL
;
96 static int current_buf
= 0;
97 static int current_ip_buf
= 0;
98 static int num_buffers
= 1; // default
99 static int visible_buf
= -1; // -1 means: no buffer was drawn yet
100 static XvImage
*xvimage
[NUM_BUFFERS
];
103 static uint32_t image_width
;
104 static uint32_t image_height
;
105 static uint32_t image_format
;
107 static int int_pause
;
109 static uint32_t drwX
, drwY
;
110 static uint32_t max_width
= 0, max_height
= 0; // zero means: not set
112 static void (*draw_alpha_fnc
) (int x0
, int y0
, int w
, int h
,
113 unsigned char *src
, unsigned char *srca
,
116 static void draw_alpha_yv12(int x0
, int y0
, int w
, int h
,
117 unsigned char *src
, unsigned char *srca
,
120 x0
+= image_width
* (vo_panscan_x
>> 1) / (vo_dwidth
+ vo_panscan_x
);
121 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
,
122 xvimage
[current_buf
]->data
+
123 xvimage
[current_buf
]->offsets
[0] +
124 xvimage
[current_buf
]->pitches
[0] * y0
+ x0
,
125 xvimage
[current_buf
]->pitches
[0]);
128 static void draw_alpha_yuy2(int x0
, int y0
, int w
, int h
,
129 unsigned char *src
, unsigned char *srca
,
132 x0
+= image_width
* (vo_panscan_x
>> 1) / (vo_dwidth
+ vo_panscan_x
);
133 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
134 xvimage
[current_buf
]->data
+
135 xvimage
[current_buf
]->offsets
[0] +
136 xvimage
[current_buf
]->pitches
[0] * y0
+ 2 * x0
,
137 xvimage
[current_buf
]->pitches
[0]);
140 static void draw_alpha_uyvy(int x0
, int y0
, int w
, int h
,
141 unsigned char *src
, unsigned char *srca
,
144 x0
+= image_width
* (vo_panscan_x
>> 1) / (vo_dwidth
+ vo_panscan_x
);
145 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
146 xvimage
[current_buf
]->data
+
147 xvimage
[current_buf
]->offsets
[0] +
148 xvimage
[current_buf
]->pitches
[0] * y0
+ 2 * x0
+ 1,
149 xvimage
[current_buf
]->pitches
[0]);
152 static void draw_alpha_null(int x0
, int y0
, int w
, int h
,
153 unsigned char *src
, unsigned char *srca
,
159 static void deallocate_xvimage(int foo
);
162 * connect to server, create and map window,
163 * allocate colors and (shared) memory
165 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
166 uint32_t d_height
, uint32_t flags
, char *title
,
170 XSetWindowAttributes xswa
;
171 XWindowAttributes attribs
;
172 unsigned long xswamask
;
176 int vm
= flags
& VOFLAG_MODESWITCHING
;
179 image_height
= height
;
181 image_format
= format
;
183 if ((max_width
!= 0 && max_height
!= 0) &&
184 (image_width
> max_width
|| image_height
> max_height
))
186 mp_msg( MSGT_VO
, MSGL_ERR
, MSGTR_VO_XV_ImagedimTooHigh
,
187 image_width
, image_height
, max_width
, max_height
);
195 vo_doublebuffering
? (vo_directrendering
? NUM_BUFFERS
: 2) : 1;
197 /* check image formats */
202 for (i
= 0; i
< formats
; i
++)
204 mp_msg(MSGT_VO
, MSGL_V
,
205 "Xvideo image format: 0x%x (%4.4s) %s\n", fo
[i
].id
,
207 (fo
[i
].format
== XvPacked
) ? "packed" : "planar");
208 if (fo
[i
].id
== format
)
209 xv_format
= fo
[i
].id
;
217 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize the window
227 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
),
229 depth
= attribs
.depth
;
230 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
232 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
234 xswa
.background_pixel
= 0;
235 if (xv_ck_info
.method
== CK_METHOD_BACKGROUND
)
237 xswa
.background_pixel
= xv_colorkey
;
239 xswa
.border_pixel
= 0;
240 xswamask
= CWBackPixel
| CWBorderPixel
;
242 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
, vo_dwidth
, vo_dheight
,
243 flags
, CopyFromParent
, "xv", title
);
244 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
249 /* Grab the mouse pointer in our window */
251 XGrabPointer(mDisplay
, vo_window
, True
, 0,
252 GrabModeAsync
, GrabModeAsync
,
253 vo_window
, None
, CurrentTime
);
254 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
259 mp_msg(MSGT_VO
, MSGL_V
, "using Xvideo port %d for hw scaling\n",
267 draw_alpha_fnc
= draw_alpha_yv12
;
271 draw_alpha_fnc
= draw_alpha_yuy2
;
274 draw_alpha_fnc
= draw_alpha_uyvy
;
277 draw_alpha_fnc
= draw_alpha_null
;
281 for (current_buf
= 0; current_buf
< num_buffers
; ++current_buf
)
282 deallocate_xvimage(current_buf
);
284 for (current_buf
= 0; current_buf
< num_buffers
; ++current_buf
)
285 allocate_xvimage(current_buf
);
290 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0) vo_fs
= 1;
291 vo_calc_drwXY(&drwX
, &drwY
);
295 vo_xv_draw_colorkey(drwX
- (vo_panscan_x
>> 1),
296 drwY
- (vo_panscan_y
>> 1),
297 vo_dwidth
+ vo_panscan_x
- 1,
298 vo_dheight
+ vo_panscan_y
- 1);
300 mp_msg(MSGT_VO
, MSGL_V
, "[xv] dx: %d dy: %d dw: %d dh: %d\n", drwX
,
301 drwY
, vo_dwidth
, vo_dheight
);
306 static void allocate_xvimage(int foo
)
309 * allocate XvImages. FIXME: no error checking, without
310 * mit-shm this will bomb... trzing to fix ::atmos
313 if (mLocalDisplay
&& XShmQueryExtension(mDisplay
))
318 mp_msg(MSGT_VO
, MSGL_INFO
,
319 MSGTR_LIBVO_XV_SharedMemoryNotSupported
);
324 (XvImage
*) XvShmCreateImage(mDisplay
, xv_port
, xv_format
,
325 NULL
, image_width
, image_height
,
329 shmget(IPC_PRIVATE
, xvimage
[foo
]->data_size
, IPC_CREAT
| 0777);
330 Shminfo
[foo
].shmaddr
= (char *) shmat(Shminfo
[foo
].shmid
, 0, 0);
331 Shminfo
[foo
].readOnly
= False
;
333 xvimage
[foo
]->data
= Shminfo
[foo
].shmaddr
;
334 XShmAttach(mDisplay
, &Shminfo
[foo
]);
335 XSync(mDisplay
, False
);
336 shmctl(Shminfo
[foo
].shmid
, IPC_RMID
, 0);
341 (XvImage
*) XvCreateImage(mDisplay
, xv_port
, xv_format
, NULL
,
342 image_width
, image_height
);
343 xvimage
[foo
]->data
= malloc(xvimage
[foo
]->data_size
);
344 XSync(mDisplay
, False
);
346 memset(xvimage
[foo
]->data
, 128, xvimage
[foo
]->data_size
);
350 static void deallocate_xvimage(int foo
)
355 XShmDetach(mDisplay
, &Shminfo
[foo
]);
356 shmdt(Shminfo
[foo
].shmaddr
);
360 free(xvimage
[foo
]->data
);
364 XSync(mDisplay
, False
);
368 static inline void put_xvimage( XvImage
* xvi
)
373 XvShmPutImage(mDisplay
, xv_port
, vo_window
, vo_gc
,
374 xvi
, 0, 0, image_width
,
375 image_height
, drwX
- (vo_panscan_x
>> 1),
376 drwY
- (vo_panscan_y
>> 1), vo_dwidth
+ vo_panscan_x
,
377 vo_dheight
+ vo_panscan_y
,
382 XvPutImage(mDisplay
, xv_port
, vo_window
, vo_gc
,
383 xvi
, 0, 0, image_width
, image_height
,
384 drwX
- (vo_panscan_x
>> 1), drwY
- (vo_panscan_y
>> 1),
385 vo_dwidth
+ vo_panscan_x
,
386 vo_dheight
+ vo_panscan_y
);
390 static void check_events(void)
392 int e
= vo_x11_check_events(mDisplay
);
394 if (e
& VO_EVENT_RESIZE
)
396 vo_calc_drwXY(&drwX
, &drwY
);
399 if (e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
)
401 vo_xv_draw_colorkey(drwX
- (vo_panscan_x
>> 1),
402 drwY
- (vo_panscan_y
>> 1),
403 vo_dwidth
+ vo_panscan_x
- 1,
404 vo_dheight
+ vo_panscan_y
- 1);
407 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && int_pause
)
409 /* did we already draw a buffer */
410 if ( visible_buf
!= -1 )
412 /* redraw the last visible buffer */
413 put_xvimage( xvimage
[visible_buf
] );
418 static void draw_osd(void)
420 vo_draw_text(image_width
-
421 image_width
* vo_panscan_x
/ (vo_dwidth
+ vo_panscan_x
),
422 image_height
, draw_alpha_fnc
);
425 static void flip_page(void)
427 put_xvimage( xvimage
[current_buf
] );
429 /* remember the currently visible buffer */
430 visible_buf
= current_buf
;
435 vo_directrendering
? 0 : ((current_buf
+ 1) % num_buffers
);
438 XSync(mDisplay
, False
);
442 static int draw_slice(uint8_t * image
[], int stride
[], int w
, int h
,
447 dst
= xvimage
[current_buf
]->data
+ xvimage
[current_buf
]->offsets
[0] +
448 xvimage
[current_buf
]->pitches
[0] * y
+ x
;
449 memcpy_pic(dst
, image
[0], w
, h
, xvimage
[current_buf
]->pitches
[0],
457 dst
= xvimage
[current_buf
]->data
+ xvimage
[current_buf
]->offsets
[1] +
458 xvimage
[current_buf
]->pitches
[1] * y
+ x
;
459 if (image_format
!= IMGFMT_YV12
)
460 memcpy_pic(dst
, image
[1], w
, h
, xvimage
[current_buf
]->pitches
[1],
463 memcpy_pic(dst
, image
[2], w
, h
, xvimage
[current_buf
]->pitches
[1],
466 dst
= xvimage
[current_buf
]->data
+ xvimage
[current_buf
]->offsets
[2] +
467 xvimage
[current_buf
]->pitches
[2] * y
+ x
;
468 if (image_format
== IMGFMT_YV12
)
469 memcpy_pic(dst
, image
[1], w
, h
, xvimage
[current_buf
]->pitches
[1],
472 memcpy_pic(dst
, image
[2], w
, h
, xvimage
[current_buf
]->pitches
[1],
478 static int draw_frame(uint8_t * src
[])
483 static uint32_t draw_image(mp_image_t
* mpi
)
485 if (mpi
->flags
& MP_IMGFLAG_DIRECT
)
488 current_buf
= (int) (mpi
->priv
); // hack!
491 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
492 return VO_TRUE
; // done
493 if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
495 draw_slice(mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, 0, 0);
498 if (mpi
->flags
& MP_IMGFLAG_YUV
)
501 memcpy_pic(xvimage
[current_buf
]->data
+
502 xvimage
[current_buf
]->offsets
[0], mpi
->planes
[0],
503 mpi
->w
* (mpi
->bpp
/ 8), mpi
->h
,
504 xvimage
[current_buf
]->pitches
[0], mpi
->stride
[0]);
507 return VO_FALSE
; // not (yet) supported
510 static uint32_t get_image(mp_image_t
* mpi
)
512 int buf
= current_buf
; // we shouldn't change current_buf unless we do DR!
514 if (mpi
->type
== MP_IMGTYPE_STATIC
&& num_buffers
> 1)
515 return VO_FALSE
; // it is not static
516 if (mpi
->imgfmt
!= image_format
)
517 return VO_FALSE
; // needs conversion :(
518 // if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram
519 if (mpi
->flags
& MP_IMGFLAG_READABLE
&&
520 (mpi
->type
== MP_IMGTYPE_IPB
|| mpi
->type
== MP_IMGTYPE_IP
))
522 // reference (I/P) frame of IP or IPB:
524 return VO_FALSE
; // not enough
526 // for IPB with 2 buffers we can DR only one of the 2 P frames:
527 if (mpi
->type
== MP_IMGTYPE_IPB
&& num_buffers
< 3
530 buf
= current_ip_buf
;
531 if (mpi
->type
== MP_IMGTYPE_IPB
)
532 ++buf
; // preserve space for B
534 if (mpi
->height
> xvimage
[buf
]->height
)
535 return VO_FALSE
; //buffer to small
536 if (mpi
->width
* (mpi
->bpp
/ 8) > xvimage
[buf
]->pitches
[0])
537 return VO_FALSE
; //buffer to small
538 if ((mpi
->flags
& (MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_ACCEPT_WIDTH
))
539 || (mpi
->width
* (mpi
->bpp
/ 8) == xvimage
[buf
]->pitches
[0]))
543 xvimage
[current_buf
]->data
+ xvimage
[current_buf
]->offsets
[0];
544 mpi
->stride
[0] = xvimage
[current_buf
]->pitches
[0];
545 mpi
->width
= mpi
->stride
[0] / (mpi
->bpp
/ 8);
546 if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
548 if (mpi
->flags
& MP_IMGFLAG_SWAPPED
)
552 xvimage
[current_buf
]->data
+
553 xvimage
[current_buf
]->offsets
[1];
555 xvimage
[current_buf
]->data
+
556 xvimage
[current_buf
]->offsets
[2];
557 mpi
->stride
[1] = xvimage
[current_buf
]->pitches
[1];
558 mpi
->stride
[2] = xvimage
[current_buf
]->pitches
[2];
563 xvimage
[current_buf
]->data
+
564 xvimage
[current_buf
]->offsets
[2];
566 xvimage
[current_buf
]->data
+
567 xvimage
[current_buf
]->offsets
[1];
568 mpi
->stride
[1] = xvimage
[current_buf
]->pitches
[2];
569 mpi
->stride
[2] = xvimage
[current_buf
]->pitches
[1];
572 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
573 mpi
->priv
= (void *) current_buf
;
574 // printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n");
580 static int query_format(uint32_t format
)
583 int flag
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_ACCEPT_STRIDE
; // FIXME! check for DOWN
585 /* check image formats */
586 for (i
= 0; i
< formats
; i
++)
588 if (fo
[i
].id
== format
)
589 return flag
; //xv_format = fo[i].id;
594 static void uninit(void)
598 if (!vo_config_count
)
601 XvFreeAdaptorInfo(ai
);
607 for (i
= 0; i
< num_buffers
; i
++)
608 deallocate_xvimage(i
);
612 mp_input_rm_event_fd(ConnectionNumber(mDisplay
));
616 static int preinit(const char *arg
)
621 strarg_t ck_src_arg
= { 0, NULL
};
622 strarg_t ck_method_arg
= { 0, NULL
};
627 /* name arg type arg var test */
628 { "port", OPT_ARG_INT
, &xv_port
, (opt_test_f
)int_pos
},
629 { "adaptor", OPT_ARG_INT
, &xv_adaptor
, (opt_test_f
)int_non_neg
},
630 { "ck", OPT_ARG_STR
, &ck_src_arg
, xv_test_ck
},
631 { "ck-method", OPT_ARG_STR
, &ck_method_arg
, xv_test_ckm
},
637 /* parse suboptions */
638 if ( subopt_parse( arg
, subopts
) != 0 )
643 /* modify colorkey settings according to the given options */
644 xv_setup_colorkeyhandling( ck_method_arg
.str
, ck_src_arg
.str
);
649 /* check for Xvideo extension */
650 if (Success
!= XvQueryExtension(mDisplay
, &ver
, &rel
, &req
, &ev
, &err
))
652 mp_msg(MSGT_VO
, MSGL_ERR
,
653 MSGTR_LIBVO_XV_XvNotSupportedByX11
);
657 /* check for Xvideo support */
659 XvQueryAdaptors(mDisplay
, DefaultRootWindow(mDisplay
), &adaptors
,
662 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed
);
671 for (port_found
= 0, i
= 0; !port_found
&& i
< adaptors
; i
++)
673 if ((ai
[i
].type
& XvInputMask
) && (ai
[i
].type
& XvImageMask
))
675 for (xv_p
= ai
[i
].base_id
;
676 xv_p
< ai
[i
].base_id
+ ai
[i
].num_ports
; ++xv_p
)
688 if (XvGrabPort(mDisplay
, xv_port
, CurrentTime
))
692 mp_msg(MSGT_VO
, MSGL_WARN
,
693 MSGTR_LIBVO_XV_InvalidPortParameter
);
698 for (i
= 0; i
< adaptors
&& xv_port
== 0; i
++)
700 /* check if adaptor number has been specified */
701 if (xv_adaptor
!= -1 && xv_adaptor
!= i
)
704 if ((ai
[i
].type
& XvInputMask
) && (ai
[i
].type
& XvImageMask
))
706 for (xv_p
= ai
[i
].base_id
;
707 xv_p
< ai
[i
].base_id
+ ai
[i
].num_ports
; ++xv_p
)
708 if (!XvGrabPort(mDisplay
, xv_p
, CurrentTime
))
711 mp_msg(MSGT_VO
, MSGL_V
,
712 "[VO_XV] Using Xv Adapter #%d (%s)\n",
717 mp_msg(MSGT_VO
, MSGL_WARN
,
718 MSGTR_LIBVO_XV_CouldNotGrabPort
, (int) xv_p
);
726 mp_msg(MSGT_VO
, MSGL_ERR
,
727 MSGTR_LIBVO_XV_CouldNotFindFreePort
);
729 mp_msg(MSGT_VO
, MSGL_ERR
,
730 MSGTR_LIBVO_XV_NoXvideoSupport
);
734 if ( !vo_xv_init_colorkey() )
736 return -1; // bail out, colorkey setup failed
738 vo_xv_enable_vsync();
739 vo_xv_get_max_img_dim( &max_width
, &max_height
);
741 fo
= XvListImageFormats(mDisplay
, xv_port
, (int *) &formats
);
743 mp_input_add_event_fd(ConnectionNumber(mDisplay
), check_events
);
747 static int control(uint32_t request
, void *data
, ...)
752 return int_pause
= 1;
754 return int_pause
= 0;
755 case VOCTRL_QUERY_FORMAT
:
756 return query_format(*((uint32_t *) data
));
757 case VOCTRL_GET_IMAGE
:
758 return get_image(data
);
759 case VOCTRL_DRAW_IMAGE
:
760 return draw_image(data
);
761 case VOCTRL_GUISUPPORT
:
763 case VOCTRL_GET_PANSCAN
:
764 if (!vo_config_count
|| !vo_fs
)
767 case VOCTRL_FULLSCREEN
:
769 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
770 case VOCTRL_SET_PANSCAN
:
771 if ((vo_fs
&& (vo_panscan
!= vo_panscan_amount
))
772 || (!vo_fs
&& vo_panscan_amount
))
774 int old_y
= vo_panscan_y
;
778 if (old_y
!= vo_panscan_y
)
780 vo_x11_clearwindow_part(mDisplay
, vo_window
,
781 vo_dwidth
+ vo_panscan_x
- 1,
782 vo_dheight
+ vo_panscan_y
- 1,
784 vo_xv_draw_colorkey(drwX
- (vo_panscan_x
>> 1),
785 drwY
- (vo_panscan_y
>> 1),
786 vo_dwidth
+ vo_panscan_x
- 1,
787 vo_dheight
+ vo_panscan_y
- 1);
792 case VOCTRL_SET_EQUALIZER
:
798 value
= va_arg(ap
, int);
802 return vo_xv_set_eq(xv_port
, data
, value
);
804 case VOCTRL_GET_EQUALIZER
:
810 value
= va_arg(ap
, int *);
814 return vo_xv_get_eq(xv_port
, data
, value
);
819 case VOCTRL_UPDATE_SCREENINFO
:
820 update_xinerama_info();