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
[] = {
53 static bool DeinterlaceIsModeValid(const char *mode
)
55 for (unsigned i
= 0; deinterlace_modes
[i
]; i
++) {
56 if( !strcmp(deinterlace_modes
[i
], mode
))
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 )
72 char *psz_find
= strstr( psz_filter
, psz_module
);
75 if( psz_find
[i_module
] == '\0' || psz_find
[i_module
] == ':' )
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
;
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" );
104 strcpy( &psz
[0], &psz
[strlen("deinterlace")] );
106 strcpy( &psz
[0], &psz
[1] );
108 var_SetString( p_vout
, "video-filter", 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" ) )
124 char *psz_tmp
= psz_filter
;
125 if( asprintf( &psz_filter
, "%s:%s", psz_tmp
, "deinterlace" ) < 0 )
126 psz_filter
= psz_tmp
;
132 psz_filter
= strdup( "deinterlace" );
137 var_SetString( p_vout
, "video-filter", 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
);
151 var_Create( p_input
, "deinterlace", VLC_VAR_INTEGER
);
152 var_SetInteger( p_input
, "deinterlace", i_deinterlace
);
154 static const char * const ppsz_variable
[] = {
156 "sout-deinterlace-mode",
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
;
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
) )
180 DeinterlaceSave( p_vout
, i_deinterlace
, psz_mode
);
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" );
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 */
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
);
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
] ) )
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
);
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 )
261 psz_deinterlace
= psz_filter_mode
;
265 if( i_deinterlace
< 0 )
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
;
292 state
->date
= mdate();