Index: configure
===================================================================
--- configure	(revision 25144)
+++ configure	(working copy)
@@ -128,6 +128,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
   --disable-opengl-video   disable OpenGL based video display
   --enable-mac-accel       enable Mac OS X MPEG acceleration
   --disable-opengl-vsync   disable OpenGL vsync method
@@ -1336,6 +1337,7 @@
     dvdv
     opengl
     vdpau
+    vaapi
 '
 
 CMDLINE_SELECT="
@@ -1678,6 +1680,7 @@
 xvmc_deps="xv X11_extensions_XvMClib_h"
 xvmc_vld_deps="xvmc X11_extensions_vldXvMC_h"
 xvmcw_deps="xvmc"
+vaapi_deps="opengl_video"
 
 # default parameters
 pre_logfile="config.ep"
@@ -3394,6 +3397,8 @@
 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 X11/extensions/XvMClib.h
 
 check_struct dxva2api.h DXVA_PictureParameters wDecodedPictureIndex
@@ -3662,6 +3667,10 @@
       disable vdpau; }
 fi
 
+if ! disabled vaapi && enabled va_va_h; then
+    enable vaapi
+fi
+
 enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel"
 enabled debug && add_cxxflags -g"$debuglevel"
 
@@ -4219,6 +4228,7 @@
   echo "XvMC libs                 $VENDOR_XVMC_LIBS"
 fi
   echo "VDPAU support             ${vdpau-no}"
+  echo "VAAPI support             ${vaapi-no}"
 fi
   echo "OpenGL video              ${opengl_video-no}"
   if test x"$target_os" = x"darwin" ; then
Index: libs/libmythtv/videoout_openglvaapi.h
===================================================================
--- libs/libmythtv/videoout_openglvaapi.h	(revision 0)
+++ libs/libmythtv/videoout_openglvaapi.h	(revision 0)
@@ -0,0 +1,45 @@
+#ifndef VIDEOOUTPUTOPENGLVAAPI_H
+#define VIDEOOUTPUTOPENGLVAAPI_H
+
+#include "videoout_opengl.h"
+#include "vaapicontext.h"
+
+class VideoOutputOpenGLVAAPI : public VideoOutputOpenGL
+{
+  public:
+    static void GetRenderOptions(render_opts &opts, QStringList &cpudeints);
+
+    VideoOutputOpenGLVAAPI(MythCodecID codec_id);
+   ~VideoOutputOpenGLVAAPI();
+
+    bool  Init(int width, int height, float aspect, WId winid,
+               int winx, int winy, int winw, int winh, WId embedid = 0);
+    bool  InitVAAPIContext(QSize size);
+    bool  CreateBuffers(void);
+    void* GetVAAPIContext(void);
+    void  SetProfile(void);
+    virtual void TearDown(void);
+    virtual bool InputChanged(const QSize &input_size, float aspect,
+                              MythCodecID  av_codec_id, void *codec_private,
+                              bool &aspect_only);
+    uint8_t* GetSurfaceIDPointer(void* buf);
+    void ProcessFrame(VideoFrame *frame, OSD *osd,
+                              FilterChain *filterList,
+                              const PIPMap &pipPlayers,
+                              FrameScanType scan);
+    void Show(FrameScanType );
+
+    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:
+    MythCodecID   m_codec_id;
+    VAAPIContext *m_ctx;
+};
+
+#endif // VIDEOOUTPUTOPENGLVAAPI_H
+
Index: libs/libmythtv/videoout_opengl.cpp
===================================================================
--- libs/libmythtv/videoout_opengl.cpp	(revision 25144)
+++ libs/libmythtv/videoout_opengl.cpp	(working copy)
@@ -9,23 +9,15 @@
 #include "mythuihelper.h"
 
 #define LOC      QString("VidOutOGL: ")
-#define LOC_ERR  QString("VidOutOGL: ")
+#define LOC_ERR  QString("VidOutOGL Error: ")
 
 void VideoOutputOpenGL::GetRenderOptions(render_opts &opts,
                                          QStringList &cpudeints)
 {
     opts.renderers->append("opengl");
     opts.deints->insert("opengl", cpudeints);
-    (*opts.deints)["opengl"].append("opengllinearblend");
-    (*opts.deints)["opengl"].append("openglonefield");
-    (*opts.deints)["opengl"].append("openglkerneldeint");
     (*opts.deints)["opengl"].append("bobdeint");
-    (*opts.deints)["opengl"].append("openglbobdeint");
-    (*opts.deints)["opengl"].append("opengldoubleratelinearblend");
-    (*opts.deints)["opengl"].append("opengldoubleratekerneldeint");
-    (*opts.deints)["opengl"].append("opengldoubleratefieldorder");
-    (*opts.deints)["opengl"].append("opengldoublerateyadif");
-    (*opts.deints)["opengl"].append("openglyadif");
+    opts.deints->insert("opengl", VideoOutputOpenGL::GetOpenGLDeints());
     (*opts.osds)["opengl"].append("softblend");
     (*opts.osds)["opengl"].append("opengl2");
     (*opts.safe_renderers)["dummy"].append("opengl");
@@ -37,6 +29,21 @@
     opts.priorities->insert("opengl", 65);
 }
 
+QStringList VideoOutputOpenGL::GetOpenGLDeints(void)
+{
+    QStringList result;
+    result.append("opengllinearblend");
+    result.append("openglonefield");
+    result.append("openglkerneldeint");
+    result.append("openglbobdeint");
+    result.append("opengldoubleratelinearblend");
+    result.append("opengldoubleratekerneldeint");
+    result.append("opengldoubleratefieldorder");
+    result.append("opengldoublerateyadif");
+    result.append("openglyadif");
+    return result;
+}
+
 VideoOutputOpenGL::VideoOutputOpenGL(void)
     : VideoOutput(),
     gl_context_lock(QMutex::Recursive),
@@ -123,12 +130,12 @@
                       winid, winx, winy, winw, winh,
                       embedid);
 
-    if (db_vdisp_profile)
-        db_vdisp_profile->SetVideoRenderer("opengl");
+    SetProfile();
 
     success &= SetupContext();
     InitDisplayMeasurements(width, height, false);
     success &= CreateBuffers();
+    success &= CreatePauseFrame();
     success &= SetupOpenGL();
 
     InitOSD();
@@ -144,6 +151,12 @@
     return success;
 }
 
+void VideoOutputOpenGL::SetProfile(void)
+{
+    if (db_vdisp_profile)
+        db_vdisp_profile->SetVideoRenderer("opengl");
+}
+
 bool VideoOutputOpenGL::InputChanged(const QSize &input_size,
                                      float        aspect,
                                      MythCodecID  av_codec_id,
@@ -276,12 +289,13 @@
 bool VideoOutputOpenGL::CreateBuffers(void)
 {
     QMutexLocker locker(&gl_context_lock);
-
-    bool success = true;
     vbuffers.Init(31, true, 1, 12, 4, 2, false);
-    success &= vbuffers.CreateBuffers(windows[0].GetVideoDim().width(),
-                                      windows[0].GetVideoDim().height());
+    return vbuffers.CreateBuffers(windows[0].GetVideoDim().width(),
+                                  windows[0].GetVideoDim().height());
+}
 
+bool VideoOutputOpenGL::CreatePauseFrame(void)
+{
     av_pause_frame.height = vbuffers.GetScratchFrame()->height;
     av_pause_frame.width  = vbuffers.GetScratchFrame()->width;
     av_pause_frame.bpp    = vbuffers.GetScratchFrame()->bpp;
@@ -290,17 +304,12 @@
     av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
 
     if (!av_pause_frame.buf)
-    {
-        success = false;
-    }
-    else
-    {
-        int size = av_pause_frame.width * av_pause_frame.height;
-        memset(av_pause_frame.buf, 0,   size);
-        memset(av_pause_frame.buf + size, 127, size / 2);
-    }
+        return false;
 
-    return success;
+    int size = av_pause_frame.width * av_pause_frame.height;
+    memset(av_pause_frame.buf, 0,   size);
+    memset(av_pause_frame.buf + size, 127, size / 2);
+    return true;
 }
 
 void VideoOutputOpenGL::ProcessFrame(VideoFrame *frame, OSD *osd,
@@ -371,8 +380,8 @@
     framesPlayed = buffer->frameNumber + 1;
     gl_context_lock.unlock();
 
-    if (buffer->codec != FMT_YV12)
-        return;
+    //if (buffer->codec != FMT_YV12)
+    //    return;
 
     gl_videochain->SetVideoRect(vsz_enabled ? vsz_desired_display_rect :
                                               windows[0].GetDisplayVideoRect(),
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 25144)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -49,6 +49,10 @@
 }
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+#include "videoout_openglvaapi.h"
+#endif // USING_VAAPI
+
 extern "C" {
 #include "avutil.h"
 #include "ac3_parser.h"
@@ -92,6 +96,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;
@@ -461,6 +467,11 @@
     opts.decoders->append("vdpau");
     (*opts.equiv_decoders)["vdpau"].append("dummy");
 #endif
+
+#ifdef USING_VAAPI
+    opts.decoders->append("vaapi");
+    (*opts.equiv_decoders)["vaapi"].append("dummy");
+#endif
 }
 
 AvFormatDecoder::AvFormatDecoder(NuppelVideoPlayer *parent,
@@ -1368,6 +1379,25 @@
     return fmt[i];
 }
 
+static bool IS_VAAPI_PIX_FMT(enum PixelFormat fmt)
+{
+    return fmt == PIX_FMT_VAAPI_MOCO ||
+           fmt == PIX_FMT_VAAPI_IDCT ||
+           fmt == PIX_FMT_VAAPI_VLD;
+}
+
+static enum PixelFormat get_format_vaapi(struct AVCodecContext *avctx,
+                                         const enum PixelFormat *fmt)
+{
+    if (!fmt)
+        return PIX_FMT_NONE;
+    int i = 0;
+    for (; fmt[i] != PIX_FMT_NONE ; i++)
+        if (IS_VAAPI_PIX_FMT(fmt[i]))
+            break;
+    return fmt[i];
+}
+
 static bool IS_DR1_PIX_FMT(const enum PixelFormat fmt)
 {
     switch (fmt)
@@ -1439,7 +1469,7 @@
         directrendering = true;
         if (
         !gCoreContext->GetNumSetting("DecodeExtraAudio", 0) &&
-        !CODEC_IS_HWACCEL(codec))
+        !CODEC_IS_HWACCEL(codec)) // FIXME - no VAAPI
     {
         SetLowBuffers(false);
     }
@@ -1473,6 +1503,13 @@
         enc->draw_horiz_band = render_slice_vdpau;
         enc->slice_flags     = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
     }
+    else if (codec && IS_VAAPI_PIX_FMT(enc->pix_fmt))
+    {
+        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; // is this correct?
+    }
     else if (codec && codec->capabilities & CODEC_CAP_DR1)
     {
         enc->flags          |= CODEC_FLAG_EMU_EDGE;
@@ -1955,6 +1992,26 @@
                         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;
+                        enc->pix_fmt = pix_fmt;
+                        if (!no_hardware_decoders &&
+                            codec_is_vaapi_hw(video_codec_id))
+                        {
+                            enc->pix_fmt = pix_fmt;
+                        }
+                    }
+#endif // USING_VAAPI
 #ifdef USING_XVMC
 
                     bool force_xv = no_hardware_decoders;
@@ -2673,6 +2730,39 @@
     }
 }
 
+int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic)
+{
+    AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
+    VideoFrame *frame = nd->GetNVP()->GetNextVideoFrame(false);
+
+    pic->data[0] = frame->buf;
+    pic->data[1] = frame->priv[0];
+    pic->data[2] = frame->priv[1];
+
+    pic->linesize[0] = 0;
+    pic->linesize[1] = 0;
+    pic->linesize[2] = 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->GetNVP()->getVideoOutput())
+    {
+        VideoOutputOpenGLVAAPI *vo =
+            dynamic_cast<VideoOutputOpenGLVAAPI*>(nd->GetNVP()->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: libs/libmythtv/videoout_openglvaapi.cpp
===================================================================
--- libs/libmythtv/videoout_openglvaapi.cpp	(revision 0)
+++ libs/libmythtv/videoout_openglvaapi.cpp	(revision 0)
@@ -0,0 +1,206 @@
+#include "videoout_openglvaapi.h"
+
+#define LOC      QString("VidOutVAAPI: ")
+#define LOC_ERR  QString("VidOutVAAPI Error: ")
+
+void VideoOutputOpenGLVAAPI::GetRenderOptions(render_opts &opts,
+                                              QStringList &cpudeints)
+{
+    opts.renderers->append("openglvaapi");
+    opts.deints->insert("openglvaapi", VideoOutputOpenGL::GetOpenGLDeints());
+    (*opts.osds)["openglvaapi"].append("opengl2");
+
+    if (opts.decoders->contains("vaapi"))
+        (*opts.safe_renderers)["vaapi"].append("openglvaapi");
+
+    opts.priorities->insert("openglvaapi", 110);
+}
+
+VideoOutputOpenGLVAAPI::VideoOutputOpenGLVAAPI(MythCodecID codec_id)
+  : VideoOutputOpenGL(), m_codec_id(codec_id), m_ctx(NULL)
+{
+    if (gCoreContext->GetNumSetting("UseVideoModes", 0))
+        display_res = DisplayRes::GetDisplayRes(true);
+}
+
+VideoOutputOpenGLVAAPI::~VideoOutputOpenGLVAAPI()
+{
+    TearDown();
+}
+
+void VideoOutputOpenGLVAAPI::TearDown(void)
+{
+    VideoOutputOpenGL::TearDown();
+    delete m_ctx;
+}
+
+bool VideoOutputOpenGLVAAPI::Init(int width, int height, float aspect,
+                                  WId winid, int winx, int winy, int winw,
+                                  int winh, WId embedid)
+{
+    if (!InitVAAPIContext(QSize(width, height)))
+        return false;
+    return VideoOutputOpenGL::Init(width, height, aspect, winid, winx, winy,
+                                   winw, winh, embedid);
+}
+
+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")
+            .arg(input_size.width()).arg(input_size.height()).arg(aspect)
+            .arg(toString(av_codec_id)));
+
+    QMutexLocker locker(&gl_context_lock);
+
+    if (!codec_is_vaapi_hw(av_codec_id))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+            QString("New video codec is not supported."));
+        errorState = kError_Unknown;
+        return false;
+    }
+
+    if (input_size == windows[0].GetVideoDim())
+    {
+        if (windows[0].GetVideoAspect() != aspect)
+        {
+            aspect_only = true;
+            VideoAspectRatioChanged(aspect);
+            MoveResize();
+        }
+        return true;
+    }
+
+    TearDown();
+    QRect disp = windows[0].GetDisplayVisibleRect();
+    if (Init(input_size.width(), input_size.height(),
+             aspect, gl_parent_win, disp.left(),  disp.top(),
+             disp.width(), disp.height(), gl_embed_win))
+    {
+        BestDeint();
+        return true;
+    }
+
+    VERBOSE(VB_IMPORTANT, LOC_ERR +
+        QString("Failed to re-initialise video output."));
+    errorState = kError_Unknown;
+
+    return false;
+}
+
+bool VideoOutputOpenGLVAAPI::InitVAAPIContext(QSize size)
+{
+    m_ctx = new VAAPIContext(m_codec_id);
+    if (m_ctx && m_ctx->Create(size))
+        return true;
+    return false;
+}
+
+bool VideoOutputOpenGLVAAPI::CreateBuffers(void)
+{
+    if (!codec_is_vaapi_hw(m_codec_id) || !m_ctx)
+        return false;
+
+    QMutexLocker locker(&gl_context_lock);
+    int num_buffers = m_ctx->GetNumBuffers();
+    const QSize video_dim = windows[0].GetVideoDim();
+    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));
+    }
+    return ok;
+}
+
+void* VideoOutputOpenGLVAAPI::GetVAAPIContext(void)
+{
+    if (m_ctx)
+        return &m_ctx->m_ctx;
+    return NULL;
+}
+
+void VideoOutputOpenGLVAAPI::SetProfile(void)
+{
+    if (db_vdisp_profile)
+        db_vdisp_profile->SetVideoRenderer("openglvaapi");
+}
+
+uint8_t* VideoOutputOpenGLVAAPI::GetSurfaceIDPointer(void* buf)
+{
+    if (m_ctx)
+        return m_ctx->GetSurfaceIDPointer(buf);
+    return NULL;
+}
+
+void VideoOutputOpenGLVAAPI::ProcessFrame(VideoFrame *frame, OSD *osd,
+                                          FilterChain *filterList,
+                                          const PIPMap &pipPlayers,
+                                          FrameScanType scan)
+{
+    QMutexLocker locker(&gl_context_lock);
+    if (!gl_videochain || !gl_context)
+        return;
+
+    OpenGLLocker ctx_lock(gl_context);
+
+    if (!frame)
+    {
+        frame = vbuffers.GetScratchFrame();
+        CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame);
+    }
+
+    if (!windows[0].IsEmbedding())
+    {
+        gl_pipchain_active = NULL;
+        ShowPIPs(frame, pipPlayers);
+    }
+
+    if (m_ctx)
+    {
+        QRect disp = windows[0].GetDisplayVideoRect();
+        m_ctx->ShowSurface(gl_parent_win, disp, frame->buf);
+    }
+}
+
+void VideoOutputOpenGLVAAPI::Show(FrameScanType scan)
+{
+}
+
+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_hw(myth_codec_id)) &&
+         !getenv("NO_VAAPI"))
+    {
+        list += "openglvaapi";
+    }
+    return list;
+}
+
+MythCodecID VideoOutputOpenGLVAAPI::GetBestSupportedCodec(
+    uint width,       uint height,
+    uint stream_type, bool no_acceleration,
+    PixelFormat &pix_fmt)
+{
+    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));
+    use_cpu |= !codec_is_vaapi_hw(test_cid);
+    use_cpu |= !VAAPIContext::IsFormatAccelerated(size, test_cid, pix_fmt);
+    if ((dec != "vaapi") || getenv("NO_VAAPI") || use_cpu)
+        return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
+
+    return test_cid;
+}
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 25144)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -344,6 +344,11 @@
 
     using_glx_proc_addr_arb:DEFINES += USING_GLX_PROC_ADDR_ARB
 
+    using_vaapi: DEFINES += USING_VAAPI
+    using_vaapi: DEFINES += videoout_openglvaapi.h   vaapicontext.h
+    using_vaapi: SOURCES += videoout_openglvaapi.cpp vaapicontext.cpp
+    using_vaapi: LIBS    += -lva -lva-x11
+
     # Misc. frontend
     HEADERS += DetectLetterbox.h
     SOURCES += DetectLetterbox.cpp
Index: libs/libmythtv/vaapicontext.cpp
===================================================================
--- libs/libmythtv/vaapicontext.cpp	(revision 0)
+++ libs/libmythtv/vaapicontext.cpp	(revision 0)
@@ -0,0 +1,348 @@
+#include "mythverbose.h"
+#include "mythxdisplay.h"
+#include "mythcodecid.h"
+
+#include "vaapicontext.h"
+
+#define LOC     QString("VAAPI: ")
+#define LOC_ERR QString("VAAPI Error: ")
+#define NUM_VAAPI_BUFFERS 20
+
+#define INIT_ST \
+  VAStatus va_status; \
+  bool ok = true;
+
+#define CHECK_ST \
+  ok &= (va_status == VA_STATUS_SUCCESS); \
+  if (!ok) { \
+      VERBOSE(VB_GENERAL, LOC_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, LOC_ERR + arg2); \
+  }
+
+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 ";
+    if (VAEntrypointIDCT == entry)       return "IDCT ";
+    if (VAEntrypointMoComp == entry)     return "MC ";
+    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 VAProfileH263Baseline;
+    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;
+}
+
+bool VAAPIContext::IsFormatAccelerated(QSize size, MythCodecID codec,
+                                       PixelFormat &pix_fmt)
+{
+    bool result = false;
+    VAAPIContext *ctx = new VAAPIContext(codec);
+    if (ctx)
+    {
+        result  = ctx->CreateDummy(size);
+        pix_fmt = ctx->GetPixelFormat();
+    }
+    delete ctx;
+    return result;
+}
+
+VAAPIContext::VAAPIContext(MythCodecID codec)
+  : m_codec(codec), m_display(NULL),
+    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));
+}
+
+VAAPIContext::~VAAPIContext()
+{
+    INIT_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_ctx.display)
+    {
+        va_status = vaTerminate(m_ctx.display);
+        CHECK_ST
+    }
+
+    if (m_surfaces)
+        delete [] m_surfaces;
+    if (m_surfaceData)
+        delete [] m_surfaceData;
+
+    delete m_display;
+}
+
+bool VAAPIContext::CreateDummy(QSize size)\
+{
+    m_size = size;
+    bool ok = true;
+    m_display = OpenMythXDisplay();
+    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")
+    return ok;
+}
+
+bool VAAPIContext::Create(QSize size)
+{
+    m_size = size;
+    bool ok = true;
+    m_display = OpenMythXDisplay();
+    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")
+    CREATE_CHECK(InitBuffers(), "Failed to create buffers.")
+    CREATE_CHECK(InitContext(), "Failed to create context")
+    return ok;
+}
+
+bool VAAPIContext::InitDisplay(void)
+{
+    int major_ver, minor_ver;
+    m_ctx.display = vaGetDisplay(m_display->GetDisplay());
+    INIT_ST
+    va_status = vaInitialize(m_ctx.display, &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_ctx.display)));
+    }
+    return ok;
+}
+
+bool VAAPIContext::InitProfiles(void)
+{
+    if (!codec_is_vaapi_hw(m_codec) || !m_ctx.display)
+        return false;
+
+    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, LOC_ERR + "Failed to find supported profile.");
+        return false;
+    }
+
+    if (entry_found > VAEntrypointMoComp)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_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;
+    else if (VAEntrypointIDCT == m_vaEntrypoint)
+        m_pix_fmt = PIX_FMT_VAAPI_IDCT;
+    else if (VAEntrypointMoComp == m_vaEntrypoint)
+        m_pix_fmt = PIX_FMT_VAAPI_MOCO;
+    return true;
+}
+
+bool VAAPIContext::InitBuffers(void)
+{
+    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 > VAEntrypointMoComp)
+        return false;
+
+    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, LOC_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, LOC_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, LOC_ERR + "Failed to create decoder context.");
+        return false;
+    }
+    return true;
+}
+
+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;
+    return (uint8_t*)(uintptr_t)surf->m_id;
+}
+
+void VAAPIContext::ShowSurface(int win, QRect &rect, void* buf)
+{
+    if (!buf)
+        return;
+
+    const vaapi_surface *surf = (vaapi_surface*)buf;
+    INIT_ST
+    va_status = vaPutSurface(m_ctx.display, surf->m_id, win, 0, 0,
+                             m_size.width(), m_size.height(),
+                             rect.left(), rect.top(),
+                             rect.width(), rect.height(),
+                             NULL, 0, 0);
+    CHECK_ST
+}
Index: libs/libmythtv/videoout_opengl.h
===================================================================
--- libs/libmythtv/videoout_opengl.h	(revision 25144)
+++ libs/libmythtv/videoout_opengl.h	(working copy)
@@ -10,22 +10,24 @@
 {
   public:
     static void GetRenderOptions(render_opts &opts, QStringList &cpudeints);
+    static QStringList GetOpenGLDeints(void);
     VideoOutputOpenGL();
-   ~VideoOutputOpenGL();
+    virtual ~VideoOutputOpenGL();
 
-    bool Init(int width, int height, float aspect, WId winid,
-              int winx, int winy, int winw, int winh, WId embedid = 0);
-    void TearDown(void);
+    virtual bool Init(int width, int height, float aspect, WId winid,
+                      int winx, int winy, int winw, int winh, WId embedid = 0);
+    virtual void SetProfile(void);
+    virtual void TearDown(void);
 
     void PrepareFrame(VideoFrame *buffer, FrameScanType, OSD *osd);
-    void ProcessFrame(VideoFrame *frame, OSD *osd,
-                      FilterChain *filterList,
-                      const PIPMap &pipPlayers,
-                      FrameScanType scan);
-    void Show(FrameScanType );
-    bool InputChanged(const QSize &input_size, float aspect,
-                      MythCodecID  av_codec_id, void *codec_private,
-                      bool &aspect_only);
+    virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
+                              FilterChain *filterList,
+                              const PIPMap &pipPlayers,
+                              FrameScanType scan);
+    virtual void Show(FrameScanType );
+    virtual bool InputChanged(const QSize &input_size, float aspect,
+                              MythCodecID  av_codec_id, void *codec_private,
+                              bool &aspect_only);
     DisplayInfo GetDisplayInfo(void);
     void UpdatePauseFrame(void);
     void DrawUnusedRects(bool) { }
@@ -51,8 +53,9 @@
     virtual bool ApproveDeintFilter(const QString& filtername) const;
     virtual MythPainter *GetOSDPainter(void)  { return (MythPainter*)gl_painter; }
 
-  private:
-    bool CreateBuffers(void);
+  protected:
+    virtual bool CreateBuffers(void);
+    bool CreatePauseFrame(void);
     bool SetupContext(void);
     bool SetupOpenGL(void);
     void InitOSD(void);
Index: libs/libmythtv/mythcodecid.h
===================================================================
--- libs/libmythtv/mythcodecid.h	(revision 25144)
+++ libs/libmythtv/mythcodecid.h	(working copy)
@@ -76,6 +76,17 @@
 
     kCodec_VDPAU_END,
 
+    kCodec_VAAPI_BEGIN = kCodec_VDPAU_END,
+
+    kCodec_MPEG1_VAAPI,
+    kCodec_MPEG2_VAAPI,
+    kCodec_H263_VAAPI,
+    kCodec_MPEG4_VAAPI,
+    kCodec_H264_VAAPI,
+    kCodec_VC1_VAAPI,
+    kCodec_WMV3_VAAPI,
+
+    kCodec_VAAPI_END,
 } MythCodecID;
 
 // MythCodecID convenience functions
@@ -93,6 +104,10 @@
                               (id < kCodec_VDPAU_END)
 #define codec_is_vdpau_hw(id) (codec_is_vdpau(id) &&\
                               (id != kCodec_H263_VDPAU))
+#define codec_is_vaapi(id)    (id > kCodec_VAAPI_BEGIN) &&\
+                              (id < kCodec_VAAPI_END)
+#define codec_is_vaapi_hw(id) (codec_is_vaapi(id) &&\
+                              (id != kCodec_H263_VAAPI))
 
 QString get_encoding_type(MythCodecID codecid);
 QString get_decoder_name(MythCodecID codec_id, bool libmpeg2);
Index: libs/libmythtv/mythcodecid.cpp
===================================================================
--- libs/libmythtv/mythcodecid.cpp	(revision 25144)
+++ libs/libmythtv/mythcodecid.cpp	(working copy)
@@ -92,6 +92,21 @@
         case kCodec_WMV3_VDPAU:
             return "WMV3 VDPAU";
 
+        case kCodec_MPEG1_VAAPI:
+            return "MPEG1 VAAPI";
+        case kCodec_MPEG2_VAAPI:
+            return "MPEG2 VAAPI";
+        case kCodec_H263_VAAPI:
+            return "H.263 VAAPI";
+        case kCodec_MPEG4_VAAPI:
+            return "MPEG4 VAAPI";
+        case kCodec_H264_VAAPI:
+            return "H.264 VAAPI";
+        case kCodec_VC1_VAAPI:
+            return "VC1 VAAPI";
+        case kCodec_WMV3_VAAPI:
+            return "WMV3 VAAPI";
+
         default:
             break;
     }
@@ -228,6 +243,34 @@
             vdpau = true;
             break;
 
+        case kCodec_MPEG1_VAAPI:
+            ret = CODEC_ID_MPEG1VIDEO;
+            vld = idct = mc = true;
+            break;
+        case kCodec_MPEG2_VAAPI:
+            ret = CODEC_ID_MPEG2VIDEO;
+            vld = idct = mc = true;
+            break;
+        case kCodec_H263_VAAPI:
+            VERBOSE(VB_IMPORTANT, "Error: VAAPI H.263 not supported by ffmpeg");
+            break;
+        case kCodec_MPEG4_VAAPI:
+            ret = CODEC_ID_MPEG4;
+            vld = true;
+            break;
+        case kCodec_H264_VAAPI:
+            ret = CODEC_ID_H264;
+            vld = true;
+            break;
+        case kCodec_VC1_VAAPI:
+            ret = CODEC_ID_VC1;
+            vld = true;
+            break;
+        case kCodec_WMV3_VAAPI:
+            ret = CODEC_ID_WMV3;
+            vld = true;
+            break;
+
         default:
             VERBOSE(VB_IMPORTANT,
                     QString("Error: MythCodecID %1 has not been "
@@ -283,6 +326,7 @@
         case kCodec_MPEG2_VLD:
         case kCodec_MPEG2_DVDV:
         case kCodec_MPEG2_VDPAU:
+        case kCodec_MPEG2_VAAPI:
             return "MPEG-2";
 
         case kCodec_H263:
@@ -291,6 +335,7 @@
         case kCodec_H263_VLD:
         case kCodec_H263_DVDV:
         case kCodec_H263_VDPAU:
+        case kCodec_H263_VAAPI:
             return "H.263";
 
         case kCodec_NUV_MPEG4:
@@ -300,6 +345,7 @@
         case kCodec_MPEG4_VLD:
         case kCodec_MPEG4_DVDV:
         case kCodec_MPEG4_VDPAU:
+        case kCodec_MPEG4_VAAPI:
             return "MPEG-4";
 
         case kCodec_H264:
@@ -338,5 +384,8 @@
     if (codec_is_vdpau(codec_id))
         return "vdpau";
 
+    if (codec_is_vaapi(codec_id))
+        return "vaapi";
+
     return "ffmpeg";
 }
Index: libs/libmythtv/videooutbase.cpp
===================================================================
--- libs/libmythtv/videooutbase.cpp	(revision 25144)
+++ 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, cpudeints);
+#endif // USING_VAAPI
 }
 
 /**
@@ -143,6 +151,10 @@
     renderers += VideoOutputVDPAU::GetAllowedRenderers(codec_id, video_dim);
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+    renderers += VideoOutputOpenGLVAAPI::GetAllowedRenderers(codec_id, video_dim);
+#endif // USING_VAAPI
+
     VERBOSE(VB_PLAYBACK, LOC + "Allowed renderers: " +
             to_comma_list(renderers));
 
@@ -205,6 +217,11 @@
             vo = new VideoOutputVDPAU(codec_id);
 #endif // USING_VDPAU
 
+#ifdef USING_VAAPI
+        if (renderer == "openglvaapi")
+            vo = new VideoOutputOpenGLVAAPI(codec_id);
+#endif // USING_VAAPI
+
 #ifdef USING_XV
         if (xvlist.contains(renderer))
             vo = new VideoOutputXv(codec_id);
Index: libs/libmythtv/vaapicontext.h
===================================================================
--- libs/libmythtv/vaapicontext.h	(revision 0)
+++ libs/libmythtv/vaapicontext.h	(revision 0)
@@ -0,0 +1,51 @@
+#ifndef VAAPICONTEXT_H
+#define VAAPICONTEXT_H
+
+extern "C" {
+#include "libavcodec/vaapi.h"
+}
+
+#include "va/va.h"
+#include "va/va_x11.h"
+
+struct vaapi_surface
+{
+    VASurfaceID m_id;
+};
+
+class VAAPIContext
+{
+  public:
+    static bool IsFormatAccelerated(QSize size, MythCodecID codec,
+                                    PixelFormat &pix_fmt);
+    VAAPIContext(MythCodecID codec);
+   ~VAAPIContext();
+
+    bool  Create(QSize size);
+    bool  CreateDummy(QSize size);
+    void* GetVideoSurface(int i);
+    int   GetNumBuffers(void)        { return m_numSurfaces; }
+    PixelFormat GetPixelFormat(void) { return m_pix_fmt;     }
+    uint8_t* GetSurfaceIDPointer(void* buf);
+
+    // temp hack
+    void  ShowSurface(int win, QRect &rect, void* buf);
+
+    bool InitDisplay(void);
+    bool InitProfiles(void);
+    bool InitBuffers(void);
+    bool InitContext(void);
+
+    vaapi_context  m_ctx;
+    MythCodecID    m_codec;
+    QSize          m_size;
+    MythXDisplay  *m_display;
+    VAProfile      m_vaProfile;
+    VAEntrypoint   m_vaEntrypoint;
+    PixelFormat    m_pix_fmt;
+    int            m_numSurfaces;
+    VASurfaceID   *m_surfaces;
+    vaapi_surface *m_surfaceData;
+};
+
+#endif // VAAPICONTEXT_H
Index: libs/libmythtv/videodisplayprofile.cpp
===================================================================
--- libs/libmythtv/videodisplayprofile.cpp	(revision 25144)
+++ 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("VA API");
     }
 
     QString ret = decoder;
@@ -691,6 +692,11 @@
             "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 and playback.");
+
     return msg;
 }
 
@@ -1237,6 +1243,12 @@
             "This is the only video renderer for NVidia VDPAU decoding.");
     }
 
+    if (renderer == "openglvaapi")
+    {
+        msg = QObject::tr(
+            "This is the only video renderer for VAAPI decoding.");
+    }
+
     return msg;
 }

