<html><head></head><body><div class="gmail_quote">Le 26 juin 2017 19:20:19 GMT+02:00, Steve Lhomme <robux4@videolabs.io> a écrit :<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<pre class="k9mail">So they can be reused by other deinterlacing implementations<br />---<br /> modules/video_filter/<a href="http://Makefile.am">Makefile.am</a>                 |   3 +-<br /> modules/video_filter/deinterlace/algo_ivtc.c     |  34 +--<br /> modules/video_filter/deinterlace/algo_phosphor.c |   4 +-<br /> modules/video_filter/deinterlace/algo_yadif.c    |  10 +-<br /> modules/video_filter/deinterlace/common.c        | 317 +++++++++++++++++++++<br /> modules/video_filter/deinterlace/common.h        |  62 ++++-<br /> modules/video_filter/deinterlace/deinterlace.c   | 334 +++--------------------<br /> modules/video_filter/deinterlace/deinterlace.h   |  37 +--<br /> 8 files changed, 445 insertions(+), 356 deletions(-)<br /> create mode 100644 modules/video_filter/deinterlace/common.c<br /><br />diff --git a/modules/video_filter/<a href="http://Makefile.am">Makefile.am</a> b/modules/video_filter/<a href="http://Makefile.am">Makefile.am</a><br />index 8fcc93c4db..a46eb3ce89 100644<br />--- a/modules/video_filter/<a href="http://Makefile.am">Makefile.am</a><br />+++ b/modules/video_filter/<a href="http://Makefile.am">Makefile.am</a><br />@@ -109,7 +109,8 @@ video_filter_LTLIBRARIES = \<br /> <br /> libdeinterlace_plugin_la_SOURCES = \<br />  video_filter/deinterlace/deinterlace.c video_filter/deinterlace/deinterlace.h \<br />- video_filter/deinterlace/mmx.h video_filter/deinterlace/common.h \<br />+        video_filter/deinterlace/mmx.h \<br />+        video_filter/deinterlace/common.c video_filter/deinterlace/common.h \<br />  video_filter/deinterlace/merge.c video_filter/deinterlace/merge.h \<br />  video_filter/deinterlace/helpers.c video_filter/deinterlace/helpers.h \<br />  video_filter/deinterlace/algo_basic.c video_filter/deinterlace/algo_basic.h \<br />diff --git a/modules/video_filter/deinterlace/algo_ivtc.c b/modules/video_filter/deinterlace/algo_ivtc.c<br />index 5603828f0e..2fb378aecb 100644<br />--- a/modules/video_filter/deinterlace/algo_ivtc.c<br />+++ b/modules/video_filter/deinterlace/algo_ivtc.c<br />@@ -406,8 +406,8 @@ static void IVTCLowLevelDetect( filter_t *p_filter )<br /> <br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br />-    picture_t *p_curr = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_curr = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br />     assert( p_curr != NULL );<br />@@ -458,7 +458,7 @@ static void IVTCCadenceDetectAlgoScores( filter_t *p_filter )<br /> <br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br /> <br />@@ -632,7 +632,7 @@ static void IVTCCadenceDetectAlgoVektor( filter_t *p_filter )<br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br /> <br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br /> <br />@@ -860,9 +860,9 @@ static void IVTCSoftTelecineDetect( filter_t *p_filter )<br /> <br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br />-    picture_t *p_prev = p_sys->pp_history[0];<br />-    picture_t *p_curr = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_prev = p_sys->context.pp_history[0];<br />+    picture_t *p_curr = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br />     assert( p_curr != NULL );<br />@@ -977,9 +977,9 @@ static void IVTCCadenceAnalyze( filter_t *p_filter )<br /> <br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br />-    picture_t *p_prev = p_sys->pp_history[0];<br />-    picture_t *p_curr = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_prev = p_sys->context.pp_history[0];<br />+    picture_t *p_curr = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br />     assert( p_curr != NULL );<br />@@ -1216,8 +1216,8 @@ static bool IVTCOutputOrDropFrame( filter_t *p_filter, picture_t *p_dst )<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br />     mtime_t t_final = VLC_TS_INVALID; /* for custom timestamp mangling */<br /> <br />-    picture_t *p_curr = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_curr = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     assert( p_next != NULL );<br />     assert( p_curr != NULL );<br />@@ -1479,9 +1479,9 @@ int RenderIVTC( filter_t *p_filter, picture_t *p_dst, picture_t *p_pic,<br />     filter_sys_t *p_sys = p_filter->p_sys;<br />     ivtc_sys_t *p_ivtc  = &p_sys->ivtc;<br /> <br />-    picture_t *p_prev = p_sys->pp_history[0];<br />-    picture_t *p_curr = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_prev = p_sys->context.pp_history[0];<br />+    picture_t *p_curr = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     /* If the history mechanism has failed, we have nothing to do. */<br />     if( !p_next )<br />@@ -1523,7 +1523,7 @@ int RenderIVTC( filter_t *p_filter, picture_t *p_dst, picture_t *p_pic,<br />         bool b_have_output_frame = IVTCOutputOrDropFrame( p_filter, p_dst );<br /> <br />         /* The next frame will get a custom timestamp, too. */<br />-        p_sys->i_frame_offset = CUSTOM_PTS;<br />+        p_sys->context.i_frame_offset = CUSTOM_PTS;<br /> <br />         if( b_have_output_frame )<br />             return VLC_SUCCESS;<br />@@ -1572,7 +1572,7 @@ int RenderIVTC( filter_t *p_filter, picture_t *p_dst, picture_t *p_pic,<br /> <br />         /* At the next frame, the filter starts. The next frame will get<br />            a custom timestamp. */<br />-        p_sys->i_frame_offset = CUSTOM_PTS;<br />+        p_sys->context.i_frame_offset = CUSTOM_PTS;<br /> <br />         picture_Copy( p_dst, p_next );<br />         return VLC_SUCCESS;<br />diff --git a/modules/video_filter/deinterlace/algo_phosphor.c b/modules/video_filter/deinterlace/algo_phosphor.c<br />index cc90ec13a6..cd954c631d 100644<br />--- a/modules/video_filter/deinterlace/algo_phosphor.c<br />+++ b/modules/video_filter/deinterlace/algo_phosphor.c<br />@@ -290,8 +290,8 @@ int RenderPhosphor( filter_t *p_filter,<br />     filter_sys_t *p_sys = p_filter->p_sys;<br /> <br />     /* Last two input frames */<br />-    picture_t *p_in  = p_sys->pp_history[HISTORY_SIZE-1];<br />-    picture_t *p_old = p_sys->pp_history[HISTORY_SIZE-2];<br />+    picture_t *p_in  = p_sys->context.pp_history[HISTORY_SIZE-1];<br />+    picture_t *p_old = p_sys->context.pp_history[HISTORY_SIZE-2];<br /> <br />     /* Use the same input picture as "old" at the first frame after startup */<br />     if( !p_old )<br />diff --git a/modules/video_filter/deinterlace/algo_yadif.c b/modules/video_filter/deinterlace/algo_yadif.c<br />index b326a17736..a3ccb1108b 100644<br />--- a/modules/video_filter/deinterlace/algo_yadif.c<br />+++ b/modules/video_filter/deinterlace/algo_yadif.c<br />@@ -59,9 +59,9 @@ int RenderYadif( filter_t *p_filter, picture_t *p_dst, picture_t *p_src,<br />     assert( i_field == 0 || i_field == 1 );<br /> <br />     /* As the pitches must match, use ONLY pictures coming from picture_New()! */<br />-    picture_t *p_prev = p_sys->pp_history[0];<br />-    picture_t *p_cur  = p_sys->pp_history[1];<br />-    picture_t *p_next = p_sys->pp_history[2];<br />+    picture_t *p_prev = p_sys->context.pp_history[0];<br />+    picture_t *p_cur  = p_sys->context.pp_history[1];<br />+    picture_t *p_next = p_sys->context.pp_history[2];<br /> <br />     /* Account for soft field repeat.<br /> <br />@@ -172,7 +172,7 @@ int RenderYadif( filter_t *p_filter, picture_t *p_dst, picture_t *p_src,<br />             }<br />         }<br /> <br />-        p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame, too */<br />+        p_sys->context.i_frame_offset = 1; /* p_cur will be rendered at next frame, too */<br /> <br />         return VLC_SUCCESS;<br />     }<br />@@ -187,7 +187,7 @@ int RenderYadif( filter_t *p_filter, picture_t *p_dst, picture_t *p_src,<br />     }<br />     else<br />     {<br />-        p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame */<br />+        p_sys->context.i_frame_offset = 1; /* p_cur will be rendered at next frame */<br /> <br />         return VLC_EGENERIC;<br />     }<br />diff --git a/modules/video_filter/deinterlace/common.c b/modules/video_filter/deinterlace/common.c<br />new file mode 100644<br />index 0000000000..e36cb1d08f<br />--- /dev/null<br />+++ b/modules/video_filter/deinterlace/common.c<br />@@ -0,0 +1,317 @@<br />+/*****************************************************************************<br />+ * common.c : Common helper function for the VLC deinterlacer<br />+ *****************************************************************************<br />+ * Copyright (C) 2000-2017 VLC authors and VideoLAN<br />+ * $Id$<br />+ *<br />+ * Author: Sam Hocevar <sam@zoy.org><br />+ *         Christophe Massiot <massiot@via.ecp.fr><br />+ *         Laurent Aimar <fenrir@videolan.org><br />+ *         Juha Jeronen <juha.jeronen@jyu.fi><br />+ *         Steve Lhomme <robux4@gmail.com><br />+ *<br />+ * This program is free software; you can redistribute it and/or modify it<br />+ * under the terms of the GNU Lesser General Public License as published by<br />+ * the Free Software Foundation; either version 2.1 of the License, or<br />+ * (at your option) any later version.<br />+ *<br />+ * This program is distributed in the hope that it will be useful,<br />+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br />+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />+ * GNU Lesser General Public License for more details.<br />+ *<br />+ * You should have received a copy of the GNU Lesser General Public License<br />+ * along with this program; if not, write to the Free Software Foundation,<br />+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br />+ *****************************************************************************/<br />+<br />+#ifdef HAVE_CONFIG_H<br />+# include "config.h"<br />+#endif<br />+<br />+#include <vlc_picture.h><br />+<br />+#include "common.h"<br />+<br />+void FlushDeinterlacing(struct deinterlace_ctx *p_context)<br />+{<br />+    p_context->meta[0].pi_date = VLC_TS_INVALID;<br />+    p_context->meta[0].pi_nb_fields = 2;<br />+    p_context->meta[0].pb_top_field_first = true;<br />+    for( int i = 1; i < METADATA_SIZE; i++ )<br />+        p_context->meta[i] = p_context->meta[i-1];<br />+<br />+    p_context->i_frame_offset = 0; /* reset to default value (first frame after<br />+                                      flush cannot have offset) */<br />+    for( int i = 0; i < HISTORY_SIZE; i++ )<br />+    {<br />+        if( p_context->pp_history[i] )<br />+            picture_Release( p_context->pp_history[i] );<br />+        p_context->pp_history[i] = NULL;<br />+    }<br />+}<br />+<br />+mtime_t GetFieldDuration(const struct deinterlace_ctx *p_context,<br />+                         const video_format_t *fmt, picture_t *p_pic )<br />+{<br />+    mtime_t i_field_dur = 0;<br />+<br />+    /* Calculate one field duration. */<br />+    int i = 0;<br />+    int iend = METADATA_SIZE-1;<br />+    /* Find oldest valid logged date.<br />+       The current input frame doesn't count. */<br />+    for( ; i < iend; i++ )<br />+        if( p_context->meta[i].pi_date > VLC_TS_INVALID )<br />+            break;<br />+    if( i < iend )<br />+    {<br />+        /* Count how many fields the valid history entries<br />+           (except the new frame) represent. */<br />+        int i_fields_total = 0;<br />+        for( int j = i ; j < iend; j++ )<br />+            i_fields_total += p_context->meta[j].pi_nb_fields;<br />+        /* One field took this long. */<br />+        i_field_dur = (p_pic->date - p_context->meta[i].pi_date) / i_fields_total;<br />+    }<br />+    else if (fmt->i_frame_rate_base)<br />+        i_field_dur = 10000 * fmt->i_frame_rate / fmt->i_frame_rate_base;<br />+<br />+    /* Note that we default to field duration 0 if it could not be<br />+       determined. This behaves the same as the old code - leaving the<br />+       extra output frame dates the same as p_pic->date if the last cached<br />+       date was not valid.<br />+    */<br />+    return i_field_dur;<br />+}<br />+<br />+void GetDeinterlacingOutput( const struct deinterlace_ctx *p_context,<br />+                             video_format_t *p_dst, const video_format_t *p_src )<br />+{<br />+    *p_dst = *p_src;<br />+<br />+    if( p_context->b_half_height )<br />+    {<br />+        p_dst->i_height /= 2;<br />+        p_dst->i_visible_height /= 2;<br />+        p_dst->i_y_offset /= 2;<br />+        p_dst->i_sar_den *= 2;<br />+    }<br />+<br />+    if( p_context->b_double_rate )<br />+    {<br />+        p_dst->i_frame_rate *= 2;<br />+    }<br />+}<br />+<br />+picture_t *DoDeinterlacing( filter_t *p_filter,<br />+                            struct deinterlace_ctx *p_context, picture_t *p_pic )<br />+{<br />+    picture_t *p_dst[DEINTERLACE_DST_SIZE];<br />+    int i_double_rate_alloc_end;<br />+    /* Remember the frame offset that we should use for this frame.<br />+       The value in p_sys will be updated to reflect the correct value<br />+       for the *next* frame when we call the renderer. */<br />+    int i_frame_offset;<br />+    int i_meta_idx;<br />+<br />+    bool b_top_field_first;<br />+<br />+    /* Request output picture */<br />+    p_dst[0] = filter_NewPicture( p_filter );<br />+    if( p_dst[0] == NULL )<br />+    {<br />+        picture_Release( p_pic );<br />+        return NULL;<br />+    }<br />+    picture_CopyProperties( p_dst[0], p_pic );<br />+<br />+    /* Any unused p_dst pointers must be NULL, because they are used to<br />+       check how many output frames we have. */<br />+    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )<br />+        p_dst[i] = NULL;<br />+<br />+    /* Update the input frame history, if the currently active algorithm<br />+       needs it. */<br />+    if( p_context->b_use_frame_history )<br />+    {<br />+        /* Keep reference for the picture */<br />+        picture_t *p_dup = picture_Hold( p_pic );<br />+<br />+        /* Slide the history */<br />+        if( p_context->pp_history[0] )<br />+            picture_Release( p_context->pp_history[0] );<br />+        for( int i = 1; i < HISTORY_SIZE; i++ )<br />+            p_context->pp_history[i-1] = p_context->pp_history[i];<br />+        p_context->pp_history[HISTORY_SIZE-1] = p_dup;<br />+    }<br />+<br />+    /* Slide the metadata history. */<br />+    for( int i = 1; i < METADATA_SIZE; i++ )<br />+        p_context->meta[i-1] = p_context->meta[i];<br />+    /* The last element corresponds to the current input frame. */<br />+    p_context->meta[METADATA_SIZE-1].pi_date            = p_pic->date;<br />+    p_context->meta[METADATA_SIZE-1].pi_nb_fields       = p_pic->i_nb_fields;<br />+    p_context->meta[METADATA_SIZE-1].pb_top_field_first = p_pic->b_top_field_first;<br />+<br />+    /* Remember the frame offset that we should use for this frame.<br />+       The value in p_sys will be updated to reflect the correct value<br />+       for the *next* frame when we call the renderer. */<br />+    i_frame_offset = p_context->i_frame_offset;<br />+    i_meta_idx     = (METADATA_SIZE-1) - i_frame_offset;<br />+<br />+    int i_nb_fields;<br />+<br />+    /* These correspond to the current *outgoing* frame. */<br />+    if( i_frame_offset != CUSTOM_PTS )<br />+    {<br />+        /* Pick the correct values from the history. */<br />+        b_top_field_first = p_context->meta[i_meta_idx].pb_top_field_first;<br />+        i_nb_fields       = p_context->meta[i_meta_idx].pi_nb_fields;<br />+    }<br />+    else<br />+    {<br />+        /* Framerate doublers must not request CUSTOM_PTS, as they need the<br />+           original field timings, and need Deinterlace() to allocate the<br />+           correct number of output frames. */<br />+        assert( !p_context->b_double_rate );<br />+<br />+        /* NOTE: i_nb_fields is only used for framerate doublers, so it is<br />+                 unused in this case. b_top_field_first is only passed to the<br />+                 algorithm. We assume that algorithms that request CUSTOM_PTS<br />+                 will, if necessary, extract the TFF/BFF information themselves.<br />+        */<br />+        b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed<br />+                                                         to be meaningful */<br />+        i_nb_fields       = p_pic->i_nb_fields;       /* unused */<br />+    }<br />+<br />+    /* For framerate doublers, determine field duration and allocate<br />+       output frames. */<br />+    i_double_rate_alloc_end = 0; /* One past last for allocated output<br />+                                        frames in p_dst[]. Used only for<br />+                                        framerate doublers. Will be inited<br />+                                        below. Declared here because the<br />+                                        PTS logic needs the result. */<br />+    if( p_context->b_double_rate )<br />+    {<br />+        i_double_rate_alloc_end = i_nb_fields;<br />+        if( i_nb_fields > DEINTERLACE_DST_SIZE )<br />+        {<br />+            /* Note that the effective buffer size depends also on the constant<br />+               private_picture in vout_wrapper.c, since that determines the<br />+               maximum number of output pictures filter_NewPicture() will<br />+               successfully allocate for one input frame.<br />+            */<br />+            msg_Err( p_filter, "Framerate doubler: output buffer too small; "\<br />+                               "fields = %d, buffer size = %d. Dropping the "\<br />+                               "remaining fields.",<br />+                               i_nb_fields, DEINTERLACE_DST_SIZE );<br />+            i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;<br />+        }<br />+<br />+        /* Allocate output frames. */<br />+        for( int i = 1; i < i_double_rate_alloc_end ; ++i )<br />+        {<br />+            p_dst[i-1]->p_next =<br />+            p_dst[i]           = filter_NewPicture( p_filter );<br />+            if( p_dst[i] )<br />+            {<br />+                picture_CopyProperties( p_dst[i], p_pic );<br />+            }<br />+            else<br />+            {<br />+                msg_Err( p_filter, "Framerate doubler: could not allocate "\<br />+                                   "output frame %d", i+1 );<br />+                i_double_rate_alloc_end = i; /* Inform the PTS logic about the<br />+                                                correct end position. */<br />+                break; /* If this happens, the rest of the allocations<br />+                          aren't likely to work, either... */<br />+            }<br />+        }<br />+        /* Now we have allocated *up to* the correct number of frames;<br />+           normally, exactly the correct number. Upon alloc failure,<br />+           we may have succeeded in allocating *some* output frames,<br />+           but fewer than were desired. In such a case, as many will<br />+           be rendered as were successfully allocated.<br />+<br />+           Note that now p_dst[i] != NULL<br />+           for 0 <= i < i_double_rate_alloc_end. */<br />+    }<br />+    assert( p_context->b_double_rate  ||  p_dst[1] == NULL );<br />+    assert( i_nb_fields > 2  ||  p_dst[2] == NULL );<br />+<br />+    /* Render */<br />+    if ( p_context->b_single_field )<br />+    {<br />+        if ( p_context->pf_render_pic( p_filter, p_dst[0], p_pic,<br />+                                       0, 0 ) )<br />+            goto drop;<br />+    }<br />+    else<br />+    {<br />+        /* Note: RenderIVTC will automatically drop the duplicate frames<br />+                 produced by IVTC. This is part of normal operation. */<br />+        if ( p_context->pf_render_pic( p_filter, p_dst[0], p_pic,<br />+                                       0, !b_top_field_first ) )<br />+            goto drop;<br />+        if ( p_dst[1] )<br />+            p_context->pf_render_pic( p_filter, p_dst[1], p_pic,<br />+                                      1, !b_top_field_first );<br />+        if ( p_dst[2] )<br />+            p_context->pf_render_pic( p_filter, p_dst[1], p_pic,<br />+                                      2, !b_top_field_first );<br />+    }<br />+<br />+    /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS<br />+       for this frame. */<br />+    assert( i_frame_offset <= METADATA_SIZE ||<br />+            i_frame_offset == CUSTOM_PTS );<br />+    if( i_frame_offset != CUSTOM_PTS )<br />+    {<br />+        mtime_t i_base_pts = p_context->meta[i_meta_idx].pi_date;<br />+<br />+        /* Note: in the usual case (i_frame_offset = 0  and<br />+                 b_double_rate = false), this effectively does nothing.<br />+                 This is needed to correct the timestamp<br />+                 when i_frame_offset > 0. */<br />+        p_dst[0]->date = i_base_pts;<br />+<br />+        if( p_context->b_double_rate )<br />+        {<br />+            mtime_t i_field_dur = GetFieldDuration( p_context, &p_pic->format, p_pic );<br />+            /* Processing all actually allocated output frames. */<br />+            for( int i = 1; i < i_double_rate_alloc_end; ++i )<br />+            {<br />+                /* XXX it's not really good especially for the first picture, but<br />+                 * I don't think that delaying by one frame is worth it */<br />+                if( i_base_pts > VLC_TS_INVALID )<br />+                    p_dst[i]->date = i_base_pts + i * i_field_dur;<br />+                else<br />+                    p_dst[i]->date = VLC_TS_INVALID;<br />+            }<br />+        }<br />+    }<br />+<br />+    for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )<br />+    {<br />+        if( p_dst[i] )<br />+        {<br />+            p_dst[i]->b_progressive = true;<br />+            p_dst[i]->i_nb_fields = 2;<br />+        }<br />+    }<br />+<br />+    picture_Release( p_pic );<br />+    return p_dst[0];<br />+<br />+drop:<br />+    picture_Release( p_dst[0] );<br />+    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )<br />+    {<br />+        if( p_dst[i] )<br />+            picture_Release( p_dst[i] );<br />+    }<br />+    picture_Release( p_pic );<br />+    return NULL;<br />+}<br />diff --git a/modules/video_filter/deinterlace/common.h b/modules/video_filter/deinterlace/common.h<br />index dcd7e63c73..739398cdb9 100644<br />--- a/modules/video_filter/deinterlace/common.h<br />+++ b/modules/video_filter/deinterlace/common.h<br />@@ -1,10 +1,11 @@<br /> /*****************************************************************************<br />  * common.h : Common macros for the VLC deinterlacer<br />  *****************************************************************************<br />- * Copyright (C) 2000-2011 VLC authors and VideoLAN<br />+ * Copyright (C) 2000-2017 VLC authors and VideoLAN<br />  * $Id$<br />  *<br />  * Author: Sam Hocevar <sam@zoy.org><br />+ *         Steve Lhomme <robux4@gmail.com><br />  *<br />  * This program is free software; you can redistribute it and/or modify it<br />  * under the terms of the GNU Lesser General Public License as published by<br />@@ -24,6 +25,11 @@<br /> #ifndef VLC_DEINTERLACE_COMMON_H<br /> #define VLC_DEINTERLACE_COMMON_H 1<br /> <br />+#include <vlc_common.h><br />+#include <vlc_filter.h><br />+<br />+#include <assert.h><br />+<br /> /**<br />  * \file<br />  * Common macros for the VLC deinterlacer.<br />@@ -35,4 +41,58 @@<br /> #define FFMIN(a,b)      __MIN(a,b)<br /> #define FFMIN3(a,b,c)   FFMIN(FFMIN(a,b),c)<br /> <br />+/**<br />+ * Metadata history structure, used for framerate doublers.<br />+ * This is used for computing field duration in Deinterlace().<br />+ * @see Deinterlace()<br />+ */<br />+typedef struct {<br />+    mtime_t pi_date;<br />+    int     pi_nb_fields;<br />+    bool    pb_top_field_first;<br />+} metadata_history_t;<br />+<br />+#define METADATA_SIZE (3)<br />+#define HISTORY_SIZE (3)<br />+#define CUSTOM_PTS -1<br />+<br />+struct deinterlace_ctx<br />+{<br />+    /* Algorithm behaviour flags */<br />+    bool b_double_rate;       /**< Shall we double the framerate? */<br />+    bool b_half_height;       /**< Shall be divide the height by 2 */<br />+    bool b_use_frame_history; /**< Use the input frame history buffer? */<br />+    bool b_single_field;      /**< The filter doesn't handle the field info */<br />+<br />+    /**<br />+     * Metadata history (PTS, nb_fields, TFF). Used for framerate doublers.<br />+     * @see metadata_history_t<br />+     */<br />+    metadata_history_t meta[METADATA_SIZE];<br />+<br />+    /** Output frame timing / framerate doubler control<br />+        (see extra documentation in deinterlace.h) */<br />+    int i_frame_offset;<br />+<br />+    /** Input frame history buffer for algorithms with temporal filtering. */<br />+    picture_t *pp_history[HISTORY_SIZE];<br />+<br />+    int (*pf_render_pic)(filter_t *p_filter, picture_t *p_dst, picture_t *p_pic,<br />+                         int order, int i_field);<br />+};<br />+<br />+#define DEINTERLACE_DST_SIZE 3<br />+<br />+mtime_t GetFieldDuration( const struct deinterlace_ctx *,<br />+                          const video_format_t *fmt, picture_t *p_pic );<br />+<br />+void GetDeinterlacingOutput( const struct deinterlace_ctx *,<br />+                             video_format_t *p_dst, const video_format_t *p_src );<br />+<br />+picture_t *DoDeinterlacing( filter_t *,<br />+                            struct deinterlace_ctx *, picture_t * );<br />+<br />+void FlushDeinterlacing( struct deinterlace_ctx * );<br />+<br />+<br /> #endif<br />diff --git a/modules/video_filter/deinterlace/deinterlace.c b/modules/video_filter/deinterlace/deinterlace.c<br />index a1efcf6b8e..392e9c9d7b 100644<br />--- a/modules/video_filter/deinterlace/deinterlace.c<br />+++ b/modules/video_filter/deinterlace/deinterlace.c<br />@@ -151,43 +151,43 @@ static void SetFilterMethod( filter_t *p_filter, const char *mode, bool pack )<br />     if ( mode == NULL )<br />         mode = "auto";<br /> <br />-    p_sys->b_double_rate = false;<br />-    p_sys->b_half_height = false;<br />-    p_sys->b_use_frame_history = false;<br />-    p_sys->b_single_field = false;<br />+    p_sys->context.b_double_rate = false;<br />+    p_sys->context.b_half_height = false;<br />+    p_sys->context.b_use_frame_history = false;<br />+    p_sys->context.b_single_field = false;<br />     p_sys->b_phosphor_mode = false;<br /> <br />     if ( !strcmp( mode, "auto" ) || !strcmp( mode, "x" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderX;<br />-        p_sys->b_single_field = true;<br />+        p_sys->context.pf_render_pic = RenderX;<br />+        p_sys->context.b_single_field = true;<br />     }<br />     else if( !strcmp( mode, "discard" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderDiscard;<br />-        p_sys->b_single_field = true;<br />-        p_sys->b_half_height = true;<br />+        p_sys->context.pf_render_pic = RenderDiscard;<br />+        p_sys->context.b_single_field = true;<br />+        p_sys->context.b_half_height = true;<br />     }<br />     else if( !strcmp( mode, "bob" ) || !strcmp( mode, "progressive-scan" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderBob;<br />-        p_sys->b_double_rate = true;<br />+        p_sys->context.pf_render_pic = RenderBob;<br />+        p_sys->context.b_double_rate = true;<br />     }<br />     else if( !strcmp( mode, "linear" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderLinear;<br />-        p_sys->b_double_rate = true;<br />+        p_sys->context.pf_render_pic = RenderLinear;<br />+        p_sys->context.b_double_rate = true;<br />     }<br />     else if( !strcmp( mode, "mean" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderMean;<br />-        p_sys->b_single_field = true;<br />-        p_sys->b_half_height = true;<br />+        p_sys->context.pf_render_pic = RenderMean;<br />+        p_sys->context.b_single_field = true;<br />+        p_sys->context.b_half_height = true;<br />     }<br />     else if( !strcmp( mode, "blend" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderBlend;<br />-        p_sys->b_single_field = true;<br />+        p_sys->context.pf_render_pic = RenderBlend;<br />+        p_sys->context.b_single_field = true;<br />     }<br />     else if( pack )<br />     {<br />@@ -197,15 +197,15 @@ static void SetFilterMethod( filter_t *p_filter, const char *mode, bool pack )<br />     }<br />     else if( !strcmp( mode, "yadif" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderYadif;<br />-        p_sys->b_single_field = true;<br />-        p_sys->b_use_frame_history = true;<br />+        p_sys->context.pf_render_pic = RenderYadif;<br />+        p_sys->context.b_single_field = true;<br />+        p_sys->context.b_use_frame_history = true;<br />     }<br />     else if( !strcmp( mode, "yadif2x" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderYadif;<br />-        p_sys->b_double_rate = true;<br />-        p_sys->b_use_frame_history = true;<br />+        p_sys->context.pf_render_pic = RenderYadif;<br />+        p_sys->context.b_double_rate = true;<br />+        p_sys->context.b_use_frame_history = true;<br />     }<br />     else if( p_sys->chroma->pixel_size > 1 )<br />     {<br />@@ -215,16 +215,16 @@ static void SetFilterMethod( filter_t *p_filter, const char *mode, bool pack )<br />     }<br />     else if( !strcmp( mode, "phosphor" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderPhosphor;<br />+        p_sys->context.pf_render_pic = RenderPhosphor;<br />         p_sys->b_phosphor_mode = true;<br />-        p_sys->b_double_rate = true;<br />-        p_sys->b_use_frame_history = true;<br />+        p_sys->context.b_double_rate = true;<br />+        p_sys->context.b_use_frame_history = true;<br />     }<br />     else if( !strcmp( mode, "ivtc" ) )<br />     {<br />-        p_sys->pf_render_pic = RenderIVTC;<br />-        p_sys->b_single_field = true;<br />-        p_sys->b_use_frame_history = true;<br />+        p_sys->context.pf_render_pic = RenderIVTC;<br />+        p_sys->context.b_single_field = true;<br />+        p_sys->context.b_use_frame_history = true;<br />     }<br />     else<br />         msg_Err( p_filter, "unknown deinterlace mode \"%s\"", mode );<br />@@ -248,20 +248,8 @@ static void GetOutputFormat( filter_t *p_filter,<br />                       video_format_t *p_dst, const video_format_t *p_src )<br /> {<br />     filter_sys_t *p_sys = p_filter->p_sys;<br />-    *p_dst = *p_src;<br /> <br />-    if( p_sys->b_half_height )<br />-    {<br />-        p_dst->i_height /= 2;<br />-        p_dst->i_visible_height /= 2;<br />-        p_dst->i_y_offset /= 2;<br />-        p_dst->i_sar_den *= 2;<br />-    }<br />-<br />-    if( p_sys->b_double_rate )<br />-    {<br />-        p_dst->i_frame_rate *= 2;<br />-    }<br />+    GetDeinterlacingOutput(&p_sys->context, p_dst, p_src);<br /> <br />     if( p_sys->b_phosphor_mode &&<br />         2 * p_sys->chroma->p[1].h.num == p_sys->chroma->p[1].h.den &&<br />@@ -282,240 +270,10 @@ static void GetOutputFormat( filter_t *p_filter,<br />  * video filter functions<br />  *****************************************************************************/<br /> <br />-#define DEINTERLACE_DST_SIZE 3<br />-<br />-static mtime_t GetFieldDuration( metadata_history_t meta[static METADATA_SIZE],<br />-                                 picture_t *p_pic )<br />-{<br />-    mtime_t i_field_dur = 0;<br />-<br />-    /* Calculate one field duration. */<br />-    int i = 0;<br />-    int iend = METADATA_SIZE-1;<br />-    /* Find oldest valid logged date.<br />-       The current input frame doesn't count. */<br />-    for( ; i < iend; i++ )<br />-        if( meta[i].pi_date > VLC_TS_INVALID )<br />-            break;<br />-    if( i < iend )<br />-    {<br />-        /* Count how many fields the valid history entries<br />-           (except the new frame) represent. */<br />-        int i_fields_total = 0;<br />-        for( int j = i ; j < iend; j++ )<br />-            i_fields_total += meta[j].pi_nb_fields;<br />-        /* One field took this long. */<br />-        i_field_dur = (p_pic->date - meta[i].pi_date) / i_fields_total;<br />-    }<br />-    /* Note that we default to field duration 0 if it could not be<br />-       determined. This behaves the same as the old code - leaving the<br />-       extra output frame dates the same as p_pic->date if the last cached<br />-       date was not valid.<br />-    */<br />-    return i_field_dur;<br />-}<br />-<br /> /* This is the filter function. See Open(). */<br /> picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )<br /> {<br />-    filter_sys_t *p_sys = p_filter->p_sys;<br />-    picture_t *p_dst[DEINTERLACE_DST_SIZE];<br />-<br />-    /* Request output picture */<br />-    p_dst[0] = filter_NewPicture( p_filter );<br />-    if( p_dst[0] == NULL )<br />-    {<br />-        picture_Release( p_pic );<br />-        return NULL;<br />-    }<br />-    picture_CopyProperties( p_dst[0], p_pic );<br />-<br />-    /* Any unused p_dst pointers must be NULL, because they are used to<br />-       check how many output frames we have. */<br />-    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )<br />-        p_dst[i] = NULL;<br />-<br />-    /* Update the input frame history, if the currently active algorithm<br />-       needs it. */<br />-    if( p_sys->b_use_frame_history )<br />-    {<br />-        /* Keep reference for the picture */<br />-        picture_t *p_dup = picture_Hold( p_pic );<br />-<br />-        /* Slide the history */<br />-        if( p_sys->pp_history[0] )<br />-            picture_Release( p_sys->pp_history[0] );<br />-        for( int i = 1; i < HISTORY_SIZE; i++ )<br />-            p_sys->pp_history[i-1] = p_sys->pp_history[i];<br />-        p_sys->pp_history[HISTORY_SIZE-1] = p_dup;<br />-    }<br />-<br />-    /* Slide the metadata history. */<br />-    for( int i = 1; i < METADATA_SIZE; i++ )<br />-        p_sys->meta[i-1] = p_sys->meta[i];<br />-    /* The last element corresponds to the current input frame. */<br />-    p_sys->meta[METADATA_SIZE-1].pi_date            = p_pic->date;<br />-    p_sys->meta[METADATA_SIZE-1].pi_nb_fields       = p_pic->i_nb_fields;<br />-    p_sys->meta[METADATA_SIZE-1].pb_top_field_first = p_pic->b_top_field_first;<br />-<br />-    /* Remember the frame offset that we should use for this frame.<br />-       The value in p_sys will be updated to reflect the correct value<br />-       for the *next* frame when we call the renderer. */<br />-    int i_frame_offset = p_sys->i_frame_offset;<br />-    int i_meta_idx     = (METADATA_SIZE-1) - i_frame_offset;<br />-<br />-    /* These correspond to the current *outgoing* frame. */<br />-    bool b_top_field_first;<br />-    int i_nb_fields;<br />-    if( i_frame_offset != CUSTOM_PTS )<br />-    {<br />-        /* Pick the correct values from the history. */<br />-        b_top_field_first = p_sys->meta[i_meta_idx].pb_top_field_first;<br />-        i_nb_fields       = p_sys->meta[i_meta_idx].pi_nb_fields;<br />-    }<br />-    else<br />-    {<br />-        /* Framerate doublers must not request CUSTOM_PTS, as they need the<br />-           original field timings, and need Deinterlace() to allocate the<br />-           correct number of output frames. */<br />-        assert( !p_sys->b_double_rate );<br />-<br />-        /* NOTE: i_nb_fields is only used for framerate doublers, so it is<br />-                 unused in this case. b_top_field_first is only passed to the<br />-                 algorithm. We assume that algorithms that request CUSTOM_PTS<br />-                 will, if necessary, extract the TFF/BFF information themselves.<br />-        */<br />-        b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed<br />-                                                         to be meaningful */<br />-        i_nb_fields       = p_pic->i_nb_fields;       /* unused */<br />-    }<br />-<br />-    /* For framerate doublers, determine field duration and allocate<br />-       output frames. */<br />-    int i_double_rate_alloc_end = 0; /* One past last for allocated output<br />-                                        frames in p_dst[]. Used only for<br />-                                        framerate doublers. Will be inited<br />-                                        below. Declared here because the<br />-                                        PTS logic needs the result. */<br />-    if( p_sys->b_double_rate )<br />-    {<br />-        i_double_rate_alloc_end = i_nb_fields;<br />-        if( i_nb_fields > DEINTERLACE_DST_SIZE )<br />-        {<br />-            /* Note that the effective buffer size depends also on the constant<br />-               private_picture in vout_wrapper.c, since that determines the<br />-               maximum number of output pictures filter_NewPicture() will<br />-               successfully allocate for one input frame.<br />-            */<br />-            msg_Err( p_filter, "Framerate doubler: output buffer too small; "\<br />-                               "fields = %d, buffer size = %d. Dropping the "\<br />-                               "remaining fields.",<br />-                               i_nb_fields, DEINTERLACE_DST_SIZE );<br />-            i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;<br />-        }<br />-<br />-        /* Allocate output frames. */<br />-        for( int i = 1; i < i_double_rate_alloc_end ; ++i )<br />-        {<br />-            p_dst[i-1]->p_next =<br />-            p_dst[i]           = filter_NewPicture( p_filter );<br />-            if( p_dst[i] )<br />-            {<br />-                picture_CopyProperties( p_dst[i], p_pic );<br />-            }<br />-            else<br />-            {<br />-                msg_Err( p_filter, "Framerate doubler: could not allocate "\<br />-                                   "output frame %d", i+1 );<br />-                i_double_rate_alloc_end = i; /* Inform the PTS logic about the<br />-                                                correct end position. */<br />-                break; /* If this happens, the rest of the allocations<br />-                          aren't likely to work, either... */<br />-            }<br />-        }<br />-        /* Now we have allocated *up to* the correct number of frames;<br />-           normally, exactly the correct number. Upon alloc failure,<br />-           we may have succeeded in allocating *some* output frames,<br />-           but fewer than were desired. In such a case, as many will<br />-           be rendered as were successfully allocated.<br />-<br />-           Note that now p_dst[i] != NULL<br />-           for 0 <= i < i_double_rate_alloc_end. */<br />-    }<br />-    assert( p_sys->b_double_rate  ||  p_dst[1] == NULL );<br />-    assert( i_nb_fields > 2  ||  p_dst[2] == NULL );<br />-<br />-    /* Render */<br />-    if ( p_sys->b_single_field )<br />-    {<br />-        if ( p_sys->pf_render_pic( p_filter, p_dst[0], p_pic, 0, 0 ) )<br />-            goto drop;<br />-    }<br />-    else<br />-    {<br />-        /* Note: RenderIVTC will automatically drop the duplicate frames<br />-                 produced by IVTC. This is part of normal operation. */<br />-        if ( p_sys->pf_render_pic( p_filter, p_dst[0], p_pic,<br />-                                   0, !b_top_field_first ) )<br />-            goto drop;<br />-        if ( p_dst[1] )<br />-            p_sys->pf_render_pic( p_filter, p_dst[1], p_pic,<br />-                                  1, !b_top_field_first );<br />-        if ( p_dst[2] )<br />-            p_sys->pf_render_pic( p_filter, p_dst[1], p_pic,<br />-                                  2, !b_top_field_first );<br />-    }<br />-<br />-    /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS<br />-       for this frame. */<br />-    assert( i_frame_offset <= METADATA_SIZE  ||  i_frame_offset == CUSTOM_PTS );<br />-    if( i_frame_offset != CUSTOM_PTS )<br />-    {<br />-        mtime_t i_base_pts = p_sys->meta[i_meta_idx].pi_date;<br />-<br />-        /* Note: in the usual case (i_frame_offset = 0  and<br />-                 b_double_rate = false), this effectively does nothing.<br />-                 This is needed to correct the timestamp<br />-                 when i_frame_offset > 0. */<br />-        p_dst[0]->date = i_base_pts;<br />-<br />-        if( p_sys->b_double_rate )<br />-        {<br />-            mtime_t i_field_dur = GetFieldDuration( p_sys->meta, p_pic );<br />-            /* Processing all actually allocated output frames. */<br />-            for( int i = 1; i < i_double_rate_alloc_end; ++i )<br />-            {<br />-                /* XXX it's not really good especially for the first picture, but<br />-                 * I don't think that delaying by one frame is worth it */<br />-                if( i_base_pts > VLC_TS_INVALID )<br />-                    p_dst[i]->date = i_base_pts + i * i_field_dur;<br />-                else<br />-                    p_dst[i]->date = VLC_TS_INVALID;<br />-            }<br />-        }<br />-    }<br />-<br />-    for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )<br />-    {<br />-        if( p_dst[i] )<br />-        {<br />-            p_dst[i]->b_progressive = true;<br />-            p_dst[i]->i_nb_fields = 2;<br />-        }<br />-    }<br />-<br />-    picture_Release( p_pic );<br />-    return p_dst[0];<br />-<br />-drop:<br />-    picture_Release( p_dst[0] );<br />-    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )<br />-    {<br />-        if( p_dst[i] )<br />-            picture_Release( p_dst[i] );<br />-    }<br />-    picture_Release( p_pic );<br />-    return NULL;<br />+    return DoDeinterlacing( p_filter, &p_filter->p_sys->context, p_pic );<br /> }<br /> <br /> /*****************************************************************************<br />@@ -524,22 +282,8 @@ drop:<br /> <br /> void Flush( filter_t *p_filter )<br /> {<br />-    filter_sys_t *p_sys = p_filter->p_sys;<br />+    FlushDeinterlacing(&p_filter->p_sys->context);<br /> <br />-    for( int i = 0; i < METADATA_SIZE; i++ )<br />-    {<br />-        p_sys->meta[i].pi_date = VLC_TS_INVALID;<br />-        p_sys->meta[i].pi_nb_fields = 2;<br />-        p_sys->meta[i].pb_top_field_first = true;<br />-    }<br />-    p_sys->i_frame_offset = 0; /* reset to default value (first frame after<br />-                                  flush cannot have offset) */<br />-    for( int i = 0; i < HISTORY_SIZE; i++ )<br />-    {<br />-        if( p_sys->pp_history[i] )<br />-            picture_Release( p_sys->pp_history[i] );<br />-        p_sys->pp_history[i] = NULL;<br />-    }<br />     IVTCClearState( p_filter );<br /> }<br /> <br />@@ -553,7 +297,7 @@ int Mouse( filter_t *p_filter,<br /> {<br />     VLC_UNUSED(p_old);<br />     *p_mouse = *p_new;<br />-    if( p_filter->p_sys->b_half_height )<br />+    if( p_filter->p_sys->context.b_half_height )<br />         p_mouse->i_y *= 2;<br />     return VLC_SUCCESS;<br /> }<br />@@ -613,14 +357,14 @@ notsupp:<br /> <br />     for( int i = 0; i < METADATA_SIZE; i++ )<br />     {<br />-        p_sys->meta[i].pi_date = VLC_TS_INVALID;<br />-        p_sys->meta[i].pi_nb_fields = 2;<br />-        p_sys->meta[i].pb_top_field_first = true;<br />+        p_sys->context.meta[i].pi_date = VLC_TS_INVALID;<br />+        p_sys->context.meta[i].pi_nb_fields = 2;<br />+        p_sys->context.meta[i].pb_top_field_first = true;<br />     }<br />-    p_sys->i_frame_offset = 0; /* start with default value (first-ever frame<br />+    p_sys->context.i_frame_offset = 0; /* start with default value (first-ever frame<br />                                   cannot have offset) */<br />     for( int i = 0; i < HISTORY_SIZE; i++ )<br />-        p_sys->pp_history[i] = NULL;<br />+        p_sys->context.pp_history[i] = NULL;<br /> <br />     IVTCClearState( p_filter );<br /> <br />diff --git a/modules/video_filter/deinterlace/deinterlace.h b/modules/video_filter/deinterlace/deinterlace.h<br />index 728a7ff5fc..9d951b9881 100644<br />--- a/modules/video_filter/deinterlace/deinterlace.h<br />+++ b/modules/video_filter/deinterlace/deinterlace.h<br />@@ -42,6 +42,7 @@ struct vlc_object_t;<br /> #include "algo_yadif.h"<br /> #include "algo_phosphor.h"<br /> #include "algo_ivtc.h"<br />+#include "common.h"<br /> <br /> /*****************************************************************************<br />  * Local data<br />@@ -61,20 +62,6 @@ static const char *const mode_list_text[] = {<br />  * Data structures<br />  *****************************************************************************/<br /> <br />-#define METADATA_SIZE (3)<br />-/**<br />- * Metadata history structure, used for framerate doublers.<br />- * This is used for computing field duration in Deinterlace().<br />- * @see Deinterlace()<br />- */<br />-typedef struct {<br />-    mtime_t pi_date;<br />-    int     pi_nb_fields;<br />-    bool    pb_top_field_first;<br />-} metadata_history_t;<br />-<br />-#define HISTORY_SIZE (3)<br />-#define CUSTOM_PTS -1<br /> /**<br />  * Top-level deinterlace subsystem state.<br />  */<br />@@ -82,12 +69,6 @@ struct filter_sys_t<br /> {<br />     const vlc_chroma_description_t *chroma;<br /> <br />-    /* Algorithm behaviour flags */<br />-    bool b_double_rate;       /**< Shall we double the framerate? */<br />-    bool b_half_height;       /**< Shall be divide the height by 2 */<br />-    bool b_use_frame_history; /**< Use the input frame history buffer? */<br />-    bool b_single_field;      /**< The filter doesn't handle the field info */<br />-<br />     /** Merge routine: C, MMX, SSE, ALTIVEC, NEON, ... */<br />     void (*pf_merge) ( void *, const void *, const void *, size_t );<br /> #if defined (__i386__) || defined (__x86_64__)<br />@@ -95,21 +76,7 @@ struct filter_sys_t<br />     void (*pf_end_merge) ( void );<br /> #endif<br /> <br />-    int (*pf_render_pic)(filter_t *p_filter, picture_t *p_dst, picture_t *p_pic,<br />-                         int order, int i_field);<br />-<br />-    /**<br />-     * Metadata history (PTS, nb_fields, TFF). Used for framerate doublers.<br />-     * @see metadata_history_t<br />-     */<br />-    metadata_history_t meta[METADATA_SIZE];<br />-<br />-    /** Output frame timing / framerate doubler control<br />-        (see extra documentation in deinterlace.h) */<br />-    int i_frame_offset;<br />-<br />-    /** Input frame history buffer for algorithms with temporal filtering. */<br />-    picture_t *pp_history[HISTORY_SIZE];<br />+    struct deinterlace_ctx   context;<br /> <br />     /* Algorithm-specific substructures */<br />     bool b_phosphor_mode;     /**< The filter mode is "phosphor" */</pre></blockquote></div><br clear="all">For empirical reasons, I fear that this ends up worse rather than better. Sure, in theory, this is reusable... But look at the decoder synch stuff that was also supposed to be reusable...<br>
<br>
Case in point, VDPAU has its own history implementation, and it is very compact. Using this code would probably involve reverse abstraction antipattern, and make the code overall more intricate...<br>
-- <br>
Rémi Denis-Courmont<br>
Typed on an inconvenient virtual keyboard</body></html>