Index: /home/mark/trunk/mythtv/configure
===================================================================
--- /home/mark/trunk/mythtv/configure	(revision 26284)
+++ /home/mark/trunk/mythtv/configure	(working copy)
@@ -125,6 +125,7 @@
   --enable-xvmc-vld        enable XvMC VLD accel. for the Unichrome (Pro) chipset
   --xvmc-lib=LIB           XvMC library override (for crosscompiling)
   --enable-vdpau           enable NVidia VDPAU hardware acceleration.
+  --enable-vaapi           enable VAAPI hardware acceleration
   --enable-crystalhd       enable Broadcom CrystalHD hardware decoder support
   --disable-opengl-video   disable OpenGL based video display
   --disable-quartz-video   disable Mac OS X CoreVideo based video display
@@ -1358,6 +1359,7 @@
     mythtranscode
     opengl
     vdpau
+    vaapi
 '
 
 CMDLINE_SELECT="
@@ -1720,6 +1722,7 @@
 xvmc_deps="xv X11_extensions_XvMClib_h"
 xvmc_vld_deps="xvmc X11_extensions_vldXvMC_h"
 xvmcw_deps="xvmc"
+vaapi_deps="x11 opengl"
 
 <<BLOCKQUOTE
 # tests
@@ -3566,6 +3569,9 @@
 check_header termios.h
 check_header vdpau/vdpau.h
 check_header vdpau/vdpau_x11.h
+check_header va/va.h
+check_header va/va_x11.h
+check_header va/va_glx.h
 check_header X11/extensions/XvMClib.h
 
 check_struct dxva2api.h DXVA_PictureParameters wDecodedPictureIndex
@@ -3844,6 +3850,17 @@
         disable crystalhd;
 fi
 
+if enabled vaapi; then
+    enabled va_va_h && enabled va_va_glx_h && enabled va_va_x11_h || disable vaapi
+    if enabled vaapi; then
+        # TODO check for SDS versions
+        check_cpp_condition va/va.h "VA_VERSION_HEX >= 0x001F0000" ||
+        { echolog "VAAPI requires libva >= 0.31.1" && disable vaapi; }
+    fi
+else
+    disable vaapi
+fi
+
 enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel"
 enabled debug && add_cxxflags -g"$debuglevel"
 
@@ -4405,6 +4422,7 @@
   echo "XvMC libs                 $VENDOR_XVMC_LIBS"
 fi
   echo "VDPAU support             ${vdpau-no}"
+  echo "VAAPI support             ${vaapi-no}"
   echo "CrystalHD support         ${crystalhd-no}"
 fi
   echo "OpenGL video              ${opengl_video-no}"
Index: /home/mark/trunk/mythtv/external/FFmpeg/libavutil/libm.h
===================================================================
--- /home/mark/trunk/mythtv/external/FFmpeg/libavutil/libm.h	(revision 26284)
+++ /home/mark/trunk/mythtv/external/FFmpeg/libavutil/libm.h	(working copy)
@@ -59,10 +59,10 @@
 #endif /* HAVE_LOG2F */
 
 #if !HAVE_LRINT
-static av_always_inline av_const long int lrint(double x)
-{
-    return rint(x);
-}
+//static av_always_inline av_const long int lrint(double x)
+//{
+//    return rint(x);
+//  }
 #endif /* HAVE_LRINT */
 
 #if !HAVE_LRINTF
@@ -73,10 +73,10 @@
 #endif /* HAVE_LRINTF */
 
 #if !HAVE_ROUND
-static av_always_inline av_const double round(double x)
-{
-    return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
-}
+//static av_always_inline av_const double round(double x)
+//{
+//    return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);
+//}
 #endif /* HAVE_ROUND */
 
 #if !HAVE_ROUNDF
Index: /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.h
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.h	(revision 0)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.h	(revision 0)
@@ -0,0 +1,48 @@
+#ifndef VIDEOOUTPUTOPENGLVAAPI_H
+#define VIDEOOUTPUTOPENGLVAAPI_H
+
+#include "videoout_opengl.h"
+#include "vaapicontext.h"
+
+class VideoOutputOpenGLVAAPI : public VideoOutputOpenGL
+{
+  public:
+    static void GetRenderOptions(render_opts &opts);
+
+    VideoOutputOpenGLVAAPI(bool direct_update = false);
+   ~VideoOutputOpenGLVAAPI();
+
+    bool  Init(int width, int height, float aspect, WId winid,
+               int winx, int winy, int winw, int winh,
+               MythCodecID codec_id, WId embedid = 0);
+    bool  CreateVAAPIContext(QSize size);
+    void  DeleteVAAPIContext(void);
+    bool  CreateBuffers(void);
+    void* GetVAAPIContext(void);
+    uint8_t* GetSurfaceIDPointer(void* buf);
+    void  SetProfile(void);
+    void  TearDown(void);
+    bool  InputChanged(const QSize &input_size, float aspect,
+                       MythCodecID  av_codec_id, void *codec_private,
+                       bool &aspect_only);
+    void  ProcessFrame(VideoFrame *frame, OSD *osd,
+                       FilterChain *filterList,
+                       const PIPMap &pipPlayers,
+                       FrameScanType scan);
+    bool  ApproveDeintFilter(const QString& filtername) const;
+    bool  SetDeinterlacingEnabled(bool enable);
+    bool  SetupDeinterlace(bool i, const QString& ovrf="");
+    
+    static QStringList GetAllowedRenderers(MythCodecID myth_codec_id,
+                                           const QSize &video_dim);
+    static MythCodecID GetBestSupportedCodec(uint width, uint height,
+                                             uint stream_type,
+                                             bool no_acceleration,
+                                             PixelFormat &pix_fmt);
+
+  private:
+    VAAPIContext *m_ctx;
+};
+
+#endif // VIDEOOUTPUTOPENGLVAAPI_H
+
Index: /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.cpp	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.cpp	(working copy)
@@ -39,11 +39,12 @@
     opts.priorities->insert("opengl", 65);
 }
 
-VideoOutputOpenGL::VideoOutputOpenGL()
+VideoOutputOpenGL::VideoOutputOpenGL(bool direct_update)
     : VideoOutput(),
     gl_context_lock(QMutex::Recursive),
     gl_context(NULL), gl_videochain(NULL), gl_pipchain_active(NULL),
-    gl_parent_win(0), gl_embed_win(0), gl_painter(NULL)
+    gl_parent_win(0), gl_embed_win(0), gl_painter(NULL),
+    gl_direct_update(direct_update)
 {
     bzero(&av_pause_frame, sizeof(av_pause_frame));
     av_pause_frame.buf = NULL;
@@ -246,10 +247,10 @@
     OpenGLLocker ctx_lock(gl_context);
     gl_videochain = new OpenGLVideo();
     success = gl_videochain->Init(gl_context, db_use_picture_controls,
-                                  window.GetVideoDim(), dvr,
+                                  window.GetActualVideoDim(), dvr,
                                   window.GetDisplayVideoRect(),
                                   window.GetVideoRect(), true,
-                                  GetFilters(), !codec_is_std(video_codec_id),
+                                  GetFilters(), gl_direct_update,
                                   db_letterbox_colour);
     if (success)
     {
Index: /home/mark/trunk/mythtv/libs/libmythtv/avformatdecoder.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/avformatdecoder.cpp	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -52,6 +52,10 @@
 }
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+#include "videoout_openglvaapi.h"
+#endif // USING_VAAPI
+
 extern "C" {
 #include "libavutil/avutil.h"
 #include "libavcodec/ac3_parser.h"
@@ -126,6 +130,8 @@
 void render_slice_vdpau(struct AVCodecContext *s, const AVFrame *src,
                         int offset[4], int y, int type, int height);
 
+int  get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic);
+
 static AVCodec *find_vdpau_decoder(AVCodec *c, enum CodecID id)
 {
     AVCodec *codec = c;
@@ -238,6 +244,11 @@
     (*opts.equiv_decoders)["vdpau"].append("dummy");
 #endif
 
+#ifdef USING_VAAPI
+    opts.decoders->append("vaapi");
+    (*opts.equiv_decoders)["vaapi"].append("dummy");
+#endif
+
     PrivateDecoder::GetDecoders(opts);
 }
 
@@ -1256,6 +1267,13 @@
         enc->draw_horiz_band = render_slice_vdpau;
         enc->slice_flags     = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
     }
+    else if (CODEC_IS_VAAPI(codec, enc))
+    {
+        enc->get_buffer      = get_avf_buffer_vaapi;
+        enc->get_format      = get_format_vaapi;
+        enc->release_buffer  = release_avf_buffer;
+        enc->slice_flags     = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
+    }
     else if (codec && codec->capabilities & CODEC_CAP_DR1)
     {
         enc->flags          |= CODEC_FLAG_EMU_EDGE;
@@ -1801,6 +1819,25 @@
                         handled = true;
                     }
 #endif // USING_VDPAU
+#ifdef USING_VAAPI
+                    MythCodecID vaapi_mcid;
+                    PixelFormat pix_fmt = PIX_FMT_YUV420P;
+                    vaapi_mcid = VideoOutputOpenGLVAAPI::GetBestSupportedCodec(
+                        width, height, mpeg_version(enc->codec_id),
+                        no_hardware_decoders, pix_fmt);
+
+                    if (vaapi_mcid >= video_codec_id)
+                    {
+                        enc->codec_id = (CodecID)myth2av_codecid(vaapi_mcid);
+                        video_codec_id = vaapi_mcid;
+                        handled = true;
+                        if (!no_hardware_decoders &&
+                            codec_is_vaapi(video_codec_id))
+                        {
+                            enc->pix_fmt = pix_fmt;
+                        }
+                    }
+#endif // USING_VAAPI
 #ifdef USING_XVMC
 
                     bool force_xv = no_hardware_decoders;
@@ -2515,6 +2552,37 @@
     }
 }
 
+int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic)
+{
+    AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
+    VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame(false);
+
+    pic->data[0]     = frame->buf;
+    pic->data[1]     = NULL;
+    pic->data[2]     = NULL;
+    pic->data[3]     = NULL;
+    pic->linesize[0] = 0;
+    pic->linesize[1] = 0;
+    pic->linesize[2] = 0;
+    pic->linesize[3] = 0;
+    pic->opaque      = frame;
+    pic->type        = FF_BUFFER_TYPE_USER;
+    pic->age         = 256 * 256 * 256 * 64;
+    frame->pix_fmt   = c->pix_fmt;
+
+#ifdef USING_VAAPI
+    if (nd->GetPlayer()->getVideoOutput())
+    {
+        VideoOutputOpenGLVAAPI *vo =
+            dynamic_cast<VideoOutputOpenGLVAAPI*>(nd->GetPlayer()->getVideoOutput());
+        c->hwaccel_context = (vaapi_context*)vo->GetVAAPIContext();
+        pic->data[3] = vo->GetSurfaceIDPointer(frame->buf);
+    }
+#endif
+
+    return 0;
+}
+
 void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len)
 {
     if (!len)
Index: /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.cpp	(revision 0)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videoout_openglvaapi.cpp	(revision 0)
@@ -0,0 +1,274 @@
+#include "videoout_openglvaapi.h"
+
+#define LOC  QString("VidOutGLVAAPI: ")
+#define ERR  QString("VidOutGLVAAPI Error: ")
+
+void VideoOutputOpenGLVAAPI::GetRenderOptions(render_opts &opts)
+{
+    opts.renderers->append("openglvaapi");
+    opts.renderers->append("openglvaapiglx");
+
+    (*opts.deints)["openglvaapi"].append("vaapionefield");
+    (*opts.deints)["openglvaapi"].append("vaapibobdeint");
+    (*opts.deints)["openglvaapi"].append("none");
+    (*opts.osds)["openglvaapi"].append("opengl2");
+
+    (*opts.deints)["openglvaapiglx"].append("vaapionefield");
+    (*opts.deints)["openglvaapiglx"].append("vaapibobdeint");
+    (*opts.deints)["openglvaapiglx"].append("none");
+    (*opts.osds)["openglvaapiglx"].append("opengl2");
+
+    if (opts.decoders->contains("vaapi"))
+    {
+        (*opts.safe_renderers)["vaapi"].append("openglvaapi");
+        (*opts.safe_renderers)["vaapi"].append("openglvaapiglx");
+    }
+    if (opts.decoders->contains("ffmpeg"))
+    {
+        (*opts.safe_renderers)["ffmpeg"].append("openglvaapi");
+        (*opts.safe_renderers)["ffmpeg"].append("openglvaapiglx");
+    }
+    if (opts.decoders->contains("libmpeg2"))
+    {
+        (*opts.safe_renderers)["libmpeg2"].append("openglvaapi");
+        (*opts.safe_renderers)["libmpeg2"].append("openglvaapiglx");
+    }
+
+    (*opts.safe_renderers)["dummy"].append("openglvaapi");
+    (*opts.safe_renderers)["nuppel"].append("openglvaapi");
+    (*opts.safe_renderers)["dummy"].append("openglvaapiglx");
+    (*opts.safe_renderers)["nuppel"].append("openglvaapiglx");
+
+    opts.priorities->insert("openglvaapi", 100);
+    opts.priorities->insert("openglvaapiglx", 110);
+}
+
+VideoOutputOpenGLVAAPI::VideoOutputOpenGLVAAPI(bool direct_update)
+  : VideoOutputOpenGL(direct_update), m_ctx(NULL)
+{
+    if (gCoreContext->GetNumSetting("UseVideoModes", 0))
+        display_res = DisplayRes::GetDisplayRes(true);
+}
+
+VideoOutputOpenGLVAAPI::~VideoOutputOpenGLVAAPI()
+{
+    TearDown();
+}
+
+void VideoOutputOpenGLVAAPI::TearDown(void)
+{
+    DeleteVAAPIContext();
+}
+
+bool VideoOutputOpenGLVAAPI::InputChanged(const QSize &input_size, float aspect,
+                              MythCodecID  av_codec_id, void *codec_private,
+                              bool &aspect_only)
+{
+    VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
+            .arg(input_size.width()).arg(input_size.height()).arg(aspect)
+            .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
+
+    if (!codec_is_vaapi(av_codec_id))
+        return VideoOutputOpenGL::InputChanged(input_size, aspect, av_codec_id,
+                                               codec_private, aspect_only);
+                                                   
+    QMutexLocker locker(&gl_context_lock);
+    bool cid_changed = (video_codec_id != av_codec_id);
+    bool res_changed = input_size  != window.GetActualVideoDim();
+    bool asp_changed = aspect      != window.GetVideoAspect();
+    
+    if (!res_changed && !cid_changed)
+    {
+        if (asp_changed)
+        {
+            aspect_only = true;
+            VideoAspectRatioChanged(aspect);
+            MoveResize();
+        }
+        return true;
+    }
+
+    TearDown();
+    QRect disp = window.GetDisplayVisibleRect();
+    if (Init(input_size.width(), input_size.height(),
+             aspect, gl_parent_win, disp.left(),  disp.top(),
+             disp.width(), disp.height(), av_codec_id, gl_embed_win))
+    {
+        BestDeint();
+        return true;
+    }
+
+    VERBOSE(VB_IMPORTANT, ERR + QString("Failed to re-initialise video output."));
+    errorState = kError_Unknown;
+
+    return false;
+}
+
+bool VideoOutputOpenGLVAAPI::Init(int width, int height, float aspect,
+                                  WId winid, int winx, int winy, int winw,
+                                  int winh, MythCodecID codec_id, WId embedid)
+{
+    if (codec_is_vaapi(codec_id))
+    {
+        video_codec_id = codec_id;
+        if (!CreateVAAPIContext(QSize(width, height)))
+            return false;
+    }
+
+    return VideoOutputOpenGL::Init(width, height, aspect, winid, winx, winy,
+                                   winw, winh, video_codec_id, embedid);
+}
+
+bool VideoOutputOpenGLVAAPI::CreateVAAPIContext(QSize size)
+{
+    if (m_ctx)
+        DeleteVAAPIContext();
+    m_ctx = new VAAPIContext(video_codec_id, gl_direct_update);
+    if (m_ctx && m_ctx->CreateDisplay(size) && m_ctx->CreateBuffers())
+        return true;
+    VERBOSE(VB_IMPORTANT, ERR + QString("Failed to create VAAPI context."));
+    errorState = kError_Unknown;
+    return false;
+}
+
+void VideoOutputOpenGLVAAPI::DeleteVAAPIContext(void)
+{
+    delete m_ctx;
+    m_ctx = NULL;
+}
+
+bool VideoOutputOpenGLVAAPI::CreateBuffers(void)
+{
+    if ((!codec_is_vaapi(video_codec_id)) || !m_ctx)
+        return VideoOutputOpenGL::CreateBuffers();
+
+    QMutexLocker locker(&gl_context_lock);
+    int num_buffers = m_ctx->GetNumBuffers();
+    const QSize video_dim = window.GetActualVideoDim();
+    vbuffers.Init(num_buffers, true, 2, 1, 4, 1, false); // shouldn't need pause frame
+
+    bool ok = true;
+    for (int i = 0; i < num_buffers; i++)
+    {
+        ok &= vbuffers.CreateBuffer(video_dim.width(),
+                                    video_dim.height(), i,
+                                    m_ctx->GetVideoSurface(i), FMT_VAAPI);
+    }
+    return ok;
+}
+
+void* VideoOutputOpenGLVAAPI::GetVAAPIContext(void)
+{
+    if (m_ctx)
+        return &m_ctx->m_ctx;
+    return NULL;
+}
+
+uint8_t* VideoOutputOpenGLVAAPI::GetSurfaceIDPointer(void* buf)
+{
+    if (m_ctx)
+        return m_ctx->GetSurfaceIDPointer(buf);
+    return NULL;
+}
+
+void VideoOutputOpenGLVAAPI::SetProfile(void)
+{
+    if (db_vdisp_profile)
+        db_vdisp_profile->SetVideoRenderer("openglvaapi");
+}
+
+bool VideoOutputOpenGLVAAPI::ApproveDeintFilter(const QString &filtername) const
+{
+    return filtername.contains("vaapi");
+}
+
+bool VideoOutputOpenGLVAAPI::SetDeinterlacingEnabled(bool enable)
+{
+    m_deinterlacing = enable;
+    SetupDeinterlace(enable);
+    return m_deinterlacing;
+}
+
+bool VideoOutputOpenGLVAAPI::SetupDeinterlace(bool i, const QString& ovrf)
+{
+    m_deinterlacing = i;
+    return m_deinterlacing;
+}
+
+void VideoOutputOpenGLVAAPI::ProcessFrame(VideoFrame *frame, OSD *osd,
+                                          FilterChain *filterList,
+                                          const PIPMap &pipPlayers,
+                                          FrameScanType scan)
+{
+    VideoOutputOpenGL::ProcessFrame(frame, osd, filterList, pipPlayers, scan);
+
+    QMutexLocker locker(&gl_context_lock);
+    if (codec_is_vaapi(video_codec_id) && m_ctx && gl_videochain && frame)
+    {
+        bool success = false;
+        if (gl_direct_update)
+        {
+            gl_context->makeCurrent();
+            uint tex = gl_videochain->GetInputTexture();
+            gl_context->EnableTextures(tex);            
+            success = m_ctx->CopySurfaceToTexture(frame->buf, tex,
+                                                  gl_videochain->GetTextureType(),
+                                                  scan);
+            if (success)
+                gl_videochain->SetInputUpdated();
+            gl_context->doneCurrent();
+        }
+        else
+        {
+            gl_context->makeCurrent();
+            success = m_ctx->FillFrame(frame, gl_videochain);
+            gl_context->doneCurrent();
+        }
+        if (!success)
+            VERBOSE(VB_PLAYBACK, ERR + "Failed to update video texture.");
+    }
+}
+
+QStringList VideoOutputOpenGLVAAPI::GetAllowedRenderers(
+    MythCodecID myth_codec_id, const QSize &video_dim)
+{
+    (void) video_dim;
+    QStringList list;
+    if ((codec_is_std(myth_codec_id) || (codec_is_vaapi(myth_codec_id))) &&
+         !getenv("NO_VAAPI"))
+    {
+        list += "openglvaapi";
+        list += "openglvaapiglx";
+    }
+    return list;
+}
+
+MythCodecID VideoOutputOpenGLVAAPI::GetBestSupportedCodec(
+    uint width,       uint height,
+    uint stream_type, bool no_acceleration,
+    PixelFormat &pix_fmt)
+{
+    static bool debug = true;
+    if (debug)
+    {
+        VERBOSE(VB_IMPORTANT, LOC + "Testing VAAPI codec support");
+        debug = false;
+    }
+
+    QSize size(width, height);
+    bool use_cpu = no_acceleration;
+    VideoDisplayProfile vdp;
+    vdp.SetInput(size);
+    QString dec = vdp.GetDecoder();
+
+    MythCodecID test_cid = (MythCodecID)(kCodec_MPEG1_VAAPI + (stream_type-1));
+    if (codec_is_vaapi(test_cid))
+        use_cpu |= !VAAPIContext::IsFormatAccelerated(size, test_cid, pix_fmt);
+    else
+        use_cpu = true;
+
+    if ((dec != "vaapi") || getenv("NO_VAAPI") || use_cpu)
+        return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
+
+    return test_cid;
+}
Index: /home/mark/trunk/mythtv/libs/libmythtv/libmythtv.pro
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/libmythtv.pro	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/libmythtv.pro	(working copy)
@@ -354,6 +354,11 @@
     using_opengl_video:HEADERS += openglvideo.h   videoout_opengl.h
     using_opengl_video:SOURCES += openglvideo.cpp videoout_opengl.cpp
 
+    using_vaapi: DEFINES += USING_VAAPI
+    using_vaapi: DEFINES += vaapicontext.h   videoout_openglvaapi.h
+    using_vaapi: SOURCES += vaapicontext.cpp videoout_openglvaapi.cpp
+    using_vaapi: LIBS    += -lva -lva-x11 -lva-glx
+
     # Misc. frontend
     HEADERS += DetectLetterbox.h
     SOURCES += DetectLetterbox.cpp
Index: /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.cpp	(revision 0)
+++ /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.cpp	(revision 0)
@@ -0,0 +1,660 @@
+#include "openglvideo.h"
+#include "mythverbose.h"
+#include "mythxdisplay.h"
+#include "mythcodecid.h"
+#include "frame.h"
+#include "vaapicontext.h"
+#include "myth_imgconvert.h"
+
+#define LOC QString("VAAPI: ")
+#define ERR QString("VAAPI Error: ")
+#define NUM_VAAPI_BUFFERS 20
+
+#ifndef VA_FOURCC_I420
+#define VA_FOURCC_I420 0x30323449
+#endif
+
+#define INIT_ST \
+  VAStatus va_status; \
+  bool ok = true;
+
+#define CHECK_ST \
+  ok &= (va_status == VA_STATUS_SUCCESS); \
+  if (!ok) { \
+      VERBOSE(VB_IMPORTANT, ERR + QString("Error at %1:%2 (#%3, %4)") \
+              .arg(__FILE__).arg( __LINE__).arg(va_status) \
+              .arg(vaErrorStr(va_status))); \
+  }
+
+#define CREATE_CHECK(arg1, arg2) \
+  if (ok) \
+  { \
+      ok = arg1; \
+      if (!ok) \
+          VERBOSE(VB_IMPORTANT, ERR + arg2); \
+  }
+
+QString profileToString(VAProfile profile);
+QString entryToString(VAEntrypoint entry);
+VAProfile preferredProfile(MythCodecID codec);
+
+QString profileToString(VAProfile profile)
+{
+    if (VAProfileMPEG2Simple == profile)         return "MPEG2Simple";
+    if (VAProfileMPEG2Main == profile)           return "MPEG2Main";
+    if (VAProfileMPEG4Simple == profile)         return "MPEG4Simple";
+    if (VAProfileMPEG4AdvancedSimple == profile) return "MPEG4AdvSimple";
+    if (VAProfileMPEG4Main == profile)           return "MPEG4Main";
+    if (VAProfileH264Baseline == profile)        return "H264Base";
+    if (VAProfileH264Main == profile)            return "H264Main";
+    if (VAProfileH264High == profile)            return "H264High";
+    if (VAProfileVC1Simple == profile)           return "VC1Simple";
+    if (VAProfileVC1Main == profile)             return "VC1Main";
+    if (VAProfileVC1Advanced == profile)         return "VC1Advanced";
+    if (VAProfileH263Baseline == profile)        return "H263Base";
+    return "Unknown";
+}
+
+QString entryToString(VAEntrypoint entry)
+{
+    if (VAEntrypointVLD == entry)        return "VLD ";
+    if (VAEntrypointIZZ == entry)        return "IZZ (UNSUPPORTED) ";
+    if (VAEntrypointIDCT == entry)       return "IDCT (UNSUPPORTED) ";
+    if (VAEntrypointMoComp == entry)     return "MC (UNSUPPORTED) ";
+    if (VAEntrypointDeblocking == entry) return "Deblock (UNSUPPORTED) ";
+    if (VAEntrypointEncSlice == entry)   return "EncSlice (UNSUPPORTED) ";
+    return "Unknown";
+}
+
+VAProfile preferredProfile(MythCodecID codec)
+{
+    // FIXME handle unsupported codecs properly
+    if (kCodec_H263_VAAPI  == codec) return VAProfileMPEG4AdvancedSimple;
+    if (kCodec_MPEG4_VAAPI == codec) return VAProfileMPEG4AdvancedSimple;
+    if (kCodec_H264_VAAPI  == codec) return VAProfileH264High;
+    if (kCodec_VC1_VAAPI   == codec) return VAProfileVC1Advanced;
+    if (kCodec_WMV3_VAAPI  == codec) return VAProfileVC1Main;
+    return VAProfileMPEG2Main;
+}
+
+class VAAPIDisplay
+{
+  public:
+    VAAPIDisplay() : m_va_disp(NULL), m_x_disp(NULL), m_ref_count(0) { }
+   ~VAAPIDisplay()
+    {
+        if (m_va_disp)
+        {
+            INIT_ST
+            XLOCK(m_x_disp, va_status = vaTerminate(m_va_disp));
+            CHECK_ST
+        }
+        if (m_x_disp)
+        {
+            m_x_disp->Sync(true);
+            delete m_x_disp;
+        }
+    }
+
+    bool Create(bool use_glx)
+    {
+        m_x_disp = OpenMythXDisplay();
+        if (!m_x_disp)
+            return false;
+
+        MythXLocker locker(m_x_disp);
+        int major_ver, minor_ver;
+
+        if (use_glx)
+            m_va_disp = vaGetDisplayGLX(m_x_disp->GetDisplay());
+        else
+            m_va_disp = vaGetDisplay(m_x_disp->GetDisplay());
+
+        if (!m_va_disp)
+        {
+            VERBOSE(VB_IMPORTANT, ERR + "Failed to create VADisplay");
+            return false;
+        }
+
+        INIT_ST
+        va_status = vaInitialize(m_va_disp, &major_ver, &minor_ver);
+        CHECK_ST
+
+        static bool debugged = false;
+        if (ok && !debugged)
+        {
+            debugged = true;
+            VERBOSE(VB_IMPORTANT, LOC + QString("Version: %1.%2")
+                                        .arg(major_ver).arg(minor_ver));
+            VERBOSE(VB_IMPORTANT, LOC + QString("Vendor : %1")
+                                        .arg(vaQueryVendorString(m_va_disp)));
+        }
+        if (ok)
+        {
+            UpRef();
+            VERBOSE(VB_PLAYBACK, LOC +
+                    QString("Created VAAPI display (GLX: %1)").arg(use_glx));
+        }
+        return ok;
+    }
+
+    void UpRef(void)
+    {
+        XLOCK(m_x_disp, m_ref_count++)
+    }
+
+    void DownRef(void)
+    {
+        m_x_disp->Lock();
+        m_ref_count--;
+        if (m_ref_count <= 0)
+        {
+            if (gVAAPIDisplay == this)
+                gVAAPIDisplay = NULL;
+            VERBOSE(VB_PLAYBACK, LOC + "Deleting VAAPI display.");
+            m_x_disp->Unlock();
+            delete this;
+            return;
+        }
+        m_x_disp->Unlock();
+    }
+
+    static VAAPIDisplay* GetDisplay(bool use_glx)
+    {
+        if (gVAAPIDisplay)
+        {
+            gVAAPIDisplay->UpRef();
+            return gVAAPIDisplay;
+        }
+
+        gVAAPIDisplay = new VAAPIDisplay();
+        if (gVAAPIDisplay && gVAAPIDisplay->Create(use_glx))
+            return gVAAPIDisplay;
+
+        delete gVAAPIDisplay;
+        gVAAPIDisplay = NULL;
+        return NULL;
+    }
+
+    static VAAPIDisplay *gVAAPIDisplay;
+    void                *m_va_disp;
+    MythXDisplay        *m_x_disp;
+    int                  m_ref_count;
+};
+
+VAAPIDisplay* VAAPIDisplay::gVAAPIDisplay = NULL;
+
+bool VAAPIContext::IsFormatAccelerated(QSize size, MythCodecID codec,
+                                       PixelFormat &pix_fmt)
+{
+    bool result = false;
+    VAAPIContext *ctx = new VAAPIContext(codec, false);
+    if (ctx)
+    {
+        result  = ctx->CreateDisplay(size);
+        pix_fmt = ctx->GetPixelFormat();
+    }
+    delete ctx;
+    return result;
+}
+
+VAAPIContext::VAAPIContext(MythCodecID codec, bool use_glx)
+  : m_use_glx(use_glx), m_codec(codec),
+    m_vaProfile(VAProfileMPEG2Main)/* ?? */,
+    m_vaEntrypoint(VAEntrypointEncSlice),
+    m_pix_fmt(PIX_FMT_YUV420P), m_numSurfaces(NUM_VAAPI_BUFFERS),
+    m_surfaces(NULL), m_surfaceData(NULL)
+{
+    memset(&m_ctx, 0, sizeof(vaapi_context));
+    memset(&m_image, 0, sizeof(VAImage));
+    init(&m_frame, FMT_NONE, NULL, 0, 0, 0);
+}
+
+VAAPIContext::~VAAPIContext()
+{
+    if (m_frame.buf)
+        delete [] m_frame.buf;
+
+    ClearGLXSurfaces();
+
+    if (m_display)
+    {
+        m_display->m_x_disp->Lock();
+
+        INIT_ST
+        if (m_image.image_id != VA_INVALID_ID)
+        {
+            va_status = vaDestroyImage(m_ctx.display, m_image.image_id);
+            CHECK_ST
+        }
+        if (m_ctx.context_id)
+        {
+            va_status = vaDestroyContext(m_ctx.display, m_ctx.context_id);
+            CHECK_ST
+        }
+        if (m_ctx.config_id)
+        {
+            va_status = vaDestroyConfig(m_ctx.display, m_ctx.config_id);
+            CHECK_ST
+        }
+        if (m_surfaces)
+        {
+            va_status = vaDestroySurfaces(m_ctx.display, m_surfaces, m_numSurfaces);
+            CHECK_ST
+        }
+    }
+
+    if (m_surfaces)
+        delete [] m_surfaces;
+    if (m_surfaceData)
+        delete [] m_surfaceData;
+
+    if (m_display)
+    {
+        m_display->m_x_disp->Unlock();
+        m_display->DownRef();
+    }
+
+    VERBOSE(VB_PLAYBACK, LOC + "Deleted context");
+}
+
+bool VAAPIContext::CreateDisplay(QSize size)\
+{
+    m_size = size;
+    bool ok = true;
+    m_display = VAAPIDisplay::GetDisplay(m_use_glx);
+    CREATE_CHECK(!m_size.isEmpty(), "Invalid size")
+    CREATE_CHECK(m_display != NULL, "Invalid display")
+    CREATE_CHECK(InitDisplay(),     "Invalid VADisplay")
+    CREATE_CHECK(InitProfiles(),    "No supported profiles")
+    if (ok)
+        VERBOSE(VB_PLAYBACK, LOC + QString("Created ctx display (%1x%2->%3x%4)")
+            .arg(size.width()).arg(size.height())
+            .arg(m_size.width()).arg(m_size.height()));
+    return ok;
+}
+
+bool VAAPIContext::CreateBuffers(void)
+{
+    bool ok = true;
+    CREATE_CHECK(!m_size.isEmpty(), "Invalid size")
+    CREATE_CHECK(InitBuffers(),     "Failed to create buffers.")
+    CREATE_CHECK(InitContext(),     "Failed to create context")
+    if (!m_use_glx)
+        CREATE_CHECK(InitImage(), "Failed to create VAImage.")
+    if (ok)
+        VERBOSE(VB_PLAYBACK, LOC + "Created buffers");
+    return ok;
+}
+
+bool VAAPIContext::InitDisplay(void)
+{
+    if (!m_display)
+        return false;
+    m_ctx.display = m_display->m_va_disp;
+    return m_ctx.display;
+}
+
+bool VAAPIContext::InitProfiles(void)
+{
+    if (!(codec_is_vaapi(m_codec)) || !m_ctx.display)
+        return false;
+
+    MythXLocker locker(m_display->m_x_disp);
+    int max_profiles, max_entrypoints;
+    VAProfile profile_wanted = preferredProfile(m_codec);
+    VAProfile profile_found  = VAProfileMPEG2Main;   // FIXME
+    VAEntrypoint entry_found = VAEntrypointEncSlice; // unsupported value
+
+    max_profiles          = vaMaxNumProfiles(m_ctx.display);
+    max_entrypoints       = vaMaxNumEntrypoints(m_ctx.display);
+    VAProfile *profiles   = new VAProfile[max_profiles];
+    VAEntrypoint *entries = new VAEntrypoint[max_entrypoints];
+
+    static bool debugged = false;
+    if (profiles && entries)
+    {
+        INIT_ST
+        int act_profiles, act_entries;
+        va_status = vaQueryConfigProfiles(m_ctx.display,
+                                          profiles,
+                                         &act_profiles);
+        CHECK_ST
+        if (ok && act_profiles > 0)
+        {
+            for (int i = 0; i < act_profiles; i++)
+            {
+                va_status = vaQueryConfigEntrypoints(m_ctx.display,
+                                                     profiles[i],
+                                                     entries,
+                                                    &act_entries);
+                if (va_status == VA_STATUS_SUCCESS && act_entries > 0)
+                {
+                    if (profiles[i] == profile_wanted)
+                    {
+                        profile_found = profile_wanted;
+                        for (int j = 0; j < act_entries; j++)
+                            if (entries[j] < entry_found)
+                                entry_found = entries[j];
+                    }
+
+                    if (!debugged)
+                    {
+                        QString entrylist = "Entrypoints: ";
+                        for (int j = 0; j < act_entries; j++)
+                            entrylist += entryToString(entries[j]);
+                        VERBOSE(VB_IMPORTANT, LOC + QString("Profile: %1 %2")
+                            .arg(profileToString(profiles[i])).arg(entrylist));
+                    }
+                }
+            }
+        }
+        debugged = true;
+    }
+    delete profiles;
+    delete entries;
+
+    VERBOSE(VB_PLAYBACK, LOC + QString("Desired profile for '%1': %2")
+        .arg(toString(m_codec)).arg(profileToString(profile_wanted)));
+    VERBOSE(VB_PLAYBACK, LOC + QString("Found profile %1 with entry %2")
+        .arg(profileToString(profile_found)).arg(entryToString(entry_found)));
+
+    if (profile_wanted != profile_found)
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to find supported profile.");
+        return false;
+    }
+
+    if (entry_found > VAEntrypointVLD)
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to find suitable entry point.");
+        return false;
+    }
+
+    m_vaProfile = profile_wanted;
+    m_vaEntrypoint = entry_found;
+    if (VAEntrypointVLD == m_vaEntrypoint)
+        m_pix_fmt = PIX_FMT_VAAPI_VLD;
+    return true;
+}
+
+bool VAAPIContext::InitBuffers(void)
+{
+    if (!m_ctx.display)
+        return false;
+        
+    MythXLocker locker(m_display->m_x_disp);
+    m_surfaces    = new VASurfaceID[m_numSurfaces];
+    m_surfaceData = new vaapi_surface[m_numSurfaces];
+
+    if (!m_surfaces || !m_surfaceData)
+        return false;
+
+    INIT_ST
+    va_status = vaCreateSurfaces(m_ctx.display, m_size.width(), m_size.height(),
+                                 VA_RT_FORMAT_YUV420, m_numSurfaces,
+                                 m_surfaces);
+    CHECK_ST
+
+    for (int i = 0; i < m_numSurfaces; i++)
+        m_surfaceData[i].m_id = m_surfaces[i];
+    return ok;
+}
+
+bool VAAPIContext::InitContext(void)
+{
+    if (!m_ctx.display || m_vaEntrypoint > VAEntrypointVLD)
+        return false;
+
+    MythXLocker locker(m_display->m_x_disp);
+    VAConfigAttrib attrib;
+    attrib.type = VAConfigAttribRTFormat;
+    INIT_ST
+    va_status = vaGetConfigAttributes(m_ctx.display, m_vaProfile,
+                                      m_vaEntrypoint, &attrib, 1);
+    CHECK_ST
+
+    if (!ok || !(attrib.value & VA_RT_FORMAT_YUV420))
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to confirm YUV420 chroma");
+        return false;
+    }
+
+    va_status = vaCreateConfig(m_ctx.display, m_vaProfile, m_vaEntrypoint,
+                               &attrib, 1, &m_ctx.config_id);
+    CHECK_ST
+    if (!ok)
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to create decoder config.");
+        return false;
+    }
+
+    va_status = vaCreateContext(m_ctx.display, m_ctx.config_id,
+                                m_size.width(), m_size.height(), VA_PROGRESSIVE,
+                                m_surfaces, m_numSurfaces,
+                                &m_ctx.context_id);
+    CHECK_ST
+    if (!ok)
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to create decoder context.");
+        return false;
+    }
+    return true;
+}
+
+bool VAAPIContext::InitImage(void)
+{
+    int count = vaMaxNumImageFormats(m_ctx.display);
+    if (!count)
+        return false;
+
+    INIT_ST
+    VAImageFormat *fmts = new VAImageFormat[count];
+    va_status = vaQueryImageFormats(m_ctx.display, fmts, &count);
+    CHECK_ST
+    if (!ok)
+    {
+        delete [] fmts;
+        return false;
+    }
+
+    for (int i = 0; i < count; i++)
+    {
+        if (!(fmts[i].fourcc == VA_FOURCC_YV12 ||
+              fmts[i].fourcc == VA_FOURCC_NV12 ||
+              fmts[i].fourcc == VA_FOURCC_I420))
+        {
+            continue;
+        }
+
+        VERBOSE(VB_PLAYBACK, LOC + QString("Testing image format %1: %2")
+                .arg(i+1).arg(fourcc_str(fmts[i].fourcc)));
+
+        INIT_ST
+        va_status = vaCreateImage(m_ctx.display, &fmts[i],
+                                  m_size.width(), m_size.height(), &m_image);
+        CHECK_ST
+        if (m_image.image_id == VA_INVALID_ID)
+        {
+            VERBOSE(VB_IMPORTANT, LOC + "Failed to create VAImage");
+            continue;
+        }
+
+        if (m_image.width != m_size.width() || m_image.height != m_size.height())
+            VERBOSE(VB_IMPORTANT, LOC + "VAImage size does not match frame size.");
+
+        va_status = vaGetImage(m_ctx.display, m_surfaces[0], 0, 0,
+                               m_image.width, m_image.height,
+                               m_image.image_id);
+        if (VA_STATUS_SUCCESS == va_status)
+        {
+            VERBOSE(VB_PLAYBACK, LOC + QString("Using %1 image format")
+                    .arg(fourcc_str(fmts[i].fourcc)));
+
+            init(&m_frame, FMT_YV12, NULL, m_image.width, m_image.height,
+                 (m_image.width * m_image.height * 3) / 2);
+
+            if (m_image.format.fourcc == VA_FOURCC_NV12)
+            {
+                m_frame.buf = new unsigned char[m_frame.size];
+            }
+            else
+            {
+                m_frame.pitches[0] = (int)m_image.pitches[0];
+                m_frame.offsets[0] = (int)m_image.offsets[0];
+                int u = m_image.format.fourcc == VA_FOURCC_I420 ? 1 : 2;
+                int v = m_image.format.fourcc == VA_FOURCC_I420 ? 2 : 1;
+                m_frame.pitches[1] = (int)m_image.pitches[u];
+                m_frame.pitches[2] = (int)m_image.pitches[v];
+                m_frame.offsets[1] = (int)m_image.offsets[u];
+                m_frame.offsets[2] = (int)m_image.offsets[v];
+            }
+            return true;
+        }
+        vaDestroyImage(m_ctx.display, m_image.image_id);
+    }
+    return false;
+}
+
+void* VAAPIContext::GetVideoSurface(int i)
+{
+    if (i < 0 || i >= m_numSurfaces)
+        return NULL;
+    return &m_surfaceData[i];
+}
+
+uint8_t* VAAPIContext::GetSurfaceIDPointer(void* buf)
+{
+    if (!buf)
+        return NULL;
+
+    const vaapi_surface *surf = (vaapi_surface*)buf;
+    INIT_ST
+    va_status = vaSyncSurface(m_ctx.display, surf->m_id);
+    CHECK_ST
+    return (uint8_t*)(uintptr_t)surf->m_id;
+}
+
+bool VAAPIContext::FillFrame(VideoFrame *frame, OpenGLVideo *chain)
+{
+    if (!frame || !chain || m_use_glx)
+        return false;
+
+    const vaapi_surface *surf = (vaapi_surface*)frame->buf;
+    if (!surf)
+        return false;
+
+    VASurfaceID id = surf->m_id;
+
+    INIT_ST
+    VASurfaceStatus status;
+    va_status = vaQuerySurfaceStatus(m_ctx.display, id, &status);
+    CHECK_ST
+    if (VASurfaceReady != status)
+    {
+        VERBOSE(VB_PLAYBACK, LOC + QString("Surface not ready %1")
+                .arg(status));
+        return true;
+    }
+
+    m_display->m_x_disp->Lock();
+    va_status = vaGetImage(m_ctx.display, id, 0, 0,
+                           m_image.width, m_image.height,
+                           m_image.image_id);
+    if (!ok)
+        return false;
+
+    uint8_t *buffer = NULL;
+    va_status = vaMapBuffer(m_ctx.display, m_image.buf, (void**)&buffer);
+    CHECK_ST
+    if (!buffer)
+        return false;
+
+    if (m_image.format.fourcc == VA_FOURCC_NV12)
+    {
+        AVPicture img_in, img_out;
+        avpicture_fill(&img_out, (uint8_t *)m_frame.buf, PIX_FMT_YUV420P,
+                       m_image.width, m_image.height);
+        avpicture_fill(&img_in, buffer, PIX_FMT_NV12,
+                       m_image.width, m_image.height);
+        myth_sws_img_convert(&img_out, PIX_FMT_YUV420P, &img_in, PIX_FMT_NV12,
+                       m_image.width, m_image.height);
+    }
+    else
+        m_frame.buf = (unsigned char*)buffer;
+
+    m_frame.interlaced_frame = frame->interlaced_frame;
+    chain->UpdateInputFrame(&m_frame, false);
+    va_status = vaUnmapBuffer(m_ctx.display, m_image.buf);
+    m_display->m_x_disp->Unlock();
+
+    if (m_image.format.fourcc != VA_FOURCC_NV12)
+        m_frame.buf = NULL;
+    CHECK_ST
+    return true;
+}
+
+bool VAAPIContext::CopySurfaceToTexture(const void* buf, uint texture,
+                                        uint texture_type,
+                                        FrameScanType scan)
+{
+    if (!buf || !texture || !m_use_glx)
+        return false;
+
+    const vaapi_surface *surf = (vaapi_surface*)buf;
+    void* glx_surface = GetGLXSurface(texture, texture_type);
+    if (!glx_surface)
+        return false;
+
+    int field = VA_FRAME_PICTURE;
+    if (scan == kScan_Interlaced)
+        field = VA_TOP_FIELD;
+    else if (scan == kScan_Intr2ndField)
+        field = VA_BOTTOM_FIELD;
+    INIT_ST
+    XLOCK(m_display->m_x_disp,
+          va_status = vaCopySurfaceGLX(m_ctx.display, glx_surface,
+                                       surf->m_id, field));
+    CHECK_ST
+    return true;
+}
+
+void* VAAPIContext::GetGLXSurface(uint texture, uint texture_type)
+{
+    if (m_glxSurfaces.contains(texture))
+        return m_glxSurfaces.value(texture);
+
+    void *glx_surface = NULL;
+    INIT_ST
+    XLOCK(m_display->m_x_disp,
+          va_status = vaCreateSurfaceGLX(m_ctx.display, texture_type,
+                                         texture, &glx_surface));
+    CHECK_ST
+    if (!glx_surface)
+    {
+        VERBOSE(VB_IMPORTANT, ERR + "Failed to create GLX surface.");
+        return NULL;
+    }
+
+    m_glxSurfaces.insert(texture, glx_surface);
+
+    VERBOSE(VB_PLAYBACK, LOC + QString("Number of VAAPI GLX surfaces: %1")
+        .arg(m_glxSurfaces.size()));
+    return glx_surface;
+}
+
+void VAAPIContext::ClearGLXSurfaces(void)
+{
+    if (!m_display)
+        return;
+
+    m_display->m_x_disp->Lock();
+    INIT_ST
+    foreach (void* surface, m_glxSurfaces)
+    {
+        va_status = vaDestroySurfaceGLX(m_ctx.display, surface);
+        CHECK_ST
+    }
+    m_glxSurfaces.clear();
+    m_display->m_x_disp->Unlock();
+}
Index: /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.h
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.h	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videoout_opengl.h	(working copy)
@@ -10,7 +10,7 @@
 {
   public:
     static void GetRenderOptions(render_opts &opts, QStringList &cpudeints);
-    VideoOutputOpenGL();
+    VideoOutputOpenGL(bool direct_update = false);
     virtual ~VideoOutputOpenGL();
 
     virtual bool Init(int width, int height, float aspect, WId winid,
@@ -70,6 +70,7 @@
     VideoFrame        av_pause_frame;
 
     MythOpenGLPainter *gl_painter;
+    bool               gl_direct_update;
 };
 
 #endif
Index: /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.h
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.h	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.h	(working copy)
@@ -44,7 +44,7 @@
               QSize videoDim, QRect displayVisibleRect,
               QRect displayVideoRect, QRect videoRect,
               bool viewport_control,  QString options,
-              bool hwaccel,
+              bool force_rgbatex,
               LetterBoxColour letterbox_colour = kLetterBoxColour_Black);
 
     uint GetInputTexture(void);
@@ -128,7 +128,7 @@
     OpenGLFilterType defaultUpsize;
     uint           gl_features;
     bool           using_ycbcrtex;
-    bool           using_hardwaretex;
+    bool           using_rgbatex;
     LetterBoxColour gl_letterbox_colour;
 };
 #endif // _OPENGL_VIDEO_H__
Index: /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.cpp	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/openglvideo.cpp	(working copy)
@@ -84,7 +84,7 @@
     textureRects(false),      textureType(GL_TEXTURE_2D),
     helperTexture(0),         defaultUpsize(kGLFilterResize),
     gl_features(0),           using_ycbcrtex(false),
-    using_hardwaretex(false),
+    using_rgbatex(false),
     gl_letterbox_colour(kLetterBoxColour_Black)
 {
 }
@@ -140,7 +140,7 @@
                        QSize videoDim, QRect displayVisibleRect,
                        QRect displayVideoRect, QRect videoRect,
                        bool viewport_control, QString options,
-                       bool hw_accel,
+                       bool force_rgbatex,
                        LetterBoxColour letterbox_colour)
 {
     gl_context            = glcontext;
@@ -177,11 +177,11 @@
 
     SetViewPort(display_visible_rect.size());
 
-    using_hardwaretex   = hw_accel;
-    bool use_pbo        = !using_hardwaretex && (gl_features & kGLExtPBufObj);
+    using_rgbatex       = force_rgbatex;
+    bool use_pbo        = gl_features & kGLExtPBufObj;
     bool basic_features = gl_features & kGLExtFragProg;
     bool full_features  = basic_features && (gl_features & kGLExtFBufObj);
-    using_ycbcrtex      = !using_hardwaretex && !full_features &&
+    using_ycbcrtex      = !using_rgbatex && !full_features &&
                           (gl_features & kGLMesaYCbCr);
 
     if (using_ycbcrtex)
@@ -196,19 +196,19 @@
                 QString("No OpenGL feature support for Bicubic filter."));
     }
 
-    if (!using_hardwaretex &&
+    if (!using_rgbatex &&
         (defaultUpsize != kGLFilterBicubic) && (gl_features & kGLExtRect))
         textureType = gl_context->GetTextureType(textureRects);
 
     GLuint tex = 0;
     bool    ok = false;
 
-    if (basic_features && !using_hardwaretex)
+    if (basic_features && !using_rgbatex)
     {
         tex = CreateVideoTexture(actual_video_dim, inputTextureSize, use_pbo);
         ok = tex && AddFilter(kGLFilterYUV2RGB);
     }
-    else if (using_ycbcrtex || using_hardwaretex)
+    else if (using_ycbcrtex || using_rgbatex)
     {
         tex = CreateVideoTexture(actual_video_dim,
                                  inputTextureSize, use_pbo);
@@ -216,12 +216,12 @@
         if (ok && using_ycbcrtex)
             VERBOSE(VB_PLAYBACK, LOC + QString("Using GL_MESA_ycbcr_texture for"
                                                " colorspace conversion."));
-        else if (ok && using_hardwaretex)
+        else if (ok && using_rgbatex)
             VERBOSE(VB_PLAYBACK, LOC + QString("Using plain RGBA tex for hw accel."));
         else
         {
             using_ycbcrtex = false;
-            using_hardwaretex = false;
+            using_rgbatex = false;
         }
     }
 
@@ -717,11 +717,6 @@
         tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
                                             GL_UNSIGNED_SHORT_8_8_MESA,
                                             GL_YCBCR_MESA, GL_YCBCR_MESA);
-    else if (using_hardwaretex)
-        tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
-                                            GL_UNSIGNED_BYTE, GL_RGBA,
-                                            GL_RGBA, GL_LINEAR,
-                                            GL_CLAMP_TO_EDGE);
     else
         tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType);
     tex_size = gl_context->GetTextureSize(textureType, size);
@@ -785,6 +780,7 @@
     {
         return;
     }
+
     if (hardwareDeinterlacing)
         RotateTextures();
 
Index: /home/mark/trunk/mythtv/libs/libmythtv/videooutbase.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videooutbase.cpp	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videooutbase.cpp	(working copy)
@@ -40,6 +40,10 @@
 #include "videoout_vdpau.h"
 #endif
 
+#ifdef USING_VAAPI
+#include "videoout_openglvaapi.h"
+#endif
+
 #include "videoout_null.h"
 #include "dithertable.h"
 
@@ -96,6 +100,10 @@
 #ifdef USING_VDPAU
     VideoOutputVDPAU::GetRenderOptions(opts);
 #endif // USING_VDPAU
+
+#ifdef USING_VAAPI
+    VideoOutputOpenGLVAAPI::GetRenderOptions(opts);
+#endif // USING_VAAPI
 }
 
 /**
@@ -143,6 +151,12 @@
     renderers += VideoOutputVDPAU::GetAllowedRenderers(codec_id, video_dim);
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+    const QStringList vaapilist
+            = VideoOutputOpenGLVAAPI::GetAllowedRenderers(codec_id, video_dim);
+    renderers += vaapilist;
+#endif // USING_VAAPI
+
     VERBOSE(VB_PLAYBACK, LOC + "Allowed renderers: " +
             to_comma_list(renderers));
 
@@ -205,6 +219,13 @@
             vo = new VideoOutputVDPAU();
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+        if (renderer == "openglvaapi")
+            vo = new VideoOutputOpenGLVAAPI();
+        if (renderer == "openglvaapiglx")
+            vo = new VideoOutputOpenGLVAAPI(true);
+#endif // USING_VAAPI
+
 #ifdef USING_XV
         if (xvlist.contains(renderer))
             vo = new VideoOutputXv();
Index: /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.h
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.h	(revision 0)
+++ /home/mark/trunk/mythtv/libs/libmythtv/vaapicontext.h	(revision 0)
@@ -0,0 +1,66 @@
+#ifndef VAAPICONTEXT_H
+#define VAAPICONTEXT_H
+
+#include <QHash>
+
+extern "C" {
+#include "libavcodec/vaapi.h"
+}
+#include "va/va.h"
+#include "va/va_x11.h"
+#include "va/va_glx.h"
+
+struct vaapi_surface
+{
+    VASurfaceID m_id;
+};
+
+class VAAPIDisplay;
+class OpenGLVideo;
+
+class VAAPIContext
+{
+  public:
+    static bool IsFormatAccelerated(QSize size, MythCodecID codec,
+                                    PixelFormat &pix_fmt);
+    VAAPIContext(MythCodecID codec, bool use_glx);
+   ~VAAPIContext();
+
+    bool  CreateDisplay(QSize size);
+    bool  CreateBuffers(void);
+    void* GetVideoSurface(int i);
+    uint8_t* GetSurfaceIDPointer(void* buf);
+    
+    int   GetNumBuffers(void)        { return m_numSurfaces; }
+    PixelFormat GetPixelFormat(void) { return m_pix_fmt;     }
+
+    bool FillFrame(VideoFrame *frame, OpenGLVideo *chain);
+
+    bool  CopySurfaceToTexture(const void* buf, uint texture, uint texture_type,
+                               FrameScanType scan);
+    void* GetGLXSurface(uint texture, uint texture_type);
+    void  ClearGLXSurfaces(void);
+
+    bool InitDisplay(void);
+    bool InitProfiles(void);
+    bool InitBuffers(void);
+    bool InitContext(void);
+    bool InitImage(void);
+
+    bool           m_use_glx;
+    vaapi_context  m_ctx;
+    MythCodecID    m_codec;
+    QSize          m_size;
+    VAAPIDisplay  *m_display;
+    VAProfile      m_vaProfile;
+    VAEntrypoint   m_vaEntrypoint;
+    PixelFormat    m_pix_fmt;
+    int            m_numSurfaces;
+    VASurfaceID   *m_surfaces;
+    vaapi_surface *m_surfaceData;
+    QHash<uint, void*> m_glxSurfaces;
+    VAImage        m_image;
+    VideoFrame     m_frame;
+};
+
+#endif // VAAPICONTEXT_H
Index: /home/mark/trunk/mythtv/libs/libmythtv/videodisplayprofile.cpp
===================================================================
--- /home/mark/trunk/mythtv/libs/libmythtv/videodisplayprofile.cpp	(revision 26284)
+++ /home/mark/trunk/mythtv/libs/libmythtv/videodisplayprofile.cpp	(working copy)
@@ -642,6 +642,7 @@
         dec_name["xvmc-vld"] = QObject::tr("VIA XvMC");
         dec_name["macaccel"] = QObject::tr("Mac hardware acceleration");
         dec_name["vdpau"]    = QObject::tr("NVidia VDPAU acceleration");
+        dec_name["vaapi"]    = QObject::tr("VAAPI acceleration");
     }
 
     QString ret = decoder;
@@ -680,7 +681,6 @@
     if (decoder == "xvmc-vld")
         msg += QObject::tr("VIA XvMC will use the VIA VLD XvMC extension.");
 
-
     if (decoder == "macaccel")
         msg += QObject::tr(
             "Mac hardware will try to use the graphics "
@@ -691,6 +691,10 @@
             "VDPAU will attempt to use the graphics hardware to "
             "accelerate video decoding and playback.");
 
+    if (decoder == "vaapi")
+        msg += QObject::tr(
+            "VAAPI will attempt to use the graphics hardware to "
+            "accelerate video decoding.");
     return msg;
 }
 
@@ -748,6 +752,10 @@
         return QObject::tr("Advanced (1x, HW)");
     else if ("vdpauadvanceddoublerate" == short_name)
         return QObject::tr("Advanced (2x, HW)");
+    else if ("vaapionefield" == short_name)
+        return QObject::tr("One Field (1x, HW)");
+    else if ("vaapibobdeint" == short_name)
+        return QObject::tr("Bob (2x, HW)");
 
     return "";
 }
@@ -1237,6 +1245,21 @@
             "This is the only video renderer for NVidia VDPAU decoding.");
     }
 
+    if (renderer == "openglvaapi")
+    {
+        msg = QObject::tr(
+             "This video renderer uses VAAPI for video decoding and "
+             "OpenGL for scaling and color conversion.");
+    }
+
+    if (renderer == "openglvaapiglx")
+    {
+        msg = QObject::tr(
+             "This video renderer uses VAAPI for video decoding and "
+             "OpenGL for scaling and color conversion. Video frames are "
+             "transferred directly from VAAPI to OpenGL.");
+    }
+
     return msg;
 }
 
@@ -1370,6 +1393,10 @@
         msg = kBasicMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
     else if (deint == "vdpauadvanceddoublerate")
         msg = kAdvMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
+    else if (deint == "vaapionefield")
+        msg = kOneFieldMsg + " " + kUsingGPU;
+    else if (deint == "vaapibobdeint")
+        msg = kBobMsg + " " + kUsingGPU;
     else
         msg = QObject::tr("'%1' has not been documented yet.").arg(deint);
 


