diff --git a/mythtv/configure b/mythtv/configure
index f7cfc291b8..2f50f4536c 100755
--- a/mythtv/configure
+++ b/mythtv/configure
@@ -134,6 +134,7 @@ Advanced options (experts only):
   --disable-vdpau          disable NVidia VDPAU hardware acceleration.
   --disable-crystalhd      disable Broadcom CrystalHD hardware decoder support
   --disable-vaapi          disable VAAPI hardware accelerated video decoding
+  --disable-vaapi2         disable VAAPI@ hardware accelerated video decoding
   --disable-openmax        disable OpenMAX hardware accelerated video decoding
   --disable-dxva2          disable hardware accelerated decoding on windows
   --disable-mediacodec     disable hardware accelerated decoding on android
@@ -1401,6 +1402,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST="
     crystalhd
     dxva2
     vaapi
+    vaapi2
     vda
     vdpau
 "
@@ -2040,6 +2042,7 @@ USING_LIST='
     opengl
     opengles
     vaapi
+    vaapi2
     vdpau
     openmax
     mediacodec
@@ -7272,6 +7275,7 @@ if enabled x11 ; then
   echo "xv support                ${xv-no}"
   echo "VDPAU support             ${vdpau-no}"
   echo "VAAPI support             ${vaapi-no}"
+  echo "VAAPI2 support            ${vaapi2-no}"
   echo "CrystalHD support         ${crystalhd-no}"
   echo "OpenMAX support           ${openmax-no}"
   if enabled openmax ; then
diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
index 5b5fce95e8..1e1ba28edc 100644
--- a/mythtv/libs/libmythtv/avformatdecoder.cpp
+++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
@@ -70,6 +70,10 @@ extern "C" {
 #include <QtAndroidExtras>
 #endif
 
+#ifdef USING_VAAPI2
+#include "vaapi2context.h"
+#endif
+
 extern "C" {
 #include "libavutil/avutil.h"
 #include "libavutil/error.h"
@@ -182,6 +186,9 @@ int  get_avf_buffer_dxva2(struct AVCodecContext *c, AVFrame *pic, int flags);
 #ifdef USING_VAAPI
 int  get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic, int flags);
 #endif
+#ifdef USING_VAAPI2
+int  get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic, int flags);
+#endif
 
 static int determinable_frame_size(struct AVCodecContext *avctx)
 {
@@ -248,28 +255,29 @@ static int has_codec_parameters(AVStream *st)
     return 1;
 }
 
-static bool force_sw_decode(AVCodecContext *avctx)
+static bool force_sw_decode(AVCodecContext * /*avctx*/)
 {
-    switch (avctx->codec_id)
-    {
-        case AV_CODEC_ID_H264:
-            switch (avctx->profile)
-            {
-                case FF_PROFILE_H264_HIGH_10:
-                case FF_PROFILE_H264_HIGH_10_INTRA:
-                case FF_PROFILE_H264_HIGH_422:
-                case FF_PROFILE_H264_HIGH_422_INTRA:
-                case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
-                case FF_PROFILE_H264_HIGH_444_INTRA:
-                case FF_PROFILE_H264_CAVLC_444:
-                    return true;
-                default:
-                    break;
-            }
-            break;
-        default:
-            break;
-    }
+    // This is nonsense...
+    // switch (avctx->codec_id)
+    // {
+    //     case AV_CODEC_ID_H264:
+    //         switch (avctx->profile)
+    //         {
+    //             case FF_PROFILE_H264_HIGH_10:
+    //             case FF_PROFILE_H264_HIGH_10_INTRA:
+    //             case FF_PROFILE_H264_HIGH_422:
+    //             case FF_PROFILE_H264_HIGH_422_INTRA:
+    //             case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
+    //             case FF_PROFILE_H264_HIGH_444_INTRA:
+    //             case FF_PROFILE_H264_CAVLC_444:
+    //                 return true;
+    //             default:
+    //                 break;
+    //         }
+    //         break;
+    //     default:
+    //         break;
+    // }
     return false;
 }
 
@@ -385,6 +393,10 @@ void AvFormatDecoder::GetDecoders(render_opts &opts)
     opts.decoders->append("vaapi");
     (*opts.equiv_decoders)["vaapi"].append("dummy");
 #endif
+#ifdef USING_VAAPI2
+    opts.decoders->append("vaapi2");
+    (*opts.equiv_decoders)["vaapi2"].append("dummy");
+#endif
 #ifdef USING_MEDIACODEC
     opts.decoders->append("mediacodec");
     (*opts.equiv_decoders)["mediacodec"].append("dummy");
@@ -1515,7 +1527,7 @@ enum AVPixelFormat get_format_dxva2(struct AVCodecContext *avctx,
 }
 #endif
 
-#ifdef USING_VAAPI
+
 static bool IS_VAAPI_PIX_FMT(enum AVPixelFormat fmt)
 {
     return fmt == AV_PIX_FMT_VAAPI_MOCO ||
@@ -1523,6 +1535,8 @@ static bool IS_VAAPI_PIX_FMT(enum AVPixelFormat fmt)
            fmt == AV_PIX_FMT_VAAPI_VLD;
 }
 
+#ifdef USING_VAAPI
+
 // Declared separately to allow attribute
 static enum AVPixelFormat get_format_vaapi(struct AVCodecContext *,
                                          const enum AVPixelFormat *) MUNUSED;
@@ -1549,6 +1563,30 @@ enum AVPixelFormat get_format_vaapi(struct AVCodecContext *avctx,
 }
 #endif
 
+#ifdef USING_VAAPI2
+static enum AVPixelFormat get_format_vaapi2(struct AVCodecContext *avctx,
+                                           const enum AVPixelFormat *valid_fmts)
+{
+    enum AVPixelFormat ret = AV_PIX_FMT_NONE;
+    while (*valid_fmts != AV_PIX_FMT_NONE) {
+        if (IS_VAAPI_PIX_FMT(*valid_fmts))
+        {
+            ret = *valid_fmts;
+            avctx->pix_fmt = ret;
+            // Vaapi2Context::SetHwframeCtx(avctx, 20);
+            break;
+        }
+        valid_fmts++;
+    }
+
+    // AVBufferRef* dev_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
+    // AVBufferRef* frame_ctx = av_hwframe_ctx_alloc(dev_ctx);
+    // avctx->hw_frames_ctx = frame_ctx;
+    // avctx->hwaccel_context =
+    return ret;
+}
+#endif
+
 #ifdef USING_MEDIACODEC
 static enum AVPixelFormat get_format_mediacodec(struct AVCodecContext *avctx,
                                            const enum AVPixelFormat *valid_fmts)
@@ -1629,7 +1667,7 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
     else
 #endif
 #ifdef USING_VAAPI
-    if (CODEC_IS_VAAPI(codec, enc))
+    if (CODEC_IS_VAAPI(codec, enc) && codec_is_vaapi(video_codec_id))
     {
         enc->get_buffer2     = get_avf_buffer_vaapi;
         enc->get_format      = get_format_vaapi;
@@ -1644,6 +1682,14 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
         enc->slice_flags     = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
     }
     else
+#endif
+#ifdef USING_VAAPI2
+    if (codec_is_vaapi2(video_codec_id))
+    {
+        enc->get_buffer2     = get_avf_buffer_vaapi2;
+        enc->get_format      = get_format_vaapi2;
+    }
+    else
 #endif
     if (codec && codec->capabilities & AV_CODEC_CAP_DR1)
     {
@@ -1659,6 +1705,27 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
                 .arg(ff_codec_id_string(enc->codec_id)));
     }
 
+    MythCodecContext *mctx = gCodecMap->getMythCodecContext(stream, video_codec_id);
+    if (mctx)
+    {
+        mctx->setPlayer(m_parent);
+        int ret = mctx->HwDecoderInit(enc);
+        if (ret < 0)
+        {
+            char error[AV_ERROR_MAX_STRING_SIZE];
+            if (ret < 0)
+            {
+                LOG(VB_GENERAL, LOG_ERR, LOC +
+                    QString("HwDecoderInit unable to initialize hardware decoder: %1 (%2)")
+                    .arg(av_make_error_string(error, sizeof(error), ret))
+                    .arg(ret));
+                // force it to switch to software decoding
+                averror_count = SEQ_PKT_ERR_MAX + 1;
+                m_streams_changed = true;
+            }
+        }
+    }
+
     if (FlagIsSet(kDecodeLowRes)    || FlagIsSet(kDecodeSingleThreaded) ||
         FlagIsSet(kDecodeFewBlocks) || FlagIsSet(kDecodeNoLoopFilter)   ||
         FlagIsSet(kDecodeNoDecode))
@@ -2535,6 +2602,24 @@ int AvFormatDecoder::ScanStreams(bool novideo)
                         foundgpudecoder = true;
                     }
                 }
+#endif // USING_MEDIACODEC
+#ifdef USING_VAAPI2
+                if (!foundgpudecoder)
+                {
+                    MythCodecID vaapi2_mcid;
+                    AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
+                    vaapi2_mcid = Vaapi2Context::GetBestSupportedCodec(
+                        &codec, dec, mpeg_version(enc->codec_id),
+                        pix_fmt);
+
+                    if (codec_is_vaapi2(vaapi2_mcid))
+                    {
+                        gCodecMap->freeCodecContext(ic->streams[selTrack]);
+                        enc = gCodecMap->getCodecContext(ic->streams[selTrack], codec);
+                        video_codec_id = vaapi2_mcid;
+                        foundgpudecoder = true;
+                    }
+                }
 #endif // USING_MEDIACODEC
             }
             // default to mpeg2
@@ -2556,7 +2641,9 @@ int AvFormatDecoder::ScanStreams(bool novideo)
 
             use_frame_timing = false;
             if (! private_dec
-                && (codec_is_std(video_codec_id) || codec_is_mediacodec(video_codec_id)))
+                && (codec_is_std(video_codec_id)
+                    || codec_is_mediacodec(video_codec_id)
+                    || codec_is_vaapi2(video_codec_id)))
                 use_frame_timing = true;
 
             if (FlagIsSet(kDecodeSingleThreaded))
@@ -3056,6 +3143,16 @@ int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic, int /*flags*/)
 }
 #endif
 
+#ifdef USING_VAAPI2
+int get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic, int flags)
+{
+    AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
+
+    nd->directrendering = false;
+    return avcodec_default_get_buffer2(c, pic, flags);
+}
+#endif
+
 void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len, bool scte)
 {
     if (!len)
@@ -3591,6 +3688,8 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
     int retryCount = 0;
     int ret = 0, gotpicture = 0;
     AVCodecContext *context = gCodecMap->getCodecContext(curstream);
+    MythCodecContext *mctx = gCodecMap->getMythCodecContext(curstream);
+    mctx->setPlayer(m_parent);
     MythAVFrame mpa_pic;
     if (!mpa_pic)
     {
@@ -3630,7 +3729,10 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
             //  into separate routines or separate threads.
             //  Also now that it always consumes a whole buffer some code
             //  in the caller may be able to be optimized.
-            ret = avcodec_receive_frame(context, mpa_pic);
+
+            // ret = avcodec_receive_frame(context, mpa_pic);
+            // FilteredReceiveFrame will apply any codec-dependent filtering
+            ret = mctx->FilteredReceiveFrame(context, mpa_pic);
 
             if (ret == 0)
                 gotpicture = 1;
@@ -3671,16 +3773,13 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
                     QString("video avcodec_send_packet error: %1 (%2) gotpicture:%3")
                     .arg(av_make_error_string(error, sizeof(error), ret2))
                     .arg(ret2).arg(gotpicture));
-            if (ret == AVERROR_INVALIDDATA || ret2 == AVERROR_INVALIDDATA)
+            if (++averror_count > SEQ_PKT_ERR_MAX)
             {
-                if (++averror_count > SEQ_PKT_ERR_MAX)
-                {
-                    // If erroring on GPU assist, try switching to software decode
-                    if (codec_is_std(video_codec_id))
-                        m_parent->SetErrored(QObject::tr("Video Decode Error"));
-                    else
-                        m_streams_changed = true;
-                }
+                // If erroring on GPU assist, try switching to software decode
+                if (codec_is_std(video_codec_id))
+                    m_parent->SetErrored(QObject::tr("Video Decode Error"));
+                else
+                    m_streams_changed = true;
             }
             if (ret == AVERROR_EXTERNAL || ret2 == AVERROR_EXTERNAL)
                 m_streams_changed = true;
@@ -3832,6 +3931,9 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
 
     VideoFrame *picframe = (VideoFrame *)(mpa_pic->opaque);
 
+    // if (IS_VAAPI_PIX_FMT((AVPixelFormat)mpa_pic->format))
+    //     directrendering=false;
+
     if (FlagIsSet(kDecodeNoDecode))
     {
         // Do nothing, we just want the pts, captions, subtites, etc.
@@ -3840,6 +3942,26 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
     }
     else if (!directrendering)
     {
+        AVFrame *tmp_frame = NULL;
+        AVFrame *use_frame = NULL;
+
+        if (IS_VAAPI_PIX_FMT((AVPixelFormat)mpa_pic->format))
+        {
+            int ret = 0;
+            tmp_frame = av_frame_alloc();
+            use_frame = tmp_frame;
+            /* retrieve data from GPU to CPU */
+            if ((ret = av_hwframe_transfer_data(use_frame, mpa_pic, 0)) < 0) {
+                LOG(VB_GENERAL, LOG_ERR, LOC
+                    + QString("Error %1 transferring the data to system memory")
+                        .arg(ret));
+                av_frame_free(&use_frame);
+                return false;
+            }
+        }
+        else
+            use_frame = mpa_pic;
+
         AVFrame tmppicture;
 
         VideoFrame *xf = picframe;
@@ -3847,8 +3969,8 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
 
         unsigned char *buf = picframe->buf;
         av_image_fill_arrays(tmppicture.data, tmppicture.linesize,
-            buf, AV_PIX_FMT_YUV420P, context->width,
-                       context->height, IMAGE_ALIGN);
+            buf, AV_PIX_FMT_YUV420P, use_frame->width,
+                       use_frame->height, IMAGE_ALIGN);
         tmppicture.data[0] = buf + picframe->offsets[0];
         tmppicture.data[1] = buf + picframe->offsets[1];
         tmppicture.data[2] = buf + picframe->offsets[2];
@@ -3857,9 +3979,9 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
         tmppicture.linesize[2] = picframe->pitches[2];
 
         QSize dim = get_video_dim(*context);
-        sws_ctx = sws_getCachedContext(sws_ctx, context->width,
-                                       context->height, context->pix_fmt,
-                                       context->width, context->height,
+        sws_ctx = sws_getCachedContext(sws_ctx, use_frame->width,
+                                       use_frame->height, (AVPixelFormat)use_frame->format,
+                                       use_frame->width, use_frame->height,
                                        AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
                                        NULL, NULL, NULL);
         if (!sws_ctx)
@@ -3867,7 +3989,7 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
             LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate sws context");
             return false;
         }
-        sws_scale(sws_ctx, mpa_pic->data, mpa_pic->linesize, 0, dim.height(),
+        sws_scale(sws_ctx, use_frame->data, use_frame->linesize, 0, dim.height(),
                   tmppicture.data, tmppicture.linesize);
 
         if (xf)
@@ -3880,6 +4002,8 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
             xf->aspect = current_aspect;
             m_parent->DiscardVideoFrame(xf);
         }
+        if (tmp_frame)
+            av_frame_free(&tmp_frame);
     }
     else if (!picframe)
     {
diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
index e4dded2157..1ea3785b7d 100644
--- a/mythtv/libs/libmythtv/avformatdecoder.h
+++ b/mythtv/libs/libmythtv/avformatdecoder.h
@@ -206,6 +206,8 @@ class AvFormatDecoder : public DecoderBase
 
     friend int get_avf_buffer(struct AVCodecContext *c, AVFrame *pic,
                               int flags);
+    friend int get_avf_buffer_vaapi2(struct AVCodecContext *c, AVFrame *pic,
+                              int flags);
     friend void release_avf_buffer(void *opaque, uint8_t *data);
 
     friend int open_avf(URLContext *h, const char *filename, int flags);
diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
index 939ca20984..8ffe3b8266 100644
--- a/mythtv/libs/libmythtv/libmythtv.pro
+++ b/mythtv/libs/libmythtv/libmythtv.pro
@@ -366,9 +366,11 @@ using_frontend {
     HEADERS += decoderbase.h
     HEADERS += nuppeldecoder.h          avformatdecoder.h
     HEADERS += privatedecoder.h
+    HEADERS += mythcodeccontext.h
     SOURCES += decoderbase.cpp
     SOURCES += nuppeldecoder.cpp        avformatdecoder.cpp
     SOURCES += privatedecoder.cpp
+    SOURCES += mythcodeccontext.cpp
 
     using_crystalhd {
         DEFINES += USING_CRYSTALHD
@@ -505,6 +507,12 @@ using_frontend {
         using_opengl_video:DEFINES += USING_GLVAAPI
     }
 
+    using_vaapi2 {
+        DEFINES += USING_VAAPI2
+        HEADERS += vaapi2context.h
+        SOURCES += vaapi2context.cpp
+    }
+
     using_mediacodec {
         DEFINES += USING_MEDIACODEC
         HEADERS += mediacodeccontext.h
diff --git a/mythtv/libs/libmythtv/mythavutil.cpp b/mythtv/libs/libmythtv/mythavutil.cpp
index c21aec4456..06eb918bd0 100644
--- a/mythtv/libs/libmythtv/mythavutil.cpp
+++ b/mythtv/libs/libmythtv/mythavutil.cpp
@@ -10,6 +10,7 @@
 #include "mythavutil.h"
 #include "mythcorecontext.h"
 #include "mythconfig.h"
+#include "vaapi2context.h"
 extern "C" {
 #include "libswscale/swscale.h"
 #include "libavfilter/avfilter.h"
@@ -388,7 +389,7 @@ AVCodecContext *MythCodecMap::getCodecContext(const AVStream *stream,
     const AVCodec *pCodec, bool nullCodec)
 {
     QMutexLocker lock(&mapLock);
-    AVCodecContext *avctx = streamMap.value(stream, NULL);
+    AVCodecContext *avctx = streamAvMap.value(stream, NULL);
     if (!avctx)
     {
         if (stream == NULL || stream->codecpar == NULL)
@@ -411,31 +412,49 @@ AVCodecContext *MythCodecMap::getCodecContext(const AVStream *stream,
             avcodec_free_context(&avctx);
         if (avctx)
         {
-            av_codec_set_pkt_timebase(avctx, stream->time_base);
-            streamMap.insert(stream, avctx);
+            avctx->pkt_timebase =  stream->time_base;
+            streamAvMap.insert(stream, avctx);
         }
     }
     return avctx;
 }
 
+MythCodecContext *MythCodecMap::getMythCodecContext(AVStream* stream, MythCodecID codec)
+{
+    QMutexLocker lock(&mapLock);
+    MythCodecContext *mctx = streamMythMap.value(stream, NULL);
+    if (!mctx && codec)
+    {
+        if (codec_is_vaapi2(codec))
+            mctx = new Vaapi2Context(stream);
+        if (!mctx)
+            mctx = new MythCodecContext(stream);
+        streamMythMap.insert(stream, mctx);
+    }
+    return mctx;
+}
+
 AVCodecContext *MythCodecMap::hasCodecContext(const AVStream *stream)
 {
-    return streamMap.value(stream, NULL);
+    return streamAvMap.value(stream, NULL);
 }
 
 void MythCodecMap::freeCodecContext(const AVStream *stream)
 {
     QMutexLocker lock(&mapLock);
-    AVCodecContext *avctx = streamMap.take(stream);
+    AVCodecContext *avctx = streamAvMap.take(stream);
     if (avctx)
         avcodec_free_context(&avctx);
+    MythCodecContext *mctx = streamMythMap.take(stream);
+    if (mctx)
+        delete mctx;
 }
 
 void MythCodecMap::freeAllCodecContexts()
 {
     QMutexLocker lock(&mapLock);
-    QMap<const AVStream*, AVCodecContext*>::iterator i = streamMap.begin();
-    while (i != streamMap.end()) {
+    QMap<const AVStream*, AVCodecContext*>::iterator i = streamAvMap.begin();
+    while (i != streamAvMap.end()) {
         const AVStream *stream = i.key();
         ++i;
         freeCodecContext(stream);
diff --git a/mythtv/libs/libmythtv/mythavutil.h b/mythtv/libs/libmythtv/mythavutil.h
index 1357fe2c54..b14ad3ddd2 100644
--- a/mythtv/libs/libmythtv/mythavutil.h
+++ b/mythtv/libs/libmythtv/mythavutil.h
@@ -11,6 +11,8 @@
 
 #include "mythtvexp.h" // for MUNUSED
 #include "mythframe.h"
+#include "mythcodecid.h"
+
 extern "C" {
 #include "libavcodec/avcodec.h"
 }
@@ -86,6 +88,8 @@ private:
  * This is a singeton class - only 1 instance gets created.
  */
 
+class MythCodecContext;
+
 class MTV_PUBLIC MythCodecMap
 {
   public:
@@ -95,10 +99,13 @@ class MTV_PUBLIC MythCodecMap
     AVCodecContext *getCodecContext(const AVStream*,
         const AVCodec *pCodec = NULL, bool nullCodec = false);
     AVCodecContext *hasCodecContext(const AVStream*);
+    MythCodecContext *getMythCodecContext(AVStream*,
+        const MythCodecID codec = kCodec_NONE);
     void freeCodecContext(const AVStream*);
     void freeAllCodecContexts();
   protected:
-    QMap<const AVStream*, AVCodecContext*> streamMap;
+    QMap<const AVStream*, AVCodecContext*> streamAvMap;
+    QMap<const AVStream*, MythCodecContext*> streamMythMap;
     QMutex mapLock;
 };
 
diff --git a/mythtv/libs/libmythtv/mythcodeccontext.cpp b/mythtv/libs/libmythtv/mythcodeccontext.cpp
new file mode 100644
index 0000000000..1038c81f08
--- /dev/null
+++ b/mythtv/libs/libmythtv/mythcodeccontext.cpp
@@ -0,0 +1,356 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 MythTV Developers <mythtv-dev@mythtv.org>
+//
+// This is part of MythTV (https://www.mythtv.org)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "mythcorecontext.h"
+#include "mythlogging.h"
+#include "mythcodeccontext.h"
+#include "videooutbase.h"
+#include "mythplayer.h"
+
+extern "C" {
+    #include "libavutil/pixfmt.h"
+    #include "libavutil/hwcontext.h"
+    #include "libavcodec/avcodec.h"
+    #include "libavfilter/avfilter.h"
+    #include "libavfilter/buffersink.h"
+    #include "libavfilter/buffersrc.h"
+    #include "libavformat/avformat.h"
+    #include "libavutil/opt.h"
+    #include "libavutil/buffer.h"
+}
+
+#define LOC QString("MythCodecContext: ")
+
+MythCodecContext::MythCodecContext(AVStream* initStream) :
+    stream(initStream),
+    buffersink_ctx(NULL),
+    buffersrc_ctx(NULL),
+    filter_graph(NULL),
+    filtersInitialized(false),
+    hw_frames_ctx(0),
+    player(NULL),
+    ptsUsed(0)
+{
+    priorPts[0] = 0;
+    priorPts[1] = 0;
+}
+
+MythCodecContext::~MythCodecContext()
+{
+    CloseFilters();
+}
+
+QStringList MythCodecContext::MythCodecContext::GetDeinterlacers(QString decodername)
+{
+    QStringList ret;
+#ifdef USING_VAAPI2
+    if (decodername == "vaapi2")
+    {
+        ret.append("vaapi2default");
+        ret.append("vaapi2bob");
+        ret.append("vaapi2weave");
+        ret.append("vaapi2motion_adaptive");
+        ret.append("vaapi2motion_compensated");
+        ret.append("vaapi2doubleratedefault");
+        ret.append("vaapi2doubleratebob");
+        ret.append("vaapi2doublerateweave");
+        ret.append("vaapi2doubleratemotion_adaptive");
+        ret.append("vaapi2doubleratemotion_compensated");
+
+/*
+    "mode", "Deinterlacing mode",
+        "default", "Use the highest-numbered (and therefore possibly most advanced) deinterlacing algorithm",
+        "bob", "Use the bob deinterlacing algorithm",
+        "weave", "Use the weave deinterlacing algorithm",
+        "motion_adaptive", "Use the motion adaptive deinterlacing algorithm",
+        "motion_compensated", "Use the motion compensated deinterlacing algorithm",
+
+    "rate", "Generate output at frame rate or field rate",
+        "frame", "Output at frame rate (one frame of output for each field-pair)",
+        "field", "Output at field rate (one frame of output for each field)",
+
+    "auto", "Only deinterlace fields, passing frames through unchanged",
+        1 = enabled
+        0 = disabled
+*/
+
+    }
+#endif
+    return ret;
+}
+
+
+// Currently this will only set up the filter after an interlaced frame.
+// If we need other filters apart from deinterlace filters we will
+// need to make a change here.
+
+int MythCodecContext::FilteredReceiveFrame(AVCodecContext *ctx, AVFrame *frame)
+{
+    int ret = 0;
+
+    while (1)
+    {
+        if (filter_graph)
+        {
+            ret = av_buffersink_get_frame(buffersink_ctx, frame);
+            if  (ret >= 0)
+            {
+                if (priorPts[0] && ptsUsed == priorPts[1])
+                {
+                    frame->pts = priorPts[1] + (priorPts[1] - priorPts[0])/2;
+                    frame->scte_cc_len = 0;
+                    frame->atsc_cc_len = 0;
+                    av_frame_remove_side_data(frame, AV_FRAME_DATA_A53_CC);
+                }
+                else
+                {
+                    frame->pts = priorPts[1];
+                    ptsUsed = priorPts[1];
+                }
+// {const char *msg = QString("filter pts=%1 interlaced=%2")
+//     .arg(frame->pts).arg(frame->interlaced_frame).toLocal8Bit();
+// fprintf(stderr,"%s\n", msg);}
+            }
+            if  (ret != AVERROR(EAGAIN))
+                break;
+        }
+
+        // EAGAIN or no filter graph
+        ret = avcodec_receive_frame(ctx, frame);
+        if (ret < 0)
+            break;
+// {const char *msg = QString("codec pts=%1 interlaced=%2")
+//     .arg(frame->pts).arg(frame->interlaced_frame).toLocal8Bit();
+// fprintf(stderr,"%s\n", msg);}
+        priorPts[0]=priorPts[1];
+        priorPts[1]=frame->pts;
+        if (frame->interlaced_frame || filter_graph)
+        {
+            if (!filtersInitialized
+              || width != frame->width
+              || height != frame->height)
+            {
+                // bypass any frame of unknown format
+                if (frame->format < 0)
+                    break;
+                ret = InitFilters(ctx, frame);
+                filtersInitialized = true;
+                if (ret < 0)
+                {
+                    LOG(VB_GENERAL, LOG_ERR, LOC + "InitFilters failed - continue without filters");
+                    break;
+                }
+            }
+            if (filter_graph)
+            {
+                ret = av_buffersrc_add_frame(buffersrc_ctx, frame);
+                if (ret < 0)
+                    break;
+            }
+            else
+                break;
+        }
+        else
+            break;
+    }
+
+    return ret;
+}
+
+
+int MythCodecContext::InitFilters(AVCodecContext *ctx, AVFrame *frame)
+{
+    char args[512];
+    int ret = 0;
+    CloseFilters();
+    width = frame->width;
+    height = frame->height;
+    if (!player)
+        return -1;
+    VideoOutput *vo = player->GetVideoOutput();
+    VideoDisplayProfile *vdisp_profile = vo->GetProfile();
+    QString filtername = vdisp_profile->GetFilteredDeint(QString());
+    QString filters = GetDeinterlaceFilter(filtername);
+
+    if (filters.isEmpty())
+        return ret;
+
+    const AVFilter *buffersrc  = avfilter_get_by_name("buffer");
+    const AVFilter *buffersink = avfilter_get_by_name("buffersink");
+    AVFilterInOut *outputs = avfilter_inout_alloc();
+    AVFilterInOut *inputs  = avfilter_inout_alloc();
+    AVRational time_base = stream->time_base;
+    // enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
+    // enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_VAAPI_VLD, AV_PIX_FMT_NONE };
+    AVBufferSrcParameters* params = NULL;
+
+    filter_graph = avfilter_graph_alloc();
+    if (!outputs || !inputs || !filter_graph)
+    {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    /* buffer video source: the decoded frames from the decoder will be inserted here. */
+    snprintf(args, sizeof(args),
+            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+            frame->width, frame->height, frame->format, // ctx->pix_fmt,
+            time_base.num, time_base.den,
+            ctx->sample_aspect_ratio.num, ctx->sample_aspect_ratio.den);
+
+    // isInterlaced = frame->interlaced_frame;
+
+    ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
+                                       args, NULL, filter_graph);
+    if (ret < 0)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC + "avfilter_graph_create_filter failed for buffer source");
+        goto end;
+    }
+
+    params = av_buffersrc_parameters_alloc();
+    // params->format = frame->format;
+    // params->time_base.num = stream->time_base.num;
+    // params->time_base.den = stream->time_base.den;
+    // params->width = frame->width;
+    // params->height = frame->height;
+    // params->sample_aspect_ratio.num = ctx->sample_aspect_ratio.num;
+    // params->sample_aspect_ratio.den = ctx->sample_aspect_ratio.den;
+    if (hw_frames_ctx)
+        av_buffer_unref(&hw_frames_ctx);
+    hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);
+    params->hw_frames_ctx = hw_frames_ctx;
+
+    ret = av_buffersrc_parameters_set(buffersrc_ctx, params);
+
+    if (ret < 0)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC + "av_buffersrc_parameters_set failed");
+        goto end;
+    }
+
+    av_freep(&params);
+
+    /* buffer video sink: to terminate the filter chain. */
+    ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+                                       NULL, NULL, filter_graph);
+    if (ret < 0)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC + "avfilter_graph_create_filter failed for buffer sink");
+        goto end;
+    }
+
+    // ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
+    //                           AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+    // if (ret < 0)
+    // {
+    //     LOG(VB_GENERAL, LOG_ERR, LOC + "av_opt_set_int_list pix_fmts failed");
+    //     goto end;
+    // }
+
+    /*
+     * Set the endpoints for the filter graph. The filter_graph will
+     * be linked to the graph described by filters_descr.
+     */
+
+    /*
+     * The buffer source output must be connected to the input pad of
+     * the first filter described by filters_descr; since the first
+     * filter input label is not specified, it is set to "in" by
+     * default.
+     */
+    outputs->name       = av_strdup("in");
+    outputs->filter_ctx = buffersrc_ctx;
+    outputs->pad_idx    = 0;
+    outputs->next       = NULL;
+
+    /*
+     * The buffer sink input must be connected to the output pad of
+     * the last filter described by filters_descr; since the last
+     * filter output label is not specified, it is set to "out" by
+     * default.
+     */
+    inputs->name       = av_strdup("out");
+    inputs->filter_ctx = buffersink_ctx;
+    inputs->pad_idx    = 0;
+    inputs->next       = NULL;
+
+    if ((ret = avfilter_graph_parse_ptr(filter_graph, filters.toLocal8Bit(),
+                                    &inputs, &outputs,0)) < 0)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC
+            + QString("avfilter_graph_parse_ptr failed for %1").arg(filters));
+        goto end;
+    }
+
+    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC
+            + QString("avfilter_graph_config failed"));
+        goto end;
+    }
+
+    // send the first packet to the filters
+    // frame->pts = frame->best_effort_timestamp;
+    // ret = av_buffersrc_add_frame(buffersrc_ctx, frame);
+    // av_frame_unref(frame);
+
+    // if (ret < 0)
+    // {
+    //     LOG(VB_GENERAL, LOG_ERR, LOC
+    //         + QString("av_buffersrc_add_frame first time failed"));
+    //     goto end;
+    // }
+    LOG(VB_PLAYBACK, LOG_INFO, LOC +
+        QString("Using hardware decoder based deinterlace filter <%1>.")
+            .arg(filters));
+end:
+    if (ret < 0)
+    {
+        avfilter_graph_free(&filter_graph);
+        filter_graph = NULL;
+    }
+    avfilter_inout_free(&inputs);
+    avfilter_inout_free(&outputs);
+
+    return ret;
+}
+
+void MythCodecContext::CloseFilters()
+{
+    avfilter_graph_free(&filter_graph);
+    filter_graph = NULL;
+    buffersink_ctx = NULL;
+    buffersrc_ctx = NULL;
+    filtersInitialized = false;
+    ptsUsed = 0;
+    priorPts[0] = 0;
+    priorPts[1] = 0;
+    // isInterlaced = 0;
+    width = 0;
+    height = 0;
+
+    if (hw_frames_ctx)
+        av_buffer_unref(&hw_frames_ctx);
+}
\ No newline at end of file
diff --git a/mythtv/libs/libmythtv/mythcodeccontext.h b/mythtv/libs/libmythtv/mythcodeccontext.h
new file mode 100644
index 0000000000..95cb1858d6
--- /dev/null
+++ b/mythtv/libs/libmythtv/mythcodeccontext.h
@@ -0,0 +1,66 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 MythTV Developers <mythtv-dev@mythtv.org>
+//
+// This is part of MythTV (https://www.mythtv.org)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef MYTHCODECONTEXT_H
+#define MYTHCODECCONTEXT_H
+
+struct AVCodecContext;
+struct AVFrame;
+struct AVStream;
+struct AVFilterContext;
+struct AVFilterGraph;
+struct AVBufferRef;
+class MythPlayer;
+
+#include "mythtvexp.h"
+
+class MTV_PUBLIC MythCodecContext
+{
+  public:
+    MythCodecContext(AVStream* initStream);
+    virtual ~MythCodecContext();
+    virtual int HwDecoderInit(AVCodecContext * /*ctx*/) { return 0; }
+    virtual int FilteredReceiveFrame(AVCodecContext *ctx, AVFrame *frame);
+    int InitFilters(AVCodecContext *ctx, AVFrame *frame);
+    void CloseFilters();
+    static QStringList GetDeinterlacers(QString decodername);
+    virtual QString GetDeinterlaceFilter(QString /*filtername*/) { return QString(); }
+    void setPlayer(MythPlayer *tPlayer) { player = tPlayer; }
+  protected:
+    AVStream* stream;
+    AVFilterContext *buffersink_ctx;
+    AVFilterContext *buffersrc_ctx;
+    AVFilterGraph *filter_graph;
+    bool filtersInitialized;
+    AVBufferRef *hw_frames_ctx;
+    MythPlayer *player;
+    int64_t priorPts[2];
+    int64_t ptsUsed;
+    // bool isInterlaced;
+    int width;
+    int height;
+};
+
+#endif // MYTHCODECCONTEXT_H
\ No newline at end of file
diff --git a/mythtv/libs/libmythtv/mythcodecid.cpp b/mythtv/libs/libmythtv/mythcodecid.cpp
index b2023512b5..cff4ba0358 100644
--- a/mythtv/libs/libmythtv/mythcodecid.cpp
+++ b/mythtv/libs/libmythtv/mythcodecid.cpp
@@ -123,6 +123,27 @@ QString toString(MythCodecID codecid)
         case kCodec_HEVC_MEDIACODEC:
             return "HEVC MEDIACODEC";
 
+        case kCodec_MPEG1_VAAPI2:
+            return "MPEG1 VAAPI2";
+        case kCodec_MPEG2_VAAPI2:
+            return "MPEG2 VAAPI2";
+        case kCodec_H263_VAAPI2:
+            return "H.263 VAAPI2";
+        case kCodec_MPEG4_VAAPI2:
+            return "MPEG4 VAAPI2";
+        case kCodec_H264_VAAPI2:
+            return "H.264 VAAPI2";
+        case kCodec_VC1_VAAPI2:
+            return "VC1 VAAPI2";
+        case kCodec_WMV3_VAAPI2:
+            return "WMV3 VAAPI2";
+        case kCodec_VP8_VAAPI2:
+            return "VP8 VAAPI2";
+        case kCodec_VP9_VAAPI2:
+            return "VP9 VAAPI2";
+        case kCodec_HEVC_VAAPI2:
+            return "HEVC VAAPI2";
+
         default:
             break;
     }
@@ -305,6 +326,37 @@ int myth2av_codecid(MythCodecID codec_id, bool &vdpau)
             ret = AV_CODEC_ID_HEVC;
             break;
 
+        case kCodec_MPEG1_VAAPI2:
+            ret = AV_CODEC_ID_MPEG1VIDEO;
+            break;
+        case kCodec_MPEG2_VAAPI2:
+            ret = AV_CODEC_ID_MPEG2VIDEO;
+            break;
+        case kCodec_H263_VAAPI2:
+            ret = AV_CODEC_ID_H263;
+            break;
+        case kCodec_MPEG4_VAAPI2:
+            ret = AV_CODEC_ID_MPEG4;
+            break;
+        case kCodec_H264_VAAPI2:
+            ret = AV_CODEC_ID_H264;
+            break;
+        case kCodec_VC1_VAAPI2:
+            ret = AV_CODEC_ID_VC1;
+            break;
+        case kCodec_WMV3_VAAPI2:
+            ret = AV_CODEC_ID_WMV3;
+            break;
+        case kCodec_VP8_VAAPI2:
+            ret = AV_CODEC_ID_VP8;
+            break;
+        case kCodec_VP9_VAAPI2:
+            ret = AV_CODEC_ID_VP9;
+            break;
+        case kCodec_HEVC_VAAPI2:
+            ret = AV_CODEC_ID_HEVC;
+            break;
+
         default:
             LOG(VB_GENERAL, LOG_ERR,
                 QString("Error: MythCodecID %1 has not been "
@@ -356,11 +408,13 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_MPEG1_VAAPI:
         case kCodec_MPEG1_DXVA2:
         case kCodec_MPEG1_MEDIACODEC:
+        case kCodec_MPEG1_VAAPI2:
         case kCodec_MPEG2:
         case kCodec_MPEG2_VDPAU:
         case kCodec_MPEG2_VAAPI:
         case kCodec_MPEG2_DXVA2:
         case kCodec_MPEG2_MEDIACODEC:
+        case kCodec_MPEG2_VAAPI2:
             return "MPEG-2";
 
         case kCodec_H263:
@@ -368,6 +422,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_H263_VAAPI:
         case kCodec_H263_DXVA2:
         case kCodec_H263_MEDIACODEC:
+        case kCodec_H263_VAAPI2:
             return "H.263";
 
         case kCodec_NUV_MPEG4:
@@ -376,6 +431,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_MPEG4_VAAPI:
         case kCodec_MPEG4_DXVA2:
         case kCodec_MPEG4_MEDIACODEC:
+        case kCodec_MPEG4_VAAPI2:
             return "MPEG-4";
 
         case kCodec_H264:
@@ -383,6 +439,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_H264_VAAPI:
         case kCodec_H264_DXVA2:
         case kCodec_H264_MEDIACODEC:
+        case kCodec_H264_VAAPI2:
             return "H.264";
 
         case kCodec_VC1:
@@ -390,6 +447,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_VC1_VAAPI:
         case kCodec_VC1_DXVA2:
         case kCodec_VC1_MEDIACODEC:
+        case kCodec_VC1_VAAPI2:
             return "VC-1";
 
         case kCodec_WMV3:
@@ -397,6 +455,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_WMV3_VAAPI:
         case kCodec_WMV3_DXVA2:
         case kCodec_WMV3_MEDIACODEC:
+        case kCodec_WMV3_VAAPI2:
             return "WMV3";
 
         case kCodec_VP8:
@@ -404,6 +463,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_VP8_VAAPI:
         case kCodec_VP8_DXVA2:
         case kCodec_VP8_MEDIACODEC:
+        case kCodec_VP8_VAAPI2:
             return "VP8";
 
         case kCodec_VP9:
@@ -411,6 +471,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_VP9_VAAPI:
         case kCodec_VP9_DXVA2:
         case kCodec_VP9_MEDIACODEC:
+        case kCodec_VP9_VAAPI2:
             return "VP8";
 
         case kCodec_HEVC:
@@ -418,6 +479,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_HEVC_VAAPI:
         case kCodec_HEVC_DXVA2:
         case kCodec_HEVC_MEDIACODEC:
+        case kCodec_HEVC_VAAPI2:
             return "HEVC";
 
         case kCodec_NONE:
@@ -426,6 +488,7 @@ QString get_encoding_type(MythCodecID codecid)
         case kCodec_VAAPI_END:
         case kCodec_DXVA2_END:
         case kCodec_MEDIACODEC_END:
+        case kCodec_VAAPI2_END:
             return QString();
     }
 
@@ -446,5 +509,8 @@ QString get_decoder_name(MythCodecID codec_id)
     if (codec_is_mediacodec(codec_id))
         return "mediacodec";
 
+    if (codec_is_vaapi2(codec_id))
+        return "vaapi2";
+
     return "ffmpeg";
 }
diff --git a/mythtv/libs/libmythtv/mythcodecid.h b/mythtv/libs/libmythtv/mythcodecid.h
index ce3620467d..f1d225d4be 100644
--- a/mythtv/libs/libmythtv/mythcodecid.h
+++ b/mythtv/libs/libmythtv/mythcodecid.h
@@ -91,6 +91,21 @@ typedef enum
 
     kCodec_MEDIACODEC_END,
 
+    kCodec_VAAPI2_BEGIN = kCodec_MEDIACODEC_END,
+
+    kCodec_MPEG1_VAAPI2,
+    kCodec_MPEG2_VAAPI2,
+    kCodec_H263_VAAPI2,
+    kCodec_MPEG4_VAAPI2,
+    kCodec_H264_VAAPI2,
+    kCodec_VC1_VAAPI2,
+    kCodec_WMV3_VAAPI2,
+    kCodec_VP8_VAAPI2,
+    kCodec_VP9_VAAPI2,
+    kCodec_HEVC_VAAPI2,
+
+    kCodec_VAAPI2_END,
+
 } MythCodecID;
 
 // MythCodecID convenience functions
@@ -113,8 +128,10 @@ typedef enum
                                 (id == kCodec_VC1_DXVA2)))
 #define codec_is_mediacodec(id) ((id > kCodec_MEDIACODEC_BEGIN) &&     \
                                (id < kCodec_MEDIACODEC_END))
+#define codec_is_vaapi2(id)    ((id > kCodec_VAAPI2_BEGIN) &&     \
+                               (id < kCodec_VAAPI2_END))
 
-#define codec_sw_copy(id) (codec_is_std(id) || codec_is_mediacodec(id))
+#define codec_sw_copy(id) (codec_is_std(id) || codec_is_mediacodec(id) || codec_is_vaapi2(id))
 
 QString get_encoding_type(MythCodecID codecid);
 QString get_decoder_name(MythCodecID codec_id);
@@ -156,9 +173,4 @@ int mpeg_version(int codec_id);
 #define CODEC_IS_MEDIACODEC(codec) (0)
 #endif
 
-#define CODEC_IS_HWACCEL(codec, enc) (CODEC_IS_VDPAU(codec)      ||     \
-                                      CODEC_IS_VAAPI(codec, enc) ||     \
-                                      CODEC_IS_DXVA2(codec, enc) ||    \
-                                      CODEC_IS_MEDIACODEC(codec))
-
 #endif // _MYTH_CODEC_ID_H_
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index e4e0bd83ea..9ce7962160 100644
--- a/mythtv/libs/libmythtv/mythplayer.cpp
+++ b/mythtv/libs/libmythtv/mythplayer.cpp
@@ -2182,6 +2182,11 @@ void MythPlayer::SetBuffering(bool new_buffering)
     }
 }
 
+// For debugging playback set this to increase the timeout so that
+// playback does not fail if stepping through code.
+// Set PREBUFFERDEBUG to any value and you will get 30 minutes.
+static char *preBufferDebug = getenv("PREBUFFERDEBUG");
+
 bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
 {
     if (!videoOutput)
@@ -2247,7 +2252,10 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
                 audio.Pause(false);
             }
         }
-        if ((waited_for > 500) && !videoOutput->EnoughFreeFrames())
+        int msecs = 500;
+        if (preBufferDebug)
+            msecs = 1800000;
+        if ((waited_for > msecs /*500*/) && !videoOutput->EnoughFreeFrames())
         {
             LOG(VB_GENERAL, LOG_NOTICE, LOC +
                 "Timed out waiting for frames, and"
@@ -2257,7 +2265,10 @@ bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
             // to recover from serious problems if frames get leaked.
             DiscardVideoFrames(true);
         }
-        if (waited_for > 30000) // 30 seconds for internet streamed media
+        msecs = 30000;
+        if (preBufferDebug)
+            msecs = 1800000;
+        if (waited_for > msecs /*30000*/) // 30 seconds for internet streamed media
         {
             LOG(VB_GENERAL, LOG_ERR, LOC +
                 "Waited too long for decoder to fill video buffers. Exiting..");
diff --git a/mythtv/libs/libmythtv/vaapi2context.cpp b/mythtv/libs/libmythtv/vaapi2context.cpp
new file mode 100644
index 0000000000..21e9dec4cf
--- /dev/null
+++ b/mythtv/libs/libmythtv/vaapi2context.cpp
@@ -0,0 +1,171 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 MythTV Developers <mythtv-dev@mythtv.org>
+//
+// This is part of MythTV (https://www.mythtv.org)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "mythcorecontext.h"
+#include "mythlogging.h"
+#include "vaapi2context.h"
+#include "videooutbase.h"
+#include "mythplayer.h"
+
+extern "C" {
+    #include "libavutil/pixfmt.h"
+    #include "libavutil/hwcontext.h"
+    #include "libavcodec/avcodec.h"
+}
+
+#define LOC QString("VAAPI2: ")
+
+Vaapi2Context::Vaapi2Context(AVStream* initStream) :
+    MythCodecContext(initStream)
+{
+
+}
+
+MythCodecID Vaapi2Context::GetBestSupportedCodec(
+    AVCodec **ppCodec,
+    const QString &decoder,
+    uint stream_type,
+    AVPixelFormat &pix_fmt)
+{
+    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_VAAPI;
+
+    AVPixelFormat fmt = AV_PIX_FMT_NONE;
+    if (decoder == "vaapi2")
+    {
+        for (int i = 0;; i++) {
+            const AVCodecHWConfig *config = avcodec_get_hw_config(*ppCodec, i);
+            if (!config) {
+                LOG(VB_PLAYBACK, LOG_INFO, LOC +
+                    QString("Decoder %1 does not support device type %2.")
+                        .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
+                break;
+            }
+            if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
+                config->device_type == type) {
+                fmt = config->pix_fmt;
+                break;
+            }
+        }
+    }
+    if (fmt == AV_PIX_FMT_NONE)
+        return (MythCodecID)(kCodec_MPEG1 + (stream_type - 1));
+    else
+    {
+        LOG(VB_PLAYBACK, LOG_INFO, LOC +
+            QString("Decoder %1 supports device type %2.")
+                .arg((*ppCodec)->name).arg(av_hwdevice_get_type_name(type)));
+        pix_fmt = fmt;
+        return (MythCodecID)(kCodec_MPEG1_VAAPI2 + (stream_type - 1));
+    }
+}
+
+// const char *filter_descr = "scale=78:24,transpose=cclock";
+/* other way:
+   scale=78:24 [scl]; [scl] transpose=cclock // assumes "[in]" and "[out]" to be input output pads respectively
+ */
+
+int Vaapi2Context::HwDecoderInit(AVCodecContext *ctx)
+{
+    int ret = 0;
+    AVBufferRef *hw_device_ctx = NULL;
+
+    const char *device = NULL;
+    QString vaapiDevice = gCoreContext->GetSetting("VAAPIDevice");
+    if (!vaapiDevice.isEmpty())
+    {
+        device = vaapiDevice.toLocal8Bit().constData();
+    }
+
+    ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,
+                                      device, NULL, 0);
+    if (ret < 0)
+    {
+        char error[AV_ERROR_MAX_STRING_SIZE];
+        LOG(VB_GENERAL, LOG_ERR, LOC +
+            QString("av_hwdevice_ctx_create  Device = <%3> error: %1 (%2)")
+            .arg(av_make_error_string(error, sizeof(error), ret))
+            .arg(ret).arg(vaapiDevice));
+    }
+    else
+    {
+        ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
+        av_buffer_unref(&hw_device_ctx);
+    }
+
+    return ret;
+}
+
+
+QString Vaapi2Context::GetDeinterlaceFilter(QString filtername)
+{
+    // example filter - deinterlace_vaapi=mode=default:rate=frame:auto=1
+    // example filtername - vaapi2doubleratemotion_compensated
+    QString ret;
+    QString rate="frame";
+    if (!filtername.startsWith("vaapi2"))
+        return ret;
+    filtername.remove(0,6); //remove "vaapi2"
+    if (filtername.startsWith("doublerate"))
+    {
+        rate="field";
+        filtername.remove(0,10);  // remove "doublerate"
+    }
+    ret=QString("deinterlace_vaapi=mode=%1:rate=%2:auto=1")
+        .arg(filtername).arg(rate);
+
+    return ret;
+}
+
+
+
+// If we find that it needs more buffers than the default
+// we can uncomment this and call it from get_format_vaapi2
+// int Vaapi2Context::SetHwframeCtx(AVCodecContext *ctx, int poolsize)
+// {
+//     AVBufferRef *hw_frames_ref;
+//     AVHWFramesContext *frames_ctx = NULL;
+//     int err = 0;
+
+//     if (!(hw_frames_ref = av_hwframe_ctx_alloc(ctx->hw_device_ctx))) {
+//         fprintf(stderr, "Failed to create VAAPI frame context.\n");
+//         return -1;
+//     }
+//     frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
+//     frames_ctx->format    = AV_PIX_FMT_VAAPI;
+//     frames_ctx->sw_format = AV_PIX_FMT_NV12;
+//     frames_ctx->width     = ctx->width;
+//     frames_ctx->height    = ctx->height;
+//     frames_ctx->initial_pool_size = poolsize;
+//     if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
+//         fprintf(stderr, "Failed to initialize VAAPI frame context.");
+//         av_buffer_unref(&hw_frames_ref);
+//         return err;
+//     }
+//     ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
+//     if (!ctx->hw_frames_ctx)
+//         err = AVERROR(ENOMEM);
+
+//     av_buffer_unref(&hw_frames_ref);
+//     return err;
+// }
diff --git a/mythtv/libs/libmythtv/vaapi2context.h b/mythtv/libs/libmythtv/vaapi2context.h
new file mode 100644
index 0000000000..fcd84b5833
--- /dev/null
+++ b/mythtv/libs/libmythtv/vaapi2context.h
@@ -0,0 +1,49 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 MythTV Developers <mythtv-dev@mythtv.org>
+//
+// This is part of MythTV (https://www.mythtv.org)
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef VAAPI2CONTEXT_H
+#define VAAPI2CONTEXT_H
+
+#include "mythtvexp.h"
+#include "mythcodecid.h"
+#include "mythcodeccontext.h"
+
+extern "C" {
+    #include "libavcodec/avcodec.h"
+}
+
+class MTV_PUBLIC Vaapi2Context : public MythCodecContext
+{
+  public:
+    Vaapi2Context(AVStream* initStream);
+    static MythCodecID GetBestSupportedCodec(AVCodec **ppCodec,
+                                             const QString &decoder,
+                                             uint stream_type,
+                                             AVPixelFormat &pix_fmt);
+    int HwDecoderInit(AVCodecContext *ctx);
+    virtual QString GetDeinterlaceFilter(QString filtername);
+};
+
+#endif // VAAPI2CONTEXT_H
\ No newline at end of file
diff --git a/mythtv/libs/libmythtv/videodisplayprofile.cpp b/mythtv/libs/libmythtv/videodisplayprofile.cpp
index 700ee3bb99..990b1ae6f7 100644
--- a/mythtv/libs/libmythtv/videodisplayprofile.cpp
+++ b/mythtv/libs/libmythtv/videodisplayprofile.cpp
@@ -8,6 +8,7 @@ using namespace std;
 #include "mythlogging.h"
 #include "videooutbase.h"
 #include "avformatdecoder.h"
+#include "mythcodeccontext.h"
 
 
 // options are NNN NNN-MMM 0-MMM NNN-99999 >NNN >=NNN <MMM <=MMM or blank
@@ -258,6 +259,8 @@ bool ProfileItem::IsValid(QString *reason) const
     }
 
     QStringList deints    = VideoDisplayProfile::GetDeinterlacers(renderer);
+    QStringList decoderdeints  = MythCodecContext::GetDeinterlacers(decoder);
+    deints.append(decoderdeints);
     QString     deint0    = Get("pref_deint0");
     QString     deint1    = Get("pref_deint1");
     if (!deint0.isEmpty() && !deints.contains(deint0))
@@ -852,6 +855,7 @@ QString VideoDisplayProfile::GetDecoderName(const QString &decoder)
         dec_name["dxva2"]    = QObject::tr("Windows hardware acceleration");
         dec_name["vda"]      = QObject::tr("Mac VDA hardware acceleration");
         dec_name["mediacodec"] = QObject::tr("Android MediaCodec decoder");
+        dec_name["vaapi2"]   = QObject::tr("VAAPI2 acceleration");
     }
 
     QString ret = decoder;
@@ -913,6 +917,11 @@ QString VideoDisplayProfile::GetDecoderHelp(QString decoder)
             "Mediacodec will use the graphics hardware to "
             "accelerate video decoding on Android. ");
 
+    if (decoder == "vaapi2")
+        msg += QObject::tr(
+            "VAAPI2 is a new implementation of VAAPI to will use the graphics hardware to "
+            "accelerate video decoding on Intel CPUs. ");
+
     return msg;
 }
 
@@ -941,19 +950,19 @@ QString VideoDisplayProfile::GetDeinterlacerName(const QString &short_name)
     else if ("fieldorderdoubleprocessdeint" == short_name)
         return QObject::tr("Interlaced (2x)");
     else if ("opengllinearblend" == short_name)
-        return QObject::tr("Linear blend (HW)");
+        return QObject::tr("Linear blend (HW-GL)");
     else if ("openglkerneldeint" == short_name)
-        return QObject::tr("Kernel (HW)");
+        return QObject::tr("Kernel (HW-GL)");
     else if ("openglbobdeint" == short_name)
-        return QObject::tr("Bob (2x, HW)");
+        return QObject::tr("Bob (2x, HW-GL)");
     else if ("openglonefield" == short_name)
-        return QObject::tr("One field (HW)");
+        return QObject::tr("One field (HW-GL)");
     else if ("opengldoubleratekerneldeint" == short_name)
-        return QObject::tr("Kernel (2x, HW)");
+        return QObject::tr("Kernel (2x, HW-GL)");
     else if ("opengldoubleratelinearblend" == short_name)
-        return QObject::tr("Linear blend (2x, HW)");
+        return QObject::tr("Linear blend (2x, HW-GL)");
     else if ("opengldoubleratefieldorder" == short_name)
-        return QObject::tr("Interlaced (2x, HW)");
+        return QObject::tr("Interlaced (2x, HW-GL)");
     else if ("vdpauonefield" == short_name)
         return QObject::tr("One Field (1x, HW)");
     else if ("vdpaubobdeint" == short_name)
@@ -978,6 +987,28 @@ QString VideoDisplayProfile::GetDeinterlacerName(const QString &short_name)
     else if ("openmaxlinedouble" == short_name)
         return QObject::tr("Line double (HW)");
 #endif // def USING_OPENMAX
+#ifdef USING_VAAPI2
+    else if ("vaapi2default" == short_name)
+        return QObject::tr("Advanced (HW-VA)");
+    else if ("vaapi2bob" == short_name)
+        return QObject::tr("Bob (HW-VA)");
+    else if ("vaapi2weave" == short_name)
+        return QObject::tr("Weave (HW-VA)");
+    else if ("vaapi2motion_adaptive" == short_name)
+        return QObject::tr("Motion Adaptive (HW-VA)");
+    else if ("vaapi2motion_compensated" == short_name)
+        return QObject::tr("Motion Compensated (HW-VA)");
+    else if ("vaapi2doubleratedefault" == short_name)
+        return QObject::tr("Advanced (2x, HW-VA)");
+    else if ("vaapi2doubleratebob" == short_name)
+        return QObject::tr("Bob (2x, HW-VA)");
+    else if ("vaapi2doublerateweave" == short_name)
+        return QObject::tr("Weave (2x, HW-VA)");
+    else if ("vaapi2doubleratemotion_adaptive" == short_name)
+        return QObject::tr("Motion Adaptive (2x, HW-VA)");
+    else if ("vaapi2doubleratemotion_compensated" == short_name)
+        return QObject::tr("Motion Compensated (2x, HW-VA)");
+#endif
 
     return "";
 }
@@ -1468,7 +1499,20 @@ void VideoDisplayProfile::CreateProfiles(const QString &hostname)
         CreateProfile(groupid, 1, "", "", "",
                       "mediacodec", 4, true, "opengl",
                       "opengl2", true,
-                      "none", "none",
+                      "opengldoubleratelinearblend", "opengllinearblend",
+                      "");
+    }
+#endif
+
+#ifdef USING_VAAPI2
+    if (!profiles.contains("VAAPI2 Normal")) {
+        (void) QObject::tr("VAAPI2 Normal",
+                           "Sample: VAAPI2 Normal");
+        groupid = CreateProfileGroup("VAAPI2 Normal", hostname);
+        CreateProfile(groupid, 1, "", "", "",
+                      "vaapi2", 4, true, "opengl",
+                      "opengl2", true,
+                      "vaapi2doubleratedefault", "vaapi2default",
                       "");
     }
 #endif
@@ -1615,6 +1659,10 @@ QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint)
 
     QString kUsingGPU = QObject::tr("(Hardware Accelerated)");
 
+    QString kUsingVA = QObject::tr("(VAAPI Hardware Accelerated)");
+
+    QString kUsingGL = QObject::tr("(OpenGL Hardware Accelerated)");
+
     QString kGreedyHMsg = QObject::tr(
         "This deinterlacer uses several fields to reduce motion blur. "
         "It has increased CPU requirements.");
@@ -1635,6 +1683,18 @@ QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint)
         "This deinterlacer uses multiple fields to reduce motion blur "
         "and smooth edges. ");
 
+    QString kMostAdvMsg = QObject::tr(
+        "Use the most advanced hardware deinterlacing algorithm available. ");
+
+    QString kWeaveMsg = QObject::tr(
+        "Use the weave deinterlacing algorithm. ");
+
+    QString kMAMsg = QObject::tr(
+        "Use the motion adaptive deinterlacing algorithm. ");
+
+    QString kMCMsg = QObject::tr(
+        "Use the motion compensated deinterlacing algorithm. ");
+
     if (deint == "none")
         msg = kNoneMsg;
     else if (deint == "onefield")
@@ -1648,19 +1708,19 @@ QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint)
     else if (deint == "kerneldoubleprocessdeint")
         msg = kKernelMsg + " " + kDoubleRateMsg;
     else if (deint == "openglonefield")
-        msg = kOneFieldMsg + " " + kUsingGPU;
+        msg = kOneFieldMsg + " " + kUsingGL;
     else if (deint == "openglbobdeint")
-        msg = kBobMsg + " " + kUsingGPU;
+        msg = kBobMsg + " " + kUsingGL;
     else if (deint == "opengllinearblend")
-        msg = kLinearBlendMsg + " " + kUsingGPU;
+        msg = kLinearBlendMsg + " " + kUsingGL;
     else if (deint == "openglkerneldeint")
-        msg = kKernelMsg + " " + kUsingGPU;
+        msg = kKernelMsg + " " + kUsingGL;
     else if (deint == "opengldoubleratelinearblend")
-        msg = kLinearBlendMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
+        msg = kLinearBlendMsg + " " +  kDoubleRateMsg + " " + kUsingGL;
     else if (deint == "opengldoubleratekerneldeint")
-        msg = kKernelMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
+        msg = kKernelMsg + " " +  kDoubleRateMsg + " " + kUsingGL;
     else if (deint == "opengldoubleratefieldorder")
-        msg = kFieldOrderMsg + " " +  kDoubleRateMsg  + " " + kUsingGPU;
+        msg = kFieldOrderMsg + " " +  kDoubleRateMsg  + " " + kUsingGL;
     else if (deint == "greedyhdeint")
         msg = kGreedyHMsg;
     else if (deint == "greedyhdoubleprocessdeint")
@@ -1687,6 +1747,27 @@ QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint)
         msg = kOneFieldMsg + " " + kUsingGPU;
     else if (deint == "vaapibobdeint")
         msg = kBobMsg + " " + kUsingGPU;
+
+    else if (deint == "vaapi2default")
+        msg = kMostAdvMsg + " " +  kUsingVA;
+    else if (deint == "vaapi2bob")
+        msg = kBobMsg + " " +  kUsingVA;
+    else if (deint == "vaapi2weave")
+        msg = kWeaveMsg + " " +  kUsingVA;
+    else if (deint == "vaapi2motion_adaptive")
+        msg = kMAMsg + " " +  kUsingVA;
+    else if (deint == "vaapi2motion_compensated")
+        msg = kMCMsg + " " +  kUsingVA;
+    else if (deint == "vaapi2doubleratedefault")
+        msg = kMostAdvMsg + " " +  kDoubleRateMsg + " " + kUsingVA;
+    else if (deint == "vaapi2doubleratebob")
+        msg = kBobMsg + " " +  kDoubleRateMsg + " " + kUsingVA;
+    else if (deint == "vaapi2doublerateweave")
+        msg = kWeaveMsg + " " +  kDoubleRateMsg + " " + kUsingVA;
+    else if (deint == "vaapi2doubleratemotion_adaptive")
+        msg = kMAMsg + " " +  kDoubleRateMsg + " " + kUsingVA;
+    else if (deint == "vaapi2doubleratemotion_compensated")
+        msg = kMCMsg + " " +  kDoubleRateMsg + " " + kUsingVA;
     else
         msg = QObject::tr("'%1' has not been documented yet.").arg(deint);
 
diff --git a/mythtv/libs/libmythtv/videoout_opengl.cpp b/mythtv/libs/libmythtv/videoout_opengl.cpp
index b689947d73..51b62527ec 100644
--- a/mythtv/libs/libmythtv/videoout_opengl.cpp
+++ b/mythtv/libs/libmythtv/videoout_opengl.cpp
@@ -40,6 +40,8 @@ void VideoOutputOpenGL::GetRenderOptions(render_opts &opts,
         (*opts.safe_renderers)["openmax"].append("opengl");
     if (opts.decoders->contains("mediacodec"))
         (*opts.safe_renderers)["mediacodec"].append("opengl");
+    if (opts.decoders->contains("vaapi2"))
+        (*opts.safe_renderers)["vaapi2"].append("opengl");
     opts.priorities->insert("opengl", 65);
 
     // lite profile - no colourspace control, GPU deinterlacing
@@ -270,7 +272,9 @@ bool VideoOutputOpenGL::InputChanged(const QSize &video_dim_buf,
         StopEmbedding();
     }
 
-    if (!codec_is_std(av_codec_id) && !codec_is_mediacodec(av_codec_id))
+    if (!codec_is_std(av_codec_id)
+        && !codec_is_mediacodec(av_codec_id)
+        && !codec_is_vaapi2(av_codec_id))
     {
         LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
         errorState = kError_Unknown;
@@ -741,7 +745,8 @@ QStringList VideoOutputOpenGL::GetAllowedRenderers(
     {
         list << "opengl" << "opengl-lite";
     }
-    else if (codec_is_mediacodec(myth_codec_id) && !getenv("NO_OPENGL"))
+    else if ((codec_is_mediacodec(myth_codec_id) || codec_is_vaapi2(myth_codec_id))
+            && !getenv("NO_OPENGL"))
     {
         list << "opengl";
     }
@@ -812,6 +817,9 @@ bool VideoOutputOpenGL::SetupDeinterlace(
     if (db_vdisp_profile)
         m_deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
 
+    if (m_deintfiltername.startsWith("vaapi2"))
+        return false;
+
     if (!m_deintfiltername.contains("opengl"))
     {
         gl_videochain->SetDeinterlacing(false);
diff --git a/mythtv/libs/libmythtv/videoout_xv.cpp b/mythtv/libs/libmythtv/videoout_xv.cpp
index ccc756ace7..1074b1ea4c 100644
--- a/mythtv/libs/libmythtv/videoout_xv.cpp
+++ b/mythtv/libs/libmythtv/videoout_xv.cpp
@@ -122,6 +122,15 @@ void VideoOutputXv::GetRenderOptions(render_opts &opts,
         (*opts.safe_renderers)["crystalhd"].append("xshm");
         (*opts.safe_renderers)["crystalhd"].append("xv-blit");
     }
+
+    // These could work but needs some debugging so disable for now
+    // if (opts.decoders->contains("vaapi2"))
+    // {
+    //     (*opts.safe_renderers)["vaapi2"].append("xlib");
+    //     (*opts.safe_renderers)["vaapi2"].append("xshm");
+    //     (*opts.safe_renderers)["vaapi2"].append("xv-blit");
+    // }
+
 }
 
 /** \class  VideoOutputXv
@@ -2090,6 +2099,8 @@ static QStringList allowed_video_renderers(
 
     QStringList list;
     if (codec_is_std(myth_codec_id))
+    // this needs some work
+    //  || codec_is_vaapi2(myth_codec_id))
     {
         if (xv)
             list += "xv-blit";
diff --git a/mythtv/libs/libmythtv/videooutbase.cpp b/mythtv/libs/libmythtv/videooutbase.cpp
index 60b2d4fa24..dc892c4647 100644
--- a/mythtv/libs/libmythtv/videooutbase.cpp
+++ b/mythtv/libs/libmythtv/videooutbase.cpp
@@ -607,8 +607,16 @@ bool VideoOutput::SetupDeinterlace(bool interlaced,
         else
             m_deintfiltername = "";
 
-        m_deintFiltMan = new FilterManager;
         m_deintFilter = NULL;
+        m_deintFiltMan = NULL;
+
+        if (m_deintfiltername.startsWith("vaapi2"))
+        {
+            m_deinterlacing = false;
+            return false;
+        }
+
+        m_deintFiltMan = new FilterManager;
 
         if (!m_deintfiltername.isEmpty())
         {
diff --git a/mythtv/libs/libmythtv/videooutbase.h b/mythtv/libs/libmythtv/videooutbase.h
index 0c11bd60ce..35a5f2877a 100644
--- a/mythtv/libs/libmythtv/videooutbase.h
+++ b/mythtv/libs/libmythtv/videooutbase.h
@@ -76,6 +76,8 @@ class VideoOutput
     virtual void PrepareFrame(VideoFrame *buffer, FrameScanType,
                               OSD *osd) = 0;
     virtual void Show(FrameScanType) = 0;
+    VideoDisplayProfile *GetProfile() { return db_vdisp_profile; }
+
 
     virtual void WindowResized(const QSize &) {}
 
diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
index 7f87ba55ca..c169aab6a5 100644
--- a/mythtv/programs/mythfrontend/globalsettings.cpp
+++ b/mythtv/programs/mythfrontend/globalsettings.cpp
@@ -38,6 +38,7 @@
 #include "mythuihelper.h"
 #include "mythuidefines.h"
 #include "langsettings.h"
+#include "mythcodeccontext.h"
 
 #ifdef USING_AIRPLAY
 #include "AirPlay/mythraopconnection.h"
@@ -66,6 +67,25 @@ static HostSpinBoxSetting *AudioReadAhead()
     return gc;
 }
 
+#ifdef USING_VAAPI2
+static HostTextEditSetting *VAAPIDevice()
+{
+    HostTextEditSetting *ge = new HostTextEditSetting("VAAPIDevice");
+
+    ge->setLabel(MainGeneralSettings::tr("Decoder Device for VAAPI2 hardware decoding"));
+
+    ge->setValue("");
+
+    QString help = MainGeneralSettings::tr(
+        "Use this if your system does not detect the VAAPI device. "
+        "Example: '/dev/dri/renderD128'.");
+
+    ge->setHelpText(help);
+
+    return ge;
+}
+#endif
+
 #if CONFIG_DEBUGTYPE
 static HostCheckBoxSetting *FFmpegDemuxer()
 {
@@ -937,6 +957,9 @@ void PlaybackProfileItemConfig::decoderChanged(const QString &dec)
 
     decoder->setHelpText(VideoDisplayProfile::GetDecoderHelp(dec));
 
+    QString vrenderer2 = vidrend->getValue();
+    vrenderChanged(vrenderer2);
+
     InitLabel();
 }
 
@@ -944,6 +967,9 @@ void PlaybackProfileItemConfig::vrenderChanged(const QString &renderer)
 {
     QStringList osds    = VideoDisplayProfile::GetOSDs(renderer);
     QStringList deints  = VideoDisplayProfile::GetDeinterlacers(renderer);
+    QString decodername = decoder->getValue();
+    QStringList decoderdeints  = MythCodecContext::GetDeinterlacers(decodername);
+    deints.append(decoderdeints);
     QString     losd    = osdrend->getValue();
     QString     ldeint0 = deint0->getValue();
     QString     ldeint1 = deint1->getValue();
@@ -3958,6 +3984,9 @@ void PlaybackSettings::Load(void)
     GroupSetting* general = new GroupSetting();
     general->setLabel(tr("General Playback"));
     general->addChild(RealtimePriority());
+#ifdef USING_VAAPI2
+    general->addChild(VAAPIDevice());
+#endif
     general->addChild(AudioReadAhead());
     general->addChild(JumpToProgramOSD());
     general->addChild(ClearSavedPosition());
diff --git a/mythtv/programs/mythfrontend/mythfrontend.pro b/mythtv/programs/mythfrontend/mythfrontend.pro
index 580bc606af..83517acfef 100644
--- a/mythtv/programs/mythfrontend/mythfrontend.pro
+++ b/mythtv/programs/mythfrontend/mythfrontend.pro
@@ -116,6 +116,7 @@ using_opengl:DEFINES += USING_OPENGL
 using_opengl_video:DEFINES += USING_OPENGL_VIDEO
 using_vdpau:DEFINES += USING_VDPAU
 using_vaapi:using_opengl_video:DEFINES += USING_GLVAAPI
+using_vaapi2:DEFINES += USING_VAAPI2
 
 using_pulse:DEFINES += USING_PULSE
 using_pulseoutput: DEFINES += USING_PULSEOUTPUT
