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)
48 #include "video_out.h"
49 #include "libmpcodecs/vfcap.h"
50 #include "libmpcodecs/mp_image.h"
54 #include <X11/Xutil.h>
57 #include "x11_common.h"
59 #include "fastmemcpy.h"
63 #include "subopt-helper.h"
65 #include "input/input.h"
69 #include "gui/interface.h"
72 #include "libavutil/common.h"
74 static const vo_info_t info
= {
77 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
84 #include <X11/extensions/XShm.h>
87 // Note: depends on the inclusion of X11/extensions/XShm.h
88 #include <X11/extensions/Xv.h>
89 #include <X11/extensions/Xvlib.h>
93 XvImageFormatValues
*fo
;
94 unsigned int formats
, adaptors
, xv_format
;
99 int have_visible_image_copy
;
100 int have_next_image_copy
;
101 int unchanged_visible_image
;
102 int unchanged_next_image
;
104 XvImage
*xvimage
[NUM_BUFFERS
+ 1];
105 uint32_t image_width
;
106 uint32_t image_height
;
107 uint32_t image_format
;
110 uint32_t max_width
, max_height
; // zero means: not set
111 int event_fd_registered
; // for uninit called from preinit
113 int osd_objects_drawn
;
114 void (*draw_alpha_fnc
)(void *ctx
, int x0
, int y0
, int w
, int h
,
115 unsigned char *src
, unsigned char *srca
,
118 XShmSegmentInfo Shminfo
[NUM_BUFFERS
];
123 static void allocate_xvimage(struct vo
*, int);
126 static void draw_alpha_yv12(void *p
, int x0
, int y0
, int w
, int h
,
127 unsigned char *src
, unsigned char *srca
,
131 struct xvctx
*ctx
= vo
->priv
;
132 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
133 / (vo
->dwidth
+ vo
->panscan_x
);
134 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
,
135 ctx
->xvimage
[ctx
->current_buf
]->data
+
136 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
137 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ x0
,
138 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
139 ctx
->osd_objects_drawn
++;
142 static void draw_alpha_yuy2(void *p
, int x0
, int y0
, int w
, int h
,
143 unsigned char *src
, unsigned char *srca
,
147 struct xvctx
*ctx
= vo
->priv
;
148 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
149 / (vo
->dwidth
+ vo
->panscan_x
);
150 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
151 ctx
->xvimage
[ctx
->current_buf
]->data
+
152 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
153 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
,
154 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
155 ctx
->osd_objects_drawn
++;
158 static void draw_alpha_uyvy(void *p
, int x0
, int y0
, int w
, int h
,
159 unsigned char *src
, unsigned char *srca
,
163 struct xvctx
*ctx
= vo
->priv
;
164 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
165 / (vo
->dwidth
+ vo
->panscan_x
);
166 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
167 ctx
->xvimage
[ctx
->current_buf
]->data
+
168 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
169 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
+ 1,
170 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
171 ctx
->osd_objects_drawn
++;
174 static void draw_alpha_null(void *p
, int x0
, int y0
, int w
, int h
,
175 unsigned char *src
, unsigned char *srca
,
181 static void deallocate_xvimage(struct vo
*vo
, int foo
);
184 * connect to server, create and map window,
185 * allocate colors and (shared) memory
187 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
188 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
189 char *title
, uint32_t format
)
191 struct MPOpts
*opts
= vo
->opts
;
192 struct vo_x11_state
*x11
= vo
->x11
;
194 XSetWindowAttributes xswa
;
195 XWindowAttributes attribs
;
196 unsigned long xswamask
;
198 struct xvctx
*ctx
= vo
->priv
;
201 ctx
->image_height
= height
;
202 ctx
->image_width
= width
;
203 ctx
->image_format
= format
;
205 if ((ctx
->max_width
!= 0 && ctx
->max_height
!= 0)
206 && (ctx
->image_width
> ctx
->max_width
207 || ctx
->image_height
> ctx
->max_height
)) {
208 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_VO_XV_ImagedimTooHigh
,
209 ctx
->image_width
, ctx
->image_height
, ctx
->max_width
,
215 ctx
->visible_buf
= -1;
216 ctx
->have_visible_image_copy
= false;
217 ctx
->have_next_image_copy
= false;
219 /* check image formats */
221 for (i
= 0; i
< ctx
->formats
; i
++) {
222 mp_msg(MSGT_VO
, MSGL_V
, "Xvideo image format: 0x%x (%4.4s) %s\n",
223 ctx
->fo
[i
].id
, (char *) &ctx
->fo
[i
].id
,
224 (ctx
->fo
[i
].format
== XvPacked
) ? "packed" : "planar");
225 if (ctx
->fo
[i
].id
== format
)
226 ctx
->xv_format
= ctx
->fo
[i
].id
;
233 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize the window
238 int vm
= flags
& VOFLAG_MODESWITCHING
;
241 ctx
->mode_switched
= 1;
244 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
246 depth
= attribs
.depth
;
247 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
249 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
251 xswa
.background_pixel
= 0;
252 if (x11
->xv_ck_info
.method
== CK_METHOD_BACKGROUND
)
253 xswa
.background_pixel
= x11
->xv_colorkey
;
254 xswa
.border_pixel
= 0;
255 xswamask
= CWBackPixel
| CWBorderPixel
;
257 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, vo
->dwidth
,
258 vo
->dheight
, flags
, CopyFromParent
, "xv",
260 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
264 /* Grab the mouse pointer in our window */
266 XGrabPointer(x11
->display
, x11
->window
, True
, 0, GrabModeAsync
,
267 GrabModeAsync
, x11
->window
, None
, CurrentTime
);
268 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
,
274 mp_msg(MSGT_VO
, MSGL_V
, "using Xvideo port %d for hw scaling\n",
277 switch (ctx
->xv_format
) {
281 ctx
->draw_alpha_fnc
= draw_alpha_yv12
;
285 ctx
->draw_alpha_fnc
= draw_alpha_yuy2
;
288 ctx
->draw_alpha_fnc
= draw_alpha_uyvy
;
291 ctx
->draw_alpha_fnc
= draw_alpha_null
;
294 // In case config has been called before
295 for (i
= 0; i
< ctx
->total_buffers
; i
++)
296 deallocate_xvimage(vo
, i
);
299 vo_doublebuffering
? (vo_directrendering
? NUM_BUFFERS
: 2) : 1;
300 ctx
->total_buffers
= ctx
->num_buffers
+ 1;
302 for (i
= 0; i
< ctx
->total_buffers
; i
++)
303 allocate_xvimage(vo
, i
);
305 ctx
->current_buf
= 0;
306 ctx
->current_ip_buf
= 0;
308 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
310 vo_calc_drwXY(vo
, &ctx
->drwX
, &ctx
->drwY
);
314 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
315 ctx
->drwY
- (vo
->panscan_y
>> 1),
316 vo
->dwidth
+ vo
->panscan_x
- 1,
317 vo
->dheight
+ vo
->panscan_y
- 1);
319 mp_msg(MSGT_VO
, MSGL_V
, "[xv] dx: %d dy: %d dw: %d dh: %d\n", ctx
->drwX
,
320 ctx
->drwY
, vo
->dwidth
, vo
->dheight
);
325 static void allocate_xvimage(struct vo
*vo
, int foo
)
327 struct xvctx
*ctx
= vo
->priv
;
328 struct vo_x11_state
*x11
= vo
->x11
;
330 * allocate XvImages. FIXME: no error checking, without
331 * mit-shm this will bomb... trzing to fix ::atmos
334 if (x11
->display_is_local
&& XShmQueryExtension(x11
->display
))
338 mp_msg(MSGT_VO
, MSGL_INFO
, MSGTR_LIBVO_XV_SharedMemoryNotSupported
);
340 if (ctx
->Shmem_Flag
) {
342 (XvImage
*) XvShmCreateImage(x11
->display
, x11
->xv_port
,
343 ctx
->xv_format
, NULL
,
344 ctx
->image_width
, ctx
->image_height
,
347 ctx
->Shminfo
[foo
].shmid
= shmget(IPC_PRIVATE
,
348 ctx
->xvimage
[foo
]->data_size
,
350 ctx
->Shminfo
[foo
].shmaddr
= (char *) shmat(ctx
->Shminfo
[foo
].shmid
, 0,
352 ctx
->Shminfo
[foo
].readOnly
= False
;
354 ctx
->xvimage
[foo
]->data
= ctx
->Shminfo
[foo
].shmaddr
;
355 XShmAttach(x11
->display
, &ctx
->Shminfo
[foo
]);
356 XSync(x11
->display
, False
);
357 shmctl(ctx
->Shminfo
[foo
].shmid
, IPC_RMID
, 0);
362 (XvImage
*) XvCreateImage(x11
->display
, x11
->xv_port
,
363 ctx
->xv_format
, NULL
, ctx
->image_width
,
365 ctx
->xvimage
[foo
]->data
= malloc(ctx
->xvimage
[foo
]->data_size
);
366 XSync(x11
->display
, False
);
368 memset(ctx
->xvimage
[foo
]->data
, 128, ctx
->xvimage
[foo
]->data_size
);
372 static void deallocate_xvimage(struct vo
*vo
, int foo
)
374 struct xvctx
*ctx
= vo
->priv
;
376 if (ctx
->Shmem_Flag
) {
377 XShmDetach(vo
->x11
->display
, &ctx
->Shminfo
[foo
]);
378 shmdt(ctx
->Shminfo
[foo
].shmaddr
);
382 free(ctx
->xvimage
[foo
]->data
);
384 XFree(ctx
->xvimage
[foo
]);
386 XSync(vo
->x11
->display
, False
);
390 static inline void put_xvimage(struct vo
*vo
, XvImage
*xvi
)
392 struct xvctx
*ctx
= vo
->priv
;
393 struct vo_x11_state
*x11
= vo
->x11
;
395 if (ctx
->Shmem_Flag
) {
396 XvShmPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
,
397 0, 0, ctx
->image_width
, ctx
->image_height
,
398 ctx
->drwX
- (vo
->panscan_x
>> 1),
399 ctx
->drwY
- (vo
->panscan_y
>> 1),
400 vo
->dwidth
+ vo
->panscan_x
, vo
->dheight
+ vo
->panscan_y
,
405 XvPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
, 0,
406 0, ctx
->image_width
, ctx
->image_height
,
407 ctx
->drwX
- (vo
->panscan_x
>> 1),
408 ctx
->drwY
- (vo
->panscan_y
>> 1),
409 vo
->dwidth
+ vo
->panscan_x
, vo
->dheight
+ vo
->panscan_y
);
413 // Only copies luma for planar formats as draw_alpha doesn't change others */
414 void copy_backup_image(struct vo
*vo
, int dest
, int src
)
416 struct xvctx
*ctx
= vo
->priv
;
418 XvImage
*vb
= ctx
->xvimage
[dest
];
419 XvImage
*cp
= ctx
->xvimage
[src
];
420 memcpy_pic(vb
->data
+ vb
->offsets
[0], cp
->data
+ cp
->offsets
[0],
421 vb
->width
, vb
->height
,
422 vb
->pitches
[0], cp
->pitches
[0]);
425 static void check_events(struct vo
*vo
)
427 struct xvctx
*ctx
= vo
->priv
;
428 struct vo_x11_state
*x11
= vo
->x11
;
429 int e
= vo_x11_check_events(vo
);
431 if (e
& VO_EVENT_RESIZE
)
432 vo_calc_drwXY(vo
, &ctx
->drwX
, &ctx
->drwY
);
434 if (e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) {
435 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
436 ctx
->drwY
- (vo
->panscan_y
>> 1),
437 vo
->dwidth
+ vo
->panscan_x
- 1,
438 vo
->dheight
+ vo
->panscan_y
- 1);
441 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && ctx
->is_paused
) {
442 /* did we already draw a buffer */
443 if (ctx
->visible_buf
!= -1) {
444 /* redraw the last visible buffer */
445 put_xvimage(vo
, ctx
->xvimage
[ctx
->visible_buf
]);
450 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
452 struct xvctx
*ctx
= vo
->priv
;
454 ctx
->osd_objects_drawn
= 0;
457 ctx
->image_width
* vo
->panscan_x
/ (vo
->dwidth
+
459 ctx
->image_height
, ctx
->draw_alpha_fnc
, vo
);
460 if (ctx
->osd_objects_drawn
)
461 ctx
->unchanged_next_image
= false;
464 static int redraw_osd(struct vo
*vo
, struct osd_state
*osd
)
466 struct xvctx
*ctx
= vo
->priv
;
468 if (ctx
->have_visible_image_copy
)
469 copy_backup_image(vo
, ctx
->visible_buf
, ctx
->num_buffers
);
470 else if (ctx
->unchanged_visible_image
) {
471 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->visible_buf
);
472 ctx
->have_visible_image_copy
= true;
476 int temp
= ctx
->current_buf
;
477 ctx
->current_buf
= ctx
->visible_buf
;
479 ctx
->current_buf
= temp
;
480 put_xvimage(vo
, ctx
->xvimage
[ctx
->visible_buf
]);
484 static void flip_page(struct vo
*vo
)
486 struct xvctx
*ctx
= vo
->priv
;
487 put_xvimage(vo
, ctx
->xvimage
[ctx
->current_buf
]);
489 /* remember the currently visible buffer */
490 ctx
->visible_buf
= ctx
->current_buf
;
492 ctx
->have_visible_image_copy
= ctx
->have_next_image_copy
;
493 ctx
->have_next_image_copy
= false;
494 ctx
->unchanged_visible_image
= ctx
->unchanged_next_image
;
495 ctx
->unchanged_next_image
= false;
497 if (ctx
->num_buffers
> 1) {
498 ctx
->current_buf
= vo_directrendering
? 0 : ((ctx
->current_buf
+ 1) %
500 XFlush(vo
->x11
->display
);
502 XSync(vo
->x11
->display
, False
);
506 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
509 struct xvctx
*ctx
= vo
->priv
;
511 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
513 dst
= current_image
->data
+ current_image
->offsets
[0]
514 + current_image
->pitches
[0] * y
+ x
;
515 memcpy_pic(dst
, image
[0], w
, h
, current_image
->pitches
[0], stride
[0]);
522 dst
= current_image
->data
+ current_image
->offsets
[1]
523 + current_image
->pitches
[1] * y
+ x
;
524 if (ctx
->image_format
!= IMGFMT_YV12
)
525 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
527 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
529 dst
= current_image
->data
+ current_image
->offsets
[2]
530 + current_image
->pitches
[2] * y
+ x
;
531 if (ctx
->image_format
== IMGFMT_YV12
)
532 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
534 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
539 static int draw_frame(struct vo
*vo
, uint8_t *src
[])
544 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
546 struct xvctx
*ctx
= vo
->priv
;
548 ctx
->have_next_image_copy
= false;
550 if (mpi
->flags
& MP_IMGFLAG_DIRECT
)
552 ctx
->current_buf
= (int) (mpi
->priv
); // hack!
553 else if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
555 else if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
556 draw_slice(vo
, mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, 0, 0);
557 else if (mpi
->flags
& MP_IMGFLAG_YUV
)
559 memcpy_pic(ctx
->xvimage
[ctx
->current_buf
]->data
+
560 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0], mpi
->planes
[0],
561 mpi
->w
* (mpi
->bpp
/ 8), mpi
->h
,
562 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0], mpi
->stride
[0]);
566 if (ctx
->is_paused
) {
567 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->current_buf
);
568 ctx
->have_next_image_copy
= true;
570 ctx
->unchanged_next_image
= true;
574 static uint32_t get_image(struct xvctx
*ctx
, mp_image_t
*mpi
)
576 // we shouldn't change current_buf unless we do DR!
577 int buf
= ctx
->current_buf
;
579 if (mpi
->type
== MP_IMGTYPE_STATIC
&& ctx
->num_buffers
> 1)
580 return VO_FALSE
; // it is not static
581 if (mpi
->imgfmt
!= ctx
->image_format
)
582 return VO_FALSE
; // needs conversion :(
583 if (mpi
->flags
& MP_IMGFLAG_READABLE
584 && (mpi
->type
== MP_IMGTYPE_IPB
|| mpi
->type
== MP_IMGTYPE_IP
)) {
585 // reference (I/P) frame of IP or IPB:
586 if (ctx
->num_buffers
< 2)
587 return VO_FALSE
; // not enough
588 ctx
->current_ip_buf
^= 1;
589 // for IPB with 2 buffers we can DR only one of the 2 P frames:
590 if (mpi
->type
== MP_IMGTYPE_IPB
&& ctx
->num_buffers
< 3
591 && ctx
->current_ip_buf
)
593 buf
= ctx
->current_ip_buf
;
594 if (mpi
->type
== MP_IMGTYPE_IPB
)
595 ++buf
; // preserve space for B
597 if (mpi
->height
> ctx
->xvimage
[buf
]->height
)
598 return VO_FALSE
; //buffer to small
599 if (mpi
->width
* (mpi
->bpp
/ 8) > ctx
->xvimage
[buf
]->pitches
[0])
600 return VO_FALSE
; //buffer to small
601 if ((mpi
->flags
& (MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_ACCEPT_WIDTH
))
602 || (mpi
->width
* (mpi
->bpp
/ 8) == ctx
->xvimage
[buf
]->pitches
[0])) {
603 ctx
->current_buf
= buf
;
604 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
605 mpi
->planes
[0] = current_image
->data
+ current_image
->offsets
[0];
606 mpi
->stride
[0] = current_image
->pitches
[0];
607 mpi
->width
= mpi
->stride
[0] / (mpi
->bpp
/ 8);
608 if (mpi
->flags
& MP_IMGFLAG_PLANAR
) {
609 if (mpi
->flags
& MP_IMGFLAG_SWAPPED
) {
611 mpi
->planes
[1] = current_image
->data
612 + current_image
->offsets
[1];
613 mpi
->planes
[2] = current_image
->data
614 + current_image
->offsets
[2];
615 mpi
->stride
[1] = current_image
->pitches
[1];
616 mpi
->stride
[2] = current_image
->pitches
[2];
619 mpi
->planes
[1] = current_image
->data
620 + current_image
->offsets
[2];
621 mpi
->planes
[2] = current_image
->data
622 + current_image
->offsets
[1];
623 mpi
->stride
[1] = current_image
->pitches
[2];
624 mpi
->stride
[2] = current_image
->pitches
[1];
627 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
628 mpi
->priv
= (void *) ctx
->current_buf
;
634 static int query_format(struct xvctx
*ctx
, uint32_t format
)
637 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
639 /* check image formats */
640 for (i
= 0; i
< ctx
->formats
; i
++) {
641 if (ctx
->fo
[i
].id
== format
)
642 return flag
; //xv_format = fo[i].id;
647 static void uninit(struct vo
*vo
)
649 struct xvctx
*ctx
= vo
->priv
;
652 ctx
->visible_buf
= -1;
654 XvFreeAdaptorInfo(ctx
->ai
);
660 for (i
= 0; i
< ctx
->total_buffers
; i
++)
661 deallocate_xvimage(vo
, i
);
663 if (ctx
->mode_switched
)
666 if (ctx
->event_fd_registered
)
667 mp_input_rm_key_fd(vo
->input_ctx
, ConnectionNumber(vo
->x11
->display
));
668 // uninit() shouldn't get called unless initialization went past vo_init()
672 static int x11_fd_callback(void *ctx
, int fd
)
676 return mplayer_get_key(vo
->key_fifo
, 0);
679 static int preinit(struct vo
*vo
, const char *arg
)
684 strarg_t ck_src_arg
= { 0, NULL
};
685 strarg_t ck_method_arg
= { 0, NULL
};
686 struct xvctx
*ctx
= talloc_zero(vo
, struct xvctx
);
688 struct vo_x11_state
*x11
= vo
->x11
;
692 /* name arg type arg var test */
693 {"port", OPT_ARG_INT
, &x11
->xv_port
, (opt_test_f
) int_pos
},
694 {"adaptor", OPT_ARG_INT
, &xv_adaptor
, (opt_test_f
) int_non_neg
},
695 {"ck", OPT_ARG_STR
, &ck_src_arg
, xv_test_ck
},
696 {"ck-method", OPT_ARG_STR
, &ck_method_arg
, xv_test_ckm
},
702 /* parse suboptions */
703 if (subopt_parse(arg
, subopts
) != 0) {
707 /* modify colorkey settings according to the given options */
708 xv_setup_colorkeyhandling(vo
, ck_method_arg
.str
, ck_src_arg
.str
);
713 /* check for Xvideo extension */
714 unsigned int ver
, rel
, req
, ev
, err
;
715 if (Success
!= XvQueryExtension(x11
->display
, &ver
, &rel
, &req
, &ev
, &err
)) {
716 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_XvNotSupportedByX11
);
720 /* check for Xvideo support */
722 XvQueryAdaptors(x11
->display
, DefaultRootWindow(x11
->display
),
723 &ctx
->adaptors
, &ctx
->ai
)) {
724 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed
);
732 for (port_found
= 0, i
= 0; !port_found
&& i
< ctx
->adaptors
; i
++) {
733 if ((ctx
->ai
[i
].type
& XvInputMask
)
734 && (ctx
->ai
[i
].type
& XvImageMask
)) {
735 for (xv_p
= ctx
->ai
[i
].base_id
;
736 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
;
738 if (xv_p
== x11
->xv_port
) {
746 if (XvGrabPort(x11
->display
, x11
->xv_port
, CurrentTime
))
749 mp_msg(MSGT_VO
, MSGL_WARN
, MSGTR_LIBVO_XV_InvalidPortParameter
);
754 for (i
= 0; i
< ctx
->adaptors
&& x11
->xv_port
== 0; i
++) {
755 /* check if adaptor number has been specified */
756 if (xv_adaptor
!= -1 && xv_adaptor
!= i
)
759 if ((ctx
->ai
[i
].type
& XvInputMask
) && (ctx
->ai
[i
].type
& XvImageMask
)) {
760 for (xv_p
= ctx
->ai
[i
].base_id
;
761 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
; ++xv_p
)
762 if (!XvGrabPort(x11
->display
, xv_p
, CurrentTime
)) {
764 mp_msg(MSGT_VO
, MSGL_V
,
765 "[VO_XV] Using Xv Adapter #%d (%s)\n",
769 mp_msg(MSGT_VO
, MSGL_WARN
, MSGTR_LIBVO_XV_CouldNotGrabPort
,
777 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_CouldNotFindFreePort
);
779 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_NoXvideoSupport
);
783 if (!vo_xv_init_colorkey(vo
)) {
784 goto error
; // bail out, colorkey setup failed
786 vo_xv_enable_vsync(vo
);
787 vo_xv_get_max_img_dim(vo
, &ctx
->max_width
, &ctx
->max_height
);
789 ctx
->fo
= XvListImageFormats(x11
->display
, x11
->xv_port
,
790 (int *) &ctx
->formats
);
792 mp_input_add_key_fd(vo
->input_ctx
, ConnectionNumber(x11
->display
), 1,
793 x11_fd_callback
, NULL
, vo
);
794 ctx
->event_fd_registered
= 1;
798 uninit(vo
); // free resources
802 static int control(struct vo
*vo
, uint32_t request
, void *data
)
804 struct xvctx
*ctx
= vo
->priv
;
805 struct vo_x11_state
*x11
= vo
->x11
;
808 return (ctx
->is_paused
= 1);
810 return (ctx
->is_paused
= 0);
811 case VOCTRL_QUERY_FORMAT
:
812 return query_format(ctx
, *((uint32_t *) data
));
813 case VOCTRL_GET_IMAGE
:
814 return get_image(ctx
, data
);
815 case VOCTRL_DRAW_IMAGE
:
816 return draw_image(vo
, data
);
817 case VOCTRL_GUISUPPORT
:
819 case VOCTRL_GET_PANSCAN
:
820 if (!vo
->config_ok
|| !vo_fs
)
823 case VOCTRL_FULLSCREEN
:
824 vo_x11_fullscreen(vo
);
825 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
826 case VOCTRL_SET_PANSCAN
:
827 if ((vo_fs
&& (vo_panscan
!= vo
->panscan_amount
))
828 || (!vo_fs
&& vo
->panscan_amount
)) {
829 int old_y
= vo
->panscan_y
;
833 if (old_y
!= vo
->panscan_y
) {
834 vo_x11_clearwindow_part(vo
, x11
->window
,
835 vo
->dwidth
+ vo
->panscan_x
- 1,
836 vo
->dheight
+ vo
->panscan_y
- 1, 1);
837 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
838 ctx
->drwY
- (vo
->panscan_y
>> 1),
839 vo
->dwidth
+ vo
->panscan_x
- 1,
840 vo
->dheight
+ vo
->panscan_y
- 1);
845 case VOCTRL_SET_EQUALIZER
:
847 struct voctrl_set_equalizer_args
*args
= data
;
848 return vo_xv_set_eq(vo
, x11
->xv_port
, args
->name
, args
->value
);
850 case VOCTRL_GET_EQUALIZER
:
852 struct voctrl_get_equalizer_args
*args
= data
;
853 return vo_xv_get_eq(vo
, x11
->xv_port
, args
->name
, args
->valueptr
);
858 case VOCTRL_UPDATE_SCREENINFO
:
859 update_xinerama_info(vo
);
861 case VOCTRL_REDRAW_OSD
:
862 return redraw_osd(vo
, data
);
867 const struct vo_driver video_out_xv
= {
873 .draw_frame
= draw_frame
,
874 .draw_slice
= draw_slice
,
875 .draw_osd
= draw_osd
,
876 .flip_page
= flip_page
,
877 .check_events
= check_events
,