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
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 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[] = {
55 static bool DeinterlaceIsModeValid(const char *mode)
57 for (unsigned i = 0; deinterlace_modes[i]; 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 for (int i = 0; optd && i < optd->i_list; i++) {
186 val.i_int = optd->pi_list[i];
187 text.psz_string = (char*)vlc_gettext(optd->ppsz_list_text[i]);
188 var_Change(vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text);
190 var_AddCallback(vout, "deinterlace", DeinterlaceCallback, NULL);
192 var_Create(vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE);
193 char *deinterlace_mode = var_GetNonEmptyString(vout, "deinterlace-mode");
195 text.psz_string = _("Deinterlace mode");
196 var_Change(vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL);
198 const module_config_t *optm = config_FindConfig(VLC_OBJECT(vout), "deinterlace-mode");
199 var_Change(vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL);
200 for (int i = 0; optm && i < optm->i_list; i++) {
201 if (!DeinterlaceIsModeValid(optm->ppsz_list[i]))
204 val.psz_string = optm->ppsz_list[i];
205 text.psz_string = (char*)vlc_gettext(optm->ppsz_list_text[i]);
206 var_Change(vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text);
208 var_AddCallback(vout, "deinterlace-mode", DeinterlaceCallback, NULL);
210 var_Create(vout, "deinterlace-needed", VLC_VAR_BOOL);
211 var_AddCallback(vout, "deinterlace-needed", DeinterlaceCallback, NULL);
213 /* Override the initial value from filters if present */
214 char *filter_mode = NULL;
215 if (DeinterlaceIsPresent(vout))
216 filter_mode = var_CreateGetNonEmptyString(vout, "sout-deinterlace-mode");
218 deinterlace_state = 1;
219 free(deinterlace_mode);
220 deinterlace_mode = filter_mode;
224 val.psz_string = deinterlace_mode ? deinterlace_mode : optm->orig.psz;
225 var_Change(vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL);
226 val.b_bool = is_interlaced;
227 var_Change(vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL);
229 var_SetInteger(vout, "deinterlace", deinterlace_state);
230 free(deinterlace_mode);
233 void vout_SetInterlacingState(vout_thread_t *vout, vout_interlacing_support_t *state, bool is_interlaced)
235 /* Wait 30s before quiting interlacing mode */
236 const int interlacing_change = (!!is_interlaced) - (!!state->is_interlaced);
237 if ((interlacing_change == 1) ||
238 (interlacing_change == -1 && state->date + 30000000 < mdate())) {
239 msg_Dbg(vout, "Detected %s video",
240 is_interlaced ? "interlaced" : "progressive");
241 var_SetBool(vout, "deinterlace-needed", is_interlaced);
243 state->is_interlaced = is_interlaced;
246 state->date = mdate();