[vlc-devel] [PATCH 8/8] dxva2_deinterlace: implement different deinterlacing mode

Steve Lhomme robux4 at videolabs.io
Sat Jul 1 18:07:14 CEST 2017


try to match the modes with existing software ones
---
 modules/video_output/Makefile.am               |   9 +-
 modules/video_output/win32/dxva2_deinterlace.c | 254 ++++++++++++++++++++-----
 2 files changed, 214 insertions(+), 49 deletions(-)

diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 68b23927dc..cf51c53e93 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -237,10 +237,11 @@ libdirect3d9_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
 	-DMODULE_NAME_IS_direct3d9
 libdirect3d9_plugin_la_LIBADD = -lgdi32 $(LIBCOM) -luuid
 libdirect3d9_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
-libdxva2_deinterlace_plugin_la_SOURCES = video_output/win32/dxva2_deinterlace.c \
-	video_chroma/d3d9_fmt.h
-libdxva2_deinterlace_plugin_la_LIBADD = $(LIBCOM)
-libdxva2_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
+libdirect3d9_deinterlace_plugin_la_SOURCES = video_output/win32/dxva2_deinterlace.c \
+        video_filter/deinterlace/common.c video_filter/deinterlace/common.h \
+        video_chroma/d3d9_fmt.h
+libdirect3d9_deinterlace_plugin_la_LIBADD = $(LIBCOM)
+libdirect3d9_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
 if HAVE_WIN32_DESKTOP
 vout_LTLIBRARIES += $(LTLIBdirect3d9)
 vout_LTLIBRARIES += $(LTLIBdxva2_deinterlace)
diff --git a/modules/video_output/win32/dxva2_deinterlace.c b/modules/video_output/win32/dxva2_deinterlace.c
index b01e46b282..3fd86a882d 100644
--- a/modules/video_output/win32/dxva2_deinterlace.c
+++ b/modules/video_output/win32/dxva2_deinterlace.c
@@ -37,6 +37,7 @@
 #include <d3d9.h>
 #include <dxva2api.h>
 #include "../../video_chroma/d3d9_fmt.h"
+#include "../../video_filter/deinterlace/common.h"
 
 struct filter_sys_t
 {
@@ -46,41 +47,136 @@ struct filter_sys_t
     IDirect3DDevice9               *d3ddev;
     IDirectXVideoProcessor         *processor;
     IDirect3DSurface9              *hw_surface;
+
+    DXVA2_VideoProcessorCaps       decoder_caps;
+
+    struct deinterlace_ctx         context;
+};
+
+#define FILTER_CFG_PREFIX "sout-deinterlace-"
+
+static const char *const mode_list[] = {
+    "blend", "bob", "x", "yadif2x", "ivtc" };
+
+/** User labels for the available deinterlace modes. */
+static const char *const mode_list_text[] = {
+    N_("Blend"), N_("Bob"), "X", "Yadif (2x)",
+    N_("Film NTSC (IVTC)") };
+
+#define DEINT_MODE_TEXT N_("Streaming deinterlace mode")
+#define DEINT_MODE_LONGTEXT N_("Deinterlace method to use for streaming.")
+
+static const char *const ppsz_filter_options[] = {
+    "mode",
+    NULL
+};
+
+struct filter_mode_t
+{
+    const char       *psz_mode;
+    UINT              i_mode;
+    deinterlace_algo  settings;
+};
+static struct filter_mode_t filter_mode [] = {
+    { "blend",   DXVA2_DeinterlaceTech_BOBLineReplicate,
+                 { false, false, false, false } },
+    { "bob",     DXVA2_DeinterlaceTech_BOBVerticalStretch,
+                 { true,  false, false, false } },
+    { "x",       DXVA2_DeinterlaceTech_BOBVerticalStretch4Tap,
+                 { true, true, false, false } },
+    { "ivtc",    DXVA2_DeinterlaceTech_InverseTelecine,
+                 { false, true, true, false } },
+    { "yadif2x", DXVA2_DeinterlaceTech_PixelAdaptive,
+                 { true,  true, false, false } },
 };
 
-static picture_t *Deinterlace(filter_t *filter, picture_t *src)
+static void Flush(filter_t *filter)
+{
+    FlushDeinterlacing(&filter->p_sys->context);
+}
+
+static void FillSample( DXVA2_VideoSample *p_sample,
+                        const struct deinterlace_ctx *p_context,
+                        picture_t *p_pic,
+                        const video_format_t *p_fmt,
+                        const RECT *p_area,
+                        int i_field )
+{
+    picture_sys_t *p_sys_src = ActivePictureSys(p_pic);
+
+    p_sample->SrcSurface = p_sys_src->surface;
+    p_sample->SampleFormat.SampleFormat = p_pic->b_top_field_first ?
+                DXVA2_SampleFieldInterleavedEvenFirst :
+                DXVA2_SampleFieldInterleavedOddFirst;
+    p_sample->Start = 0;
+    p_sample->End = GetFieldDuration(p_context, p_fmt, p_pic) * 10;
+    p_sample->SampleData = DXVA2_SampleData_RFF_TFF_Present;
+    if (!i_field)
+        p_sample->SampleData |= DXVA2_SampleData_TFF;
+    else
+        p_sample->SampleData |= DXVA2_SampleData_RFF;
+    p_sample->DstRect = p_sample->SrcRect = *p_area;
+    p_sample->PlanarAlpha    = DXVA2_Fixed32OpaqueAlpha();
+}
+
+static int RenderPic( filter_t *filter, picture_t *p_outpic, picture_t *src,
+                      int order, int i_field )
 {
     filter_sys_t *sys = filter->p_sys;
+    const int i_samples = sys->decoder_caps.NumBackwardRefSamples + 1 +
+                          sys->decoder_caps.NumForwardRefSamples;
     HRESULT hr;
     DXVA2_VideoProcessBltParams params = {0};
-    DXVA2_VideoSample sample = {0};
-    D3DSURFACE_DESC dstDesc;
+    DXVA2_VideoSample samples[i_samples];
+    picture_t         *pictures[i_samples];
+    D3DSURFACE_DESC srcDesc, dstDesc;
+    RECT area;
 
-    hr = IDirect3DSurface9_GetDesc( src->p_sys->surface, &dstDesc );
-    if (FAILED(hr))
-        return src; /* cannot deinterlace without copying fields */
+    picture_t *p_prev = sys->context.pp_history[0];
+    picture_t *p_cur  = sys->context.pp_history[1];
+    picture_t *p_next = sys->context.pp_history[2];
 
-    picture_t *dst = filter_NewPicture(filter);
-    if (dst == NULL)
-        return src; /* cannot deinterlace without copying fields */
+    picture_sys_t *p_sys_src = ActivePictureSys(src);
 
-    sample.SrcSurface = src->p_sys->surface;
-    sample.SampleFormat.SampleFormat = src->b_top_field_first ?
-                DXVA2_SampleFieldInterleavedEvenFirst :
-                DXVA2_SampleFieldInterleavedOddFirst;
-    sample.Start = 0;
-    sample.End = sample.Start + 333666;
-    sample.SampleData = DXVA2_SampleData_RFF_TFF_Present;
-    if (src->b_top_field_first)
-        sample.SampleData |= DXVA2_SampleData_TFF;
-    sample.SrcRect.bottom = dstDesc.Height;
-    sample.SrcRect.right  = dstDesc.Width;
-    sample.DstRect        = sample.SrcRect;
-    sample.PlanarAlpha    = DXVA2_Fixed32OpaqueAlpha();
-
-    params.TargetFrame = sample.Start;
-    params.TargetRect  = sample.DstRect;
-    params.DestData    = sample.SampleData;
+    hr = IDirect3DSurface9_GetDesc( p_sys_src->surface, &srcDesc );
+    if (unlikely(FAILED(hr)))
+        return VLC_EGENERIC;
+    hr = IDirect3DSurface9_GetDesc( sys->hw_surface, &dstDesc );
+    if (unlikely(FAILED(hr)))
+        return VLC_EGENERIC;
+
+    area.top = area.left = 0;
+    area.bottom = __MIN(srcDesc.Height, dstDesc.Height);
+    area.right  = __MIN(srcDesc.Width,  dstDesc.Width);
+
+    int idx = i_samples - 1;
+    if (p_next)
+    {
+        pictures[idx--] = p_next;
+        if (p_cur)
+            pictures[idx--] = p_cur;
+        if (p_prev)
+            pictures[idx--] = p_prev;
+    }
+    else
+        pictures[idx--] = src;
+    while (idx >= 0)
+        pictures[idx--] = NULL;
+
+    for (idx = 0; idx <= i_samples-1; idx++)
+    {
+        if (pictures[idx])
+            FillSample( &samples[idx], &sys->context, pictures[idx], &filter->fmt_out.video, &area, i_field);
+        else
+        {
+            FillSample( &samples[idx], &sys->context, src, &filter->fmt_out.video, &area, i_field);
+            samples[idx].SampleFormat.SampleFormat = DXVA2_SampleUnknown;
+        }
+    }
+
+    params.TargetFrame = (samples[0].End - samples[0].Start) * order / 2;
+    params.TargetRect  = area;
+    params.DestData    = 0;
     params.Alpha       = DXVA2_Fixed32OpaqueAlpha();
     params.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
     params.BackgroundColor.Alpha = 0xFFFF;
@@ -88,26 +184,43 @@ static picture_t *Deinterlace(filter_t *filter, picture_t *src)
     hr = IDirectXVideoProcessor_VideoProcessBlt( sys->processor,
                                                  sys->hw_surface,
                                                  &params,
-                                                 &sample,
-                                                 1, NULL );
+                                                 samples,
+                                                 i_samples, NULL );
     if (FAILED(hr))
-        goto error;
+        return VLC_EGENERIC;
 
     hr = IDirect3DDevice9_StretchRect( sys->d3ddev,
                                        sys->hw_surface, NULL,
-                                       dst->p_sys->surface, NULL,
+                                       p_outpic->p_sys->surface, NULL,
                                        D3DTEXF_NONE);
     if (FAILED(hr))
-        goto error;
+        return VLC_EGENERIC;
 
-    picture_CopyProperties(dst, src);
-    picture_Release(src);
-    dst->b_progressive = true;
-    dst->i_nb_fields = 1;
-    return dst;
-error:
-    picture_Release(dst);
-    return src;
+    return VLC_SUCCESS;
+}
+
+static int RenderSinglePic( filter_t *p_filter, picture_t *p_outpic, picture_t *p_pic )
+{
+    return RenderPic( p_filter, p_outpic, p_pic, 0, 0 );
+}
+
+static picture_t *Deinterlace(filter_t *p_filter, picture_t *p_pic)
+{
+    return DoDeinterlacing( p_filter, &p_filter->p_sys->context, p_pic );
+}
+
+static const struct filter_mode_t *GetFilterMode(const char *mode)
+{
+    if ( mode == NULL || !strcmp( mode, "auto" ) )
+        mode = "x";
+
+    for (size_t i=0; i<ARRAY_SIZE(filter_mode); i++)
+    {
+        if( !strcmp( mode, filter_mode[i].psz_mode ) )
+            return &filter_mode[i];
+    }
+
+    return NULL;
 }
 
 static int Open(vlc_object_t *obj)
@@ -140,6 +253,12 @@ static int Open(vlc_object_t *obj)
     if (dst == NULL)
         goto error;
 
+    if (!dst->p_sys)
+    {
+        msg_Dbg(filter, "D3D11 opaque without a texture");
+        goto error;
+    }
+
     sys = calloc(1, sizeof (*sys));
     if (unlikely(sys == NULL))
         goto error;
@@ -158,7 +277,7 @@ static int Open(vlc_object_t *obj)
 
     D3DSURFACE_DESC dstDesc;
     hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc );
-    if (FAILED(hr))
+    if (unlikely(FAILED(hr)))
         goto error;
 
     hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService,
@@ -193,16 +312,33 @@ static int Open(vlc_object_t *obj)
     if (FAILED(hr))
         goto error;
 
-    DXVA2_VideoProcessorCaps caps;
-    for (UINT i=0; i<count && processorGUID==NULL; ++i) {
+    config_ChainParse( filter, FILTER_CFG_PREFIX, ppsz_filter_options,
+                       filter->p_cfg );
+    char *psz_mode = var_InheritString( filter, FILTER_CFG_PREFIX "mode" );
+    const struct filter_mode_t *p_mode = GetFilterMode(psz_mode);
+    if (p_mode == NULL)
+    {
+        msg_Dbg(filter, "unknown mode %s, trying blend", psz_mode);
+        p_mode = GetFilterMode("blend");
+    }
+
+    DXVA2_VideoProcessorCaps caps, best_caps;
+    unsigned best_score = 0;
+    for (UINT i=0; i<count; ++i) {
         hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
                                                                   processorGUIDs+i,
                                                                   &dsc,
                                                                   dsc.Format,
                                                                   &caps);
-        if ( SUCCEEDED(hr) && caps.DeinterlaceTechnology &&
-             !caps.NumForwardRefSamples && !caps.NumBackwardRefSamples )
+        if ( FAILED(hr) || !caps.DeinterlaceTechnology )
+            continue;
+
+        unsigned score = (caps.DeinterlaceTechnology & p_mode->i_mode) ? 10 : 1;
+        if (best_score < score) {
+            best_score = score;
+            best_caps = caps;
             processorGUID = processorGUIDs + i;
+        }
     }
 
     if (processorGUID == NULL)
@@ -239,7 +375,30 @@ static int Open(vlc_object_t *obj)
 
     sys->hdecoder_dll = hdecoder_dll;
     sys->d3d9_dll     = d3d9_dll;
+    sys->decoder_caps = best_caps;
+
+    sys->context.settings = p_mode->settings;
+    sys->context.settings.b_use_frame_history = best_caps.NumBackwardRefSamples != 0 ||
+                                       best_caps.NumForwardRefSamples  != 0;
+    assert(sys->context.settings.b_use_frame_history == p_mode->settings.b_use_frame_history);
+    if (sys->context.settings.b_double_rate)
+        sys->context.pf_render_ordered = RenderPic;
+    else
+        sys->context.pf_render_single_pic = RenderSinglePic;
+
+    video_format_t out_fmt;
+    GetDeinterlacingOutput( &sys->context, &out_fmt, &filter->fmt_in.video );
+    if( !filter->b_allow_fmt_out_change &&
+         out_fmt.i_height != filter->fmt_in.video.i_height )
+    {
+       goto error;
+    }
+
+    InitDeinterlacingContext( &sys->context );
+
+    filter->fmt_out.video   = out_fmt;
     filter->pf_video_filter = Deinterlace;
+    filter->pf_flush        = Flush;
     filter->p_sys = sys;
 
     return VLC_SUCCESS;
@@ -277,10 +436,15 @@ static void Close(vlc_object_t *obj)
 }
 
 vlc_module_begin()
-    set_description(N_("DXVA2 deinterlacing filter"))
+    set_description(N_("Direct3D9 deinterlacing filter"))
     set_capability("video filter", 0)
     set_category(CAT_VIDEO)
     set_subcategory(SUBCAT_VIDEO_VFILTER)
     set_callbacks(Open, Close)
     add_shortcut ("deinterlace")
+
+    add_string( FILTER_CFG_PREFIX "mode", "auto", DEINT_MODE_TEXT,
+                DEINT_MODE_LONGTEXT, false )
+        change_string_list( mode_list, mode_list_text )
+        change_safe ()
 vlc_module_end()
-- 
2.13.0



More information about the vlc-devel mailing list