[vlc-devel] [PATCH 7/9] deinterlace: merge separate fields into a picture to match other sources

Steve Lhomme robux4 at ycbcr.xyz
Mon Nov 16 13:44:18 CET 2020


Set the default to blend in that case as other modes produce various artifacts
from a correct looking source. yadif and yadif2 also give good results.

Filters not setting b_merge_fields won't have MergeFields called.

Direct3D11 implementation is possible via shaders.
---
 modules/hw/d3d11/d3d11_deinterlace.c          |  5 ++
 modules/hw/d3d9/dxva2_deinterlace.c           |  6 +++
 modules/video_filter/deinterlace/common.c     | 47 +++++++++++++++++++
 modules/video_filter/deinterlace/common.h     |  5 ++
 .../video_filter/deinterlace/deinterlace.c    | 29 +++++++++++-
 5 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/modules/hw/d3d11/d3d11_deinterlace.c b/modules/hw/d3d11/d3d11_deinterlace.c
index fafb4fd84b6..0d7bc095b8a 100644
--- a/modules/hw/d3d11/d3d11_deinterlace.c
+++ b/modules/hw/d3d11/d3d11_deinterlace.c
@@ -219,6 +219,11 @@ picture_t *AllocPicture( filter_t *p_filter )
     return pic;
 }
 
+void MergeFields( filter_t *p_filter, picture_t *merged, picture_t *fields[2])
+{
+    vlc_assert_unreachable(); // TODO add b_merge_fields support
+}
+
 static void D3D11CloseDeinterlace(filter_t *filter)
 {
     filter_sys_t *sys = filter->p_sys;
diff --git a/modules/hw/d3d9/dxva2_deinterlace.c b/modules/hw/d3d9/dxva2_deinterlace.c
index 65cacdad59b..ea5be24e008 100644
--- a/modules/hw/d3d9/dxva2_deinterlace.c
+++ b/modules/hw/d3d9/dxva2_deinterlace.c
@@ -321,6 +321,12 @@ picture_t *AllocPicture( filter_t *p_filter )
     return pic;
 }
 
+void MergeFields( filter_t *p_filter, picture_t *merged, picture_t *fields[2])
+{
+    VLC_UNUSED(p_filter); VLC_UNUSED(merged); VLC_UNUSED(fields);
+    vlc_assert_unreachable(); // b_merge_fields not supported
+}
+
 
 static void D3D9CloseDeinterlace(filter_t *filter)
 {
diff --git a/modules/video_filter/deinterlace/common.c b/modules/video_filter/deinterlace/common.c
index 94a6280e37e..13b33feb0d1 100644
--- a/modules/video_filter/deinterlace/common.c
+++ b/modules/video_filter/deinterlace/common.c
@@ -49,10 +49,19 @@ void InitDeinterlacingContext( struct deinterlace_ctx *p_context )
                                   cannot have offset) */
     for( int i = 0; i < HISTORY_SIZE; i++ )
         p_context->pp_history[i] = NULL;
+
+    p_context->b_merge_fields = false;
+    p_context->prev = NULL;
 }
 
 void FlushDeinterlacing(struct deinterlace_ctx *p_context)
 {
+    if ( p_context->prev )
+    {
+        picture_Release( p_context->prev );
+        p_context->prev = NULL;
+    }
+
     p_context->meta[0].pi_date = VLC_TICK_INVALID;
     p_context->meta[0].pi_nb_fields = 2;
     p_context->meta[0].pb_top_field_first = true;
@@ -108,6 +117,15 @@ void GetDeinterlacingOutput( const struct deinterlace_ctx *p_context,
 {
     *p_dst = *p_src;
 
+    if( p_context->b_merge_fields )
+    {
+        p_dst->i_num_fields = 2;
+        p_dst->i_height *= 2;
+        p_dst->i_visible_height *= 2;
+        p_dst->i_y_offset *= 2;
+        p_dst->i_frame_rate /= 2; // we turn 2 picture_t into 1
+    }
+
     if( p_context->settings.b_half_height )
     {
         p_dst->i_height /= 2;
@@ -127,6 +145,35 @@ void GetDeinterlacingOutput( const struct deinterlace_ctx *p_context,
 picture_t *DoDeinterlacing( filter_t *p_filter,
                             struct deinterlace_ctx *p_context, picture_t *p_pic )
 {
+    if ( p_context->b_merge_fields && p_pic != NULL )
+    {
+        if ( p_context->prev == NULL )
+        {
+            p_context->prev = p_pic;
+            return NULL;
+        }
+
+        picture_t *out = AllocPicture( p_filter );
+        if (likely(out != NULL))
+        {
+            picture_t *src_pics[2] = { p_context->prev, p_pic };
+
+            MergeFields( p_filter, out, src_pics );
+
+            out->date = p_pic->date;
+            out->b_force = p_pic->b_force;
+            out->b_still = p_pic->b_still;
+
+            out->b_top_field_first = p_pic->b_top_field_first;
+        }
+        picture_Release( p_context->prev );
+        p_context->prev = NULL;
+        picture_Release( p_pic );
+        if (out == NULL)
+            return NULL;
+        p_pic = out;
+    }
+
     picture_t *p_dst[DEINTERLACE_DST_SIZE];
     int i_double_rate_alloc_end;
     /* Remember the frame offset that we should use for this frame.
diff --git a/modules/video_filter/deinterlace/common.h b/modules/video_filter/deinterlace/common.h
index 144523647c2..160ec2c567a 100644
--- a/modules/video_filter/deinterlace/common.h
+++ b/modules/video_filter/deinterlace/common.h
@@ -66,6 +66,10 @@ struct deinterlace_ctx
     /* Algorithm behaviour flags */
     deinterlace_algo   settings;
 
+    /* Incoming pictures only contain one field */
+    bool        b_merge_fields;
+    picture_t  *prev;
+
     /**
      * Metadata history (PTS, nb_fields, TFF). Used for framerate doublers.
      * @see metadata_history_t
@@ -123,5 +127,6 @@ picture_t *DoDeinterlacing( filter_t *, struct deinterlace_ctx *, picture_t * );
 void FlushDeinterlacing( struct deinterlace_ctx * );
 
 picture_t *AllocPicture( filter_t * );
+void MergeFields( filter_t *, picture_t *merged, picture_t *fields[2]);
 
 #endif
diff --git a/modules/video_filter/deinterlace/deinterlace.c b/modules/video_filter/deinterlace/deinterlace.c
index 62bd077c0a2..cf4b4deb367 100644
--- a/modules/video_filter/deinterlace/deinterlace.c
+++ b/modules/video_filter/deinterlace/deinterlace.c
@@ -378,7 +378,12 @@ static void SetFilterMethod( filter_t *p_filter, const char *mode, bool pack )
     filter_sys_t *p_sys = p_filter->p_sys;
 
     if ( mode == NULL || !strcmp( mode, "auto" ) )
-        mode = "x";
+    {
+        if ( p_sys->context.b_merge_fields )
+            mode = "blend";
+        else
+            mode = "x";
+    }
 
     for ( size_t i = 0; i < ARRAY_SIZE(filter_mode); i++ )
     {
@@ -434,9 +439,27 @@ static void GetOutputFormat( filter_t *p_filter,
 
 picture_t *AllocPicture( filter_t *filter )
 {
-    return filter_NewPicture( filter );
+    // TODO update the private pool after format update return filter_NewPicture( filter );
+    return picture_NewFromFormat( &filter->fmt_out.video );
 }
 
+void MergeFields( filter_t *p_filter, picture_t *merged, picture_t *fields[2])
+{
+    VLC_UNUSED(p_filter);
+    for (int plane=0; plane<merged->i_planes; plane++)
+    {
+        plane_t dst = merged->p[plane];
+        const plane_t *src1 = &fields[0]->p[plane];
+        const plane_t *src2 = &fields[1]->p[plane];
+
+        dst.i_pitch *= 2; // every other line
+        plane_CopyPixels(&dst, src1);
+        dst.p_pixels += dst.i_pitch / 2; // other field
+        plane_CopyPixels(&dst, src2);
+    }
+}
+
+
 /* This is the filter function. See Open(). */
 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
 {
@@ -540,6 +563,8 @@ notsupp:
 
     config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
                        p_filter->p_cfg );
+    p_sys->context.b_merge_fields = p_filter->fmt_in.video.i_num_fields == 1;
+
     char *psz_mode = var_InheritString( p_filter, FILTER_CFG_PREFIX "mode" );
     SetFilterMethod( p_filter, psz_mode, packed );
 
-- 
2.26.2



More information about the vlc-devel mailing list