da2f0ec62c6b81e0bf3574f59a57a26b9ba6447c
[vlc.git] / src / video_output / interlacing.c
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_vout.h>
30
31 #include "vout_private.h"
32 #include "vout_internal.h"
33
34 /*****************************************************************************
35  * Deinterlacing
36  *****************************************************************************/
37 /* XXX
38  * You can use the non vout filter if and only if the video properties stay the
39  * same (width/height/chroma/fps), at least for now.
40  */
41 static const char deinterlace_modes[][9]= {
42     "auto",
43     "discard",
44     "blend",
45     "mean",
46     "bob",
47     "linear",
48     "x",
49     "yadif",
50     "yadif2x",
51     "phosphor",
52     "ivtc",
53 };
54
55 static bool DeinterlaceIsModeValid(const char *mode)
56 {
57     for (unsigned i = 0; i < ARRAY_SIZE(deinterlace_modes); i++) {
58         if (!strcmp(deinterlace_modes[i], mode))
59             return true;
60     }
61     return false;
62 }
63
64 static int DeinterlaceCallback(vlc_object_t *object, char const *cmd,
65                                vlc_value_t oldval, vlc_value_t newval, void *data)
66 {
67     VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(data);
68     vout_thread_t *vout = (vout_thread_t *)object;
69
70     /* */
71     const int  deinterlace_state = var_GetInteger(vout, "deinterlace");
72     char       *mode             = var_GetString(vout,  "deinterlace-mode");
73     const bool is_needed         = var_GetBool(vout,    "deinterlace-needed");
74     if (!mode || !DeinterlaceIsModeValid(mode))
75     {
76         free(mode);
77         return VLC_EGENERIC;
78     }
79
80     /* */
81     char *old = var_CreateGetString(vout, "sout-deinterlace-mode");
82     var_SetString(vout, "sout-deinterlace-mode", mode);
83
84     msg_Dbg(vout, "deinterlace %d, mode %s, is_needed %d", deinterlace_state, mode, is_needed);
85     vout_ControlChangeInterlacing(vout, deinterlace_state != 0 && (is_needed || deinterlace_state >= 0));
86
87     /* */
88     free(old);
89     free(mode);
90     return VLC_SUCCESS;
91 }
92
93 void vout_InitInterlacingSupport(vout_thread_t *vout, vout_thread_private_t *sys)
94 {
95     vlc_value_t val;
96
97     msg_Dbg(vout, "Deinterlacing available");
98
99     sys->interlacing.has_deint = false;
100
101     /* Create the configuration variables */
102     /* */
103     var_Create(vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
104     int deinterlace_state = var_GetInteger(vout, "deinterlace");
105
106     var_Change(vout, "deinterlace", VLC_VAR_SETTEXT, _("Deinterlace"));
107
108     const module_config_t *optd = config_FindConfig("deinterlace");
109     var_Change(vout, "deinterlace", VLC_VAR_CLEARCHOICES);
110     if (likely(optd != NULL))
111         for (unsigned i = 0; i < optd->list_count; i++) {
112             val.i_int = optd->list.i[i];
113             var_Change(vout, "deinterlace", VLC_VAR_ADDCHOICE, val,
114                        vlc_gettext(optd->list_text[i]));
115         }
116     var_AddCallback(vout, "deinterlace", DeinterlaceCallback, NULL);
117     /* */
118     var_Create(vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
119     char *deinterlace_mode = var_GetNonEmptyString(vout, "deinterlace-mode");
120
121     var_Change(vout, "deinterlace-mode", VLC_VAR_SETTEXT,
122                _("Deinterlace mode"));
123
124     const module_config_t *optm = config_FindConfig("deinterlace-mode");
125     var_Change(vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES);
126     if (likely(optm != NULL))
127         for (unsigned i = 0; i < optm->list_count; i++) {
128              if (!DeinterlaceIsModeValid(optm->list.psz[i]))
129                  continue;
130
131              val.psz_string  = (char *)optm->list.psz[i];
132              var_Change(vout, "deinterlace-mode", VLC_VAR_ADDCHOICE,
133                         val, vlc_gettext(optm->list_text[i]));
134          }
135     var_AddCallback(vout, "deinterlace-mode", DeinterlaceCallback, NULL);
136     /* */
137     var_Create(vout, "deinterlace-needed", VLC_VAR_BOOL);
138     var_AddCallback(vout, "deinterlace-needed", DeinterlaceCallback, NULL);
139
140     /* */
141     val.psz_string = deinterlace_mode ? deinterlace_mode : optm->orig.psz;
142     var_Change(vout, "deinterlace-mode", VLC_VAR_SETVALUE, val);
143
144     var_SetInteger(vout, "deinterlace", deinterlace_state);
145     free(deinterlace_mode);
146
147     sys->interlacing.is_interlaced = false;
148 }
149
150 void vout_ReinitInterlacingSupport(vout_thread_t *vout, vout_thread_private_t *sys)
151 {
152     sys->interlacing.is_interlaced = false;
153     var_SetBool(vout, "deinterlace-needed", false);
154 }
155
156 void vout_SetInterlacingState(vout_thread_t *vout, vout_thread_private_t *sys, bool is_interlaced)
157 {
158     /* Wait 30s before quiting interlacing mode */
159     const int interlacing_change = (!!is_interlaced)
160                                  - (!!sys->interlacing.is_interlaced);
161     if (interlacing_change == 1 ||
162         (interlacing_change == -1 &&
163         sys->interlacing.date + VLC_TICK_FROM_SEC(30) < vlc_tick_now()))
164     {
165         msg_Dbg(vout, "Detected %s video",
166                  is_interlaced ? "interlaced" : "progressive");
167         var_SetBool(vout, "deinterlace-needed", is_interlaced);
168         sys->interlacing.is_interlaced = is_interlaced;
169     }
170     if (is_interlaced)
171         sys->interlacing.date = vlc_tick_now();
172 }