Qt/EPG: Remove channels when they don't have any item.
[vlc/gmpfix.git] / src / video_output / interlacing.c
blob78280d204c68ac682cf6a624f797fcb00b38623f
1 /*****************************************************************************
2 * interlacing.c
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
5 * $Id$
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <assert.h>
29 #include <vlc_common.h>
30 #include <vlc_vout.h>
32 #include "interlacing.h"
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.
41 static const char *deinterlace_modes[] = {
43 //"discard",
44 "blend",
45 //"mean",
46 //"bob",
47 //"linear",
48 "x",
49 "yadif",
50 //"yadif2x",
51 NULL
53 static bool DeinterlaceIsModeValid(const char *mode)
55 for (unsigned i = 0; deinterlace_modes[i]; i++) {
56 if( !strcmp(deinterlace_modes[i], mode))
57 return true;
59 return false;
62 static char *FilterFind( char *psz_filter_base, const char *psz_module )
64 const size_t i_module = strlen( psz_module );
65 const char *psz_filter = psz_filter_base;
67 if( !psz_filter || i_module <= 0 )
68 return NULL;
70 for( ;; )
72 char *psz_find = strstr( psz_filter, psz_module );
73 if( !psz_find )
74 return NULL;
75 if( psz_find[i_module] == '\0' || psz_find[i_module] == ':' )
76 return psz_find;
77 psz_filter = &psz_find[i_module];
81 static bool DeinterlaceIsPresent( vout_thread_t *p_vout )
83 char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" );
85 bool b_found = FilterFind( psz_filter, "deinterlace" ) != NULL;
87 free( psz_filter );
89 return b_found;
92 static void DeinterlaceRemove( vout_thread_t *p_vout )
94 char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" );
96 char *psz = FilterFind( psz_filter, "deinterlace" );
97 if( !psz )
99 free( psz_filter );
100 return;
103 /* */
104 strcpy( &psz[0], &psz[strlen("deinterlace")] );
105 if( *psz == ':' )
106 strcpy( &psz[0], &psz[1] );
108 var_SetString( p_vout, "video-filter", psz_filter );
109 free( psz_filter );
111 static void DeinterlaceAdd( vout_thread_t *p_vout )
113 char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" );
115 if( FilterFind( psz_filter, "deinterlace" ) )
117 free( psz_filter );
118 return;
121 /* */
122 if( psz_filter )
124 char *psz_tmp = psz_filter;
125 if( asprintf( &psz_filter, "%s:%s", psz_tmp, "deinterlace" ) < 0 )
126 psz_filter = psz_tmp;
127 else
128 free( psz_tmp );
130 else
132 psz_filter = strdup( "deinterlace" );
135 if( psz_filter )
137 var_SetString( p_vout, "video-filter", psz_filter );
138 free( psz_filter );
142 static void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const char *psz_mode )
144 /* We have to set input variable to ensure restart support
145 * FIXME to be removed when vout_Request does the right job.
147 vlc_object_t *p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
148 if( !p_input )
149 return;
151 var_Create( p_input, "deinterlace", VLC_VAR_INTEGER );
152 var_SetInteger( p_input, "deinterlace", i_deinterlace );
154 static const char * const ppsz_variable[] = {
155 "deinterlace-mode",
156 "sout-deinterlace-mode",
157 NULL
159 for( int i = 0; ppsz_variable[i]; i++ )
161 var_Create( p_input, ppsz_variable[i], VLC_VAR_STRING );
162 var_SetString( p_input, ppsz_variable[i], psz_mode );
165 vlc_object_release( p_input );
167 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
168 vlc_value_t oldval, vlc_value_t newval, void *p_data )
170 VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data);
171 vout_thread_t *p_vout = (vout_thread_t *)p_this;
173 /* */
174 const int i_deinterlace = var_GetInteger( p_this, "deinterlace" );
175 char *psz_mode = var_GetString( p_this, "deinterlace-mode" );
176 const bool is_needed = var_GetBool( p_this, "deinterlace-needed" );
177 if( !psz_mode || !DeinterlaceIsModeValid(psz_mode) )
178 return VLC_EGENERIC;
180 DeinterlaceSave( p_vout, i_deinterlace, psz_mode );
182 /* */
183 char *psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" );
184 var_SetString( p_vout, "sout-deinterlace-mode", psz_mode );
186 msg_Dbg( p_vout, "deinterlace %d, mode %s, is_needed %d", i_deinterlace, psz_mode, is_needed );
187 if( i_deinterlace == 0 || ( i_deinterlace == -1 && !is_needed ) )
189 DeinterlaceRemove( p_vout );
191 else if( !DeinterlaceIsPresent( p_vout ) )
193 DeinterlaceAdd( p_vout );
195 else if( psz_old && strcmp( psz_old, psz_mode ) )
197 var_TriggerCallback( p_vout, "video-filter" );
200 /* */
201 free( psz_old );
202 free( psz_mode );
203 return VLC_SUCCESS;
206 void vout_InitInterlacingSupport( vout_thread_t *p_vout, bool is_interlaced )
208 vlc_value_t val, text;
210 msg_Dbg( p_vout, "Deinterlacing available" );
212 /* Create the configuration variables */
213 /* */
214 var_Create( p_vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE );
215 int i_deinterlace = var_GetInteger( p_vout, "deinterlace" );
217 text.psz_string = _("Deinterlace");
218 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
220 const module_config_t *p_optd = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace" );
221 var_Change( p_vout, "deinterlace", VLC_VAR_CLEARCHOICES, NULL, NULL );
222 for( int i = 0; p_optd && i < p_optd->i_list; i++ )
224 val.i_int = p_optd->pi_list[i];
225 text.psz_string = (char*)vlc_gettext(p_optd->ppsz_list_text[i]);
226 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
228 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
229 /* */
230 var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE );
231 char *psz_deinterlace = var_GetNonEmptyString( p_vout, "deinterlace-mode" );
233 text.psz_string = _("Deinterlace mode");
234 var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL );
236 const module_config_t *p_optm = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace-mode" );
237 var_Change( p_vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL );
238 for( int i = 0; p_optm && i < p_optm->i_list; i++ )
240 if( !DeinterlaceIsModeValid( p_optm->ppsz_list[i] ) )
241 continue;
243 val.psz_string = p_optm->ppsz_list[i];
244 text.psz_string = (char*)vlc_gettext(p_optm->ppsz_list_text[i]);
245 var_Change( p_vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text );
247 var_AddCallback( p_vout, "deinterlace-mode", DeinterlaceCallback, NULL );
248 /* */
249 var_Create( p_vout, "deinterlace-needed", VLC_VAR_BOOL );
250 var_AddCallback( p_vout, "deinterlace-needed", DeinterlaceCallback, NULL );
252 /* Override the initial value from filters if present */
253 char *psz_filter_mode = NULL;
254 if( DeinterlaceIsPresent( p_vout ) )
255 psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" );
256 if( psz_filter_mode )
258 free( psz_deinterlace );
259 if( i_deinterlace >= -1 )
260 i_deinterlace = 1;
261 psz_deinterlace = psz_filter_mode;
264 /* */
265 if( i_deinterlace < 0 )
266 i_deinterlace = -1;
268 /* */
269 val.psz_string = psz_deinterlace ? psz_deinterlace : p_optm->orig.psz;
270 var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL );
271 val.b_bool = is_interlaced;
272 var_Change( p_vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL );
274 var_SetInteger( p_vout, "deinterlace", i_deinterlace );
275 free( psz_deinterlace );
278 void vout_SetInterlacingState( vout_thread_t *p_vout, vout_interlacing_support_t *state, bool is_interlaced )
280 /* Wait 30s before quiting interlacing mode */
281 const int interlacing_change = (!!is_interlaced) - (!!state->is_interlaced);
282 if ((interlacing_change == 1) ||
283 (interlacing_change == -1 && state->date + 30000000 < mdate())) {
285 msg_Dbg( p_vout, "Detected %s video",
286 is_interlaced ? "interlaced" : "progressive" );
287 var_SetBool( p_vout, "deinterlace-needed", is_interlaced );
289 state->is_interlaced = is_interlaced;
291 if (is_interlaced)
292 state->date = mdate();