X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=34e6c2afbd2753197dee183111d8a230aaae9f6c;hb=b2fa8fea83dd007cb7612c93fb7f698035a462c8;hp=ae354e7c1b8edc7337115ee8a16f552ecfbbce75;hpb=acf420dbd2a8e2dbd82c39d580325708500099d7;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index ae354e7c1b..34e6c2afbd 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -92,8 +92,27 @@ int vout_Snapshot( vout_thread_t *, picture_t * ); /* Display media title in OSD */ static void DisplayTitleOnOSD( vout_thread_t *p_vout ); -/* */ -static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ); +/* Time during which the thread will sleep if it has nothing to + * display (in micro-seconds) */ +#define VOUT_IDLE_SLEEP ((int)(0.020*CLOCK_FREQ)) + +/* Maximum lap of time allowed between the beginning of rendering and + * display. If, compared to the current date, the next image is too + * late, the thread will perform an idle loop. This time should be + * at least VOUT_IDLE_SLEEP plus the time required to render a few + * images, to avoid trashing of decoded images */ +#define VOUT_DISPLAY_DELAY ((int)(0.200*CLOCK_FREQ)) + +/* Better be in advance when awakening than late... */ +#define VOUT_MWAIT_TOLERANCE ((mtime_t)(0.020*CLOCK_FREQ)) + +/* Minimum number of direct pictures the video output will accept without + * creating additional pictures in system memory */ +#ifdef OPTIMIZE_MEMORY +# define VOUT_MIN_DIRECT_PICTURES (VOUT_MAX_PICTURES/2) +#else +# define VOUT_MIN_DIRECT_PICTURES (3*VOUT_MAX_PICTURES/4) +#endif /***************************************************************************** * Video Filter2 functions @@ -112,7 +131,9 @@ static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ) { vout_thread_t *p_vout = (vout_thread_t*)p_filter->p_owner; - DropPicture( p_vout, p_pic ); + vlc_mutex_lock( &p_vout->picture_lock ); + vout_UsePictureLocked( p_vout, p_pic ); + vlc_mutex_unlock( &p_vout->picture_lock ); } static int video_filter_buffer_allocation_init( filter_t *p_filter, void *p_data ) @@ -132,7 +153,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. @@ -252,11 +272,6 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, 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 ); } } @@ -373,9 +388,14 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) 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; /* Initialize locks */ - vlc_mutex_init_recursive( &p_vout->picture_lock ); + vlc_mutex_init( &p_vout->picture_lock ); + vlc_cond_init( &p_vout->p->picture_wait ); vlc_mutex_init( &p_vout->change_lock ); vlc_mutex_init( &p_vout->p->vfilter_lock ); @@ -547,11 +567,13 @@ static void vout_Destructor( vlc_object_t * p_this ) spu_Destroy( p_vout->p_spu ); /* Destroy the locks */ + 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 ); free( p_vout->p->psz_filter_chain ); + free( p_vout->p->psz_title ); config_ChainDestroy( p_vout->p_cfg ); @@ -580,6 +602,11 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) vlc_object_lock( p_vout ); assert( !p_vout->p->b_paused || !b_paused ); + + vlc_mutex_lock( &p_vout->picture_lock ); + + p_vout->p->i_picture_displayed_date = 0; + if( p_vout->p->b_paused ) { const mtime_t i_duration = i_date - p_vout->p->i_pause_date; @@ -591,8 +618,15 @@ void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date ) if( p_pic->i_status == READY_PICTURE ) p_pic->date += i_duration; } + vlc_cond_signal( &p_vout->p->picture_wait ); + vlc_mutex_unlock( &p_vout->picture_lock ); + spu_OffsetSubtitleDate( p_vout->p_spu, i_duration ); } + else + { + vlc_mutex_unlock( &p_vout->picture_lock ); + } p_vout->p->b_paused = b_paused; p_vout->p->i_pause_date = i_date; @@ -613,6 +647,7 @@ void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_l void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) { vlc_mutex_lock( &p_vout->picture_lock ); + p_vout->p->i_picture_displayed_date = 0; for( int i = 0; i < p_vout->render.i_pictures; i++ ) { picture_t *p_pic = p_vout->render.pp_picture[i]; @@ -626,15 +661,16 @@ void vout_Flush( vout_thread_t *p_vout, mtime_t i_date ) p_pic->date = 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 ) +void vout_FixLeaks( vout_thread_t *p_vout, bool b_forced ) { int i_pic, i_ready_pic; vlc_mutex_lock( &p_vout->picture_lock ); - for( i_pic = 0, i_ready_pic = 0; i_pic < p_vout->render.i_pictures; i_pic++ ) + for( i_pic = 0, i_ready_pic = 0; i_pic < p_vout->render.i_pictures && !b_forced; i_pic++ ) { const picture_t *p_pic = p_vout->render.pp_picture[i_pic]; @@ -657,7 +693,7 @@ void vout_FixLeaks( vout_thread_t *p_vout ) break; } } - if( i_pic < p_vout->render.i_pictures ) + if( i_pic < p_vout->render.i_pictures && !b_forced ) { vlc_mutex_unlock( &p_vout->picture_lock ); return; @@ -665,20 +701,56 @@ void vout_FixLeaks( vout_thread_t *p_vout ) /* Too many pictures are still referenced, there is probably a bug * with the decoder */ - msg_Err( p_vout, "pictures leaked, resetting the heap" ); + if( !b_forced ) + msg_Err( p_vout, "pictures leaked, resetting the heap" ); /* Just free all the pictures */ for( i_pic = 0; i_pic < p_vout->render.i_pictures; i_pic++ ) { picture_t *p_pic = p_vout->render.pp_picture[i_pic]; - if( p_pic->i_status == RESERVED_PICTURE ) - vout_DestroyPicture( p_vout, p_pic ); - if( p_pic->i_refcount > 0 ) - vout_UnlinkPicture( p_vout, p_pic ); + 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 ); } + vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); } +void vout_NextPicture( vout_thread_t *p_vout, mtime_t *pi_duration ) +{ + vlc_mutex_lock( &p_vout->picture_lock ); + + const mtime_t i_displayed_date = p_vout->p->i_picture_displayed_date; + + p_vout->p->b_picture_displayed = false; + p_vout->p->b_picture_empty = false; + if( p_vout->p->p_picture_displayed ) + { + p_vout->p->p_picture_displayed->date = 1; + vlc_cond_signal( &p_vout->p->picture_wait ); + } + + while( !p_vout->p->b_picture_displayed && !p_vout->p->b_picture_empty ) + vlc_cond_wait( &p_vout->p->picture_wait, &p_vout->picture_lock ); + + *pi_duration = __MAX( p_vout->p->i_picture_displayed_date - i_displayed_date, 0 ); + + /* TODO advance subpicture by the 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_object_lock( p_vout ); + free( p_vout->p->psz_title ); + p_vout->p->psz_title = strdup( psz_title ); + vlc_object_unlock( p_vout ); +} /***************************************************************************** * InitThread: initialize video output thread @@ -715,6 +787,8 @@ static int InitThread( vout_thread_t *p_vout ) if( p_vout->pf_init( p_vout ) ) return VLC_EGENERIC; + p_vout->p->p_picture_displayed = NULL; + if( !I_OUTPUTPICTURES ) { msg_Err( p_vout, "plugin was unable to allocate at least " @@ -885,10 +959,6 @@ static void* RunThread( vlc_object_t *p_this ) vout_thread_t *p_vout = (vout_thread_t *)p_this; int i_idle_loops = 0; /* loops without displaying a picture */ - picture_t * p_last_picture = NULL; /* last picture */ - - subpicture_t * p_subpic = NULL; /* subpicture pointer */ - bool b_drop_late; int canc = vlc_savecancel(); @@ -914,9 +984,6 @@ static void* RunThread( vlc_object_t *p_this ) 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 @@ -925,99 +992,81 @@ static void* RunThread( vlc_object_t *p_this ) { /* Initialize loop variables */ const mtime_t current_date = mdate(); - picture_t *p_picture = NULL; + picture_t *p_picture; picture_t *p_filtered_picture; - mtime_t display_date = 0; + mtime_t display_date; picture_t *p_directbuffer; int i_index; - /* Find the picture to display (the one with the earliest date). */ + 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 */ + picture_t *p_last = p_vout->p->p_picture_displayed;; + + p_picture = NULL; for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) { picture_t *p_pic = PP_RENDERPICTURE[i_index]; - if( p_pic->i_status == READY_PICTURE && - ( p_picture == NULL || p_pic->date < display_date ) ) + if( p_pic->i_status != READY_PICTURE ) + continue; + + if( p_vout->p->b_paused && p_last && p_last->date > 1 ) + continue; + + if( p_last && p_pic != p_last && p_pic->date <= p_last->date ) + { + /* Drop old picture */ + vout_UsePictureLocked( p_vout, p_pic ); + } + else if( !p_vout->p->b_paused && !p_pic->b_force && p_pic != p_last && + p_pic->date < current_date + p_vout->p->render_time && + b_drop_late ) + { + /* 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++; + + msg_Warn( p_vout, "late picture skipped (%"PRId64")", + current_date - p_pic->date ); + } + else if( ( !p_last || p_last->date < p_pic->date ) && + ( p_picture == NULL || p_pic->date < p_picture->date ) ) { p_picture = p_pic; - display_date = p_picture->date; } } - if( p_vout->p->b_paused && p_last_picture != NULL ) + if( !p_picture ) { - p_picture = NULL; - if( p_last_picture->date == 1 ) - { - for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) - { - picture_t *p_pic = PP_RENDERPICTURE[i_index]; + p_picture = p_last; - if( p_pic->i_status != READY_PICTURE ) - continue; - if( p_pic->date <= p_last_picture->date && p_pic != p_last_picture ) - { - DropPicture( p_vout, p_pic ); - } - else if( p_pic->date > p_last_picture->date && ( p_picture == NULL || p_pic->date < display_date ) ) - { - p_picture = p_pic; - display_date = p_picture->date; - } - } + if( !p_vout->p->b_picture_empty ) + { + p_vout->p->b_picture_empty = true; + vlc_cond_signal( &p_vout->p->picture_wait ); } - if( !p_picture ) - p_picture = p_last_picture; } + display_date = 0; if( p_picture ) { - /* If we met the last picture, parse again to see whether there is - * a more appropriate one. */ - if( p_picture == p_last_picture && !p_vout->p->b_paused ) - { - for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) - { - picture_t *p_pic = PP_RENDERPICTURE[i_index]; - - if( p_pic->i_status == READY_PICTURE && - p_pic != p_last_picture && - ( p_picture == p_last_picture || p_pic->date < display_date ) ) - { - p_picture = p_pic; - display_date = p_picture->date; - } - } - } + display_date = p_picture->date; /* If we found better than the last picture, destroy it */ - if( p_last_picture && p_picture != p_last_picture ) + if( p_last && p_picture != p_last ) { - DropPicture( p_vout, p_last_picture ); - p_last_picture = NULL; + vout_UsePictureLocked( p_vout, p_last ); + p_vout->p->p_picture_displayed = p_last = NULL; } /* Compute FPS rate */ - p_vout->p->p_fps_sample[ p_vout->p->c_fps_samples++ % VOUT_FPS_SAMPLES ] - = display_date; + p_vout->p->p_fps_sample[ p_vout->p->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date; - if( !p_picture->b_force && - p_picture != p_last_picture && - display_date < current_date + p_vout->p->render_time && - b_drop_late ) - { - /* Picture is late: it will be destroyed and the thread - * will directly choose the next picture */ - DropPicture( p_vout, p_picture ); - p_vout->p->i_picture_lost++; - msg_Warn( p_vout, "late picture skipped (%"PRId64")", - current_date - display_date ); - vlc_mutex_unlock( &p_vout->picture_lock ); - continue; - } - - if( display_date > current_date + VOUT_DISPLAY_DELAY ) + if( !p_vout->p->b_paused && display_date > current_date + VOUT_DISPLAY_DELAY ) { /* A picture is ready to be rendered, but its rendering date * is far from the current one so the thread will perform an @@ -1026,7 +1075,7 @@ static void* RunThread( vlc_object_t *p_this ) p_picture = NULL; display_date = 0; } - else if( p_picture == p_last_picture ) + else if( p_picture == p_last ) { /* We are asked to repeat the previous picture, but we first * wait for a couple of idle loops */ @@ -1042,6 +1091,24 @@ static void* RunThread( vlc_object_t *p_this ) display_date = current_date + p_vout->p->render_time; } } + else if( p_vout->p->b_paused && display_date > current_date + VOUT_DISPLAY_DELAY ) + { + display_date = current_date + VOUT_DISPLAY_DELAY; + } + + if( p_picture ) + { + if( p_picture->date > 1 ) + { + p_vout->p->i_picture_displayed_date = p_picture->date; + if( p_picture != p_last && !p_vout->p->b_picture_displayed ) + { + p_vout->p->b_picture_displayed = true; + vlc_cond_signal( &p_vout->p->picture_wait ); + } + } + p_vout->p->p_picture_displayed = p_picture; + } } vlc_mutex_unlock( &p_vout->picture_lock ); @@ -1053,15 +1120,14 @@ 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 a bit ugly that b_snapshot is not locked but I do not + /* 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; - if( b_snapshot ) - p_vout->p->b_snapshot = false; + const bool b_snapshot = p_vout->p->b_snapshot && p_picture != NULL; /* * 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 ); @@ -1077,7 +1143,12 @@ static void* RunThread( vlc_object_t *p_this ) * 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 ); + } /* * Call the plugin-specific rendering method if there is one @@ -1114,7 +1185,7 @@ static void* RunThread( vlc_object_t *p_this ) /* Sleep a while or until a given date */ if( display_date != 0 ) { - /* If there are filters in the chain, better give them the picture + /* If there are *vout* filters in the chain, better give them the picture * in advance */ if( !p_vout->p->psz_filter_chain || !*p_vout->p->psz_filter_chain ) { @@ -1123,7 +1194,10 @@ static void* RunThread( vlc_object_t *p_this ) } else { - msleep( VOUT_IDLE_SLEEP ); + /* 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 ); } /* On awakening, take back lock and send immediately picture @@ -1144,13 +1218,16 @@ static void* RunThread( vlc_object_t *p_this ) /* Tell the vout this was the last picture and that it does not * need to be forced anymore. */ - p_last_picture = p_picture; - p_last_picture->b_force = false; + p_picture->b_force = false; } /* Drop the filtered picture if created by video filters */ if( p_filtered_picture != NULL && p_filtered_picture != p_picture ) - DropPicture( p_vout, p_filtered_picture ); + { + vlc_mutex_lock( &p_vout->picture_lock ); + vout_UsePictureLocked( p_vout, p_filtered_picture ); + vlc_mutex_unlock( &p_vout->picture_lock ); + } if( p_picture != NULL ) { @@ -1189,8 +1266,10 @@ static void* RunThread( vlc_object_t *p_this ) p_vout->pf_end( p_vout ); + p_vout->p->p_picture_displayed = NULL; for( i = 0; i < I_OUTPUTPICTURES; i++ ) p_vout->p_picture[ i ].i_status = FREE_PICTURE; + vlc_cond_signal( &p_vout->p->picture_wait ); I_OUTPUTPICTURES = 0; @@ -1238,6 +1317,7 @@ static void* RunThread( vlc_object_t *p_this ) if( p_vout->b_error ) msg_Err( p_vout, "InitThread after VOUT_PICTURE_BUFFERS_CHANGE failed\n" ); + vlc_cond_signal( &p_vout->p->picture_wait ); vlc_mutex_unlock( &p_vout->picture_lock ); if( p_vout->b_error ) @@ -1343,8 +1423,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 ); @@ -1376,7 +1457,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 ) { @@ -1408,29 +1489,7 @@ static void ChromaDestroy( vout_thread_t *p_vout ) p_vout->p->p_chroma = NULL; } -static void DropPicture( vout_thread_t *p_vout, picture_t *p_picture ) -{ - vlc_mutex_lock( &p_vout->picture_lock ); - if( p_picture->i_refcount ) - { - /* Pretend we displayed the picture, but don't destroy - * it since the decoder might still need it. */ - p_picture->i_status = DISPLAYED_PICTURE; - } - else - { - /* Destroy the picture without displaying it */ - p_picture->i_status = DESTROYED_PICTURE; - p_vout->i_heap_size--; - picture_CleanupQuant( p_picture ); - } - vlc_mutex_unlock( &p_vout->picture_lock ); -} - - - /* following functions are local */ - static int ReduceHeight( int i_ratio ) { int i_dummy = VOUT_ASPECT_FACTOR; @@ -1556,13 +1615,21 @@ static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, { psz_filter = realloc( psz_filter, strlen( psz_filter ) + sizeof(":deinterlace") ); - if( psz_filter && *psz_filter ) strcat( psz_filter, ":" ); - strcat( psz_filter, "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 ) return VLC_EGENERIC; + if( !p_input ) + { + free( psz_filter ); + return VLC_EGENERIC; + } if( psz_mode && *psz_mode ) { @@ -1633,68 +1700,22 @@ static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd, static void DisplayTitleOnOSD( vout_thread_t *p_vout ) { - input_thread_t *p_input; - mtime_t i_now, i_stop; + const mtime_t i_start = mdate(); + const mtime_t i_stop = i_start + INT64_C(1000) * p_vout->p->i_title_timeout; - if( !config_GetInt( p_vout, "osd" ) ) return; + vlc_object_assert_locked( p_vout ); - p_input = (input_thread_t *)vlc_object_find( p_vout, - VLC_OBJECT_INPUT, FIND_ANYWHERE ); - if( p_input ) - { - 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 ) ) - { - 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 ); - } - else if( !EMPTY_STR( psz_artist ) ) - { - char *psz_string = NULL; - if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 ) - { - 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 ); - } - } - 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 ); - } - vlc_object_release( p_input ); - free( psz_artist ); - free( psz_name ); - free( psz_nowplaying ); - } + 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; }