X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=691e144064b91334005ed7e8fe141e0cfae6d92e;hb=a7a12139a54c29083e6b73f6fde96c7f673482df;hp=bf4ba431e92be8a69254ea4d6930b7845c0d8934;hpb=db4b1b44bf969f3db9b17e31d48efed60b5154cd;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index bf4ba431e9..691e144064 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -66,7 +66,7 @@ * Local prototypes *****************************************************************************/ static int InitThread ( vout_thread_t * ); -static void* RunThread ( vlc_object_t * ); +static void* RunThread ( void * ); static void ErrorThread ( vout_thread_t * ); static void CleanThread ( vout_thread_t * ); static void EndThread ( vout_thread_t * ); @@ -79,13 +79,20 @@ 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 * ); + /* From vout_intf.c */ int vout_Snapshot( vout_thread_t *, picture_t * ); @@ -153,7 +160,6 @@ static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, video_format_t *p_fmt ) { - const bool b_vout_provided = p_vout != NULL; if( !p_fmt ) { /* Video output is no longer used. @@ -175,17 +181,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 ) { @@ -206,7 +208,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 ) @@ -269,15 +271,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 ); - /* Display title if we are not using the vout given to vout_Request. - * XXX for now b_vout_provided is always true at this stage */ - if( p_vout->p->b_title_show && !b_vout_provided ) - DisplayTitleOnOSD( p_vout ); + vlc_object_attach( p_vout, p_this ); + spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), true ); } } @@ -301,11 +299,11 @@ 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; + vlc_fourcc_t i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, p_fmt->i_chroma ); unsigned int i_aspect = p_fmt->i_aspect; config_chain_t *p_cfg; @@ -380,7 +378,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Initialize misc stuff */ p_vout->i_changes = 0; - p_vout->b_scale = 1; + p_vout->b_autoscale = 1; + p_vout->i_zoom = ZOOM_FP_FACTOR; p_vout->b_fullscreen = 0; p_vout->i_alignment = 0; p_vout->p->render_time = 10; @@ -391,13 +390,15 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) p_vout->p->b_paused = false; p_vout->p->i_pause_date = 0; p_vout->pf_control = NULL; - p_vout->p_window = NULL; p_vout->p->i_par_num = p_vout->p->i_par_den = 1; p_vout->p->p_picture_displayed = NULL; 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; + + vout_snapshot_Init( &p_vout->p->snapshot ); /* Initialize locks */ vlc_mutex_init( &p_vout->picture_lock ); @@ -410,23 +411,25 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL ); - var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER ); + var_Create( p_vout, "mouse-clicked", VLC_VAR_BOOL ); /* 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 ); /* If the parent is not a VOUT object, that means we are at the start of * the video output pipe */ - if( p_parent->i_object_type != VLC_OBJECT_VOUT ) + if( vlc_internals( p_parent )->i_object_type != VLC_OBJECT_VOUT ) { /* Look for the default filter configuration */ p_vout->p->psz_filter_chain = @@ -435,6 +438,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 { @@ -453,6 +458,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 ); @@ -462,9 +470,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 = var_CreateGetString( p_vout, "vout" ); } else { @@ -482,56 +488,49 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) "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_set_destructor( p_vout, vout_Destructor ); + 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; } /* 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 ); - if( vlc_thread_create( p_vout, "video output", RunThread, - VLC_THREAD_PRIORITY_OUTPUT, true ) ) + /* */ + DeinterlaceEnable( p_vout ); + + /* */ + 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; - vlc_object_set_destructor( p_vout, vout_Destructor ); + 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; } - vlc_object_set_destructor( p_vout, vout_Destructor ); + vlc_mutex_lock( &p_vout->change_lock ); + while( !p_vout->p->b_ready ) + { /* We are (ab)using the same condition in opposite directions for + * b_ready and b_done. This works because of the strict ordering. */ + assert( !p_vout->p->b_done ); + vlc_cond_wait( &p_vout->p->change_wait, &p_vout->change_lock ); + } + vlc_mutex_unlock( &p_vout->change_lock ); if( p_vout->b_error ) { @@ -549,14 +548,20 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) * You HAVE to call it on vout created by vout_Create before vlc_object_release. * You should NEVER call it on vout not obtained through vout_Create * (like with vout_Request or vlc_object_find.) - * You can use vout_CloseAndRelease() as a convenient method. + * You can use vout_CloseAndRelease() as a convenience method. *****************************************************************************/ void vout_Close( vout_thread_t *p_vout ) { assert( p_vout ); - vlc_object_kill( p_vout ); - vlc_thread_join( p_vout ); + vlc_mutex_lock( &p_vout->change_lock ); + 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; } @@ -570,15 +575,22 @@ static void vout_Destructor( vlc_object_t * p_this ) assert( !p_vout->p_module ); /* */ - 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 ); vlc_cond_destroy( &p_vout->p->picture_wait ); vlc_mutex_destroy( &p_vout->picture_lock ); vlc_mutex_destroy( &p_vout->change_lock ); vlc_mutex_destroy( &p_vout->p->vfilter_lock ); + /* */ + vout_snapshot_Clean( &p_vout->p->snapshot ); + + /* */ free( p_vout->p->psz_filter_chain ); + free( p_vout->p->psz_title ); config_ChainDestroy( p_vout->p_cfg ); @@ -604,7 +616,7 @@ static void vout_Destructor( vlc_object_t * p_this ) /* */ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) { - vlc_object_lock( p_vout ); + vlc_mutex_lock( &p_vout->change_lock ); assert( !p_vout->p->b_paused || !b_paused ); @@ -635,11 +647,12 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) p_vout->p->b_paused = b_paused; p_vout->p->i_pause_date = i_date; - vlc_object_unlock( p_vout ); + vlc_mutex_unlock( &p_vout->change_lock ); } + void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_lost ) { - vlc_object_lock( p_vout ); + vlc_mutex_lock( &p_vout->change_lock ); *pi_displayed = p_vout->p->i_picture_displayed; *pi_lost = p_vout->p->i_picture_lost; @@ -647,8 +660,9 @@ void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_l p_vout->p->i_picture_displayed = 0; p_vout->p->i_picture_lost = 0; - vlc_object_unlock( p_vout ); + vlc_mutex_unlock( &p_vout->change_lock ); } + void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) { vlc_mutex_lock( &p_vout->picture_lock ); @@ -669,6 +683,7 @@ void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); } + void vout_FixLeaks( vout_thread_t *p_vout, bool b_forced ) { int i_pic, i_ready_pic; @@ -716,7 +731,16 @@ void vout_FixLeaks( vout_thread_t *p_vout, bool b_forced ) msg_Dbg( p_vout, "[%d] %d %d", i_pic, p_pic->i_status, p_pic->i_refcount ); p_pic->i_refcount = 0; - vout_UsePictureLocked( p_vout, p_pic ); + + switch( p_pic->i_status ) + { + case READY_PICTURE: + case DISPLAYED_PICTURE: + case RESERVED_PICTURE: + if( p_pic != p_vout->p->p_picture_displayed ) + vout_UsePictureLocked( p_vout, p_pic ); + break; + } } vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); @@ -745,6 +769,24 @@ void vout_NextPicture( vout_thread_t *p_vout, mtime_t *pi_duration ) vlc_mutex_unlock( &p_vout->picture_lock ); } +void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title ) +{ + assert( psz_title ); + + if( !config_GetInt( p_vout, "osd" ) ) + return; + + vlc_mutex_lock( &p_vout->change_lock ); + free( p_vout->p->psz_title ); + p_vout->p->psz_title = strdup( 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 ***************************************************************************** @@ -761,10 +803,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 && @@ -802,28 +844,8 @@ static int InitThread( vout_thread_t *p_vout ) 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 = @@ -848,16 +870,6 @@ static int InitThread( vout_thread_t *p_vout ) 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 ); @@ -866,6 +878,38 @@ 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, ar %i:%i, 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, + i_aspect_x, i_aspect_y, + 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, ar %i:%i, 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, + i_aspect_x, i_aspect_y, + 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, ar %i:%i, 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, + i_aspect_x, i_aspect_y, + 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 ) @@ -926,17 +970,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; } @@ -947,15 +980,14 @@ static int InitThread( vout_thread_t *p_vout ) * terminated. It handles the pictures arriving in the video heap and the * display device events. *****************************************************************************/ -static void* RunThread( vlc_object_t *p_this ) +static void* RunThread( void *p_this ) { - vout_thread_t *p_vout = (vout_thread_t *)p_this; + vout_thread_t *p_vout = p_this; int i_idle_loops = 0; /* loops without displaying a picture */ + int i_picture_qtype_last = QTYPE_NONE; bool b_drop_late; - int canc = vlc_savecancel(); - /* * Initialize thread */ @@ -965,26 +997,21 @@ static void* RunThread( vlc_object_t *p_this ) b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" ); /* signal the creation of the vout */ - vlc_thread_ready( p_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 ); - vlc_restorecancel( canc ); return NULL; } - vlc_object_lock( p_vout ); - - if( p_vout->p->b_title_show ) - DisplayTitleOnOSD( p_vout ); - /* * Main loop - it is not executed if an error occurred during * initialization */ - while( vlc_object_alive( p_vout ) && !p_vout->b_error ) + while( !p_vout->p->b_done && !p_vout->b_error ) { /* Initialize loop variables */ const mtime_t current_date = mdate(); @@ -994,6 +1021,9 @@ static void* RunThread( vlc_object_t *p_this ) picture_t *p_directbuffer; int i_index; + if( p_vout->p->b_title_show && p_vout->p->psz_title ) + DisplayTitleOnOSD( p_vout ); + vlc_mutex_lock( &p_vout->picture_lock ); /* Look for the earliest picture but after the last displayed one */ @@ -1024,8 +1054,8 @@ static void* RunThread( vlc_object_t *p_this ) vout_UsePictureLocked( p_vout, p_pic ); p_vout->p->i_picture_lost++; - 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 ) ) @@ -1103,6 +1133,11 @@ static void* RunThread( vlc_object_t *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); + vlc_mutex_unlock( &p_vout->picture_lock ); if( p_picture == NULL ) @@ -1113,35 +1148,36 @@ static void* RunThread( vlc_object_t *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 ); + 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 @@ -1168,13 +1204,14 @@ static void* RunThread( vlc_object_t *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 */ vlc_mutex_unlock( &p_vout->change_lock ); - vlc_object_unlock( p_vout ); - /* Sleep a while or until a given date */ if( display_date != 0 ) { @@ -1187,7 +1224,7 @@ static void* RunThread( vlc_object_t *p_this ) } else { - /* Wait until a frame is being sent or a supurious wakeup (not a problem here) */ + /* Wait until a frame is being sent or a spurious wakeup (not a problem here) */ vlc_mutex_lock( &p_vout->picture_lock ); vlc_cond_timedwait( &p_vout->p->picture_wait, &p_vout->picture_lock, current_date + VOUT_IDLE_SLEEP ); vlc_mutex_unlock( &p_vout->picture_lock ); @@ -1195,9 +1232,7 @@ static void* RunThread( vlc_object_t *p_this ) /* On awakening, take back lock and send immediately picture * to display. */ - vlc_object_lock( p_vout ); - /* Note: vlc_object_alive() could be false here, and we - * could be dead */ + /* Note: p_vout->p->b_done could be true here and now */ vlc_mutex_lock( &p_vout->change_lock ); /* @@ -1241,6 +1276,14 @@ static void* RunThread( vlc_object_t *p_this ) break; } + while( p_vout->i_changes & VOUT_ON_TOP_CHANGE ) + { + p_vout->i_changes &= ~VOUT_ON_TOP_CHANGE; + vlc_mutex_unlock( &p_vout->change_lock ); + vout_Control( p_vout, VOUT_SET_STAY_ON_TOP, p_vout->b_on_top ); + vlc_mutex_lock( &p_vout->change_lock ); + } + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) { /* this must only happen when the vout plugin is incapable of @@ -1308,7 +1351,7 @@ static void* RunThread( vlc_object_t *p_this ) p_vout->b_error = InitThread( p_vout ); if( p_vout->b_error ) - msg_Err( p_vout, "InitThread after VOUT_PICTURE_BUFFERS_CHANGE failed\n" ); + msg_Err( p_vout, "InitThread after VOUT_PICTURE_BUFFERS_CHANGE failed" ); vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); @@ -1317,6 +1360,14 @@ static void* RunThread( vlc_object_t *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; + /* Check for "video filter2" changes */ vlc_mutex_lock( &p_vout->p->vfilter_lock ); if( p_vout->p->psz_vf2 ) @@ -1333,6 +1384,9 @@ static void* RunThread( vlc_object_t *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 ); } @@ -1348,8 +1402,6 @@ static void* RunThread( vlc_object_t *p_this ) EndThread( p_vout ); vlc_mutex_unlock( &p_vout->change_lock ); - vlc_object_unlock( p_vout ); - vlc_restorecancel( canc ); return NULL; } @@ -1362,9 +1414,9 @@ static void* RunThread( vlc_object_t *p_this ) *****************************************************************************/ static void ErrorThread( vout_thread_t *p_vout ) { - /* Wait until a `die' order */ - while( vlc_object_alive( p_vout ) ) - vlc_object_wait( p_vout ); + /* Wait until a `close' order */ + while( !p_vout->p->b_done ) + vlc_cond_wait( &p_vout->p->change_wait, &p_vout->change_lock ); } /***************************************************************************** @@ -1416,8 +1468,9 @@ static void EndThread( vout_thread_t *p_vout ) /* FIXME does that function *really* need to be called inside the thread ? */ - /* Destroy subpicture unit */ + /* Detach subpicture unit from both input and vout */ spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), false ); + vlc_object_detach( p_vout->p_spu ); /* Destroy the video filters2 */ filter_chain_Delete( p_vout->p->p_vf2_chain ); @@ -1449,7 +1502,7 @@ static int ChromaCreate( vout_thread_t *p_vout ) VideoFormatImportRgb( &p_chroma->fmt_in.video, &p_vout->render ); VideoFormatImportRgb( &p_chroma->fmt_out.video, &p_vout->output ); - p_chroma->p_module = module_need( p_chroma, "video filter2", NULL, 0 ); + p_chroma->p_module = module_need( p_chroma, "video filter2", NULL, false ); if( p_chroma->p_module == NULL ) { @@ -1482,44 +1535,9 @@ 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 ); + const int i_pgcd = i_aspect ? GCD( i_aspect, VOUT_ASPECT_FACTOR ) : 1; *i_aspect_x = i_aspect / i_pgcd; *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd; } @@ -1579,75 +1597,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, @@ -1655,17 +1609,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 ); @@ -1690,70 +1641,352 @@ static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd, return VLC_SUCCESS; } -static void DisplayTitleOnOSD( vout_thread_t *p_vout ) +/***************************************************************************** + * Post-processing + *****************************************************************************/ +static bool PostProcessIsPresent( const char *psz_filter ) { - input_thread_t *p_input; - mtime_t i_now, i_stop; + 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] == ':' ); +} - if( !config_GetInt( p_vout, "osd" ) ) return; +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); - p_input = (input_thread_t *)vlc_object_find( p_vout, - VLC_OBJECT_INPUT, FIND_ANYWHERE ); - if( p_input ) + static const char *psz_pp = "postproc"; + + char *psz_vf2 = var_GetString( p_vout, "video-filter" ); + + if( newval.i_int <= 0 ) { - i_now = mdate(); - i_stop = i_now + (mtime_t)(p_vout->p->i_title_timeout * 1000); - char *psz_nowplaying = - input_item_GetNowPlaying( input_GetItem( p_input ) ); - char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) ); - char *psz_name = input_item_GetTitle( input_GetItem( p_input ) ); - if( EMPTY_STR( psz_name ) ) - { - free( psz_name ); - psz_name = input_item_GetName( input_GetItem( p_input ) ); - } - if( !EMPTY_STR( psz_nowplaying ) ) + if( PostProcessIsPresent( psz_vf2 ) ) { - vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, - psz_nowplaying, 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_now, i_stop ); + strcpy( psz_vf2, &psz_vf2[strlen(psz_pp)] ); + if( *psz_vf2 == ':' ) + strcpy( psz_vf2, &psz_vf2[1] ); } - else if( !EMPTY_STR( psz_artist ) ) + } + else + { + if( !PostProcessIsPresent( psz_vf2 ) ) { - char *psz_string = NULL; - if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 ) + 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 { - vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, - psz_string, 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_now, i_stop ); - free( psz_string ); + 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 - { - vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, - psz_name, 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_now, i_stop ); - } + 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 ); + vlc_object_release( p_input ); - free( psz_artist ); - free( psz_name ); - free( psz_nowplaying ); } + + char *psz_old; + + if( p_mode->b_vout_filter ) + { + psz_old = var_CreateGetString( p_vout, "deinterlace-mode" ); + } + else + { + psz_old = var_CreateGetString( p_vout, "sout-deinterlace-mode" ); + var_SetString( p_vout, "sout-deinterlace-mode", p_mode->psz_mode ); + } + + /* */ + if( !strcmp( p_mode->psz_mode, "" ) ) + { + DeinterlaceRemove( p_vout, false ); + DeinterlaceRemove( p_vout, true ); + } + else if( !DeinterlaceIsPresent( p_vout, p_mode->b_vout_filter ) ) + { + DeinterlaceRemove( p_vout, !p_mode->b_vout_filter ); + DeinterlaceAdd( p_vout, p_mode->b_vout_filter ); + } + else + { + DeinterlaceRemove( p_vout, !p_mode->b_vout_filter ); + if( psz_old && strcmp( psz_old, p_mode->psz_mode ) ) + var_TriggerCallback( p_vout, p_mode->b_vout_filter ? "vout-filter" : "video-filter" ); + } + free( psz_old ); + + (void)psz_cmd; (void) oldval; (void) p_data; + 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 variable */ + 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 ); + + for( int i = 0; p_deinterlace_mode[i].psz_mode; i++ ) + { + val.psz_string = (char*)p_deinterlace_mode[i].psz_mode; + text.psz_string = (char*)vlc_gettext(p_deinterlace_mode[i].psz_description); + var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); + } + var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL ); + + /* */ + char *psz_mode = NULL; + if( var_Type( p_vout, "vout-deinterlace" ) != 0 ) + psz_mode = var_CreateGetNonEmptyString( p_vout, "vout-deinterlace" ); + if( !psz_mode ) + { + /* Get the initial value */ + if( DeinterlaceIsPresent( p_vout, true ) ) + psz_mode = var_CreateGetNonEmptyString( p_vout, "deinterlace-mode" ); + else if( DeinterlaceIsPresent( p_vout, false ) ) + psz_mode = var_CreateGetNonEmptyString( p_vout, "sout-deinterlace-mode" ); + } + var_SetString( p_vout, "deinterlace", psz_mode ? psz_mode : "" ); + free( psz_mode ); }