Web lists-archives.com

[MPlayer-dev-eng] [RFC][PATCH][EXPERIMENTAL] VAAPI support




Hi,
 this is a first attempt at porting VAAPI support from mplayer-vaapi
(https://github.com/gbeauchesne/mplayer-vaapi).

The patch still requires a lot of cleanup, but it works for me at least
for h264, mpeg2 and some wmv3. mpeg4 and h263 fails for me, but I get
the same results with the original mplayer-vaapi.

In my test it doesn't break VDPAU (h264 only, tested via vaapi wrapper)
nor software decoding.
It breaks mencoder (linking fails); fixing is trivial but I haven't
bothered to look at it yet.
Compilation may fail without vaapi headers (untested).

This is tested only on a sandybridge with vaapi 0.36.0 (debian stable).

All the options of the vo (deinterlacing, gl, xrender, ...) are
untested.

The stat files require some dependency, but the configure part is not
added yet; the files are there only to make the compiler happy.



Please note that I have no clue about the vaapi vo code, except that it
uses plane 3 for the surface. It just works.


What is still missing:
 - check and update with latest ffmpeg api (mplayer-vaapi development
   basically ended in 2011, with a small update for 0.34 in 2012)
 - cleanup and testing
 - support for newer libvaaapi
 - new features: vp8 and hevc (vp9 also?)
 - EGL?


More general things to do
 - better usability (why do I have to force the decoder? mplayer-vaapi
   uses a -va acceltype switch, together with the -vo)
 - encoding? (if ffmpeg supports it) (also for vdpau)






If you want to test it, copy vo_vaapi.c, stats.c and stats.h in libvo,
apply the patch and configure+compile as usual.
The interface is the same as VDPAU, pass -vo vaapi and -vc yourcodec
(eg. ffh264vaapi for h264 video).


Have fun!


Ciao,
 Roberto
Index: Makefile
===================================================================
--- Makefile	(revisione 37542)
+++ Makefile	(copia locale)
@@ -556,6 +556,7 @@
 SRCS_MPLAYER-$(TGA)           += libvo/vo_tga.c
 SRCS_MPLAYER-$(V4L2)          += libvo/vo_v4l2.c
 SRCS_MPLAYER-$(V4L2)          += libao2/ao_v4l2.c
+SRCS_MPLAYER-$(VAAPI)         += libvo/vo_vaapi.c
 SRCS_MPLAYER-$(VDPAU)         += libvo/vo_vdpau.c
 SRCS_MPLAYER-$(VESA)          += libvo/gtf.c                            \
                                  libvo/vo_vesa.c                        \
@@ -611,6 +612,7 @@
                libao2/audio_out.c       \
                libvo/aspect.c           \
                libvo/geometry.c         \
+               libvo/stats.c            \
                libvo/video_out.c        \
                libvo/vo_mpegpes.c       \
                libvo/vo_null.c          \
Index: codec-cfg.c
===================================================================
--- codec-cfg.c	(revisione 37542)
+++ codec-cfg.c	(copia locale)
@@ -258,6 +258,13 @@
     {"VDPAU_MPEG4", IMGFMT_VDPAU_MPEG4},
     {"VDPAU_HEVC",  IMGFMT_VDPAU_HEVC},
 
+    {"VAAPI_MPEG2", IMGFMT_VAAPI_MPEG2},
+    {"VAAPI_MPEG4", IMGFMT_VAAPI_MPEG4},
+    {"VAAPI_H263",  IMGFMT_VAAPI_H263},
+    {"VAAPI_H264",  IMGFMT_VAAPI_H264},
+    {"VAAPI_WMV3",  IMGFMT_VAAPI_WMV3},
+    {"VAAPI_VC1",   IMGFMT_VAAPI_VC1},
+
     {NULL,    0}
 };
 
Index: configure
===================================================================
--- configure	(revisione 37542)
+++ configure	(copia locale)
@@ -483,8 +483,10 @@
   --enable-dvb             enable DVB video output [autodetect]
   --enable-mga             enable mga_vid video output [autodetect]
   --enable-xmga            enable mga_vid X11 video output [autodetect]
+  --enable-xrender         enable Xrender video output [autodetect]
   --enable-xv              enable Xv video output [autodetect]
   --enable-xvmc            enable XvMC acceleration [disable]
+  --enable-vaapi           enable VA API acceleration [autodetect]
   --enable-vda             enable VDA acceleration [autodetect]
   --enable-vdpau           enable VDPAU acceleration [autodetect]
   --enable-vm              enable XF86VidMode support [autodetect]
@@ -600,6 +602,7 @@
   --extra-libs-mplayer=FLAGS  extra linker flags for MPlayer
   --extra-libs-mencoder=FLAGS extra linker flags for MEncoder
   --with-xvmclib=NAME         adapter-specific library name (e.g. XvMCNVIDIA)
+  --with-vaapi-prefix=PATH    prefix to VA-API include and lib directories
 
   --with-freetype-config=PATH path to freetype-config
   --with-sdl-config=PATH      path to sdl*-config
@@ -675,6 +678,8 @@
 _dga2=auto
 _xv=auto
 _xvmc=no  #auto when complete
+_vaapi=auto
+_vaapi_glx=no
 _vda=auto
 _vdpau=auto
 _sdl=auto
@@ -757,6 +762,7 @@
 _xinerama=auto
 _mga=auto
 _xmga=auto
+_xrender=auto
 _vm=auto
 _xf86keysym=auto
 _mlib=no #broken, thus disabled
@@ -908,6 +914,9 @@
   --with-xvmclib=*)
     _xvmclib=$(option_value $ac_option)
     ;;
+  --with-vaapi-prefix=*)
+    _vaapiprefix=$(echo $ac_option | cut -d '=' -f 2)
+    ;;
 
   --with-sdl-config=*)
     _sdlconfig=$(option_value $ac_option)
@@ -1016,6 +1025,8 @@
   --disable-x11)        _x11=no         ;;
   --enable-xshape)      _xshape=yes     ;;
   --disable-xshape)     _xshape=no      ;;
+  --enable-xrender)     _xrender=yes    ;;
+  --disable-xrender)    _xrender=no     ;;
   --enable-xss)         _xss=yes        ;;
   --disable-xss)        _xss=no         ;;
   --enable-xv)          _xv=yes         ;;
@@ -1022,6 +1033,8 @@
   --disable-xv)         _xv=no          ;;
   --enable-xvmc)        _xvmc=yes       ;;
   --disable-xvmc)       _xvmc=no        ;;
+  --enable-vaapi)       _vaapi=yes      ;;
+  --disable-vaapi)      _vaapi=no       ;;
   --enable-vda)         _vda=yes        ;;
   --disable-vda)        _vda=no         ;;
   --enable-vdpau)       _vdpau=yes      ;;
@@ -4676,6 +4689,30 @@
 fi
 
 
+echocheck "Xrender"
+if test "$_xrender" = auto ; then
+  cat > $TMPC <<EOF
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrender.h>
+int main(void) {
+  (void) XRenderCreatePicture(0, 0, 0, 0, 0);
+  return 0; }
+EOF
+  _xrender=no
+  cc_check -lXrender && _xrender=yes
+fi
+
+if test "$_xrender" = yes ; then
+  def_xrender='#define CONFIG_XRENDER 1'
+  libs_mplayer="$libs_mplayer -lXrender"
+  vomodules="xrender $vomodules"
+else
+  def_xrender='#undef CONFIG_XRENDER'
+  novomodules="xrender $novomodules"
+fi
+echores "$_xrender"
+
+
 echocheck "Xv"
 if test "$_xv" = auto && test "$_x11" = yes ; then
   _xv=no
@@ -4724,6 +4761,34 @@
 echores "$_xvmc"
 
 
+echocheck "VA-API"
+if test -n "$_vaapiprefix"; then
+  _vaapiinc="-I$_vaapiprefix/include"
+  _vaapilib="-L$_vaapiprefix/lib"
+fi
+if test "$_vaapi" = yes -o "$_vaapi" = auto; then
+  _vaapi=no
+  cat > $TMPC <<EOF
+#include <va/va_x11.h>
+int main(void) { (void) vaGetDisplay(0); return 0; }
+EOF
+  cc_check $_vaapiinc $_vaapilib -lva-x11 -lva && _vaapi=yes
+fi
+
+if test "$_vaapi" = yes ; then
+  def_vaapi='#define CONFIG_VAAPI 1'
+  extra_cflags="$extra_cflags $_vaapiinc"
+  libs_mencoder="$libs_mencoder $_vaapilib -lva"
+  libs_mplayer="$libs_mplayer $_vaapilib -lva-x11 -lva"
+  vomodules="vaapi $vomodules"
+  libavhwaccels="$libavhwaccels MPEG1_VAAPI_HWACCEL MPEG2_VAAPI_HWACCEL MPEG4_VAAPI_HWACCEL H263_VAAPI_HWACCEL H264_VAAPI_HWACCEL WMV3_VAAPI_HWACCEL VC1_VAAPI_HWACCEL"
+else
+  def_vaapi='#define CONFIG_VAAPI 0'
+  novomodules="vaapi $novomodules"
+fi
+echores "$_vaapi"
+
+
 echocheck "Video Decode Acceleration (VDA)"
 if test "$_vda" = auto ; then
   _vda=no
@@ -5583,6 +5648,44 @@
 echores "$_gl"
 
 
+echocheck "OpenGL utilities (GLU)"
+_glu=no
+if test "$_gl" = yes; then
+  cat > $TMPC << EOF
+#include <GL/glu.h>
+int main(void) {
+  gluPerspective(0.0, 0.0, 0.0, 0.0);
+  return 0;
+}
+EOF
+  cc_check -lGLU && _glu=yes
+fi
+if test "$_glu" = yes; then
+  libs_mplayer="$libs_mplayer -lGLU"
+fi
+echores "$_glu"
+
+
+echocheck "VA-API (with GLX support)"
+if test "$_vaapi" = yes; then
+  _vaapi_glx=no
+  if test "$_gl" = "yes" -a "$_glu" = yes; then
+    cat > $TMPC <<EOF
+#include <va/va_glx.h>
+int main(void) { (void) vaGetDisplayGLX(0); return 0; }
+EOF
+    cc_check $_vaapiinc $_vaapilib -lva-glx -lva && _vaapi_glx=yes
+  fi
+fi
+if test "$_vaapi_glx" = yes; then
+  def_vaapi_glx='#define CONFIG_VAAPI_GLX 1'
+  libs_mplayer="$libs_mplayer -lva-glx -lva"
+else
+  def_vaapi_glx='#define CONFIG_VAAPI_GLX 0'
+fi
+echores "$_vaapi_glx"
+
+
 echocheck "MatrixView"
 if test "$matrixview" = auto ; then
   matrixview="$_gl"
@@ -8517,6 +8620,7 @@
 UNRAR_EXEC = $_unrar_exec
 V4L2 = $_v4l2
 VCD = $_vcd
+VAAPI = $_vaapi
 VDA = $_vda
 VDPAU = $_vdpau
 VESA = $_vesa
@@ -8694,8 +8798,10 @@
 CONFIG_NETWORK  = $networking
 CONFIG_RTPDEC   = $networking
 CONFIG_VF_LAVFI = $_vf_lavfi
+CONFIG_VAAPI    = $_vaapi
 CONFIG_VDA      = $_vda
 CONFIG_VDPAU    = $_vdpau
+CONFIG_XRENDER  = $_xrender
 CONFIG_XVMC     = $_xvmc
 CONFIG_ZLIB     = $_zlib
 
@@ -9082,6 +9188,8 @@
 $def_tdfxvid
 $def_tga
 $def_v4l2
+$def_vaapi
+$def_vaapi_glx
 $def_vdpau
 $def_vesa
 $def_vidix
@@ -9107,6 +9215,7 @@
 $def_xinerama
 $def_xmga
 $def_xss
+$def_xrender
 $def_xv
 $def_xvmc
 $def_xvr100
@@ -9242,7 +9351,6 @@
 #define CONFIG_SWSCALE_ALPHA 1
 #define SWS_MAX_FILTER_SIZE 256
 #define CONFIG_QSV 0
-#define CONFIG_VAAPI 0
 
 #define HAVE_ALIGNED_STACK 1
 #define HAVE_AS_DN_DIRECTIVE 1
Index: etc/codecs.conf
===================================================================
--- etc/codecs.conf	(revisione 37542)
+++ etc/codecs.conf	(copia locale)
@@ -564,6 +564,38 @@
   out VDPAU_MPEG1
   out VDPAU_MPEG2
 
+videocodec ffmpeg12vaapi
+  info "FFmpeg MPEG-1/2 (VAAPI)"
+  status working
+  format 0x10000001  ; MPEG-1
+  format 0x10000002  ; MPEG-2
+  fourcc mpg1,mpg2,MPG2
+  fourcc PIM1        ; Pinnacle hardware-MPEG-1
+  fourcc PIM2        ; Pinnacle hardware-MPEG-2
+  fourcc "DVR "
+  fourcc hdv2
+  fourcc MPEG
+  fourcc hdv1
+  fourcc hdv3        ; HDV 1080i50
+  fourcc hdv5        ; HDV  720p25
+  fourcc mx5p        ; MPEG IMX 625/50 (50 Mb/s)
+  fourcc hdv6,hdv7,hdv8
+  fourcc xdv1,xdv2,xdv3
+  fourcc xdv4,xdv5,xdv6
+  fourcc xdv7,xdv8,xdv9
+  fourcc xdva,xdvb,xdvc
+  fourcc xdvd,xdve,xdvf
+  fourcc mx5n,mx4n,mx4p
+  fourcc mx3n,mx3p
+  fourcc AVmp
+  fourcc mp2v,mpgv
+  fourcc LMP2 ; Lead mpeg2 in avi
+  fourcc m2v1,m1v1
+  fourcc "m1v "
+  driver ffmpeg
+  dll "mpegvideo"
+  out VAAPI_MPEG2
+
 videocodec ffmpeg2crystalhd
   info "FFmpeg MPEG-2 (CrystalHD)"
   status working
@@ -1277,6 +1309,14 @@
   dll wmv3
   out VDPAU_WMV3
 
+videocodec ffwmv3vaapi
+  info "FFmpeg WMV3/WMV9 (VAAPI)"
+  status buggy
+  fourcc WMV3,wmv3
+  driver ffmpeg
+  dll wmv3
+  out VAAPI_WMV3
+
 videocodec ffwmv3crystalhd
   info "FFmpeg WMV3/WMV9 (CrystalHD)"
   status buggy
@@ -1303,6 +1343,15 @@
   dll vc1
   out VDPAU_VC1
 
+videocodec ffvc1vaapi
+  info "FFmpeg WVC1 (VAAPI)"
+  status buggy
+  fourcc WVC1,wvc1,WMVA
+  fourcc vc-1,VC-1
+  driver ffmpeg
+  dll vc1
+  out VAAPI_VC1
+
 videocodec ffvc1crystalhd
   info "FFmpeg WVC1 (CrystalHD)"
   status buggy
@@ -1403,6 +1452,26 @@
   dll h264
   out VDPAU_H264
 
+videocodec ffh264vaapi
+  info "FFmpeg H.264 (VAAPI)"
+  status working
+  fourcc H264,h264
+  fourcc X264,x264
+  fourcc avc1,AVC1
+  fourcc davc,DAVC
+  fourcc ai1p,ai1q,ai12,ai13
+  fourcc ai15,ai16
+  fourcc ai5p,ai5q,ai52,ai53
+  fourcc ai55,ai56
+  fourcc x3eV
+  fourcc Q264,V264
+  fourcc GAVC,UMSV
+  fourcc rv64 ; Radvision
+  format 0x10000005
+  driver ffmpeg
+  dll h264
+  out VAAPI_H264
+
 videocodec ffh264crystalhd
   info "FFmpeg H.264 (CrystalHD)"
   status working
@@ -1546,6 +1615,42 @@
   dll mpeg4
   out VDPAU_MPEG4
 
+videocodec ffodivxvaapi
+  info "FFmpeg MPEG-4,DIVX-4/5 (VAAPI)"
+  status working
+  fourcc FMP4,fmp4
+  fourcc DIVX,divx
+  fourcc DIV1,div1 divx
+  fourcc MP4S,mp4s ; ISO MPEG-4 Video V1
+  fourcc M4S2,m4s2
+  fourcc xvid,XVID,XviD,XVIX
+  fourcc DX50,dx50,BLZ0 DX50
+  fourcc mp4v,MP4V
+  format 0x4
+  fourcc UMP4
+  fourcc RMP4
+  fourcc 3IV2,3iv2  ; 3ivx Delta 4
+  fourcc DXGM
+  fourcc SEDG ; diskless camcorder Samsung Miniket VP-M110
+  fourcc SMP4,smp4 ; Samsung SMP4 video codec
+  fourcc VIDM ; vidm 4.01 codec
+  format 0x10000004  ; mpeg 4 es
+  fourcc m4cc,M4CC
+  fourcc hdx4,HDX4
+  fourcc FVFW,fvfw
+  fourcc FFDS
+  fourcc DCOD,MVXM,EM4A,PM4V
+  fourcc M4T3,DMK2,DIGI,INMC
+  fourcc EPHV,SN40,WAWV
+  fourcc uldx,ULDX,VSPX
+  fourcc SIPP ; Samsung SHR-6040
+  fourcc DreX,DM4V,LMP4,DP02
+  fourcc QMP4
+  fourcc DYM4
+  driver ffmpeg
+  dll mpeg4
+  out VAAPI_MPEG4
+
 videocodec ffodivxcrystalhd
   info "FFmpeg MPEG-4,DIVX-4/5 (CrystalHD)"
   status working
@@ -2222,6 +2327,22 @@
   dll h263
   out YV12,I420,IYUV
 
+videocodec ffh263vaapi
+  info "FFmpeg H.263+ (VAAPI)"
+  status working
+  fourcc H263,U263,h263,X263,M263
+  fourcc viv1 h263 ; internal MPlayer FourCC
+  fourcc s263
+  fourcc T263
+  fourcc D263,d263     ; DEC H263
+  fourcc L263     ; Lead H263
+  fourcc ILVR     ; ITU H263+
+  fourcc VX1K     ; Agora Labs VX1000S H263
+  fourcc lsvm     ; lsv h263
+  driver ffmpeg
+  dll h263
+  out VAAPI_H263
+
 videocodec ffzygo
   info "FFmpeg ZyGo"
   status untested
Index: help/help_mp-en.h
===================================================================
--- help/help_mp-en.h	(revisione 37542)
+++ help/help_mp-en.h	(copia locale)
@@ -1614,6 +1614,7 @@
 #define MSGTR_MPCODECS_TryingPixfmt "[VD_FFMPEG] Trying pixfmt=%d.\n"
 #define MSGTR_MPCODECS_McGetBufferShouldWorkOnlyWithXVMC "[VD_FFMPEG] The mc_get_buffer should work only with XVMC acceleration!!"
 #define MSGTR_MPCODECS_OnlyBuffersAllocatedByVoXvmcAllowed "[VD_FFMPEG] Only buffers allocated by vo_xvmc allowed.\n"
+#define MSGTR_MPCODECS_VAAPIAcceleratedCodec "[VD_FFMPEG] VA API accelerated codec.\n"
 
 // libmpcodecs/ve_lavc.c
 #define MSGTR_MPCODECS_HighQualityEncodingSelected "[VE_LAVC] High quality encoding selected (non-realtime)!\n"
Index: libmpcodecs/img_format.c
===================================================================
--- libmpcodecs/img_format.c	(revisione 37542)
+++ libmpcodecs/img_format.c	(copia locale)
@@ -143,6 +143,14 @@
     case IMGFMT_VDPAU_WMV3:      return "WMV3 VDPAU acceleration";
     case IMGFMT_VDPAU_VC1:       return "VC1 VDPAU acceleration";
     case IMGFMT_VDPAU_HEVC:      return "HEVC VDPAU acceleration";
+    case IMGFMT_VAAPI_MPEG2:     return "MPEG-2 VA-API Acceleration";
+    case IMGFMT_VAAPI_MPEG2_IDCT: return "MPEG-2 VA-API Acceleration (Motion Compensation and IDCT)";
+    case IMGFMT_VAAPI_MPEG2_MOCO: return "MPEG-2 VA-API Acceleration (Motion Compensation)";
+    case IMGFMT_VAAPI_MPEG4:     return "MPEG-4 VA-API Acceleration";
+    case IMGFMT_VAAPI_H263:      return "H.263 VA-API Acceleration";
+    case IMGFMT_VAAPI_H264:      return "H.264 VA-API Acceleration";
+    case IMGFMT_VAAPI_WMV3:      return "WMV3 VA-API Acceleration";
+    case IMGFMT_VAAPI_VC1:       return "VC-1 VA-API Acceleration";
     }
     snprintf(unknown_format,20,"Unknown 0x%04x",format);
     return unknown_format;
Index: libmpcodecs/img_format.h
===================================================================
--- libmpcodecs/img_format.h	(revisione 37542)
+++ libmpcodecs/img_format.h	(copia locale)
@@ -295,8 +295,29 @@
 #define IMGFMT_VDPAU_MPEG4         (IMGFMT_VDPAU|0x06)
 #define IMGFMT_VDPAU_HEVC          (IMGFMT_VDPAU|0x07)
 
-#define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VDPAU(fmt) || IMGFMT_IS_XVMC(fmt))
+// VA-API Formats
+#define IMGFMT_VAAPI               0x56410000 /* 'VA'00 */
+#define IMGFMT_VAAPI_MASK          0xFFFF0000
+#define IMGFMT_IS_VAAPI(fmt)       (((fmt)&IMGFMT_VAAPI_MASK)==IMGFMT_VAAPI)
+#define IMGFMT_VAAPI_CODEC_MASK    0x000000F0
+#define IMGFMT_VAAPI_CODEC(fmt)    ((fmt)&IMGFMT_VAAPI_CODEC_MASK)
+#define IMGFMT_VAAPI_CODEC_MPEG2   (0x10)
+#define IMGFMT_VAAPI_CODEC_MPEG4   (0x20)
+#define IMGFMT_VAAPI_CODEC_H264    (0x30)
+#define IMGFMT_VAAPI_CODEC_VC1     (0x40)
+#define IMGFMT_VAAPI_MPEG2         (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_MPEG2)
+#define IMGFMT_VAAPI_MPEG2_IDCT    (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_MPEG2|1)
+#define IMGFMT_VAAPI_MPEG2_MOCO    (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_MPEG2|2)
+#define IMGFMT_VAAPI_MPEG4         (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_MPEG4)
+#define IMGFMT_VAAPI_H263          (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_MPEG4|1)
+#define IMGFMT_VAAPI_H264          (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_H264)
+#define IMGFMT_VAAPI_VC1           (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_VC1)
+#define IMGFMT_VAAPI_WMV3          (IMGFMT_VAAPI|IMGFMT_VAAPI_CODEC_VC1|1)
 
+#define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VDPAU(fmt) || \
+                                IMGFMT_IS_VAAPI(fmt) || \
+                                IMGFMT_IS_XVMC(fmt))
+
 typedef struct {
     void* data;
     int size;
Index: libmpcodecs/vd_ffmpeg.c
===================================================================
--- libmpcodecs/vd_ffmpeg.c	(revisione 37542)
+++ libmpcodecs/vd_ffmpeg.c	(copia locale)
@@ -37,6 +37,10 @@
 
 #include "vd_internal.h"
 
+#if CONFIG_VAAPI
+#include "libavcodec/vaapi.h"
+extern struct vaapi_context *va_context;
+#endif
 #if CONFIG_VDPAU
 #include "libavcodec/vdpau.h"
 #endif
@@ -231,6 +235,7 @@
 
 static int pixfmt2imgfmt2(enum AVPixelFormat fmt, enum AVCodecID cid)
 {
+    mp_msg(MSGT_DECVIDEO, MSGL_DBG2, "p2i2: fmt %x, cid %x\n", fmt, cid);
     if (fmt == AV_PIX_FMT_VDPAU)
         switch (cid) {
         case AV_CODEC_ID_H264:       return IMGFMT_VDPAU_H264;
@@ -241,6 +246,16 @@
         case AV_CODEC_ID_VC1:        return IMGFMT_VDPAU_VC1;
         case AV_CODEC_ID_HEVC:       return IMGFMT_VDPAU_HEVC;
         }
+    if (fmt == AV_PIX_FMT_VAAPI)
+        switch (cid) {
+        case AV_CODEC_ID_H264:       return IMGFMT_VAAPI_H264;
+        case AV_CODEC_ID_H263:       return IMGFMT_VAAPI_H263;
+        case AV_CODEC_ID_MPEG2VIDEO: return IMGFMT_VAAPI_MPEG2;
+        case AV_CODEC_ID_MPEG4:      return IMGFMT_VAAPI_MPEG4;
+        case AV_CODEC_ID_WMV3:       return IMGFMT_VAAPI_WMV3;
+        case AV_CODEC_ID_VC1:        return IMGFMT_VAAPI_VC1;
+//        case AV_CODEC_ID_HEVC:       return IMGFMT_VAAPI_HEVC;
+        }
     return pixfmt2imgfmt(fmt);
 }
 
@@ -292,13 +307,15 @@
     ctx->use_vdpau = fmt == AV_PIX_FMT_VDPAU;
     imgfmt = pixfmt2imgfmt2(fmt, avctx->codec_id);
 #if CONFIG_VDPAU
-    if (!ctx->use_vdpau) {
-        av_freep(&avctx->hwaccel_context);
-    } else {
+    if (ctx->use_vdpau) {
         AVVDPAUContext *vdpc = avctx->hwaccel_context;
         if (!vdpc)
             avctx->hwaccel_context = vdpc = av_alloc_vdpaucontext();
         vdpc->render2 = vdpau_render_wrapper;
+    } else if (IMGFMT_IS_VAAPI(imgfmt)){
+//            avctx->hwaccel_context = va_context;
+    } else {
+        av_freep(&avctx->hwaccel_context);
     }
 #endif
     if (IMGFMT_IS_HWACCEL(imgfmt)) {
@@ -306,13 +323,16 @@
         ctx->nonref_dr = 0;
         avctx->get_buffer2 = get_buffer2;
         mp_msg(MSGT_DECVIDEO, MSGL_V, IMGFMT_IS_XVMC(imgfmt) ?
-               MSGTR_MPCODECS_XVMCAcceleratedMPEG2 :
-               "[VD_FFMPEG] VDPAU accelerated decoding\n");
+               MSGTR_MPCODECS_XVMCAcceleratedMPEG2 : 
+               (IMGFMT_IS_VDPAU(imgfmt) ?
+               "[VD_FFMPEG] VDPAU accelerated decoding\n" :
+               "[VD_FFMPEG] VAAPI accelerated decoding\n"));
         if (ctx->use_vdpau) {
             avctx->draw_horiz_band = NULL;
             avctx->slice_flags = 0;
             ctx->do_slices = 0;
         } else {
+avctx->thread_count = 1;
             avctx->draw_horiz_band = draw_slice;
             avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
             ctx->do_slices = 1;
@@ -526,7 +546,8 @@
             mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_CantCloseCodec);
 
         av_freep(&avctx->extradata);
-        av_freep(&avctx->hwaccel_context);
+        if (!IMGFMT_IS_VAAPI(ctx->best_csp)) // VAAPI manages its context
+            av_freep(&avctx->hwaccel_context);
         av_freep(&avctx->slice_offset);
     }
 
@@ -541,7 +562,7 @@
     mp_image_t *mpi = src->opaque;
     sh_video_t *sh = s->opaque;
     vd_ffmpeg_ctx *ctx = sh->context;
-    uint8_t *source[MP_MAX_PLANES]= {src->data[0] + offset[0], src->data[1] + offset[1], src->data[2] + offset[2]};
+    uint8_t *source[MP_MAX_PLANES]= {src->data[0] + offset[0], src->data[1] + offset[1], src->data[2] + offset[2], src->data[3] + offset[3]};
     int strides[MP_MAX_PLANES] = {src->linesize[0], src->linesize[1], src->linesize[2]};
     if (!src->data[0]) {
         mp_msg(MSGT_DECVIDEO, MSGL_FATAL, "BUG in FFmpeg, draw_slice called with NULL pointer!\n");
@@ -622,7 +643,7 @@
 static int init_vo(sh_video_t *sh, enum AVPixelFormat pix_fmt, int ignore_aspect)
 {
     vd_ffmpeg_ctx *ctx = sh->context;
-    const AVCodecContext *avctx = ctx->avctx;
+    /*const*/ AVCodecContext *avctx = ctx->avctx;
     int width, height;
     int imgfmt = pixfmt2imgfmt2(pix_fmt, avctx->codec_id);
 
@@ -655,6 +676,8 @@
         sh->disp_h = height;
         if (!mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, ctx->best_csp))
             return -1;
+        if (IMGFMT_IS_VAAPI(imgfmt)) // Really needed here?
+            avctx->hwaccel_context = va_context;
         ctx->vo_initialized = 1;
     }
     return 0;
@@ -752,6 +775,12 @@
         avctx->draw_horiz_band= draw_slice;
     }
 #endif
+#if CONFIG_VAAPI
+    if(IMGFMT_IS_VAAPI(mpi->imgfmt)) {
+//        mpi->planes[3] = mpi->priv;
+        avctx->draw_horiz_band= draw_slice; // Needed?
+    }
+#endif
 
     pic->data[0]= mpi->planes[0];
     pic->data[1]= mpi->planes[1];
Index: libvo/gl_common.c
===================================================================
--- libvo/gl_common.c	(revisione 37542)
+++ libvo/gl_common.c	(copia locale)
@@ -165,6 +165,11 @@
 void (GLAPIENTRY *mpglUniform1iv)(GLint, GLsizei, const GLint *);
 void (GLAPIENTRY *mpglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const float *);
 
+void (GLAPIENTRY *mpglXBindTexImage)(Display *, GLXDrawable, int, const int *);
+void (GLAPIENTRY *mpglXReleaseTexImage)(Display *, GLXDrawable, int);
+GLXPixmap (GLAPIENTRY *mpglXCreatePixmap)(Display *, GLXFBConfig, Pixmap, const int *);
+void (GLAPIENTRY *mpglXDestroyPixmap)(Display *, GLXPixmap);
+
 //! \defgroup glgeneral OpenGL general helper functions
 
 //! \defgroup glcontext OpenGL context management helper functions
@@ -550,6 +555,12 @@
   SIMPLE_FUNC_DESC(GetUniformLocation),
   SIMPLE_FUNC_DESC(Uniform1iv),
   SIMPLE_FUNC_DESC(UniformMatrix4fv),
+
+  {&mpglXBindTexImage, "GLX_EXT_texture_from_pixmap", {"glXBindTexImageEXT", NULL}},
+  {&mpglXReleaseTexImage, "GLX_EXT_texture_from_pixmap", {"glXReleaseTexImageEXT", NULL}},
+  {&mpglXCreatePixmap, "GLX_EXT_texture_from_pixmap", {"glXCreatePixmap", NULL}},
+  {&mpglXDestroyPixmap, "GLX_EXT_texture_from_pixmap", {"glXDestroyPixmap", NULL}},
+
   {NULL}
 };
 
Index: libvo/gl_common.h
===================================================================
--- libvo/gl_common.h	(revisione 37542)
+++ libvo/gl_common.h	(copia locale)
@@ -316,4 +316,9 @@
 extern void* (GLAPIENTRY *mpglAllocateMemoryMESA)(void *, int, size_t, float, float, float);
 extern void (GLAPIENTRY *mpglFreeMemoryMESA)(void *, int, void *);
 
+extern void (GLAPIENTRY *mpglXBindTexImage)(Display *, GLXDrawable, int, const int *);
+extern void (GLAPIENTRY *mpglXReleaseTexImage)(Display *, GLXDrawable, int);
+extern GLXPixmap (GLAPIENTRY *mpglXCreatePixmap)(Display *, GLXFBConfig, Pixmap, const int *);
+extern void (GLAPIENTRY *mpglXDestroyPixmap)(Display *, GLXPixmap);
+
 #endif /* MPLAYER_GL_COMMON_H */
Index: libvo/video_out.c
===================================================================
--- libvo/video_out.c	(revisione 37542)
+++ libvo/video_out.c	(copia locale)
@@ -101,6 +101,7 @@
 extern const vo_functions_t video_out_xmga;
 extern const vo_functions_t video_out_x11;
 extern const vo_functions_t video_out_xvmc;
+extern const vo_functions_t video_out_vaapi;
 extern const vo_functions_t video_out_vdpau;
 extern const vo_functions_t video_out_xv;
 extern const vo_functions_t video_out_gl_nosw;
@@ -304,6 +305,9 @@
 #ifdef CONFIG_MNG
         &video_out_mng,
 #endif
+#if CONFIG_VAAPI
+        &video_out_vaapi,
+#endif
         NULL
 };
 
#include "config.h"
#include "stats.h"
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <inttypes.h>

#if CONFIG_LIBGTOP
#include <glibtop/cpu.h>
#include <glibtop/proctime.h>
#include <glibtop/procstate.h>
#endif

// Process statistics
struct proc_stats {
    uint64_t utime;
    uint64_t stime;
    uint64_t cutime;
    uint64_t cstime;
    uint64_t frequency;
    uint64_t cpu_time;
    uint64_t start_time;
    uint64_t current_time;
};

// Get current process stats
static int get_proc_stats(struct proc_stats *pstats);

void stats_init(void)
{
#if CONFIG_LIBGTOP
    glibtop_init();
#endif
}

void stats_exit(void)
{
#if CONFIG_LIBGTOP
    glibtop_close();
#endif
}

// Get CPU frequency
unsigned int get_cpu_frequency(void)
{
    unsigned int freq = 0;
#if defined __linux__
    {
        FILE *proc_file = fopen("/proc/cpuinfo", "r");
        if (proc_file) {
            char line[256];
            char *old_locale = setlocale(LC_NUMERIC, NULL);
            setlocale(LC_NUMERIC, "C");
            while(fgets(line, sizeof(line), proc_file)) {
                float f;
                int len = strlen(line);
                if (len == 0)
                    continue;
                line[len - 1] = 0;
                if (sscanf(line, "cpu MHz : %f", &f) == 1)
                    freq = (unsigned int)f;
            }
            setlocale(LC_NUMERIC, old_locale);
            fclose(proc_file);
        }
    }
#endif
    return freq;
}

// Get CPU usage in percent
static float get_cpu_usage_1(void)
{
    static struct proc_stats prev_stats;
    struct proc_stats curr_stats;
    uint64_t prev_proc_time = 0, curr_proc_time = 0;
    float pcpu = 0.0f;

    if (get_proc_stats(&curr_stats) == 0) {
        prev_proc_time += prev_stats.utime;
        prev_proc_time += prev_stats.stime;
        prev_proc_time += prev_stats.cutime;
        prev_proc_time += prev_stats.cstime;
        curr_proc_time += curr_stats.utime;
        curr_proc_time += curr_stats.stime;
        curr_proc_time += curr_stats.cutime;
        curr_proc_time += curr_stats.cstime;
        if (prev_stats.start_time > 0)
            pcpu = 100.0 * ((float)(curr_proc_time - prev_proc_time) /
                            (float)(curr_stats.cpu_time - prev_stats.cpu_time));
        prev_stats = curr_stats;
    }
    return pcpu;
}

float get_cpu_usage(enum CpuUsageType type)
{
    static float pcpu_total = 0.0;
    static unsigned int n_samples;
    float pcpu;

    pcpu        = get_cpu_usage_1();
    pcpu_total += pcpu / 100.0;
    ++n_samples;

    if (type == CPU_USAGE_AVERAGE)
        pcpu = 100.0 * (pcpu_total / n_samples);
    return pcpu;
}

// For ELF executable, notes are pushed before environment and args
static int find_elf_note(unsigned long match, unsigned long *pval)
{
    unsigned long *ep = (unsigned long *)__environ;
    while (*ep++);
    for (; *ep != 0; ep += 2) {
        if (ep[0] == match) {
            *pval = ep[1];
            return 0;
        }
    }
    return -1;
}

#ifndef AT_CLKTCK
#define AT_CLKTCK 17
#endif

// Get current process stats
int get_proc_stats(struct proc_stats *pstats)
{
    int error = -1;
    char line[256], *str, *end;
    char vc;
    int vi;
    unsigned long vul;
    unsigned long long vull;
    float vf;
#if defined __linux__
    {
        FILE *proc_file = fopen("/proc/self/stat", "r");
        if (proc_file) {
            if (fgets(line, sizeof(line), proc_file)) {
                unsigned long utime, stime, cutime, cstime, start_time;
                str = strrchr(line, ')');
                if (str && sscanf(str + 2,
                                  "%c "
                                  "%d %d %d %d %d "
                                  "%lu %lu %lu %lu %lu %lu %lu "
                                  "%ld %ld %ld %ld %ld %ld "
                                  "%lu %lu ",
                                  &vc,
                                  &vi, &vi, &vi, &vi, &vi, 
                                  &vul, &vul, &vul, &vul, &vul, &utime, &stime,
                                  &cutime, &cstime, &vul, &vul, &vul, &vul,
                                  &start_time, &vul) == 21) {
                    pstats->utime      = utime;
                    pstats->stime      = stime;
                    pstats->cutime     = cutime;
                    pstats->cstime     = cstime;
                    pstats->start_time = start_time;
                    error = 0;
                }
            }
            fclose(proc_file);
        }
        if (error)
            return error;
        error = -1;

        if (find_elf_note(AT_CLKTCK, &vul) == 0) {
            pstats->frequency = vul;
            error = 0;
        }
        if (error)
            return error;
        error = -1;

        proc_file = fopen("/proc/uptime", "r");
        if (proc_file) {
            if (fgets(line, sizeof(line), proc_file)) {
                char *old_locale = setlocale(LC_NUMERIC, NULL);
                setlocale(LC_NUMERIC, "C");
                if (sscanf(line, "%f", &vf) == 1) {
                    pstats->cpu_time = (uint64_t)(vf * (float)pstats->frequency);
                    error = 0;
                }
                setlocale(LC_NUMERIC, old_locale);
            }
            fclose(proc_file);
        }
    }
#elif CONFIG_LIBGTOP
    {
        glibtop_cpu cpu;
        glibtop_proc_time proc_time;
        glibtop_proc_state proc_state;

        glibtop_get_cpu(&cpu);
        glibtop_get_proc_state(&proc_state, getpid());
        pstats->cpu_time   = cpu.xcpu_total[proc_state.processor];

        glibtop_get_proc_time(&proc_time, getpid());
        pstats->utime      = proc_time.utime;
        pstats->stime      = proc_time.stime;
        pstats->cutime     = proc_time.cutime;
        pstats->cstime     = proc_time.cstime;
        pstats->start_time = proc_time.start_time;
        pstats->frequency  = proc_time.frequency;

        error = 0;
    }
#endif
    return error;
}
#ifndef MPLAYER_STATS_H
#define MPLAYER_STATS_H

#include <stdint.h>

void stats_init(void);
void stats_exit(void);

/// CPU usage model
enum CpuUsageType {
    CPU_USAGE_QUANTUM = 1, ///< CPU usage since the last call to cpu_get_usage()
    CPU_USAGE_AVERAGE      ///< CPU usage average'd since program start
};

/// Get CPU frequency
unsigned int get_cpu_frequency(void);

/// Get CPU usage in percent
float get_cpu_usage(enum CpuUsageType type);

#endif /* MPLAYER_STATS_H */
/*
 * VA API output module
 *
 * Copyright (C) 2008-2009 Splitted-Desktop Systems
 *
 * This file is part of MPlayer.
 *
 * MPlayer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * MPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
#include "mp_msg.h"
#include "help_mp.h"
#include "subopt-helper.h"
#include "video_out.h"
#include "video_out_internal.h"
#include "fastmemcpy.h"
#include "sub/sub.h"
#include "sub/eosd.h"
#include "x11_common.h"
#include "libavutil/common.h"
#include "libavcodec/vaapi.h"
#include "gui/interface.h"
#include "stats.h"
#include <stdarg.h>

#if CONFIG_GL
#include "gl_common.h"
#include <GL/glu.h>
#include <GL/glx.h>
#endif

#include <assert.h>
#include <strings.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <va/va_x11.h>
#if CONFIG_VAAPI_GLX
#include <va/va_glx.h>
#endif

#if CONFIG_XRENDER
#include <X11/extensions/Xrender.h>
#endif

/* Compatibility glue with upstream libva */
#ifndef VA_SDS_VERSION
#define VA_SDS_VERSION          0
#endif

/* Compatibility glue with VA-API >= 0.30 */
#ifndef VA_INVALID_ID
#define VA_INVALID_ID           0xffffffff
#endif
#ifndef VA_FOURCC
#define VA_FOURCC(ch0, ch1, ch2, ch3)           \
    ((uint32_t)(uint8_t)(ch0) |                 \
     ((uint32_t)(uint8_t)(ch1) << 8) |          \
     ((uint32_t)(uint8_t)(ch2) << 16) |         \
     ((uint32_t)(uint8_t)(ch3) << 24 ))
#endif
#if defined VA_SRC_BT601 && defined VA_SRC_BT709
# define USE_VAAPI_COLORSPACE 1
#else
# define USE_VAAPI_COLORSPACE 0
#endif

/* Defined to 1 if VA/GLX 'bind' API is available */
#define USE_VAAPI_GLX_BIND                                \
    (VA_MAJOR_VERSION == 0 &&                             \
     ((VA_MINOR_VERSION == 30 &&                          \
       VA_MICRO_VERSION == 4 && VA_SDS_VERSION >= 5) ||   \
      (VA_MINOR_VERSION == 31 &&                          \
       VA_MICRO_VERSION == 0 && VA_SDS_VERSION >= 1 && VA_SDS_VERSION < 5)))

/* Compatibility glue with VA-API >= 0.31 */
#if defined VA_CHECK_VERSION
#if VA_CHECK_VERSION(0,31,0)
#define vaPutImage2             vaPutImage
#define vaAssociateSubpicture2  vaAssociateSubpicture
#endif
#endif

/* Compatibility glue with VA-API >= 0.31.1 */
#ifndef VA_SRC_SMPTE_240
#define VA_SRC_SMPTE_240        0x00000040
#endif
#if defined VA_FILTER_SCALING_MASK
# define USE_VAAPI_SCALING 1
#else
# define USE_VAAPI_SCALING 0
#endif

/* Compatibility glue with VA-API >= 0.34 */
#if VA_CHECK_VERSION(0,34,0)
#include <va/va_compat.h>
#endif

static vo_info_t info = {
    "VA API with X11",
    "vaapi",
    "Gwenole Beauchesne <gbeauchesne@xxxxxxxxxxxxxxxxxxxx>",
    ""
};

const LIBVO_EXTERN(vaapi)

/* Numbers of video surfaces */
#define MAX_OUTPUT_SURFACES       2 /* Maintain synchronisation points in flip_page() */
#define MAX_VIDEO_SURFACES       21 /* Maintain free surfaces in a queue (use least-recently-used) */
#define NUM_VIDEO_SURFACES_MPEG2  3 /* 1 decode frame, up to  2 references */
#define NUM_VIDEO_SURFACES_MPEG4  3 /* 1 decode frame, up to  2 references */
#define NUM_VIDEO_SURFACES_H264  21 /* 1 decode frame, up to 20 references */
#define NUM_VIDEO_SURFACES_VC1    3 /* 1 decode frame, up to  2 references */

static void ensure_osd(void);
static int reset_xrender_specific(void);

typedef void (*draw_alpha_func)(int x0, int y0, int w, int h,
                                unsigned char *src, unsigned char *srca,
                                int stride);

typedef void (*eosd_draw_alpha_func)(unsigned char *src,
                                     int src_w, int src_h, int src_stride,
                                     int dst_x, int dst_y,
                                     uint32_t color);

struct vaapi_surface {
    VASurfaceID id;
    VAImage     image;
    int         is_bound; /* Flag: image bound to the surface? */
};

struct vaapi_equalizer {
    VADisplayAttribute brightness;
    VADisplayAttribute contrast;
    VADisplayAttribute hue;
    VADisplayAttribute saturation;
};

static int                      g_is_visible;
static int                      g_is_paused;
static uint32_t                 g_image_width;
static uint32_t                 g_image_height;
static uint32_t                 g_image_format;
static uint32_t                 g_image_fields;
static Pixmap                   g_image_pixmap;
static struct vo_rect           g_output_rect;
static struct vaapi_surface    *g_output_surfaces[MAX_OUTPUT_SURFACES];
static unsigned int             g_output_surface;
static int                      g_deint;
static int                      g_deint_type;
static int                      g_colorspace;
static unsigned int             g_scaling;

static int                      gl_enabled;
static int                      gl_use_tfp;
#if CONFIG_GL
static MPGLContext              gl_context;
static int                      gl_binding;
static int                      gl_reflect;
static int                      gl_finish;
static GLuint                   gl_texture;
static GLuint                   gl_font_base;
static Pixmap                   gl_pixmap;
static int                      gl_visual_attr[] = {
    GLX_RGBA,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    GLX_DOUBLEBUFFER,
    GL_NONE
};
#endif

#if CONFIG_VAAPI_GLX
static void                    *gl_surface;
#endif

static int                      xr_enabled;
#if CONFIG_XRENDER
static Picture                  xr_video_picture;
static Picture                  xr_window_picture;
#endif

/*static*/ struct vaapi_context    *va_context; // HACK, fixme [R]
static VAProfile               *va_profiles;
static int                      va_num_profiles;
static VAEntrypoint            *va_entrypoints;
static int                      va_num_entrypoints;
static VASurfaceID             *va_surface_ids;
static int                      va_num_surfaces;
static struct vaapi_surface   **va_free_surfaces;
static int                      va_free_surfaces_head_index;
static int                      va_free_surfaces_tail_index;
static VAImageFormat           *va_image_formats;
static int                      va_num_image_formats;
static VAImageFormat           *va_subpic_formats;
static unsigned int            *va_subpic_flags;
static int                      va_num_subpic_formats;
static VAImage                  va_osd_image;
static uint8_t                 *va_osd_image_data;
static VASubpictureID           va_osd_subpicture;
static int                      va_osd_associated;
static draw_alpha_func          va_osd_draw_alpha;
static uint8_t                 *va_osd_palette;
static struct vaapi_equalizer   va_equalizer;
static VAImage                  va_eosd_image;
static uint8_t                 *va_eosd_image_data;
static VASubpictureID           va_eosd_subpicture;
static int                      va_eosd_associated;
static eosd_draw_alpha_func     va_eosd_draw_alpha;

///< Flag: direct surface mapping: use mpi->number to select free VA surface?
static int                      va_dm;

///< Flag: gather run-time statistics (CPU usage, frequency)
static int                      cpu_stats;
static unsigned int             cpu_frequency;
static float                    cpu_usage;

// X error trap
static int x11_error_code = 0;
static int (*old_error_handler)(Display *, XErrorEvent *);

static int error_handler(Display *dpy, XErrorEvent *error)
{
    x11_error_code = error->error_code;
    return 0;
}

static void x11_trap_errors(void)
{
    x11_error_code    = 0;
    old_error_handler = XSetErrorHandler(error_handler);
}

static int x11_untrap_errors(void)
{
    XSetErrorHandler(old_error_handler);
    return x11_error_code;
}

static int check_status(VAStatus status, const char *msg)
{
    if (status != VA_STATUS_SUCCESS) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] %s: %s\n", msg, vaErrorStr(status));
        return 0;
    }
    return 1;
}

static const char *string_of_VAImageFormat(VAImageFormat *imgfmt)
{
    static char str[5];
    str[0] = imgfmt->fourcc;
    str[1] = imgfmt->fourcc >> 8;
    str[2] = imgfmt->fourcc >> 16;
    str[3] = imgfmt->fourcc >> 24;
    str[4] = '\0';
    return str;
}

static const char *string_of_VAProfile(VAProfile profile)
{
    switch (profile) {
#define PROFILE(profile) \
        case VAProfile##profile: return "VAProfile" #profile
        PROFILE(MPEG2Simple);
        PROFILE(MPEG2Main);
        PROFILE(MPEG4Simple);
        PROFILE(MPEG4AdvancedSimple);
        PROFILE(MPEG4Main);
#if VA_CHECK_VERSION(0,32,0)
        PROFILE(JPEGBaseline);
        PROFILE(H263Baseline);
        PROFILE(H264ConstrainedBaseline);
#endif
        PROFILE(H264Baseline);
        PROFILE(H264Main);
        PROFILE(H264High);
        PROFILE(VC1Simple);
        PROFILE(VC1Main);
        PROFILE(VC1Advanced);
#undef PROFILE
    default: break;
    }
    return "<unknown>";
}

static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
{
    switch (entrypoint) {
#define ENTRYPOINT(entrypoint) \
        case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
        ENTRYPOINT(VLD);
        ENTRYPOINT(IZZ);
        ENTRYPOINT(IDCT);
        ENTRYPOINT(MoComp);
        ENTRYPOINT(Deblocking);
#if VA_CHECK_VERSION(0,32,0)
        ENTRYPOINT(EncSlice);
        ENTRYPOINT(EncPicture);
#endif
#if VA_CHECK_VERSION(0,34,0)
        ENTRYPOINT(VideoProc);
#endif
#undef ENTRYPOINT
    default: break;
    }
    return "<unknown>";
}

static int has_profile(VAProfile profile)
{
    if (va_profiles && va_num_profiles > 0) {
        int i;
        for (i = 0; i < va_num_profiles; i++) {
            if (va_profiles[i] == profile)
                return 1;
        }
    }
    return 0;
}

static int VAProfile_from_imgfmt(uint32_t format)
{
    static const int mpeg2_profiles[] =
        { VAProfileMPEG2Main, VAProfileMPEG2Simple, -1 };
    static const int mpeg4_profiles[] =
        { VAProfileMPEG4Main, VAProfileMPEG4AdvancedSimple, VAProfileMPEG4Simple, -1 };
    static const int h264_profiles[] =
        { VAProfileH264High, VAProfileH264Main, VAProfileH264Baseline, -1 };
    static const int wmv3_profiles[] =
        { VAProfileVC1Main, VAProfileVC1Simple, -1 };
    static const int vc1_profiles[] =
        { VAProfileVC1Advanced, -1 };

    const int *profiles = NULL;
    switch (IMGFMT_VAAPI_CODEC(format)) {
    case IMGFMT_VAAPI_CODEC_MPEG2:
        profiles = mpeg2_profiles;
        break;
    case IMGFMT_VAAPI_CODEC_MPEG4:
        profiles = mpeg4_profiles;
        break;
    case IMGFMT_VAAPI_CODEC_H264:
        profiles = h264_profiles;
        break;
    case IMGFMT_VAAPI_CODEC_VC1:
        switch (format) {
        case IMGFMT_VAAPI_WMV3:
            profiles = wmv3_profiles;
            break;
        case IMGFMT_VAAPI_VC1:
            profiles = vc1_profiles;
            break;
        }
        break;
    }

    if (profiles) {
        for (int i = 0; profiles[i] != -1; i++) {
            if (has_profile(profiles[i]))
                return profiles[i];
        }
    }
    return -1;
}

static int has_entrypoint(VAEntrypoint entrypoint)
{
    if (va_entrypoints && va_num_entrypoints > 0) {
        int i;
        for (i = 0; i < va_num_entrypoints; i++) {
            if (va_entrypoints[i] == entrypoint)
                return 1;
        }
    }
    return 0;
}

static int VAEntrypoint_from_imgfmt(uint32_t format)
{
    int entrypoint = 0;
    switch (format) {
    case IMGFMT_VAAPI_MPEG2:
    case IMGFMT_VAAPI_MPEG4:
    case IMGFMT_VAAPI_H263:
    case IMGFMT_VAAPI_H264:
    case IMGFMT_VAAPI_WMV3:
    case IMGFMT_VAAPI_VC1:
        entrypoint = VAEntrypointVLD;
        break;
    case IMGFMT_VAAPI_MPEG2_IDCT:
        entrypoint = VAEntrypointIDCT;
        break;
    case IMGFMT_VAAPI_MPEG2_MOCO:
        entrypoint = VAEntrypointMoComp;
        break;
    }

    if (entrypoint)
        return has_entrypoint(entrypoint);

    return -1;
}

static VAImageFormat *find_image_format(uint32_t fourcc)
{
    if (va_image_formats && va_num_image_formats > 0) {
        int i;
        for (i = 0; i < va_num_image_formats; i++) {
            if (va_image_formats[i].fourcc == fourcc)
                return &va_image_formats[i];
        }
    }
    return NULL;
}

static VAImageFormat *VAImageFormat_from_imgfmt(uint32_t format)
{
    uint32_t fourcc = 0;

    switch (format) {
    case IMGFMT_NV12: fourcc = VA_FOURCC('N','V','1','2'); break;
    case IMGFMT_YV12: fourcc = VA_FOURCC('Y','V','1','2'); break;
    case IMGFMT_I420: fourcc = VA_FOURCC('I','4','2','0'); break;
    case IMGFMT_IYUV: fourcc = VA_FOURCC('I','Y','U','V'); break;
    }

    if (fourcc)
        return find_image_format(fourcc);

    return NULL;
}

static struct vaapi_surface *alloc_vaapi_surface(unsigned int width,
                                                 unsigned int height,
                                                 unsigned int format)
{
    struct vaapi_surface *surface = NULL;
    struct vaapi_surface **surfaces;
    VASurfaceID *surface_ids;
    VAStatus status;

    surface = calloc(1, sizeof(*surface));
    if (!surface)
        goto error;

    surfaces = realloc(va_free_surfaces,
                       (1 + va_num_surfaces) * sizeof(surfaces[0]));
    if (!surfaces)
        goto error;

    surface_ids = realloc(va_surface_ids,
                          (1 + va_num_surfaces) * sizeof(surface_ids[0]));
    if (!surface_ids)
        goto error;

    status = vaCreateSurfaces(va_context->display, width, height, format,
                              1, &surface->id);
    if (!check_status(status, "vaCreateSurfaces()"))
        goto error;

    va_surface_ids                    = surface_ids;
    va_surface_ids[va_num_surfaces]   = surface->id;
    va_free_surfaces                  = surfaces;
    va_free_surfaces[va_num_surfaces] = surface;
    surface->image.image_id           = VA_INVALID_ID;
    surface->image.buf                = VA_INVALID_ID;
    ++va_num_surfaces;
    return surface;
error:
    free(surface);
    return NULL;
}

static void resize(void)
{
    struct vo_rect src;

    calc_src_dst_rects(g_image_width, g_image_height,
                       &src, &g_output_rect, NULL, NULL);

    ensure_osd();

    vo_x11_clearwindow(mDisplay, vo_window);

#if CONFIG_GL
#define FOVY     60.0f
#define ASPECT   1.0f
#define Z_NEAR   0.1f
#define Z_FAR    100.0f
#define Z_CAMERA 0.869f

    if (gl_enabled) {
        glViewport(0, 0, vo_dwidth, vo_dheight);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOVY, ASPECT, Z_NEAR, Z_FAR);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(-0.5f, -0.5f, -Z_CAMERA);
        glScalef(1.0f / (GLfloat)vo_dwidth,
                 -1.0f / (GLfloat)vo_dheight,
                 1.0f / (GLfloat)vo_dwidth);
        glTranslatef(0.0f, -1.0f * (GLfloat)vo_dheight, 0.0f);
    }
#endif

#if CONFIG_XRENDER
    if (xr_enabled)
        reset_xrender_specific();
#endif

    if (g_is_visible)
        flip_page();
}

#if CONFIG_GL
static int gl_build_font(void)
{
    XFontStruct *fi;

    gl_font_base = glGenLists(96);

    fi = XLoadQueryFont(mDisplay, "-adobe-helvetica-medium-r-normal--16-*-*-*-p-*-iso8859-1" );
    if (!fi) {
        fi = XLoadQueryFont(mDisplay, "fixed");
        if (!fi)
            return -1;
    }

    glXUseXFont(fi->fid, 32, 96, gl_font_base);
    XFreeFont(mDisplay, fi);
    return 0;
}

static void gl_printf(const char *format, ...)
{
    va_list args;
    char *text;
    int textlen;

    va_start(args, format);
    textlen = vsnprintf(NULL, 0, format, args);
    va_end(args);

    text = malloc(textlen + 1);
    if (!text)
        return;

    va_start(args, format);
    vsprintf(text, format, args);
    va_end(args);

    glPushAttrib(GL_LIST_BIT);
    glListBase(gl_font_base - 32);
    glCallLists(textlen, GL_UNSIGNED_BYTE, text);
    glPopAttrib();
    free(text);
}

static void gl_draw_rectangle(int x, int y, int w, int h, unsigned int rgba)
{
    glColor4f((GLfloat)((rgba >> 24) & 0xff) / 255.0,
              (GLfloat)((rgba >> 16) & 0xff) / 255.0,
              (GLfloat)((rgba >> 8) & 0xff) / 255.0,
              (GLfloat)(rgba & 0xff) / 255.0);

    glTranslatef((GLfloat)x, (GLfloat)y, 0.0f);
    glBegin(GL_QUADS);
    {
        glVertex2i(0, 0);
        glVertex2i(w, 0);
        glVertex2i(w, h);
        glVertex2i(0, h);
    }
    glEnd();
}
#endif

#if CONFIG_XRENDER
static int init_xrender(void)
{
    int dummy;

    return XRenderQueryExtension(mDisplay, &dummy, &dummy);
}

static void uninit_xrender(void)
{
}
#endif

static inline unsigned char *get_osd_image_data(int x0, int y0)
{
    return (va_osd_image_data +
            va_osd_image.offsets[0] +
            va_osd_image.pitches[0] * y0 +
            x0 * ((va_osd_image.format.bits_per_pixel + 7) / 8));
}

static void draw_alpha_rgb32(int x0, int y0, int w, int h,
                             unsigned char *src, unsigned char *srca,
                             int stride)
{
    int x, y;
    const unsigned int dststride = va_osd_image.pitches[0];
    unsigned char *dst = get_osd_image_data(x0, y0);

    for (y = 0; y < h; y++, dst += dststride, src += stride, srca += stride)
        for (x = 0; x < w; x++) {
            const unsigned char c = src[x];
            dst[4*x + 0] = c;
            dst[4*x + 1] = c;
            dst[4*x + 2] = c;
            dst[4*x + 3] = -srca[x];
        }
}

static void draw_alpha_IA44(int x0, int y0, int w, int h,
                            unsigned char *src, unsigned char *srca,
                            int stride)
{
    int x, y;
    const unsigned int dststride = va_osd_image.pitches[0];
    unsigned char *dst = get_osd_image_data(x0, y0);

    for (y = 0; y < h; y++, dst += dststride)
        for (x = 0; x < w; x++)
            dst[x] = (src[y*stride + x] >> 4) | (-srca[y*stride + x] & 0xf0);
}

static void draw_alpha_AI44(int x0, int y0, int w, int h,
                            unsigned char *src, unsigned char *srca,
                            int stride)
{
    int x, y;
    const unsigned int dststride = va_osd_image.pitches[0];
    unsigned char *dst = get_osd_image_data(x0, y0);

    for (y = 0; y < h; y++, dst += dststride)
        for (x = 0; x < w; x++)
            dst[x] = (src[y*stride + x] & 0xf0) | (-srca[y*stride + x] >> 4);
}

static void draw_alpha_IA88(int x0, int y0, int w, int h,
                            unsigned char *src, unsigned char *srca,
                            int stride)
{
    int x, y;
    const unsigned int dststride = va_osd_image.pitches[0];
    unsigned char *dst = get_osd_image_data(x0, y0);

    for (y = 0; y < h; y++, dst += dststride)
        for (x = 0; x < w; x++) {
            dst[2*x + 0] =  src [y*stride + x];
            dst[2*x + 1] = -srca[y*stride + x];
        }
}

static void draw_alpha_AI88(int x0, int y0, int w, int h,
                            unsigned char *src, unsigned char *srca,
                            int stride)
{
    int x, y;
    const unsigned int dststride = va_osd_image.pitches[0];
    unsigned char *dst = get_osd_image_data(x0, y0);

    for (y = 0; y < h; y++, dst += dststride)
        for (x = 0; x < w; x++) {
            dst[2*x + 0] = -srca[y*stride + x];
            dst[2*x + 1] =  src [y*stride + x];
        }
}

///< List of subpicture formats in preferred order
static const struct {
    uint32_t format;
    draw_alpha_func draw_alpha;
}
va_osd_info[] = {
    { VA_FOURCC('I','A','4','4'), draw_alpha_IA44  },
    { VA_FOURCC('A','I','4','4'), draw_alpha_AI44  },
    { VA_FOURCC('I','A','8','8'), draw_alpha_IA88  },
    { VA_FOURCC('A','I','8','8'), draw_alpha_AI88  },
    { VA_FOURCC('B','G','R','A'), draw_alpha_rgb32 },
    { VA_FOURCC('R','G','B','A'), draw_alpha_rgb32 },
    { 0, NULL }
};

static uint8_t *gen_osd_palette(const VAImage *image)
{
    uint8_t *palette;
    int i, is_rgb;
    int r_idx = -1, g_idx = -1, b_idx = -1;
    int y_idx = -1, u_idx = -1, v_idx = -1;
    int i_idx = -1, a_idx = -1;

    if (image->num_palette_entries < 1)
        return NULL;

    palette = malloc(image->num_palette_entries * image->entry_bytes);
    if (!palette)
        return NULL;

    for (i = 0; i < image->entry_bytes; i++) {
        switch (image->component_order[i]) {
        case 'R': r_idx = i; is_rgb = 1; break;
        case 'G': g_idx = i; is_rgb = 1; break;
        case 'B': b_idx = i; is_rgb = 1; break;
        case 'Y': y_idx = i; is_rgb = 0; break;
        case 'U': u_idx = i; is_rgb = 0; break;
        case 'V': v_idx = i; is_rgb = 0; break;
        case 'I': i_idx = i; break;
        case 'A': a_idx = i; break;
        }
    }

    if (r_idx != -1 && g_idx != -1 && b_idx != -1) {      /* RGB format */
        for (i = 0; i < image->num_palette_entries; i++) {
            const int n = i * image->entry_bytes;
            palette[n + r_idx] = i * 0xff / (image->num_palette_entries - 1);
            palette[n + g_idx] = i * 0xff / (image->num_palette_entries - 1);
            palette[n + b_idx] = i * 0xff / (image->num_palette_entries - 1);
        }
    }
    else if (y_idx != -1 && u_idx != -1 && v_idx != -1) { /* YUV format */
        for (i = 0; i < image->num_palette_entries; i++) {
            const int n = i * image->entry_bytes;
            palette[n + y_idx] = i * 0xff / (image->num_palette_entries - 1);
            palette[n + u_idx] = 0x80;
            palette[n + v_idx] = 0x80;
        }
    }
    else if (i_idx != -1 && a_idx != -1) {/* AYUV format (GMA500 "psb" bug) */
        for (i = 0; i < image->num_palette_entries; i++) {
            const int n = i * image->entry_bytes;
            palette[n + 0] = 0x80;
            palette[n + 1] = 0x80;
            palette[n + 2] = 16 + i * 220 / (image->num_palette_entries - 1);
            palette[n + 3] = 0;
        }
    }
    else {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not set up subpicture palette\n");
        free(palette);
        palette = NULL;
    }
    return palette;
}

static void disable_osd(void)
{
    if (!va_osd_associated)
        return;

    vaDeassociateSubpicture(va_context->display,
                            va_osd_subpicture,
                            va_surface_ids, va_num_surfaces);

    va_osd_associated = 0;
}

static int enable_osd(void)
{
    VAStatus status;

    disable_osd();

    status = vaAssociateSubpicture2(va_context->display,
                                    va_osd_subpicture,
                                    va_surface_ids, va_num_surfaces,
                                    0, 0,
                                    va_osd_image.width, va_osd_image.height,
                                    0, 0,
                                    g_image_width, g_image_height,
                                    0);
    if (!check_status(status, "vaAssociateSubpicture()"))
        return -1;

    va_osd_associated = 1;
    return 0;
}

static void destroy_osd(void)
{
    disable_osd();

    if (va_osd_subpicture != VA_INVALID_ID) {
        vaDestroySubpicture(va_context->display, va_osd_subpicture);
        va_osd_subpicture = VA_INVALID_ID;
    }

    if (va_osd_image.image_id != VA_INVALID_ID) {
        vaDestroyImage(va_context->display, va_osd_image.image_id);
        va_osd_image.image_id = VA_INVALID_ID;
        va_osd_image.width    = 0;
        va_osd_image.height   = 0;
    }
}

static void create_osd(void)
{
    VAStatus status;
    int i, j;

    for (i = 0; va_osd_info[i].format; i++) {
        for (j = 0; j < va_num_subpic_formats; j++)
            if (va_subpic_formats[j].fourcc == va_osd_info[i].format)
                break;
        if (j < va_num_subpic_formats &&
            vaCreateImage(va_context->display, &va_subpic_formats[j],
                          g_output_rect.width, g_output_rect.height,
                          &va_osd_image) == VA_STATUS_SUCCESS) {
            va_osd_palette = gen_osd_palette(&va_osd_image);
            if (((!va_osd_image.num_palette_entries) ^ (!va_osd_palette)) == 0)
                break;
            vaDestroyImage(va_context->display, va_osd_image.image_id);
            va_osd_image.image_id = VA_INVALID_ID;
        }
    }

    if (va_osd_info[i].format &&
        vaCreateSubpicture(va_context->display, va_osd_image.image_id,
                           &va_osd_subpicture) == VA_STATUS_SUCCESS) {
        va_osd_draw_alpha = va_osd_info[i].draw_alpha;
        if (va_osd_palette) {
            status = vaSetImagePalette(va_context->display,
                                       va_osd_image.image_id, va_osd_palette);
            check_status(status, "vaSetImagePalette()");
        }
        mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for OSD\n",
               string_of_VAImageFormat(&va_osd_image.format));
    }
}

static void ensure_osd(void)
{
    if (g_output_rect.width  == va_osd_image.width &&
        g_output_rect.height == va_osd_image.height)
        return;

    destroy_osd();
    create_osd();
}

static inline unsigned char *get_eosd_image_data(int x0, int y0)
{
    return (va_eosd_image_data +
            va_eosd_image.offsets[0] +
            va_eosd_image.pitches[0] * y0 +
            x0 * ((va_eosd_image.format.bits_per_pixel + 7) / 8));
}

static void eosd_draw_alpha_bgra(unsigned char *src,
                                 int src_w, int src_h, int src_stride,
                                 int dst_x, int dst_y,
                                 uint32_t color)
{
    int x, y;
    const unsigned int dst_stride = va_eosd_image.pitches[0];
    unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
    const unsigned int r = (color >> 24) & 0xff;
    const unsigned int g = (color >> 16) & 0xff;
    const unsigned int b = (color >>  8) & 0xff;
    const unsigned int a = 0xff - (color & 0xff);

    for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
        for (x = 0; x < src_w; x++) {
            const unsigned int v = src[x];
            dst[4*x + 0] = (b * v + dst[4*x + 0] * (0xff - v)) / 255;
            dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
            dst[4*x + 2] = (r * v + dst[4*x + 2] * (0xff - v)) / 255;
            dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
        }
}

static void eosd_draw_alpha_rgba(unsigned char *src,
                                 int src_w, int src_h, int src_stride,
                                 int dst_x, int dst_y,
                                 uint32_t color)
{
    int x, y;
    const unsigned int dst_stride = va_eosd_image.pitches[0];
    unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
    const unsigned int r = (color >> 24) & 0xff;
    const unsigned int g = (color >> 16) & 0xff;
    const unsigned int b = (color >>  8) & 0xff;
    const unsigned int a = 0xff - (color & 0xff);

    for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
        for (x = 0; x < src_w; x++) {
            const unsigned int v = src[x];
            dst[4*x + 0] = (r * v + dst[4*x + 0] * (0xff - v)) / 255;
            dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
            dst[4*x + 2] = (b * v + dst[4*x + 2] * (0xff - v)) / 255;
            dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
        }
}

static void disable_eosd(void)
{
    if (!va_eosd_associated)
        return;

    vaDeassociateSubpicture(va_context->display,
                            va_eosd_subpicture,
                            va_surface_ids, va_num_surfaces);

    va_eosd_associated = 0;
}

static int enable_eosd(void)
{
    VAStatus status;

    if (va_eosd_associated)
        return 0;

    status = vaAssociateSubpicture2(va_context->display,
                                    va_eosd_subpicture,
                                    va_surface_ids, va_num_surfaces,
                                    0, 0, g_image_width, g_image_height,
                                    0, 0, g_image_width, g_image_height,
                                    0);
    if (!check_status(status, "vaAssociateSubpicture()"))
        return -1;

    va_eosd_associated = 1;
    return 0;
}

///< List of subpicture formats in preferred order
static const struct {
    uint32_t format;
    eosd_draw_alpha_func draw_alpha;
}
va_eosd_info[] = {
    { VA_FOURCC('B','G','R','A'), eosd_draw_alpha_bgra },
    { VA_FOURCC('R','G','B','A'), eosd_draw_alpha_rgba },
    { 0, NULL }
};

static int is_direct_mapping_init(void)
{
    VADisplayAttribute attr;
    VAStatus status;

    if (va_dm < 2)
        return va_dm;

#if VA_CHECK_VERSION(0,34,0)
    attr.type  = VADisplayAttribRenderMode;
    attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;

    status = vaGetDisplayAttributes(va_context->display, &attr, 1);
    if (status == VA_STATUS_SUCCESS)
        return !(attr.value & (VA_RENDER_MODE_LOCAL_OVERLAY|
                               VA_RENDER_MODE_EXTERNAL_OVERLAY));
#else
    /* If the driver doesn't make a copy of the VA surface for
       display, then we have to retain it until it's no longer the
       visible surface. In other words, if the driver is using
       DirectSurface mode, we don't want to decode the new surface
       into the previous one that was used for display. */
    attr.type  = VADisplayAttribDirectSurface;
    attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;

    status = vaGetDisplayAttributes(va_context->display, &attr, 1);
    if (status == VA_STATUS_SUCCESS)
        return !attr.value;
#endif
    return 0;
}

static inline int is_direct_mapping(void)
{
    static int dm = -1;
    if (dm < 0) {
        dm = is_direct_mapping_init();
        if (dm)
            mp_msg(MSGT_VO, MSGL_INFO,
                   "[vo_vaapi] Using 1:1 VA surface mapping\n");
    }
    return dm;
}

static int int_012(int *n)
{
    return *n >= 0 && *n <= 2;
}

#if USE_VAAPI_SCALING
static strarg_t g_scaling_arg = { 0, NULL };

static int test_scaling_arg(void *arg)
{
    strarg_t * const strarg = arg;

    return (strargcmp(strarg, "default") == 0 ||
            strargcmp(strarg, "fast") == 0 ||
            strargcmp(strarg, "hq") == 0);
}

static void setup_scaling(const char *scaling)
{
    if (strcmp(scaling, "default") == 0)
        g_scaling = VA_FILTER_SCALING_DEFAULT;
    else if (strcmp(scaling, "fast") == 0)
        g_scaling = VA_FILTER_SCALING_FAST;
    else if (strcmp(scaling, "hq") == 0)
        g_scaling = VA_FILTER_SCALING_HQ;
    else if (strcmp(scaling, "nla") == 0)
        g_scaling = VA_FILTER_SCALING_NL_ANAMORPHIC;
}
#endif

static const opt_t subopts[] = {
    { "dm",          OPT_ARG_INT,  &va_dm,        (opt_test_f)int_012 },
    { "stats",       OPT_ARG_BOOL, &cpu_stats,    NULL },
    { "deint",       OPT_ARG_INT,  &g_deint,      (opt_test_f)int_012 },
#if USE_VAAPI_COLORSPACE
    { "colorspace",  OPT_ARG_INT,  &g_colorspace, (opt_test_f)int_012 },
#endif
#if USE_VAAPI_SCALING
    { "scaling",     OPT_ARG_STR,  &g_scaling_arg, test_scaling_arg },
#endif
#if CONFIG_GL
    { "gl",          OPT_ARG_BOOL, &gl_enabled,   NULL },
    { "glfinish",    OPT_ARG_BOOL, &gl_finish,    NULL },
#if USE_VAAPI_GLX_BIND
    { "bind",        OPT_ARG_BOOL, &gl_binding,   NULL },
#endif
    { "reflect",     OPT_ARG_BOOL, &gl_reflect,   NULL },
    { "tfp",         OPT_ARG_BOOL, &gl_use_tfp,   NULL },
#endif
#if CONFIG_XRENDER
    { "xrender",     OPT_ARG_BOOL, &xr_enabled,   NULL },
#endif
    { NULL, }
};

static int preinit(const char *arg)
{
    VADisplayAttribute *display_attrs;
    VAStatus status;
    int va_major_version, va_minor_version;
    int i, max_image_formats, max_subpic_formats, max_profiles;
    int num_display_attrs, max_display_attrs;

    va_dm = 2;
    g_deint = 0;
    g_deint_type = 2;
    g_colorspace = 1;
    g_scaling = 0;
    if (subopt_parse(arg, subopts) != 0) {
        mp_msg(MSGT_VO, MSGL_FATAL,
               "\n-vo vaapi command line help:\n"
               "Example: mplayer -vo vaapi:gl\n"
               "\nOptions:\n"
               "  dm\n"
               "    0: use least-recently-used VA surface\n"
               "    1: identify VA surface with MPI index\n"
               "    2: auto-detect use of direct surface mapping (default)\n"
               "  deint (all modes > 0 respect -field-dominance)\n"
               "    0: no deinterlacing (default)\n"
               "    1: only show first field\n"
               "    2: bob deinterlacing\n"
#if USE_VAAPI_COLORSPACE
               "  colorspace\n"
               "    0: guess based on video resolution\n"
               "    1: ITU-R BT.601 (default)\n"
               "    2: ITU-R BT.709\n"
               "    3: SMPTE-240M\n"
#endif
#if USE_VAAPI_SCALING
               "  scaling\n"
               "    default: use implementation default (default)\n"
               "    fast:    use fast scaling, but possibly with less quality\n"
               "    hq:      use high-quality scaling, but possibly slower\n"
               "    nla:     use non-linear anamorphic scaling\n"
#endif
#if CONFIG_GL
               "  gl\n"
               "    Enable OpenGL rendering\n"
               "  glfinish\n"
               "    Call glFinish() before swapping buffers\n"
               "  tfp\n"
               "    Use GLX texture-from-pixmap instead of VA/GLX extensions\n"
#if USE_VAAPI_GLX_BIND
               "  bind\n"
               "    Use VA surface binding instead of copy\n"
#endif
               "  reflect\n"
               "    Enable OpenGL reflection effects\n"
#endif
#if CONFIG_XRENDER
               "  xrender\n"
               "    Enable Xrender rendering, thus vaPutSurface() to a Pixmap\n"
#endif
               "\n" );
        return -1;
    }
    if (gl_enabled && xr_enabled) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] User requested both Xrender and OpenGL rendering\n");
        return -1;
    }
    if (g_deint)
        g_deint_type = g_deint;
#if CONFIG_GL
    if (gl_enabled)
        mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using OpenGL rendering%s\n",
               gl_reflect ? ", with reflection effects" : "");
#endif
#if CONFIG_XRENDER
    if (xr_enabled)
        mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using Xrender rendering\n");
#endif
#if USE_VAAPI_SCALING
    if (g_scaling_arg.str) {
        mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using '%s' scaling\n", g_scaling_arg.str);
        setup_scaling(g_scaling_arg.str);
    }
#endif

    stats_init();

#if CONFIG_GL
    if (gl_enabled && !init_mpglcontext(&gl_context, GLTYPE_X11))
        return -1;
    else
#endif
    if (!vo_init())
        return -1;
#if CONFIG_XRENDER
    if (xr_enabled && !init_xrender())
        return -1;
#endif

    va_context = calloc(1, sizeof(*va_context));
    if (!va_context)
        return -1;

#if CONFIG_VAAPI_GLX
    if (gl_enabled)
        va_context->display = vaGetDisplayGLX(mDisplay);
    else
#endif
        va_context->display = vaGetDisplay(mDisplay);
    if (!va_context->display)
        return -1;
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA display %p\n", va_context->display);

    status = vaInitialize(va_context->display, &va_major_version, &va_minor_version);
    if (!check_status(status, "vaInitialize()"))
        return -1;
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA API version %d.%d\n",
           va_major_version, va_minor_version);

    max_image_formats = vaMaxNumImageFormats(va_context->display);
    va_image_formats = calloc(max_image_formats, sizeof(*va_image_formats));
    if (!va_image_formats)
        return -1;
    status = vaQueryImageFormats(va_context->display, va_image_formats, &va_num_image_formats);
    if (!check_status(status, "vaQueryImageFormats()"))
        return -1;
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d image formats available\n",
           va_num_image_formats);
    for (i = 0; i < va_num_image_formats; i++)
        mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAImageFormat(&va_image_formats[i]));

    max_subpic_formats = vaMaxNumSubpictureFormats(va_context->display);
    va_subpic_formats = calloc(max_subpic_formats, sizeof(*va_subpic_formats));
    if (!va_subpic_formats)
        return -1;
    va_subpic_flags = calloc(max_subpic_formats, sizeof(*va_subpic_flags));
    if (!va_subpic_flags)
        return -1;
    status = vaQuerySubpictureFormats(va_context->display, va_subpic_formats, va_subpic_flags, &va_num_subpic_formats);
    if (!check_status(status, "vaQuerySubpictureFormats()"))
        va_num_subpic_formats = 0; /* XXX: don't error out for IEGD */
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d subpicture formats available\n",
           va_num_subpic_formats);
    for (i = 0; i < va_num_subpic_formats; i++)
        mp_msg(MSGT_VO, MSGL_DBG2, "  %s, flags 0x%x\n", string_of_VAImageFormat(&va_subpic_formats[i]), va_subpic_flags[i]);

    max_profiles = vaMaxNumProfiles(va_context->display);
    va_profiles = calloc(max_profiles, sizeof(*va_profiles));
    if (!va_profiles)
        return -1;
    status = vaQueryConfigProfiles(va_context->display, va_profiles, &va_num_profiles);
    if (!check_status(status, "vaQueryConfigProfiles()"))
        return -1;
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d profiles available\n",
           va_num_profiles);
    for (i = 0; i < va_num_profiles; i++)
        mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAProfile(va_profiles[i]));

    va_osd_subpicture      = VA_INVALID_ID;
    va_osd_image.image_id  = VA_INVALID_ID;
    va_eosd_subpicture     = VA_INVALID_ID;
    va_eosd_image.image_id = VA_INVALID_ID;

    max_display_attrs = vaMaxNumDisplayAttributes(va_context->display);
    display_attrs = calloc(max_display_attrs, sizeof(*display_attrs));
    if (display_attrs) {
        num_display_attrs = 0;
        status = vaQueryDisplayAttributes(va_context->display,
                                          display_attrs, &num_display_attrs);
        if (check_status(status, "vaQueryDisplayAttributes()")) {
            for (i = 0; i < num_display_attrs; i++) {
                VADisplayAttribute *attr;
                switch (display_attrs[i].type) {
                case VADisplayAttribBrightness:
                    attr = &va_equalizer.brightness;
                    break;
                case VADisplayAttribContrast:
                    attr = &va_equalizer.contrast;
                    break;
                case VADisplayAttribHue:
                    attr = &va_equalizer.hue;
                    break;
                case VADisplayAttribSaturation:
                    attr = &va_equalizer.saturation;
                    break;
                default:
                    attr = NULL;
                    break;
                }
                if (attr)
                    *attr = display_attrs[i];
            }
        }
        free(display_attrs);
    }
    return 0;
}

static void free_video_specific(void)
{
    int i;

#if CONFIG_VAAPI_GLX
    if (gl_surface) {
        VAStatus status;
        status = vaDestroySurfaceGLX(va_context->display, gl_surface);
        check_status(status, "vaDestroySurfaceGLX()");
        gl_surface = NULL;
    }
#endif

    if (va_context && va_context->context_id) {
        vaDestroyContext(va_context->display, va_context->context_id);
        va_context->context_id = 0;
    }

    if (va_free_surfaces) {
        for (i = 0; i < va_num_surfaces; i++) {
            if (!va_free_surfaces[i])
                continue;
            if (va_free_surfaces[i]->image.image_id != VA_INVALID_ID) {
                vaDestroyImage(va_context->display,
                               va_free_surfaces[i]->image.image_id);
                va_free_surfaces[i]->image.image_id = VA_INVALID_ID;
            }
            free(va_free_surfaces[i]);
            va_free_surfaces[i] = NULL;
        }
        free(va_free_surfaces);
        va_free_surfaces = NULL;
        va_free_surfaces_head_index = 0;
        va_free_surfaces_tail_index = 0;
    }

    g_output_surface = 0;
    memset(g_output_surfaces, 0, sizeof(g_output_surfaces));

    if (va_osd_palette) {
        free(va_osd_palette);
        va_osd_palette = NULL;
    }

    disable_eosd();
    disable_osd();

    if (va_eosd_subpicture != VA_INVALID_ID) {
        vaDestroySubpicture(va_context->display, va_eosd_subpicture);
        va_eosd_subpicture = VA_INVALID_ID;
    }

    if (va_eosd_image.image_id != VA_INVALID_ID) {
        vaDestroyImage(va_context->display, va_eosd_image.image_id);
        va_eosd_image.image_id = VA_INVALID_ID;
    }

    destroy_osd();

    if (va_surface_ids) {
        vaDestroySurfaces(va_context->display, va_surface_ids, va_num_surfaces);
        free(va_surface_ids);
        va_surface_ids = NULL;
        va_num_surfaces = 0;
    }

    if (va_context && va_context->config_id) {
        vaDestroyConfig(va_context->display, va_context->config_id);
        va_context->config_id = 0;
    }

    if (va_entrypoints) {
        free(va_entrypoints);
        va_entrypoints = NULL;
    }

#if CONFIG_GL
    if (gl_pixmap) {
        x11_trap_errors();
        mpglXDestroyPixmap(mDisplay, gl_pixmap);
        XSync(mDisplay, False);
        x11_untrap_errors();
        gl_pixmap = None;
    }

    if (g_image_pixmap) {
        XFreePixmap(mDisplay, g_image_pixmap);
        g_image_pixmap = None;
    }

    if (gl_texture) {
        glDeleteTextures(1, &gl_texture);
        gl_texture = GL_NONE;
    }
#endif

#if CONFIG_XRENDER
    if (xr_window_picture) {
        XRenderFreePicture(mDisplay, xr_window_picture);
        xr_window_picture = None;
    }
#endif

    g_is_visible = 0;
}

static void uninit(void)
{
    if (!vo_config_count)
        return;

    free_video_specific();

    if (va_profiles) {
        free(va_profiles);
        va_profiles = NULL;
    }

    if (va_subpic_flags) {
        free(va_subpic_flags);
        va_subpic_flags = NULL;
    }

    if (va_subpic_formats) {
        free(va_subpic_formats);
        va_subpic_formats = NULL;
    }

    if (va_image_formats) {
        free(va_image_formats);
        va_image_formats = NULL;
    }

    if (va_context && va_context->display) {
        vaTerminate(va_context->display);
        va_context->display = NULL;
    }

    if (va_context) {
        free(va_context);
        va_context = NULL;
    }

#ifdef CONFIG_XF86VM
    vo_vm_close();
#endif
#if CONFIG_XRENDER
    if (xr_enabled)
        uninit_xrender();
#endif
#if CONFIG_GL
    if (gl_enabled)
        uninit_mpglcontext(&gl_context);
    else
#endif
    vo_x11_uninit();

    stats_exit();
}

static int config_x11(uint32_t width, uint32_t height,
                      uint32_t display_width, uint32_t display_height,
                      uint32_t flags, char *title)
{
    Colormap cmap;
    XVisualInfo visualInfo;
    XVisualInfo *vi;
    XSetWindowAttributes xswa;
    unsigned long xswa_mask;
    XWindowAttributes wattr;
    int depth;

// GUI part to be fixed, it's changed [R]
#ifdef CONFIG_GUIqqqq
    if (use_gui)
        guiGetEvent(guiSetShVideo, 0);  // the GUI will set up / resize our window
    else
#endif
    {
#ifdef CONFIG_XF86VM
        if (flags & VOFLAG_MODESWITCHING)
            vo_vm_switch();
#endif
        XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &wattr);
        depth = wattr.depth;
        if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
            depth = 24;
        XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &visualInfo);

#if CONFIG_GL
        if (gl_enabled) {
            vi = glXChooseVisual(mDisplay, mScreen, gl_visual_attr);
            if (!vi)
                return -1;
            cmap = XCreateColormap(mDisplay, mRootWin, vi->visual, AllocNone);
            if (cmap == None)
                return -1;
        }
        else
#endif
        {
            vi = &visualInfo;
            XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, vi);
            cmap = CopyFromParent;
        }

        vo_x11_create_vo_window(vi,
                                vo_dx, vo_dy, display_width, display_height,
                                flags, cmap, "vaapi", title);

        if (vi != &visualInfo)
            XFree(vi);

        xswa_mask             = CWBorderPixel | CWBackPixel;
        xswa.border_pixel     = 0;
        xswa.background_pixel = 0;
        XChangeWindowAttributes(mDisplay, vo_window, xswa_mask, &xswa);

#ifdef CONFIG_XF86VM
        if (flags & VOFLAG_MODESWITCHING) {
            /* Grab the mouse pointer in our window */
            if (vo_grabpointer)
                XGrabPointer(mDisplay, vo_window, True, 0,
                             GrabModeAsync, GrabModeAsync,
                             vo_window, None, CurrentTime);
            XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
        }
#endif
    }
    return 0;
}

#if CONFIG_GL
static GLXFBConfig *get_fbconfig_for_depth(int depth)
{
    GLXFBConfig *fbconfigs, *ret = NULL;
    int          n_elements, i, found;
    int          db, stencil, alpha, rgba, value;

    static GLXFBConfig *cached_config = NULL;
    static int          have_cached_config = 0;

    if (have_cached_config)
        return cached_config;

    fbconfigs = glXGetFBConfigs(mDisplay, mScreen, &n_elements);

    db      = SHRT_MAX;
    stencil = SHRT_MAX;
    rgba    = 0;

    found = n_elements;

    for (i = 0; i < n_elements; i++) {
        XVisualInfo *vi;
        int          visual_depth;

        vi = glXGetVisualFromFBConfig(mDisplay, fbconfigs[i]);
        if (!vi)
            continue;

        visual_depth = vi->depth;
        XFree(vi);

        if (visual_depth != depth)
            continue;

        glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_ALPHA_SIZE, &alpha);
        glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_BUFFER_SIZE, &value);
        if (value != depth && (value - alpha) != depth)
            continue;

        value = 0;
        if (depth == 32) {
            glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
                                 GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
            if (value)
                rgba = 1;
        }

        if (!value) {
            if (rgba)
                continue;

            glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
                                 GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
            if (!value)
                continue;
        }

        glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_DOUBLEBUFFER, &value);
        if (value > db)
            continue;
        db = value;

        glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_STENCIL_SIZE, &value);
        if (value > stencil)
            continue;
        stencil = value;

        found = i;
    }

    if (found != n_elements) {
        ret = malloc(sizeof(*ret));
        *ret = fbconfigs[found];
    }

    if (n_elements)
        XFree(fbconfigs);

    have_cached_config = 1;
    cached_config = ret;
    return ret;
}

static int config_tfp(unsigned int width, unsigned int height)
{
    GLXFBConfig *fbconfig;
    int attribs[7], i = 0;
    const int depth = 24;

    if (!mpglXBindTexImage || !mpglXReleaseTexImage) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] No GLX texture-from-pixmap extension available\n");
        return -1;
    }

    if (depth != 24 && depth != 32)
        return -1;

    g_image_pixmap = XCreatePixmap(mDisplay, vo_window, width, height, depth);
    if (!g_image_pixmap) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create X11 pixmap\n");
        return -1;
    }

    fbconfig = get_fbconfig_for_depth(depth);
    if (!fbconfig) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not find an FBConfig for 32-bit pixmap\n");
        return -1;
    }

    attribs[i++] = GLX_TEXTURE_TARGET_EXT;
    attribs[i++] = GLX_TEXTURE_2D_EXT;
    attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
    if (depth == 24)
        attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
    else if (depth == 32)
        attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
    attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
    attribs[i++] = GL_FALSE;
    attribs[i++] = None;

    x11_trap_errors();
    gl_pixmap = mpglXCreatePixmap(mDisplay, *fbconfig, g_image_pixmap, attribs);
    XSync(mDisplay, False);
    if (x11_untrap_errors()) {
        mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create GLX pixmap\n");
        return -1;
    }
    return 0;
}

static int config_glx(unsigned int width, unsigned int height)
{
    if (gl_context.setGlWindow(&gl_context) == SET_WINDOW_FAILED)
        return -1;

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);
    glDrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    /* Create TFP resources */
    if (gl_use_tfp && config_tfp(width, height) == 0)
        mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using GLX texture-from-pixmap extension\n");
    else
        gl_use_tfp = 0;

    /* Create OpenGL texture */
    /* XXX: assume GL_ARB_texture_non_power_of_two is available */
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &gl_texture);
    mpglBindTexture(GL_TEXTURE_2D, gl_texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    if (!gl_use_tfp) {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                     GL_BGRA, GL_UNSIGNED_BYTE, NULL);
    }
    mpglBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    if (gl_build_font() < 0)
        return -1;
    return 0;
}
#endif

#if CONFIG_XRENDER
static XRenderPictFormat *get_xrender_argb32_format(void)
{
    static XRenderPictFormat *pictformat = NULL;
    XRenderPictFormat templ;

    const unsigned long mask =
        PictFormatType      |
        PictFormatDepth     |
        PictFormatRed       |
        PictFormatRedMask   |
        PictFormatGreen     |
        PictFormatGreenMask |
        PictFormatBlue      |
        PictFormatBlueMask  |
        PictFormatAlphaMask;

    if (pictformat)
        return pictformat;

    /* First, look for a 32-bit format which ignores the alpha component */
    templ.depth            = 32;
    templ.type             = PictTypeDirect;
    templ.direct.red       = 16;
    templ.direct.green     = 8;
    templ.direct.blue      = 0;
    templ.direct.redMask   = 0xff;
    templ.direct.greenMask = 0xff;
    templ.direct.blueMask  = 0xff;
    templ.direct.alphaMask = 0;

    pictformat = XRenderFindFormat(mDisplay, mask, &templ, 0);

    if (!pictformat) {
        /* Not all X servers support xRGB32 formats. However, the
         * XRENDER spec says that they must support an ARGB32 format,
         * so we can always return that.
         */
        pictformat = XRenderFindStandardFormat(mDisplay, PictStandardARGB32);
        if (!pictformat)
            mp_msg(MSGT_VO, MSGL_ERR, "XRENDER ARGB32 format not supported\n");
    }
    return pictformat;
}

static int create_xrender_specific(void)
{
    XRenderPictFormat *pictformat;

    if (g_output_rect.width == 0 && g_output_rect.height == 0)
        return 0;

    g_image_pixmap = XCreatePixmap(mDisplay, vo_window, g_output_rect.width,
                                   g_output_rect.height, 32);
    if (!g_image_pixmap) {
        mp_msg(MSGT_VO, MSGL_ERR, "Could not create video pixmap\n");
        return -1;
    }

    pictformat = get_xrender_argb32_format();
    if (!pictformat)
        return -1;
    xr_video_picture = XRenderCreatePicture(mDisplay, g_image_pixmap,
                                            pictformat, 0, NULL);
    if (!xr_video_picture) {
        mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Pixmap\n");
        return -1;
    }
    return 0;
}

static void free_xrender_specific(void)
{
    if (xr_video_picture) {
        XRenderFreePicture(mDisplay, xr_video_picture);
        xr_video_picture = None;
    }

    if (g_image_pixmap) {
        XFreePixmap(mDisplay, g_image_pixmap);
        g_image_pixmap = None;
    }
}

static int reset_xrender_specific(void)
{
    free_xrender_specific();
    return create_xrender_specific();
}

/* XXX: create a Pixmap as large as the display rect */
static int config_xrender(unsigned int width, unsigned int height)
{
    XWindowAttributes wattr;
    XRenderPictFormat *pictformat;

    XGetWindowAttributes(mDisplay, vo_window, &wattr);
    pictformat = XRenderFindVisualFormat(mDisplay, wattr.visual);
    if (!pictformat) {
        mp_msg(MSGT_VO, MSGL_ERR, "XRENDER does not support Window visual\n");
        return -1;
    }

    xr_window_picture = XRenderCreatePicture(mDisplay, vo_window, pictformat,
                                             0, NULL);
    if (!xr_window_picture) {
        mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Window\n");
        return -1;
    }
    return reset_xrender_specific();
}
#endif

static int config_vaapi(uint32_t width, uint32_t height, uint32_t format)
{
    VAConfigAttrib attrib;
    VAStatus status;
    int i, j, profile, entrypoint, max_entrypoints, num_surfaces;

    /* Create video surfaces */
    if (!IMGFMT_IS_VAAPI(format))
        num_surfaces = MAX_OUTPUT_SURFACES;
    else {
        switch (IMGFMT_VAAPI_CODEC(format)) {
        case IMGFMT_VAAPI_CODEC_MPEG2:
            num_surfaces = NUM_VIDEO_SURFACES_MPEG2;
            break;
        case IMGFMT_VAAPI_CODEC_MPEG4:
            num_surfaces = NUM_VIDEO_SURFACES_MPEG4;
            break;
        case IMGFMT_VAAPI_CODEC_H264:
            num_surfaces = NUM_VIDEO_SURFACES_H264;
            break;
        case IMGFMT_VAAPI_CODEC_VC1:
            num_surfaces = NUM_VIDEO_SURFACES_VC1;
            break;
        default:
            num_surfaces = 0;
            break;
        }
        if (num_surfaces == 0)
            return -1;
        if (!is_direct_mapping())
            num_surfaces = FFMIN(2 * num_surfaces, MAX_VIDEO_SURFACES);
    }
    for (i = 0; i < num_surfaces; i++) {
        struct vaapi_surface *surface;
        surface = alloc_vaapi_surface(width, height, VA_RT_FORMAT_YUV420);
        if (!surface)
            return -1;
    }
    assert(va_num_surfaces == num_surfaces);

#if CONFIG_VAAPI_GLX
    /* Create GLX surfaces */
    if (gl_enabled && !gl_use_tfp) {
        status = vaCreateSurfaceGLX(va_context->display,
                                    GL_TEXTURE_2D, gl_texture,
                                    &gl_surface);
        if (!check_status(status, "vaCreateSurfaceGLX()"))
            return -1;
    }
#endif

    /* Create OSD data */
    va_osd_draw_alpha     = NULL;
    va_osd_image.image_id = VA_INVALID_ID;
    va_osd_image.buf      = VA_INVALID_ID;
    va_osd_subpicture     = VA_INVALID_ID;
    ensure_osd();

    /* Create EOSD data */
    va_eosd_draw_alpha     = NULL;
    va_eosd_image.image_id = VA_INVALID_ID;
    va_eosd_image.buf      = VA_INVALID_ID;
    va_eosd_subpicture     = VA_INVALID_ID;
    for (i = 0; va_eosd_info[i].format; i++) {
        for (j = 0; j < va_num_subpic_formats; j++)
            if (va_subpic_formats[j].fourcc == va_eosd_info[i].format)
                break;
        if (j < va_num_subpic_formats &&
            vaCreateImage(va_context->display, &va_subpic_formats[j],
                          width, height, &va_eosd_image) == VA_STATUS_SUCCESS)
            break;
    }
    if (va_eosd_info[i].format &&
        vaCreateSubpicture(va_context->display, va_eosd_image.image_id,
                           &va_eosd_subpicture) == VA_STATUS_SUCCESS) {
        va_eosd_draw_alpha = va_eosd_info[i].draw_alpha;
        mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for EOSD\n",
               string_of_VAImageFormat(&va_eosd_image.format));
    }

    /* Allocate VA images */
    if (!IMGFMT_IS_VAAPI(format)) {
        VAImageFormat *image_format = VAImageFormat_from_imgfmt(format);
        if (!image_format)
            return -1;
        for (i = 0; i < va_num_surfaces; i++) {
            struct vaapi_surface * const s = va_free_surfaces[i];
            s->is_bound = 0;
            status = vaDeriveImage(va_context->display, s->id, &s->image);
            if (status == VA_STATUS_SUCCESS) {
                /* vaDeriveImage() is supported, check format */
                if (s->image.format.fourcc != image_format->fourcc) {
                    vaDestroyImage(va_context->display, s->image.image_id);
                    return -1;
                }
                if (s->image.width == width && s->image.height == height) {
                    s->is_bound = 1;
                    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using vaDeriveImage()\n");
                }
                else {
                    vaDestroyImage(va_context->display, s->image.image_id);
                    status = VA_STATUS_ERROR_OPERATION_FAILED;
                }
                
            }
            if (status != VA_STATUS_SUCCESS) {
                status = vaCreateImage(va_context->display, image_format,
                                       width, height, &s->image);
                if (!check_status(status, "vaCreateImage()"))
                    return -1;
            }
        }
        return 0;
    }

    /* Check profile */
    profile = VAProfile_from_imgfmt(format);
    if (profile < 0)
        return -1;

    /* Check entry-point (only VLD for now) */
    max_entrypoints = vaMaxNumEntrypoints(va_context->display);
    va_entrypoints = calloc(max_entrypoints, sizeof(*va_entrypoints));
    if (!va_entrypoints)
        return -1;

    status = vaQueryConfigEntrypoints(va_context->display, profile,
                                      va_entrypoints, &va_num_entrypoints);
    if (!check_status(status, "vaQueryConfigEntrypoints()"))
        return -1;

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config_vaapi(%s): %d entrypoints available\n",
           string_of_VAProfile(profile), va_num_entrypoints);
    for (i = 0; i < va_num_entrypoints; i++)
        mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAEntrypoint(va_entrypoints[i]));

    entrypoint = VAEntrypoint_from_imgfmt(format);
    if (entrypoint != VAEntrypointVLD)
        return -1;

    /* Check chroma format (only 4:2:0 for now) */
    attrib.type = VAConfigAttribRTFormat;
    status = vaGetConfigAttributes(va_context->display, profile, entrypoint, &attrib, 1);
    if (!check_status(status, "vaGetConfigAttributes()"))
        return -1;
    if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
        return -1;

    /* Create a configuration for the decode pipeline */
    status = vaCreateConfig(va_context->display, profile, entrypoint, &attrib, 1, &va_context->config_id);
    if (!check_status(status, "vaCreateConfig()"))
        return -1;

    /* Create a context for the decode pipeline */
    status = vaCreateContext(va_context->display, va_context->config_id,
                             width, height, VA_PROGRESSIVE,
                             va_surface_ids, va_num_surfaces,
                             &va_context->context_id);
    if (!check_status(status, "vaCreateContext()"))
        return -1;
    return 0;
}

static int config(uint32_t width, uint32_t height,
                  uint32_t display_width, uint32_t display_height,
                  uint32_t flags, char *title, uint32_t format)
{
    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config(): size %dx%d, display size %dx%d, flags %x, title '%s', format %x (%s)\n",
           width, height, display_width, display_height, flags, title, format, vo_format_name(format));

    // Avoid useless reinits, avoid broken first frame [R]
    if (width == g_image_width &&
        height == g_image_height &&
        format == g_image_format)
         return 0;

    free_video_specific();

    if (config_x11(width, height, display_width, display_height, flags, title) < 0)
        return -1;

#if CONFIG_GL
    if (gl_enabled && config_glx(width, height) < 0)
        return -1;
#endif

#if CONFIG_XRENDER
    if (xr_enabled && config_xrender(width, height) < 0)
        return -1;
#endif

    if (config_vaapi(width, height, format) < 0)
        return -1;

    g_is_visible   = 0;
    g_is_paused    = 0;
    g_image_width  = width;
    g_image_height = height;
    g_image_format = format;
    resize();
    return 0;
}

static int query_format(uint32_t format)
{
    const int default_caps = (VFCAP_CSP_SUPPORTED |
                              VFCAP_CSP_SUPPORTED_BY_HW |
                              VFCAP_HWSCALE_UP |
                              VFCAP_HWSCALE_DOWN |
                              VFCAP_OSD |
                              VFCAP_EOSD);

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] query_format(): format %x (%s)\n",
           format, vo_format_name(format));

    switch (format) {
    case IMGFMT_VAAPI_MPEG2:
    case IMGFMT_VAAPI_MPEG4:
    case IMGFMT_VAAPI_H263:
    case IMGFMT_VAAPI_H264:
    case IMGFMT_VAAPI_WMV3:
    case IMGFMT_VAAPI_VC1:
        return default_caps | VOCAP_NOSLICES;
    case IMGFMT_NV12:
    case IMGFMT_YV12:
    case IMGFMT_I420:
    case IMGFMT_IYUV:
        if (VAImageFormat_from_imgfmt(format))
            return default_caps;
        break;
    }
    return 0;
}

static inline int get_field_flags(int i)
{
    return (g_deint && (g_image_fields & MP_IMGFIELD_INTERLACED) ? 
            (((!!(g_image_fields & MP_IMGFIELD_TOP_FIRST)) ^ i) == 0 ?
             VA_BOTTOM_FIELD : VA_TOP_FIELD) : VA_FRAME_PICTURE);
}

static inline int get_colorspace_flags(void)
{
    int csp = 0;
#if USE_VAAPI_COLORSPACE
    switch (g_colorspace) {
    case 0:
        csp = ((g_image_width >= 1280 || g_image_height > 576) ?
               VA_SRC_BT709 : VA_SRC_BT601);
        break;
    case 1:
        csp = VA_SRC_BT601;
        break;
    case 2:
        csp = VA_SRC_BT709;
        break;
    case 3:
        csp = VA_SRC_SMPTE_240;
        break;
    default:
        assert(0);
        break;
    }
#endif
    return csp;
}

static void put_surface_x11(struct vaapi_surface *surface)
{
    VAStatus status;
    int i;

    for (i = 0; i <= !!(g_deint > 1); i++) {
        const unsigned int flags = (get_field_flags(i) |
                                    get_colorspace_flags() |
                                    g_scaling);
        status = vaPutSurface(va_context->display,
                              surface->id,
                              vo_window,
                              0, 0, g_image_width, g_image_height,
                              g_output_rect.left,
                              g_output_rect.top,
                              g_output_rect.width,
                              g_output_rect.height,
                              NULL, 0,
                              flags);
        if (!check_status(status, "vaPutSurface()"))
            return;
    }
}

#if CONFIG_GL
static void put_surface_glx(struct vaapi_surface *surface)
{
    VAStatus status;
    int i;

    if (gl_use_tfp) {
        for (i = 0; i <= !!(g_deint > 1); i++) {
            const unsigned int flags = (get_field_flags(i) |
                                        get_colorspace_flags() |
                                        g_scaling);
            status = vaPutSurface(va_context->display,
                                  surface->id,
                                  g_image_pixmap,
                                  0, 0, g_image_width, g_image_height,
                                  0, 0, g_image_width, g_image_height,
                                  NULL, 0,
                                  flags);
            if (!check_status(status, "vaPutSurface()"))
                return;
        }
        g_output_surfaces[g_output_surface] = surface;
        return;
    }

#if CONFIG_VAAPI_GLX
    if (gl_binding) {
#if USE_VAAPI_GLX_BIND
        for (i = 0; i <= !!(g_deint > 1); i++) {
            const unsigned int flags = (get_field_flags(i) |
                                        get_colorspace_flags() |
                                        g_scaling);
            status = vaAssociateSurfaceGLX(va_context->display,
                                           gl_surface,
                                           surface->id,
                                           flags);
            if (!check_status(status, "vaAssociateSurfaceGLX()"))
                return;
        }
#else
        mp_msg(MSGT_VO, MSGL_WARN, "vaAssociateSurfaceGLX() is not implemented\n");
        gl_binding = 0;
#endif
    }

    if (!gl_binding) {
        for (i = 0; i <= !!(g_deint > 1); i++) {
            const unsigned int flags = (get_field_flags(i) |
                                        get_colorspace_flags() |
                                        g_scaling);
            status = vaCopySurfaceGLX(va_context->display,
                                      gl_surface,
                                      surface->id,
                                      flags);

            if (status == VA_STATUS_ERROR_UNIMPLEMENTED) {
                mp_msg(MSGT_VO, MSGL_WARN,
                       "[vo_vaapi] vaCopySurfaceGLX() is not implemented\n");
                gl_binding = 1;
            }
            else {
                if (!check_status(status, "vaCopySurfaceGLX()"))
                    return;
            }
        }
    }
#endif
    g_output_surfaces[g_output_surface] = surface;
}

static int glx_bind_texture(void)
{
    glEnable(GL_TEXTURE_2D);
    mpglBindTexture(GL_TEXTURE_2D, gl_texture);

    if (gl_use_tfp) {
        x11_trap_errors();
        mpglXBindTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT, NULL);
        XSync(mDisplay, False);
        if (x11_untrap_errors())
            mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Update bind_tex_image failed\n");
    }

#if USE_VAAPI_GLX_BIND
    if (gl_binding) {
        VAStatus status;
        status = vaBeginRenderSurfaceGLX(va_context->display, gl_surface);
        if (!check_status(status, "vaBeginRenderSurfaceGLX()"))
            return -1;
    }
#endif
    return 0;
}

static int glx_unbind_texture(void)
{
    if (gl_use_tfp) {
        x11_trap_errors();
        mpglXReleaseTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT);
        if (x11_untrap_errors())
            mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Failed to release?\n");
    }

#if USE_VAAPI_GLX_BIND
    if (gl_binding) {
        VAStatus status;
        status = vaEndRenderSurfaceGLX(va_context->display, gl_surface);
        if (!check_status(status, "vaEndRenderSurfaceGLX()"))
            return -1;
    }
#endif

    mpglBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
    return 0;
}

static void render_background(void)
{
    /* Original code from Mirco Muller (MacSlow):
       <http://cgit.freedesktop.org/~macslow/gl-gst-player/> */
    GLfloat fStartX = 0.0f;
    GLfloat fStartY = 0.0f;
    GLfloat fWidth  = (GLfloat)vo_dwidth;
    GLfloat fHeight = (GLfloat)vo_dheight;

    glBegin(GL_QUADS);
    {
        /* top third, darker grey to white */
        glColor3f(0.85f, 0.85f, 0.85f);
        glVertex3f(fStartX, fStartY, 0.0f);
        glColor3f(0.85f, 0.85f, 0.85f);
        glVertex3f(fStartX + fWidth, fStartY, 0.0f);
        glColor3f(1.0f, 1.0f, 1.0f);
        glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
        glColor3f(1.0f, 1.0f, 1.0f);
        glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);

        /* middle third, just plain white */
        glColor3f(1.0f, 1.0f, 1.0f);
        glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
        glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
        glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
        glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);

        /* bottom third, white to lighter grey */
        glColor3f(1.0f, 1.0f, 1.0f);
        glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
        glColor3f(1.0f, 1.0f, 1.0f);
        glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
        glColor3f(0.62f, 0.66f, 0.69f);
        glVertex3f(fStartX + fWidth, fStartY + fHeight, 0.0f);
        glColor3f(0.62f, 0.66f, 0.69f);
        glVertex3f(fStartX, fStartY + fHeight, 0.0f);
    }
    glEnd();
}

static void render_frame(void)
{
    struct vo_rect * const r = &g_output_rect;

    if (glx_bind_texture() < 0)
        return;
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);
    {
        glTexCoord2f(0.0f, 0.0f); glVertex2i(r->left, r->top);
        glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->bottom);
        glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->bottom);
        glTexCoord2f(1.0f, 0.0f); glVertex2i(r->right, r->top);
    }
    glEnd();
    if (glx_unbind_texture() < 0)
        return;
}

static void render_reflection(void)
{
    struct vo_rect * const r = &g_output_rect;
    const unsigned int rh  = g_output_rect.height / 5;
    GLfloat ry = 1.0f - (GLfloat)rh / (GLfloat)r->height;

    if (glx_bind_texture() < 0)
        return;
    glBegin(GL_QUADS);
    {
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->top);
        glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->top);

        glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
        glTexCoord2f(1.0f, ry); glVertex2i(r->right, r->top + rh);
        glTexCoord2f(0.0f, ry); glVertex2i(r->left, r->top + rh);
    }
    glEnd();
    if (glx_unbind_texture() < 0)
        return;
}

static void flip_page_glx(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    if (gl_reflect) {
        render_background();

        glPushMatrix();
        glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
        glTranslatef(50.0f, 0.0f, 0.0f);
    }

    render_frame();

    if (gl_reflect) {
        glPushMatrix();
        glTranslatef(0.0, (GLfloat)g_output_rect.height + 5.0f, 0.0f);
        render_reflection();
        glPopMatrix();
        glPopMatrix();
    }

    if (cpu_stats) {
        gl_draw_rectangle(0, 0, vo_dwidth, 32, 0x000000ff);
        glColor3f(1.0f, 1.0f, 1.0f);
        glRasterPos2i(16, 20);
        gl_printf("MPlayer: %.1f%% of CPU @ %u MHz", cpu_usage, cpu_frequency);
    }

    if (gl_finish)
        mpglFinish();
    gl_context.swapGlBuffers(&gl_context);

    if (vo_fs) /* avoid flickering borders in fullscreen mode */
        glClear(GL_COLOR_BUFFER_BIT);
}
#endif

#if CONFIG_XRENDER
static void put_surface_xrender(struct vaapi_surface *surface)
{
    VAStatus status;
    int i;

    for (i = 0; i <= !!(g_deint > 1); i++) {
        const unsigned int flags = (get_field_flags(i) |
                                    get_colorspace_flags() |
                                    g_scaling);
        status = vaPutSurface(va_context->display,
                              surface->id,
                              g_image_pixmap,
                              0, 0, g_image_width, g_image_height,
                              0, 0, g_output_rect.width, g_output_rect.height,
                              NULL, 0,
                              flags);
        if (!check_status(status, "vaPutSurface()"))
            return;
        XRenderComposite(mDisplay,
                         PictOpSrc, xr_video_picture, 0, xr_window_picture,
                         0, 0,
                         0, 0,
                         g_output_rect.left, g_output_rect.top,
                         g_output_rect.width, g_output_rect.height);
    }
}
#endif

static void put_surface(struct vaapi_surface *surface)
{
    if (!surface || surface->id == VA_INVALID_SURFACE)
        return;

#if CONFIG_GL
    if (gl_enabled)
        put_surface_glx(surface);
    else
#endif
#if CONFIG_XRENDER
    if (xr_enabled)
        put_surface_xrender(surface);
    else
#endif
        put_surface_x11(surface);
}

static int draw_slice(uint8_t * image[], int stride[],
                      int w, int h, int x, int y)
{
    struct vaapi_surface * const surface = va_free_surfaces[g_output_surface];
    VAImage * const va_image = &surface->image;
    VAStatus status;
    uint8_t *image_data = NULL;
    uint8_t *dst[3] = { 0, };
    unsigned int dst_stride[3] = { 0, };

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_slice(): location (%d,%d), size %dx%d\n", x, y, w, h);

    status = vaMapBuffer(va_context->display, va_image->buf,
                         (void *)&image_data);
    if (!check_status(status, "vaMapBuffer()"))
        return VO_FALSE;

    dst_stride[0] = va_image->pitches[0];
    dst[0] = image_data + va_image->offsets[0] + y * dst_stride[0] + x;

    memcpy_pic(dst[0], image[0], w, h, dst_stride[0], stride[0]);

    x /= 2;
    y /= 2;
    w /= 2;
    h /= 2;

    if (g_image_format == IMGFMT_YV12) {
        /* MPlayer's YV12 is actually I420, so swap U/V components */
        dst_stride[1] = va_image->pitches[2];
        dst[1] = image_data + va_image->offsets[2] + y * dst_stride[1] + x;
        dst_stride[2] = va_image->pitches[1];
        dst[2] = image_data + va_image->offsets[1] + y * dst_stride[2] + x;
    }
    else {
        if (image[1]) {
            dst_stride[1] = va_image->pitches[1];
            dst[1] = image_data + va_image->offsets[1] + y * dst_stride[1] + x;
        }
        if (image[2]) {
            dst_stride[2] = va_image->pitches[2];
            dst[2] = image_data + va_image->offsets[2] + y * dst_stride[2] + x;
        }
    }

    if (image[1]) /* RGBA only has a single plane */
        memcpy_pic(dst[1], image[1], w, h, dst_stride[1], stride[1]);

    if (image[2]) /* NV12 only has two planes */
        memcpy_pic(dst[2], image[2], w, h, dst_stride[2], stride[2]);

    status = vaUnmapBuffer(va_context->display, surface->image.buf);
    if (!check_status(status, "vaUnmapBuffer()"))
        return VO_FALSE;

    return VO_TRUE;
}

static int draw_frame(uint8_t * src[])
{
// Removed no longer exising error message [R]
    return VO_ERROR;
}

static void draw_osd(void)
{
    VAStatus status;
    const int osd_width  = va_osd_image.width;
    const int osd_height = va_osd_image.height;

    ensure_osd();
    if (va_osd_image.image_id == VA_INVALID_ID)
        return;

    if (!va_osd_draw_alpha)
        return;

    if (!vo_update_osd(osd_width, osd_height))
        return;
 
    if (!vo_osd_check_range_update(0, 0, osd_width, osd_height)) {
        disable_osd();
        return;
    }

    status = vaMapBuffer(va_context->display, va_osd_image.buf,
                         (void *)&va_osd_image_data);
    if (!check_status(status, "vaMapBuffer()"))
        return;

    memset(va_osd_image_data, 0, va_osd_image.data_size);

    vo_draw_text(osd_width, osd_height, va_osd_draw_alpha);

    status = vaUnmapBuffer(va_context->display, va_osd_image.buf);
    if (!check_status(status, "vaUnmapBuffer()"))
        return;
    va_osd_image_data = NULL;

    enable_osd();
}

static void draw_eosd(struct mp_eosd_image_list *imgs)
{
    struct mp_eosd_image *img = eosd_image_first(imgs);
    struct mp_eosd_image *i;
    VAStatus status;

    if (!va_eosd_draw_alpha)
        return;

    // Nothing changed, no need to redraw
    if (imgs->changed == 0)
        return;

    // There's nothing to render!
    if (!img) {
        disable_eosd();
        return;
    }

    if (imgs->changed == 1)
        goto eosd_skip_upload;

    status = vaMapBuffer(va_context->display, va_eosd_image.buf,
                         (void *)&va_eosd_image_data);
    if (!check_status(status, "vaMapBuffer()"))
        return;

    memset(va_eosd_image_data, 0, va_eosd_image.data_size);

    for (i = img; i; i = i->next)
        va_eosd_draw_alpha(i->bitmap, i->w, i->h, i->stride,
                           i->dst_x, i->dst_y, i->color);

    status = vaUnmapBuffer(va_context->display, va_eosd_image.buf);
    if (!check_status(status, "vaUnmapBuffer()"))
        return;
    va_eosd_image_data = NULL;

eosd_skip_upload:
    enable_eosd();
}

static void flip_page(void)
{
    struct vaapi_surface *surface;

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] flip_page()\n");

    surface = g_output_surfaces[g_output_surface];
    if (!surface)
        return;

    put_surface(surface);
    g_output_surface = (g_output_surface + 1) % MAX_OUTPUT_SURFACES;
    g_is_visible     = 1;

#if CONFIG_GL
    if (gl_enabled)
        flip_page_glx();
#endif
}

static struct vaapi_surface *get_surface(mp_image_t *mpi)
{
    struct vaapi_surface *surface;

    if (mpi->type == MP_IMGTYPE_NUMBERED && is_direct_mapping()) {
        assert(mpi->number < va_num_surfaces);
        surface = va_free_surfaces[mpi->number];
        return surface;
    }

    /* Push current surface to a free slot */
    if (mpi->priv) {
        assert(!va_free_surfaces[va_free_surfaces_tail_index]);
        va_free_surfaces[va_free_surfaces_tail_index] = mpi->priv;
        va_free_surfaces_tail_index = (va_free_surfaces_tail_index + 1) % va_num_surfaces;
    }

    /* Pop the least recently used free surface */
    assert(va_free_surfaces[va_free_surfaces_head_index]);
    surface = va_free_surfaces[va_free_surfaces_head_index];
    va_free_surfaces[va_free_surfaces_head_index] = NULL;
    va_free_surfaces_head_index = (va_free_surfaces_head_index + 1) % va_num_surfaces;
    return surface;
}

static uint32_t get_image(mp_image_t *mpi)
{
    struct vaapi_surface *surface;

    if (mpi->type != MP_IMGTYPE_NUMBERED)
        return VO_FALSE;

    if (!IMGFMT_IS_VAAPI(g_image_format))
        return VO_FALSE;

    surface = get_surface(mpi);
    if (!surface)
        return VO_FALSE;

    mpi->flags |= MP_IMGFLAG_DIRECT;
    mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = mpi->stride[3] = 0;
    mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = mpi->planes[3] = NULL;
    mpi->planes[0] = (char *)surface;
    mpi->planes[3] = (char *)(uintptr_t)surface->id;
    mpi->num_planes = 1;
    mpi->priv = surface;

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] get_image(): surface 0x%08x\n", surface->id);

    return VO_TRUE;
}

static int put_image(mp_image_t *mpi, struct vaapi_surface *surface)
{
    VAStatus status;
 
    if ((mpi->flags & (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV)) != (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV))
        return VO_FALSE;

    if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
        if (!draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0))
            return VO_FALSE;
    }

    if (!surface->is_bound) {
        status = vaPutImage2(va_context->display,
                             surface->id,
                             surface->image.image_id,
                             mpi->x, mpi->y, mpi->w, mpi->h,
                             mpi->x, mpi->y, mpi->w, mpi->h);
        if (!check_status(status, "vaPutImage()"))
            return VO_FALSE;
    }

    return VO_TRUE;
}

static uint32_t draw_image(mp_image_t *mpi)
{
    struct vaapi_surface *surface = (struct vaapi_surface *)mpi->priv;

    g_image_fields = mpi->fields;

    if (!IMGFMT_IS_VAAPI(mpi->imgfmt)) {
        /* XXX: no direct rendering in non-accelerated mode */
        surface = va_free_surfaces[g_output_surface];
        if (!put_image(mpi, surface))
            return VO_FALSE;
    }

    mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_image(): surface 0x%08x\n", surface->id);

    g_output_surfaces[g_output_surface] = surface;

    if (cpu_stats) {
        static uint64_t ticks;
        if ((ticks++ % 30) == 0) {
            cpu_frequency = get_cpu_frequency();
            cpu_usage = get_cpu_usage(CPU_USAGE_QUANTUM);
        }
    }
    return VO_TRUE;
}

static void check_events(void)
{
    int events = vo_x11_check_events(mDisplay);

    if (events & VO_EVENT_RESIZE)
        resize();

    if ((events & (VO_EVENT_EXPOSE|VO_EVENT_RESIZE)) && g_is_paused) {
        /* Redraw the last visible buffer  */
        if (g_is_visible) {
            struct vaapi_surface *surface = g_output_surfaces[g_output_surface];
            if (surface)
                put_surface(surface);
        }
    }
}

static VADisplayAttribute *get_display_attribute(const char *name)
{
    VADisplayAttribute *attr;
    if (!strcasecmp(name, "brightness"))
        attr = &va_equalizer.brightness;
    else if (!strcasecmp(name, "contrast"))
        attr = &va_equalizer.contrast;
    else if (!strcasecmp(name, "saturation"))
        attr = &va_equalizer.saturation;
    else if (!strcasecmp(name, "hue"))
        attr = &va_equalizer.hue;
    else
        attr = NULL;
    return attr;
}

static int get_equalizer(const char *name, int *value)
{
    VADisplayAttribute * const attr = get_display_attribute(name);
    int r;

    if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_GETTABLE))
        return VO_NOTIMPL;

    /* normalize to -100 .. 100 range */
    r = attr->max_value - attr->min_value;
    if (r == 0)
        return VO_NOTIMPL;
    *value = ((attr->value - attr->min_value) * 200) / r - 100;
    return VO_TRUE;
}

static int set_equalizer(const char *name, int value)
{
    VADisplayAttribute * const attr = get_display_attribute(name);
    VAStatus status;
    int r;

    if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_SETTABLE))
        return VO_NOTIMPL;

    /* normalize to attribute value range */
    r = attr->max_value - attr->min_value;
    if (r == 0)
        return VO_NOTIMPL;
    attr->value = ((value + 100) * r) / 200 + attr->min_value;

    status = vaSetDisplayAttributes(va_context->display, attr, 1);
    if (!check_status(status, "vaSetDisplayAttributes()"))
        return VO_FALSE;
    return VO_TRUE;
}

static int control(uint32_t request, void *data)
{
    switch (request) {
    case VOCTRL_GET_DEINTERLACE:
        *(int*)data = g_deint;
        return VO_TRUE;
    case VOCTRL_SET_DEINTERLACE:
        g_deint = *(int*)data;
        if (g_deint)
            g_deint = g_deint_type;
        return VO_TRUE;
    case VOCTRL_PAUSE:
        return (g_is_paused = 1);
    case VOCTRL_RESUME:
        return (g_is_paused = 0);
    case VOCTRL_QUERY_FORMAT:
        return query_format(*((uint32_t *)data));
    case VOCTRL_GET_IMAGE:
        return get_image(data);
    case VOCTRL_DRAW_IMAGE:
        return draw_image(data);
    case VOCTRL_GUISUPPORT:
        return VO_TRUE;
    case VOCTRL_BORDER:
        vo_x11_border();
        resize();
        return VO_TRUE;
    case VOCTRL_FULLSCREEN:
        vo_x11_fullscreen();
        resize();
        return VO_TRUE;
    case VOCTRL_SET_EQUALIZER: {
        vf_equalizer_t *eq = data;
        if (g_image_format == IMGFMT_BGRA)
            return VO_NOTIMPL;

        return set_equalizer(eq->item, eq->value);
    }
    case VOCTRL_GET_EQUALIZER: {
        vf_equalizer_t *eq = data;
        return get_equalizer(eq->item, &eq->value);
    }
    case VOCTRL_ONTOP:
        vo_x11_ontop();
        return VO_TRUE;
    case VOCTRL_UPDATE_SCREENINFO:
        update_xinerama_info();
        return VO_TRUE;
    case VOCTRL_GET_PANSCAN:
        return VO_TRUE;
    case VOCTRL_SET_PANSCAN:
        resize();
        return VO_TRUE;
// Restore the control msg instead of the non-static hack [R]
    /*case VOCTRL_GET_HWACCEL_CONTEXT:
        *((void **)data) = va_context;
        return VO_TRUE;*/
    case VOCTRL_DRAW_EOSD:
        if (!data)
            return VO_FALSE;
        draw_eosd(data);
        return VO_TRUE;
    case VOCTRL_GET_EOSD_RES: {
        struct mp_eosd_settings *r = data;
        r->mt = r->mb = r->ml = r->mr = 0;
        r->srcw = g_image_width;
        r->srch = g_image_height;
        r->w    = g_image_width;
        r->h    = g_image_height;
        return VO_TRUE;
    }
    }
    return VO_NOTIMPL;
}
_______________________________________________
MPlayer-dev-eng mailing list
MPlayer-dev-eng@xxxxxxxxxxxx
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng