[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,
¶ms,
- &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