From 7ea9a56dee592c4a8fb072e04730307a7c25b00f Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Sun, 25 Apr 2010 16:34:57 +0200 Subject: [PATCH] Split out interlacing/post-processing management from video_output.c (vout). --- src/Makefile.am | 4 + src/video_output/interlacing.c | 294 ++++++++++++++++++++++ src/video_output/interlacing.h | 39 +++ src/video_output/postprocessing.c | 143 +++++++++++ src/video_output/postprocessing.h | 37 +++ src/video_output/video_output.c | 397 ++---------------------------- 6 files changed, 531 insertions(+), 383 deletions(-) create mode 100644 src/video_output/interlacing.c create mode 100644 src/video_output/interlacing.h create mode 100644 src/video_output/postprocessing.c create mode 100644 src/video_output/postprocessing.h diff --git a/src/Makefile.am b/src/Makefile.am index be4c772034..bc93824fac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -361,9 +361,13 @@ SOURCES_libvlc_common = \ video_output/event.h \ video_output/inhibit.c \ video_output/inhibit.h \ + video_output/interlacing.c \ + video_output/interlacing.h \ video_output/snapshot.c \ video_output/snapshot.h \ video_output/statistic.h \ + video_output/postprocessing.c \ + video_output/postprocessing.h \ video_output/video_output.c \ video_output/vout_pictures.c \ video_output/vout_pictures.h \ diff --git a/src/video_output/interlacing.c b/src/video_output/interlacing.c new file mode 100644 index 0000000000..c25c08bbd8 --- /dev/null +++ b/src/video_output/interlacing.c @@ -0,0 +1,294 @@ +/***************************************************************************** + * interlacing.c + ***************************************************************************** + * Copyright (C) 2010 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include +#include + +#include "interlacing.h" + +/***************************************************************************** + * Deinterlacing + *****************************************************************************/ +/* 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 char *deinterlace_modes[] = { + "" + //"discard", + "blend", + //"mean", + //"bob", + //"linear", + "x", + //"yadif", + //"yadif2x", + NULL +}; +static bool DeinterlaceIsModeValid(const char *mode) +{ + for (unsigned i = 0; deinterlace_modes[i]; i++) { + if( !strcmp(deinterlace_modes[i], mode)) + return true; + } + return false; +} + +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 ) +{ + char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); + + bool b_found = FilterFind( psz_filter, "deinterlace" ) != NULL; + + free( psz_filter ); + + return b_found; +} + +static void DeinterlaceRemove( vout_thread_t *p_vout ) +{ + char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); + + 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, "video-filter", psz_filter ); + free( psz_filter ); +} +static void DeinterlaceAdd( vout_thread_t *p_vout ) +{ + char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); + + 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, "video-filter", psz_filter ); + free( psz_filter ); + } +} + +static void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const char *psz_mode ) +{ + /* We have to set input variable to ensure restart support + * FIXME to be removed when vout_Request does the right job. + */ + vlc_object_t *p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); + if( !p_input ) + return; + + var_Create( p_input, "deinterlace", VLC_VAR_INTEGER ); + var_SetInteger( p_input, "deinterlace", i_deinterlace ); + + static const char * const ppsz_variable[] = { + "deinterlace-mode", + "sout-deinterlace-mode", + NULL + }; + for( int i = 0; ppsz_variable[i]; i++ ) + { + var_Create( p_input, ppsz_variable[i], VLC_VAR_STRING ); + var_SetString( p_input, ppsz_variable[i], psz_mode ); + } + + vlc_object_release( p_input ); +} +static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, + vlc_value_t oldval, vlc_value_t newval, void *p_data ) +{ + VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data); + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* */ + const int i_deinterlace = var_GetInteger( p_this, "deinterlace" ); + char *psz_mode = var_GetString( p_this, "deinterlace-mode" ); + const bool is_needed = var_GetBool( p_this, "deinterlace-needed" ); + if( !psz_mode || !DeinterlaceIsModeValid(psz_mode) ) + return VLC_EGENERIC; + + DeinterlaceSave( p_vout, i_deinterlace, psz_mode ); + + /* */ + char *psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" ); + + msg_Dbg( p_vout, "deinterlace %d, mode %s, is_needed %d", i_deinterlace, psz_mode, is_needed ); + if( i_deinterlace == 0 || ( i_deinterlace == -1 && !is_needed ) ) + { + DeinterlaceRemove( p_vout ); + } + else if( !DeinterlaceIsPresent( p_vout ) ) + { + DeinterlaceAdd( p_vout ); + } + else if( psz_old && strcmp( psz_old, psz_mode ) ) + { + var_TriggerCallback( p_vout, "video-filter" ); + } + + /* */ + free( psz_old ); + free( psz_mode ); + return VLC_SUCCESS; +} + +void vout_InitInterlacingSupport( vout_thread_t *p_vout, bool is_interlaced ) +{ + vlc_value_t val, text; + + msg_Dbg( p_vout, "Deinterlacing available" ); + + /* Create the configuration variables */ + /* */ + var_Create( p_vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); + int i_deinterlace = var_GetInteger( p_vout, "deinterlace" ); + + text.psz_string = _("Deinterlace"); + var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL ); + + const module_config_t *p_optd = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace" ); + var_Change( p_vout, "deinterlace", VLC_VAR_CLEARCHOICES, NULL, NULL ); + for( int i = 0; p_optd && i < p_optd->i_list; i++ ) + { + val.i_int = p_optd->pi_list[i]; + text.psz_string = (char*)vlc_gettext(p_optd->ppsz_list_text[i]); + var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); + } + var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); + /* */ + var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); + char *psz_deinterlace = var_GetNonEmptyString( p_vout, "deinterlace-mode" ); + + text.psz_string = _("Deinterlace mode"); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL ); + + const module_config_t *p_optm = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace-mode" ); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL ); + for( int i = 0; p_optm && i < p_optm->i_list; i++ ) + { + if( !DeinterlaceIsModeValid( p_optm->ppsz_list[i] ) ) + continue; + + val.psz_string = p_optm->ppsz_list[i]; + text.psz_string = (char*)vlc_gettext(p_optm->ppsz_list_text[i]); + var_Change( p_vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text ); + } + var_AddCallback( p_vout, "deinterlace-mode", DeinterlaceCallback, NULL ); + /* */ + var_Create( p_vout, "deinterlace-needed", VLC_VAR_BOOL ); + var_AddCallback( p_vout, "deinterlace-needed", DeinterlaceCallback, NULL ); + + /* Override the initial value from filters if present */ + char *psz_filter_mode = NULL; + if( DeinterlaceIsPresent( p_vout ) ) + psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" ); + if( psz_filter_mode ) + { + free( psz_deinterlace ); + if( i_deinterlace >= -1 ) + i_deinterlace = 1; + psz_deinterlace = psz_filter_mode; + } + + /* */ + if( i_deinterlace < 0 ) + i_deinterlace = -1; + + /* */ + val.psz_string = psz_deinterlace ? psz_deinterlace : p_optm->orig.psz; + var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL ); + val.b_bool = is_interlaced; + var_Change( p_vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL ); + + var_SetInteger( p_vout, "deinterlace", i_deinterlace ); + free( psz_deinterlace ); +} + +void vout_SetInterlacingState( vout_thread_t *p_vout, vout_interlacing_support_t *state, bool is_interlaced ) +{ + /* Wait 30s before quiting interlacing mode */ + const int interlacing_change = (!!is_interlaced) - (!!state->is_interlaced); + if ((interlacing_change == 1) || + (interlacing_change == -1 && state->date + 30000000 < mdate())) { + + msg_Dbg( p_vout, "Detected %s video", + is_interlaced ? "interlaced" : "progressive" ); + var_SetBool( p_vout, "deinterlace-needed", is_interlaced ); + + state->is_interlaced = is_interlaced; + } + if (is_interlaced) + state->date = mdate(); +} + + diff --git a/src/video_output/interlacing.h b/src/video_output/interlacing.h new file mode 100644 index 0000000000..bc0b729ea0 --- /dev/null +++ b/src/video_output/interlacing.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * interlacing.h: Interlacing related helpers + ***************************************************************************** + * Copyright (C) 2010 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#if defined(__PLUGIN__) || defined(__BUILTIN__) || !defined(__LIBVLC__) +# error This header file can only be included from LibVLC. +#endif + +#ifndef _VOUT_INTERLACING_H +#define _VOUT_INTERLACING_H + +typedef struct { + bool is_interlaced; + mtime_t date; +} vout_interlacing_support_t; + +void vout_InitInterlacingSupport(vout_thread_t *, bool is_interlaced); +void vout_SetInterlacingState(vout_thread_t *, vout_interlacing_support_t *, bool is_interlaced); + +#endif diff --git a/src/video_output/postprocessing.c b/src/video_output/postprocessing.c new file mode 100644 index 0000000000..6b86efd2f2 --- /dev/null +++ b/src/video_output/postprocessing.c @@ -0,0 +1,143 @@ +/***************************************************************************** + * postprocessing.c + ***************************************************************************** + * Copyright (C) 2010 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include +#include + +#include "postprocessing.h" + +static bool PostProcessIsPresent( const char *psz_filter ) +{ + const char *psz_pp = "postproc"; + const size_t i_pp = strlen(psz_pp); + return psz_filter && + !strncmp( psz_filter, psz_pp, strlen(psz_pp) ) && + ( psz_filter[i_pp] == '\0' || psz_filter[i_pp] == ':' ); +} + +static int PostProcessCallback( 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; + VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data); + + static const char *psz_pp = "postproc"; + + char *psz_vf2 = var_GetString( p_vout, "video-filter" ); + + if( newval.i_int <= 0 ) + { + if( PostProcessIsPresent( psz_vf2 ) ) + { + strcpy( psz_vf2, &psz_vf2[strlen(psz_pp)] ); + if( *psz_vf2 == ':' ) + strcpy( psz_vf2, &psz_vf2[1] ); + } + } + else + { + if( !PostProcessIsPresent( psz_vf2 ) ) + { + if( psz_vf2 ) + { + char *psz_tmp = psz_vf2; + if( asprintf( &psz_vf2, "%s:%s", psz_pp, psz_tmp ) < 0 ) + psz_vf2 = psz_tmp; + else + free( psz_tmp ); + } + else + { + psz_vf2 = strdup( psz_pp ); + } + } + } + if( newval.i_int > 0 ) + var_SetInteger( p_vout, "postproc-q", newval.i_int ); + if( psz_vf2 ) + { + var_SetString( p_vout, "video-filter", psz_vf2 ); + free( psz_vf2 ); + } + else if( newval.i_int > 0 ) + { + var_TriggerCallback( p_vout, "video-filter" ); + } + return VLC_SUCCESS; +} +static void PostProcessEnable( vout_thread_t *p_vout ) +{ + vlc_value_t text; + msg_Dbg( p_vout, "Post-processing available" ); + var_Create( p_vout, "postprocess", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); + text.psz_string = _("Post processing"); + var_Change( p_vout, "postprocess", VLC_VAR_SETTEXT, &text, NULL ); + + for( int i = 0; i <= 6; i++ ) + { + vlc_value_t val; + vlc_value_t text; + char psz_text[1+1]; + + val.i_int = i; + snprintf( psz_text, sizeof(psz_text), "%d", i ); + if( i == 0 ) + text.psz_string = _("Disable"); + else + 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" ); +} + +void vout_SetPostProcessingState(vout_thread_t *vout, vout_postprocessing_support_t *state, int qtype) +{ + const int postproc_change = (qtype != QTYPE_NONE) - (state->qtype != QTYPE_NONE); + if (postproc_change == 1) + PostProcessEnable(vout); + else if (postproc_change == -1) + PostProcessDisable(vout); + if (postproc_change) + state->qtype = qtype; +} + diff --git a/src/video_output/postprocessing.h b/src/video_output/postprocessing.h new file mode 100644 index 0000000000..4521e1a95b --- /dev/null +++ b/src/video_output/postprocessing.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * postprocessing.h: Post processing related helpers + ***************************************************************************** + * Copyright (C) 2010 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#if defined(__PLUGIN__) || defined(__BUILTIN__) || !defined(__LIBVLC__) +# error This header file can only be included from LibVLC. +#endif + +#ifndef _VOUT_POSTPROCESSING_H +#define _VOUT_POSTPROCESSING_H + +typedef struct { + int qtype; +} vout_postprocessing_support_t; + +void vout_SetPostProcessingState(vout_thread_t *, vout_postprocessing_support_t *, int qtype); + +#endif diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index afafd3f4d5..df544a32b4 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -49,6 +49,8 @@ #include #include "vout_pictures.h" #include "vout_internal.h" +#include "interlacing.h" +#include "postprocessing.h" /***************************************************************************** * Local prototypes @@ -62,15 +64,6 @@ static int FilterCallback( vlc_object_t *, char const *, static int VideoFilter2Callback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * ); -/* */ -static void PostProcessEnable( vout_thread_t * ); -static void PostProcessDisable( vout_thread_t * ); -static int PostProcessCallback( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); -/* */ -static void DeinterlaceEnable( vout_thread_t *, bool is_interlaced ); -static void DeinterlaceNeeded( vout_thread_t *, bool ); - /* Display media title in OSD */ static void DisplayTitleOnOSD( vout_thread_t *p_vout ); @@ -384,7 +377,7 @@ vout_thread_t * (vout_Create)( vlc_object_t *p_parent, video_format_t *p_fmt ) var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL ); /* */ - DeinterlaceEnable( p_vout, p_vout->p->displayed.is_interlaced ); + vout_InitInterlacingSupport( p_vout, p_vout->p->displayed.is_interlaced ); if( p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ) { @@ -917,9 +910,13 @@ static void *Thread(void *object) goto exit_thread; /* */ - bool last_picture_interlaced = false; - int last_picture_qtype = QTYPE_NONE; - mtime_t last_picture_interlaced_date = mdate(); + vout_interlacing_support_t interlacing = { + .is_interlaced = false, + .date = mdate(), + }; + vout_postprocessing_support_t postprocessing = { + .qtype = QTYPE_NONE, + }; /* * Main loop - it is not executed if an error occurred during @@ -971,24 +968,10 @@ static void *Thread(void *object) } /* Post processing */ - const int postproc_change = (picture_qtype != QTYPE_NONE) - (last_picture_qtype != QTYPE_NONE); - if (postproc_change == 1) - PostProcessEnable(vout); - else if (postproc_change == -1) - PostProcessDisable(vout); - if (postproc_change) - last_picture_qtype = picture_qtype; - - /* Deinterlacing - * Wait 30s before quiting interlacing mode */ - const int interlacing_change = (!!picture_interlaced) - (!!last_picture_interlaced); - if ((interlacing_change == 1) || - (interlacing_change == -1 && last_picture_interlaced_date + 30000000 < mdate())) { - DeinterlaceNeeded(vout, picture_interlaced); - last_picture_interlaced = picture_interlaced; - } - if (picture_interlaced) - last_picture_interlaced_date = mdate(); + vout_SetPostProcessingState(vout, &postprocessing, picture_qtype); + + /* Deinterlacing */ + vout_SetInterlacingState(vout, &interlacing, picture_interlaced); /* Check for "video filter2" changes */ vlc_mutex_lock(&vout->p->vfilter_lock); @@ -1095,108 +1078,6 @@ static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd, return VLC_SUCCESS; } -/***************************************************************************** - * Post-processing - *****************************************************************************/ -static bool PostProcessIsPresent( const char *psz_filter ) -{ - const char *psz_pp = "postproc"; - const size_t i_pp = strlen(psz_pp); - return psz_filter && - !strncmp( psz_filter, psz_pp, strlen(psz_pp) ) && - ( psz_filter[i_pp] == '\0' || psz_filter[i_pp] == ':' ); -} - -static int PostProcessCallback( 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; - VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data); - - static const char *psz_pp = "postproc"; - - char *psz_vf2 = var_GetString( p_vout, "video-filter" ); - - if( newval.i_int <= 0 ) - { - if( PostProcessIsPresent( psz_vf2 ) ) - { - strcpy( psz_vf2, &psz_vf2[strlen(psz_pp)] ); - if( *psz_vf2 == ':' ) - strcpy( psz_vf2, &psz_vf2[1] ); - } - } - else - { - if( !PostProcessIsPresent( psz_vf2 ) ) - { - if( psz_vf2 ) - { - char *psz_tmp = psz_vf2; - if( asprintf( &psz_vf2, "%s:%s", psz_pp, psz_tmp ) < 0 ) - psz_vf2 = psz_tmp; - else - free( psz_tmp ); - } - else - { - psz_vf2 = strdup( psz_pp ); - } - } - } - if( newval.i_int > 0 ) - var_SetInteger( p_vout, "postproc-q", newval.i_int ); - if( psz_vf2 ) - { - var_SetString( p_vout, "video-filter", psz_vf2 ); - free( psz_vf2 ); - } - else if( newval.i_int > 0 ) - { - var_TriggerCallback( p_vout, "video-filter" ); - } - return VLC_SUCCESS; -} -static void PostProcessEnable( vout_thread_t *p_vout ) -{ - vlc_value_t text; - msg_Dbg( p_vout, "Post-processing available" ); - var_Create( p_vout, "postprocess", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE ); - text.psz_string = _("Post processing"); - var_Change( p_vout, "postprocess", VLC_VAR_SETTEXT, &text, NULL ); - - for( int i = 0; i <= 6; i++ ) - { - vlc_value_t val; - vlc_value_t text; - char psz_text[1+1]; - - val.i_int = i; - snprintf( psz_text, sizeof(psz_text), "%d", i ); - if( i == 0 ) - text.psz_string = _("Disable"); - else - 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 DisplayTitleOnOSD( vout_thread_t *p_vout ) { const mtime_t i_start = mdate(); @@ -1221,256 +1102,6 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) p_vout->p->title.value = NULL; } -/***************************************************************************** - * Deinterlacing - *****************************************************************************/ -/* 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 char *deinterlace_modes[] = { - "" - //"discard", - "blend", - //"mean", - //"bob", - //"linear", - "x", - //"yadif", - //"yadif2x", - NULL -}; -static bool DeinterlaceIsModeValid(const char *mode) -{ - for (unsigned i = 0; deinterlace_modes[i]; i++) { - if( !strcmp(deinterlace_modes[i], mode)) - return true; - } - return false; -} - -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 ) -{ - char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); - - bool b_found = FilterFind( psz_filter, "deinterlace" ) != NULL; - - free( psz_filter ); - - return b_found; -} - -static void DeinterlaceRemove( vout_thread_t *p_vout ) -{ - char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); - - 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, "video-filter", psz_filter ); - free( psz_filter ); -} -static void DeinterlaceAdd( vout_thread_t *p_vout ) -{ - char *psz_filter = var_GetNonEmptyString( p_vout, "video-filter" ); - - 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, "video-filter", psz_filter ); - free( psz_filter ); - } -} - -static void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const char *psz_mode ) -{ - /* We have to set input variable to ensure restart support - * FIXME to be removed when vout_Request does the right job. - */ - vlc_object_t *p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); - if( !p_input ) - return; - - var_Create( p_input, "deinterlace", VLC_VAR_INTEGER ); - var_SetInteger( p_input, "deinterlace", i_deinterlace ); - - static const char * const ppsz_variable[] = { - "deinterlace-mode", - "sout-deinterlace-mode", - NULL - }; - for( int i = 0; ppsz_variable[i]; i++ ) - { - var_Create( p_input, ppsz_variable[i], VLC_VAR_STRING ); - var_SetString( p_input, ppsz_variable[i], psz_mode ); - } - - vlc_object_release( p_input ); -} -static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) -{ - VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data); - vout_thread_t *p_vout = (vout_thread_t *)p_this; - - /* */ - const int i_deinterlace = var_GetInteger( p_this, "deinterlace" ); - char *psz_mode = var_GetString( p_this, "deinterlace-mode" ); - const bool is_needed = var_GetBool( p_this, "deinterlace-needed" ); - if( !psz_mode || !DeinterlaceIsModeValid(psz_mode) ) - return VLC_EGENERIC; - - DeinterlaceSave( p_vout, i_deinterlace, psz_mode ); - - /* */ - char *psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" ); - - msg_Dbg( p_vout, "deinterlace %d, mode %s, is_needed %d", i_deinterlace, psz_mode, is_needed ); - if( i_deinterlace == 0 || ( i_deinterlace == -1 && !is_needed ) ) - { - DeinterlaceRemove( p_vout ); - } - else if( !DeinterlaceIsPresent( p_vout ) ) - { - DeinterlaceAdd( p_vout ); - } - else if( psz_old && strcmp( psz_old, psz_mode ) ) - { - var_TriggerCallback( p_vout, "video-filter" ); - } - - /* */ - free( psz_old ); - free( psz_mode ); - return VLC_SUCCESS; -} - -static void DeinterlaceEnable( vout_thread_t *p_vout, bool is_interlaced ) -{ - vlc_value_t val, text; - - msg_Dbg( p_vout, "Deinterlacing available" ); - - /* Create the configuration variables */ - /* */ - var_Create( p_vout, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); - int i_deinterlace = var_GetInteger( p_vout, "deinterlace" ); - - text.psz_string = _("Deinterlace"); - var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL ); - - const module_config_t *p_optd = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace" ); - var_Change( p_vout, "deinterlace", VLC_VAR_CLEARCHOICES, NULL, NULL ); - for( int i = 0; p_optd && i < p_optd->i_list; i++ ) - { - val.i_int = p_optd->pi_list[i]; - text.psz_string = (char*)vlc_gettext(p_optd->ppsz_list_text[i]); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - } - var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); - /* */ - var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_HASCHOICE ); - char *psz_deinterlace = var_GetNonEmptyString( p_vout, "deinterlace-mode" ); - - text.psz_string = _("Deinterlace mode"); - var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETTEXT, &text, NULL ); - - const module_config_t *p_optm = config_FindConfig( VLC_OBJECT(p_vout), "deinterlace-mode" ); - var_Change( p_vout, "deinterlace-mode", VLC_VAR_CLEARCHOICES, NULL, NULL ); - for( int i = 0; p_optm && i < p_optm->i_list; i++ ) - { - if( !DeinterlaceIsModeValid( p_optm->ppsz_list[i] ) ) - continue; - - val.psz_string = p_optm->ppsz_list[i]; - text.psz_string = (char*)vlc_gettext(p_optm->ppsz_list_text[i]); - var_Change( p_vout, "deinterlace-mode", VLC_VAR_ADDCHOICE, &val, &text ); - } - var_AddCallback( p_vout, "deinterlace-mode", DeinterlaceCallback, NULL ); - /* */ - var_Create( p_vout, "deinterlace-needed", VLC_VAR_BOOL ); - var_AddCallback( p_vout, "deinterlace-needed", DeinterlaceCallback, NULL ); - - /* Override the initial value from filters if present */ - char *psz_filter_mode = NULL; - if( DeinterlaceIsPresent( p_vout ) ) - psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" ); - if( psz_filter_mode ) - { - free( psz_deinterlace ); - if( i_deinterlace >= -1 ) - i_deinterlace = 1; - psz_deinterlace = psz_filter_mode; - } - - /* */ - if( i_deinterlace < 0 ) - i_deinterlace = -1; - - /* */ - val.psz_string = psz_deinterlace ? psz_deinterlace : p_optm->orig.psz; - var_Change( p_vout, "deinterlace-mode", VLC_VAR_SETVALUE, &val, NULL ); - val.b_bool = is_interlaced; - var_Change( p_vout, "deinterlace-needed", VLC_VAR_SETVALUE, &val, NULL ); - - var_SetInteger( p_vout, "deinterlace", i_deinterlace ); - free( psz_deinterlace ); -} - -static void DeinterlaceNeeded( vout_thread_t *p_vout, bool is_interlaced ) -{ - msg_Dbg( p_vout, "Detected %s video", - is_interlaced ? "interlaced" : "progressive" ); - var_SetBool( p_vout, "deinterlace-needed", is_interlaced ); -} - /* */ static void PrintVideoFormat(vout_thread_t *vout, const char *description, -- 2.39.2