1 /* vo_xv.c, X11 Xv interface */
3 // Number of buffers _FOR_DOUBLEBUFFERING_MODE_
4 // Use option -double to enable double buffering! (default: single buffer)
29 #include "video_out.h"
30 #include "libmpcodecs/vfcap.h"
31 #include "libmpcodecs/mp_image.h"
35 #include <X11/Xutil.h>
38 #include "x11_common.h"
40 #include "fastmemcpy.h"
44 #include "subopt-helper.h"
46 #include "input/input.h"
50 #include "gui/interface.h"
53 #include "libavutil/common.h"
55 static const vo_info_t info
= {
58 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
65 #include <X11/extensions/XShm.h>
68 // Note: depends on the inclusion of X11/extensions/XShm.h
69 #include <X11/extensions/Xv.h>
70 #include <X11/extensions/Xvlib.h>
74 XvImageFormatValues
*fo
;
75 unsigned int formats
, adaptors
, xv_format
;
80 XvImage
*xvimage
[NUM_BUFFERS
];
82 uint32_t image_height
;
83 uint32_t image_format
;
86 uint32_t max_width
, max_height
; // zero means: not set
87 int event_fd_registered
; // for uninit called from preinit
89 void (*draw_alpha_fnc
)(void *ctx
, int x0
, int y0
, int w
, int h
,
90 unsigned char *src
, unsigned char *srca
,
93 XShmSegmentInfo Shminfo
[NUM_BUFFERS
];
98 // FIXME: dynamically allocate this stuff
99 static void allocate_xvimage(struct vo
*, int);
103 static void draw_alpha_yv12(void *p
, int x0
, int y0
, int w
, int h
,
104 unsigned char *src
, unsigned char *srca
,
108 struct xvctx
*ctx
= vo
->priv
;
109 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
110 / (vo
->dwidth
+ vo
->panscan_x
);
111 vo_draw_alpha_yv12(w
, h
, src
, srca
, stride
,
112 ctx
->xvimage
[ctx
->current_buf
]->data
+
113 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
114 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ x0
,
115 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
118 static void draw_alpha_yuy2(void *p
, int x0
, int y0
, int w
, int h
,
119 unsigned char *src
, unsigned char *srca
,
123 struct xvctx
*ctx
= vo
->priv
;
124 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
125 / (vo
->dwidth
+ vo
->panscan_x
);
126 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
127 ctx
->xvimage
[ctx
->current_buf
]->data
+
128 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
129 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
,
130 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
133 static void draw_alpha_uyvy(void *p
, int x0
, int y0
, int w
, int h
,
134 unsigned char *src
, unsigned char *srca
,
138 struct xvctx
*ctx
= vo
->priv
;
139 x0
+= ctx
->image_width
* (vo
->panscan_x
>> 1)
140 / (vo
->dwidth
+ vo
->panscan_x
);
141 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
,
142 ctx
->xvimage
[ctx
->current_buf
]->data
+
143 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0] +
144 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0] * y0
+ 2 * x0
+ 1,
145 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0]);
148 static void draw_alpha_null(void *p
, int x0
, int y0
, int w
, int h
,
149 unsigned char *src
, unsigned char *srca
,
155 static void deallocate_xvimage(struct vo
*vo
, int foo
);
157 static void calc_drwXY(struct vo
*vo
, uint32_t *drwX
, uint32_t *drwY
) {
158 struct MPOpts
*opts
= vo
->opts
;
161 aspect(vo
, &vo
->dwidth
, &vo
->dheight
, A_ZOOM
);
162 vo
->dwidth
= FFMIN(vo
->dwidth
, opts
->vo_screenwidth
);
163 vo
->dheight
= FFMIN(vo
->dheight
, opts
->vo_screenheight
);
164 *drwX
= (opts
->vo_screenwidth
- vo
->dwidth
) / 2;
165 *drwY
= (opts
->vo_screenheight
- vo
->dheight
) / 2;
166 mp_msg(MSGT_VO
, MSGL_V
, "[xv-fs] dx: %d dy: %d dw: %d dh: %d\n",
167 *drwX
, *drwY
, vo
->dwidth
, vo
->dheight
);
168 } else if (WinID
== 0) {
175 * connect to server, create and map window,
176 * allocate colors and (shared) memory
178 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
179 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
180 char *title
, uint32_t format
)
182 struct MPOpts
*opts
= vo
->opts
;
183 struct vo_x11_state
*x11
= vo
->x11
;
187 XSetWindowAttributes xswa
;
188 XWindowAttributes attribs
;
189 unsigned long xswamask
;
191 struct xvctx
*ctx
= vo
->priv
;
194 ctx
->image_height
= height
;
195 ctx
->image_width
= width
;
196 ctx
->image_format
= format
;
198 if ((ctx
->max_width
!= 0 && ctx
->max_height
!= 0) &&
199 (ctx
->image_width
> ctx
->max_width
|| ctx
->image_height
> ctx
->max_height
))
201 mp_msg( MSGT_VO
, MSGL_ERR
, MSGTR_VO_XV_ImagedimTooHigh
,
202 ctx
->image_width
, ctx
->image_height
, ctx
->max_width
, ctx
->max_height
);
206 x11
->vo_mouse_autohide
= 1;
209 ctx
->visible_buf
= -1;
211 /* check image formats */
213 for (i
= 0; i
< ctx
->formats
; i
++) {
214 mp_msg(MSGT_VO
, MSGL_V
,
215 "Xvideo image format: 0x%x (%4.4s) %s\n", ctx
->fo
[i
].id
,
216 (char *) &ctx
->fo
[i
].id
,
217 (ctx
->fo
[i
].format
== XvPacked
) ? "packed" : "planar");
218 if (ctx
->fo
[i
].id
== format
)
219 ctx
->xv_format
= ctx
->fo
[i
].id
;
226 guiGetEvent(guiSetShVideo
, 0); // let the GUI to setup/resize our window
232 hint
.width
= d_width
;
233 hint
.height
= d_height
;
235 unsigned int modeline_width
, modeline_height
;
238 int vm
= flags
& VOFLAG_MODESWITCHING
;
241 if ((d_width
== 0) && (d_height
== 0))
243 vm_width
= ctx
->image_width
;
244 vm_height
= ctx
->image_height
;
248 vm_height
= d_height
;
250 vo_vm_switch(vo
, vm_width
, vm_height
, &modeline_width
,
252 ctx
->mode_switched
= 1;
253 hint
.x
= (opts
->vo_screenwidth
- modeline_width
) / 2;
254 hint
.y
= (opts
->vo_screenheight
- modeline_height
) / 2;
255 hint
.width
= modeline_width
;
256 hint
.height
= modeline_height
;
257 aspect_save_screenres(vo
, modeline_width
, modeline_height
);
259 #warning This "else" makes no sense
261 hint
.flags
= PPosition
| PSize
/* | PBaseSize */ ;
262 hint
.base_width
= hint
.width
;
263 hint
.base_height
= hint
.height
;
264 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
266 depth
= attribs
.depth
;
267 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
269 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
271 xswa
.background_pixel
= 0;
272 if (x11
->xv_ck_info
.method
== CK_METHOD_BACKGROUND
)
274 xswa
.background_pixel
= x11
->xv_colorkey
;
276 xswa
.border_pixel
= 0;
277 xswamask
= CWBackPixel
| CWBorderPixel
;
281 x11
->window
= WinID
? ((Window
) WinID
) : x11
->rootwin
;
284 XUnmapWindow(x11
->display
, x11
->window
);
285 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
,
287 vo_x11_selectinput_witherr(x11
->display
, x11
->window
,
288 StructureNotifyMask
|
295 XMapWindow(x11
->display
, x11
->window
);
297 uint32_t drwBorderWidth
, drwDepth
;
298 XGetGeometry(x11
->display
, x11
->window
, &mRoot
,
299 &ctx
->drwX
, &ctx
->drwY
, &vo
->dwidth
, &vo
->dheight
,
300 &drwBorderWidth
, &drwDepth
);
301 if (vo
->dwidth
<= 0) vo
->dwidth
= d_width
;
302 if (vo
->dheight
<= 0) vo
->dheight
= d_height
;
303 aspect_save_prescale(vo
, vo
->dwidth
, vo
->dheight
);
307 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, d_width
, d_height
,
308 flags
, CopyFromParent
, "xv", title
);
309 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
312 if (x11
->vo_gc
!= None
)
313 XFreeGC(x11
->display
, x11
->vo_gc
);
314 x11
->vo_gc
= XCreateGC(x11
->display
, x11
->window
, 0L, &xgcv
);
315 XSync(x11
->display
, False
);
319 /* Grab the mouse pointer in our window */
321 XGrabPointer(x11
->display
, x11
->window
, True
, 0,
322 GrabModeAsync
, GrabModeAsync
,
323 x11
->window
, None
, CurrentTime
);
324 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
, CurrentTime
);
329 mp_msg(MSGT_VO
, MSGL_V
, "using Xvideo port %d for hw scaling\n",
332 switch (ctx
->xv_format
)
337 ctx
->draw_alpha_fnc
= draw_alpha_yv12
;
341 ctx
->draw_alpha_fnc
= draw_alpha_yuy2
;
344 ctx
->draw_alpha_fnc
= draw_alpha_uyvy
;
347 ctx
->draw_alpha_fnc
= draw_alpha_null
;
350 // In case config has been called before
351 for (i
= 0; i
< ctx
->num_buffers
; i
++)
352 deallocate_xvimage(vo
, i
);
355 vo_doublebuffering
? (vo_directrendering
? NUM_BUFFERS
: 2) : 1;
357 for (i
= 0; i
< ctx
->num_buffers
; i
++)
358 allocate_xvimage(vo
, i
);
360 ctx
->current_buf
= 0;
361 ctx
->current_ip_buf
= 0;
364 set_gamma_correction();
367 aspect(vo
, &vo
->dwidth
, &vo
->dheight
, A_NOZOOM
);
368 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0) vo_fs
= 1;
369 calc_drwXY(vo
, &ctx
->drwX
, &ctx
->drwY
);
373 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
374 ctx
->drwY
- (vo
->panscan_y
>> 1),
375 vo
->dwidth
+ vo
->panscan_x
- 1,
376 vo
->dheight
+ vo
->panscan_y
- 1);
378 mp_msg(MSGT_VO
, MSGL_V
, "[xv] dx: %d dy: %d dw: %d dh: %d\n", ctx
->drwX
,
379 ctx
->drwY
, vo
->dwidth
, vo
->dheight
);
382 vo_x11_setlayer(vo
, x11
->window
, opts
->vo_ontop
);
387 static void allocate_xvimage(struct vo
*vo
, int foo
)
389 struct xvctx
*ctx
= vo
->priv
;
390 struct vo_x11_state
*x11
= vo
->x11
;
392 * allocate XvImages. FIXME: no error checking, without
393 * mit-shm this will bomb... trzing to fix ::atmos
396 if (x11
->display_is_local
&& XShmQueryExtension(x11
->display
))
401 mp_msg(MSGT_VO
, MSGL_INFO
,
402 MSGTR_LIBVO_XV_SharedMemoryNotSupported
);
407 (XvImage
*) XvShmCreateImage(x11
->display
, x11
->xv_port
, ctx
->xv_format
,
408 NULL
, ctx
->image_width
, ctx
->image_height
,
411 ctx
->Shminfo
[foo
].shmid
=
412 shmget(IPC_PRIVATE
, ctx
->xvimage
[foo
]->data_size
, IPC_CREAT
| 0777);
413 ctx
->Shminfo
[foo
].shmaddr
= (char *) shmat(ctx
->Shminfo
[foo
].shmid
, 0, 0);
414 ctx
->Shminfo
[foo
].readOnly
= False
;
416 ctx
->xvimage
[foo
]->data
= ctx
->Shminfo
[foo
].shmaddr
;
417 XShmAttach(x11
->display
, &ctx
->Shminfo
[foo
]);
418 XSync(x11
->display
, False
);
419 shmctl(ctx
->Shminfo
[foo
].shmid
, IPC_RMID
, 0);
424 (XvImage
*) XvCreateImage(x11
->display
, x11
->xv_port
, ctx
->xv_format
, NULL
,
425 ctx
->image_width
, ctx
->image_height
);
426 ctx
->xvimage
[foo
]->data
= malloc(ctx
->xvimage
[foo
]->data_size
);
427 XSync(x11
->display
, False
);
429 memset(ctx
->xvimage
[foo
]->data
, 128, ctx
->xvimage
[foo
]->data_size
);
433 static void deallocate_xvimage(struct vo
*vo
, int foo
)
435 struct xvctx
*ctx
= vo
->priv
;
439 XShmDetach(vo
->x11
->display
, &ctx
->Shminfo
[foo
]);
440 shmdt(ctx
->Shminfo
[foo
].shmaddr
);
444 free(ctx
->xvimage
[foo
]->data
);
446 XFree(ctx
->xvimage
[foo
]);
448 XSync(vo
->x11
->display
, False
);
452 static inline void put_xvimage(struct vo
*vo
, XvImage
*xvi
)
454 struct xvctx
*ctx
= vo
->priv
;
455 struct vo_x11_state
*x11
= vo
->x11
;
459 XvShmPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
,
460 xvi
, 0, 0, ctx
->image_width
,
461 ctx
->image_height
, ctx
->drwX
- (vo
->panscan_x
>> 1),
462 ctx
->drwY
- (vo
->panscan_y
>> 1), vo
->dwidth
+ vo
->panscan_x
,
463 vo
->dheight
+ vo
->panscan_y
,
468 XvPutImage(x11
->display
, x11
->xv_port
, x11
->window
, x11
->vo_gc
,
469 xvi
, 0, 0, ctx
->image_width
, ctx
->image_height
,
470 ctx
->drwX
- (vo
->panscan_x
>> 1), ctx
->drwY
- (vo
->panscan_y
>> 1),
471 vo
->dwidth
+ vo
->panscan_x
,
472 vo
->dheight
+ vo
->panscan_y
);
476 static void check_events(struct vo
*vo
)
478 struct xvctx
*ctx
= vo
->priv
;
479 struct vo_x11_state
*x11
= vo
->x11
;
480 int e
= vo_x11_check_events(vo
);
482 if (e
& VO_EVENT_RESIZE
)
485 uint32_t drwBorderWidth
, drwDepth
;
486 XGetGeometry(x11
->display
, x11
->window
, &mRoot
, &ctx
->drwX
, &ctx
->drwY
,
487 &vo
->dwidth
, &vo
->dheight
, &drwBorderWidth
, &drwDepth
);
488 mp_msg(MSGT_VO
, MSGL_V
, "[xv] dx: %d dy: %d dw: %d dh: %d\n", ctx
->drwX
,
489 ctx
->drwY
, vo
->dwidth
, vo
->dheight
);
491 calc_drwXY(vo
, &ctx
->drwX
, &ctx
->drwY
);
494 if (e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
)
496 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
497 ctx
->drwY
- (vo
->panscan_y
>> 1),
498 vo
->dwidth
+ vo
->panscan_x
- 1,
499 vo
->dheight
+ vo
->panscan_y
- 1);
502 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && ctx
->is_paused
)
504 /* did we already draw a buffer */
505 if ( ctx
->visible_buf
!= -1 )
507 /* redraw the last visible buffer */
508 put_xvimage(vo
, ctx
->xvimage
[ctx
->visible_buf
]);
513 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
515 struct xvctx
*ctx
= vo
->priv
;
517 osd_draw_text(osd
, ctx
->image_width
-
518 ctx
->image_width
* vo
->panscan_x
/ (vo
->dwidth
+ vo
->panscan_x
),
519 ctx
->image_height
, ctx
->draw_alpha_fnc
, vo
);
522 static void flip_page(struct vo
*vo
)
524 struct xvctx
*ctx
= vo
->priv
;
525 put_xvimage(vo
, ctx
->xvimage
[ctx
->current_buf
]);
527 /* remember the currently visible buffer */
528 ctx
->visible_buf
= ctx
->current_buf
;
530 if (ctx
->num_buffers
> 1)
533 vo_directrendering
? 0 : ((ctx
->current_buf
+ 1) % ctx
->num_buffers
);
534 XFlush(vo
->x11
->display
);
536 XSync(vo
->x11
->display
, False
);
540 static int draw_slice(struct vo
*vo
, uint8_t * image
[], int stride
[], int w
,
543 struct xvctx
*ctx
= vo
->priv
;
545 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
547 dst
= current_image
->data
+ current_image
->offsets
[0] +
548 current_image
->pitches
[0] * y
+ x
;
549 memcpy_pic(dst
, image
[0], w
, h
, current_image
->pitches
[0],
557 dst
= current_image
->data
+ current_image
->offsets
[1] +
558 current_image
->pitches
[1] * y
+ x
;
559 if (ctx
->image_format
!= IMGFMT_YV12
)
560 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1],
563 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1],
566 dst
= current_image
->data
+ current_image
->offsets
[2] +
567 current_image
->pitches
[2] * y
+ x
;
568 if (ctx
->image_format
== IMGFMT_YV12
)
569 memcpy_pic(dst
, image
[1], w
, h
, current_image
->pitches
[1],
572 memcpy_pic(dst
, image
[2], w
, h
, current_image
->pitches
[1],
578 static int draw_frame(struct vo
*vo
, uint8_t * src
[])
580 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_XV_DrawFrameCalled
);
584 static uint32_t draw_image(struct vo
*vo
, mp_image_t
* mpi
)
586 struct xvctx
*ctx
= vo
->priv
;
587 if (mpi
->flags
& MP_IMGFLAG_DIRECT
)
590 ctx
->current_buf
= (int) (mpi
->priv
); // hack!
593 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
594 return VO_TRUE
; // done
595 if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
597 draw_slice(vo
, mpi
->planes
, mpi
->stride
, mpi
->w
, mpi
->h
, 0, 0);
600 if (mpi
->flags
& MP_IMGFLAG_YUV
)
603 memcpy_pic(ctx
->xvimage
[ctx
->current_buf
]->data
+
604 ctx
->xvimage
[ctx
->current_buf
]->offsets
[0], mpi
->planes
[0],
605 mpi
->w
* (mpi
->bpp
/ 8), mpi
->h
,
606 ctx
->xvimage
[ctx
->current_buf
]->pitches
[0], mpi
->stride
[0]);
609 return VO_FALSE
; // not (yet) supported
612 static uint32_t get_image(struct xvctx
*ctx
, mp_image_t
* mpi
)
614 int buf
= ctx
->current_buf
; // we shouldn't change current_buf unless we do DR!
616 if (mpi
->type
== MP_IMGTYPE_STATIC
&& ctx
->num_buffers
> 1)
617 return VO_FALSE
; // it is not static
618 if (mpi
->imgfmt
!= ctx
->image_format
)
619 return VO_FALSE
; // needs conversion :(
620 // if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram
621 if (mpi
->flags
& MP_IMGFLAG_READABLE
&&
622 (mpi
->type
== MP_IMGTYPE_IPB
|| mpi
->type
== MP_IMGTYPE_IP
))
624 // reference (I/P) frame of IP or IPB:
625 if (ctx
->num_buffers
< 2)
626 return VO_FALSE
; // not enough
627 ctx
->current_ip_buf
^= 1;
628 // for IPB with 2 buffers we can DR only one of the 2 P frames:
629 if (mpi
->type
== MP_IMGTYPE_IPB
&& ctx
->num_buffers
< 3
630 && ctx
->current_ip_buf
)
632 buf
= ctx
->current_ip_buf
;
633 if (mpi
->type
== MP_IMGTYPE_IPB
)
634 ++buf
; // preserve space for B
636 if (mpi
->height
> ctx
->xvimage
[buf
]->height
)
637 return VO_FALSE
; //buffer to small
638 if (mpi
->width
* (mpi
->bpp
/ 8) > ctx
->xvimage
[buf
]->pitches
[0])
639 return VO_FALSE
; //buffer to small
640 if ((mpi
->flags
& (MP_IMGFLAG_ACCEPT_STRIDE
| MP_IMGFLAG_ACCEPT_WIDTH
))
641 || (mpi
->width
* (mpi
->bpp
/ 8) == ctx
->xvimage
[buf
]->pitches
[0]))
643 ctx
->current_buf
= buf
;
644 XvImage
*current_image
= ctx
->xvimage
[ctx
->current_buf
];
645 mpi
->planes
[0] = current_image
->data
+ current_image
->offsets
[0];
646 mpi
->stride
[0] = current_image
->pitches
[0];
647 mpi
->width
= mpi
->stride
[0] / (mpi
->bpp
/ 8);
648 if (mpi
->flags
& MP_IMGFLAG_PLANAR
)
650 if (mpi
->flags
& MP_IMGFLAG_SWAPPED
)
654 current_image
->data
+
655 current_image
->offsets
[1];
657 current_image
->data
+
658 current_image
->offsets
[2];
659 mpi
->stride
[1] = current_image
->pitches
[1];
660 mpi
->stride
[2] = current_image
->pitches
[2];
665 current_image
->data
+
666 current_image
->offsets
[2];
668 current_image
->data
+
669 current_image
->offsets
[1];
670 mpi
->stride
[1] = current_image
->pitches
[2];
671 mpi
->stride
[2] = current_image
->pitches
[1];
674 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
675 mpi
->priv
= (void *) ctx
->current_buf
;
676 // printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n");
682 static int query_format(struct xvctx
*ctx
, uint32_t format
)
685 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
687 /* check image formats */
688 for (i
= 0; i
< ctx
->formats
; i
++)
690 if (ctx
->fo
[i
].id
== format
)
691 return flag
; //xv_format = fo[i].id;
696 static void uninit(struct vo
*vo
)
698 struct xvctx
*ctx
= vo
->priv
;
701 ctx
->visible_buf
= -1;
703 XvFreeAdaptorInfo(ctx
->ai
);
709 for (i
= 0; i
< ctx
->num_buffers
; i
++)
710 deallocate_xvimage(vo
, i
);
712 if (ctx
->mode_switched
)
715 if (ctx
->event_fd_registered
)
716 mp_input_rm_key_fd(vo
->input_ctx
, ConnectionNumber(vo
->x11
->display
));
717 // uninit() shouldn't get called unless initialization went past vo_init()
721 static int x11_fd_callback(void *ctx
, int fd
)
725 return mplayer_get_key(vo
->key_fifo
, 0);
728 static int preinit(struct vo
*vo
, const char *arg
)
733 strarg_t ck_src_arg
= { 0, NULL
};
734 strarg_t ck_method_arg
= { 0, NULL
};
735 struct xvctx
*ctx
= talloc_zero(vo
, struct xvctx
);
737 struct vo_x11_state
*x11
= vo
->x11
;
742 /* name arg type arg var test */
743 { "port", OPT_ARG_INT
, &x11
->xv_port
, (opt_test_f
)int_pos
},
744 { "adaptor", OPT_ARG_INT
, &xv_adaptor
, (opt_test_f
)int_non_neg
},
745 { "ck", OPT_ARG_STR
, &ck_src_arg
, xv_test_ck
},
746 { "ck-method", OPT_ARG_STR
, &ck_method_arg
, xv_test_ckm
},
752 /* parse suboptions */
753 if ( subopt_parse( arg
, subopts
) != 0 )
758 /* modify colorkey settings according to the given options */
759 xv_setup_colorkeyhandling(vo
, ck_method_arg
.str
, ck_src_arg
.str
);
764 /* check for Xvideo extension */
765 unsigned int ver
, rel
, req
, ev
, err
;
766 if (Success
!= XvQueryExtension(x11
->display
, &ver
, &rel
, &req
, &ev
, &err
))
768 mp_msg(MSGT_VO
, MSGL_ERR
,
769 MSGTR_LIBVO_XV_XvNotSupportedByX11
);
773 /* check for Xvideo support */
775 XvQueryAdaptors(x11
->display
, DefaultRootWindow(x11
->display
), &ctx
->adaptors
,
778 mp_msg(MSGT_VO
, MSGL_ERR
, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed
);
787 for (port_found
= 0, i
= 0; !port_found
&& i
< ctx
->adaptors
; i
++)
789 if ((ctx
->ai
[i
].type
& XvInputMask
) && (ctx
->ai
[i
].type
& XvImageMask
))
791 for (xv_p
= ctx
->ai
[i
].base_id
;
792 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
; ++xv_p
)
794 if (xv_p
== x11
->xv_port
)
804 if (XvGrabPort(x11
->display
, x11
->xv_port
, CurrentTime
))
808 mp_msg(MSGT_VO
, MSGL_WARN
,
809 MSGTR_LIBVO_XV_InvalidPortParameter
);
814 for (i
= 0; i
< ctx
->adaptors
&& x11
->xv_port
== 0; i
++)
816 /* check if adaptor number has been specified */
817 if (xv_adaptor
!= -1 && xv_adaptor
!= i
)
820 if ((ctx
->ai
[i
].type
& XvInputMask
) && (ctx
->ai
[i
].type
& XvImageMask
))
822 for (xv_p
= ctx
->ai
[i
].base_id
;
823 xv_p
< ctx
->ai
[i
].base_id
+ ctx
->ai
[i
].num_ports
; ++xv_p
)
824 if (!XvGrabPort(x11
->display
, xv_p
, CurrentTime
))
827 mp_msg(MSGT_VO
, MSGL_V
,
828 "[VO_XV] Using Xv Adapter #%d (%s)\n",
833 mp_msg(MSGT_VO
, MSGL_WARN
,
834 MSGTR_LIBVO_XV_CouldNotGrabPort
, (int) xv_p
);
842 mp_msg(MSGT_VO
, MSGL_ERR
,
843 MSGTR_LIBVO_XV_CouldNotFindFreePort
);
845 mp_msg(MSGT_VO
, MSGL_ERR
,
846 MSGTR_LIBVO_XV_NoXvideoSupport
);
850 if (!vo_xv_init_colorkey(vo
)) {
851 goto error
; // bail out, colorkey setup failed
853 vo_xv_enable_vsync(vo
);
854 vo_xv_get_max_img_dim(vo
, &ctx
->max_width
, &ctx
->max_height
);
856 ctx
->fo
= XvListImageFormats(x11
->display
, x11
->xv_port
, (int *) &ctx
->formats
);
858 mp_input_add_key_fd(vo
->input_ctx
, ConnectionNumber(x11
->display
), 1,
859 x11_fd_callback
, NULL
, vo
);
860 ctx
->event_fd_registered
= 1;
864 uninit(vo
); // free resources
868 static int control(struct vo
*vo
, uint32_t request
, void *data
)
870 struct xvctx
*ctx
= vo
->priv
;
871 struct vo_x11_state
*x11
= vo
->x11
;
875 return (ctx
->is_paused
= 1);
877 return (ctx
->is_paused
= 0);
878 case VOCTRL_QUERY_FORMAT
:
879 return query_format(ctx
, *((uint32_t *) data
));
880 case VOCTRL_GET_IMAGE
:
881 return get_image(ctx
, data
);
882 case VOCTRL_DRAW_IMAGE
:
883 return draw_image(vo
, data
);
884 case VOCTRL_GUISUPPORT
:
886 case VOCTRL_GET_PANSCAN
:
887 if (!vo
->config_ok
|| !vo_fs
)
890 case VOCTRL_FULLSCREEN
:
891 vo_x11_fullscreen(vo
);
892 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
893 case VOCTRL_SET_PANSCAN
:
894 if ((vo_fs
&& (vo_panscan
!= vo
->panscan_amount
))
895 || (!vo_fs
&& vo
->panscan_amount
))
897 int old_y
= vo
->panscan_y
;
901 if (old_y
!= vo
->panscan_y
)
903 vo_x11_clearwindow_part(vo
, x11
->window
,
904 vo
->dwidth
+ vo
->panscan_x
- 1,
905 vo
->dheight
+ vo
->panscan_y
- 1,
907 vo_xv_draw_colorkey(vo
, ctx
->drwX
- (vo
->panscan_x
>> 1),
908 ctx
->drwY
- (vo
->panscan_y
>> 1),
909 vo
->dwidth
+ vo
->panscan_x
- 1,
910 vo
->dheight
+ vo
->panscan_y
- 1);
915 case VOCTRL_SET_EQUALIZER
:
917 struct voctrl_set_equalizer_args
*args
= data
;
918 return vo_xv_set_eq(vo
, x11
->xv_port
, args
->name
, args
->value
);
920 case VOCTRL_GET_EQUALIZER
:
922 struct voctrl_get_equalizer_args
*args
= data
;
923 return vo_xv_get_eq(vo
, x11
->xv_port
, args
->name
, args
->valueptr
);
928 case VOCTRL_UPDATE_SCREENINFO
:
929 update_xinerama_info(vo
);
935 const struct vo_driver video_out_xv
= {
941 .draw_frame
= draw_frame
,
942 .draw_slice
= draw_slice
,
943 .draw_osd
= draw_osd
,
944 .flip_page
= flip_page
,
945 .check_events
= check_events
,