X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=bfac617547103d5ec21a0cd60de4f6edb6a232a6;hb=65113f55d63c9995b9ec781e75d531a9bd20d848;hp=0751e7563328f579fbe553b075d5c4191fe182c5;hpb=31a51c3e45d72159defca0aaf95a5b599fc7cc5d;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 0751e75633..bfac617547 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -38,11 +38,6 @@ #include /* free() */ #include - -#ifdef HAVE_SYS_TIMES_H -# include -#endif - #include #include @@ -71,21 +66,27 @@ static void ErrorThread ( vout_thread_t * ); static void CleanThread ( vout_thread_t * ); static void EndThread ( vout_thread_t * ); -static void AspectRatio ( int, int *, int * ); - static void VideoFormatImportRgb( video_format_t *, const picture_heap_t * ); static void PictureHeapFixRgb( picture_heap_t * ); static void vout_Destructor ( vlc_object_t * p_this ); /* Object variables callbacks */ -static int DeinterlaceCallback( vlc_object_t *, char const *, - vlc_value_t, vlc_value_t, void * ); static int FilterCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * ); 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 void PostProcessSetFilterQuality( vout_thread_t *p_vout ); +static int PostProcessCallback( vlc_object_t *, char const *, + vlc_value_t, vlc_value_t, void * ); +/* */ +static void DeinterlaceEnable( vout_thread_t * ); +static void DeinterlaceNeeded( vout_thread_t *, bool ); + /* From vout_intf.c */ int vout_Snapshot( vout_thread_t *, picture_t * ); @@ -174,17 +175,13 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, /* If we now have a video output, check it has the right properties */ if( p_vout ) { - char *psz_filter_chain; - vlc_value_t val; - vlc_mutex_lock( &p_vout->change_lock ); /* We don't directly check for the "vout-filter" variable for obvious * performance reasons. */ if( p_vout->p->b_filter_change ) { - var_Get( p_vout, "vout-filter", &val ); - psz_filter_chain = val.psz_string; + char *psz_filter_chain = var_GetString( p_vout, "vout-filter" ); if( psz_filter_chain && !*psz_filter_chain ) { @@ -205,7 +202,7 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, free( psz_filter_chain ); } - if( p_vout->fmt_render.i_chroma != p_fmt->i_chroma || + if( p_vout->fmt_render.i_chroma != vlc_fourcc_GetCodec( VIDEO_ES, p_fmt->i_chroma ) || p_vout->fmt_render.i_width != p_fmt->i_width || p_vout->fmt_render.i_height != p_fmt->i_height || p_vout->p->b_filter_change ) @@ -220,44 +217,37 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, else { /* This video output is cool! Hijack it. */ - if( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) - { - /* Correct aspect ratio on change - * FIXME factorize this code with other aspect ration related code */ - unsigned int i_sar_num; - unsigned int i_sar_den; - unsigned int i_aspect; - - i_aspect = p_fmt->i_aspect; - vlc_ureduce( &i_sar_num, &i_sar_den, - p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); + /* Correct aspect ratio on change + * FIXME factorize this code with other aspect ration related code */ + unsigned int i_sar_num; + unsigned int i_sar_den; + vlc_ureduce( &i_sar_num, &i_sar_den, + p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); #if 0 - /* What's that, it does not seems to be used correcly everywhere - * beside the previous p_vout->fmt_render.i_aspect != p_fmt->i_aspect - * should be fixed to use it too then */ - if( p_vout->i_par_num > 0 && p_vout->i_par_den > 0 ) - { - i_sar_num *= p_vout->i_par_den; - i_sar_den *= p_vout->i_par_num; - i_aspect = i_aspect * p_vout->i_par_den / p_vout->i_par_num; - } + /* What's that, it does not seems to be used correcly everywhere */ + if( p_vout->i_par_num > 0 && p_vout->i_par_den > 0 ) + { + i_sar_num *= p_vout->i_par_den; + i_sar_den *= p_vout->i_par_num; + } #endif - if( i_sar_num > 0 && i_sar_den > 0 && i_aspect > 0 ) - { - p_vout->fmt_in.i_sar_num = i_sar_num; - p_vout->fmt_in.i_sar_den = i_sar_den; - p_vout->fmt_in.i_aspect = i_aspect; - - p_vout->fmt_render.i_sar_num = i_sar_num; - p_vout->fmt_render.i_sar_den = i_sar_den; - p_vout->fmt_render.i_aspect = i_aspect; - - p_vout->render.i_aspect = i_aspect; - - p_vout->i_changes |= VOUT_ASPECT_CHANGE; - - } + if( i_sar_num > 0 && i_sar_den > 0 && + ( i_sar_num != p_vout->fmt_render.i_sar_num || + i_sar_den != p_vout->fmt_render.i_sar_den ) ) + { + p_vout->fmt_in.i_sar_num = i_sar_num; + p_vout->fmt_in.i_sar_den = i_sar_den; + + p_vout->fmt_render.i_sar_num = i_sar_num; + p_vout->fmt_render.i_sar_den = i_sar_den; + + p_vout->render.i_aspect = (int64_t)i_sar_num * + p_vout->fmt_render.i_width * + VOUT_ASPECT_FACTOR / + i_sar_den / + p_vout->fmt_render.i_height; + p_vout->i_changes |= VOUT_ASPECT_CHANGE; } vlc_mutex_unlock( &p_vout->change_lock ); @@ -268,10 +258,11 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, { msg_Dbg( p_this, "reusing provided vout" ); - spu_Attach( p_vout->p_spu, p_this, true ); - + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); vlc_object_detach( p_vout ); + vlc_object_attach( p_vout, p_this ); + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), true ); } } @@ -295,24 +286,28 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) { vout_thread_t * p_vout; /* thread descriptor */ int i_index; /* loop variable */ - vlc_value_t val, text; + vlc_value_t text; unsigned int i_width = p_fmt->i_width; unsigned int i_height = p_fmt->i_height; - vlc_fourcc_t i_chroma = p_fmt->i_chroma; - unsigned int i_aspect = p_fmt->i_aspect; + vlc_fourcc_t i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, p_fmt->i_chroma ); config_chain_t *p_cfg; char *psz_parser; char *psz_name; - if( i_width <= 0 || i_height <= 0 || i_aspect <= 0 ) + if( i_width <= 0 || i_height <= 0 ) return NULL; vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den, p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 ); if( p_fmt->i_sar_num <= 0 || p_fmt->i_sar_den <= 0 ) return NULL; + unsigned int i_aspect = (int64_t)p_fmt->i_sar_num * + i_width * + VOUT_ASPECT_FACTOR / + p_fmt->i_sar_den / + i_height; /* Allocate descriptor */ static const char typename[] = "video output"; @@ -380,8 +375,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) p_vout->i_alignment = 0; p_vout->p->render_time = 10; p_vout->p->c_fps_samples = 0; - p_vout->p->i_picture_lost = 0; - p_vout->p->i_picture_displayed = 0; + vout_statistic_Init( &p_vout->p->statistic ); p_vout->p->b_filter_change = 0; p_vout->p->b_paused = false; p_vout->p->i_pause_date = 0; @@ -392,6 +386,12 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) p_vout->p->i_picture_displayed_date = 0; p_vout->p->b_picture_displayed = false; p_vout->p->b_picture_empty = false; + p_vout->p->i_picture_qtype = QTYPE_NONE; + p_vout->p->b_picture_interlaced = false; + + vlc_mouse_Init( &p_vout->p->mouse ); + + vout_snapshot_Init( &p_vout->p->snapshot ); /* Initialize locks */ vlc_mutex_init( &p_vout->picture_lock ); @@ -408,13 +408,15 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Initialize subpicture unit */ p_vout->p_spu = spu_Create( p_vout ); - spu_Attach( p_vout->p_spu, p_parent, true ); /* Attach the new object now so we can use var inheritance below */ vlc_object_attach( p_vout, p_parent ); + /* */ spu_Init( p_vout->p_spu ); + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), true ); + /* Take care of some "interface/control" related initialisations */ vout_IntfInit( p_vout ); @@ -429,6 +431,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Apply video filter2 objects on the first vout */ p_vout->p->psz_vf2 = var_CreateGetStringCommand( p_vout, "video-filter" ); + + p_vout->p->b_first_vout = true; } else { @@ -447,6 +451,9 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) var_Create( p_vout, "video-filter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); p_vout->p->psz_vf2 = var_GetString( p_vout, "video-filter" ); + + /* */ + p_vout->p->b_first_vout = false; } var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL ); @@ -456,9 +463,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Choose the video output module */ if( !p_vout->p->psz_filter_chain || !*p_vout->p->psz_filter_chain ) { - var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - var_Get( p_vout, "vout", &val ); - psz_parser = val.psz_string; + psz_parser = NULL; } else { @@ -471,57 +476,34 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) free( psz_parser ); free( psz_tmp ); p_vout->p_cfg = p_cfg; - p_vout->p_module = module_need( p_vout, - ( p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ) ? - "video filter" : "video output", psz_name, p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ); - free( psz_name ); - - vlc_object_set_destructor( p_vout, vout_Destructor ); - - if( p_vout->p_module == NULL ) - { - msg_Err( p_vout, "no suitable vout module" ); - vlc_object_release( p_vout ); - return NULL; - } /* Create a few object variables for interface interaction */ - var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE ); - text.psz_string = _("Deinterlace"); - var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL ); - val.psz_string = (char *)""; text.psz_string = _("Disable"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"discard"; text.psz_string = _("Discard"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"blend"; text.psz_string = _("Blend"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"mean"; text.psz_string = _("Mean"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"bob"; text.psz_string = _("Bob"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"linear"; text.psz_string = _("Linear"); - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = (char *)"x"; text.psz_string = (char *)"X"; - var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - - if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS ) - { - var_Set( p_vout, "deinterlace", val ); - free( val.psz_string ); - } - var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); - var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); text.psz_string = _("Filters"); var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL ); var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL ); + /* */ + DeinterlaceEnable( p_vout ); + + if( p_vout->p->psz_filter_chain && *p_vout->p->psz_filter_chain ) + p_vout->p->psz_module_type = "video filter"; + else + p_vout->p->psz_module_type = "video output"; + p_vout->p->psz_module_name = psz_name; + p_vout->p_module = NULL; + + /* */ + vlc_object_set_destructor( p_vout, vout_Destructor ); + + /* */ vlc_cond_init( &p_vout->p->change_wait ); if( vlc_clone( &p_vout->p->thread, RunThread, p_vout, VLC_THREAD_PRIORITY_OUTPUT ) ) { - module_unneed( p_vout, p_vout->p_module ); - p_vout->p_module = NULL; + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); + spu_Destroy( p_vout->p_spu ); + p_vout->p_spu = NULL; vlc_object_release( p_vout ); return NULL; } @@ -561,9 +543,10 @@ void vout_Close( vout_thread_t *p_vout ) p_vout->p->b_done = true; vlc_cond_signal( &p_vout->p->change_wait ); vlc_mutex_unlock( &p_vout->change_lock ); + + vout_snapshot_End( &p_vout->p->snapshot ); + vlc_join( p_vout->p->thread, NULL ); - module_unneed( p_vout, p_vout->p_module ); - p_vout->p_module = NULL; } /* */ @@ -574,8 +557,11 @@ static void vout_Destructor( vlc_object_t * p_this ) /* Make sure the vout was stopped first */ assert( !p_vout->p_module ); + free( p_vout->p->psz_module_name ); + /* */ - spu_Destroy( p_vout->p_spu ); + if( p_vout->p_spu ) + spu_Destroy( p_vout->p_spu ); /* Destroy the locks */ vlc_cond_destroy( &p_vout->p->change_wait ); @@ -584,6 +570,13 @@ static void vout_Destructor( vlc_object_t * p_this ) vlc_mutex_destroy( &p_vout->change_lock ); vlc_mutex_destroy( &p_vout->p->vfilter_lock ); + /* */ + vout_statistic_Clean( &p_vout->p->statistic ); + + /* */ + vout_snapshot_Clean( &p_vout->p->snapshot ); + + /* */ free( p_vout->p->psz_filter_chain ); free( p_vout->p->psz_title ); @@ -591,21 +584,6 @@ static void vout_Destructor( vlc_object_t * p_this ) free( p_vout->p ); -#ifndef __APPLE__ - vout_thread_t *p_another_vout; - - /* This is a dirty hack mostly for Linux, where there is no way to get the - * GUI back if you closed it while playing video. This is solved in - * Mac OS X, where we have this novelty called menubar, that will always - * allow you access to the applications main functionality. They should try - * that on linux sometime. */ - p_another_vout = vlc_object_find( p_this->p_libvlc, - VLC_OBJECT_VOUT, FIND_ANYWHERE ); - if( p_another_vout == NULL ) - var_SetBool( p_this->p_libvlc, "intf-show", true ); - else - vlc_object_release( p_another_vout ); -#endif } /* */ @@ -647,15 +625,8 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_lost ) { - vlc_mutex_lock( &p_vout->change_lock ); - - *pi_displayed = p_vout->p->i_picture_displayed; - *pi_lost = p_vout->p->i_picture_lost; - - p_vout->p->i_picture_displayed = 0; - p_vout->p->i_picture_lost = 0; - - vlc_mutex_unlock( &p_vout->change_lock ); + vout_statistic_GetReset( &p_vout->p->statistic, + pi_displayed, pi_lost ); } void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) @@ -768,7 +739,7 @@ void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) { assert( psz_title ); - if( !config_GetInt( p_vout, "osd" ) ) + if( !var_InheritBool( p_vout, "osd" ) ) return; vlc_mutex_lock( &p_vout->change_lock ); @@ -777,6 +748,11 @@ void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) vlc_mutex_unlock( &p_vout->change_lock ); } +spu_t *vout_GetSpu( vout_thread_t *p_vout ) +{ + return p_vout->p_spu; +} + /***************************************************************************** * InitThread: initialize video output thread ***************************************************************************** @@ -793,10 +769,10 @@ static bool ChromaIsEqual( const picture_heap_t *p_output, const picture_heap_t if( !vout_ChromaCmp( p_output->i_chroma, p_render->i_chroma ) ) return false; - if( p_output->i_chroma != FOURCC_RV15 && - p_output->i_chroma != FOURCC_RV16 && - p_output->i_chroma != FOURCC_RV24 && - p_output->i_chroma != FOURCC_RV32 ) + if( p_output->i_chroma != VLC_CODEC_RGB15 && + p_output->i_chroma != VLC_CODEC_RGB16 && + p_output->i_chroma != VLC_CODEC_RGB24 && + p_output->i_chroma != VLC_CODEC_RGB32 ) return true; return p_output->i_rmask == p_render->i_rmask && @@ -806,7 +782,7 @@ static bool ChromaIsEqual( const picture_heap_t *p_output, const picture_heap_t static int InitThread( vout_thread_t *p_vout ) { - int i, i_aspect_x, i_aspect_y; + int i; /* Initialize output method, it allocates direct buffers for us */ if( p_vout->pf_init( p_vout ) ) @@ -832,30 +808,6 @@ static int InitThread( vout_thread_t *p_vout ) msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES ); - AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y ); - - msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), " - "chroma %4.4s, ar %i:%i, sar %i:%i", - p_vout->fmt_render.i_width, p_vout->fmt_render.i_height, - p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset, - p_vout->fmt_render.i_visible_width, - p_vout->fmt_render.i_visible_height, - (char*)&p_vout->fmt_render.i_chroma, - i_aspect_x, i_aspect_y, - p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den ); - - AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y ); - - msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), " - "chroma %4.4s, ar %i:%i, sar %i:%i", - p_vout->fmt_in.i_width, p_vout->fmt_in.i_height, - p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset, - p_vout->fmt_in.i_visible_width, - p_vout->fmt_in.i_visible_height, - (char*)&p_vout->fmt_in.i_chroma, - i_aspect_x, i_aspect_y, - p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den ); - if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height ) { p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width = @@ -864,12 +816,11 @@ static int InitThread( vout_thread_t *p_vout ) p_vout->output.i_height; p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0; - p_vout->fmt_out.i_aspect = p_vout->output.i_aspect; p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; } if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num ) { - p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect * + p_vout->fmt_out.i_sar_num = p_vout->output.i_aspect * p_vout->fmt_out.i_height; p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_vout->fmt_out.i_width; @@ -878,18 +829,6 @@ static int InitThread( vout_thread_t *p_vout ) vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den, p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 ); - AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y ); - - msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), " - "chroma %4.4s, ar %i:%i, sar %i:%i", - p_vout->fmt_out.i_width, p_vout->fmt_out.i_height, - p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset, - p_vout->fmt_out.i_visible_width, - p_vout->fmt_out.i_visible_height, - (char*)&p_vout->fmt_out.i_chroma, - i_aspect_x, i_aspect_y, - p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den ); - /* FIXME removed the need of both fmt_* and heap infos */ /* Calculate shifts from system-updated masks */ PictureHeapFixRgb( &p_vout->render ); @@ -898,6 +837,35 @@ static int InitThread( vout_thread_t *p_vout ) PictureHeapFixRgb( &p_vout->output ); VideoFormatImportRgb( &p_vout->fmt_out, &p_vout->output ); + /* print some usefull debug info about different vout formats + */ + msg_Dbg( p_vout, "pic render sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", + p_vout->fmt_render.i_width, p_vout->fmt_render.i_height, + p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset, + p_vout->fmt_render.i_visible_width, + p_vout->fmt_render.i_visible_height, + (char*)&p_vout->fmt_render.i_chroma, + p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den, + p_vout->fmt_render.i_rmask, p_vout->fmt_render.i_gmask, p_vout->fmt_render.i_bmask ); + + msg_Dbg( p_vout, "pic in sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", + p_vout->fmt_in.i_width, p_vout->fmt_in.i_height, + p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset, + p_vout->fmt_in.i_visible_width, + p_vout->fmt_in.i_visible_height, + (char*)&p_vout->fmt_in.i_chroma, + p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den, + p_vout->fmt_in.i_rmask, p_vout->fmt_in.i_gmask, p_vout->fmt_in.i_bmask ); + + msg_Dbg( p_vout, "pic out sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, sar %i:%i, msk r0x%x g0x%x b0x%x", + p_vout->fmt_out.i_width, p_vout->fmt_out.i_height, + p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset, + p_vout->fmt_out.i_visible_width, + p_vout->fmt_out.i_visible_height, + (char*)&p_vout->fmt_out.i_chroma, + p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, + p_vout->fmt_out.i_rmask, p_vout->fmt_out.i_gmask, p_vout->fmt_out.i_bmask ); + /* Check whether we managed to create direct buffers similar to * the render buffers, ie same size and chroma */ if( ( p_vout->output.i_width == p_vout->render.i_width ) @@ -958,17 +926,6 @@ static int InitThread( vout_thread_t *p_vout ) } } - /* Link pictures back to their heap */ - for( i = 0 ; i < I_RENDERPICTURES ; i++ ) - { - PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render; - } - - for( i = 0 ; i < I_OUTPUTPICTURES ; i++ ) - { - PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output; - } - return VLC_SUCCESS; } @@ -983,27 +940,35 @@ static void* RunThread( void *p_this ) { vout_thread_t *p_vout = p_this; int i_idle_loops = 0; /* loops without displaying a picture */ - - bool b_drop_late; + int i_picture_qtype_last = QTYPE_NONE; + bool b_picture_interlaced_last = false; + mtime_t i_picture_interlaced_last_date; /* * Initialize thread */ + p_vout->p_module = module_need( p_vout, + p_vout->p->psz_module_type, + p_vout->p->psz_module_name, + !strcmp(p_vout->p->psz_module_type, "video filter") ); + vlc_mutex_lock( &p_vout->change_lock ); - p_vout->b_error = InitThread( p_vout ); - b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); + if( p_vout->p_module ) + p_vout->b_error = InitThread( p_vout ); + else + p_vout->b_error = true; /* signal the creation of the vout */ p_vout->p->b_ready = true; vlc_cond_signal( &p_vout->p->change_wait ); if( p_vout->b_error ) - { - EndThread( p_vout ); - vlc_mutex_unlock( &p_vout->change_lock ); - return NULL; - } + goto exit_thread; + + /* */ + const bool b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); + i_picture_interlaced_last_date = mdate(); /* * Main loop - it is not executed if an error occurred during @@ -1050,10 +1015,10 @@ static void* RunThread( void *p_this ) /* Picture is late: it will be destroyed and the thread * will directly choose the next picture */ vout_UsePictureLocked( p_vout, p_pic ); - p_vout->p->i_picture_lost++; + vout_statistic_Update( &p_vout->p->statistic, 0, 1 ); - msg_Warn( p_vout, "late picture skipped (%"PRId64")", - current_date - p_pic->date ); + msg_Warn( p_vout, "late picture skipped (%"PRId64" > %d)", + current_date - p_pic->date, - p_vout->p->render_time ); } else if( ( !p_last || p_last->date < p_pic->date ) && ( p_picture == NULL || p_pic->date < p_picture->date ) ) @@ -1131,6 +1096,14 @@ static void* RunThread( void *p_this ) p_vout->p->p_picture_displayed = p_picture; } } + + /* */ + const int i_postproc_type = p_vout->p->i_picture_qtype; + const int i_postproc_state = (p_vout->p->i_picture_qtype != QTYPE_NONE) - (i_picture_qtype_last != QTYPE_NONE); + + const bool b_picture_interlaced = p_vout->p->b_picture_interlaced; + const int i_picture_interlaced_state = (!!p_vout->p->b_picture_interlaced) - (!!b_picture_interlaced_last); + vlc_mutex_unlock( &p_vout->picture_lock ); if( p_picture == NULL ) @@ -1141,35 +1114,36 @@ static void* RunThread( void *p_this ) p_filtered_picture = filter_chain_VideoFilter( p_vout->p->p_vf2_chain, p_picture ); - /* FIXME it is ugly that b_snapshot is not locked but I do not - * know which lock to use (here and in the snapshot callback) */ - const bool b_snapshot = p_vout->p->b_snapshot && p_picture != NULL; + const bool b_snapshot = vout_snapshot_IsRequested( &p_vout->p->snapshot ); /* * Check for subpictures to display */ - subpicture_t *p_subpic = NULL; - if( display_date > 0 ) - p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date, - p_vout->p->b_paused, b_snapshot ); + mtime_t spu_render_time; + if( p_vout->p->b_paused ) + spu_render_time = p_vout->p->i_pause_date; + else if( p_picture ) + spu_render_time = p_picture->date > 1 ? p_picture->date : mdate(); + else + spu_render_time = 0; + subpicture_t *p_subpic = spu_SortSubpictures( p_vout->p_spu, + spu_render_time, + b_snapshot ); /* * Perform rendering */ - p_vout->p->i_picture_displayed++; - p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture, - p_subpic, p_vout->p->b_paused ); + vout_statistic_Update( &p_vout->p->statistic, 1, 0 ); + p_directbuffer = vout_RenderPicture( p_vout, + p_filtered_picture, p_subpic, + spu_render_time ); /* * Take a snapshot if requested */ if( p_directbuffer && b_snapshot ) - { - /* FIXME lock (see b_snapshot) */ - p_vout->p->b_snapshot = false; - - vout_Snapshot( p_vout, p_directbuffer ); - } + vout_snapshot_Set( &p_vout->p->snapshot, + &p_vout->fmt_out, p_directbuffer ); /* * Call the plugin-specific rendering method if there is one @@ -1196,6 +1170,9 @@ static void* RunThread( void *p_this ) p_vout->p->render_time += current_render_time; p_vout->p->render_time >>= 2; } + else + msg_Dbg( p_vout, "skipped big render time %d > %d", (int) current_render_time, + (int) (p_vout->p->render_time +VOUT_DISPLAY_DELAY ) ) ; } /* Give back change lock */ @@ -1301,7 +1278,7 @@ static void* RunThread( void *p_this ) if( p_vout->pf_init( p_vout ) ) { msg_Err( p_vout, "cannot resize display" ); - /* FIXME: pf_end will be called again in EndThread() */ + /* FIXME: pf_end will be called again in CleanThread()? */ p_vout->b_error = 1; } @@ -1349,6 +1326,26 @@ static void* RunThread( void *p_this ) break; } + /* Post processing */ + if( i_postproc_state == 1 ) + PostProcessEnable( p_vout ); + else if( i_postproc_state == -1 ) + PostProcessDisable( p_vout ); + if( i_postproc_state != 0 ) + i_picture_qtype_last = i_postproc_type; + + /* Deinterlacing + * Wait 30s before quiting interlacing mode */ + if( ( i_picture_interlaced_state == 1 ) || + ( i_picture_interlaced_state == -1 && i_picture_interlaced_last_date + 30000000 < current_date ) ) + { + DeinterlaceNeeded( p_vout, b_picture_interlaced ); + b_picture_interlaced_last = b_picture_interlaced; + } + if( b_picture_interlaced ) + i_picture_interlaced_last_date = current_date; + + /* Check for "video filter2" changes */ vlc_mutex_lock( &p_vout->p->vfilter_lock ); if( p_vout->p->psz_vf2 ) @@ -1365,6 +1362,9 @@ static void* RunThread( void *p_this ) free( p_vout->p->psz_vf2 ); p_vout->p->psz_vf2 = NULL; + + if( i_picture_qtype_last != QTYPE_NONE ) + PostProcessSetFilterQuality( p_vout ); } vlc_mutex_unlock( &p_vout->p->vfilter_lock ); } @@ -1375,11 +1375,18 @@ static void* RunThread( void *p_this ) if( p_vout->b_error ) ErrorThread( p_vout ); - /* End of thread */ + /* Clean thread */ CleanThread( p_vout ); + +exit_thread: + /* End of thread */ EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); + if( p_vout->p_module ) + module_unneed( p_vout, p_vout->p_module ); + p_vout->p_module = NULL; + return NULL; } @@ -1434,16 +1441,6 @@ static void CleanThread( vout_thread_t *p_vout ) *****************************************************************************/ static void EndThread( vout_thread_t *p_vout ) { -#ifdef STATS - { - struct tms cpu_usage; - times( &cpu_usage ); - - msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)", - cpu_usage.tms_utime, cpu_usage.tms_stime ); - } -#endif - /* FIXME does that function *really* need to be called inside the thread ? */ /* Detach subpicture unit from both input and vout */ @@ -1513,47 +1510,6 @@ static void ChromaDestroy( vout_thread_t *p_vout ) } /* following functions are local */ -static int ReduceHeight( int i_ratio ) -{ - int i_dummy = VOUT_ASPECT_FACTOR; - int i_pgcd = 1; - - if( !i_ratio ) - { - return i_pgcd; - } - - /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */ - while( !(i_ratio & 1) && !(i_dummy & 1) ) - { - i_ratio >>= 1; - i_dummy >>= 1; - i_pgcd <<= 1; - } - - while( !(i_ratio % 3) && !(i_dummy % 3) ) - { - i_ratio /= 3; - i_dummy /= 3; - i_pgcd *= 3; - } - - while( !(i_ratio % 5) && !(i_dummy % 5) ) - { - i_ratio /= 5; - i_dummy /= 5; - i_pgcd *= 5; - } - - return i_pgcd; -} - -static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y ) -{ - unsigned int i_pgcd = ReduceHeight( i_aspect ); - *i_aspect_x = i_aspect / i_pgcd; - *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd; -} /** * This function copies all RGB informations from a picture_heap_t into @@ -1610,75 +1566,11 @@ static void PictureHeapFixRgb( picture_heap_t *p_heap ) * object variables callbacks: a bunch of object variables are used by the * interfaces to interact with the vout. *****************************************************************************/ -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; - input_thread_t *p_input; - vlc_value_t val; - - char *psz_mode = newval.psz_string; - char *psz_filter, *psz_deinterlace = NULL; - (void)psz_cmd; (void)oldval; (void)p_data; - - var_Get( p_vout, "vout-filter", &val ); - psz_filter = val.psz_string; - if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" ); - - if( !psz_mode || !*psz_mode ) - { - if( psz_deinterlace ) - { - char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1; - if( psz_src[0] == ':' ) psz_src++; - memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 ); - } - } - else if( !psz_deinterlace ) - { - psz_filter = realloc( psz_filter, strlen( psz_filter ) + - sizeof(":deinterlace") ); - if( psz_filter ) - { - if( *psz_filter ) - strcat( psz_filter, ":" ); - strcat( psz_filter, "deinterlace" ); - } - } - - p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, - FIND_PARENT ); - if( !p_input ) - { - free( psz_filter ); - return VLC_EGENERIC; - } - - if( psz_mode && *psz_mode ) - { - /* Modify input as well because the vout might have to be restarted */ - val.psz_string = psz_mode; - var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING ); - var_Set( p_input, "deinterlace-mode", val ); - } - vlc_object_release( p_input ); - - val.b_bool = true; - var_Set( p_vout, "intf-change", val ); - - val.psz_string = psz_filter; - var_Set( p_vout, "vout-filter", val ); - free( psz_filter ); - - return VLC_SUCCESS; -} - static int FilterCallback( 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; input_thread_t *p_input; - vlc_value_t val; (void)psz_cmd; (void)oldval; (void)p_data; p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, @@ -1686,17 +1578,14 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, if (!p_input) { msg_Err( p_vout, "Input not found" ); - return( VLC_EGENERIC ); + return VLC_EGENERIC; } - val.b_bool = true; - var_Set( p_vout, "intf-change", val ); + var_SetBool( p_vout, "intf-change", true ); /* Modify input as well because the vout might have to be restarted */ - val.psz_string = newval.psz_string; var_Create( p_input, "vout-filter", VLC_VAR_STRING ); - - var_Set( p_input, "vout-filter", val ); + var_SetString( p_input, "vout-filter", newval.psz_string ); /* Now restart current video stream */ input_Control( p_input, INPUT_RESTART_ES, -VIDEO_ES ); @@ -1721,11 +1610,121 @@ 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( psz_vf2 ) + { + var_SetString( p_vout, "video-filter", psz_vf2 ); + free( psz_vf2 ); + } + + 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 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, @@ -1742,3 +1741,293 @@ static void DisplayTitleOnOSD( vout_thread_t *p_vout ) p_vout->p->psz_title = NULL; } +/***************************************************************************** + * Deinterlacing + *****************************************************************************/ +typedef struct +{ + const char *psz_mode; + 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[] = { + { "", false }, + { "discard", true }, + { "blend", false }, + { "mean", true }, + { "bob", true }, + { "linear", true }, + { "x", false }, + { "yadif", true }, + { "yadif2x", true }, + { 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 void DeinterlaceSave( vout_thread_t *p_vout, int i_deinterlace, const char *psz_mode, bool is_needed ) +{ + /* 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 */ + vlc_object_t *p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT ); + if( !p_input ) + return; + + /* Another hack for "vout filter" mode */ + if( i_deinterlace < 0 ) + i_deinterlace = is_needed ? -2 : -3; + + var_Create( p_input, "deinterlace", VLC_VAR_INTEGER ); + var_SetInteger( p_input, "deinterlace", i_deinterlace ); + + static const char * const ppsz_variable[] = { + "deinterlace-mode", + "filter-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 ) + return VLC_EGENERIC; + + DeinterlaceSave( p_vout, i_deinterlace, psz_mode, is_needed ); + + /* */ + bool b_vout_filter = true; + for( const deinterlace_mode_t *p_mode = &p_deinterlace_mode[0]; p_mode->psz_mode; p_mode++ ) + { + if( !strcmp( p_mode->psz_mode, psz_mode ) ) + { + b_vout_filter = p_mode->b_vout_filter; + break; + } + } + + /* */ + char *psz_old; + if( b_vout_filter ) + { + psz_old = var_CreateGetString( p_vout, "filter-deinterlace-mode" ); + } + else + { + psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" ); + var_SetString( p_vout, "sout-deinterlace-mode", psz_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, false ); + DeinterlaceRemove( p_vout, true ); + } + else + { + if( !DeinterlaceIsPresent( p_vout, b_vout_filter ) ) + { + DeinterlaceRemove( p_vout, !b_vout_filter ); + DeinterlaceAdd( p_vout, b_vout_filter ); + } + else + { + /* The deinterlace filter was already inserted but we have changed the mode */ + DeinterlaceRemove( p_vout, !b_vout_filter ); + if( psz_old && strcmp( psz_old, psz_mode ) ) + var_TriggerCallback( p_vout, b_vout_filter ? "vout-filter" : "video-filter" ); + } + } + + /* */ + free( psz_old ); + free( psz_mode ); + return VLC_SUCCESS; +} + +static void DeinterlaceEnable( vout_thread_t *p_vout ) +{ + vlc_value_t val, text; + + if( !p_vout->p->b_first_vout ) + return; + + 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++ ) + { + 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, true ) ) + psz_filter_mode = var_CreateGetNonEmptyString( p_vout, "filter-deinterlace-mode" ); + else if( DeinterlaceIsPresent( p_vout, false ) ) + 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 == -2 ) + p_vout->p->b_picture_interlaced = true; + else if( i_deinterlace == -3 ) + p_vout->p->b_picture_interlaced = false; + 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 = p_vout->p->b_picture_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 ); +} +