diff options
Diffstat (limited to 'media-video/mplayer/files/vaapi-take3/01-mplayer-vaapi.patch')
-rw-r--r-- | media-video/mplayer/files/vaapi-take3/01-mplayer-vaapi.patch | 4012 |
1 files changed, 4012 insertions, 0 deletions
diff --git a/media-video/mplayer/files/vaapi-take3/01-mplayer-vaapi.patch b/media-video/mplayer/files/vaapi-take3/01-mplayer-vaapi.patch new file mode 100644 index 0000000..74939c7 --- /dev/null +++ b/media-video/mplayer/files/vaapi-take3/01-mplayer-vaapi.patch @@ -0,0 +1,4012 @@ +diff --git a/Makefile b/Makefile +index 2de75fb..fd4e503 100644 +--- a/Makefile ++++ b/Makefile +@@ -590,6 +590,7 @@ SRCS_MPLAYER-$(TDFXVID) += libvo/vo_tdfx_vid.c + 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 libvo/vesa_lvo.c + SRCS_MPLAYER-$(VIDIX) += libvo/vo_cvidix.c \ +@@ -643,6 +644,7 @@ SRCS_MPLAYER = command.c \ + 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 \ +diff --git a/cfg-common.h b/cfg-common.h +index c6dfef0..a280890 100644 +--- a/cfg-common.h ++++ b/cfg-common.h +@@ -521,6 +521,7 @@ const m_option_t common_opts[] = { + {"vfm", &video_fm_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, + {"ac", &audio_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, + {"vc", &video_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, ++ {"va", &video_hwaccel_name, CONF_TYPE_STRING, 0, 0, 0, NULL}, + + // postprocessing: + #ifdef CONFIG_FFMPEG +diff --git a/codec-cfg.c b/codec-cfg.c +index 4db74c5..2f160fb 100644 +--- a/codec-cfg.c ++++ b/codec-cfg.c +@@ -224,6 +224,13 @@ static const struct { + {"VDPAU_VC1",IMGFMT_VDPAU_VC1}, + {"VDPAU_MPEG4",IMGFMT_VDPAU_MPEG4}, + ++ {"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} + }; + +diff --git a/configure b/configure +index 1e0f7fc..45e4574 100755 +--- a/configure ++++ b/configure +@@ -421,6 +421,9 @@ Codecs: + --disable-muxer=MUXER disable specified FFmpeg muxer + --enable-muxer=MUXER enable specified FFmpeg muxer + ++Hardware acceleration: ++ --enable-vaapi enable VA-API acceleration [disable] ++ + Video output: + --disable-vidix disable VIDIX [for x86 *nix] + --with-vidix-drivers[=*] list of VIDIX drivers to be compiled in +@@ -450,6 +453,7 @@ Video output: + --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-vdpau enable VDPAU acceleration [autodetect] +@@ -555,6 +559,7 @@ Use these options if autodetection fails: + --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-glib-config=PATH path to glib*-config + --with-gtk-config=PATH path to gtk*-config +@@ -618,8 +623,7 @@ libavparsers=$libavparsers_all + libavbsfs_all=$(sed -n 's/^[^#]*BSF.*(.*, *\(.*\)).*/\1_bsf/p' ffmpeg/libavcodec/allcodecs.c | tr '[a-z]' '[A-Z]') + libavbsfs=$libavbsfs_all + libavhwaccels_all=$(sed -n 's/^[^#]*HWACCEL.*(.*, *\(.*\)).*/\1_hwaccel/p' ffmpeg/libavcodec/allcodecs.c | tr '[a-z]' '[A-Z]') +-# Disable all hardware accelerators for now. +-libavhwaccels= ++libavhwaccels=$(for h in $libavhwaccels_all; do case $h in (*_VAAPI_HWACCEL) echo $h;; esac; done) + libavdemuxers_all=$(sed -n 's/^[^#]*DEMUX.*(.*, *\(.*\)).*/\1_demuxer/p' ffmpeg/libavformat/allformats.c | tr '[a-z]' '[A-Z]') + libavdemuxers=$(echo $libavdemuxers_all | sed -e 's/ LIB[A-Z0-9_]*_DEMUXER//g' -e s/REDIR_DEMUXER// -e s/AVISYNTH_DEMUXER//) + libavmuxers_all=$(sed -n 's/^[^#]*_MUX.*(.*, *\(.*\)).*/\1_muxer/p' ffmpeg/libavformat/allformats.c | tr '[a-z]' '[A-Z]') +@@ -628,11 +632,15 @@ libavprotocols_all=$(sed -n 's/^[^#]*PROTOCOL.*(.*, *\(.*\)).*/\1_protocol/p' ff + libavprotocols=$libavprotocols_all + _mencoder=yes + _mplayer=yes ++_vaapi=auto ++_vaapi_glx=no ++_libgtop=auto + _x11=auto + _xshape=auto + _xss=auto + _dga1=auto + _dga2=auto ++_xrender=auto + _xv=auto + _xvmc=no #auto when complete + _vdpau=auto +@@ -855,6 +863,9 @@ for ac_option do + _xvmclib=$(echo $ac_option | cut -d '=' -f 2) + ;; + ++ --with-vaapi-prefix=*) ++ _vaapiprefix=$(echo $ac_option | cut -d '=' -f 2) ++ ;; + --with-sdl-config=*) + _sdlconfig=$(echo $ac_option | cut -d '=' -f 2) + ;; +@@ -970,10 +981,14 @@ for ac_option do + --disable-xshape) _xshape=no ;; + --enable-xss) _xss=yes ;; + --disable-xss) _xss=no ;; ++ --enable-xrender) _xrender=yes ;; ++ --disable-xrender) _xrender=no ;; + --enable-xv) _xv=yes ;; + --disable-xv) _xv=no ;; + --enable-xvmc) _xvmc=yes ;; + --disable-xvmc) _xvmc=no ;; ++ --enable-vaapi) _vaapi=yes ;; ++ --disable-vaapi) _vaapi=no ;; + --enable-vdpau) _vdpau=yes ;; + --disable-vdpau) _vdpau=no ;; + --enable-sdl) _sdl=yes ;; +@@ -1068,6 +1083,8 @@ for ac_option do + --disable-twolame) _twolame=no ;; + --enable-libcdio) _libcdio=yes ;; + --disable-libcdio) _libcdio=no ;; ++ --enable-libgtop) _libgtop=yes ;; ++ --disable-libgtop) _libgtop=no ;; + --enable-liblzo) _liblzo=yes ;; + --disable-liblzo) _liblzo=no ;; + --enable-libvorbis) _libvorbis=yes ;; +@@ -3895,6 +3912,28 @@ fi + echores "$_gettimeofday" + + ++echocheck "clock_gettime()" ++cat > $TMPC << EOF ++#include <time.h> ++int main(void) { ++ struct timespec t; ++ clock_gettime(CLOCK_REALTIME, &t); ++ return 0; ++} ++EOF ++_clock_gettime=no ++cc_check -lrt && _clock_gettime=yes ++if test "$_clock_gettime" = yes ; then ++ def_clock_gettime='#define HAVE_CLOCK_GETTIME 1' ++ extra_ldflags="$extra_ldflags -lrt" ++ _need_clock_gettime=no ++else ++ def_clock_gettime='#undef HAVE_CLOCK_GETTIME' ++ _need_clock_gettime=yes ++fi ++echores "$_clock_gettime" ++ ++ + echocheck "glob()" + _glob=no + statement_check glob.h 'glob("filename", 0, 0, 0)' && _glob=yes +@@ -4265,7 +4304,7 @@ else + novomodules="x11 $novomodules" + res_comment="check if the dev(el) packages are installed" + # disable stuff that depends on X +- _xv=no ; _xvmc=no ; _xinerama=no ; _vm=no ; _xf86keysym=no ; _vdpau=no ++ _xv=no ; _xvmc=no ; _xinerama=no ; _vm=no ; _xf86keysym=no ; _vaapi=no ; _vdpau=no + fi + echores "$_x11" + +@@ -4312,6 +4351,30 @@ else + 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 ; then + _xv=no +@@ -4791,6 +4854,31 @@ echores "$_corevideo" + fi #if darwin + + ++echocheck "libgtop" ++if test "$_libgtop" = auto ; then ++ _libgtop=no ++ if $_pkg_config --exists 'libgtop-2.0' ; then ++ ++cat > $TMPC << EOF ++#include <glibtop/cpu.h> ++#include <glibtop/proctime.h> ++int main(void) { return 0; } ++EOF ++cc_check $($_pkg_config --libs --cflags libgtop-2.0) && tmp_run && _libgtop=yes ++ ++ fi ++fi ++echores "$_libgtop" ++ ++if test "$_libgtop" = yes ; then ++ def_libgtop='#define CONFIG_LIBGTOP 1' ++ libs_mplayer="$libs_mplayer $($_pkg_config --libs libgtop-2.0)" ++ extra_cflags="$extra_cflags $($_pkg_config --cflags libgtop-2.0)" ++else ++ def_libgtop='#define CONFIG_LIBGTOP 0' ++fi ++ ++ + echocheck "PNG support" + if test "$_png" = auto ; then + _png=no +@@ -5152,6 +5240,23 @@ else + fi + 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 "MatrixView" + if test "$_gl" = no ; then +@@ -5719,6 +5824,57 @@ echores "$_dart" + fi #if os2 + + ++######################### ++# HARDWARE ACCELERATORS # ++######################### ++ ++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 && _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 -lva-x11" ++ vomodules="vaapi $vomodules" ++else ++ def_vaapi='#define CONFIG_VAAPI 0' ++ novomodules="vaapi $novomodules" ++ libavhwaccels=`echo $libavhwaccels | sed -e "s/\(MPEG[124]\|H26[34]\|WMV3\|VC1\)_VAAPI_HWACCEL//g"` ++fi ++echores "$_vaapi" ++ ++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 && _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" ++else ++ def_vaapi_glx='#define CONFIG_VAAPI_GLX 0' ++fi ++echores "$_vaapi_glx" ++ ++ + # set default CD/DVD devices + if win32 || os2 ; then + default_cdrom_device="D:" +@@ -8051,6 +8207,7 @@ TV_V4L2 = $_tv_v4l2 + TWOLAME=$_twolame + UNRAR_EXEC = $_unrar_exec + V4L2 = $_v4l2 ++VAAPI = $_vaapi + VCD = $_vcd + VDPAU = $_vdpau + VESA = $_vesa +@@ -8140,7 +8297,9 @@ CONFIG_MLIB = $_mlib + CONFIG_MUXERS = $_mencoder + CONFIG_POSTPROC = yes + CONFIG_RTPDEC = $networking ++CONFIG_VAAPI = $_vaapi + CONFIG_VDPAU = $_vdpau ++CONFIG_XRENDER = $_xrender + CONFIG_XVMC = $_xvmc + CONFIG_ZLIB = $_zlib + +@@ -8254,6 +8413,7 @@ $def_winsock2_h + + + /* system functions */ ++$def_clock_gettime + $def_gethostbyname2 + $def_gettimeofday + $def_glob +@@ -8284,6 +8444,7 @@ $def_extern_asm + $def_extern_prefix + $def_iconv + $def_kstat ++$def_libgtop + $def_macosx_bundle + $def_macosx_finder + $def_maemo +@@ -8513,6 +8674,8 @@ $def_tdfxfb + $def_tdfxvid + $def_tga + $def_v4l2 ++$def_vaapi ++$def_vaapi_glx + $def_vdpau + $def_vesa + $def_vidix +@@ -8538,6 +8701,7 @@ $def_xf86keysym + $def_xinerama + $def_xmga + $def_xss ++$def_xrender + $def_xv + $def_xvmc + $def_xvr100 +diff --git a/etc/codecs.conf b/etc/codecs.conf +index d353bb5..e39a926 100644 +--- a/etc/codecs.conf ++++ b/etc/codecs.conf +@@ -212,6 +212,7 @@ videocodec ffmpeg2 + fourcc slif ; SoftLab MPEG-2 I-frames Codec + driver ffmpeg + dll "mpeg2video" ++ out VAAPI_MPEG2 + out YV12,I420,IYUV + out 422P,444P + +@@ -941,6 +942,7 @@ videocodec ffwmv3 + fourcc WMV3,wmv3 + driver ffmpeg + dll wmv3 ++ out VAAPI_WMV3 + out YV12,I420,IYUV + + videocodec ffwmvp +@@ -967,6 +969,7 @@ videocodec ffvc1 + fourcc vc-1,VC-1 + driver ffmpeg + dll vc1 ++ out VAAPI_VC1 + out YV12,I420,IYUV + + videocodec ffvc1vdpau +@@ -989,6 +992,7 @@ videocodec ffh264 + format 0x10000005 + driver ffmpeg + dll h264 ++ out VAAPI_H264 + out YV12,I420,IYUV + + videocodec ffh264vdpau +@@ -1058,6 +1062,7 @@ videocodec ffodivx + fourcc SIPP ; Samsung SHR-6040 + driver ffmpeg + dll mpeg4 ;opendivx ++ out VAAPI_MPEG4 + out YV12,I420,IYUV + + videocodec ffodivxvdpau +@@ -1646,6 +1651,7 @@ videocodec ffh263 + fourcc VX1K ; Agora Labs VX1000S H263 + driver ffmpeg + dll h263 ++ out VAAPI_H263 + out YV12,I420,IYUV + + videocodec ffzygo +diff --git a/ffmpeg/libavcodec/vaapi_vc1.c b/ffmpeg/libavcodec/vaapi_vc1.c +index 2c24042..34e9056 100644 +--- a/ffmpeg/libavcodec/vaapi_vc1.c ++++ b/ffmpeg/libavcodec/vaapi_vc1.c +@@ -160,6 +160,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t + pic_param->sequence_fields.bits.syncmarker = s->resync_marker; + pic_param->sequence_fields.bits.rangered = v->rangered; + pic_param->sequence_fields.bits.max_b_frames = s->avctx->max_b_frames; ++ pic_param->sequence_fields.bits.profile = v->profile; + pic_param->coded_width = s->avctx->coded_width; + pic_param->coded_height = s->avctx->coded_height; + pic_param->entrypoint_fields.value = 0; /* reset all bits */ +diff --git a/fmt-conversion.c b/fmt-conversion.c +index 9e88100..bd32ce8 100644 +--- a/fmt-conversion.c ++++ b/fmt-conversion.c +@@ -18,14 +18,16 @@ + + #include "mp_msg.h" + #include "libavutil/avutil.h" ++#include "libavcodec/avcodec.h" + #include "libmpcodecs/img_format.h" + #include "libavutil/samplefmt.h" + #include "libaf/af_format.h" + #include "fmt-conversion.h" + + static const struct { + int fmt; + enum PixelFormat pix_fmt; ++ enum CodecID codec_id; + } conversion_map[] = { + {IMGFMT_ARGB, PIX_FMT_ARGB}, + {IMGFMT_BGRA, PIX_FMT_BGRA}, +@@ -95,6 +97,17 @@ static const struct { + {IMGFMT_VDPAU_WMV3, PIX_FMT_VDPAU_WMV3}, + {IMGFMT_VDPAU_VC1, PIX_FMT_VDPAU_VC1}, + {IMGFMT_VDPAU_MPEG4, PIX_FMT_VDPAU_MPEG4}, ++ ++ /* VA-API formats */ ++ {IMGFMT_VAAPI_MPEG2, PIX_FMT_VAAPI_VLD, CODEC_ID_MPEG2VIDEO}, ++ {IMGFMT_VAAPI_MPEG2_IDCT,PIX_FMT_VAAPI_IDCT, CODEC_ID_MPEG2VIDEO}, ++ {IMGFMT_VAAPI_MPEG2_MOCO,PIX_FMT_VAAPI_MOCO, CODEC_ID_MPEG2VIDEO}, ++ {IMGFMT_VAAPI_MPEG4, PIX_FMT_VAAPI_VLD, CODEC_ID_MPEG4}, ++ {IMGFMT_VAAPI_H263, PIX_FMT_VAAPI_VLD, CODEC_ID_H263}, ++ {IMGFMT_VAAPI_H264, PIX_FMT_VAAPI_VLD, CODEC_ID_H264}, ++ {IMGFMT_VAAPI_WMV3, PIX_FMT_VAAPI_VLD, CODEC_ID_WMV3}, ++ {IMGFMT_VAAPI_VC1, PIX_FMT_VAAPI_VLD, CODEC_ID_VC1}, ++ + {0, PIX_FMT_NONE} + }; + +@@ -111,12 +124,14 @@ enum PixelFormat imgfmt2pixfmt(int fmt) + return pix_fmt; + } + +-int pixfmt2imgfmt(enum PixelFormat pix_fmt) ++int pixfmt2imgfmt(enum PixelFormat pix_fmt, int codec_id) + { + int i; + int fmt; + for (i = 0; conversion_map[i].pix_fmt != PIX_FMT_NONE; i++) +- if (conversion_map[i].pix_fmt == pix_fmt) ++ if (conversion_map[i].pix_fmt == pix_fmt && ++ (conversion_map[i].codec_id == 0 || ++ conversion_map[i].codec_id == codec_id)) + break; + fmt = conversion_map[i].fmt; + if (!fmt) +--- a/fmt-conversion.h 2011-03-22 16:20:04.000000000 +0100 ++++ b/fmt-conversion.h 2011-04-06 21:00:34.561717643 +0200 +@@ -24,7 +24,7 @@ + #include "libavutil/samplefmt.h" + + enum PixelFormat imgfmt2pixfmt(int fmt); +-int pixfmt2imgfmt(enum PixelFormat pix_fmt); ++int pixfmt2imgfmt(enum PixelFormat pix_fmt, int codec_id); + enum AVSampleFormat affmt2samplefmt(int fmt); + int samplefmt2affmt(enum AVSampleFormat sample_fmt); + diff --git a/fmt-conversion.h b/fmt-conversion.h +index 9e133a8..962ca4e 100644 +diff --git a/gui/mplayer/gtk/opts.c b/gui/mplayer/gtk/opts.c +index 4f7ffb2..0da5434 100644 +--- a/gui/mplayer/gtk/opts.c ++++ b/gui/mplayer/gtk/opts.c +@@ -66,9 +66,11 @@ static GtkWidget * CLVDrivers; + GtkWidget * prEFontName; + GtkWidget * prEDVDDevice; + GtkWidget * prECDRomDevice; ++static GtkWidget * EVHW; + static GtkWidget * EVFM; + static GtkWidget * EAFM; + ++static GtkWidget * CBVHW; + static GtkWidget * CBVFM; + static GtkWidget * CBAFM; + static GtkWidget * CBAudioEqualizer; +@@ -354,6 +356,26 @@ void ShowPreferences( void ) + // -- 5. page + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( CBNonInterlaved ),force_ni ); + if ( index_mode == 1 ) gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( CBIndex ),1 ); ++ ++ { ++ int i; ++ GList * Items = NULL; ++ char * name = NULL; ++ ++ Items = g_list_append(Items, MSGTR_PREFERENCES_None); ++ for (i = 0; i < HWACCEL_COUNT; i++) { ++ const char *hwaccel_name = get_video_hwaccel_name(i); ++ if (!hwaccel_name) ++ continue; ++ Items = g_list_append(Items, hwaccel_name); ++ if (video_hwaccel_name && !gstrcmp(video_hwaccel_name, get_video_hwaccel_short_name(i) ) ) name = hwaccel_name; ++ } ++ gtk_combo_set_popdown_strings(GTK_COMBO(CBVHW), Items); ++ g_list_free(Items); ++ if (name) ++ gtk_entry_set_text(GTK_ENTRY(EVHW), name); ++ } ++ + { + int i; + GList * Items = NULL; +@@ -600,6 +622,17 @@ static void prButton( GtkButton * button, gpointer user_data ) + if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( CBIndex ) ) ) index_mode=1; + + { ++ int i; ++ const char *tmp = gtk_entry_get_text(GTK_ENTRY(EVHW)); ++ for (i = 0; i < HWACCEL_COUNT; i++) { ++ if (!gstrcmp(tmp, get_video_hwaccel_name(i))) { ++ video_hwaccel_name = get_video_hwaccel_short_name(i); ++ break; ++ } ++ } ++ } ++ ++ { + int i; + const char * tmp = gtk_entry_get_text( GTK_ENTRY( EVFM ) ); + for( i=0;mpcodecs_vd_drivers[i];i++ ) +@@ -1201,6 +1234,20 @@ GtkWidget * create_Preferences( void ) + + hbox5=AddHBox( vbox602,1 ); + ++ AddLabel( MSGTR_PREFERENCES_VideoHardwareAcceleration,hbox5 ); ++ ++ CBVHW=gtk_combo_new(); ++ gtk_widget_set_name( CBVHW,"CBVHW" ); ++ gtk_widget_show( CBVHW ); ++ gtk_box_pack_start( GTK_BOX( hbox5 ),CBVHW,TRUE,TRUE,0 ); ++ ++ EVHW=GTK_COMBO( CBVHW )->entry; ++ gtk_widget_set_name( EVHW,"CEVHW" ); ++ gtk_entry_set_editable( GTK_ENTRY( EVHW ),FALSE ); ++ gtk_widget_show( EVHW ); ++ ++ hbox5=AddHBox( vbox602,1 ); ++ + AddLabel( MSGTR_PREFERENCES_VideoCodecFamily,hbox5 ); + + CBVFM=gtk_combo_new(); +diff --git a/help/help_mp-en.h b/help/help_mp-en.h +index d9d8166..bd2c99c 100644 +--- a/help/help_mp-en.h ++++ b/help/help_mp-en.h +@@ -721,6 +721,7 @@ static const char help_text[]= + #define MSGTR_PREFERENCES_IDX "Rebuild index table, if needed" + #define MSGTR_PREFERENCES_VideoCodecFamily "Video codec family:" + #define MSGTR_PREFERENCES_AudioCodecFamily "Audio codec family:" ++#define MSGTR_PREFERENCES_VideoHardwareAcceleration "Video hardware acceleration:" + #define MSGTR_PREFERENCES_FRAME_OSD_Level "OSD level" + #define MSGTR_PREFERENCES_FRAME_Subtitle "Subtitle" + #define MSGTR_PREFERENCES_FRAME_Font "Font" +@@ -1656,6 +1657,7 @@ static const char help_text[]= + #define MSGTR_MPCODECS_UnexpectedInitVoError "[VD_FFMPEG] Unexpected init_vo error.\n" + #define MSGTR_MPCODECS_UnrecoverableErrorRenderBuffersNotTaken "[VD_FFMPEG] Unrecoverable error, render buffers not taken.\n" + #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" +diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c +index 95249c5..172864b 100644 +--- a/libmpcodecs/dec_video.c ++++ b/libmpcodecs/dec_video.c +@@ -53,9 +53,47 @@ + int field_dominance = -1; + + int divx_quality = 0; ++char *video_hwaccel_name=NULL; + + const vd_functions_t *mpvdec = NULL; + ++int get_video_hwaccel(void) ++{ ++ static int video_hwaccel = -1; ++ if (video_hwaccel < 0) { ++ video_hwaccel = HWACCEL_NONE; ++ if (video_hwaccel_name) { ++ if (!strcmp(video_hwaccel_name,"xvmc")) ++ video_hwaccel = HWACCEL_XVMC; ++ else if (!strcmp(video_hwaccel_name,"vaapi")) ++ video_hwaccel = HWACCEL_VAAPI; ++ else if (!strcmp(video_hwaccel_name,"vdpau")) ++ video_hwaccel = HWACCEL_VDPAU; ++ } ++ } ++ return video_hwaccel; ++} ++ ++const char *get_video_hwaccel_name(int hwaccel) ++{ ++ switch (hwaccel) { ++ case HWACCEL_XVMC: return "XvMC"; ++ case HWACCEL_VAAPI: return "VA API"; ++ case HWACCEL_VDPAU: return "VDPAU"; ++ } ++ return NULL; ++} ++ ++const char *get_video_hwaccel_short_name(int hwaccel) ++{ ++ switch (hwaccel) { ++ case HWACCEL_XVMC: return "xvmc"; ++ case HWACCEL_VAAPI: return "vaapi"; ++ case HWACCEL_VDPAU: return "vdpau"; ++ } ++ return NULL; ++} ++ + int get_video_quality_max(sh_video_t *sh_video) + { + vf_instance_t *vf = sh_video->vfilter; +diff --git a/libmpcodecs/dec_video.h b/libmpcodecs/dec_video.h +index 4be4205..1a51635 100644 +--- a/libmpcodecs/dec_video.h ++++ b/libmpcodecs/dec_video.h +@@ -21,6 +21,14 @@ + + #include "libmpdemux/stheader.h" + ++enum { ++ HWACCEL_NONE = 0, ++ HWACCEL_XVMC, ++ HWACCEL_VAAPI, ++ HWACCEL_VDPAU, ++ HWACCEL_COUNT ++}; ++ + extern int field_dominance; + + // dec_video.c: +@@ -41,6 +49,11 @@ int set_rectangle(sh_video_t *sh_video, int param, int value); + void resync_video_stream(sh_video_t *sh_video); + int get_current_video_decoder_lag(sh_video_t *sh_video); + ++int get_video_hwaccel(void); ++const char *get_video_hwaccel_name(int hwaccel); ++const char *get_video_hwaccel_short_name(int hwaccel); ++ + extern int divx_quality; ++extern char *video_hwaccel_name; + + #endif /* MPLAYER_DEC_VIDEO_H */ +diff --git a/libmpcodecs/img_format.c b/libmpcodecs/img_format.c +index ba87042..641b61e 100644 +--- a/libmpcodecs/img_format.c ++++ b/libmpcodecs/img_format.c +@@ -96,6 +96,14 @@ const char *vo_format_name(int format) + case IMGFMT_ZRMJPEGIB: return "Zoran MJPEG bottom field first"; + case IMGFMT_XVMC_MOCO_MPEG2: return "MPEG1/2 Motion Compensation"; + case IMGFMT_XVMC_IDCT_MPEG2: return "MPEG1/2 Motion Compensation and IDCT"; ++ 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"; + case IMGFMT_VDPAU_MPEG1: return "MPEG1 VDPAU acceleration"; + case IMGFMT_VDPAU_MPEG2: return "MPEG2 VDPAU acceleration"; + case IMGFMT_VDPAU_H264: return "H.264 VDPAU acceleration"; +diff --git a/libmpcodecs/img_format.h b/libmpcodecs/img_format.h +index c95ed4d..403690e 100644 +--- a/libmpcodecs/img_format.h ++++ b/libmpcodecs/img_format.h +@@ -182,6 +182,26 @@ + #define IMGFMT_XVMC_MOCO_MPEG2 (IMGFMT_XVMC|0x02) + #define IMGFMT_XVMC_IDCT_MPEG2 (IMGFMT_XVMC|0x82) + ++/* 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) ++ + // VDPAU specific format. + #define IMGFMT_VDPAU 0x1DC80000 + #define IMGFMT_VDPAU_MASK 0xFFFF0000 +@@ -193,7 +213,9 @@ + #define IMGFMT_VDPAU_VC1 (IMGFMT_VDPAU|0x05) + #define IMGFMT_VDPAU_MPEG4 (IMGFMT_VDPAU|0x06) + +-#define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VDPAU(fmt) || IMGFMT_IS_XVMC(fmt)) ++#define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VAAPI(fmt) || \ ++ IMGFMT_IS_VDPAU(fmt) || \ ++ IMGFMT_IS_XVMC(fmt)) + + typedef struct { + void* data; +diff --git a/libmpcodecs/vd.c b/libmpcodecs/vd.c +index bdec830..63a7df8 100644 +--- a/libmpcodecs/vd.c ++++ b/libmpcodecs/vd.c +@@ -403,3 +403,12 @@ void mpcodecs_draw_slice(sh_video_t *sh, unsigned char **src, int *stride, + if (vf->draw_slice) + vf->draw_slice(vf, src, stride, w, h, x, y); + } ++ ++void *mpcodecs_get_hwaccel_context(sh_video_t *sh) ++{ ++ void *ctx = NULL; ++ struct vf_instance *vf = sh->vfilter; ++ if (vf->control(vf, VFCTRL_GET_HWACCEL_CONTEXT, &ctx) == CONTROL_TRUE) ++ return ctx; ++ return NULL; ++} +diff --git a/libmpcodecs/vd.h b/libmpcodecs/vd.h +index 8f7c238..e655d60 100644 +--- a/libmpcodecs/vd.h ++++ b/libmpcodecs/vd.h +@@ -64,6 +64,7 @@ extern const m_option_t xvid_dec_opts[]; + int mpcodecs_config_vo(sh_video_t *sh, int w, int h, unsigned int preferred_outfmt); + mp_image_t* mpcodecs_get_image(sh_video_t *sh, int mp_imgtype, int mp_imgflag, int w, int h); + void mpcodecs_draw_slice(sh_video_t *sh, unsigned char** src, int* stride, int w,int h, int x, int y); ++void *mpcodecs_get_hwaccel_context(sh_video_t *sh); + + #define VDFLAGS_DROPFRAME 3 + +diff --git a/libmpcodecs/vd_ffmpeg.c b/libmpcodecs/vd_ffmpeg.c +index 7c68a20..609ac41 100644 +--- a/libmpcodecs/vd_ffmpeg.c ++++ b/libmpcodecs/vd_ffmpeg.c +@@ -33,6 +33,7 @@ + + #include "vd_internal.h" + #include "vd_ffmpeg.h" ++#include "dec_video.h" + + static const vd_info_t info = { + "FFmpeg's libavcodec codec family", +@@ -232,7 +233,7 @@ static void set_format_params(struct AVCodecContext *avctx, enum PixelFormat fmt + int imgfmt; + if (fmt == PIX_FMT_NONE) + return; +- imgfmt = pixfmt2imgfmt(fmt); ++ imgfmt = pixfmt2imgfmt(fmt, avctx->codec_id); + if (IMGFMT_IS_HWACCEL(imgfmt)) { + sh_video_t *sh = avctx->opaque; + vd_ffmpeg_ctx *ctx = sh->context; +@@ -295,6 +296,12 @@ static int init(sh_video_t *sh){ + avctx->codec_type = CODEC_TYPE_VIDEO; + avctx->codec_id = lavc_codec->id; + ++#if CONFIG_VAAPI ++ if(get_video_hwaccel() == HWACCEL_VAAPI){ ++ mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_MPCODECS_VAAPIAcceleratedCodec); ++ avctx->get_format = get_format; ++ } ++#endif /* CONFIG_VAAPI */ + #if CONFIG_VDPAU + if(lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU){ + avctx->get_format = get_format; +@@ -487,7 +494,7 @@ static void draw_slice(struct AVCodecContext *s, + const AVFrame *src, int offset[4], + int y, int type, int height){ + sh_video_t *sh = s->opaque; +- 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 0 + int start=0, i; +@@ -571,9 +578,10 @@ static int init_vo(sh_video_t *sh, enum PixelFormat pix_fmt){ + sh->disp_w = width; + sh->disp_h = height; + ctx->pix_fmt = pix_fmt; +- ctx->best_csp = pixfmt2imgfmt(pix_fmt); ++ ctx->best_csp = pixfmt2imgfmt(pix_fmt, avctx->codec_id); + if (!mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, ctx->best_csp)) + return -1; ++ avctx->hwaccel_context = mpcodecs_get_hwaccel_context(sh); + ctx->vo_initialized = 1; + } + return 0; +@@ -972,24 +980,62 @@ static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){ + return mpi; + } + +-#if CONFIG_XVMC || CONFIG_VDPAU ++#if CONFIG_XVMC || CONFIG_VAAPI || CONFIG_VDPAU ++static inline int is_hwaccel_format(int imgfmt) ++{ ++ switch (get_video_hwaccel()) { ++ case HWACCEL_VAAPI: return IMGFMT_IS_VAAPI(imgfmt) != 0; ++ case HWACCEL_VDPAU: return IMGFMT_IS_VDPAU(imgfmt) != 0; ++ case HWACCEL_XVMC: return IMGFMT_IS_XVMC(imgfmt) != 0; ++ } ++ return 0; ++} ++ ++static int query_format(sh_video_t *sh, int fmt) ++{ ++ vd_ffmpeg_ctx * const ctx = sh->context; ++ AVCodecContext * const avctx = ctx->avctx; ++ int r, width, height; ++ /* XXX: some codecs have not initialized width and height yet at ++ this point, so we are faking the dimensions so that init_vo() ++ doesn't fail because of 0x0 size */ ++ if ((width = avctx->width) == 0) ++ avctx->width = 64; ++ if ((height = avctx->height) == 0) ++ avctx->height = 64; ++ r = init_vo(sh, fmt); ++ avctx->width = width; ++ avctx->height = height; ++ return r; ++} ++ + static enum PixelFormat get_format(struct AVCodecContext *avctx, +- const enum PixelFormat *fmt){ +- enum PixelFormat selected_format; ++ const enum PixelFormat *fmt){ ++ enum PixelFormat selected_format = PIX_FMT_NONE; + int imgfmt; + sh_video_t *sh = avctx->opaque; +- int i; +- +- for(i=0;fmt[i]!=PIX_FMT_NONE;i++){ +- imgfmt = pixfmt2imgfmt(fmt[i]); +- if(!IMGFMT_IS_HWACCEL(imgfmt)) continue; +- mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_MPCODECS_TryingPixfmt, i); +- if(init_vo(sh, fmt[i]) >= 0) { +- break; ++ int i, try_hwaccel; ++ ++ for (try_hwaccel = 1; try_hwaccel >= 0; --try_hwaccel) { ++ for (i = 0; fmt[i] != PIX_FMT_NONE; i++) { ++ imgfmt = pixfmt2imgfmt(fmt[i], avctx->codec_id); ++ if ((try_hwaccel ^ is_hwaccel_format(imgfmt)) != 0) ++ continue; ++ mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_MPCODECS_TryingPixfmt, i); ++ if (query_format(sh, fmt[i]) >= 0) { ++ if (try_hwaccel) { ++ /* don't allow format conversion for HW acceleration */ ++ if (sh->codec->outfmt[sh->outfmtidx] != imgfmt) ++ continue; ++ } ++ selected_format = fmt[i]; ++ break; ++ } + } ++ if (selected_format != PIX_FMT_NONE) ++ break; + } +- selected_format = fmt[i]; + set_format_params(avctx, selected_format); + return selected_format; + } +-#endif /* CONFIG_XVMC || CONFIG_VDPAU */ ++#endif /* CONFIG_XVMC || CONFIG_VAAPI || CONFIG_VDPAU */ +diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h +index 3619e69..fd869b7 100644 +--- a/libmpcodecs/vf.h ++++ b/libmpcodecs/vf.h +@@ -111,6 +111,7 @@ typedef struct vf_seteq_s + #define VFCTRL_GET_PTS 17 /* Return last pts value that reached vf_vo*/ + #define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */ + #define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */ ++#define VFCTRL_GET_HWACCEL_CONTEXT 20 /* Get HW accelerator context */ + + #include "vfcap.h" + +diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c +index b598214..da9e930 100644 +--- a/libmpcodecs/vf_vo.c ++++ b/libmpcodecs/vf_vo.c +@@ -138,6 +138,12 @@ static int control(struct vf_instance *vf, int request, void* data) + *(double *)data = vf->priv->pts; + return CONTROL_TRUE; + } ++ case VFCTRL_GET_HWACCEL_CONTEXT: ++ { ++ if(!video_out) return CONTROL_FALSE; // vo not configured? ++ return(video_out->control(VOCTRL_GET_HWACCEL_CONTEXT, data) ++ == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE; ++ } + } + // return video_out->control(request,data); + return CONTROL_UNKNOWN; +diff --git a/libvo/gl_common.c b/libvo/gl_common.c +index 116cebb..8f344f6 100644 +--- a/libvo/gl_common.c ++++ b/libvo/gl_common.c +@@ -141,6 +141,11 @@ void* (GLAPIENTRY *mpglAllocateMemoryMESA)(void *, int, size_t, float, float, fl + void (GLAPIENTRY *mpglFreeMemoryMESA)(void *, int, void *); + /** \} */ // end of glextfunctions group + ++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 +@@ -470,6 +475,10 @@ static const extfunc_desc_t extfuncs[] = { + {&mpglTexImage3D, NULL, {"glTexImage3D", NULL}}, + {&mpglAllocateMemoryMESA, "GLX_MESA_allocate_memory", {"glXAllocateMemoryMESA", NULL}}, + {&mpglFreeMemoryMESA, "GLX_MESA_allocate_memory", {"glXFreeMemoryMESA", NULL}}, ++ {&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} + }; + +diff --git a/libvo/gl_common.h b/libvo/gl_common.h +index d44e96f..fd8677b 100644 +--- a/libvo/gl_common.h ++++ b/libvo/gl_common.h +@@ -510,4 +510,9 @@ extern void (GLAPIENTRY *mpglTexImage3D)(GLenum, GLint, GLenum, GLsizei, GLsizei + 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 */ +diff --git a/libvo/stats.c b/libvo/stats.c +new file mode 100644 +index 0000000..c4ff0ca +--- /dev/null ++++ b/libvo/stats.c +@@ -0,0 +1,217 @@ ++#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; ++} +diff --git a/libvo/stats.h b/libvo/stats.h +new file mode 100644 +index 0000000..62e7412 +--- /dev/null ++++ b/libvo/stats.h +@@ -0,0 +1,21 @@ ++#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 */ +diff --git a/libvo/video_out.c b/libvo/video_out.c +index 83f2a24..d22d214 100644 +--- a/libvo/video_out.c ++++ b/libvo/video_out.c +@@ -94,6 +94,7 @@ extern const vo_functions_t video_out_mga; + 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; +@@ -291,6 +292,9 @@ const vo_functions_t* const video_out_drivers[] = + #ifdef CONFIG_MD5SUM + &video_out_md5sum, + #endif ++#if CONFIG_VAAPI ++ &video_out_vaapi, ++#endif + NULL + }; + +diff --git a/libvo/video_out.h b/libvo/video_out.h +index cbbea66..7bd3006 100644 +--- a/libvo/video_out.h ++++ b/libvo/video_out.h +@@ -80,6 +80,10 @@ + + #define VOCTRL_UPDATE_SCREENINFO 32 + ++// Return current HW acceleration context ++// void *get_hwaccel_context(void); ++#define VOCTRL_GET_HWACCEL_CONTEXT 33 ++ + // Vo can be used by xover + #define VOCTRL_XOVERLAY_SUPPORT 22 + +diff --git a/libvo/vo_vaapi.c b/libvo/vo_vaapi.c +new file mode 100644 +index 0000000..9d46485 +--- /dev/null ++++ b/libvo/vo_vaapi.c +@@ -0,0 +1,2737 @@ ++/* ++ * 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 <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 ++ ++static vo_info_t info = { ++ "VA API with X11", ++ "vaapi", ++ "Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>", ++ "" ++}; ++ ++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; ++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); ++ PROFILE(H264Baseline); ++ PROFILE(H264Main); ++ PROFILE(H264High); ++ PROFILE(VC1Simple); ++ PROFILE(VC1Main); ++ PROFILE(VC1Advanced); ++#undef PROFILE ++ } ++ 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); ++#undef ENTRYPOINT ++ } ++ 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 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; ++ 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; ++ ++#ifdef CONFIG_GUI ++ 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, mipmap, 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; ++ mipmap = 0; ++ 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)); ++ ++ 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]; ++ ++ 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[]) ++{ ++ mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_X11_DrawFrameCalled); ++ ++ return -1; ++} ++ ++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: { ++ va_list ap; ++ int value; ++ ++ va_start(ap, data); ++ value = va_arg(ap, int); ++ ++ va_end(ap); ++ return set_equalizer(data, value); ++ } ++ case VOCTRL_GET_EQUALIZER: { ++ va_list ap; ++ int *value; ++ ++ va_start(ap, data); ++ value = va_arg(ap, int *); ++ ++ va_end(ap); ++ return get_equalizer(data, 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; ++ 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; ++} |