stream.h: Add 2 prototypes instead of declaring them in cache2.c
[mplayer.git] / libvo / vo_xv.c
blob6dfd8a8cf4c9a30e48e909ededf5732731cb5ee7
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)
5 #define NUM_BUFFERS 3
7 /*
8 Buffer allocation:
10 -nodr:
11 1: TEMP
12 2: 2*TEMP
14 -dr:
15 1: TEMP
16 3: 2*STATIC+TEMP
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
24 #include "config.h"
25 #include "options.h"
26 #include "talloc.h"
27 #include "mp_msg.h"
28 #include "help_mp.h"
29 #include "video_out.h"
30 #include "libmpcodecs/vfcap.h"
31 #include "libmpcodecs/mp_image.h"
32 #include "osd.h"
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <errno.h>
38 #include "x11_common.h"
40 #include "fastmemcpy.h"
41 #include "sub.h"
42 #include "aspect.h"
44 #include "subopt-helper.h"
46 #include "input/input.h"
47 #include "mp_fifo.h"
49 #ifdef CONFIG_GUI
50 #include "gui/interface.h"
51 #endif
53 #include "libavutil/common.h"
55 static const vo_info_t info = {
56 "X11/Xv",
57 "xv",
58 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
62 #ifdef HAVE_SHM
63 #include <sys/ipc.h>
64 #include <sys/shm.h>
65 #include <X11/extensions/XShm.h>
66 #endif
68 // Note: depends on the inclusion of X11/extensions/XShm.h
69 #include <X11/extensions/Xv.h>
70 #include <X11/extensions/Xvlib.h>
72 struct xvctx {
73 XvAdaptorInfo *ai;
74 XvImageFormatValues *fo;
75 unsigned int formats, adaptors, xv_format;
76 int current_buf;
77 int current_ip_buf;
78 int num_buffers;
79 int visible_buf;
80 XvImage *xvimage[NUM_BUFFERS];
81 uint32_t image_width;
82 uint32_t image_height;
83 uint32_t image_format;
84 int is_paused;
85 uint32_t drwX, drwY;
86 uint32_t max_width, max_height; // zero means: not set
87 int event_fd_registered; // for uninit called from preinit
88 int mode_switched;
89 void (*draw_alpha_fnc)(void *ctx, int x0, int y0, int w, int h,
90 unsigned char *src, unsigned char *srca,
91 int stride);
92 #ifdef HAVE_SHM
93 XShmSegmentInfo Shminfo[NUM_BUFFERS];
94 int Shmem_Flag;
95 #endif
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,
105 int stride)
107 struct vo *vo = p;
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,
120 int stride)
122 struct vo *vo = p;
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,
135 int stride)
137 struct vo *vo = p;
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,
150 int stride)
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;
159 *drwX = *drwY = 0;
160 if (vo_fs) {
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) {
169 *drwX = vo->dx;
170 *drwY = vo->dy;
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;
184 XSizeHints hint;
185 XVisualInfo vinfo;
186 XGCValues xgcv;
187 XSetWindowAttributes xswa;
188 XWindowAttributes attribs;
189 unsigned long xswamask;
190 int depth;
191 struct xvctx *ctx = vo->priv;
192 int i;
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);
203 return -1;
206 x11->vo_mouse_autohide = 1;
208 ctx->is_paused = 0;
209 ctx->visible_buf = -1;
211 /* check image formats */
212 ctx->xv_format = 0;
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;
221 if (!ctx->xv_format)
222 return -1;
224 #ifdef CONFIG_GUI
225 if (use_gui)
226 guiGetEvent(guiSetShVideo, 0); // let the GUI to setup/resize our window
227 else
228 #endif
230 hint.x = vo->dx;
231 hint.y = vo->dy;
232 hint.width = d_width;
233 hint.height = d_height;
234 #ifdef CONFIG_XF86VM
235 unsigned int modeline_width, modeline_height;
236 uint32_t vm_width;
237 uint32_t vm_height;
238 int vm = flags & VOFLAG_MODESWITCHING;
239 if (vm)
241 if ((d_width == 0) && (d_height == 0))
243 vm_width = ctx->image_width;
244 vm_height = ctx->image_height;
245 } else
247 vm_width = d_width;
248 vm_height = d_height;
250 vo_vm_switch(vo, vm_width, vm_height, &modeline_width,
251 &modeline_height);
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);
258 } else
259 #warning This "else" makes no sense
260 #endif
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),
265 &attribs);
266 depth = attribs.depth;
267 if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
268 depth = 24;
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;
279 if (WinID >= 0)
281 x11->window = WinID ? ((Window) WinID) : x11->rootwin;
282 if (WinID)
284 XUnmapWindow(x11->display, x11->window);
285 XChangeWindowAttributes(x11->display, x11->window, xswamask,
286 &xswa);
287 vo_x11_selectinput_witherr(x11->display, x11->window,
288 StructureNotifyMask |
289 KeyPressMask |
290 PropertyChangeMask |
291 PointerMotionMask |
292 ButtonPressMask |
293 ButtonReleaseMask |
294 ExposureMask);
295 XMapWindow(x11->display, x11->window);
296 Window mRoot;
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);
305 } else
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);
316 #ifdef CONFIG_XF86VM
317 if (vm)
319 /* Grab the mouse pointer in our window */
320 if (vo_grabpointer)
321 XGrabPointer(x11->display, x11->window, True, 0,
322 GrabModeAsync, GrabModeAsync,
323 x11->window, None, CurrentTime);
324 XSetInputFocus(x11->display, x11->window, RevertToNone, CurrentTime);
326 #endif
329 mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n",
330 x11->xv_port);
332 switch (ctx->xv_format)
334 case IMGFMT_YV12:
335 case IMGFMT_I420:
336 case IMGFMT_IYUV:
337 ctx->draw_alpha_fnc = draw_alpha_yv12;
338 break;
339 case IMGFMT_YUY2:
340 case IMGFMT_YVYU:
341 ctx->draw_alpha_fnc = draw_alpha_yuy2;
342 break;
343 case IMGFMT_UYVY:
344 ctx->draw_alpha_fnc = draw_alpha_uyvy;
345 break;
346 default:
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);
354 ctx->num_buffers =
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;
363 #if 0
364 set_gamma_correction();
365 #endif
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);
371 panscan_calc(vo);
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);
381 if (opts->vo_ontop)
382 vo_x11_setlayer(vo, x11->window, opts->vo_ontop);
384 return 0;
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
395 #ifdef HAVE_SHM
396 if (x11->display_is_local && XShmQueryExtension(x11->display))
397 ctx->Shmem_Flag = 1;
398 else
400 ctx->Shmem_Flag = 0;
401 mp_msg(MSGT_VO, MSGL_INFO,
402 MSGTR_LIBVO_XV_SharedMemoryNotSupported);
404 if (ctx->Shmem_Flag)
406 ctx->xvimage[foo] =
407 (XvImage *) XvShmCreateImage(x11->display, x11->xv_port, ctx->xv_format,
408 NULL, ctx->image_width, ctx->image_height,
409 &ctx->Shminfo[foo]);
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);
420 } else
421 #endif
423 ctx->xvimage[foo] =
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);
430 return;
433 static void deallocate_xvimage(struct vo *vo, int foo)
435 struct xvctx *ctx = vo->priv;
436 #ifdef HAVE_SHM
437 if (ctx->Shmem_Flag)
439 XShmDetach(vo->x11->display, &ctx->Shminfo[foo]);
440 shmdt(ctx->Shminfo[foo].shmaddr);
441 } else
442 #endif
444 free(ctx->xvimage[foo]->data);
446 XFree(ctx->xvimage[foo]);
448 XSync(vo->x11->display, False);
449 return;
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;
456 #ifdef HAVE_SHM
457 if (ctx->Shmem_Flag)
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,
464 False);
465 } else
466 #endif
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)
484 Window mRoot;
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)
532 ctx->current_buf =
533 vo_directrendering ? 0 : ((ctx->current_buf + 1) % ctx->num_buffers);
534 XFlush(vo->x11->display);
535 } else
536 XSync(vo->x11->display, False);
537 return;
540 static int draw_slice(struct vo *vo, uint8_t * image[], int stride[], int w,
541 int h, int x, int y)
543 struct xvctx *ctx = vo->priv;
544 uint8_t *dst;
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],
550 stride[0]);
552 x /= 2;
553 y /= 2;
554 w /= 2;
555 h /= 2;
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],
561 stride[1]);
562 else
563 memcpy_pic(dst, image[2], w, h, current_image->pitches[1],
564 stride[2]);
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],
570 stride[1]);
571 else
572 memcpy_pic(dst, image[2], w, h, current_image->pitches[1],
573 stride[2]);
575 return 0;
578 static int draw_frame(struct vo *vo, uint8_t * src[])
580 mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_XV_DrawFrameCalled);
581 return -1;
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)
589 // direct rendering:
590 ctx->current_buf = (int) (mpi->priv); // hack!
591 return VO_TRUE;
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);
598 return VO_TRUE;
600 if (mpi->flags & MP_IMGFLAG_YUV)
602 // packed 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]);
607 return VO_TRUE;
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)
631 return VO_FALSE;
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)
652 // I420
653 mpi->planes[1] =
654 current_image->data +
655 current_image->offsets[1];
656 mpi->planes[2] =
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];
661 } else
663 // YV12
664 mpi->planes[1] =
665 current_image->data +
666 current_image->offsets[2];
667 mpi->planes[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");
677 return VO_TRUE;
679 return VO_FALSE;
682 static int query_format(struct xvctx *ctx, uint32_t format)
684 uint32_t i;
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;
693 return 0;
696 static void uninit(struct vo *vo)
698 struct xvctx *ctx = vo->priv;
699 int i;
701 ctx->visible_buf = -1;
702 if (ctx->ai)
703 XvFreeAdaptorInfo(ctx->ai);
704 ctx->ai = NULL;
705 if (ctx->fo) {
706 XFree(ctx->fo);
707 ctx->fo = NULL;
709 for (i = 0; i < ctx->num_buffers; i++)
710 deallocate_xvimage(vo, i);
711 #ifdef CONFIG_XF86VM
712 if (ctx->mode_switched)
713 vo_vm_close(vo);
714 #endif
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()
718 vo_x11_uninit(vo);
721 static int x11_fd_callback(void *ctx, int fd)
723 struct vo *vo = ctx;
724 check_events(vo);
725 return mplayer_get_key(vo->key_fifo, 0);
728 static int preinit(struct vo *vo, const char *arg)
730 XvPortID xv_p;
731 int busy_ports = 0;
732 unsigned int i;
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);
736 vo->priv = ctx;
737 struct vo_x11_state *x11 = vo->x11;
738 int xv_adaptor = -1;
740 opt_t subopts[] =
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 },
747 { NULL }
750 x11->xv_port = 0;
752 /* parse suboptions */
753 if ( subopt_parse( arg, subopts ) != 0 )
755 return -1;
758 /* modify colorkey settings according to the given options */
759 xv_setup_colorkeyhandling(vo, ck_method_arg.str, ck_src_arg.str);
761 if (!vo_init(vo))
762 return -1;
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);
770 goto error;
773 /* check for Xvideo support */
774 if (Success !=
775 XvQueryAdaptors(x11->display, DefaultRootWindow(x11->display), &ctx->adaptors,
776 &ctx->ai))
778 mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed);
779 goto error;
782 /* check adaptors */
783 if (x11->xv_port)
785 int port_found;
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)
796 port_found = 1;
797 break;
802 if (port_found)
804 if (XvGrabPort(x11->display, x11->xv_port, CurrentTime))
805 x11->xv_port = 0;
806 } else
808 mp_msg(MSGT_VO, MSGL_WARN,
809 MSGTR_LIBVO_XV_InvalidPortParameter);
810 x11->xv_port = 0;
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)
818 continue;
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))
826 x11->xv_port = xv_p;
827 mp_msg(MSGT_VO, MSGL_V,
828 "[VO_XV] Using Xv Adapter #%d (%s)\n",
829 i, ctx->ai[i].name);
830 break;
831 } else
833 mp_msg(MSGT_VO, MSGL_WARN,
834 MSGTR_LIBVO_XV_CouldNotGrabPort, (int) xv_p);
835 ++busy_ports;
839 if (!x11->xv_port)
841 if (busy_ports)
842 mp_msg(MSGT_VO, MSGL_ERR,
843 MSGTR_LIBVO_XV_CouldNotFindFreePort);
844 else
845 mp_msg(MSGT_VO, MSGL_ERR,
846 MSGTR_LIBVO_XV_NoXvideoSupport);
847 goto error;
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;
861 return 0;
863 error:
864 uninit(vo); // free resources
865 return -1;
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;
872 switch (request)
874 case VOCTRL_PAUSE:
875 return (ctx->is_paused = 1);
876 case VOCTRL_RESUME:
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:
885 return VO_TRUE;
886 case VOCTRL_GET_PANSCAN:
887 if (!vo->config_ok || !vo_fs)
888 return VO_FALSE;
889 return VO_TRUE;
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;
899 panscan_calc(vo);
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);
911 flip_page(vo);
914 return VO_TRUE;
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);
925 case VOCTRL_ONTOP:
926 vo_x11_ontop(vo);
927 return VO_TRUE;
928 case VOCTRL_UPDATE_SCREENINFO:
929 update_xinerama_info(vo);
930 return VO_TRUE;
932 return VO_NOTIMPL;
935 const struct vo_driver video_out_xv = {
936 .is_new = 1,
937 .info = &info,
938 .preinit = preinit,
939 .config = config,
940 .control = control,
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,
946 .uninit = uninit