Coverage Report

Created: 2025-12-31 07:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/src/video_output/interlacing.c
Line
Count
Source
1
/*****************************************************************************
2
 * interlacing.c
3
 *****************************************************************************
4
 * Copyright (C) 2010 Laurent Aimar
5
 *
6
 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
#ifdef HAVE_CONFIG_H
24
# include "config.h"
25
#endif
26
#include <assert.h>
27
28
#include <vlc_common.h>
29
#include <vlc_configuration.h>
30
#include <vlc_threads.h>
31
#include <vlc_vout.h>
32
33
#include "vout_private.h"
34
#include "vout_internal.h"
35
36
/*****************************************************************************
37
 * Deinterlacing
38
 *****************************************************************************/
39
/* XXX
40
 * You can use the non vout filter if and only if the video properties stay the
41
 * same (width/height/chroma/fps), at least for now.
42
 */
43
static const char deinterlace_modes[][9]= {
44
    "auto",
45
    "discard",
46
    "blend",
47
    "mean",
48
    "bob",
49
    "linear",
50
    "x",
51
    "yadif",
52
    "yadif2x",
53
    "phosphor",
54
    "ivtc",
55
};
56
57
static bool DeinterlaceIsModeValid(const char *mode)
58
0
{
59
0
    for (unsigned i = 0; i < ARRAY_SIZE(deinterlace_modes); i++) {
60
0
        if (!strcmp(deinterlace_modes[i], mode))
61
0
            return true;
62
0
    }
63
0
    return false;
64
0
}
65
66
static int DeinterlaceCallback(vlc_object_t *object, char const *cmd,
67
                               vlc_value_t oldval, vlc_value_t newval, void *data)
68
0
{
69
0
    VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(data);
70
0
    vout_thread_t *vout = (vout_thread_t *)object;
71
72
    /* */
73
0
    const int  deinterlace_state = var_GetInteger(vout, "deinterlace");
74
0
    char       *mode             = var_GetString(vout,  "deinterlace-mode");
75
0
    const bool is_needed         = var_GetBool(vout,    "deinterlace-needed");
76
0
    if (!mode || !DeinterlaceIsModeValid(mode))
77
0
    {
78
0
        msg_Err(vout, "unknown deinterlace mode %s", mode);
79
0
        free(mode);
80
0
        return VLC_EGENERIC;
81
0
    }
82
83
    /* */
84
0
    var_SetString(vout, "sout-deinterlace-mode", mode);
85
86
0
    msg_Dbg(vout, "deinterlace %d, mode %s, is_needed %d", deinterlace_state, mode, is_needed);
87
0
    vout_ControlChangeInterlacing(vout, deinterlace_state != 0 && (is_needed || deinterlace_state >= 0));
88
89
    /* */
90
0
    free(mode);
91
0
    return VLC_SUCCESS;
92
0
}
93
94
void vout_InitInterlacingSupport(vout_thread_t *vout, vout_interlacing_state_t *sys)
95
0
{
96
0
    vlc_value_t val;
97
98
0
    msg_Dbg(vout, "Deinterlacing available");
99
100
0
    sys->has_deint = false;
101
102
    /* Create the configuration variables */
103
    /* */
104
0
    var_Create(vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
105
0
    int deinterlace_state = var_GetInteger(vout, "deinterlace");
106
107
0
    var_Change(vout, "deinterlace", VLC_VAR_SETTEXT, _("Deinterlace"));
108
109
0
    const module_config_t *optd = config_FindConfig("deinterlace");
110
0
    var_Change(vout, "deinterlace", VLC_VAR_CLEARCHOICES);
111
0
    if (likely(optd != NULL))
112
0
        for (unsigned i = 0; i < optd->list_count; i++) {
113
0
            val.i_int = optd->list.i[i];
114
0
            var_Change(vout, "deinterlace", VLC_VAR_ADDCHOICE, val,
115
0
                       vlc_gettext(optd->list_text[i]));
116
0
        }
117
0
    var_AddCallback(vout, "deinterlace", DeinterlaceCallback, NULL);
118
    /* */
119
0
    var_Create(vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
120
0
    char *deinterlace_mode = var_GetNonEmptyString(vout, "deinterlace-mode");
121
122
0
    var_Change(vout, "deinterlace-mode", VLC_VAR_SETTEXT,
123
0
               _("Deinterlace mode"));
124
125
0
    const module_config_t *optm = config_FindConfig("deinterlace-mode");
126
0
    var_Change(vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES);
127
0
    if (likely(optm != NULL))
128
0
        for (unsigned i = 0; i < optm->list_count; i++) {
129
0
             if (!DeinterlaceIsModeValid(optm->list.psz[i]))
130
0
                 continue;
131
132
0
             val.psz_string  = (char *)optm->list.psz[i];
133
0
             var_Change(vout, "deinterlace-mode", VLC_VAR_ADDCHOICE,
134
0
                        val, vlc_gettext(optm->list_text[i]));
135
0
         }
136
0
    var_AddCallback(vout, "deinterlace-mode", DeinterlaceCallback, NULL);
137
    /* */
138
0
    var_Create(vout, "deinterlace-needed", VLC_VAR_BOOL);
139
0
    var_AddCallback(vout, "deinterlace-needed", DeinterlaceCallback, NULL);
140
141
    /* */
142
0
    val.psz_string = deinterlace_mode ? deinterlace_mode : optm->orig.psz;
143
0
    var_Change(vout, "deinterlace-mode", VLC_VAR_SETVALUE, val);
144
145
0
    var_SetInteger(vout, "deinterlace", deinterlace_state);
146
0
    free(deinterlace_mode);
147
148
0
    var_Create(vout, "sout-deinterlace-mode", VLC_VAR_STRING);
149
150
0
    sys->is_interlaced = false;
151
0
}
152
153
void vout_ReinitInterlacingSupport(vout_thread_t *vout, vout_interlacing_state_t *sys)
154
0
{
155
0
    sys->is_interlaced = false;
156
0
    var_SetBool(vout, "deinterlace-needed", false);
157
0
}
158
159
void vout_SetInterlacingState(vout_thread_t *vout, vout_interlacing_state_t *sys, bool is_interlaced)
160
0
{
161
0
    const bool interlacing_change =
162
0
        is_interlaced != sys->is_interlaced;
163
164
    /* Wait 30s before quitting interlacing mode */
165
0
    const bool is_after_deadline =
166
0
        sys->date + VLC_TICK_FROM_SEC(30) < vlc_tick_now();
167
168
0
    if (interlacing_change && (is_interlaced || is_after_deadline))
169
0
    {
170
0
        msg_Dbg(vout, "Detected %s video",
171
0
                 is_interlaced ? "interlaced" : "progressive");
172
0
        var_SetBool(vout, "deinterlace-needed", is_interlaced);
173
0
        sys->is_interlaced = is_interlaced;
174
0
    }
175
0
    if (is_interlaced)
176
0
        sys->date = vlc_tick_now();
177
0
}