1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
29 #include <vlc_common.h>
32 #include "interlacing.h"
34 /*****************************************************************************
36 *****************************************************************************/
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.
41 static const char deinterlace_modes[][9]= {
55 static bool DeinterlaceIsModeValid(const char *mode)
57 for (unsigned i = 0; i < ARRAY_SIZE(deinterlace_modes); i++) {
58 if (!strcmp(deinterlace_modes[i], mode))
64 static char *FilterFind(char *filter_base, const char *module_name)
66 const size_t module_length = strlen(module_name);
67 const char *filter = filter_base;
69 if (!filter || module_length <= 0)
73 char *start = strstr(filter, module_name);
76 if (start[module_length] == '\0' || start[module_length] == ':')
78 filter = &start[module_length];
82 static bool DeinterlaceIsPresent(vout_thread_t *vout)
84 char *filter = var_GetNonEmptyString(vout, "video-filter");
86 bool is_found = FilterFind(filter, "deinterlace") != NULL;
93 static void DeinterlaceRemove(vout_thread_t *vout)
95 char *filter = var_GetNonEmptyString(vout, "video-filter");
97 char *start = FilterFind(filter, "deinterlace");
104 strcpy(&start[0], &start[strlen("deinterlace")]);
106 strcpy(&start[0], &start[1]);
108 var_SetString(vout, "video-filter", filter);
111 static void DeinterlaceAdd(vout_thread_t *vout)
113 char *filter = var_GetNonEmptyString(vout, "video-filter");
115 if (FilterFind(filter, "deinterlace")) {
123 if (asprintf(&filter, "%s:%s", tmp, "deinterlace") < 0)
128 filter = strdup("deinterlace");
132 var_SetString(vout, "video-filter", filter);
137 static int DeinterlaceCallback(vlc_object_t *object, char const *cmd,
138 vlc_value_t oldval, vlc_value_t newval, void *data)
140 VLC_UNUSED(cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(data);
141 vout_thread_t *vout = (vout_thread_t *)object;
144 const int deinterlace_state = var_GetInteger(vout, "deinterlace");
145 char *mode = var_GetString(vout, "deinterlace-mode");
146 const bool is_needed = var_GetBool(vout, "deinterlace-needed");
147 if (!mode || !DeinterlaceIsModeValid(mode))
151 char *old = var_CreateGetString(vout, "sout-deinterlace-mode");
152 var_SetString(vout, "sout-deinterlace-mode", mode);
154 msg_Dbg(vout, "deinterlace %d, mode %s, is_needed %d", deinterlace_state, mode, is_needed);
155 if (deinterlace_state == 0 || (deinterlace_state == -1 && !is_needed))
156 DeinterlaceRemove(vout);
157 else if (!DeinterlaceIsPresent(vout))
158 DeinterlaceAdd(vout);
159 else if (old && strcmp(old, mode))
160 var_TriggerCallback(vout, "video-filter");
168 void vout_InitInterlacingSupport(vout_thread_t *vout, bool is_interlaced)
170 vlc_value_t val, text;
172 msg_Dbg(vout, "Deinterlacing available");
174 /* Create the configuration variables */
176 var_Create(vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE);
177 int deinterlace_state = var_GetInteger(vout, "deinterlace");
178 deinterlace_state = VLC_CLIP(deinterlace_state, -1, 1);
180 text.psz_string = _("Deinterlace");
181 var_Change(vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL);
183 const module_config_t *optd = config_FindConfig(VLC_OBJECT(vout), "deinterlace");
184 var_Change(vout, "deinterlace", VLC_VAR_CLEARCHOICES, NULL, NULL);
185 if (likely(optd != NULL))
186 for (unsigned i = 0; i < optd->list_count; i++) {
187 val.i_int = optd->list.i[i];
188 text.psz_string = vlc_gettext(optd->list_text[i]);
189 var_Change(vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text);
191 var_AddCallback(vout, "deinterlace", DeinterlaceCallback, NULL);
193 var_Create(vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE);
194 char *deinterlace_mode = var_GetNonEmptyString(vout, "deinterlace-mode");
196 text.psz_string = _("Deinterlace mode");
197 var_Change(vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL);
199 const module_config_t *optm = config_FindConfig(VLC_OBJECT(vout), "deinterlace-mode");
200 var_Change(vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL);
201 if (likely(optm != NULL))
202 for (unsigned i = 0; i < optm->list_count; i++) {
203 if (!DeinterlaceIsModeValid(optm->list.psz[i]))
206 val.psz_string = optm->list.psz[i];
207 text.psz_string = vlc_gettext(optm->list_text[i]);
208 var_Change(vout, "deinterlace-mode", VLC_VAR_ADDCHOICE,
211 var_AddCallback(vout, "deinterlace-mode", DeinterlaceCallback, NULL);
213 var_Create(vout, "deinterlace-needed", VLC_VAR_BOOL);
214 var_AddCallback(vout, "deinterlace-needed", DeinterlaceCallback, NULL);
216 /* Override the initial value from filters if present */
217 char *filter_mode = NULL;
218 if (DeinterlaceIsPresent(vout))
219 filter_mode = var_CreateGetNonEmptyString(vout, "sout-deinterlace-mode");
221 deinterlace_state = 1;
222 free(deinterlace_mode);
223 deinterlace_mode = filter_mode;
227 val.psz_string = deinterlace_mode ? deinterlace_mode : optm->orig.psz;
228 var_Change(vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL);
229 val.b_bool = is_interlaced;
230 var_Change(vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL);
232 var_SetInteger(vout, "deinterlace", deinterlace_state);
233 free(deinterlace_mode);
236 void vout_SetInterlacingState(vout_thread_t *vout, vout_interlacing_support_t *state, bool is_interlaced)
238 /* Wait 30s before quiting interlacing mode */
239 const int interlacing_change = (!!is_interlaced) - (!!state->is_interlaced);
240 if ((interlacing_change == 1) ||
241 (interlacing_change == -1 && state->date + 30000000 < mdate())) {
242 msg_Dbg(vout, "Detected %s video",
243 is_interlaced ? "interlaced" : "progressive");
244 var_SetBool(vout, "deinterlace-needed", is_interlaced);
246 state->is_interlaced = is_interlaced;
249 state->date = mdate();