diff --git a/mythtv/configure b/mythtv/configure
index f7cfc291b82..ec11749e0f5 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 VAAPI2 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
@@ -1395,12 +1396,13 @@ EXTERNAL_LIBRARY_LIST="
     opengl
     sdl
     sdl2
+    vaapi
+    vaapi2
 "
 
 HWACCEL_AUTODETECT_LIBRARY_LIST="
     crystalhd
     dxva2
-    vaapi
     vda
     vdpau
 "
@@ -2040,6 +2042,7 @@ USING_LIST='
     opengl
     opengles
     vaapi
+    vaapi2
     vdpau
     openmax
     mediacodec
@@ -2769,6 +2772,8 @@ enable libdns_sd
 enable libxml2
 enable lirc
 enable mediacodec
+enable vaapi
+enable vaapi2
 enable mheg
 enable mythtranscode
 enable opengl
@@ -6203,6 +6208,10 @@ enabled vaapi &&
     check_cpp_condition "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" &&
     enable vaapi_1
 
+enabled vaapi2 &&
+    check_func_headers va/va.h vaInitialize -lva ||
+    disable vaapi2
+
 enabled vdpau &&
     check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
     disable vdpau
@@ -7057,7 +7066,7 @@ ffmpeg_optset extra_cxxflags extra_ldflags target_os
 ffmpeg_optset pkg_config prefix libdir as objcc dep_cc host_cc
 ffmpeg_optset host_ld
 ffmpeg_optenable cross_compile libmp3lame libx264 libx265 libvpx libxvid
-ffmpeg_optenable vdpau vaapi libxml2 libass dxva2
+ffmpeg_optenable vdpau libxml2 libass dxva2
 ffmpeg_optenable libbluray libfontconfig libfreetype libiec61883
 ffmpeg_optenable crystalhd sdl2 ffplay
 if test $target_os = "android"; then
@@ -7066,7 +7075,9 @@ if test $target_os = "android"; then
 else
     disable mediacodec
 fi
-
+if enabled vaapi || enabled vaapi2 ; then
+    ffopts="$ffopts --enable-vaapi"
+fi
 ffmpeg_extra_cflags="$extra_cflags -w"
 
 ## Call FFmpeg configure here
@@ -7272,6 +7283,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 5b5fce95e88..835a53e23c7 100644
--- a/mythtv/libs/libmythtv/avformatdecoder.cpp
+++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
@@ -43,6 +43,7 @@ using namespace std;
 #include "lcddevice.h"
 
 #include "audiooutput.h"
+#include "mythcodeccontext.h"
 
 #ifdef USING_VDPAU
 #include "videoout_vdpau.h"
@@ -70,6 +71,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 +187,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)
 {
@@ -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");
@@ -478,6 +490,7 @@ AvFormatDecoder::~AvFormatDecoder()
     delete ttd;
     delete private_dec;
     delete m_h264_parser;
+    delete m_mythcodecctx;
 
     sws_freeContext(sws_ctx);
 
@@ -1515,14 +1528,16 @@ enum AVPixelFormat get_format_dxva2(struct AVCodecContext *avctx,
 }
 #endif
 
-#ifdef USING_VAAPI
+#if defined(USING_VAAPI) || defined(USING_VAAPI2)
 static bool IS_VAAPI_PIX_FMT(enum AVPixelFormat fmt)
 {
     return fmt == AV_PIX_FMT_VAAPI_MOCO ||
            fmt == AV_PIX_FMT_VAAPI_IDCT ||
            fmt == AV_PIX_FMT_VAAPI_VLD;
 }
+#endif
 
+#ifdef USING_VAAPI
 // Declared separately to allow attribute
 static enum AVPixelFormat get_format_vaapi(struct AVCodecContext *,
                                          const enum AVPixelFormat *) MUNUSED;
@@ -1549,6 +1564,25 @@ 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++;
+    }
+    return ret;
+}
+#endif
+
 #ifdef USING_MEDIACODEC
 static enum AVPixelFormat get_format_mediacodec(struct AVCodecContext *avctx,
                                            const enum AVPixelFormat *valid_fmts)
@@ -1629,7 +1663,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 +1678,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 +1701,31 @@ void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc,
                 .arg(ff_codec_id_string(enc->codec_id)));
     }
 
+    QString deinterlacer;
+    if (m_mythcodecctx)
+        deinterlacer = m_mythcodecctx->getDeinterlacerName();
+    delete m_mythcodecctx;
+    m_mythcodecctx = MythCodecContext::createMythCodecContext(video_codec_id);
+    m_mythcodecctx->setPlayer(m_parent);
+    m_mythcodecctx->setStream(stream);
+    m_mythcodecctx->setDeinterlacer(true,deinterlacer);
+
+    int ret = m_mythcodecctx->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))
@@ -2536,6 +2603,24 @@ int AvFormatDecoder::ScanStreams(bool novideo)
                     }
                 }
 #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_VAAPI2
             }
             // default to mpeg2
             if (video_codec_id == kCodec_NONE)
@@ -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,15 @@ 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)
@@ -3630,7 +3726,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);
+
+            // FilteredReceiveFrame will call avcodec_receive_frame and
+            // apply any codec-dependent filtering
+            ret = m_mythcodecctx->FilteredReceiveFrame(context, mpa_pic);
 
             if (ret == 0)
                 gotpicture = 1;
@@ -3671,16 +3770,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;
@@ -3840,6 +3936,27 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
     }
     else if (!directrendering)
     {
+        AVFrame *tmp_frame = NULL;
+        AVFrame *use_frame = NULL;
+#ifdef USING_VAAPI2
+        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
+#endif // USING_VAAPI2
+            use_frame = mpa_pic;
+
         AVFrame tmppicture;
 
         VideoFrame *xf = picframe;
@@ -3847,8 +3964,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 +3974,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 +3984,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 +3997,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)
     {
@@ -3928,10 +4047,13 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
         // If fps has doubled due to frame-doubling deinterlace
         // Set fps to double value.
         double fpschange = calcfps / fps;
+        int prior = fpsMultiplier;
         if (fpschange > 1.9 && fpschange < 2.1)
             fpsMultiplier = 2;
         if (fpschange > 0.5 && fpschange < 0.6)
             fpsMultiplier = 1;
+        if (fpsMultiplier != prior)
+            m_parent->SetFrameRate(fps);
     }
 
     LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
index e4dded21576..1ea3785b7db 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/decoderbase.cpp b/mythtv/libs/libmythtv/decoderbase.cpp
index b8a2edef83b..788598f119a 100644
--- a/mythtv/libs/libmythtv/decoderbase.cpp
+++ b/mythtv/libs/libmythtv/decoderbase.cpp
@@ -11,6 +11,7 @@ using namespace std;
 #include "iso639.h"
 #include "DVD/dvdringbuffer.h"
 #include "Bluray/bdringbuffer.h"
+#include "mythcodeccontext.h"
 
 #define LOC QString("Dec: ")
 
@@ -45,7 +46,9 @@ DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo)
       video_inverted(false),
       decodeAllSubtitles(false),
       // language preference
-      languagePreference(iso639_get_language_key_list())
+      languagePreference(iso639_get_language_key_list()),
+      // this will be deleted and recreated once decoder is set up
+      m_mythcodecctx(new MythCodecContext())
 {
     ResetTracks();
     tracks[kTrackTypeAudio].push_back(StreamInfo(0, 0, 0, 0, 0));
diff --git a/mythtv/libs/libmythtv/decoderbase.h b/mythtv/libs/libmythtv/decoderbase.h
index 608c1e6b336..91c8804c8de 100644
--- a/mythtv/libs/libmythtv/decoderbase.h
+++ b/mythtv/libs/libmythtv/decoderbase.h
@@ -18,6 +18,7 @@ class RingBuffer;
 class TeletextViewer;
 class MythPlayer;
 class AudioPlayer;
+class MythCodecContext;
 
 const int kDecoderProbeBufferSize = 256 * 1024;
 
@@ -270,6 +271,7 @@ class DecoderBase
     bool GetVideoInverted(void) const { return video_inverted; }
     void TrackTotalDuration(bool track) { trackTotalDuration = track; }
     int GetfpsMultiplier(void) { return fpsMultiplier; }
+    MythCodecContext *GetMythCodecContext(void) { return m_mythcodecctx; }
 
   protected:
     virtual int  AutoSelectTrack(uint type);
@@ -359,6 +361,7 @@ class DecoderBase
     StreamInfo  selectedTrack[(uint)kTrackTypeCount];
     /// language preferences for auto-selection of streams
     vector<int> languagePreference;
+    MythCodecContext *m_mythcodecctx;
 };
 
 inline int DecoderBase::IncrementTrack(uint type)
diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
index 939ca20984b..8ffe3b82665 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 c21aec44568..d3a17ccfe17 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"
@@ -411,7 +412,7 @@ AVCodecContext *MythCodecMap::getCodecContext(const AVStream *stream,
             avcodec_free_context(&avctx);
         if (avctx)
         {
-            av_codec_set_pkt_timebase(avctx, stream->time_base);
+            avctx->pkt_timebase =  stream->time_base;
             streamMap.insert(stream, avctx);
         }
     }
diff --git a/mythtv/libs/libmythtv/mythcodeccontext.cpp b/mythtv/libs/libmythtv/mythcodeccontext.cpp
new file mode 100644
index 00000000000..ae1c84370a5
--- /dev/null
+++ b/mythtv/libs/libmythtv/mythcodeccontext.cpp
@@ -0,0 +1,451 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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"
+#ifdef USING_VAAPI2
+#include "vaapi2context.h"
+#endif
+
+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() :
+    stream(NULL),
+    buffersink_ctx(NULL),
+    buffersrc_ctx(NULL),
+    filter_graph(NULL),
+    filtersInitialized(false),
+    hw_frames_ctx(NULL),
+    player(NULL),
+    ptsUsed(0),
+    doublerate(false)
+{
+    priorPts[0] = 0;
+    priorPts[1] = 0;
+}
+
+MythCodecContext::~MythCodecContext()
+{
+    CloseFilters();
+}
+
+// static
+MythCodecContext *MythCodecContext::createMythCodecContext(MythCodecID codec)
+{
+    MythCodecContext *mctx = NULL;
+#ifdef USING_VAAPI2
+    if (codec_is_vaapi2(codec))
+        mctx = new Vaapi2Context();
+#endif
+    if (!mctx)
+        mctx = new MythCodecContext();
+    return mctx;
+}
+
+// static
+QStringList 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");
+
+/*
+    Explanation of vaapi2 deinterlacing modes.
+    "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;
+}
+// static - Find if a deinterlacer is codec-provided
+bool MythCodecContext::isCodecDeinterlacer(QString decodername)
+{
+    return (decodername.startsWith("vaapi2"));
+}
+
+
+// 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];
+                }
+            }
+            if  (ret != AVERROR(EAGAIN))
+                break;
+        }
+
+        // EAGAIN or no filter graph
+        ret = avcodec_receive_frame(ctx, frame);
+        if (ret < 0)
+            break;
+        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 = InitDeinterlaceFilter(ctx, frame);
+                if (ret < 0)
+                {
+                    LOG(VB_GENERAL, LOG_ERR, LOC + "InitDeinterlaceFilter 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;
+}
+
+// Setup or change deinterlacer.
+// Same usage as VideoOutBase::SetupDeinterlace
+// enable - true to enable, false to disable
+// name - empty to use video profile deinterlacers, otherwise
+//        use the supplied name.
+// return true if the deinterlacer was found as a hardware deinterlacer.
+// return false if the deinterlacer is nnt a hardware deinterlacer,
+//        and a videououtput deinterlacer should be tried instead.
+
+bool MythCodecContext::setDeinterlacer(bool enable, QString name)
+{
+    QMutexLocker lock(&contextLock);
+    // Code to disable interlace
+    if (!enable)
+    {
+        if (deinterlacername.isEmpty())
+            return true;
+        else
+        {
+            deinterlacername.clear();
+            doublerate = false;
+            filtersInitialized = false;
+            return true;
+        }
+    }
+
+    // Code to enable or change interlace
+    if (name.isEmpty())
+    {
+        if (deinterlacername.isEmpty())
+        {
+            VideoOutput *vo = NULL;
+            VideoDisplayProfile *vdisp_profile = NULL;
+            if (player)
+                vo = player->GetVideoOutput();
+            if (vo)
+                vdisp_profile = vo->GetProfile();
+            if (vdisp_profile)
+                name = vdisp_profile->GetFilteredDeint(QString());
+        }
+        else
+            name = deinterlacername;
+    }
+    bool ret = true;
+    if (!isCodecDeinterlacer(name))
+        name.clear();
+
+    if (name.isEmpty())
+        ret = false;
+
+    if (deinterlacername == name)
+        return ret;
+
+    deinterlacername = name;
+    doublerate = deinterlacername.contains("doublerate");
+    filtersInitialized = false;
+    return ret;
+}
+
+bool MythCodecContext::BestDeint(void)
+{
+    deinterlacername.clear();
+    doublerate = false;
+    return setDeinterlacer(true);
+}
+
+bool MythCodecContext::FallbackDeint(void)
+{
+    return setDeinterlacer(true,GetFallbackDeint());
+}
+
+QString MythCodecContext::GetFallbackDeint(void)
+{
+
+    VideoOutput *vo = NULL;
+    VideoDisplayProfile *vdisp_profile = NULL;
+    if (player)
+        vo = player->GetVideoOutput();
+    if (vo)
+        vdisp_profile = vo->GetProfile();
+    if (vdisp_profile)
+        return vdisp_profile->GetFallbackDeinterlacer();
+    return QString();
+}
+
+int MythCodecContext::InitDeinterlaceFilter(AVCodecContext *ctx, AVFrame *frame)
+{
+    QMutexLocker lock(&contextLock);
+    char args[512];
+    int ret = 0;
+    CloseFilters();
+    width = frame->width;
+    height = frame->height;
+    filtersInitialized = true;
+    if (!player || !stream)
+    {
+        LOG(VB_GENERAL, LOG_ERR, LOC + "Player or stream is not set up in MythCodecContext");
+        return -1;
+    }
+    if (doublerate && !player->CanSupportDoubleRate())
+    {
+        QString request = deinterlacername;
+        deinterlacername = GetFallbackDeint();
+        LOG(VB_PLAYBACK, LOG_INFO, LOC
+          + QString("Deinterlacer %1 requires double rate, switching to %2 instead.")
+          .arg(request).arg(deinterlacername));
+        if (!isCodecDeinterlacer(deinterlacername))
+            deinterlacername.clear();
+        doublerate = deinterlacername.contains("doublerate");
+
+        // if the fallback is a non-vaapi - deinterlace will be turned off
+        // and the videoout methods can take over.
+    }
+    QString filters;
+    if (isValidDeinterlacer(deinterlacername))
+        filters = GetDeinterlaceFilter();
+
+    if (filters.isEmpty())
+    {
+        LOG(VB_GENERAL, LOG_INFO, LOC +
+            "Disabled hardware decoder based deinterlacer.");
+        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;
+    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();
+    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;
+    }
+
+    /*
+     * 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;
+    }
+
+    LOG(VB_GENERAL, LOG_INFO, LOC +
+        QString("Enabled hardware decoder based deinterlace filter '%1': <%2>.")
+            .arg(deinterlacername).arg(filters));
+end:
+    if (ret < 0)
+    {
+        avfilter_graph_free(&filter_graph);
+        filter_graph = NULL;
+        doublerate = false;
+    }
+    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 00000000000..234797aeac4
--- /dev/null
+++ b/mythtv/libs/libmythtv/mythcodeccontext.h
@@ -0,0 +1,82 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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 MYTHCODECONTEXT_H
+
+struct AVCodecContext;
+struct AVFrame;
+struct AVStream;
+struct AVFilterContext;
+struct AVFilterGraph;
+struct AVBufferRef;
+class MythPlayer;
+
+#include "mythtvexp.h"
+#include "mythcodecid.h"
+
+class MTV_PUBLIC MythCodecContext
+{
+  public:
+    MythCodecContext(void);
+    virtual ~MythCodecContext();
+    static MythCodecContext* createMythCodecContext(MythCodecID codec);
+    virtual int HwDecoderInit(AVCodecContext * /*ctx*/) { return 0; }
+    void setStream(AVStream *initStream) { stream = initStream; }
+    virtual int FilteredReceiveFrame(AVCodecContext *ctx, AVFrame *frame);
+    static QStringList GetDeinterlacers(QString decodername);
+    static bool isCodecDeinterlacer(QString decodername);
+    virtual QStringList GetDeinterlacers(void) { return QStringList(); }
+    virtual QString GetDeinterlaceFilter() { return QString(); }
+    void setPlayer(MythPlayer *tPlayer) { player = tPlayer; }
+    bool setDeinterlacer(bool enable, QString name = QString());
+    bool isDeinterlacing(void) { return filter_graph != NULL;}
+    QString getDeinterlacerName(void) { return deinterlacername; }
+    bool BestDeint(void);
+    bool FallbackDeint(void);
+    bool getDoubleRate(void) { return doublerate; }
+    QString GetFallbackDeint(void);
+
+  protected:
+    virtual bool isValidDeinterlacer(QString /*name*/) { return false; }
+    int InitDeinterlaceFilter(AVCodecContext *ctx, AVFrame *frame);
+    void CloseFilters();
+    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;
+    int width;
+    int height;
+    QString deinterlacername;
+    QMutex contextLock;
+    bool doublerate;
+};
+
+#endif // MYTHCODECCONTEXT_H
\ No newline at end of file
diff --git a/mythtv/libs/libmythtv/mythcodecid.cpp b/mythtv/libs/libmythtv/mythcodecid.cpp
index b2023512b5f..cff4ba03585 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 ce3620467d9..f1d225d4beb 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 e4e0bd83ead..f1b02571f31 100644
--- a/mythtv/libs/libmythtv/mythplayer.cpp
+++ b/mythtv/libs/libmythtv/mythplayer.cpp
@@ -53,6 +53,7 @@ using namespace std;
 #include "mythuiactions.h"              // for ACTION_LEFT, ACTION_RIGHT, etc
 #include "ringbuffer.h"                 // for RingBuffer, etc
 #include "tv_actions.h"                 // for ACTION_BIGJUMPFWD, etc
+#include "mythcodeccontext.h"
 
 extern "C" {
 #include "vsync.h"
@@ -676,7 +677,12 @@ void MythPlayer::FallbackDeint(void)
      m_double_process   = false;
 
      if (videoOutput)
-         videoOutput->FallbackDeint();
+     {
+        videoOutput->SetupDeinterlace(false);
+        bool hwset = decoder->GetMythCodecContext()->FallbackDeint();
+        if (!hwset)
+            videoOutput->FallbackDeint();
+     }
 }
 
 void MythPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
@@ -715,7 +721,18 @@ void MythPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
 
     if ((m_scan_tracker % 400) == 0)
     {
-        QString type = (m_scan_tracker < 0) ? "progressive" : "interlaced";
+        QString type;
+        //  = (m_scan_tracker < 0) ? "progressive" : "interlaced";
+        if (m_scan_tracker < 0)
+        {
+            if (decoder->GetMythCodecContext()->isDeinterlacing())
+                type = "codec-deinterlaced";
+            else
+                type = "progressive";
+        }
+        else
+            type = "interlaced";
+
         LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("%1 %2 frames seen.")
                 .arg(abs(m_scan_tracker)).arg(type));
     }
@@ -763,13 +780,13 @@ void MythPlayer::SetScanType(FrameScanType scan)
 
     if (interlaced)
     {
-        m_deint_possible = videoOutput->SetDeinterlacingEnabled(true);
-        if (!m_deint_possible)
-        {
-            LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to enable deinterlacing");
-            m_scan = scan;
-            return;
-        }
+            m_deint_possible = videoOutput->SetDeinterlacingEnabled(true);
+            if (!m_deint_possible)
+            {
+                LOG(VB_GENERAL, LOG_INFO, LOC + "Unable to enable Video Output based deinterlacing");
+                m_scan = scan;
+                return;
+            }
         if (videoOutput->NeedsDoubleFramerate())
         {
             m_double_framerate = true;
@@ -782,7 +799,7 @@ void MythPlayer::SetScanType(FrameScanType scan)
             }
         }
         m_double_process = videoOutput->IsExtraProcessingRequired();
-        LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled deinterlacing");
+        LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled Video Output based deinterlacing");
     }
     else
     {
@@ -791,7 +808,7 @@ void MythPlayer::SetScanType(FrameScanType scan)
             m_double_process = false;
             m_double_framerate = false;
             videoOutput->SetDeinterlacingEnabled(false);
-            LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled deinterlacing");
+            LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled Video Output based deinterlacing");
         }
     }
 
@@ -849,6 +866,16 @@ void MythPlayer::SetVideoParams(int width, int height, double fps,
     m_scan_tracker = (m_scan == kScan_Interlaced) ? 2 : 0;
 }
 
+
+void MythPlayer::SetFrameRate(double fps)
+{
+    video_frame_rate = fps;
+    float temp_speed = (play_speed == 0.0f) ?
+        audio.GetStretchFactor() : play_speed;
+    SetFrameInterval(kScan_Progressive,
+                        1.0 / (video_frame_rate * temp_speed));
+}
+
 void MythPlayer::SetFileLength(int total, int frames)
 {
     totalLength = total;
@@ -1889,7 +1916,8 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
         else
         {
             dropframe = true;
-            dbg = "A/V predict drop frame, ";
+            dbg = QString("A/V predict drop frame, refreshrate %1, avsync_predictor %2, diverge %3, ")
+            .arg(refreshrate).arg(avsync_predictor).arg(diverge);
         }
     }
 
@@ -2182,6 +2210,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 +2280,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 +2293,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..");
@@ -2382,12 +2421,22 @@ void MythPlayer::ForceDeinterlacer(const QString &overridefilter)
     bool normal = play_speed > 0.99f && play_speed < 1.01f && normal_speed;
     videofiltersLock.lock();
 
-    m_double_framerate =
-         videoOutput->SetupDeinterlace(true, overridefilter) &&
-         videoOutput->NeedsDoubleFramerate();
-    m_double_process = videoOutput->IsExtraProcessingRequired();
-
-    if (m_double_framerate && (!CanSupportDoubleRate() || !normal))
+    bool hwset = decoder->GetMythCodecContext()->setDeinterlacer(true, overridefilter);
+    if (hwset)
+    {
+        m_double_framerate = false;
+        m_double_process = false;
+        videoOutput->SetupDeinterlace(false);
+    }
+    else
+    {
+        m_double_framerate =
+            videoOutput->SetupDeinterlace(true, overridefilter) &&
+            videoOutput->NeedsDoubleFramerate();
+        m_double_process = videoOutput->IsExtraProcessingRequired();
+    }
+    if ((decoder->GetMythCodecContext()->getDoubleRate() || m_double_framerate)
+      && (!CanSupportDoubleRate() || !normal))
         FallbackDeint();
 
     videofiltersLock.unlock();
@@ -2480,13 +2529,18 @@ void MythPlayer::VideoStart(void)
     }
     else if (videoOutput)
     {
-        // Set up deinterlacing in the video output method
-        m_double_framerate =
-            (videoOutput->SetupDeinterlace(true) &&
-             videoOutput->NeedsDoubleFramerate());
-
-        m_double_process = videoOutput->IsExtraProcessingRequired();
+        bool hwset = decoder->GetMythCodecContext()->setDeinterlacer(true);
+        if (hwset)
+            videoOutput->SetupDeinterlace(false);
+        else
+        {
+            // Set up deinterlacing in the video output method
+            m_double_framerate =
+                (videoOutput->SetupDeinterlace(true) &&
+                videoOutput->NeedsDoubleFramerate());
 
+            m_double_process = videoOutput->IsExtraProcessingRequired();
+        }
         videosync = VideoSync::BestMethod(videoOutput, (uint)rf_int);
 
         // Make sure video sync can do it
@@ -3808,13 +3862,22 @@ void MythPlayer::ChangeSpeed(void)
                        kScan_Intr2ndField == m_scan);
 
         videofiltersLock.lock();
-        if (m_double_framerate && !play_1)
-            videoOutput->FallbackDeint();
-        else if (!m_double_framerate && CanSupportDoubleRate() && play_1 &&
-                 inter)
-            videoOutput->BestDeint();
+        bool doublerate = m_double_framerate || decoder->GetMythCodecContext()->getDoubleRate();
+        if (doublerate && !play_1)
+        {
+            bool hwdeint = decoder->GetMythCodecContext()->FallbackDeint();
+            if (!hwdeint)
+                videoOutput->FallbackDeint();
+        }
+        else if (!m_double_framerate && CanSupportDoubleRate() && play_1
+                && (inter || decoder->GetMythCodecContext()->isDeinterlacing()))
+        {
+            videoOutput->SetupDeinterlace(false);
+            bool hwdeint = decoder->GetMythCodecContext()->BestDeint();
+            if (!hwdeint)
+                videoOutput->BestDeint();
+        }
         videofiltersLock.unlock();
-
         m_double_framerate = videoOutput->NeedsDoubleFramerate();
         m_double_process = videoOutput->IsExtraProcessingRequired();
     }
@@ -5502,8 +5565,14 @@ void MythPlayer::SetDecoder(DecoderBase *dec)
             decoder = dec;
         else
         {
+            // Copy the deinterlacer name to the new decoder.
             DecoderBase *d = decoder;
             decoder = dec;
+            if (d && decoder)
+            {
+                QString deinterlacer = d->GetMythCodecContext()->getDeinterlacerName();
+                decoder->GetMythCodecContext()->setDeinterlacer(true,deinterlacer);
+            }
             delete d;
         }
         decoder_change_lock.unlock();
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index a17364522be..fd4741e1db7 100644
--- a/mythtv/libs/libmythtv/mythplayer.h
+++ b/mythtv/libs/libmythtv/mythplayer.h
@@ -166,6 +166,7 @@ class MTV_PUBLIC MythPlayer
     void SetVideoResize(const QRect &videoRect);
     void EnableFrameRateMonitor(bool enable = false);
     void ForceDeinterlacer(const QString &override = QString());
+    void SetFrameRate(double fps);
 
     // Gets
     QSize   GetVideoBufferSize(void) const    { return video_dim; }
@@ -240,6 +241,7 @@ class MTV_PUBLIC MythPlayer
                                 int &vw, int &vh, float &ar);
     InteractiveTV *GetInteractiveTV(void);
     VideoOutput *GetVideoOutput(void)       { return videoOutput; }
+    MythCodecContext *GetMythCodecContext(void) { return decoder->GetMythCodecContext(); }
 
     // Title stuff
     virtual bool SwitchTitle(int /*title*/) { return false; }
diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp
index 5ade8680bcc..b381bf6e9fc 100644
--- a/mythtv/libs/libmythtv/tv_play.cpp
+++ b/mythtv/libs/libmythtv/tv_play.cpp
@@ -78,6 +78,7 @@ using namespace std;
 #include "programtypes.h"
 #include "ringbuffer.h"                 // for RingBuffer, etc
 #include "tv_actions.h"                 // for ACTION_TOGGLESLEEP, etc
+#include "mythcodeccontext.h"
 
 #if ! HAVE_ROUND
 #define round(x) ((int) ((x) + 0.5))
@@ -11767,7 +11768,8 @@ bool TV::MenuItemDisplayPlayback(const MenuItemContext &c)
     }
     else if (matchesGroup(actionName, "DEINTERLACER_", category, prefix))
     {
-        if (m_tvm_scan_type != kScan_Progressive)
+        if (m_tvm_scan_type != kScan_Progressive
+            || ctx->player->GetMythCodecContext()->isDeinterlacing())
         {
             foreach (QString deint, m_tvm_deinterlacers)
             {
@@ -12463,8 +12465,14 @@ void TV::PlaybackMenuInit(const MenuBase &menu)
         m_tvm_subs_havetext      = ctx->player->HasTextSubtitles();
         m_tvm_subs_forcedon      = ctx->player->GetAllowForcedSubtitles();
         ctx->player->GetVideoOutput()->GetDeinterlacers(m_tvm_deinterlacers);
-        m_tvm_currentdeinterlacer =
-            ctx->player->GetVideoOutput()->GetDeinterlacer();
+        QStringList decoderdeints
+            = ctx->player->GetMythCodecContext()->GetDeinterlacers();
+        m_tvm_deinterlacers.append(decoderdeints);
+        m_tvm_currentdeinterlacer
+            = ctx->player->GetMythCodecContext()->getDeinterlacerName();
+        if (m_tvm_currentdeinterlacer.isEmpty())
+            m_tvm_currentdeinterlacer =
+                ctx->player->GetVideoOutput()->GetDeinterlacer();
         if (m_tvm_visual)
             m_tvm_visualisers = ctx->player->GetVisualiserList();
         VideoOutput *vo = ctx->player->GetVideoOutput();
diff --git a/mythtv/libs/libmythtv/vaapi2context.cpp b/mythtv/libs/libmythtv/vaapi2context.cpp
new file mode 100644
index 00000000000..cf727b02be6
--- /dev/null
+++ b/mythtv/libs/libmythtv/vaapi2context.cpp
@@ -0,0 +1,148 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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() :
+    MythCodecContext()
+{
+
+}
+
+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()
+{
+    // example filter - deinterlace_vaapi=mode=default:rate=frame:auto=1
+    // example deinterlacername - vaapi2doubleratemotion_compensated
+    QString ret;
+    QString rate="frame";
+    if (!isValidDeinterlacer(deinterlacername))
+        return ret;
+    QString filtername = deinterlacername;
+    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;
+}
+
+bool Vaapi2Context::isValidDeinterlacer(QString filtername)
+{
+    return filtername.startsWith("vaapi2");
+}
+
+QStringList Vaapi2Context::GetDeinterlacers(void)
+{
+    return MythCodecContext::GetDeinterlacers("vaapi2");
+}
diff --git a/mythtv/libs/libmythtv/vaapi2context.h b/mythtv/libs/libmythtv/vaapi2context.h
new file mode 100644
index 00000000000..05562f0e238
--- /dev/null
+++ b/mythtv/libs/libmythtv/vaapi2context.h
@@ -0,0 +1,52 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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(void);
+    static MythCodecID GetBestSupportedCodec(AVCodec **ppCodec,
+                                             const QString &decoder,
+                                             uint stream_type,
+                                             AVPixelFormat &pix_fmt);
+    int HwDecoderInit(AVCodecContext *ctx);
+    virtual QString GetDeinterlaceFilter(void);
+    virtual bool isValidDeinterlacer(QString /*name*/ );
+    virtual QStringList GetDeinterlacers(void);
+
+};
+
+#endif // VAAPI2CONTEXT_H
\ No newline at end of file
diff --git a/mythtv/libs/libmythtv/videodisplayprofile.cpp b/mythtv/libs/libmythtv/videodisplayprofile.cpp
index 700ee3bb990..4105b3d2ca7 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
+
+#if defined(USING_VAAPI2) && defined(USING_OPENGL_VIDEO)
+    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 b689947d738..b055c2a608e 100644
--- a/mythtv/libs/libmythtv/videoout_opengl.cpp
+++ b/mythtv/libs/libmythtv/videoout_opengl.cpp
@@ -10,6 +10,7 @@
 #include "openglvideo.h"
 #include "mythrender_opengl.h"
 #include "mythpainter_ogl.h"
+#include "mythcodeccontext.h"
 
 #define LOC      QString("VidOutGL: ")
 
@@ -40,6 +41,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 +273,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 +746,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 +818,9 @@ bool VideoOutputOpenGL::SetupDeinterlace(
     if (db_vdisp_profile)
         m_deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
 
+    if (MythCodecContext::isCodecDeinterlacer(m_deintfiltername))
+        return false;
+
     if (!m_deintfiltername.contains("opengl"))
     {
         gl_videochain->SetDeinterlacing(false);
diff --git a/mythtv/libs/libmythtv/videooutbase.cpp b/mythtv/libs/libmythtv/videooutbase.cpp
index 60b2d4fa249..608eeb703b6 100644
--- a/mythtv/libs/libmythtv/videooutbase.cpp
+++ b/mythtv/libs/libmythtv/videooutbase.cpp
@@ -18,6 +18,7 @@
 #include "mythxdisplay.h"
 #include "mythavutil.h"
 #include "mthreadpool.h"
+#include "mythcodeccontext.h"
 
 #ifdef USING_XV
 #include "videoout_xv.h"
@@ -607,8 +608,16 @@ bool VideoOutput::SetupDeinterlace(bool interlaced,
         else
             m_deintfiltername = "";
 
-        m_deintFiltMan = new FilterManager;
         m_deintFilter = NULL;
+        m_deintFiltMan = NULL;
+
+        if (MythCodecContext::isCodecDeinterlacer(m_deintfiltername))
+        {
+            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 0c11bd60ce2..35a5f2877a5 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 7f87ba55caa..c169aab6a50 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 580bc606af7..83517acfefc 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
