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)
47 #include "video_out.h"
48 #include "libmpcodecs/vfcap.h"
49 #include "libmpcodecs/mp_image.h"
53 #include <X11/Xutil.h>
56 #include "x11_common.h"
58 #include "fastmemcpy.h"
62 #include "subopt-helper.h"
64 #include "libavutil/common.h"
66 static const vo_info_t info
= {
69 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
76 #include <X11/extensions/XShm.h>
79 // Note: depends on the inclusion of X11/extensions/XShm.h
80 #include <X11/extensions/Xv.h>
81 #include <X11/extensions/Xvlib.h>
85 XvImageFormatValues
*fo
;
86 unsigned int formats
, adaptors
, xv_format
;
91 int have_visible_image_copy
;
92 int have_next_image_copy
;
93 int unchanged_visible_image
;
94 int unchanged_next_image
;
96 XvImage
*xvimage
[NUM_BUFFERS
+ 1];
98 uint32_t image_height
;
99 uint32_t image_format
;
101 struct vo_rect src_rect
;
102 struct vo_rect dst_rect
;
103 uint32_t max_width
, max_height
; // zero means: not set
105 int osd_objects_drawn
;
106 void (*draw_alpha_fnc
)(void *ctx
, int x0
, int y0
, int w
, int h
,
107 unsigned char *src
, unsigned char *srca
,
110 XShmSegmentInfo Shminfo
[NUM_BUFFERS
+ 1];
115 static void allocate_xvimage(struct vo
*, int);
118 static void fixup_osd_position(struct vo
*vo
, int *x0
, int *y0
, int *w
, int *h
)
120 struct xvctx
*ctx
= vo
->priv
;
121 *x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
122 / (vo
->dwidth
+ vo
->panscan_x
);
123 *w
= av_clip(*w
, 0, ctx
->image_width
);
124 *h
= av_clip(*h
, 0, ctx
->image_height
);
125 *x0
= FFMIN(*x0
, ctx
->image_width
- *w
);
126 *y0
= FFMIN(*y0
, ctx
->image_height
- *h
);
129 static void draw_alpha_yv12(void *p
, int x0
, int y0
, int w
, int h
,
130 unsigned char *src
, unsigned char *srca
,
134 struct xvctx
*ctx
= vo
->priv
;
135 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
136 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
,
137 ctx
->xvimage
[ctx
->current_buf
]->data
+
138 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
139 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ x0
,
140 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
141 ctx
->osd_objects_drawn
++;
144 static void draw_alpha_yuy2(void *p
, int x0
, int y0
, int w
, int h
,
145 unsigned char *src
, unsigned char *srca
,
149 struct xvctx
*ctx
= vo
->priv
;
150 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
151 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
152 ctx
->xvimage
[ctx
->current_buf
]->data
+
153 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
154 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
,
155 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
156 ctx
->osd_objects_drawn
++;
159 static void draw_alpha_uyvy(void *p
, int x0
, int y0
, int w
, int h
,
160 unsigned char *src
, unsigned char *srca
,
164 struct xvctx
*ctx
= vo
->priv
;
165 fixup_osd_position(vo
, &x0
, &y0
, &w
, &h
);
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
);
183 static void resize(struct vo
*vo
)
185 struct xvctx
*ctx
= vo
->priv
;
187 calc_src_dst_rects(vo
, ctx
->image_width
, ctx
->image_height
, &ctx
->src_rect
,
188 &ctx
->dst_rect
, NULL
, NULL
);
189 struct vo_rect
*dst
= &ctx
->dst_rect
;
190 vo_x11_clearwindow_part(vo
, vo
->x11
->window
, dst
->width
, dst
->height
, 1);
191 vo_xv_draw_colorkey(vo
, dst
->left
, dst
->top
, dst
->width
, dst
->height
);
195 * connect to server, create and map window,
196 * allocate colors and (shared) memory
198 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
199 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
200 char *title
, uint32_t format
)
202 struct vo_x11_state
*x11
= vo
->x11
;
204 XSetWindowAttributes xswa
;
205 XWindowAttributes attribs
;
206 unsigned long xswamask
;
208 struct xvctx
*ctx
= vo
->priv
;
211 ctx
->image_height
= height
;
212 ctx
->image_width
= width
;
213 ctx
->image_format
= format
;
215 if ((ctx
->max_width
!= 0 && ctx
->max_height
!= 0)
216 && (ctx
->image_width
> ctx
->max_width
217 || ctx
->image_height
> ctx
->max_height
)) {
218 mp_tmsg(MSGT_VO
, MSGL_ERR
, "Source image dimensions are too high: %ux%u (maximum is %ux%u)\n",
219 ctx
->image_width
, ctx
->image_height
, ctx
->max_width
,
224 ctx
->visible_buf
= -1;
225 ctx
->have_visible_image_copy
= false;
226 ctx
->have_next_image_copy
= false;
228 /* check image formats */
230 for (i
= 0; i
< ctx
->formats
; i
++) {
231 mp_msg(MSGT_VO
, MSGL_V
, "Xvideo image format: 0x%x (%4.4s) %s\n",
232 ctx
->fo
[i
].id
, (char *) &ctx
->fo
[i
].id
,
233 (ctx
->fo
[i
].format
== XvPacked
) ? "packed" : "planar");
234 if (ctx
->fo
[i
].id
== format
)
235 ctx
->xv_format
= ctx
->fo
[i
].id
;
242 int vm
= flags
& VOFLAG_MODESWITCHING
;
245 ctx
->mode_switched
= 1;
248 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
250 depth
= attribs
.depth
;
251 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
253 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
255 xswa
.background_pixel
= 0;
256 if (x11
->xv_ck_info
.method
== CK_METHOD_BACKGROUND
)
257 xswa
.background_pixel
= x11
->xv_colorkey
;
258 xswa
.border_pixel
= 0;
259 xswamask
= CWBackPixel
| CWBorderPixel
;
261 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, vo
->dwidth
,
262 vo
->dheight
, flags
, CopyFromParent
, "xv",
264 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
268 /* Grab the mouse pointer in our window */
270 XGrabPointer(x11
->display
, x11
->window
, True
, 0, GrabModeAsync
,
271 GrabModeAsync
, x11
->window
, None
, CurrentTime
);
272 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
,
278 mp_msg(MSGT_VO
, MSGL_V
, "using Xvideo port %d for hw scaling\n",
281 switch (ctx
->xv_format
) {
285 ctx
->draw_alpha_fnc
= draw_alpha_yv12
;
289 ctx
->draw_alpha_fnc
= draw_alpha_yuy2
;
292 ctx
->draw_alpha_fnc
= draw_alpha_uyvy
;
295 ctx
->draw_alpha_fnc
= draw_alpha_null
;
298 // In case config has been called before
299 for (i
= 0; i
< ctx
->total_buffers
; i
++)
300 deallocate_xvimage(vo
, i
);
303 vo_doublebuffering
? (vo_directrendering
? NUM_BUFFERS
: 2) : 1;
304 ctx
->total_buffers
= ctx
->num_buffers
+ 1;
306 for (i
= 0; i
< ctx
->total_buffers
; i
++)
307 allocate_xvimage(vo
, i
);
309 ctx
->current_buf
= 0;
310 ctx
->current_ip_buf
= 0;
318 static void allocate_xvimage(struct vo
*vo
, int foo
)
320 struct xvctx
*ctx
= vo
->priv
;
321 struct vo_x11_state
*x11
= vo
->x11
;
323 * allocate XvImages. FIXME: no error checking, without
324 * mit-shm this will bomb... trzing to fix ::atmos
327 if (x11
->display_is_local
&& XShmQueryExtension(x11
->display
))
331 mp_tmsg(MSGT_VO
, MSGL_INFO
, "[VO_XV] Shared memory not supported\nReverting to normal Xv.\n");
333 if (ctx
->Shmem_Flag
) {
335 (XvImage
*) XvShmCreateImage(x11
->display
, x11
->xv_port
,
336 ctx
->xv_format
, NULL
,
337 ctx
->image_width
, ctx
->image_height
,
340 ctx
->Shminfo
[foo
].shmid
= shmget(IPC_PRIVATE
,
341 ctx
->xvimage
[foo
]->data_size
,
343 ctx
->Shminfo
[foo
].shmaddr
= (char *) shmat(ctx
->Shminfo
[foo
].shmid
, 0,
345 ctx
->Shminfo
[foo
].readOnly
= False
;
347 ctx
->xvimage
[foo
]->data
= ctx
->Shminfo
[foo
].shmaddr
;
348 XShmAttach(x11
->display
, &ctx
->Shminfo
[foo
]);
349 XSync(x11
->display
, False
);
350 shmctl(ctx
->Shminfo
[foo
].shmid
, IPC_RMID
, 0);
355 (XvImage
*) XvCreateImage(x11
->display
, x11
->xv_port
,
356 ctx
->xv_format
, NULL
, ctx
->image_width
,
358 ctx
->xvimage
[foo
]->data
= malloc(ctx
->xvimage
[foo
]->data_size
);
359 XSync(x11
->display
, False
);
361 memset(ctx
->xvimage
[foo
]->data
, 128, ctx
->xvimage
[foo
]->data_size
);
365 static void deallocate_xvimage(struct vo
*vo
, int foo
)
367 struct xvctx
*ctx
= vo
->priv
;
369 if (ctx
->Shmem_Flag
) {
370 XShmDetach(vo
->x11
->display
, &ctx
->Shminfo
[foo
]);
371 shmdt(ctx
->Shminfo
[foo
].shmaddr
);
375 free(ctx
->xvimage
[foo
]->data
);
377 XFree(ctx
->xvimage
[foo
]);
379 XSync(vo
->x11
->display
, False
);
383 static inline void put_xvimage(struct vo
*vo
, XvImage
*xvi
)
385 struct xvctx
*ctx
= vo
->priv
;
386 struct vo_x11_state
*x11
= vo
->x11
;
387 struct vo_rect
*src
= &ctx
->src_rect
;
388 struct vo_rect
*dst
= &ctx
->dst_rect
;
390 if (ctx
->Shmem_Flag
) {
391 XvShmPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
,
392 src
->left
, src
->top
, src
->width
, src
->height
,
393 dst
->left
, dst
->top
, dst
->width
, dst
->height
,
398 XvPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
, xvi
,
399 src
->left
, src
->top
, src
->width
, src
->height
,
400 dst
->left
, dst
->top
, dst
->width
, dst
->height
);
404 // Only copies luma for planar formats as draw_alpha doesn't change others */
405 static void copy_backup_image(struct vo
*vo
, int dest
, int src
)
407 struct xvctx
*ctx
= vo
->priv
;
409 XvImage
*vb
= ctx
->xvimage
[dest
];
410 XvImage
*cp
= ctx
->xvimage
[src
];
411 memcpy_pic(vb
->data
+ vb
->offsets
[0], cp
->data
+ cp
->offsets
[0],
412 vb
->width
, vb
->height
,
413 vb
->pitches
[0], cp
->pitches
[0]);
416 static void check_events(struct vo
*vo
)
418 struct xvctx
*ctx
= vo
->priv
;
419 int e
= vo_x11_check_events(vo
);
421 if (e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
)
424 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && ctx
->is_paused
) {
425 /* did we already draw a buffer */
426 if (ctx
->visible_buf
!= -1) {
427 /* redraw the last visible buffer */
428 put_xvimage(vo
, ctx
->xvimage
[ctx
->visible_buf
]);
433 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
435 struct xvctx
*ctx
= vo
->priv
;
437 ctx
->osd_objects_drawn
= 0;
440 ctx
->image_width
* vo
->panscan_x
/ (vo
->dwidth
+
442 ctx
->image_height
, ctx
->draw_alpha_fnc
, vo
);
443 if (ctx
->osd_objects_drawn
)
444 ctx
->unchanged_next_image
= false;
447 static int redraw_osd(struct vo
*vo
, struct osd_state
*osd
)
449 struct xvctx
*ctx
= vo
->priv
;
451 if (ctx
->have_visible_image_copy
)
452 copy_backup_image(vo
, ctx
->visible_buf
, ctx
->num_buffers
);
453 else if (ctx
->unchanged_visible_image
) {
454 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->visible_buf
);
455 ctx
->have_visible_image_copy
= true;
459 int temp
= ctx
->current_buf
;
460 ctx
->current_buf
= ctx
->visible_buf
;
462 ctx
->current_buf
= temp
;
463 put_xvimage(vo
, ctx
->xvimage
[ctx
->visible_buf
]);
467 static void flip_page(struct vo
*vo
)
469 struct xvctx
*ctx
= vo
->priv
;
470 put_xvimage(vo
, ctx
->xvimage
[ctx
->current_buf
]);
472 /* remember the currently visible buffer */
473 ctx
->visible_buf
= ctx
->current_buf
;
475 ctx
->have_visible_image_copy
= ctx
->have_next_image_copy
;
476 ctx
->have_next_image_copy
= false;
477 ctx
->unchanged_visible_image
= ctx
->unchanged_next_image
;
478 ctx
->unchanged_next_image
= false;
480 if (ctx
->num_buffers
> 1) {
481 ctx
->current_buf
= vo_directrendering
? 0 : ((ctx
->current_buf
+ 1) %
483 XFlush(vo
->x11
->display
);
485 XSync(vo
->x11
->display
, False
);
489 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
492 struct xvctx
*ctx
= vo
->priv
;
494 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
496 dst
= current_image
->data
+ current_image
->offsets
[0]
497 + current_image
->pitches
[0] * y
+ x
;
498 memcpy_pic(dst
, image
[0], w
, h
, current_image
->pitches
[0], stride
[0]);
505 dst
= current_image
->data
+ current_image
->offsets
[1]
506 + current_image
->pitches
[1] * y
+ x
;
507 if (ctx
->image_format
!= IMGFMT_YV12
)
508 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
510 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
512 dst
= current_image
->data
+ current_image
->offsets
[2]
513 + current_image
->pitches
[2] * y
+ x
;
514 if (ctx
->image_format
== IMGFMT_YV12
)
515 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1], stride
[1]);
517 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1], stride
[2]);
522 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
524 struct xvctx
*ctx
= vo
->priv
;
526 ctx
->have_next_image_copy
= false;
528 if (mpi
->flags
& MP_IMGFLAG_DIRECT
)
530 ctx
->current_buf
= (int) (mpi
->priv
); // hack!
531 else if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
533 else if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
534 draw_slice(vo
, mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, 0, 0);
535 else if (mpi
->flags
& MP_IMGFLAG_YUV
)
537 memcpy_pic(ctx
->xvimage
[ctx
->current_buf
]->data
+
538 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0], mpi
->planes
[0],
539 mpi
->w
* (mpi
->bpp
/ 8), mpi
->h
,
540 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0], mpi
->stride
[0]);
544 if (ctx
->is_paused
) {
545 copy_backup_image(vo
, ctx
->num_buffers
, ctx
->current_buf
);
546 ctx
->have_next_image_copy
= true;
548 ctx
->unchanged_next_image
= true;
552 static uint32_t get_image(struct xvctx
*ctx
, mp_image_t
*mpi
)
554 // we shouldn't change current_buf unless we do DR!
555 int buf
= ctx
->current_buf
;
557 if (mpi
->type
== MP_IMGTYPE_STATIC
&& ctx
->num_buffers
> 1)
558 return VO_FALSE
; // it is not static
559 if (mpi
->imgfmt
!= ctx
->image_format
)
560 return VO_FALSE
; // needs conversion :(
561 if (mpi
->flags
& MP_IMGFLAG_READABLE
562 && (mpi
->type
== MP_IMGTYPE_IPB
|| mpi
->type
== MP_IMGTYPE_IP
)) {
563 // reference (I/P) frame of IP or IPB:
564 if (ctx
->num_buffers
< 2)
565 return VO_FALSE
; // not enough
566 ctx
->current_ip_buf
^= 1;
567 // for IPB with 2 buffers we can DR only one of the 2 P frames:
568 if (mpi
->type
== MP_IMGTYPE_IPB
&& ctx
->num_buffers
< 3
569 && ctx
->current_ip_buf
)
571 buf
= ctx
->current_ip_buf
;
572 if (mpi
->type
== MP_IMGTYPE_IPB
)
573 ++buf
; // preserve space for B
575 if (mpi
->height
> ctx
->xvimage
[buf
]->height
)
576 return VO_FALSE
; //buffer to small
577 if (mpi
->width
* (mpi
->bpp
/ 8) > ctx
->xvimage
[buf
]->pitches
[0])
578 return VO_FALSE
; //buffer to small
579 if ((mpi
->flags
& (MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_ACCEPT_WIDTH
))
580 || (mpi
->width
* (mpi
->bpp
/ 8) == ctx
->xvimage
[buf
]->pitches
[0])) {
581 ctx
->current_buf
= buf
;
582 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
583 mpi
->planes
[0] = current_image
->data
+ current_image
->offsets
[0];
584 mpi
->stride
[0] = current_image
->pitches
[0];
585 mpi
->width
= mpi
->stride
[0] / (mpi
->bpp
/ 8);
586 if (mpi
->flags
& MP_IMGFLAG_PLANAR
) {
587 if (mpi
->flags
& MP_IMGFLAG_SWAPPED
) {
589 mpi
->planes
[1] = current_image
->data
590 + current_image
->offsets
[1];
591 mpi
->planes
[2] = current_image
->data
592 + current_image
->offsets
[2];
593 mpi
->stride
[1] = current_image
->pitches
[1];
594 mpi
->stride
[2] = current_image
->pitches
[2];
597 mpi
->planes
[1] = current_image
->data
598 + current_image
->offsets
[2];
599 mpi
->planes
[2] = current_image
->data
600 + current_image
->offsets
[1];
601 mpi
->stride
[1] = current_image
->pitches
[2];
602 mpi
->stride
[2] = current_image
->pitches
[1];
605 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
606 mpi
->priv
= (void *) ctx
->current_buf
;
612 static int query_format(struct xvctx
*ctx
, uint32_t format
)
615 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
617 /* check image formats */
618 for (i
= 0; i
< ctx
->formats
; i
++) {
619 if (ctx
->fo
[i
].id
== format
)
620 return flag
; //xv_format = fo[i].id;
625 static void uninit(struct vo
*vo
)
627 struct xvctx
*ctx
= vo
->priv
;
630 ctx
->visible_buf
= -1;
632 XvFreeAdaptorInfo(ctx
->ai
);
638 for (i
= 0; i
< ctx
->total_buffers
; i
++)
639 deallocate_xvimage(vo
, i
);
641 if (ctx
->mode_switched
)
644 // uninit() shouldn't get called unless initialization went past vo_init()
648 static int preinit(struct vo
*vo
, const char *arg
)
653 strarg_t ck_src_arg
= { 0, NULL
};
654 strarg_t ck_method_arg
= { 0, NULL
};
655 struct xvctx
*ctx
= talloc_zero(vo
, struct xvctx
);
657 struct vo_x11_state
*x11
= vo
->x11
;
660 const opt_t subopts
[] =
662 /* name arg type arg var test */
663 { "port", OPT_ARG_INT
, &x11
->xv_port
, int_pos
},
664 { "adaptor", OPT_ARG_INT
, &xv_adaptor
, int_non_neg
},
665 { "ck", OPT_ARG_STR
, &ck_src_arg
, xv_test_ck
},
666 { "ck-method", OPT_ARG_STR
, &ck_method_arg
, xv_test_ckm
},
672 /* parse suboptions */
673 if (subopt_parse(arg
, subopts
) != 0) {
677 /* modify colorkey settings according to the given options */
678 xv_setup_colorkeyhandling(vo
, ck_method_arg
.str
, ck_src_arg
.str
);
683 /* check for Xvideo extension */
684 unsigned int ver
, rel
, req
, ev
, err
;
685 if (Success
!= XvQueryExtension(x11
->display
, &ver
, &rel
, &req
, &ev
, &err
)) {
686 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");
690 /* check for Xvideo support */
692 XvQueryAdaptors(x11
->display
, DefaultRootWindow(x11
->display
),
693 &ctx
->adaptors
, &ctx
->ai
)) {
694 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[VO_XV] XvQueryAdaptors failed.\n");
702 for (port_found
= 0, i
= 0; !port_found
&& i
< ctx
->adaptors
; i
++) {
703 if ((ctx
->ai
[i
].type
& XvInputMask
)
704 && (ctx
->ai
[i
].type
& XvImageMask
)) {
705 for (xv_p
= ctx
->ai
[i
].base_id
;
706 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
;
708 if (xv_p
== x11
->xv_port
) {
716 if (XvGrabPort(x11
->display
, x11
->xv_port
, CurrentTime
))
719 mp_tmsg(MSGT_VO
, MSGL_WARN
, "[VO_XV] Invalid port parameter, overriding with port 0.\n");
724 for (i
= 0; i
< ctx
->adaptors
&& x11
->xv_port
== 0; i
++) {
725 /* check if adaptor number has been specified */
726 if (xv_adaptor
!= -1 && xv_adaptor
!= i
)
729 if ((ctx
->ai
[i
].type
& XvInputMask
) && (ctx
->ai
[i
].type
& XvImageMask
)) {
730 for (xv_p
= ctx
->ai
[i
].base_id
;
731 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
; ++xv_p
)
732 if (!XvGrabPort(x11
->display
, xv_p
, CurrentTime
)) {
734 mp_msg(MSGT_VO
, MSGL_V
,
735 "[VO_XV] Using Xv Adapter #%d (%s)\n",
739 mp_tmsg(MSGT_VO
, MSGL_WARN
, "[VO_XV] Could not grab port %i.\n",
747 mp_tmsg(MSGT_VO
, MSGL_ERR
,
748 "[VO_XV] Could not find free Xvideo port - maybe another process is already\n"\
749 "[VO_XV] using it. Close all video applications, and try again. If that does\n"\
750 "[VO_XV] not help, see 'mplayer -vo help' for other (non-xv) video out drivers.\n");
752 mp_tmsg(MSGT_VO
, MSGL_ERR
,
753 "[VO_XV] It seems there is no Xvideo support for your video card available.\n"\
754 "[VO_XV] Run 'xvinfo' to verify its Xv support and read\n"\
755 "[VO_XV] DOCS/HTML/en/video.html#xv!\n"\
756 "[VO_XV] See 'mplayer -vo help' for other (non-xv) video out drivers.\n"\
757 "[VO_XV] Try -vo x11.\n");
761 if (!vo_xv_init_colorkey(vo
)) {
762 goto error
; // bail out, colorkey setup failed
764 vo_xv_enable_vsync(vo
);
765 vo_xv_get_max_img_dim(vo
, &ctx
->max_width
, &ctx
->max_height
);
767 ctx
->fo
= XvListImageFormats(x11
->display
, x11
->xv_port
,
768 (int *) &ctx
->formats
);
773 uninit(vo
); // free resources
777 static int control(struct vo
*vo
, uint32_t request
, void *data
)
779 struct xvctx
*ctx
= vo
->priv
;
780 struct vo_x11_state
*x11
= vo
->x11
;
783 return (ctx
->is_paused
= 1);
785 return (ctx
->is_paused
= 0);
786 case VOCTRL_QUERY_FORMAT
:
787 return query_format(ctx
, *((uint32_t *) data
));
788 case VOCTRL_GET_IMAGE
:
789 return get_image(ctx
, data
);
790 case VOCTRL_DRAW_IMAGE
:
791 return draw_image(vo
, data
);
792 case VOCTRL_GET_PANSCAN
:
794 case VOCTRL_FULLSCREEN
:
795 vo_x11_fullscreen(vo
);
796 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
797 case VOCTRL_SET_PANSCAN
:
800 case VOCTRL_SET_EQUALIZER
:
802 struct voctrl_set_equalizer_args
*args
= data
;
803 return vo_xv_set_eq(vo
, x11
->xv_port
, args
->name
, args
->value
);
805 case VOCTRL_GET_EQUALIZER
:
807 struct voctrl_get_equalizer_args
*args
= data
;
808 return vo_xv_get_eq(vo
, x11
->xv_port
, args
->name
, args
->valueptr
);
810 case VOCTRL_SET_YUV_COLORSPACE
:;
811 int given_cspc
= *(int *)data
% 2;
812 return vo_xv_set_eq(vo
, x11
->xv_port
, "bt_709", given_cspc
* 200 - 100);
813 case VOCTRL_GET_YUV_COLORSPACE
:;
815 if (!vo_xv_get_eq(vo
, x11
->xv_port
, "bt_709", &bt709_enabled
))
817 *(int *)data
= bt709_enabled
== 100;
822 case VOCTRL_UPDATE_SCREENINFO
:
823 update_xinerama_info(vo
);
825 case VOCTRL_REDRAW_OSD
:
826 return redraw_osd(vo
, data
);
831 const struct vo_driver video_out_xv
= {
837 .draw_slice
= draw_slice
,
838 .draw_osd
= draw_osd
,
839 .flip_page
= flip_page
,
840 .check_events
= check_events
,