/* deinterlace.c

   Copyright (c) 2003-2024 HandBrake Team
   This file is part of the HandBrake source code
   Homepage: <http://handbrake.fr/>.
   It may be used under the terms of the GNU General Public License v2.
   For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
 */

#include "handbrake/common.h"
#include "handbrake/decomb.h"
#include "handbrake/avfilter_priv.h"

#define FFMPEG_DEINTERLACE_FILTER(FILTER_ID, FILTER_NAME, FFMPEG_NAME, OPTS_TEMPLATE)  \
    static int deinterlace_##FFMPEG_NAME(hb_filter_object_t * filter,   \
        hb_filter_init_t * init);                                       \
                                                                        \
    hb_filter_object_t hb_filter_##FFMPEG_NAME =                        \
    {                                                                   \
        .id                = FILTER_ID,                                 \
        .enforce_order     = 1,                                         \
        .skip              = 1,                                         \
        .name              = FILTER_NAME,                               \
        .settings          = NULL,                                      \
        .init              = deinterlace_##FFMPEG_NAME,                 \
        .work              = hb_avfilter_null_work,                     \
        .close             = hb_avfilter_alias_close,                   \
        .settings_template = OPTS_TEMPLATE,                             \
    };                                                                  \
                                                                        \
    static int deinterlace_##FFMPEG_NAME(hb_filter_object_t * filter,   \
        hb_filter_init_t * init)                                        \
    {                                                                   \
        return deinterlace_init(filter, init, #FFMPEG_NAME);            \
    }                                                                   \

static int deinterlace_init(hb_filter_object_t * filter,
                            hb_filter_init_t * init, char *filter_name);

const char deint_template[] =
    "mode=^"HB_INT_REG"$:parity=^([01])$";

FFMPEG_DEINTERLACE_FILTER(HB_FILTER_YADIF, "Deinterlace", yadif,
                          deint_template);
FFMPEG_DEINTERLACE_FILTER(HB_FILTER_BWDIF, "Bwdif", bwdif,
                          deint_template);
/* FFMPEG_DEINTERLACE_FILTER(..., "Estdif", estdif,
                          estdif_template); */

/* Deinterlace Settings
 *  mode:parity
 *
 *  mode   - yadif deinterlace mode
 *  parity - field parity

 *
 *  Modes:
 *      1 = Enabled ("send_frame")
 *      2 = Spatial [Yadif only]
 *      4 = Bob ("send_field")
 *      8 = Selective
 *
 *  Parity:
 *      0  = Top Field First
 *      1  = Bottom Field First
 *      -1 = Automatic detection of field parity
 *
 */
static int deinterlace_init(hb_filter_object_t * filter,
                            hb_filter_init_t * init, char *filter_name)
{
    hb_filter_private_t * pv = NULL;

    pv = calloc(1, sizeof(struct hb_filter_private_s));
    filter->private_data = pv;
    if (pv == NULL)
    {
        return 1;
    }
    pv->input = *init;

    hb_dict_t *settings = filter->settings;

    int  mode = 3, parity = -1;
    uint8_t is_yadif = !(strncmp("yadif", filter_name, 5)); //yadif_cuda compliant

    hb_dict_extract_int(&mode,   settings, "mode");
    hb_dict_extract_int(&parity, settings, "parity");

    if (!(mode & MODE_YADIF_ENABLE))
    {
        return 0;
    }

    hb_dict_t * avfilter = hb_dict_init();
    hb_dict_t * avsettings = hb_dict_init();

    if (mode & MODE_XXDIF_BOB)
    {
        if ((mode & MODE_YADIF_SPATIAL) || !is_yadif)
        {
            hb_dict_set(avsettings, "mode", hb_value_string("send_field"));
        }
        else
        {
            hb_dict_set(avsettings, "mode",
                        hb_value_string("send_field_nospatial"));
        }
        init->vrate.num *= 2;
    }
    else
    {
        if ((mode & MODE_YADIF_SPATIAL) || !is_yadif)
        {
            hb_dict_set(avsettings, "mode", hb_value_string("send_frame"));
        }
        else
        {
            hb_dict_set(avsettings, "mode",
                        hb_value_string("send_frame_nospatial"));
        }
    }

    if (mode & MODE_DECOMB_SELECTIVE)
    {
        hb_dict_set(avsettings, "deint", hb_value_string("interlaced"));
    }
    if (parity == 0)
    {
        hb_dict_set(avsettings, "parity", hb_value_string("tff"));
    }
    else if (parity == 1)
    {
        hb_dict_set(avsettings, "parity", hb_value_string("bff"));
    }
    hb_dict_set(avfilter, filter_name, avsettings);
    pv->avfilters = avfilter;

    pv->output = *init;

    return 0;
}
