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.
28 #include <X11/Xutil.h>
30 #include <libavutil/common.h>
37 #include <X11/extensions/XShm.h>
40 // Note: depends on the inclusion of X11/extensions/XShm.h
41 #include <X11/extensions/Xv.h>
42 #include <X11/extensions/Xvlib.h>
47 #include "video_out.h"
48 #include "libmpcodecs/vfcap.h"
49 #include "libmpcodecs/mp_image.h"
51 #include "x11_common.h"
52 #include "fastmemcpy.h"
56 #include "subopt-helper.h"
58 static const vo_info_t info
= {
61 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
67 XvImageFormatValues
*fo
;
68 unsigned int formats
, adaptors
, xv_format
;
76 XvImage
*xvimage
[2 + 1];
78 uint32_t image_height
;
79 uint32_t image_format
;
80 uint32_t image_d_width
;
81 uint32_t image_d_height
;
83 struct vo_rect src_rect
;
84 struct vo_rect dst_rect
;
85 uint32_t max_width
, max_height
; // zero means: not set
87 int osd_objects_drawn
;
88 void (*draw_alpha_fnc
)(void *ctx
, int x0
, int y0
, int w
, int h
,
89 unsigned char *src
, unsigned char *srca
,
92 XShmSegmentInfo Shminfo
[2 + 1];
97 static void allocate_xvimage(struct vo
*, int);
100 static void fixup_osd_position(struct vo
*vo
, int *x0
, int *y0
, int *w
, int *h
)
102 struct xvctx
*ctx
= vo
->priv
;
103 *x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
104 / (vo
->dwidth
+ vo
->panscan_x
);
105 *w
= av_clip(*w
, 0, ctx
->image_width
);
106 *h
= av_clip(*h
, 0, ctx
->image_height
);
107 *x0
= FFMIN(*x0
, ctx
->image_width
- *w
);
108 *y0
= FFMIN(*y0
, ctx
->image_height
- *h
);
111 static void draw_alpha_yv12(void *p
, int x0
, int y0
, int w
, int h
,
112 unsigned char *src
, unsigned char *srca
,
116 struct xvctx
*ctx
= vo
->priv
;
117 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
118 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
,
119 ctx
->xvimage
[ctx
->current_buf
]->data
+
120 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
121 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ x0
,
122 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
123 ctx
->osd_objects_drawn
++;
126 static void draw_alpha_yuy2(void *p
, int x0
, int y0
, int w
, int h
,
127 unsigned char *src
, unsigned char *srca
,
131 struct xvctx
*ctx
= vo
->priv
;
132 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
133 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
134 ctx
->xvimage
[ctx
->current_buf
]->data
+
135 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
136 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
,
137 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
138 ctx
->osd_objects_drawn
++;
141 static void draw_alpha_uyvy(void *p
, int x0
, int y0
, int w
, int h
,
142 unsigned char *src
, unsigned char *srca
,
146 struct xvctx
*ctx
= vo
->priv
;
147 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
148 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
149 ctx
->xvimage
[ctx
->current_buf
]->data
+
150 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
151 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
+ 1,
152 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
153 ctx
->osd_objects_drawn
++;
156 static void draw_alpha_null(void *p
, int x0
, int y0
, int w
, int h
,
157 unsigned char *src
, unsigned char *srca
,
163 static void deallocate_xvimage(struct vo
*vo
, int foo
);
165 static void resize(struct vo
*vo
)
167 struct xvctx
*ctx
= vo
->priv
;
169 calc_src_dst_rects(vo
, ctx
->image_width
, ctx
->image_height
, &ctx
->src_rect
,
170 &ctx
->dst_rect
, NULL
, NULL
);
171 struct vo_rect
*dst
= &ctx
->dst_rect
;
172 vo_x11_clearwindow_part(vo
, vo
->x11
->window
, dst
->width
, dst
->height
);
173 vo_xv_draw_colorkey(vo
, dst
->left
, dst
->top
, dst
->width
, dst
->height
);
177 * connect to server, create and map window,
178 * allocate colors and (shared) memory
180 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
181 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
184 struct vo_x11_state
*x11
= vo
->x11
;
186 XSetWindowAttributes xswa
;
187 XWindowAttributes attribs
;
188 unsigned long xswamask
;
190 struct xvctx
*ctx
= vo
->priv
;
193 ctx
->image_height
= height
;
194 ctx
->image_width
= width
;
195 ctx
->image_format
= format
;
196 ctx
->image_d_width
= d_width
;
197 ctx
->image_d_height
= d_height
;
199 if ((ctx
->max_width
!= 0 && ctx
->max_height
!= 0)
200 && (ctx
->image_width
> ctx
->max_width
201 || ctx
->image_height
> ctx
->max_height
)) {
202 mp_tmsg(MSGT_VO
, MSGL_ERR
, "Source image dimensions are too high: %ux%u (maximum is %ux%u)\n",
203 ctx
->image_width
, ctx
->image_height
, ctx
->max_width
,
208 ctx
->visible_buf
= -1;
209 ctx
->have_image_copy
= false;
211 /* check image formats */
213 for (i
= 0; i
< ctx
->formats
; i
++) {
214 mp_msg(MSGT_VO
, MSGL_V
, "Xvideo image format: 0x%x (%4.4s) %s\n",
215 ctx
->fo
[i
].id
, (char *) &ctx
->fo
[i
].id
,
216 (ctx
->fo
[i
].format
== XvPacked
) ? "packed" : "planar");
217 if (ctx
->fo
[i
].id
== format
)
218 ctx
->xv_format
= ctx
->fo
[i
].id
;
225 int vm
= flags
& VOFLAG_MODESWITCHING
;
228 ctx
->mode_switched
= 1;
231 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
233 depth
= attribs
.depth
;
234 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
236 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
238 xswa
.border_pixel
= 0;
239 xswamask
= CWBorderPixel
;
240 if (x11
->xv_ck_info
.method
== CK_METHOD_BACKGROUND
) {
241 xswa
.background_pixel
= x11
->xv_colorkey
;
242 xswamask
|= CWBackPixel
;
245 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, vo
->dwidth
,
246 vo
->dheight
, flags
, CopyFromParent
, "xv");
247 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
251 /* Grab the mouse pointer in our window */
253 XGrabPointer(x11
->display
, x11
->window
, True
, 0, GrabModeAsync
,
254 GrabModeAsync
, x11
->window
, None
, CurrentTime
);
255 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
,
261 mp_msg(MSGT_VO
, MSGL_V
, "using Xvideo port %d for hw scaling\n",
264 switch (ctx
->xv_format
) {
268 ctx
->draw_alpha_fnc
= draw_alpha_yv12
;
272 ctx
->draw_alpha_fnc
= draw_alpha_yuy2
;
275 ctx
->draw_alpha_fnc
= draw_alpha_uyvy
;
278 ctx
->draw_alpha_fnc
= draw_alpha_null
;
281 // In case config has been called before
282 for (i
= 0; i
< ctx
->total_buffers
; i
++)
283 deallocate_xvimage(vo
, i
);
285 ctx
->num_buffers
= 2;
286 ctx
->total_buffers
= ctx
->num_buffers
+ 1;
288 for (i
= 0; i
< ctx
->total_buffers
; i
++)
289 allocate_xvimage(vo
, i
);
291 ctx
->current_buf
= 0;
292 ctx
->current_ip_buf
= 0;
300 static void allocate_xvimage(struct vo
*vo
, int foo
)
302 struct xvctx
*ctx
= vo
->priv
;
303 struct vo_x11_state
*x11
= vo
->x11
;
305 * allocate XvImages. FIXME: no error checking, without
306 * mit-shm this will bomb... trzing to fix ::atmos
309 if (x11
->display_is_local
&& XShmQueryExtension(x11
->display
))
313 mp_tmsg(MSGT_VO
, MSGL_INFO
, "[VO_XV] Shared memory not supported\nReverting to normal Xv.\n");
315 if (ctx
->Shmem_Flag
) {
317 (XvImage
*) XvShmCreateImage(x11
->display
, x11
->xv_port
,
318 ctx
->xv_format
, NULL
,
319 ctx
->image_width
, ctx
->image_height
,
322 ctx
->Shminfo
[foo
].shmid
= shmget(IPC_PRIVATE
,
323 ctx
->xvimage
[foo
]->data_size
,
325 ctx
->Shminfo
[foo
].shmaddr
= (char *) shmat(ctx
->Shminfo
[foo
].shmid
, 0,
327 ctx
->Shminfo
[foo
].readOnly
= False
;
329 ctx
->xvimage
[foo
]->data
= ctx
->Shminfo
[foo
].shmaddr
;
330 XShmAttach(x11
->display
, &ctx
->Shminfo
[foo
]);
331 XSync(x11
->display
, False
);
332 shmctl(ctx
->Shminfo
[foo
].shmid
, IPC_RMID
, 0);
337 (XvImage
*) XvCreateImage(x11
->display
, x11
->xv_port
,
338 ctx
->xv_format
, NULL
, ctx
->image_width
,
340 ctx
->xvimage
[foo
]->data
= malloc(ctx
->xvimage
[foo
]->data_size
);
341 XSync(x11
->display
, False
);
343 memset(ctx
->xvimage
[foo
]->data
, 128, ctx
->xvimage
[foo
]->data_size
);
347 static void deallocate_xvimage(struct vo
*vo
, int foo
)
349 struct xvctx
*ctx
= vo
->priv
;
351 if (ctx
->Shmem_Flag
) {
352 XShmDetach(vo
->x11
->display
, &ctx
->Shminfo
[foo
]);
353 shmdt(ctx
->Shminfo
[foo
].shmaddr
);
357 free(ctx
->xvimage
[foo
]->data
);
359 XFree(ctx
->xvimage
[foo
]);
361 XSync(vo
->x11
->display
, False
);
365 static inline void put_xvimage(struct vo
*vo
, XvImage
*xvi
)
367 struct xvctx
*ctx
= vo
->priv
;
368 struct vo_x11_state
*x11
= vo
->x11
;
369 struct vo_rect
*src
= &ctx
->src_rect
;
370 struct vo_rect
*dst
= &ctx
->dst_rect
;
372 if (ctx
->Shmem_Flag
) {
373 XvShmPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
,
374 src
->left
, src
->top
, src
->width
, src
->height
,
375 dst
->left
, dst
->top
, dst
->width
, dst
->height
,
380 XvPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
,
381 src
->left
, src
->top
, src
->width
, src
->height
,
382 dst
->left
, dst
->top
, dst
->width
, dst
->height
);
386 // Only copies luma for planar formats as draw_alpha doesn't change others */
387 static void copy_backup_image(struct vo
*vo
, int dest
, int src
)
389 struct xvctx
*ctx
= vo
->priv
;
391 XvImage
*vb
= ctx
->xvimage
[dest
];
392 XvImage
*cp
= ctx
->xvimage
[src
];
393 memcpy_pic(vb
->data
+ vb
->offsets
[0], cp
->data
+ cp
->offsets
[0],
394 vb
->width
, vb
->height
,
395 vb
->pitches
[0], cp
->pitches
[0]);
398 static void check_events(struct vo
*vo
)
400 int e
= vo_x11_check_events(vo
);
402 if (e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) {
404 vo
->want_redraw
= true;
408 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
410 struct xvctx
*ctx
= vo
->priv
;
412 ctx
->osd_objects_drawn
= 0;
415 ctx
->image_width
* vo
->panscan_x
/ (vo
->dwidth
+
417 ctx
->image_height
, ctx
->draw_alpha_fnc
, vo
);
418 if (ctx
->osd_objects_drawn
)
419 ctx
->unchanged_image
= false;
422 static int redraw_frame(struct vo
*vo
)
424 struct xvctx
*ctx
= vo
->priv
;
426 if (ctx
->have_image_copy
)
427 copy_backup_image(vo
, ctx
->visible_buf
, ctx
->num_buffers
);
428 else if (ctx
->unchanged_image
) {
429 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->visible_buf
);
430 ctx
->have_image_copy
= true;
433 ctx
->current_buf
= ctx
->visible_buf
;
437 static void flip_page(struct vo
*vo
)
439 struct xvctx
*ctx
= vo
->priv
;
440 put_xvimage(vo
, ctx
->xvimage
[ctx
->current_buf
]);
442 /* remember the currently visible buffer */
443 ctx
->visible_buf
= ctx
->current_buf
;
445 ctx
->current_buf
= (ctx
->current_buf
+ 1) % ctx
->num_buffers
;
446 XFlush(vo
->x11
->display
);
450 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
453 struct xvctx
*ctx
= vo
->priv
;
455 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
457 dst
= current_image
->data
+ current_image
->offsets
[0]
458 + current_image
->pitches
[0] * y
+ x
;
459 memcpy_pic(dst
, image
[0], w
, h
, current_image
->pitches
[0], stride
[0]);
466 dst
= current_image
->data
+ current_image
->offsets
[1]
467 + current_image
->pitches
[1] * y
+ x
;
468 if (ctx
->image_format
!= IMGFMT_YV12
)
469 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
471 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
473 dst
= current_image
->data
+ current_image
->offsets
[2]
474 + current_image
->pitches
[2] * y
+ x
;
475 if (ctx
->image_format
== IMGFMT_YV12
)
476 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
478 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
483 static mp_image_t
*get_screenshot(struct vo
*vo
)
485 struct xvctx
*ctx
= vo
->priv
;
487 // try to get an image without OSD
488 if (ctx
->have_image_copy
)
489 copy_backup_image(vo
, ctx
->visible_buf
, ctx
->num_buffers
);
491 XvImage
*xv_image
= ctx
->xvimage
[ctx
->visible_buf
];
493 int w
= xv_image
->width
;
494 int h
= xv_image
->height
;
496 mp_image_t
*image
= alloc_mpi(w
, h
, ctx
->image_format
);
499 if (!(image
->flags
& MP_IMGFLAG_PLANAR
) && (image
->flags
& MP_IMGFLAG_YUV
))
501 bytes
= image
->bpp
/ 8;
503 memcpy_pic(image
->planes
[0], xv_image
->data
+ xv_image
->offsets
[0],
504 bytes
* w
, h
, image
->stride
[0], xv_image
->pitches
[0]);
506 if (image
->flags
& MP_IMGFLAG_PLANAR
) {
507 int swap
= ctx
->image_format
== IMGFMT_YV12
;
508 int p1
= swap
? 2 : 1;
509 int p2
= swap
? 1 : 2;
514 memcpy_pic(image
->planes
[p1
], xv_image
->data
+ xv_image
->offsets
[1],
515 w
, h
, image
->stride
[p1
], xv_image
->pitches
[1]);
516 memcpy_pic(image
->planes
[p2
], xv_image
->data
+ xv_image
->offsets
[2],
517 w
, h
, image
->stride
[p2
], xv_image
->pitches
[2]);
520 image
->w
= ctx
->image_d_width
;
521 image
->h
= ctx
->image_d_height
;
526 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
528 struct xvctx
*ctx
= vo
->priv
;
530 ctx
->have_image_copy
= false;
532 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
534 else if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
535 draw_slice(vo
, mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, 0, 0);
536 else if (mpi
->flags
& MP_IMGFLAG_YUV
)
538 memcpy_pic(ctx
->xvimage
[ctx
->current_buf
]->data
+
539 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0], mpi
->planes
[0],
540 mpi
->w
* (mpi
->bpp
/ 8), mpi
->h
,
541 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0], mpi
->stride
[0]);
545 if (ctx
->is_paused
) {
546 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->current_buf
);
547 ctx
->have_image_copy
= true;
549 ctx
->unchanged_image
= true;
553 static int query_format(struct xvctx
*ctx
, uint32_t format
)
556 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
558 /* check image formats */
559 for (i
= 0; i
< ctx
->formats
; i
++) {
560 if (ctx
->fo
[i
].id
== format
)
561 return flag
; //xv_format = fo[i].id;
566 static void uninit(struct vo
*vo
)
568 struct xvctx
*ctx
= vo
->priv
;
571 ctx
->visible_buf
= -1;
573 XvFreeAdaptorInfo(ctx
->ai
);
579 for (i
= 0; i
< ctx
->total_buffers
; i
++)
580 deallocate_xvimage(vo
, i
);
582 if (ctx
->mode_switched
)
585 // uninit() shouldn't get called unless initialization went past vo_init()
589 static int preinit(struct vo
*vo
, const char *arg
)
594 strarg_t ck_src_arg
= { 0, NULL
};
595 strarg_t ck_method_arg
= { 0, NULL
};
596 struct xvctx
*ctx
= talloc_zero(vo
, struct xvctx
);
603 struct vo_x11_state
*x11
= vo
->x11
;
605 const opt_t subopts
[] =
607 /* name arg type arg var test */
608 { "port", OPT_ARG_INT
, &x11
->xv_port
, int_pos
},
609 { "adaptor", OPT_ARG_INT
, &xv_adaptor
, int_non_neg
},
610 { "ck", OPT_ARG_STR
, &ck_src_arg
, xv_test_ck
},
611 { "ck-method", OPT_ARG_STR
, &ck_method_arg
, xv_test_ckm
},
617 /* parse suboptions */
618 if (subopt_parse(arg
, subopts
) != 0)
621 /* modify colorkey settings according to the given options */
622 xv_setup_colorkeyhandling(vo
, ck_method_arg
.str
, ck_src_arg
.str
);
624 /* check for Xvideo extension */
625 unsigned int ver
, rel
, req
, ev
, err
;
626 if (Success
!= XvQueryExtension(x11
->display
, &ver
, &rel
, &req
, &ev
, &err
)) {
627 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[VO_XV] Sorry, Xv not supported by this X11 version/driver\n[VO_XV] ******** Try with -vo x11 or -vo sdl *********\n");
631 /* check for Xvideo support */
633 XvQueryAdaptors(x11
->display
, DefaultRootWindow(x11
->display
),
634 &ctx
->adaptors
, &ctx
->ai
)) {
635 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[VO_XV] XvQueryAdaptors failed.\n");
643 for (port_found
= 0, i
= 0; !port_found
&& i
< ctx
->adaptors
; i
++) {
644 if ((ctx
->ai
[i
].type
& XvInputMask
)
645 && (ctx
->ai
[i
].type
& XvImageMask
)) {
646 for (xv_p
= ctx
->ai
[i
].base_id
;
647 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
;
649 if (xv_p
== x11
->xv_port
) {
657 if (XvGrabPort(x11
->display
, x11
->xv_port
, CurrentTime
))
660 mp_tmsg(MSGT_VO
, MSGL_WARN
, "[VO_XV] Invalid port parameter, overriding with port 0.\n");
665 for (i
= 0; i
< ctx
->adaptors
&& x11
->xv_port
== 0; i
++) {
666 /* check if adaptor number has been specified */
667 if (xv_adaptor
!= -1 && xv_adaptor
!= i
)
670 if ((ctx
->ai
[i
].type
& XvInputMask
) && (ctx
->ai
[i
].type
& XvImageMask
)) {
671 for (xv_p
= ctx
->ai
[i
].base_id
;
672 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
; ++xv_p
)
673 if (!XvGrabPort(x11
->display
, xv_p
, CurrentTime
)) {
675 mp_msg(MSGT_VO
, MSGL_V
,
676 "[VO_XV] Using Xv Adapter #%d (%s)\n",
680 mp_tmsg(MSGT_VO
, MSGL_WARN
, "[VO_XV] Could not grab port %i.\n",
688 mp_tmsg(MSGT_VO
, MSGL_ERR
,
689 "[VO_XV] Could not find free Xvideo port - maybe another process is already\n"\
690 "[VO_XV] using it. Close all video applications, and try again. If that does\n"\
691 "[VO_XV] not help, see 'mplayer -vo help' for other (non-xv) video out drivers.\n");
693 mp_tmsg(MSGT_VO
, MSGL_ERR
,
694 "[VO_XV] It seems there is no Xvideo support for your video card available.\n"\
695 "[VO_XV] Run 'xvinfo' to verify its Xv support and read\n"\
696 "[VO_XV] DOCS/HTML/en/video.html#xv!\n"\
697 "[VO_XV] See 'mplayer -vo help' for other (non-xv) video out drivers.\n"\
698 "[VO_XV] Try -vo x11.\n");
702 if (!vo_xv_init_colorkey(vo
)) {
703 goto error
; // bail out, colorkey setup failed
705 vo_xv_enable_vsync(vo
);
706 vo_xv_get_max_img_dim(vo
, &ctx
->max_width
, &ctx
->max_height
);
708 ctx
->fo
= XvListImageFormats(x11
->display
, x11
->xv_port
,
709 (int *) &ctx
->formats
);
714 uninit(vo
); // free resources
718 static int control(struct vo
*vo
, uint32_t request
, void *data
)
720 struct xvctx
*ctx
= vo
->priv
;
721 struct vo_x11_state
*x11
= vo
->x11
;
724 return (ctx
->is_paused
= 1);
726 return (ctx
->is_paused
= 0);
727 case VOCTRL_QUERY_FORMAT
:
728 return query_format(ctx
, *((uint32_t *) data
));
729 case VOCTRL_DRAW_IMAGE
:
730 return draw_image(vo
, data
);
731 case VOCTRL_GET_PANSCAN
:
733 case VOCTRL_FULLSCREEN
:
734 vo_x11_fullscreen(vo
);
735 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
736 case VOCTRL_SET_PANSCAN
:
739 case VOCTRL_SET_EQUALIZER
: {
740 vo
->want_redraw
= true;
741 struct voctrl_set_equalizer_args
*args
= data
;
742 return vo_xv_set_eq(vo
, x11
->xv_port
, args
->name
, args
->value
);
744 case VOCTRL_GET_EQUALIZER
: {
745 struct voctrl_get_equalizer_args
*args
= data
;
746 return vo_xv_get_eq(vo
, x11
->xv_port
, args
->name
, args
->valueptr
);
748 case VOCTRL_SET_YUV_COLORSPACE
:;
749 struct mp_csp_details
* given_cspc
= data
;
750 int is_709
= given_cspc
->format
== MP_CSP_BT_709
;
751 vo_xv_set_eq(vo
, x11
->xv_port
, "bt_709", is_709
* 200 - 100);
752 vo
->want_redraw
= true;
754 case VOCTRL_GET_YUV_COLORSPACE
:;
755 struct mp_csp_details
* cspc
= data
;
756 *cspc
= (struct mp_csp_details
) MP_CSP_DETAILS_DEFAULTS
;
758 if (vo_xv_get_eq(vo
, x11
->xv_port
, "bt_709", &bt709_enabled
))
759 cspc
->format
= bt709_enabled
== 100 ? MP_CSP_BT_709
: MP_CSP_BT_601
;
764 case VOCTRL_UPDATE_SCREENINFO
:
765 update_xinerama_info(vo
);
767 case VOCTRL_REDRAW_FRAME
:
768 return redraw_frame(vo
);
769 case VOCTRL_SCREENSHOT
: {
770 struct voctrl_screenshot_args
*args
= data
;
771 args
->out_image
= get_screenshot(vo
);
778 const struct vo_driver video_out_xv
= {
784 .draw_slice
= draw_slice
,
785 .draw_osd
= draw_osd
,
786 .flip_page
= flip_page
,
787 .check_events
= check_events
,