]> granicus.if.org Git - handbrake/commitdiff
deinterlace: use avfilter yadif deinterlacer
authorJohn Stebbins <jstebbins.hb@gmail.com>
Mon, 9 Nov 2015 21:37:32 +0000 (13:37 -0800)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Mon, 15 Feb 2016 19:38:13 +0000 (12:38 -0700)
gtk/src/hb-backend.c
libhb/avfilter.c
libhb/builtin_presets.h
libhb/deinterlace.c [deleted file]
libhb/libhb_presets.list
libhb/param.c
libhb/preset.c
test/test.c

index ce262335ee91fddcb1f55ff4d575861fcd88b3a5..ccadcfbd4a1ea19e48c1ea37c8cc311259bd7dcb 100644 (file)
@@ -200,7 +200,7 @@ static options_map_t d_deint_opts[] =
 {
     {N_("Off"),         "off",         HB_FILTER_INVALID,     ""},
     {N_("Decomb"),      "decomb",      HB_FILTER_DECOMB,      ""},
-    {N_("Deinterlace"), "deinterlace", HB_FILTER_DEINTERLACE, ""},
+    {N_("Yadif"),       "deinterlace", HB_FILTER_DEINTERLACE, ""},
 };
 combo_opts_t deint_opts =
 {
index b145b7a0d3222dbb40f5a7d0220f6d4ee199a45f..4c1f1d1650ccf0fd102ee9e39e4b5a5a214779c0 100644 (file)
@@ -74,6 +74,18 @@ hb_filter_object_t hb_filter_rotate =
     .info          = avfilter_info,
 };
 
+hb_filter_object_t hb_filter_deinterlace =
+{
+    .id            = HB_FILTER_DEINTERLACE,
+    .enforce_order = 1,
+    .name          = "avfilter",
+    .settings      = NULL,
+    .init          = avfilter_init,
+    .work          = avfilter_work,
+    .close         = avfilter_close,
+    .info          = avfilter_info,
+};
+
 static AVFilterContext * append_filter( hb_filter_private_t * pv,
                                         const char * name, const char * args)
 {
@@ -429,6 +441,7 @@ void hb_avfilter_combine( hb_list_t * list )
         {
             case HB_FILTER_AVFILTER:
             case HB_FILTER_ROTATE:
+            case HB_FILTER_DEINTERLACE:
             case HB_FILTER_PAD:
                 if (avfilter != NULL)
                 {
index fa4236e3fe19957bb593e577aa1c82277a41946f..5ab646f1986e076ae92fd77b3718f89260becdc7 100644 (file)
@@ -858,6 +858,6 @@ const char hb_builtin_presets_json[] =
 "        }, \n"
 "        \"VersionMajor\": 11, \n"
 "        \"VersionMicro\": 0, \n"
-"        \"VersionMinor\": 0\n"
+"        \"VersionMinor\": 1\n"
 "    }\n"
 "}\n";
diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c
deleted file mode 100644 (file)
index a402a52..0000000
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
-
- 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 St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#include "hb.h"
-#include "hbffmpeg.h"
-#include "taskset.h"
-
-// yadif_mode is a bit vector with the following flags
-#define MODE_YADIF_ENABLE       1
-#define MODE_YADIF_SPATIAL      2
-#define MODE_YADIF_2PASS        4
-#define MODE_YADIF_BOB          8
-
-#define YADIF_MODE_DEFAULT      0
-#define YADIF_PARITY_DEFAULT   -1
-
-#define ABS(a) ((a) > 0 ? (a) : (-(a)))
-#define MIN3(a,b,c) MIN(MIN(a,b),c)
-#define MAX3(a,b,c) MAX(MAX(a,b),c)
-
-typedef struct yadif_arguments_s {
-    hb_buffer_t * dst;
-    int parity;
-    int tff;
-} yadif_arguments_t;
-
-typedef struct deint_arguments_s {
-    hb_buffer_t * src;
-    hb_buffer_t * dst;
-} deint_arguments_t;
-
-typedef struct deint_thread_arg_s {
-    hb_filter_private_t *pv;
-    int segment;
-} deint_thread_arg_t;
-
-struct hb_filter_private_s
-{
-    int              width;
-    int              height;
-
-    int              yadif_mode;
-    int              yadif_parity;
-    int              yadif_ready;
-
-    hb_buffer_t      * yadif_ref[3];
-
-    int              cpu_count;
-    int              segments;
-
-    int              deint_nsegs;
-
-    taskset_t        deint_taskset;         // Threads for fast deint
-    taskset_t        yadif_taskset;         // Threads for Yadif
-
-    deint_arguments_t *deint_arguments;     // Arguments to thread for work
-    yadif_arguments_t *yadif_arguments;     // Arguments to thread for work
-};
-
-static int hb_deinterlace_init( hb_filter_object_t * filter,
-                                hb_filter_init_t * init );
-
-static int hb_deinterlace_work( hb_filter_object_t * filter,
-                                hb_buffer_t ** buf_in,
-                                hb_buffer_t ** buf_out );
-
-static void hb_deinterlace_close( hb_filter_object_t * filter );
-
-hb_filter_object_t hb_filter_deinterlace =
-{
-    .id            = HB_FILTER_DEINTERLACE,
-    .enforce_order = 1,
-    .name          = "Deinterlace",
-    .settings      = NULL,
-    .init          = hb_deinterlace_init,
-    .work          = hb_deinterlace_work,
-    .close         = hb_deinterlace_close,
-};
-
-
-static void yadif_store_ref(hb_filter_private_t *pv, hb_buffer_t *b)
-{
-
-    hb_buffer_close(&pv->yadif_ref[0]);
-    memmove(&pv->yadif_ref[0], &pv->yadif_ref[1], sizeof(hb_buffer_t *) * 2 );
-    pv->yadif_ref[2] = b;
-}
-
-static void yadif_filter_line(
-    hb_filter_private_t * pv,
-    uint8_t             * dst,
-    uint8_t             * prev,
-    uint8_t             * cur,
-    uint8_t             * next,
-    int                   width,
-    int                   stride,
-    int                   parity)
-{
-    uint8_t *prev2 = parity ? prev : cur ;
-    uint8_t *next2 = parity ? cur  : next;
-
-    int x;
-    for( x = 0; x < width; x++)
-    {
-        int c              = cur[-stride];
-        int d              = (prev2[0] + next2[0])>>1;
-        int e              = cur[+stride];
-        int temporal_diff0 = ABS(prev2[0] - next2[0]);
-        int temporal_diff1 = ( ABS(prev[-stride] - c) + ABS(prev[+stride] - e) ) >> 1;
-        int temporal_diff2 = ( ABS(next[-stride] - c) + ABS(next[+stride] - e) ) >> 1;
-        int diff           = MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);
-        int spatial_pred   = (c+e)>>1;
-        int spatial_score  = ABS(cur[-stride-1] - cur[+stride-1]) + ABS(c-e) +
-                             ABS(cur[-stride+1] - cur[+stride+1]) - 1;
-
-#define YADIF_CHECK(j)\
-        {   int score = ABS(cur[-stride-1+j] - cur[+stride-1-j])\
-                      + ABS(cur[-stride  +j] - cur[+stride  -j])\
-                      + ABS(cur[-stride+1+j] - cur[+stride+1-j]);\
-            if( score < spatial_score ){\
-                spatial_score = score;\
-                spatial_pred  = (cur[-stride  +j] + cur[+stride  -j])>>1;\
-
-        YADIF_CHECK(-1) YADIF_CHECK(-2) }} }}
-        YADIF_CHECK( 1) YADIF_CHECK( 2) }} }}
-
-        if( pv->yadif_mode & MODE_YADIF_SPATIAL )
-        {
-            int b = (prev2[-2*stride] + next2[-2*stride])>>1;
-            int f = (prev2[+2*stride] + next2[+2*stride])>>1;
-
-            int max = MAX3(d-e, d-c, MIN(b-c, f-e));
-            int min = MIN3(d-e, d-c, MAX(b-c, f-e));
-
-            diff = MAX3( diff, min, -max );
-        }
-
-        if( spatial_pred > d + diff )
-        {
-            spatial_pred = d + diff;
-        }
-        else if( spatial_pred < d - diff )
-        {
-            spatial_pred = d - diff;
-        }
-
-        dst[0] = spatial_pred;
-
-        dst++;
-        cur++;
-        prev++;
-        next++;
-        prev2++;
-        next2++;
-    }
-}
-
-typedef struct yadif_thread_arg_s {
-    hb_filter_private_t *pv;
-    int segment;
-} yadif_thread_arg_t;
-
-/*
- * deinterlace this segment of all three planes in a single thread.
- */
-void yadif_filter_thread( void *thread_args_v )
-{
-    yadif_arguments_t *yadif_work = NULL;
-    hb_filter_private_t * pv;
-    int run = 1;
-    int segment, segment_start, segment_stop;
-    yadif_thread_arg_t *thread_args = thread_args_v;
-
-    pv = thread_args->pv;
-    segment = thread_args->segment;
-
-    hb_log("Yadif Deinterlace thread started for segment %d", segment);
-
-    while( run )
-    {
-        /*
-         * Wait here until there is work to do.
-         */
-        taskset_thread_wait4start( &pv->yadif_taskset, segment );
-
-
-        if( taskset_thread_stop( &pv->yadif_taskset, segment ) )
-        {
-            /*
-             * No more work to do, exit this thread.
-             */
-            run = 0;
-            goto report_completion;
-        }
-
-        yadif_work = &pv->yadif_arguments[segment];
-
-        if( yadif_work->dst == NULL )
-        {
-            hb_error( "Thread started when no work available" );
-            goto report_completion;
-        }
-
-        /*
-         * Process all three planes, but only this segment of it.
-         */
-        int pp;
-        for(pp = 0; pp < 3; pp++)
-        {
-            hb_buffer_t *dst = yadif_work->dst;
-            int w = dst->plane[pp].width;
-            int s = dst->plane[pp].stride;
-            int h = dst->plane[pp].height;
-            int yy;
-            int parity = yadif_work->parity;
-            int tff = yadif_work->tff;
-            int penultimate = h - 2;
-
-            int segment_height = (h / pv->segments) & ~1;
-            segment_start = segment_height * segment;
-            if( segment == pv->segments - 1 )
-            {
-                /*
-                 * Final segment
-                 */
-                segment_stop = h;
-            } else {
-                segment_stop = segment_height * ( segment + 1 );
-            }
-
-            uint8_t *dst2 = &dst->plane[pp].data[segment_start * s];
-            uint8_t *prev = &pv->yadif_ref[0]->plane[pp].data[segment_start * s];
-            uint8_t *cur  = &pv->yadif_ref[1]->plane[pp].data[segment_start * s];
-            uint8_t *next = &pv->yadif_ref[2]->plane[pp].data[segment_start * s];
-            for( yy = segment_start; yy < segment_stop; yy++ )
-            {
-                if(((yy ^ parity) &  1))
-                {
-                    /* This is the bottom field when TFF and vice-versa.
-                       It's the field that gets filtered. Because yadif
-                       needs 2 lines above and below the one being filtered,
-                       we need to mirror the edges. When TFF, this means
-                       replacing the 2nd line with a copy of the 1st,
-                       and the last with the second-to-last.                  */
-                    if( yy > 1 && yy < penultimate )
-                    {
-                        /* This isn't the top or bottom,
-                         * proceed as normal to yadif. */
-                        yadif_filter_line(pv, dst2, prev, cur, next, w, s,
-                                          parity ^ tff);
-                    }
-                    else
-                    {
-                        // parity == 0 (TFF), y1 = y0
-                        // parity == 1 (BFF), y0 = y1
-                        // parity == 0 (TFF), yu = yp
-                        // parity == 1 (BFF), yp = yu
-                        uint8_t *src  = &pv->yadif_ref[1]->plane[pp].data[(yy^parity)*s];
-                        memcpy(dst2, src, w);
-                    }
-                }
-                else
-                {
-                    /* Preserve this field unfiltered */
-                    memcpy(dst2, cur, w);
-                }
-                dst2 += s;
-                prev += s;
-                cur += s;
-                next += s;
-            }
-        }
-
-report_completion:
-        /*
-         * Finished this segment, let everyone know.
-         */
-        taskset_thread_complete( &pv->yadif_taskset, segment );
-    }
-}
-
-
-/*
- * threaded yadif - each thread deinterlaces a single segment of all
- * three planes. Where a segment is defined as the frame divided by
- * the number of CPUs.
- *
- * This function blocks until the frame is deinterlaced.
- */
-static void yadif_filter( hb_filter_private_t * pv,
-                          hb_buffer_t * dst, int parity, int tff)
-{
-
-    int segment;
-
-    for( segment = 0; segment < pv->segments; segment++ )
-    {
-        /*
-         * Setup the work for this plane.
-         */
-        pv->yadif_arguments[segment].parity = parity;
-        pv->yadif_arguments[segment].tff = tff;
-        pv->yadif_arguments[segment].dst = dst;
-    }
-
-    /* Allow the taskset threads to make one pass over the data. */
-    taskset_cycle( &pv->yadif_taskset );
-
-    /*
-     * Entire frame is now deinterlaced.
-     */
-}
-
-/*
- * deinterlace a frame in a single thread.
- */
-void deint_filter_thread( void *thread_args_v )
-{
-    deint_arguments_t *args = NULL;
-    hb_filter_private_t * pv;
-    int run = 1;
-    int segment;
-    deint_thread_arg_t *thread_args = thread_args_v;
-
-    pv = thread_args->pv;
-    segment = thread_args->segment;
-
-    hb_log("Fast Deinterlace thread started for segment %d", segment);
-
-    while( run )
-    {
-        /*
-         * Wait here until there is work to do.
-         */
-        taskset_thread_wait4start( &pv->deint_taskset, segment );
-
-
-        if( taskset_thread_stop( &pv->deint_taskset, segment ) )
-        {
-            /*
-             * No more work to do, exit this thread.
-             */
-            run = 0;
-            goto report_completion;
-        }
-
-        args = &pv->deint_arguments[segment];
-
-        if( args->dst == NULL )
-        {
-            // This can happen when flushing final buffers.
-            goto report_completion;
-        }
-
-        /*
-         * Process all three planes, but only this segment of it.
-         */
-        hb_deinterlace(args->dst, args->src);
-
-report_completion:
-        /*
-         * Finished this segment, let everyone know.
-         */
-        taskset_thread_complete( &pv->deint_taskset, segment );
-    }
-}
-
-/*
- * threaded fast deint - each thread deinterlaces a single frame.
- *
- * This function blocks until all frames are deinterlaced.
- */
-static hb_buffer_t * deint_fast(hb_filter_private_t * pv, hb_buffer_t * in)
-{
-
-    int ii;
-    hb_buffer_t *dst, *src;
-    hb_buffer_list_t list;
-
-    hb_buffer_list_clear(&list);
-    if (in != NULL)
-    {
-        dst = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height);
-        pv->deint_arguments[pv->deint_nsegs].src = in;
-        pv->deint_arguments[pv->deint_nsegs].dst = dst;
-        pv->deint_nsegs++;
-    }
-    if (in != NULL && pv->deint_nsegs < pv->segments)
-    {
-        return NULL;
-    }
-
-    if (pv->deint_nsegs > 0)
-    {
-        /* Allow the taskset threads to make one pass over the data. */
-        taskset_cycle( &pv->deint_taskset );
-    }
-
-    for (ii = 0; ii < pv->deint_nsegs; ii++)
-    {
-        src = pv->deint_arguments[ii].src;
-        dst = pv->deint_arguments[ii].dst;
-        pv->deint_arguments[ii].src = NULL;
-        pv->deint_arguments[ii].dst = NULL;
-        hb_buffer_list_append(&list, dst);
-
-        dst->s = src->s;
-        hb_buffer_close(&src);
-    }
-    pv->deint_nsegs = 0;
-
-    return hb_buffer_list_clear(&list);
-}
-
-static int hb_deinterlace_init( hb_filter_object_t * filter,
-                                hb_filter_init_t * init )
-{
-    filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
-    hb_filter_private_t * pv = filter->private_data;
-
-    pv->width = init->geometry.width;
-    pv->height = init->geometry.height;
-
-    pv->yadif_ready    = 0;
-    pv->yadif_mode     = YADIF_MODE_DEFAULT;
-    pv->yadif_parity   = YADIF_PARITY_DEFAULT;
-
-    if( filter->settings )
-    {
-        sscanf( filter->settings, "%d:%d",
-                &pv->yadif_mode,
-                &pv->yadif_parity);
-    }
-
-    pv->cpu_count = hb_get_cpu_count();
-
-    /* Allocate yadif specific buffers */
-    if( pv->yadif_mode & MODE_YADIF_ENABLE )
-    {
-        /*
-         * Setup yadif taskset.
-         */
-        pv->segments = pv->cpu_count;
-        pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->segments );
-        if( pv->yadif_arguments == NULL ||
-            taskset_init( &pv->yadif_taskset, /*thread_count*/pv->segments,
-                          sizeof( yadif_thread_arg_t ) ) == 0 )
-        {
-            hb_error( "yadif could not initialize taskset" );
-        }
-
-        int ii;
-        for( ii = 0; ii < pv->segments; ii++ )
-        {
-            yadif_thread_arg_t *thread_args;
-
-            thread_args = taskset_thread_args( &pv->yadif_taskset, ii );
-
-            thread_args->pv = pv;
-            thread_args->segment = ii;
-            pv->yadif_arguments[ii].dst = NULL;
-
-            if( taskset_thread_spawn( &pv->yadif_taskset, ii,
-                                      "yadif_filter_segment",
-                                      yadif_filter_thread,
-                                      HB_NORMAL_PRIORITY ) == 0 )
-            {
-                hb_error( "yadif could not spawn thread" );
-            }
-        }
-    }
-    else
-    {
-        /*
-         * Setup fast deint taskset.
-         */
-        pv->segments = pv->cpu_count;
-        pv->deint_arguments = malloc( sizeof( deint_arguments_t ) * pv->segments );
-        if( pv->deint_arguments == NULL ||
-            taskset_init( &pv->deint_taskset, pv->segments,
-                          sizeof( deint_thread_arg_t ) ) == 0 )
-        {
-            hb_error( "deint could not initialize taskset" );
-        }
-
-        int ii;
-        for( ii = 0; ii < pv->segments; ii++ )
-        {
-            deint_thread_arg_t *thread_args;
-
-            thread_args = taskset_thread_args( &pv->deint_taskset, ii );
-
-            thread_args->pv = pv;
-            thread_args->segment = ii;
-            pv->deint_arguments[ii].dst = NULL;
-
-            if( taskset_thread_spawn( &pv->deint_taskset, ii,
-                                      "deint_filter_segment",
-                                      deint_filter_thread,
-                                      HB_NORMAL_PRIORITY ) == 0 )
-            {
-                hb_error( "deint could not spawn thread" );
-            }
-        }
-    }
-
-    return 0;
-}
-
-static void hb_deinterlace_close( hb_filter_object_t * filter )
-{
-    hb_filter_private_t * pv = filter->private_data;
-
-    if( !pv )
-    {
-        return;
-    }
-
-    /* Cleanup yadif specific buffers */
-    if( pv->yadif_mode & MODE_YADIF_ENABLE )
-    {
-        taskset_fini( &pv->yadif_taskset );
-
-        int ii;
-        for(ii = 0; ii < 3; ii++)
-        {
-            hb_buffer_close(&pv->yadif_ref[ii]);
-        }
-
-        free( pv->yadif_arguments );
-    }
-    else
-    {
-        taskset_fini( &pv->deint_taskset );
-        free( pv->deint_arguments );
-    }
-
-    free( pv );
-    filter->private_data = NULL;
-}
-
-static int hb_deinterlace_work( hb_filter_object_t * filter,
-                                hb_buffer_t ** buf_in,
-                                hb_buffer_t ** buf_out )
-{
-    hb_filter_private_t * pv = filter->private_data;
-    hb_buffer_t * in = *buf_in;
-    hb_buffer_list_t list;
-
-    *buf_in = NULL;
-    hb_buffer_list_clear(&list);
-    if (in->s.flags & HB_BUF_FLAG_EOF)
-    {
-        if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) )
-        {
-            // Flush final frames
-            hb_buffer_list_append(&list, deint_fast(pv, NULL));
-        }
-        hb_buffer_list_append(&list, in);
-
-        *buf_out = hb_buffer_list_clear(&list);
-        return HB_FILTER_DONE;
-    }
-
-    /* Use fast deinterlace if yadif_mode < 0 */
-    if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) )
-    {
-        *buf_out = deint_fast(pv, in);
-        return HB_FILTER_OK;
-    }
-
-    /* Store current frame in yadif cache */
-    yadif_store_ref(pv, in);
-
-    // yadif requires 3 buffers, prev, cur, and next.  For the first
-    // frame, there can be no prev, so we duplicate the first frame.
-    if (!pv->yadif_ready)
-    {
-        // If yadif is not ready, store another ref and return HB_FILTER_DELAY
-        yadif_store_ref(pv, hb_buffer_dup(in));
-        pv->yadif_ready = 1;
-        // Wait for next
-        return HB_FILTER_DELAY;
-    }
-
-    /* Determine if top-field first layout */
-    int tff;
-    if( pv->yadif_parity < 0 )
-    {
-        tff = !!(in->s.flags & PIC_FLAG_TOP_FIELD_FIRST);
-    }
-    else
-    {
-        tff = (pv->yadif_parity & 1) ^ 1;
-    }
-
-    /* deinterlace both fields if yadif 2 pass or bob */
-    int frame, num_frames = 1;
-    if ((pv->yadif_mode & MODE_YADIF_2PASS) ||
-        (pv->yadif_mode & MODE_YADIF_BOB))
-    {
-        num_frames = 2;
-    }
-
-    // Will need up to 2 buffers simultaneously
-    int idx = 0;
-    hb_buffer_t * o_buf[2] = {NULL,};
-
-    /* Perform yadif filtering */
-    for( frame = 0; frame < num_frames; frame++ )
-    {
-        int parity = frame ^ tff ^ 1;
-
-        if (o_buf[idx] == NULL)
-        {
-            o_buf[idx] = hb_frame_buffer_init(in->f.fmt,
-                                              in->f.width, in->f.height);
-        }
-        yadif_filter(pv, o_buf[idx], parity, tff);
-
-        // If bob, add both frames
-        // else, add only final frame
-        if (( pv->yadif_mode & MODE_YADIF_BOB ) || frame == num_frames - 1)
-        {
-            /* Copy buffered settings to output buffer settings */
-            o_buf[idx]->s = pv->yadif_ref[1]->s;
-            o_buf[idx]->next = NULL;
-            hb_buffer_list_append(&list, o_buf[idx]);
-
-            // Indicate that buffer was consumed
-            o_buf[idx] = NULL;
-            idx ^= 1;
-        }
-    }
-    hb_buffer_close(&o_buf[0]);
-    hb_buffer_close(&o_buf[1]);
-
-    /* if bob mode is engaged, halve the duration of the
-     * timestamps. */
-    if (pv->yadif_mode & MODE_YADIF_BOB)
-    {
-        hb_buffer_t *first = hb_buffer_list_head(&list);
-        hb_buffer_t *second = hb_buffer_list_tail(&list);
-        first->s.stop -= (first->s.stop - first->s.start) / 2LL;
-        second->s.start = first->s.stop;
-        second->s.new_chap = 0;
-    }
-
-    *buf_out = hb_buffer_list_clear(&list);
-    return HB_FILTER_OK;
-}
-
index cc972f0f2e177b62f4b89df0e9c30438e3fb401e..4afc9409145790837f7f37e101445ea29706170e 100644 (file)
@@ -1,7 +1,7 @@
 <resources>
     <section name="PresetTemplate">
         <integer name="VersionMajor" value="11" />
-        <integer name="VersionMinor" value="0" />
+        <integer name="VersionMinor" value="1" />
         <integer name="VersionMicro" value="0" />
         <json name="Preset" file="preset_template.json" />
     </section>
index 8deaed3c3874095f10b5253d281aa818e4b1c8c0..3a9402021d97030cb84e824af03a6859d388ee30 100644 (file)
@@ -67,13 +67,14 @@ static hb_filter_param_t decomb_presets[] =
 
 static hb_filter_param_t deinterlace_presets[] =
 {
-    { 1, "Custom",      "custom",     NULL              },
-    { 2, "Fast",        "fast",       "0:-1:-1:0:1"     },
-    { 3, "Slow",        "slow",       "1:-1:-1:0:1"     },
-    { 4, "Slower",      "slower",     "3:-1:-1:0:1"     },
-    { 5, "Bob",         "bob",        "15:-1:-1:0:1"    },
-    { 0,  NULL,         NULL,         NULL              },
-    { 2, "Default",     "default",    "0:-1:-1:0:1"     }
+    { 1, "Custom",             "custom",       NULL              },
+    { 3, "Default",            "default",      "3:-1"            },
+    { 2, "Skip Spatial Check", "skip-spatial", "1:-1"            },
+    { 5, "Bob",                "bob",          "7:-1"            },
+    { 0,  NULL,                NULL,           NULL              },
+    { 2, "Fast",               "fast",         "1:-1:"           },
+    { 3, "Slow",               "slow",         "3:-1:"           },
+    { 4, "Slower",             "slower",       "3:-1:"           }
 };
 
 typedef struct
@@ -104,7 +105,58 @@ static filter_param_map_t param_map[] =
     { HB_FILTER_INVALID,     NULL,                NULL, 0        }
 };
 
-/* Settings:
+#define MODE_YADIF_ENABLE       1
+#define MODE_YADIF_SPATIAL      2
+#define MODE_YADIF_BOB          4
+
+/* Deinterlace Settings
+ *  mode:parity
+ *
+ *  mode   - yadif deinterlace mode
+ *  parity - field parity
+ *
+ *  Modes:
+ *      1 = Enabled
+ *      2 = Spatial
+ *      4 = Bob
+ *
+ *  Parity:
+ *      0  = Top Field First
+ *      1  = Bottom Field First
+ *      -1 = Automatic detection of field parity
+ */
+char *
+generate_deinterlace_settings(const char * settings)
+{
+    char       ** args;
+    char       * result;
+    int          ii, mode = 3, parity = -1;
+
+    args = hb_str_vsplit(settings, ':');
+    for (ii = 0; ii < 2 && args[ii]; ii++)
+    {
+        switch (ii)
+        {
+            case 0:
+                mode   = strtol(args[ii], &result, 0);
+                break;
+            case 1:
+                parity = strtol(args[ii], &result, 0);
+                break;
+        }
+    }
+    if (!(mode & MODE_YADIF_ENABLE))
+    {
+        return (char*)hb_filter_off;
+    }
+    int bob        = !!(mode & MODE_YADIF_BOB);
+    int no_spatial = !(mode & MODE_YADIF_SPATIAL);
+    mode = bob | (no_spatial << 1);
+
+    return hb_strdup_printf("yadif='mode=%d:parity=%d'", mode, parity);
+}
+
+/* Rotate Settings:
  *  degrees:mirror
  *
  *  degrees - Rotation angle, may be one of 90, 180, or 270
@@ -700,12 +752,22 @@ hb_generate_filter_settings_by_index(int filter_id, int preset,
                 filter_param = hb_strdup_printf("%d", preset);
             break;
         case HB_FILTER_DECOMB:
-        case HB_FILTER_DEINTERLACE:
         case HB_FILTER_DETELECINE:
         case HB_FILTER_HQDN3D:
             filter_param = generate_generic_settings_by_index(filter_id,
                                                               preset, custom);
             break;
+        case HB_FILTER_DEINTERLACE:
+        {
+            char * s;
+            s = generate_generic_settings_by_index(filter_id, preset, custom);
+            if (s == NULL || hb_validate_filter_settings(filter_id, s))
+            {
+                free(s);
+                return NULL;
+            }
+            return generate_deinterlace_settings(s);
+        } break;
         default:
             fprintf(stderr,
                     "hb_generate_filter_settings: Unrecognized filter (%d).\n",
@@ -754,11 +816,21 @@ hb_generate_filter_settings(int filter_id, const char *preset, const char *tune)
                 filter_param = strdup(preset);
             break;
         case HB_FILTER_DECOMB:
-        case HB_FILTER_DEINTERLACE:
         case HB_FILTER_DETELECINE:
         case HB_FILTER_HQDN3D:
             filter_param = generate_generic_settings(filter_id, preset, tune);
             break;
+        case HB_FILTER_DEINTERLACE:
+        {
+            char * s;
+            s = generate_generic_settings(filter_id, preset, tune);
+            if (s == NULL || hb_validate_filter_settings(filter_id, s))
+            {
+                free(s);
+                return NULL;
+            }
+            return generate_deinterlace_settings(s);
+        } break;
         default:
             fprintf(stderr,
                     "hb_generate_filter_settings: Unrecognized filter (%d).\n",
index bc84965e1804e00e52fe8db5eacf3b161c7377af..1670b469b0f02f0f437c9e0c1e1ba826720c8b02 100644 (file)
@@ -1969,6 +1969,79 @@ void hb_presets_clean(hb_value_t *preset)
     presets_clean(preset, hb_preset_template);
 }
 
+static void import_deint_11_0_0(hb_value_t *preset)
+{
+    hb_value_t *val = hb_dict_get(preset, "PictureDeinterlaceFilter");
+    if (val == NULL)
+    {
+        return;
+    }
+    const char * deint = hb_value_get_string(val);
+    if (deint == NULL)
+    {
+        // This really shouldn't happen for a valid preset
+        return;
+    }
+    if (strcasecmp(deint, "deinterlace"))
+    {
+        return;
+    }
+    val = hb_dict_get(preset, "PictureDeinterlacePreset");
+    if (val == NULL)
+    {
+        hb_dict_set(preset, "PictureDeinterlacePreset",
+                    hb_value_string("default"));
+        return;
+    }
+    deint = hb_value_get_string(val);
+    if (deint == NULL)
+    {
+        // This really shouldn't happen for a valid preset
+        return;
+    }
+    if (!strcasecmp(deint, "fast") || !strcasecmp(deint, "slow"))
+    {
+        // fast and slow -> skip-spatial
+        hb_dict_set(preset, "PictureDeinterlacePreset",
+                    hb_value_string("skip-spatial"));
+        return;
+    }
+    else if (!strcasecmp(deint, "bob") || !strcasecmp(deint, "default"))
+    {
+        return;
+    }
+    else if (strcasecmp(deint, "custom"))
+    {
+        // not custom -> default
+        hb_dict_set(preset, "PictureDeinterlacePreset",
+                    hb_value_string("default"));
+        return;
+    }
+    val = hb_dict_get(preset, "PictureDeinterlaceCustom");
+    if (val == NULL)
+    {
+        hb_dict_set(preset, "PictureDeinterlacePreset",
+                    hb_value_string("default"));
+        return;
+    }
+    // Translate custom values
+    deint = hb_value_get_string(val);
+    if (deint == NULL)
+    {
+        // This really shouldn't happen for a valid preset
+        return;
+    }
+    int bob, spatial, yadif, mode = 3, parity = -1;
+    sscanf(deint, "%d:%d", &mode, &parity);
+    yadif   = !!(mode & 1);
+    spatial = !!(mode & 2);
+    bob     = !!(mode & 8);
+    mode = yadif + (yadif && spatial) * 2 + bob * 4;
+    char * custom = hb_strdup_printf("%d:%d", mode, parity);
+    hb_dict_set(preset, "PictureDeinterlaceCustom", hb_value_string(custom));
+    free(custom);
+}
+
 static void import_deint_10_0_0(hb_value_t *preset)
 {
     hb_value_t *val = hb_dict_get(preset, "PictureDecombDeinterlace");
@@ -2002,6 +2075,7 @@ static void import_deint_10_0_0(hb_value_t *preset)
                         hb_value_string("default"));
         }
     }
+    import_deint_11_0_0(preset);
 }
 
 static const char* import_indexed_filter(int filter_id, int index)
@@ -2277,6 +2351,11 @@ static void import_10_0_0(hb_value_t *preset)
     import_deint_10_0_0(preset);
 }
 
+static void import_11_0_0(hb_value_t *preset)
+{
+    import_deint_11_0_0(preset);
+}
+
 static int preset_import(hb_value_t *preset, int major, int minor, int micro)
 {
     int result = 0;
@@ -2294,6 +2373,11 @@ static int preset_import(hb_value_t *preset, int major, int minor, int micro)
             import_10_0_0(preset);
             result = 1;
         }
+        else if (major == 11 && minor == 0 && micro == 0)
+        {
+            import_11_0_0(preset);
+            result = 1;
+        }
         preset_clean(preset, hb_preset_template);
     }
     return result;
@@ -2321,6 +2405,28 @@ int hb_presets_version(hb_value_t *preset, int *major, int *minor, int *micro)
     return -1;
 }
 
+void hb_presets_update_version(hb_value_t *preset)
+{
+    if (hb_value_type(preset) == HB_VALUE_TYPE_DICT)
+    {
+        // Is this a single preset or a packaged collection of presets?
+        hb_value_t *val = hb_dict_get(preset, "PresetName");
+        if (val == NULL)
+        {
+            val = hb_dict_get(preset, "VersionMajor");
+            if (val != NULL)
+            {
+                hb_dict_set(preset, "VersionMajor",
+                            hb_value_int(hb_preset_version_major));
+                hb_dict_set(preset, "VersionMinor",
+                            hb_value_int(hb_preset_version_minor));
+                hb_dict_set(preset, "VersionMicro",
+                            hb_value_int(hb_preset_version_micro));
+            }
+        }
+    }
+}
+
 int hb_presets_import(hb_value_t *preset)
 {
     preset_import_context_t ctx;
@@ -2329,6 +2435,10 @@ int hb_presets_import(hb_value_t *preset)
     ctx.result = 0;
     hb_presets_version(preset, &ctx.major, &ctx.minor, &ctx.micro);
     presets_do(do_preset_import, preset, (preset_do_context_t*)&ctx);
+    if (ctx.result)
+    {
+        hb_presets_update_version(preset);
+    }
 
     return ctx.result;
 }
index a5179c702140f2f088bd18cc2359e880aaae50e3..47bdbe417bdc4495613d504c8dc5cafd209b0a43 100644 (file)
@@ -1262,7 +1262,13 @@ static void ShowHelp()
 "\n"
 "### Filters---------------------------------------------------------------\n\n"
 "   -d, --deinterlace       Unconditionally deinterlaces all frames\n"
-"         <fast/slow/slower/bob");
+"         <");
+hb_filter_param_t * param = hb_filter_param_get_presets(HB_FILTER_DEINTERLACE);
+// Skip "custom"
+for (i = 1; param != NULL && param[i].name != NULL; i++)
+{
+    fprintf(out, "%s%s", i > 1 ? "/" : "", param[i].short_name);
+}
 #ifdef USE_QSV
 if (hb_qsv_available())
 {
@@ -1271,7 +1277,7 @@ if (hb_qsv_available())
 #endif
      fprintf( out, "> or omitted (default settings)\n"
      "           or\n"
-"         <YM:FD>           (default 0:-1)\n"
+"         <YM:FP>           Yadif Mode:Field Parity (default 3:-1)\n"
 "       --no-deinterlace    Disable preset deinterlace filter\n"
 "   -5, --decomb            Selectively deinterlaces when it detects combing\n"
 "         <fast/bob> or omitted (default settings)\n"