Fix TFP code.
[vaapi:mplayer.git] / libvo / vo_vaapi.c
1 /*
2  * VA API output module
3  *
4  * Copyright (C) 2008-2009 Splitted-Desktop Systems
5  *
6  * This file is part of MPlayer.
7  *
8  * MPlayer is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * MPlayer is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "help_mp.h"
26 #include "subopt-helper.h"
27 #include "video_out.h"
28 #include "video_out_internal.h"
29 #include "fastmemcpy.h"
30 #include "sub.h"
31 #include "x11_common.h"
32 #include "libavutil/common.h"
33 #include "libavcodec/vaapi.h"
34 #include "gui/interface.h"
35 #include "stats.h"
36 #include "libass/ass_mp.h"
37 #include <stdarg.h>
38
39 #if CONFIG_GL
40 #include "gl_common.h"
41 #include <GL/glu.h>
42 #include <GL/glx.h>
43 #endif
44
45 #include <assert.h>
46 #include <X11/Xlib.h>
47 #include <X11/Xutil.h>
48 #include <va/va_x11.h>
49 #if CONFIG_VAAPI_GLX
50 #include <va/va_glx.h>
51 #endif
52
53 #if CONFIG_XRENDER
54 #include <X11/extensions/Xrender.h>
55 #endif
56
57 /* Compatibility glue with VA-API >= 0.30 */
58 #ifndef VA_INVALID_ID
59 #define VA_INVALID_ID           0xffffffff
60 #endif
61 #ifndef VA_FOURCC
62 #define VA_FOURCC(ch0, ch1, ch2, ch3)           \
63     ((uint32_t)(uint8_t)(ch0) |                 \
64      ((uint32_t)(uint8_t)(ch1) << 8) |          \
65      ((uint32_t)(uint8_t)(ch2) << 16) |         \
66      ((uint32_t)(uint8_t)(ch3) << 24 ))
67 #endif
68 #if defined VA_SRC_BT601 && defined VA_SRC_BT709
69 #define USE_VAAPI_COLORSPACE 1
70 #else
71 #define USE_VAAPI_COLORSPACE 0
72 #endif
73
74 /* Defined to 1 if IA44/AI44 subpicture formats are allowed */
75 /* XXX: they are not visually attractive... */
76 #define USE_VAAPI_IA44_FORMATS 0
77
78 /* Defined to 1 if VA/GLX 'bind' API is available */
79 #define USE_VAAPI_GLX_BIND                                \
80     (VA_MAJOR_VERSION == 0 &&                             \
81      ((VA_MINOR_VERSION == 30 &&                          \
82        VA_MICRO_VERSION == 4 && VA_SDS_VERSION >= 5) ||   \
83       (VA_MINOR_VERSION == 31 &&                          \
84        VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5)))
85
86 /* Compatibility glue with VA-API >= 0.31 */
87 #if defined VA_CHECK_VERSION
88 #if VA_CHECK_VERSION(0,31,0)
89 #define vaPutImage2             vaPutImage
90 #define vaAssociateSubpicture2  vaAssociateSubpicture
91 #endif
92 #endif
93
94 static vo_info_t info = {
95     "VA API with X11",
96     "vaapi",
97     "Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>",
98     ""
99 };
100
101 const LIBVO_EXTERN(vaapi)
102
103 /* Numbers of video surfaces */
104 #define MAX_OUTPUT_SURFACES       2 /* Maintain synchronisation points in flip_page() */
105 #define MAX_VIDEO_SURFACES       21 /* Maintain free surfaces in a queue (use least-recently-used) */
106 #define NUM_VIDEO_SURFACES_MPEG2  3 /* 1 decode frame, up to  2 references */
107 #define NUM_VIDEO_SURFACES_MPEG4  3 /* 1 decode frame, up to  2 references */
108 #define NUM_VIDEO_SURFACES_H264  21 /* 1 decode frame, up to 20 references */
109 #define NUM_VIDEO_SURFACES_VC1    3 /* 1 decode frame, up to  2 references */
110
111 static void ensure_osd(void);
112 static int reset_xrender_specific(void);
113
114 typedef void (*draw_alpha_func)(int x0, int y0, int w, int h,
115                                 unsigned char *src, unsigned char *srca,
116                                 int stride);
117
118 typedef void (*eosd_draw_alpha_func)(unsigned char *src,
119                                      int src_w, int src_h, int src_stride,
120                                      int dst_x, int dst_y,
121                                      uint32_t color);
122
123 struct vaapi_surface {
124     VASurfaceID id;
125     VAImage     image;
126     int         is_bound; /* Flag: image bound to the surface? */
127 };
128
129 struct vaapi_equalizer {
130     VADisplayAttribute brightness;
131     VADisplayAttribute contrast;
132     VADisplayAttribute hue;
133     VADisplayAttribute saturation;
134 };
135
136 static int                      g_is_visible;
137 static int                      g_is_paused;
138 static uint32_t                 g_image_width;
139 static uint32_t                 g_image_height;
140 static uint32_t                 g_image_format;
141 static uint32_t                 g_image_fields;
142 static Pixmap                   g_image_pixmap;
143 static struct vo_rect           g_output_rect;
144 static struct vaapi_surface    *g_output_surfaces[MAX_OUTPUT_SURFACES];
145 static unsigned int             g_output_surface;
146 static int                      g_deint;
147 static int                      g_deint_type;
148 static int                      g_colorspace;
149
150 static int                      gl_enabled;
151 static int                      gl_use_tfp;
152 #if CONFIG_GL
153 static MPGLContext              gl_context;
154 static int                      gl_binding;
155 static int                      gl_reflect;
156 static int                      gl_finish;
157 static GLuint                   gl_texture;
158 static GLuint                   gl_font_base;
159 static Pixmap                   gl_pixmap;
160 static int                      gl_visual_attr[] = {
161     GLX_RGBA,
162     GLX_RED_SIZE, 1,
163     GLX_GREEN_SIZE, 1,
164     GLX_BLUE_SIZE, 1,
165     GLX_DOUBLEBUFFER,
166     GL_NONE
167 };
168 #endif
169
170 #if CONFIG_VAAPI_GLX
171 static void                    *gl_surface;
172 #endif
173
174 static int                      xr_enabled;
175 #if CONFIG_XRENDER
176 static Pixmap                   g_image_pixmap;
177 static Picture                  xr_video_picture;
178 static Picture                  xr_window_picture;
179 #endif
180
181 static struct vaapi_context    *va_context;
182 static VAProfile               *va_profiles;
183 static int                      va_num_profiles;
184 static VAEntrypoint            *va_entrypoints;
185 static int                      va_num_entrypoints;
186 static VASurfaceID             *va_surface_ids;
187 static int                      va_num_surfaces;
188 static struct vaapi_surface   **va_free_surfaces;
189 static int                      va_free_surfaces_head_index;
190 static int                      va_free_surfaces_tail_index;
191 static VAImageFormat           *va_image_formats;
192 static int                      va_num_image_formats;
193 static VAImageFormat           *va_subpic_formats;
194 static unsigned int            *va_subpic_flags;
195 static int                      va_num_subpic_formats;
196 static VAImage                  va_osd_image;
197 static uint8_t                 *va_osd_image_data;
198 static VASubpictureID           va_osd_subpicture;
199 static int                      va_osd_associated;
200 static draw_alpha_func          va_osd_draw_alpha;
201 static uint8_t                 *va_osd_palette;
202 static struct vaapi_equalizer   va_equalizer;
203 static VAImage                  va_eosd_image;
204 static uint8_t                 *va_eosd_image_data;
205 static VASubpictureID           va_eosd_subpicture;
206 static int                      va_eosd_associated;
207 static eosd_draw_alpha_func     va_eosd_draw_alpha;
208
209 ///< Flag: direct surface mapping: use mpi->number to select free VA surface?
210 static int                      va_dm;
211
212 ///< Flag: gather run-time statistics (CPU usage, frequency)
213 static int                      cpu_stats;
214 static unsigned int             cpu_frequency;
215 static float                    cpu_usage;
216
217 // X error trap
218 static int x11_error_code = 0;
219 static int (*old_error_handler)(Display *, XErrorEvent *);
220
221 static int error_handler(Display *dpy, XErrorEvent *error)
222 {
223     x11_error_code = error->error_code;
224     return 0;
225 }
226
227 static void x11_trap_errors(void)
228 {
229     x11_error_code    = 0;
230     old_error_handler = XSetErrorHandler(error_handler);
231 }
232
233 static int x11_untrap_errors(void)
234 {
235     XSetErrorHandler(old_error_handler);
236     return x11_error_code;
237 }
238
239 static int check_status(VAStatus status, const char *msg)
240 {
241     if (status != VA_STATUS_SUCCESS) {
242         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] %s: %s\n", msg, vaErrorStr(status));
243         return 0;
244     }
245     return 1;
246 }
247
248 static const char *string_of_VAImageFormat(VAImageFormat *imgfmt)
249 {
250     static char str[5];
251     str[0] = imgfmt->fourcc;
252     str[1] = imgfmt->fourcc >> 8;
253     str[2] = imgfmt->fourcc >> 16;
254     str[3] = imgfmt->fourcc >> 24;
255     str[4] = '\0';
256     return str;
257 }
258
259 static const char *string_of_VAProfile(VAProfile profile)
260 {
261     switch (profile) {
262 #define PROFILE(profile) \
263         case VAProfile##profile: return "VAProfile" #profile
264         PROFILE(MPEG2Simple);
265         PROFILE(MPEG2Main);
266         PROFILE(MPEG4Simple);
267         PROFILE(MPEG4AdvancedSimple);
268         PROFILE(MPEG4Main);
269         PROFILE(H264Baseline);
270         PROFILE(H264Main);
271         PROFILE(H264High);
272         PROFILE(VC1Simple);
273         PROFILE(VC1Main);
274         PROFILE(VC1Advanced);
275 #undef PROFILE
276     }
277     return "<unknown>";
278 }
279
280 static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
281 {
282     switch (entrypoint) {
283 #define ENTRYPOINT(entrypoint) \
284         case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
285         ENTRYPOINT(VLD);
286         ENTRYPOINT(IZZ);
287         ENTRYPOINT(IDCT);
288         ENTRYPOINT(MoComp);
289         ENTRYPOINT(Deblocking);
290 #undef ENTRYPOINT
291     }
292     return "<unknown>";
293 }
294
295 static int has_profile(VAProfile profile)
296 {
297     if (va_profiles && va_num_profiles > 0) {
298         int i;
299         for (i = 0; i < va_num_profiles; i++) {
300             if (va_profiles[i] == profile)
301                 return 1;
302         }
303     }
304     return 0;
305 }
306
307 static int VAProfile_from_imgfmt(uint32_t format)
308 {
309     static const int mpeg2_profiles[] =
310         { VAProfileMPEG2Main, VAProfileMPEG2Simple, -1 };
311     static const int mpeg4_profiles[] =
312         { VAProfileMPEG4Main, VAProfileMPEG4AdvancedSimple, VAProfileMPEG4Simple, -1 };
313     static const int h264_profiles[] =
314         { VAProfileH264High, VAProfileH264Main, VAProfileH264Baseline, -1 };
315     static const int wmv3_profiles[] =
316         { VAProfileVC1Main, VAProfileVC1Simple, -1 };
317     static const int vc1_profiles[] =
318         { VAProfileVC1Advanced, -1 };
319
320     const int *profiles = NULL;
321     switch (IMGFMT_VAAPI_CODEC(format)) {
322     case IMGFMT_VAAPI_CODEC_MPEG2:
323         profiles = mpeg2_profiles;
324         break;
325     case IMGFMT_VAAPI_CODEC_MPEG4:
326         profiles = mpeg4_profiles;
327         break;
328     case IMGFMT_VAAPI_CODEC_H264:
329         profiles = h264_profiles;
330         break;
331     case IMGFMT_VAAPI_CODEC_VC1:
332         switch (format) {
333         case IMGFMT_VAAPI_WMV3:
334             profiles = wmv3_profiles;
335             break;
336         case IMGFMT_VAAPI_VC1:
337             profiles = vc1_profiles;
338             break;
339         }
340         break;
341     }
342
343     if (profiles) {
344         for (int i = 0; profiles[i] != -1; i++) {
345             if (has_profile(profiles[i]))
346                 return profiles[i];
347         }
348     }
349     return -1;
350 }
351
352 static int has_entrypoint(VAEntrypoint entrypoint)
353 {
354     if (va_entrypoints && va_num_entrypoints > 0) {
355         int i;
356         for (i = 0; i < va_num_entrypoints; i++) {
357             if (va_entrypoints[i] == entrypoint)
358                 return 1;
359         }
360     }
361     return 0;
362 }
363
364 static int VAEntrypoint_from_imgfmt(uint32_t format)
365 {
366     int entrypoint = 0;
367     switch (format) {
368     case IMGFMT_VAAPI_MPEG2:
369     case IMGFMT_VAAPI_MPEG4:
370     case IMGFMT_VAAPI_H263:
371     case IMGFMT_VAAPI_H264:
372     case IMGFMT_VAAPI_WMV3:
373     case IMGFMT_VAAPI_VC1:
374         entrypoint = VAEntrypointVLD;
375         break;
376     case IMGFMT_VAAPI_MPEG2_IDCT:
377         entrypoint = VAEntrypointIDCT;
378         break;
379     case IMGFMT_VAAPI_MPEG2_MOCO:
380         entrypoint = VAEntrypointMoComp;
381         break;
382     }
383
384     if (entrypoint)
385         return has_entrypoint(entrypoint);
386
387     return -1;
388 }
389
390 static VAImageFormat *find_image_format(uint32_t fourcc)
391 {
392     if (va_image_formats && va_num_image_formats > 0) {
393         int i;
394         for (i = 0; i < va_num_image_formats; i++) {
395             if (va_image_formats[i].fourcc == fourcc)
396                 return &va_image_formats[i];
397         }
398     }
399     return NULL;
400 }
401
402 static VAImageFormat *VAImageFormat_from_imgfmt(uint32_t format)
403 {
404     uint32_t fourcc = 0;
405
406     switch (format) {
407     case IMGFMT_NV12: fourcc = VA_FOURCC('N','V','1','2'); break;
408     case IMGFMT_YV12: fourcc = VA_FOURCC('Y','V','1','2'); break;
409     case IMGFMT_I420: fourcc = VA_FOURCC('I','4','2','0'); break;
410     case IMGFMT_IYUV: fourcc = VA_FOURCC('I','Y','U','V'); break;
411     }
412
413     if (fourcc)
414         return find_image_format(fourcc);
415
416     return NULL;
417 }
418
419 static struct vaapi_surface *alloc_vaapi_surface(unsigned int width,
420                                                  unsigned int height,
421                                                  unsigned int format)
422 {
423     struct vaapi_surface *surface = NULL;
424     struct vaapi_surface **surfaces;
425     VASurfaceID *surface_ids;
426     VAStatus status;
427
428     surface = calloc(1, sizeof(*surface));
429     if (!surface)
430         goto error;
431
432     surfaces = realloc(va_free_surfaces,
433                        (1 + va_num_surfaces) * sizeof(surfaces[0]));
434     if (!surfaces)
435         goto error;
436
437     surface_ids = realloc(va_surface_ids,
438                           (1 + va_num_surfaces) * sizeof(surface_ids[0]));
439     if (!surface_ids)
440         goto error;
441
442     status = vaCreateSurfaces(va_context->display, width, height, format,
443                               1, &surface->id);
444     if (!check_status(status, "vaCreateSurfaces()"))
445         goto error;
446
447     va_surface_ids                    = surface_ids;
448     va_surface_ids[va_num_surfaces]   = surface->id;
449     va_free_surfaces                  = surfaces;
450     va_free_surfaces[va_num_surfaces] = surface;
451     surface->image.image_id           = VA_INVALID_ID;
452     surface->image.buf                = VA_INVALID_ID;
453     ++va_num_surfaces;
454     return surface;
455 error:
456     free(surface);
457     return NULL;
458 }
459
460 static void resize(void)
461 {
462     struct vo_rect src;
463
464     calc_src_dst_rects(g_image_width, g_image_height,
465                        &src, &g_output_rect, NULL, NULL);
466
467     ensure_osd();
468
469     vo_x11_clearwindow(mDisplay, vo_window);
470
471 #if CONFIG_GL
472 #define FOVY     60.0f
473 #define ASPECT   1.0f
474 #define Z_NEAR   0.1f
475 #define Z_FAR    100.0f
476 #define Z_CAMERA 0.869f
477
478     if (gl_enabled) {
479         glViewport(0, 0, vo_dwidth, vo_dheight);
480         glMatrixMode(GL_PROJECTION);
481         glLoadIdentity();
482         gluPerspective(FOVY, ASPECT, Z_NEAR, Z_FAR);
483         glMatrixMode(GL_MODELVIEW);
484         glLoadIdentity();
485
486         glTranslatef(-0.5f, -0.5f, -Z_CAMERA);
487         glScalef(1.0f / (GLfloat)vo_dwidth,
488                  -1.0f / (GLfloat)vo_dheight,
489                  1.0f / (GLfloat)vo_dwidth);
490         glTranslatef(0.0f, -1.0f * (GLfloat)vo_dheight, 0.0f);
491     }
492 #endif
493
494 #if CONFIG_XRENDER
495     if (xr_enabled)
496         reset_xrender_specific();
497 #endif
498
499     if (g_is_visible)
500         flip_page();
501 }
502
503 #if CONFIG_GL
504 static int gl_build_font(void)
505 {
506     XFontStruct *fi;
507
508     gl_font_base = glGenLists(96);
509
510     fi = XLoadQueryFont(mDisplay, "-adobe-helvetica-medium-r-normal--16-*-*-*-p-*-iso8859-1" );
511     if (!fi) {
512         fi = XLoadQueryFont(mDisplay, "fixed");
513         if (!fi)
514             return -1;
515     }
516
517     glXUseXFont(fi->fid, 32, 96, gl_font_base);
518     XFreeFont(mDisplay, fi);
519     return 0;
520 }
521
522 static void gl_printf(const char *format, ...)
523 {
524     va_list args;
525     char *text;
526     int textlen;
527
528     va_start(args, format);
529     textlen = vsnprintf(NULL, 0, format, args);
530     va_end(args);
531
532     text = malloc(textlen + 1);
533     if (!text)
534         return;
535
536     va_start(args, format);
537     vsprintf(text, format, args);
538     va_end(args);
539
540     glPushAttrib(GL_LIST_BIT);
541     glListBase(gl_font_base - 32);
542     glCallLists(textlen, GL_UNSIGNED_BYTE, text);
543     glPopAttrib();
544     free(text);
545 }
546
547 static void gl_draw_rectangle(int x, int y, int w, int h, unsigned int rgba)
548 {
549     glColor4f((GLfloat)((rgba >> 24) & 0xff) / 255.0,
550               (GLfloat)((rgba >> 16) & 0xff) / 255.0,
551               (GLfloat)((rgba >> 8) & 0xff) / 255.0,
552               (GLfloat)(rgba & 0xff) / 255.0);
553
554     glTranslatef((GLfloat)x, (GLfloat)y, 0.0f);
555     glBegin(GL_QUADS);
556     {
557         glVertex2i(0, 0);
558         glVertex2i(w, 0);
559         glVertex2i(w, h);
560         glVertex2i(0, h);
561     }
562     glEnd();
563 }
564 #endif
565
566 #if CONFIG_XRENDER
567 static int init_xrender(void)
568 {
569     int dummy;
570
571     return XRenderQueryExtension(mDisplay, &dummy, &dummy);
572 }
573
574 static void uninit_xrender(void)
575 {
576 }
577 #endif
578
579 static inline unsigned char *get_osd_image_data(int x0, int y0)
580 {
581     return (va_osd_image_data +
582             va_osd_image.offsets[0] +
583             va_osd_image.pitches[0] * y0 +
584             x0 * ((va_osd_image.format.bits_per_pixel + 7) / 8));
585 }
586
587 static void draw_alpha_rgb32(int x0, int y0, int w, int h,
588                              unsigned char *src, unsigned char *srca,
589                              int stride)
590 {
591     int x, y;
592     const unsigned int dststride = va_osd_image.pitches[0];
593     unsigned char *dst = get_osd_image_data(x0, y0);
594
595     for (y = 0; y < h; y++, dst += dststride, src += stride, srca += stride)
596         for (x = 0; x < w; x++) {
597             const unsigned char c = src[x];
598             dst[4*x + 0] = c;
599             dst[4*x + 1] = c;
600             dst[4*x + 2] = c;
601             dst[4*x + 3] = -srca[x];
602         }
603 }
604
605 #if USE_VAAPI_IA44_FORMATS
606 static void draw_alpha_IA44(int x0, int y0, int w, int h,
607                             unsigned char *src, unsigned char *srca,
608                             int stride)
609 {
610     int x, y;
611     const unsigned int dststride = va_osd_image.pitches[0];
612     unsigned char *dst = get_osd_image_data(x0, y0);
613
614     for (y = 0; y < h; y++, dst += dststride)
615         for (x = 0; x < w; x++)
616             dst[x] = (src[y*stride + x] & 0xf0) | (-srca[y*stride + x] >> 4);
617 }
618
619 static void draw_alpha_AI44(int x0, int y0, int w, int h,
620                             unsigned char *src, unsigned char *srca,
621                             int stride)
622 {
623     int x, y;
624     const unsigned int dststride = va_osd_image.pitches[0];
625     unsigned char *dst = get_osd_image_data(x0, y0);
626
627     for (y = 0; y < h; y++, dst += dststride)
628         for (x = 0; x < w; x++)
629             dst[x] = (src[y*stride + x] >> 4) | (-srca[y*stride + x] & 0xf0);
630 }
631 #endif
632
633 static void draw_alpha_IA88(int x0, int y0, int w, int h,
634                             unsigned char *src, unsigned char *srca,
635                             int stride)
636 {
637     int x, y;
638     const unsigned int dststride = va_osd_image.pitches[0];
639     unsigned char *dst = get_osd_image_data(x0, y0);
640
641     for (y = 0; y < h; y++, dst += dststride)
642         for (x = 0; x < w; x++) {
643             dst[2*x + 0] =  src [y*stride + x];
644             dst[2*x + 1] = -srca[y*stride + x];
645         }
646 }
647
648 static void draw_alpha_AI88(int x0, int y0, int w, int h,
649                             unsigned char *src, unsigned char *srca,
650                             int stride)
651 {
652     int x, y;
653     const unsigned int dststride = va_osd_image.pitches[0];
654     unsigned char *dst = get_osd_image_data(x0, y0);
655
656     for (y = 0; y < h; y++, dst += dststride)
657         for (x = 0; x < w; x++) {
658             dst[2*x + 0] = -srca[y*stride + x];
659             dst[2*x + 1] =  src [y*stride + x];
660         }
661 }
662
663 ///< List of subpicture formats in preferred order
664 static const struct {
665     uint32_t format;
666     draw_alpha_func draw_alpha;
667 }
668 va_osd_info[] = {
669 #if USE_VAAPI_IA44_FORMATS
670     { VA_FOURCC('I','A','4','4'), draw_alpha_IA44  },
671     { VA_FOURCC('A','I','4','4'), draw_alpha_AI44  },
672 #endif
673     { VA_FOURCC('I','A','8','8'), draw_alpha_IA88  },
674     { VA_FOURCC('A','I','8','8'), draw_alpha_AI88  },
675     { VA_FOURCC('B','G','R','A'), draw_alpha_rgb32 },
676     { VA_FOURCC('R','G','B','A'), draw_alpha_rgb32 },
677     { 0, NULL }
678 };
679
680 static uint8_t *gen_osd_palette(const VAImage *image)
681 {
682     uint8_t *palette;
683     int i, is_rgb;
684     int r_idx = -1, g_idx = -1, b_idx = -1;
685     int y_idx = -1, u_idx = -1, v_idx = -1;
686     int i_idx = -1, a_idx = -1;
687
688     if (image->num_palette_entries < 1)
689         return NULL;
690
691     palette = malloc(image->num_palette_entries * image->entry_bytes);
692     if (!palette)
693         return NULL;
694
695     for (i = 0; i < image->entry_bytes; i++) {
696         switch (image->component_order[i]) {
697         case 'R': r_idx = i; is_rgb = 1; break;
698         case 'G': g_idx = i; is_rgb = 1; break;
699         case 'B': b_idx = i; is_rgb = 1; break;
700         case 'Y': y_idx = i; is_rgb = 0; break;
701         case 'U': u_idx = i; is_rgb = 0; break;
702         case 'V': v_idx = i; is_rgb = 0; break;
703         case 'I': i_idx = i; break;
704         case 'A': a_idx = i; break;
705         }
706     }
707
708     if (r_idx != -1 && g_idx != -1 && b_idx != -1) {      /* RGB format */
709         for (i = 0; i < image->num_palette_entries; i++) {
710             const int n = i * image->entry_bytes;
711             palette[n + r_idx] = i * 0xff / (image->num_palette_entries - 1);
712             palette[n + g_idx] = i * 0xff / (image->num_palette_entries - 1);
713             palette[n + b_idx] = i * 0xff / (image->num_palette_entries - 1);
714         }
715     }
716     else if (y_idx != -1 && u_idx != -1 && v_idx != -1) { /* YUV format */
717         for (i = 0; i < image->num_palette_entries; i++) {
718             const int n = i * image->entry_bytes;
719             palette[n + y_idx] = i * 0xff / (image->num_palette_entries - 1);
720             palette[n + u_idx] = 0x80;
721             palette[n + v_idx] = 0x80;
722         }
723     }
724     else if (i_idx != -1 && a_idx != -1) {/* AYUV format (GMA500 "psb" bug) */
725         for (i = 0; i < image->num_palette_entries; i++) {
726             const int n = i * image->entry_bytes;
727             palette[n + 0] = 0x80;
728             palette[n + 1] = 0x80;
729             palette[n + 2] = 16 + i * 220 / (image->num_palette_entries - 1);
730             palette[n + 3] = 0;
731         }
732     }
733     else {
734         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not set up subpicture palette\n");
735         free(palette);
736         palette = NULL;
737     }
738     return palette;
739 }
740
741 static void disable_osd(void)
742 {
743     if (!va_osd_associated)
744         return;
745
746     vaDeassociateSubpicture(va_context->display,
747                             va_osd_subpicture,
748                             va_surface_ids, va_num_surfaces);
749
750     va_osd_associated = 0;
751 }
752
753 static int enable_osd(void)
754 {
755     VAStatus status;
756
757     disable_osd();
758
759     status = vaAssociateSubpicture2(va_context->display,
760                                     va_osd_subpicture,
761                                     va_surface_ids, va_num_surfaces,
762                                     0, 0,
763                                     va_osd_image.width, va_osd_image.height,
764                                     0, 0,
765                                     g_image_width, g_image_height,
766                                     0);
767     if (!check_status(status, "vaAssociateSubpicture()"))
768         return -1;
769
770     va_osd_associated = 1;
771     return 0;
772 }
773
774 static void destroy_osd(void)
775 {
776     disable_osd();
777
778     if (va_osd_subpicture != VA_INVALID_ID) {
779         vaDestroySubpicture(va_context->display, va_osd_subpicture);
780         va_osd_subpicture = VA_INVALID_ID;
781     }
782
783     if (va_osd_image.image_id != VA_INVALID_ID) {
784         vaDestroyImage(va_context->display, va_osd_image.image_id);
785         va_osd_image.image_id = VA_INVALID_ID;
786         va_osd_image.width    = 0;
787         va_osd_image.height   = 0;
788     }
789 }
790
791 static void create_osd(void)
792 {
793     VAStatus status;
794     int i, j;
795
796     for (i = 0; va_osd_info[i].format; i++) {
797         for (j = 0; j < va_num_subpic_formats; j++)
798             if (va_subpic_formats[j].fourcc == va_osd_info[i].format)
799                 break;
800         if (j < va_num_subpic_formats &&
801             vaCreateImage(va_context->display, &va_subpic_formats[j],
802                           g_output_rect.width, g_output_rect.height,
803                           &va_osd_image) == VA_STATUS_SUCCESS) {
804             va_osd_palette = gen_osd_palette(&va_osd_image);
805             if (((!va_osd_image.num_palette_entries) ^ (!va_osd_palette)) == 0)
806                 break;
807             vaDestroyImage(va_context->display, va_osd_image.image_id);
808             va_osd_image.image_id = VA_INVALID_ID;
809         }
810     }
811
812     if (va_osd_info[i].format &&
813         vaCreateSubpicture(va_context->display, va_osd_image.image_id,
814                            &va_osd_subpicture) == VA_STATUS_SUCCESS) {
815         va_osd_draw_alpha = va_osd_info[i].draw_alpha;
816         if (va_osd_palette) {
817             status = vaSetImagePalette(va_context->display,
818                                        va_osd_image.image_id, va_osd_palette);
819             check_status(status, "vaSetImagePalette()");
820         }
821         mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for OSD\n",
822                string_of_VAImageFormat(&va_osd_image.format));
823     }
824 }
825
826 static void ensure_osd(void)
827 {
828     if (g_output_rect.width  == va_osd_image.width &&
829         g_output_rect.height == va_osd_image.height)
830         return;
831
832     destroy_osd();
833     create_osd();
834 }
835
836 static inline unsigned char *get_eosd_image_data(int x0, int y0)
837 {
838     return (va_eosd_image_data +
839             va_eosd_image.offsets[0] +
840             va_eosd_image.pitches[0] * y0 +
841             x0 * ((va_eosd_image.format.bits_per_pixel + 7) / 8));
842 }
843
844 static void eosd_draw_alpha_bgra(unsigned char *src,
845                                  int src_w, int src_h, int src_stride,
846                                  int dst_x, int dst_y,
847                                  uint32_t color)
848 {
849     int x, y;
850     const unsigned int dst_stride = va_eosd_image.pitches[0];
851     unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
852     const unsigned int r = (color >> 24) & 0xff;
853     const unsigned int g = (color >> 16) & 0xff;
854     const unsigned int b = (color >>  8) & 0xff;
855     const unsigned int a = 0xff - (color & 0xff);
856
857     for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
858         for (x = 0; x < src_w; x++) {
859             const unsigned int v = src[x];
860             dst[4*x + 0] = (b * v + dst[4*x + 0] * (0xff - v)) / 255;
861             dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
862             dst[4*x + 2] = (r * v + dst[4*x + 2] * (0xff - v)) / 255;
863             dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
864         }
865 }
866
867 static void eosd_draw_alpha_rgba(unsigned char *src,
868                                  int src_w, int src_h, int src_stride,
869                                  int dst_x, int dst_y,
870                                  uint32_t color)
871 {
872     int x, y;
873     const unsigned int dst_stride = va_eosd_image.pitches[0];
874     unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
875     const unsigned int r = (color >> 24) & 0xff;
876     const unsigned int g = (color >> 16) & 0xff;
877     const unsigned int b = (color >>  8) & 0xff;
878     const unsigned int a = 0xff - (color & 0xff);
879
880     for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
881         for (x = 0; x < src_w; x++) {
882             const unsigned int v = src[x];
883             dst[4*x + 0] = (r * v + dst[4*x + 0] * (0xff - v)) / 255;
884             dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
885             dst[4*x + 2] = (b * v + dst[4*x + 2] * (0xff - v)) / 255;
886             dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
887         }
888 }
889
890 static void disable_eosd(void)
891 {
892     if (!va_eosd_associated)
893         return;
894
895     vaDeassociateSubpicture(va_context->display,
896                             va_eosd_subpicture,
897                             va_surface_ids, va_num_surfaces);
898
899     va_eosd_associated = 0;
900 }
901
902 static int enable_eosd(void)
903 {
904     VAStatus status;
905
906     if (va_eosd_associated)
907         return 0;
908
909     status = vaAssociateSubpicture2(va_context->display,
910                                     va_eosd_subpicture,
911                                     va_surface_ids, va_num_surfaces,
912                                     0, 0, g_image_width, g_image_height,
913                                     0, 0, g_image_width, g_image_height,
914                                     0);
915     if (!check_status(status, "vaAssociateSubpicture()"))
916         return -1;
917
918     va_eosd_associated = 1;
919     return 0;
920 }
921
922 ///< List of subpicture formats in preferred order
923 static const struct {
924     uint32_t format;
925     eosd_draw_alpha_func draw_alpha;
926 }
927 va_eosd_info[] = {
928     { VA_FOURCC('B','G','R','A'), eosd_draw_alpha_bgra },
929     { VA_FOURCC('R','G','B','A'), eosd_draw_alpha_rgba },
930     { 0, NULL }
931 };
932
933 static int is_direct_mapping_init(void)
934 {
935     VADisplayAttribute attr;
936     VAStatus status;
937
938     if (va_dm < 2)
939         return va_dm;
940
941     /* If the driver doesn't make a copy of the VA surface for
942        display, then we have to retain it until it's no longer the
943        visible surface. In other words, if the driver is using
944        DirectSurface mode, we don't want to decode the new surface
945        into the previous one that was used for display. */
946     attr.type  = VADisplayAttribDirectSurface;
947     attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
948
949     status = vaGetDisplayAttributes(va_context->display, &attr, 1);
950     if (status == VA_STATUS_SUCCESS)
951         return !attr.value;
952     return 0;
953 }
954
955 static inline int is_direct_mapping(void)
956 {
957     static int dm = -1;
958     if (dm < 0) {
959         dm = is_direct_mapping_init();
960         if (dm)
961             mp_msg(MSGT_VO, MSGL_INFO,
962                    "[vo_vaapi] Using 1:1 VA surface mapping\n");
963     }
964     return dm;
965 }
966
967 static int int_012(int *n)
968 {
969     return *n >= 0 && *n <= 2;
970 }
971
972 static const opt_t subopts[] = {
973     { "dm",          OPT_ARG_INT,  &va_dm,        (opt_test_f)int_012 },
974     { "stats",       OPT_ARG_BOOL, &cpu_stats,    NULL },
975     { "deint",       OPT_ARG_INT,  &g_deint,      (opt_test_f)int_012 },
976 #if USE_VAAPI_COLORSPACE
977     { "colorspace",  OPT_ARG_INT,  &g_colorspace, (opt_test_f)int_012 },
978 #endif
979 #if CONFIG_GL
980     { "gl",          OPT_ARG_BOOL, &gl_enabled,   NULL },
981     { "glfinish",    OPT_ARG_BOOL, &gl_finish,    NULL },
982 #if USE_VAAPI_GLX_BIND
983     { "bind",        OPT_ARG_BOOL, &gl_binding,   NULL },
984 #endif
985     { "reflect",     OPT_ARG_BOOL, &gl_reflect,   NULL },
986     { "tfp",         OPT_ARG_BOOL, &gl_use_tfp,   NULL },
987 #endif
988 #if CONFIG_XRENDER
989     { "xrender",     OPT_ARG_BOOL, &xr_enabled,   NULL },
990 #endif
991     { NULL, }
992 };
993
994 static int preinit(const char *arg)
995 {
996     VADisplayAttribute *display_attrs;
997     VAStatus status;
998     int va_major_version, va_minor_version;
999     int i, max_image_formats, max_subpic_formats, max_profiles;
1000     int num_display_attrs, max_display_attrs;
1001
1002     va_dm = 2;
1003     g_deint = 0;
1004     g_deint_type = 2;
1005     g_colorspace = 1;
1006     if (subopt_parse(arg, subopts) != 0) {
1007         mp_msg(MSGT_VO, MSGL_FATAL,
1008                "\n-vo vaapi command line help:\n"
1009                "Example: mplayer -vo vaapi:gl\n"
1010                "\nOptions:\n"
1011                "  dm\n"
1012                "    0: use least-recently-used VA surface\n"
1013                "    1: identify VA surface with MPI index\n"
1014                "    2: auto-detect use of direct surface mapping (default)\n"
1015                "  deint (all modes > 0 respect -field-dominance)\n"
1016                "    0: no deinterlacing (default)\n"
1017                "    1: only show first field\n"
1018                "    2: bob deinterlacing\n"
1019                "  colorspace\n"
1020                "    0: guess based on video resolution\n"
1021                "    1: ITU-R BT.601 (default)\n"
1022                "    2: ITU-R BT.709\n"
1023 #if CONFIG_GL
1024                "  gl\n"
1025                "    Enable OpenGL rendering\n"
1026                "  glfinish\n"
1027                "    Call glFinish() before swapping buffers\n"
1028                "  tfp\n"
1029                "    Use GLX texture-from-pixmap instead of VA/GLX extensions\n"
1030 #if USE_VAAPI_GLX_BIND
1031                "  bind\n"
1032                "    Use VA surface binding instead of copy\n"
1033 #endif
1034                "  reflect\n"
1035                "    Enable OpenGL reflection effects\n"
1036 #endif
1037 #if CONFIG_XRENDER
1038                "  xrender\n"
1039                "    Enable Xrender rendering, thus vaPutSurface() to a Pixmap\n"
1040 #endif
1041                "\n" );
1042         return -1;
1043     }
1044     if (gl_enabled && xr_enabled) {
1045         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] User requested both Xrender and OpenGL rendering\n");
1046         return -1;
1047     }
1048     if (g_deint)
1049         g_deint_type = g_deint;
1050 #if CONFIG_GL
1051     if (gl_enabled)
1052         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using OpenGL rendering%s\n",
1053                gl_reflect ? ", with reflection effects" : "");
1054 #endif
1055 #if CONFIG_XRENDER
1056     if (xr_enabled)
1057         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using Xrender rendering\n");
1058 #endif
1059
1060     stats_init();
1061
1062 #if CONFIG_GL
1063     if (gl_enabled && !init_mpglcontext(&gl_context, GLTYPE_X11))
1064         return -1;
1065     else
1066 #endif
1067     if (!vo_init())
1068         return -1;
1069 #if CONFIG_XRENDER
1070     if (xr_enabled && !init_xrender())
1071         return -1;
1072 #endif
1073
1074     va_context = calloc(1, sizeof(*va_context));
1075     if (!va_context)
1076         return -1;
1077
1078 #if CONFIG_VAAPI_GLX
1079     if (gl_enabled)
1080         va_context->display = vaGetDisplayGLX(mDisplay);
1081     else
1082 #endif
1083         va_context->display = vaGetDisplay(mDisplay);
1084     if (!va_context->display)
1085         return -1;
1086     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA display %p\n", va_context->display);
1087
1088     status = vaInitialize(va_context->display, &va_major_version, &va_minor_version);
1089     if (!check_status(status, "vaInitialize()"))
1090         return -1;
1091     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA API version %d.%d\n",
1092            va_major_version, va_minor_version);
1093
1094     max_image_formats = vaMaxNumImageFormats(va_context->display);
1095     va_image_formats = calloc(max_image_formats, sizeof(*va_image_formats));
1096     if (!va_image_formats)
1097         return -1;
1098     status = vaQueryImageFormats(va_context->display, va_image_formats, &va_num_image_formats);
1099     if (!check_status(status, "vaQueryImageFormats()"))
1100         return -1;
1101     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d image formats available\n",
1102            va_num_image_formats);
1103     for (i = 0; i < va_num_image_formats; i++)
1104         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAImageFormat(&va_image_formats[i]));
1105
1106     max_subpic_formats = vaMaxNumSubpictureFormats(va_context->display);
1107     va_subpic_formats = calloc(max_subpic_formats, sizeof(*va_subpic_formats));
1108     if (!va_subpic_formats)
1109         return -1;
1110     va_subpic_flags = calloc(max_subpic_formats, sizeof(*va_subpic_flags));
1111     if (!va_subpic_flags)
1112         return -1;
1113     status = vaQuerySubpictureFormats(va_context->display, va_subpic_formats, va_subpic_flags, &va_num_subpic_formats);
1114     if (!check_status(status, "vaQuerySubpictureFormats()"))
1115         va_num_subpic_formats = 0; /* XXX: don't error out for IEGD */
1116     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d subpicture formats available\n",
1117            va_num_subpic_formats);
1118     for (i = 0; i < va_num_subpic_formats; i++)
1119         mp_msg(MSGT_VO, MSGL_DBG2, "  %s, flags 0x%x\n", string_of_VAImageFormat(&va_subpic_formats[i]), va_subpic_flags[i]);
1120
1121     max_profiles = vaMaxNumProfiles(va_context->display);
1122     va_profiles = calloc(max_profiles, sizeof(*va_profiles));
1123     if (!va_profiles)
1124         return -1;
1125     status = vaQueryConfigProfiles(va_context->display, va_profiles, &va_num_profiles);
1126     if (!check_status(status, "vaQueryConfigProfiles()"))
1127         return -1;
1128     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d profiles available\n",
1129            va_num_profiles);
1130     for (i = 0; i < va_num_profiles; i++)
1131         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAProfile(va_profiles[i]));
1132
1133     va_osd_subpicture      = VA_INVALID_ID;
1134     va_osd_image.image_id  = VA_INVALID_ID;
1135     va_eosd_subpicture     = VA_INVALID_ID;
1136     va_eosd_image.image_id = VA_INVALID_ID;
1137
1138     max_display_attrs = vaMaxNumDisplayAttributes(va_context->display);
1139     display_attrs = calloc(max_display_attrs, sizeof(*display_attrs));
1140     if (display_attrs) {
1141         num_display_attrs = 0;
1142         status = vaQueryDisplayAttributes(va_context->display,
1143                                           display_attrs, &num_display_attrs);
1144         if (check_status(status, "vaQueryDisplayAttributes()")) {
1145             for (i = 0; i < num_display_attrs; i++) {
1146                 VADisplayAttribute *attr;
1147                 switch (display_attrs[i].type) {
1148                 case VADisplayAttribBrightness:
1149                     attr = &va_equalizer.brightness;
1150                     break;
1151                 case VADisplayAttribContrast:
1152                     attr = &va_equalizer.contrast;
1153                     break;
1154                 case VADisplayAttribHue:
1155                     attr = &va_equalizer.hue;
1156                     break;
1157                 case VADisplayAttribSaturation:
1158                     attr = &va_equalizer.saturation;
1159                     break;
1160                 default:
1161                     attr = NULL;
1162                     break;
1163                 }
1164                 if (attr)
1165                     *attr = display_attrs[i];
1166             }
1167         }
1168         free(display_attrs);
1169     }
1170     return 0;
1171 }
1172
1173 static void free_video_specific(void)
1174 {
1175     int i;
1176
1177 #if CONFIG_VAAPI_GLX
1178     if (gl_surface) {
1179         VAStatus status;
1180         status = vaDestroySurfaceGLX(va_context->display, gl_surface);
1181         check_status(status, "vaDestroySurfaceGLX()");
1182         gl_surface = NULL;
1183     }
1184 #endif
1185
1186     if (va_context && va_context->context_id) {
1187         vaDestroyContext(va_context->display, va_context->context_id);
1188         va_context->context_id = 0;
1189     }
1190
1191     if (va_free_surfaces) {
1192         for (i = 0; i < va_num_surfaces; i++) {
1193             if (!va_free_surfaces[i])
1194                 continue;
1195             if (va_free_surfaces[i]->image.image_id != VA_INVALID_ID) {
1196                 vaDestroyImage(va_context->display,
1197                                va_free_surfaces[i]->image.image_id);
1198                 va_free_surfaces[i]->image.image_id = VA_INVALID_ID;
1199             }
1200             free(va_free_surfaces[i]);
1201             va_free_surfaces[i] = NULL;
1202         }
1203         free(va_free_surfaces);
1204         va_free_surfaces = NULL;
1205         va_free_surfaces_head_index = 0;
1206         va_free_surfaces_tail_index = 0;
1207     }
1208
1209     g_output_surface = 0;
1210     memset(g_output_surfaces, 0, sizeof(g_output_surfaces));
1211
1212     if (va_osd_palette) {
1213         free(va_osd_palette);
1214         va_osd_palette = NULL;
1215     }
1216
1217     disable_eosd();
1218     disable_osd();
1219
1220     if (va_eosd_subpicture != VA_INVALID_ID) {
1221         vaDestroySubpicture(va_context->display, va_eosd_subpicture);
1222         va_eosd_subpicture = VA_INVALID_ID;
1223     }
1224
1225     if (va_eosd_image.image_id != VA_INVALID_ID) {
1226         vaDestroyImage(va_context->display, va_eosd_image.image_id);
1227         va_eosd_image.image_id = VA_INVALID_ID;
1228     }
1229
1230     destroy_osd();
1231
1232     if (va_surface_ids) {
1233         vaDestroySurfaces(va_context->display, va_surface_ids, va_num_surfaces);
1234         free(va_surface_ids);
1235         va_surface_ids = NULL;
1236         va_num_surfaces = 0;
1237     }
1238
1239     if (va_context && va_context->config_id) {
1240         vaDestroyConfig(va_context->display, va_context->config_id);
1241         va_context->config_id = 0;
1242     }
1243
1244     if (va_entrypoints) {
1245         free(va_entrypoints);
1246         va_entrypoints = NULL;
1247     }
1248
1249 #if CONFIG_GL
1250     if (gl_pixmap) {
1251         x11_trap_errors();
1252         mpglXDestroyPixmap(mDisplay, gl_pixmap);
1253         XSync(mDisplay, False);
1254         x11_untrap_errors();
1255         gl_pixmap = None;
1256     }
1257
1258     if (g_image_pixmap) {
1259         XFreePixmap(mDisplay, g_image_pixmap);
1260         g_image_pixmap = None;
1261     }
1262
1263     if (gl_texture) {
1264         glDeleteTextures(1, &gl_texture);
1265         gl_texture = GL_NONE;
1266     }
1267 #endif
1268
1269 #if CONFIG_XRENDER
1270     if (xr_window_picture) {
1271         XRenderFreePicture(mDisplay, xr_window_picture);
1272         xr_window_picture = None;
1273     }
1274 #endif
1275
1276     g_is_visible = 0;
1277 }
1278
1279 static void uninit(void)
1280 {
1281     if (!vo_config_count)
1282         return;
1283
1284     free_video_specific();
1285
1286     if (va_profiles) {
1287         free(va_profiles);
1288         va_profiles = NULL;
1289     }
1290
1291     if (va_subpic_flags) {
1292         free(va_subpic_flags);
1293         va_subpic_flags = NULL;
1294     }
1295
1296     if (va_subpic_formats) {
1297         free(va_subpic_formats);
1298         va_subpic_formats = NULL;
1299     }
1300
1301     if (va_image_formats) {
1302         free(va_image_formats);
1303         va_image_formats = NULL;
1304     }
1305
1306     if (va_context && va_context->display) {
1307         vaTerminate(va_context->display);
1308         va_context->display = NULL;
1309     }
1310
1311     if (va_context) {
1312         free(va_context);
1313         va_context = NULL;
1314     }
1315
1316 #ifdef CONFIG_XF86VM
1317     vo_vm_close();
1318 #endif
1319 #if CONFIG_XRENDER
1320     if (xr_enabled)
1321         uninit_xrender();
1322 #endif
1323 #if CONFIG_GL
1324     if (gl_enabled)
1325         uninit_mpglcontext(&gl_context);
1326     else
1327 #endif
1328     vo_x11_uninit();
1329
1330     stats_exit();
1331 }
1332
1333 static int config_x11(uint32_t width, uint32_t height,
1334                       uint32_t display_width, uint32_t display_height,
1335                       uint32_t flags, char *title)
1336 {
1337     Colormap cmap;
1338     XVisualInfo visualInfo;
1339     XVisualInfo *vi;
1340     XSetWindowAttributes xswa;
1341     unsigned long xswa_mask;
1342     XWindowAttributes wattr;
1343     int depth;
1344
1345 #ifdef CONFIG_GUI
1346     if (use_gui)
1347         guiGetEvent(guiSetShVideo, 0);  // the GUI will set up / resize our window
1348     else
1349 #endif
1350     {
1351 #ifdef CONFIG_XF86VM
1352         if (flags & VOFLAG_MODESWITCHING)
1353             vo_vm_switch();
1354 #endif
1355         XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &wattr);
1356         depth = wattr.depth;
1357         if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
1358             depth = 24;
1359         XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &visualInfo);
1360
1361 #if CONFIG_GL
1362         if (gl_enabled) {
1363             vi = glXChooseVisual(mDisplay, mScreen, gl_visual_attr);
1364             if (!vi)
1365                 return -1;
1366             cmap = XCreateColormap(mDisplay, mRootWin, vi->visual, AllocNone);
1367             if (cmap == None)
1368                 return -1;
1369         }
1370         else
1371 #endif
1372         {
1373             vi = &visualInfo;
1374             XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, vi);
1375             cmap = CopyFromParent;
1376         }
1377
1378         vo_x11_create_vo_window(vi,
1379                                 vo_dx, vo_dy, display_width, display_height,
1380                                 flags, cmap, "vaapi", title);
1381
1382         if (vi != &visualInfo)
1383             XFree(vi);
1384
1385         xswa_mask             = CWBorderPixel | CWBackPixel;
1386         xswa.border_pixel     = 0;
1387         xswa.background_pixel = 0;
1388         XChangeWindowAttributes(mDisplay, vo_window, xswa_mask, &xswa);
1389
1390 #ifdef CONFIG_XF86VM
1391         if (flags & VOFLAG_MODESWITCHING) {
1392             /* Grab the mouse pointer in our window */
1393             if (vo_grabpointer)
1394                 XGrabPointer(mDisplay, vo_window, True, 0,
1395                              GrabModeAsync, GrabModeAsync,
1396                              vo_window, None, CurrentTime);
1397             XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
1398         }
1399 #endif
1400     }
1401     return 0;
1402 }
1403
1404 #if CONFIG_GL
1405 static GLXFBConfig *get_fbconfig_for_depth(int depth)
1406 {
1407     GLXFBConfig *fbconfigs, *ret = NULL;
1408     int          n_elements, i, found;
1409     int          db, stencil, alpha, mipmap, rgba, value;
1410
1411     static GLXFBConfig *cached_config = NULL;
1412     static int          have_cached_config = 0;
1413
1414     if (have_cached_config)
1415         return cached_config;
1416
1417     fbconfigs = glXGetFBConfigs(mDisplay, mScreen, &n_elements);
1418
1419     db      = SHRT_MAX;
1420     stencil = SHRT_MAX;
1421     mipmap  = 0;
1422     rgba    = 0;
1423
1424     found = n_elements;
1425
1426     for (i = 0; i < n_elements; i++) {
1427         XVisualInfo *vi;
1428         int          visual_depth;
1429
1430         vi = glXGetVisualFromFBConfig(mDisplay, fbconfigs[i]);
1431         if (!vi)
1432             continue;
1433
1434         visual_depth = vi->depth;
1435         XFree(vi);
1436
1437         if (visual_depth != depth)
1438             continue;
1439
1440         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_ALPHA_SIZE, &alpha);
1441         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_BUFFER_SIZE, &value);
1442         if (value != depth && (value - alpha) != depth)
1443             continue;
1444
1445         value = 0;
1446         if (depth == 32) {
1447             glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
1448                                  GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
1449             if (value)
1450                 rgba = 1;
1451         }
1452
1453         if (!value) {
1454             if (rgba)
1455                 continue;
1456
1457             glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
1458                                  GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
1459             if (!value)
1460                 continue;
1461         }
1462
1463         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_DOUBLEBUFFER, &value);
1464         if (value > db)
1465             continue;
1466         db = value;
1467
1468         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_STENCIL_SIZE, &value);
1469         if (value > stencil)
1470             continue;
1471         stencil = value;
1472
1473         found = i;
1474     }
1475
1476     if (found != n_elements) {
1477         ret = malloc(sizeof(*ret));
1478         *ret = fbconfigs[found];
1479     }
1480
1481     if (n_elements)
1482         XFree(fbconfigs);
1483
1484     have_cached_config = 1;
1485     cached_config = ret;
1486     return ret;
1487 }
1488
1489 static int config_tfp(unsigned int width, unsigned int height)
1490 {
1491     GLXFBConfig *fbconfig;
1492     int attribs[7], i = 0;
1493     const int depth = 24;
1494
1495     if (!mpglXBindTexImage || !mpglXReleaseTexImage) {
1496         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] No GLX texture-from-pixmap extension available\n");
1497         return -1;
1498     }
1499
1500     if (depth != 24 && depth != 32)
1501         return -1;
1502
1503     g_image_pixmap = XCreatePixmap(mDisplay, vo_window, width, height, depth);
1504     if (!g_image_pixmap) {
1505         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create X11 pixmap\n");
1506         return -1;
1507     }
1508
1509     fbconfig = get_fbconfig_for_depth(depth);
1510     if (!fbconfig) {
1511         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not find an FBConfig for 32-bit pixmap\n");
1512         return -1;
1513     }
1514
1515     attribs[i++] = GLX_TEXTURE_TARGET_EXT;
1516     attribs[i++] = GLX_TEXTURE_2D_EXT;
1517     attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
1518     if (depth == 24)
1519         attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
1520     else if (depth == 32)
1521         attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
1522     attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
1523     attribs[i++] = GL_FALSE;
1524     attribs[i++] = None;
1525
1526     x11_trap_errors();
1527     gl_pixmap = mpglXCreatePixmap(mDisplay, *fbconfig, g_image_pixmap, attribs);
1528     XSync(mDisplay, False);
1529     if (x11_untrap_errors()) {
1530         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create GLX pixmap\n");
1531         return -1;
1532     }
1533     return 0;
1534 }
1535
1536 static int config_glx(unsigned int width, unsigned int height)
1537 {
1538     if (gl_context.setGlWindow(&gl_context) == SET_WINDOW_FAILED)
1539         return -1;
1540
1541     glDisable(GL_DEPTH_TEST);
1542     glDepthMask(GL_FALSE);
1543     glDisable(GL_CULL_FACE);
1544     glEnable(GL_TEXTURE_2D);
1545     glDrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
1546     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1547     glEnable(GL_BLEND);
1548     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1549
1550     /* Create TFP resources */
1551     if (gl_use_tfp && config_tfp(width, height) == 0)
1552         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using GLX texture-from-pixmap extension\n");
1553     else
1554         gl_use_tfp = 0;
1555
1556     /* Create OpenGL texture */
1557     /* XXX: assume GL_ARB_texture_non_power_of_two is available */
1558     glEnable(GL_TEXTURE_2D);
1559     glGenTextures(1, &gl_texture);
1560     mpglBindTexture(GL_TEXTURE_2D, gl_texture);
1561     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1562     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1563     if (!gl_use_tfp) {
1564         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1565         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1566         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1567         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
1568                      GL_BGRA, GL_UNSIGNED_BYTE, NULL);
1569     }
1570     mpglBindTexture(GL_TEXTURE_2D, 0);
1571     glDisable(GL_TEXTURE_2D);
1572
1573     glClearColor(0.0, 0.0, 0.0, 1.0);
1574     glClear(GL_COLOR_BUFFER_BIT);
1575
1576     if (gl_build_font() < 0)
1577         return -1;
1578     return 0;
1579 }
1580 #endif
1581
1582 #if CONFIG_XRENDER
1583 static XRenderPictFormat *get_xrender_argb32_format(void)
1584 {
1585     static XRenderPictFormat *pictformat = NULL;
1586     XRenderPictFormat templ;
1587
1588     const unsigned long mask =
1589         PictFormatType      |
1590         PictFormatDepth     |
1591         PictFormatRed       |
1592         PictFormatRedMask   |
1593         PictFormatGreen     |
1594         PictFormatGreenMask |
1595         PictFormatBlue      |
1596         PictFormatBlueMask  |
1597         PictFormatAlphaMask;
1598
1599     if (pictformat)
1600         return pictformat;
1601
1602     /* First, look for a 32-bit format which ignores the alpha component */
1603     templ.depth            = 32;
1604     templ.type             = PictTypeDirect;
1605     templ.direct.red       = 16;
1606     templ.direct.green     = 8;
1607     templ.direct.blue      = 0;
1608     templ.direct.redMask   = 0xff;
1609     templ.direct.greenMask = 0xff;
1610     templ.direct.blueMask  = 0xff;
1611     templ.direct.alphaMask = 0;
1612
1613     pictformat = XRenderFindFormat(mDisplay, mask, &templ, 0);
1614
1615     if (!pictformat) {
1616         /* Not all X servers support xRGB32 formats. However, the
1617          * XRENDER spec says that they must support an ARGB32 format,
1618          * so we can always return that.
1619          */
1620         pictformat = XRenderFindStandardFormat(mDisplay, PictStandardARGB32);
1621         if (!pictformat)
1622             mp_msg(MSGT_VO, MSGL_ERR, "XRENDER ARGB32 format not supported\n");
1623     }
1624     return pictformat;
1625 }
1626
1627 static int create_xrender_specific(void)
1628 {
1629     XRenderPictFormat *pictformat;
1630
1631     if (g_output_rect.width == 0 && g_output_rect.height == 0)
1632         return 0;
1633
1634     g_image_pixmap = XCreatePixmap(mDisplay, vo_window, g_output_rect.width,
1635                                    g_output_rect.height, 32);
1636     if (!g_image_pixmap) {
1637         mp_msg(MSGT_VO, MSGL_ERR, "Could not create video pixmap\n");
1638         return -1;
1639     }
1640
1641     pictformat = get_xrender_argb32_format();
1642     if (!pictformat)
1643         return -1;
1644     xr_video_picture = XRenderCreatePicture(mDisplay, g_image_pixmap,
1645                                             pictformat, 0, NULL);
1646     if (!xr_video_picture) {
1647         mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Pixmap\n");
1648         return -1;
1649     }
1650     return 0;
1651 }
1652
1653 static void free_xrender_specific(void)
1654 {
1655     if (xr_video_picture) {
1656         XRenderFreePicture(mDisplay, xr_video_picture);
1657         xr_video_picture = None;
1658     }
1659
1660     if (g_image_pixmap) {
1661         XFreePixmap(mDisplay, g_image_pixmap);
1662         g_image_pixmap = None;
1663     }
1664 }
1665
1666 static int reset_xrender_specific(void)
1667 {
1668     free_xrender_specific();
1669     return create_xrender_specific();
1670 }
1671
1672 /* XXX: create a Pixmap as large as the display rect */
1673 static int config_xrender(unsigned int width, unsigned int height)
1674 {
1675     XWindowAttributes wattr;
1676     XRenderPictFormat *pictformat;
1677
1678     XGetWindowAttributes(mDisplay, vo_window, &wattr);
1679     pictformat = XRenderFindVisualFormat(mDisplay, wattr.visual);
1680     if (!pictformat) {
1681         mp_msg(MSGT_VO, MSGL_ERR, "XRENDER does not support Window visual\n");
1682         return -1;
1683     }
1684
1685     xr_window_picture = XRenderCreatePicture(mDisplay, vo_window, pictformat,
1686                                              0, NULL);
1687     if (!xr_window_picture) {
1688         mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Window\n");
1689         return -1;
1690     }
1691     return reset_xrender_specific();
1692 }
1693 #endif
1694
1695 static int config_vaapi(uint32_t width, uint32_t height, uint32_t format)
1696 {
1697     VAConfigAttrib attrib;
1698     VAStatus status;
1699     int i, j, profile, entrypoint, max_entrypoints, num_surfaces;
1700
1701     /* Create video surfaces */
1702     if (!IMGFMT_IS_VAAPI(format))
1703         num_surfaces = MAX_OUTPUT_SURFACES;
1704     else {
1705         switch (IMGFMT_VAAPI_CODEC(format)) {
1706         case IMGFMT_VAAPI_CODEC_MPEG2:
1707             num_surfaces = NUM_VIDEO_SURFACES_MPEG2;
1708             break;
1709         case IMGFMT_VAAPI_CODEC_MPEG4:
1710             num_surfaces = NUM_VIDEO_SURFACES_MPEG4;
1711             break;
1712         case IMGFMT_VAAPI_CODEC_H264:
1713             num_surfaces = NUM_VIDEO_SURFACES_H264;
1714             break;
1715         case IMGFMT_VAAPI_CODEC_VC1:
1716             num_surfaces = NUM_VIDEO_SURFACES_VC1;
1717             break;
1718         default:
1719             num_surfaces = 0;
1720             break;
1721         }
1722         if (num_surfaces == 0)
1723             return -1;
1724         if (!is_direct_mapping())
1725             num_surfaces = FFMIN(2 * num_surfaces, MAX_VIDEO_SURFACES);
1726     }
1727     for (i = 0; i < num_surfaces; i++) {
1728         struct vaapi_surface *surface;
1729         surface = alloc_vaapi_surface(width, height, VA_RT_FORMAT_YUV420);
1730         if (!surface)
1731             return -1;
1732     }
1733     assert(va_num_surfaces == num_surfaces);
1734
1735 #if CONFIG_VAAPI_GLX
1736     /* Create GLX surfaces */
1737     if (gl_enabled && !gl_use_tfp) {
1738         status = vaCreateSurfaceGLX(va_context->display,
1739                                     GL_TEXTURE_2D, gl_texture,
1740                                     &gl_surface);
1741         if (!check_status(status, "vaCreateSurfaceGLX()"))
1742             return -1;
1743     }
1744 #endif
1745
1746     /* Create OSD data */
1747     va_osd_draw_alpha     = NULL;
1748     va_osd_image.image_id = VA_INVALID_ID;
1749     va_osd_image.buf      = VA_INVALID_ID;
1750     va_osd_subpicture     = VA_INVALID_ID;
1751     ensure_osd();
1752
1753     /* Create EOSD data */
1754     va_eosd_draw_alpha     = NULL;
1755     va_eosd_image.image_id = VA_INVALID_ID;
1756     va_eosd_image.buf      = VA_INVALID_ID;
1757     va_eosd_subpicture     = VA_INVALID_ID;
1758     for (i = 0; va_eosd_info[i].format; i++) {
1759         for (j = 0; j < va_num_subpic_formats; j++)
1760             if (va_subpic_formats[j].fourcc == va_eosd_info[i].format)
1761                 break;
1762         if (j < va_num_subpic_formats &&
1763             vaCreateImage(va_context->display, &va_subpic_formats[j],
1764                           width, height, &va_eosd_image) == VA_STATUS_SUCCESS)
1765             break;
1766     }
1767     if (va_eosd_info[i].format &&
1768         vaCreateSubpicture(va_context->display, va_eosd_image.image_id,
1769                            &va_eosd_subpicture) == VA_STATUS_SUCCESS) {
1770         va_eosd_draw_alpha = va_eosd_info[i].draw_alpha;
1771         mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for EOSD\n",
1772                string_of_VAImageFormat(&va_eosd_image.format));
1773     }
1774
1775     /* Allocate VA images */
1776     if (!IMGFMT_IS_VAAPI(format)) {
1777         VAImageFormat *image_format = VAImageFormat_from_imgfmt(format);
1778         if (!image_format)
1779             return -1;
1780         for (i = 0; i < va_num_surfaces; i++) {
1781             struct vaapi_surface * const s = va_free_surfaces[i];
1782             s->is_bound = 0;
1783             status = vaDeriveImage(va_context->display, s->id, &s->image);
1784             if (status == VA_STATUS_SUCCESS) {
1785                 /* vaDeriveImage() is supported, check format */
1786                 if (s->image.format.fourcc != image_format->fourcc) {
1787                     vaDestroyImage(va_context->display, s->image.image_id);
1788                     return -1;
1789                 }
1790                 if (s->image.width == width && s->image.height == height) {
1791                     s->is_bound = 1;
1792                     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using vaDeriveImage()\n");
1793                 }
1794                 else {
1795                     vaDestroyImage(va_context->display, s->image.image_id);
1796                     status = VA_STATUS_ERROR_OPERATION_FAILED;
1797                 }
1798                 
1799             }
1800             if (status != VA_STATUS_SUCCESS) {
1801                 status = vaCreateImage(va_context->display, image_format,
1802                                        width, height, &s->image);
1803                 if (!check_status(status, "vaCreateImage()"))
1804                     return -1;
1805             }
1806         }
1807         return 0;
1808     }
1809
1810     /* Check profile */
1811     profile = VAProfile_from_imgfmt(format);
1812     if (profile < 0)
1813         return -1;
1814
1815     /* Check entry-point (only VLD for now) */
1816     max_entrypoints = vaMaxNumEntrypoints(va_context->display);
1817     va_entrypoints = calloc(max_entrypoints, sizeof(*va_entrypoints));
1818     if (!va_entrypoints)
1819         return -1;
1820
1821     status = vaQueryConfigEntrypoints(va_context->display, profile,
1822                                       va_entrypoints, &va_num_entrypoints);
1823     if (!check_status(status, "vaQueryConfigEntrypoints()"))
1824         return -1;
1825
1826     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config_vaapi(%s): %d entrypoints available\n",
1827            string_of_VAProfile(profile), va_num_entrypoints);
1828     for (i = 0; i < va_num_entrypoints; i++)
1829         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAEntrypoint(va_entrypoints[i]));
1830
1831     entrypoint = VAEntrypoint_from_imgfmt(format);
1832     if (entrypoint != VAEntrypointVLD)
1833         return -1;
1834
1835     /* Check chroma format (only 4:2:0 for now) */
1836     attrib.type = VAConfigAttribRTFormat;
1837     status = vaGetConfigAttributes(va_context->display, profile, entrypoint, &attrib, 1);
1838     if (!check_status(status, "vaGetConfigAttributes()"))
1839         return -1;
1840     if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
1841         return -1;
1842
1843     /* Create a configuration for the decode pipeline */
1844     status = vaCreateConfig(va_context->display, profile, entrypoint, &attrib, 1, &va_context->config_id);
1845     if (!check_status(status, "vaCreateConfig()"))
1846         return -1;
1847
1848     /* Create a context for the decode pipeline */
1849     status = vaCreateContext(va_context->display, va_context->config_id,
1850                              width, height, VA_PROGRESSIVE,
1851                              va_surface_ids, va_num_surfaces,
1852                              &va_context->context_id);
1853     if (!check_status(status, "vaCreateContext()"))
1854         return -1;
1855     return 0;
1856 }
1857
1858 static int config(uint32_t width, uint32_t height,
1859                   uint32_t display_width, uint32_t display_height,
1860                   uint32_t flags, char *title, uint32_t format)
1861 {
1862     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config(): size %dx%d, display size %dx%d, flags %x, title '%s', format %x (%s)\n",
1863            width, height, display_width, display_height, flags, title, format, vo_format_name(format));
1864
1865     free_video_specific();
1866
1867     if (config_x11(width, height, display_width, display_height, flags, title) < 0)
1868         return -1;
1869
1870 #if CONFIG_GL
1871     if (gl_enabled && config_glx(width, height) < 0)
1872         return -1;
1873 #endif
1874
1875 #if CONFIG_XRENDER
1876     if (xr_enabled && config_xrender(width, height) < 0)
1877         return -1;
1878 #endif
1879
1880     if (config_vaapi(width, height, format) < 0)
1881         return -1;
1882
1883     g_is_visible   = 0;
1884     g_is_paused    = 0;
1885     g_image_width  = width;
1886     g_image_height = height;
1887     g_image_format = format;
1888     resize();
1889     return 0;
1890 }
1891
1892 static int query_format(uint32_t format)
1893 {
1894     const int default_caps = (VFCAP_CSP_SUPPORTED |
1895                               VFCAP_CSP_SUPPORTED_BY_HW |
1896                               VFCAP_HWSCALE_UP |
1897                               VFCAP_HWSCALE_DOWN |
1898                               VFCAP_OSD |
1899                               VFCAP_EOSD);
1900
1901     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] query_format(): format %x (%s)\n",
1902            format, vo_format_name(format));
1903
1904     switch (format) {
1905     case IMGFMT_VAAPI_MPEG2:
1906     case IMGFMT_VAAPI_MPEG4:
1907     case IMGFMT_VAAPI_H263:
1908     case IMGFMT_VAAPI_H264:
1909     case IMGFMT_VAAPI_WMV3:
1910     case IMGFMT_VAAPI_VC1:
1911         return default_caps | VOCAP_NOSLICES;
1912     case IMGFMT_NV12:
1913     case IMGFMT_YV12:
1914     case IMGFMT_I420:
1915     case IMGFMT_IYUV:
1916         if (VAImageFormat_from_imgfmt(format))
1917             return default_caps;
1918         break;
1919     }
1920     return 0;
1921 }
1922
1923 static inline int get_field_flags(int i)
1924 {
1925     return (g_deint && (g_image_fields & MP_IMGFIELD_INTERLACED) ? 
1926             (((!!(g_image_fields & MP_IMGFIELD_TOP_FIRST)) ^ i) == 0 ?
1927              VA_BOTTOM_FIELD : VA_TOP_FIELD) : VA_FRAME_PICTURE);
1928 }
1929
1930 static inline int get_colorspace_flags(void)
1931 {
1932     int csp = 0;
1933 #if USE_VAAPI_COLORSPACE
1934     switch (g_colorspace) {
1935     case 0:
1936         csp = ((g_image_width >= 1280 || g_image_height > 576) ?
1937                VA_SRC_BT709 : VA_SRC_BT601);
1938         break;
1939     case 1:
1940         csp = VA_SRC_BT601;
1941         break;
1942     case 2:
1943         csp = VA_SRC_BT709;
1944         break;
1945     default:
1946         assert(0);
1947         break;
1948     }
1949 #endif
1950     return csp;
1951 }
1952
1953 static void put_surface_x11(struct vaapi_surface *surface)
1954 {
1955     VAStatus status;
1956     int i;
1957
1958     for (i = 0; i <= !!(g_deint > 1); i++) {
1959         status = vaPutSurface(va_context->display,
1960                               surface->id,
1961                               vo_window,
1962                               0, 0, g_image_width, g_image_height,
1963                               g_output_rect.left,
1964                               g_output_rect.top,
1965                               g_output_rect.width,
1966                               g_output_rect.height,
1967                               NULL, 0,
1968                               get_field_flags(i) | get_colorspace_flags());
1969         if (!check_status(status, "vaPutSurface()"))
1970             return;
1971     }
1972 }
1973
1974 #if CONFIG_GL
1975 static void put_surface_glx(struct vaapi_surface *surface)
1976 {
1977     VAStatus status;
1978     int i;
1979
1980     if (gl_use_tfp) {
1981         for (i = 0; i <= !!(g_deint > 1); i++) {
1982             status = vaPutSurface(va_context->display,
1983                                   surface->id,
1984                                   g_image_pixmap,
1985                                   0, 0, g_image_width, g_image_height,
1986                                   0, 0, g_image_width, g_image_height,
1987                                   NULL, 0,
1988                                   get_field_flags(i) | get_colorspace_flags());
1989             if (!check_status(status, "vaPutSurface()"))
1990                 return;
1991         }
1992         g_output_surfaces[g_output_surface] = surface;
1993         return;
1994     }
1995
1996 #if CONFIG_VAAPI_GLX
1997     if (gl_binding) {
1998 #if USE_VAAPI_GLX_BIND
1999         for (i = 0; i <= !!(g_deint > 1); i++) {
2000             status = vaAssociateSurfaceGLX(va_context->display,
2001                                            gl_surface,
2002                                            surface->id,
2003                                            get_field_flags(i) | get_colorspace_flags());
2004             if (!check_status(status, "vaAssociateSurfaceGLX()"))
2005                 return;
2006         }
2007 #else
2008         mp_msg(MSGT_VO, MSGL_WARN, "vaAssociateSurfaceGLX() is not implemented\n");
2009         gl_binding = 0;
2010 #endif
2011     }
2012
2013     if (!gl_binding) {
2014         for (i = 0; i <= !!(g_deint > 1); i++) {
2015             status = vaCopySurfaceGLX(va_context->display,
2016                                       gl_surface,
2017                                       surface->id,
2018                                       get_field_flags(i) | get_colorspace_flags());
2019
2020             if (status == VA_STATUS_ERROR_UNIMPLEMENTED) {
2021                 mp_msg(MSGT_VO, MSGL_WARN,
2022                        "[vo_vaapi] vaCopySurfaceGLX() is not implemented\n");
2023                 gl_binding = 1;
2024             }
2025             else {
2026                 if (!check_status(status, "vaCopySurfaceGLX()"))
2027                     return;
2028             }
2029         }
2030     }
2031 #endif
2032     g_output_surfaces[g_output_surface] = surface;
2033 }
2034
2035 static int glx_bind_texture(void)
2036 {
2037     glEnable(GL_TEXTURE_2D);
2038     mpglBindTexture(GL_TEXTURE_2D, gl_texture);
2039
2040     if (gl_use_tfp) {
2041         x11_trap_errors();
2042         mpglXBindTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT, NULL);
2043         XSync(mDisplay, False);
2044         if (x11_untrap_errors())
2045             mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Update bind_tex_image failed\n");
2046     }
2047
2048 #if USE_VAAPI_GLX_BIND
2049     if (gl_binding) {
2050         VAStatus status;
2051         status = vaBeginRenderSurfaceGLX(va_context->display, gl_surface);
2052         if (!check_status(status, "vaBeginRenderSurfaceGLX()"))
2053             return -1;
2054     }
2055 #endif
2056     return 0;
2057 }
2058
2059 static int glx_unbind_texture(void)
2060 {
2061     if (gl_use_tfp) {
2062         x11_trap_errors();
2063         mpglXReleaseTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT);
2064         if (x11_untrap_errors())
2065             mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Failed to release?\n");
2066     }
2067
2068 #if USE_VAAPI_GLX_BIND
2069     if (gl_binding) {
2070         VAStatus status;
2071         status = vaEndRenderSurfaceGLX(va_context->display, gl_surface);
2072         if (!check_status(status, "vaEndRenderSurfaceGLX()"))
2073             return -1;
2074     }
2075 #endif
2076
2077     mpglBindTexture(GL_TEXTURE_2D, 0);
2078     glDisable(GL_TEXTURE_2D);
2079     return 0;
2080 }
2081
2082 static void render_background(void)
2083 {
2084     /* Original code from Mirco Muller (MacSlow):
2085        <http://cgit.freedesktop.org/~macslow/gl-gst-player/> */
2086     GLfloat fStartX = 0.0f;
2087     GLfloat fStartY = 0.0f;
2088     GLfloat fWidth  = (GLfloat)vo_dwidth;
2089     GLfloat fHeight = (GLfloat)vo_dheight;
2090
2091     glBegin(GL_QUADS);
2092     {
2093         /* top third, darker grey to white */
2094         glColor3f(0.85f, 0.85f, 0.85f);
2095         glVertex3f(fStartX, fStartY, 0.0f);
2096         glColor3f(0.85f, 0.85f, 0.85f);
2097         glVertex3f(fStartX + fWidth, fStartY, 0.0f);
2098         glColor3f(1.0f, 1.0f, 1.0f);
2099         glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
2100         glColor3f(1.0f, 1.0f, 1.0f);
2101         glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
2102
2103         /* middle third, just plain white */
2104         glColor3f(1.0f, 1.0f, 1.0f);
2105         glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
2106         glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
2107         glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2108         glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2109
2110         /* bottom third, white to lighter grey */
2111         glColor3f(1.0f, 1.0f, 1.0f);
2112         glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2113         glColor3f(1.0f, 1.0f, 1.0f);
2114         glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2115         glColor3f(0.62f, 0.66f, 0.69f);
2116         glVertex3f(fStartX + fWidth, fStartY + fHeight, 0.0f);
2117         glColor3f(0.62f, 0.66f, 0.69f);
2118         glVertex3f(fStartX, fStartY + fHeight, 0.0f);
2119     }
2120     glEnd();
2121 }
2122
2123 static void render_frame(void)
2124 {
2125     struct vo_rect * const r = &g_output_rect;
2126
2127     if (glx_bind_texture() < 0)
2128         return;
2129     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
2130     glBegin(GL_QUADS);
2131     {
2132         glTexCoord2f(0.0f, 0.0f); glVertex2i(r->left, r->top);
2133         glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->bottom);
2134         glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->bottom);
2135         glTexCoord2f(1.0f, 0.0f); glVertex2i(r->right, r->top);
2136     }
2137     glEnd();
2138     if (glx_unbind_texture() < 0)
2139         return;
2140 }
2141
2142 static void render_reflection(void)
2143 {
2144     struct vo_rect * const r = &g_output_rect;
2145     const unsigned int rh  = g_output_rect.height / 5;
2146     GLfloat ry = 1.0f - (GLfloat)rh / (GLfloat)r->height;
2147
2148     if (glx_bind_texture() < 0)
2149         return;
2150     glBegin(GL_QUADS);
2151     {
2152         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
2153         glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->top);
2154         glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->top);
2155
2156         glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
2157         glTexCoord2f(1.0f, ry); glVertex2i(r->right, r->top + rh);
2158         glTexCoord2f(0.0f, ry); glVertex2i(r->left, r->top + rh);
2159     }
2160     glEnd();
2161     if (glx_unbind_texture() < 0)
2162         return;
2163 }
2164
2165 static void flip_page_glx(void)
2166 {
2167     glClear(GL_COLOR_BUFFER_BIT);
2168
2169     if (gl_reflect) {
2170         render_background();
2171
2172         glPushMatrix();
2173         glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
2174         glTranslatef(50.0f, 0.0f, 0.0f);
2175     }
2176
2177     render_frame();
2178
2179     if (gl_reflect) {
2180         glPushMatrix();
2181         glTranslatef(0.0, (GLfloat)g_output_rect.height + 5.0f, 0.0f);
2182         render_reflection();
2183         glPopMatrix();
2184         glPopMatrix();
2185     }
2186
2187     if (cpu_stats) {
2188         gl_draw_rectangle(0, 0, vo_dwidth, 32, 0x000000ff);
2189         glColor3f(1.0f, 1.0f, 1.0f);
2190         glRasterPos2i(16, 20);
2191         gl_printf("MPlayer: %.1f%% of CPU @ %u MHz", cpu_usage, cpu_frequency);
2192     }
2193
2194     if (gl_finish)
2195         mpglFinish();
2196     gl_context.swapGlBuffers(&gl_context);
2197
2198     if (vo_fs) /* avoid flickering borders in fullscreen mode */
2199         glClear(GL_COLOR_BUFFER_BIT);
2200 }
2201 #endif
2202
2203 #if CONFIG_XRENDER
2204 static void put_surface_xrender(struct vaapi_surface *surface)
2205 {
2206     VAStatus status;
2207     int i;
2208
2209     for (i = 0; i <= !!(g_deint > 1); i++) {
2210         status = vaPutSurface(va_context->display,
2211                               surface->id,
2212                               g_image_pixmap,
2213                               0, 0, g_image_width, g_image_height,
2214                               0, 0, g_output_rect.width, g_output_rect.height,
2215                               NULL, 0,
2216                               get_field_flags(i) | get_colorspace_flags());
2217         if (!check_status(status, "vaPutSurface()"))
2218             return;
2219         XRenderComposite(mDisplay,
2220                          PictOpSrc, xr_video_picture, 0, xr_window_picture,
2221                          0, 0,
2222                          0, 0,
2223                          g_output_rect.left, g_output_rect.top,
2224                          g_output_rect.width, g_output_rect.height);
2225     }
2226 }
2227 #endif
2228
2229 static void put_surface(struct vaapi_surface *surface)
2230 {
2231     if (!surface || surface->id == VA_INVALID_SURFACE)
2232         return;
2233
2234 #if CONFIG_GL
2235     if (gl_enabled)
2236         put_surface_glx(surface);
2237     else
2238 #endif
2239 #if CONFIG_XRENDER
2240     if (xr_enabled)
2241         put_surface_xrender(surface);
2242     else
2243 #endif
2244         put_surface_x11(surface);
2245 }
2246
2247 static int draw_slice(uint8_t * image[], int stride[],
2248                       int w, int h, int x, int y)
2249 {
2250     struct vaapi_surface * const surface = va_free_surfaces[g_output_surface];
2251     VAImage * const va_image = &surface->image;
2252     VAStatus status;
2253     uint8_t *image_data = NULL;
2254     uint8_t *dst[3] = { 0, };
2255     unsigned int dst_stride[3];
2256
2257     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_slice(): location (%d,%d), size %dx%d\n", x, y, w, h);
2258
2259     status = vaMapBuffer(va_context->display, va_image->buf,
2260                          (void *)&image_data);
2261     if (!check_status(status, "vaMapBuffer()"))
2262         return VO_FALSE;
2263
2264     dst_stride[0] = va_image->pitches[0];
2265     dst[0] = image_data + va_image->offsets[0] + y * dst_stride[0] + x;
2266
2267     memcpy_pic(dst[0], image[0], w, h, dst_stride[0], stride[0]);
2268
2269     x /= 2;
2270     y /= 2;
2271     w /= 2;
2272     h /= 2;
2273
2274     if (g_image_format == IMGFMT_YV12) {
2275         /* MPlayer's YV12 is actually I420, so swap U/V components */
2276         dst_stride[1] = va_image->pitches[2];
2277         dst[1] = image_data + va_image->offsets[2] + y * dst_stride[1] + x;
2278         dst_stride[2] = va_image->pitches[1];
2279         dst[2] = image_data + va_image->offsets[1] + y * dst_stride[2] + x;
2280     }
2281     else {
2282         if (image[1]) {
2283             dst_stride[1] = va_image->pitches[1];
2284             dst[1] = image_data + va_image->offsets[1] + y * dst_stride[1] + x;
2285         }
2286         if (image[2]) {
2287             dst_stride[2] = va_image->pitches[2];
2288             dst[2] = image_data + va_image->offsets[2] + y * dst_stride[2] + x;
2289         }
2290     }
2291
2292     if (image[1]) /* RGBA only has a single plane */
2293         memcpy_pic(dst[1], image[1], w, h, dst_stride[1], stride[1]);
2294
2295     if (image[2]) /* NV12 only has two planes */
2296         memcpy_pic(dst[2], image[2], w, h, dst_stride[2], stride[2]);
2297
2298     status = vaUnmapBuffer(va_context->display, surface->image.buf);
2299     if (!check_status(status, "vaUnmapBuffer()"))
2300         return VO_FALSE;
2301
2302     return VO_TRUE;
2303 }
2304
2305 static int draw_frame(uint8_t * src[])
2306 {
2307     mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_X11_DrawFrameCalled);
2308
2309     return -1;
2310 }
2311
2312 static void draw_osd(void)
2313 {
2314     VAStatus status;
2315     const int osd_width  = va_osd_image.width;
2316     const int osd_height = va_osd_image.height;
2317
2318     ensure_osd();
2319     if (va_osd_image.image_id == VA_INVALID_ID)
2320         return;
2321
2322     if (!va_osd_draw_alpha)
2323         return;
2324
2325     if (!vo_update_osd(osd_width, osd_height))
2326         return;
2327  
2328     if (!vo_osd_check_range_update(0, 0, osd_width, osd_height)) {
2329         disable_osd();
2330         return;
2331     }
2332
2333     status = vaMapBuffer(va_context->display, va_osd_image.buf,
2334                          (void *)&va_osd_image_data);
2335     if (!check_status(status, "vaMapBuffer()"))
2336         return;
2337
2338     memset(va_osd_image_data, 0, va_osd_image.data_size);
2339
2340     vo_draw_text(osd_width, osd_height, va_osd_draw_alpha);
2341
2342     status = vaUnmapBuffer(va_context->display, va_osd_image.buf);
2343     if (!check_status(status, "vaUnmapBuffer()"))
2344         return;
2345     va_osd_image_data = NULL;
2346
2347     enable_osd();
2348 }
2349
2350 static void draw_eosd(mp_eosd_images_t *imgs)
2351 {
2352     ass_image_t *img = imgs->imgs;
2353     ass_image_t *i;
2354     VAStatus status;
2355
2356     if (!va_eosd_draw_alpha)
2357         return;
2358
2359     // Nothing changed, no need to redraw
2360     if (imgs->changed == 0)
2361         return;
2362
2363     // There's nothing to render!
2364     if (!img) {
2365         disable_eosd();
2366         return;
2367     }
2368
2369     if (imgs->changed == 1)
2370         goto eosd_skip_upload;
2371
2372     status = vaMapBuffer(va_context->display, va_eosd_image.buf,
2373                          (void *)&va_eosd_image_data);
2374     if (!check_status(status, "vaMapBuffer()"))
2375         return;
2376
2377     memset(va_eosd_image_data, 0, va_eosd_image.data_size);
2378
2379     for (i = img; i; i = i->next)
2380         va_eosd_draw_alpha(i->bitmap, i->w, i->h, i->stride,
2381                            i->dst_x, i->dst_y, i->color);
2382
2383     status = vaUnmapBuffer(va_context->display, va_eosd_image.buf);
2384     if (!check_status(status, "vaUnmapBuffer()"))
2385         return;
2386     va_eosd_image_data = NULL;
2387
2388 eosd_skip_upload:
2389     enable_eosd();
2390 }
2391
2392 static void flip_page(void)
2393 {
2394     struct vaapi_surface *surface;
2395
2396     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] flip_page()\n");
2397
2398     surface = g_output_surfaces[g_output_surface];
2399     if (!surface)
2400         return;
2401
2402     put_surface(surface);
2403     g_output_surface = (g_output_surface + 1) % MAX_OUTPUT_SURFACES;
2404     g_is_visible     = 1;
2405
2406 #if CONFIG_GL
2407     if (gl_enabled)
2408         flip_page_glx();
2409 #endif
2410 }
2411
2412 static struct vaapi_surface *get_surface(mp_image_t *mpi)
2413 {
2414     struct vaapi_surface *surface;
2415
2416     if (mpi->type == MP_IMGTYPE_NUMBERED && is_direct_mapping()) {
2417         assert(mpi->number < va_num_surfaces);
2418         surface = va_free_surfaces[mpi->number];
2419         return surface;
2420     }
2421
2422     /* Push current surface to a free slot */
2423     if (mpi->priv) {
2424         assert(!va_free_surfaces[va_free_surfaces_tail_index]);
2425         va_free_surfaces[va_free_surfaces_tail_index] = mpi->priv;
2426         va_free_surfaces_tail_index = (va_free_surfaces_tail_index + 1) % va_num_surfaces;
2427     }
2428
2429     /* Pop the least recently used free surface */
2430     assert(va_free_surfaces[va_free_surfaces_head_index]);
2431     surface = va_free_surfaces[va_free_surfaces_head_index];
2432     va_free_surfaces[va_free_surfaces_head_index] = NULL;
2433     va_free_surfaces_head_index = (va_free_surfaces_head_index + 1) % va_num_surfaces;
2434     return surface;
2435 }
2436
2437 static uint32_t get_image(mp_image_t *mpi)
2438 {
2439     struct vaapi_surface *surface;
2440
2441     if (mpi->type != MP_IMGTYPE_NUMBERED)
2442         return VO_FALSE;
2443
2444     if (!IMGFMT_IS_VAAPI(g_image_format))
2445         return VO_FALSE;
2446
2447     surface = get_surface(mpi);
2448     if (!surface)
2449         return VO_FALSE;
2450
2451     mpi->flags |= MP_IMGFLAG_DIRECT;
2452     mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = mpi->stride[3] = 0;
2453     mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = mpi->planes[3] = NULL;
2454     mpi->planes[0] = (char *)surface;
2455     mpi->planes[3] = (char *)(uintptr_t)surface->id;
2456     mpi->num_planes = 1;
2457     mpi->priv = surface;
2458
2459     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] get_image(): surface 0x%08x\n", surface->id);
2460
2461     return VO_TRUE;
2462 }
2463
2464 static int put_image(mp_image_t *mpi, struct vaapi_surface *surface)
2465 {
2466     VAStatus status;
2467  
2468     if ((mpi->flags & (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV)) != (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV))
2469         return VO_FALSE;
2470
2471     if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
2472         if (!draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0))
2473             return VO_FALSE;
2474     }
2475
2476     if (!surface->is_bound) {
2477         status = vaPutImage2(va_context->display,
2478                              surface->id,
2479                              surface->image.image_id,
2480                              mpi->x, mpi->y, mpi->w, mpi->h,
2481                              mpi->x, mpi->y, mpi->w, mpi->h);
2482         if (!check_status(status, "vaPutImage()"))
2483             return VO_FALSE;
2484     }
2485
2486     return VO_TRUE;
2487 }
2488
2489 static uint32_t draw_image(mp_image_t *mpi)
2490 {
2491     struct vaapi_surface *surface = (struct vaapi_surface *)mpi->priv;
2492
2493     g_image_fields = mpi->fields;
2494
2495     if (!IMGFMT_IS_VAAPI(mpi->imgfmt)) {
2496         /* XXX: no direct rendering in non-accelerated mode */
2497         surface = va_free_surfaces[g_output_surface];
2498         if (!put_image(mpi, surface))
2499             return VO_FALSE;
2500     }
2501
2502     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_image(): surface 0x%08x\n", surface->id);
2503
2504     g_output_surfaces[g_output_surface] = surface;
2505
2506     if (cpu_stats) {
2507         static uint64_t ticks;
2508         if ((ticks++ % 30) == 0) {
2509             cpu_frequency = get_cpu_frequency();
2510             cpu_usage = get_cpu_usage(CPU_USAGE_QUANTUM);
2511         }
2512     }
2513     return VO_TRUE;
2514 }
2515
2516 static void check_events(void)
2517 {
2518     int events = vo_x11_check_events(mDisplay);
2519
2520     if (events & VO_EVENT_RESIZE)
2521         resize();
2522
2523     if ((events & (VO_EVENT_EXPOSE|VO_EVENT_RESIZE)) && g_is_paused) {
2524         /* Redraw the last visible buffer  */
2525         if (g_is_visible) {
2526             struct vaapi_surface *surface = g_output_surfaces[g_output_surface];
2527             if (surface)
2528                 put_surface(surface);
2529         }
2530     }
2531 }
2532
2533 static VADisplayAttribute *get_display_attribute(const char *name)
2534 {
2535     VADisplayAttribute *attr;
2536     if (!strcasecmp(name, "brightness"))
2537         attr = &va_equalizer.brightness;
2538     else if (!strcasecmp(name, "contrast"))
2539         attr = &va_equalizer.contrast;
2540     else if (!strcasecmp(name, "saturation"))
2541         attr = &va_equalizer.saturation;
2542     else if (!strcasecmp(name, "hue"))
2543         attr = &va_equalizer.hue;
2544     else
2545         attr = NULL;
2546     return attr;
2547 }
2548
2549 static int get_equalizer(const char *name, int *value)
2550 {
2551     VADisplayAttribute * const attr = get_display_attribute(name);
2552     int r;
2553
2554     if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_GETTABLE))
2555         return VO_NOTIMPL;
2556
2557     /* normalize to -100 .. 100 range */
2558     r = attr->max_value - attr->min_value;
2559     if (r == 0)
2560         return VO_NOTIMPL;
2561     *value = ((attr->value - attr->min_value) * 200) / r - 100;
2562     return VO_TRUE;
2563 }
2564
2565 static int set_equalizer(const char *name, int value)
2566 {
2567     VADisplayAttribute * const attr = get_display_attribute(name);
2568     VAStatus status;
2569     int r;
2570
2571     if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_SETTABLE))
2572         return VO_NOTIMPL;
2573
2574     /* normalize to attribute value range */
2575     r = attr->max_value - attr->min_value;
2576     if (r == 0)
2577         return VO_NOTIMPL;
2578     attr->value = ((value + 100) * r) / 200 + attr->min_value;
2579
2580     status = vaSetDisplayAttributes(va_context->display, attr, 1);
2581     if (!check_status(status, "vaSetDisplayAttributes()"))
2582         return VO_FALSE;
2583     return VO_TRUE;
2584 }
2585
2586 static int control(uint32_t request, void *data, ...)
2587 {
2588     switch (request) {
2589     case VOCTRL_GET_DEINTERLACE:
2590         *(int*)data = g_deint;
2591         return VO_TRUE;
2592     case VOCTRL_SET_DEINTERLACE:
2593         g_deint = *(int*)data;
2594         if (g_deint)
2595             g_deint = g_deint_type;
2596         return VO_TRUE;
2597     case VOCTRL_PAUSE:
2598         return (g_is_paused = 1);
2599     case VOCTRL_RESUME:
2600         return (g_is_paused = 0);
2601     case VOCTRL_QUERY_FORMAT:
2602         return query_format(*((uint32_t *)data));
2603     case VOCTRL_GET_IMAGE:
2604         return get_image(data);
2605     case VOCTRL_DRAW_IMAGE:
2606         return draw_image(data);
2607     case VOCTRL_GUISUPPORT:
2608         return VO_TRUE;
2609     case VOCTRL_BORDER:
2610         vo_x11_border();
2611         resize();
2612         return VO_TRUE;
2613     case VOCTRL_FULLSCREEN:
2614         vo_x11_fullscreen();
2615         resize();
2616         return VO_TRUE;
2617     case VOCTRL_SET_EQUALIZER: {
2618         va_list ap;
2619         int value;
2620
2621         va_start(ap, data);
2622         value = va_arg(ap, int);
2623
2624         va_end(ap);
2625         return set_equalizer(data, value);
2626     }
2627     case VOCTRL_GET_EQUALIZER: {
2628         va_list ap;
2629         int *value;
2630
2631         va_start(ap, data);
2632         value = va_arg(ap, int *);
2633
2634         va_end(ap);
2635         return get_equalizer(data, value);
2636     }
2637     case VOCTRL_ONTOP:
2638         vo_x11_ontop();
2639         return VO_TRUE;
2640     case VOCTRL_UPDATE_SCREENINFO:
2641         update_xinerama_info();
2642         return VO_TRUE;
2643     case VOCTRL_GET_PANSCAN:
2644         return VO_TRUE;
2645     case VOCTRL_SET_PANSCAN:
2646         resize();
2647         return VO_TRUE;
2648     case VOCTRL_GET_HWACCEL_CONTEXT:
2649         *((void **)data) = va_context;
2650         return VO_TRUE;
2651     case VOCTRL_DRAW_EOSD:
2652         if (!data)
2653             return VO_FALSE;
2654         draw_eosd(data);
2655         return VO_TRUE;
2656     case VOCTRL_GET_EOSD_RES: {
2657         mp_eosd_res_t *r = data;
2658         r->mt = r->mb = r->ml = r->mr = 0;
2659         r->srcw = g_image_width;
2660         r->srch = g_image_height;
2661         r->w    = g_image_width;
2662         r->h    = g_image_height;
2663         return VO_TRUE;
2664     }
2665     }
2666     return VO_NOTIMPL;
2667 }