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