+ text.psz_string = psz_text;
+ var_Change( p_vout, "postprocess", VLC_VAR_ADDCHOICE, &val, &text );
+ }
+ var_AddCallback( p_vout, "postprocess", PostProcessCallback, NULL );
+
+ /* */
+ char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" );
+ int i_postproc_q = 0;
+ if( PostProcessIsPresent( psz_filter ) )
+ i_postproc_q = var_CreateGetInteger( p_vout, "postproc-q" );
+
+ var_SetInteger( p_vout, "postprocess", i_postproc_q );
+
+ free( psz_filter );
+}
+static void PostProcessDisable( vout_thread_t *p_vout )
+{
+ msg_Dbg( p_vout, "Post-processing no more available" );
+ var_Destroy( p_vout, "postprocess" );
+}
+static void PostProcessSetFilterQuality( vout_thread_t *p_vout )
+{
+ vlc_object_t *p_pp = vlc_object_find_name( p_vout, "postproc", FIND_CHILD );
+ if( !p_pp )
+ return;
+
+ var_SetInteger( p_pp, "postproc-q", var_GetInteger( p_vout, "postprocess" ) );
+ vlc_object_release( p_pp );
+}
+
+
+static void DisplayTitleOnOSD( vout_thread_t *p_vout )
+{
+ const mtime_t i_start = mdate();
+ const mtime_t i_stop = i_start + INT64_C(1000) * p_vout->p->i_title_timeout;
+
+ if( i_stop <= i_start )
+ return;
+
+ vlc_assert_locked( &p_vout->change_lock );
+
+ vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
+ p_vout->p->psz_title, NULL,
+ p_vout->p->i_title_position,
+ 30 + p_vout->fmt_in.i_width
+ - p_vout->fmt_in.i_visible_width
+ - p_vout->fmt_in.i_x_offset,
+ 20 + p_vout->fmt_in.i_y_offset,
+ i_start, i_stop );
+
+ free( p_vout->p->psz_title );
+
+ p_vout->p->psz_title = NULL;
+}
+
+/*****************************************************************************
+ * Deinterlacing
+ *****************************************************************************/
+typedef struct
+{
+ const char *psz_mode;
+ const char *psz_description;
+ bool b_vout_filter;
+} deinterlace_mode_t;
+
+/* XXX
+ * You can use the non vout filter if and only if the video properties stay the
+ * same (width/height/chroma/fps), at least for now.
+ */
+static const deinterlace_mode_t p_deinterlace_mode[] = {
+ { "", "Disable", false },
+ { "discard", "Discard", true },
+ { "blend", "Blend", false },
+ { "mean", "Mean", true },
+ { "bob", "Bob", true },
+ { "linear", "Linear", true },
+ { "x", "X", false },
+ { NULL, NULL, true }
+};
+
+static char *FilterFind( char *psz_filter_base, const char *psz_module )
+{
+ const size_t i_module = strlen( psz_module );
+ const char *psz_filter = psz_filter_base;
+
+ if( !psz_filter || i_module <= 0 )
+ return NULL;
+
+ for( ;; )
+ {
+ char *psz_find = strstr( psz_filter, psz_module );
+ if( !psz_find )
+ return NULL;
+ if( psz_find[i_module] == '\0' || psz_find[i_module] == ':' )
+ return psz_find;
+ psz_filter = &psz_find[i_module];
+ }
+}
+
+static bool DeinterlaceIsPresent( vout_thread_t *p_vout, bool b_vout_filter )
+{
+ char *psz_filter = var_GetNonEmptyString( p_vout, b_vout_filter ? "vout-filter" : "video-filter" );
+
+ bool b_found = FilterFind( psz_filter, "deinterlace" ) != NULL;
+
+ free( psz_filter );
+
+ return b_found;
+}
+
+static void DeinterlaceRemove( vout_thread_t *p_vout, bool b_vout_filter )
+{
+ const char *psz_variable = b_vout_filter ? "vout-filter" : "video-filter";
+ char *psz_filter = var_GetNonEmptyString( p_vout, psz_variable );
+
+ char *psz = FilterFind( psz_filter, "deinterlace" );
+ if( !psz )
+ {
+ free( psz_filter );
+ return;
+ }
+
+ /* */
+ strcpy( &psz[0], &psz[strlen("deinterlace")] );
+ if( *psz == ':' )
+ strcpy( &psz[0], &psz[1] );
+
+ var_SetString( p_vout, psz_variable, psz_filter );
+ free( psz_filter );
+}
+static void DeinterlaceAdd( vout_thread_t *p_vout, bool b_vout_filter )
+{
+ const char *psz_variable = b_vout_filter ? "vout-filter" : "video-filter";
+
+ char *psz_filter = var_GetNonEmptyString( p_vout, psz_variable );
+
+ if( FilterFind( psz_filter, "deinterlace" ) )
+ {
+ free( psz_filter );
+ return;
+ }
+
+ /* */
+ if( psz_filter )
+ {
+ char *psz_tmp = psz_filter;
+ if( asprintf( &psz_filter, "%s:%s", psz_tmp, "deinterlace" ) < 0 )
+ psz_filter = psz_tmp;
+ else
+ free( psz_tmp );
+ }
+ else
+ {
+ psz_filter = strdup( "deinterlace" );
+ }
+
+ if( psz_filter )
+ {
+ var_SetString( p_vout, psz_variable, psz_filter );
+ free( psz_filter );
+ }
+}
+
+static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+ vout_thread_t *p_vout = (vout_thread_t *)p_this;
+
+ /* */
+ const deinterlace_mode_t *p_mode;
+ for( p_mode = &p_deinterlace_mode[0]; p_mode->psz_mode; p_mode++ )
+ {
+ if( !strcmp( p_mode->psz_mode,
+ newval.psz_string ? newval.psz_string : "" ) )
+ break;
+ }
+ if( !p_mode->psz_mode )
+ {
+ msg_Err( p_this, "Invalid value (%s) ignored", newval.psz_string );
+ return VLC_EGENERIC;
+ }
+
+ /* We have to set input variable to ensure restart support
+ * XXX it is only needed because of vout-filter but must be done
+ * for non video filter anyway */
+ input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
+ if( p_input )
+ {
+ var_Create( p_input, "vout-deinterlace", VLC_VAR_STRING );
+ var_SetString( p_input, "vout-deinterlace", p_mode->psz_mode );
+
+ var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
+ var_SetString( p_input, "deinterlace-mode", p_mode->psz_mode );
+
+ var_Create( p_input, "sout-deinterlace-mode", VLC_VAR_STRING );
+ var_SetString( p_input, "sout-deinterlace-mode", p_mode->psz_mode );
+