X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=81efa98f591bc51f8e0b8bcdf23ff27948275b6f;hb=fa8dccb4c748f99ecfc2da40f59e4f99b9b0c143;hp=2c2909fffb0093578616ae058c10b12f17b8563f;hpb=3a6b3918c3b8c2ef6b0bc0c2a8216f846b2dc176;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 2c2909fffb..81efa98f59 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -5,7 +5,7 @@ * It includes functions allowing to open a new thread, send pictures to a * thread, and destroy a previously oppened video output thread. ***************************************************************************** - * Copyright (C) 2000-2004 the VideoLAN team + * Copyright (C) 2000-2007 the VideoLAN team * $Id$ * * Authors: Vincent Seguin @@ -29,6 +29,10 @@ /***************************************************************************** * Preamble *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include /* free() */ @@ -53,6 +57,8 @@ * helpers */ #include "input/input_internal.h" +#include "modules/modules.h" + /***************************************************************************** * Local prototypes *****************************************************************************/ @@ -66,6 +72,8 @@ static void AspectRatio ( int, int *, int * ); static int BinaryLog ( uint32_t ); static void MaskToShift ( int *, int *, uint32_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 * ); @@ -81,6 +89,9 @@ int vout_Snapshot( vout_thread_t *, picture_t * ); static int ParseVideoFilter2Chain( vout_thread_t *, char * ); static void RemoveVideoFilters2( vout_thread_t *p_vout ); +/* Display media title in OSD */ +static void DisplayTitleOnOSD( vout_thread_t *p_vout ); + /***************************************************************************** * Video Filter2 functions *****************************************************************************/ @@ -118,11 +129,9 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, /* Reattach video output to playlist before bailing out */ if( p_vout ) { - playlist_t *p_playlist = pl_Yield( p_this ); spu_Attach( p_vout->p_spu, p_this, VLC_FALSE ); vlc_object_detach( p_vout ); - vlc_object_attach( p_vout, p_playlist ); - pl_Release( p_this ); + vlc_object_attach( p_vout, p_this->p_libvlc ); } return NULL; } @@ -138,18 +147,16 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, if( !p_vout ) { - playlist_t *p_playlist = pl_Yield( p_this ); - vlc_mutex_lock( &p_playlist->gc_lock ); - p_vout = vlc_object_find( p_playlist, + p_vout = vlc_object_find( p_this->p_libvlc, VLC_OBJECT_VOUT, FIND_CHILD ); /* only first children of p_input for unused vout */ - if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist ) + if( p_vout && p_vout->p_parent != VLC_OBJECT(p_this->p_libvlc) ) { vlc_object_release( p_vout ); p_vout = NULL; } - vlc_mutex_unlock( &p_playlist->gc_lock ); - pl_Release( p_this ); + if( p_vout ) + vlc_object_detach( p_vout ); /* Remove it from the GC */ } } @@ -182,17 +189,15 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, p_vout->b_filter_change = VLC_FALSE; } - if( psz_filter_chain ) free( psz_filter_chain ); + free( psz_filter_chain ); } if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) || ( p_vout->fmt_render.i_height != p_fmt->i_height ) || - ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) || ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) || p_vout->b_filter_change ) { /* We are not interested in this format, close this vout */ - vlc_object_detach( p_vout ); vlc_object_release( p_vout ); vout_Destroy( p_vout ); p_vout = NULL; @@ -200,9 +205,10 @@ vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout, else { /* This video output is cool! Hijack it. */ - vlc_object_detach( p_vout ); spu_Attach( p_vout->p_spu, p_this, VLC_TRUE ); vlc_object_attach( p_vout, p_this ); + if( p_vout->b_title_show ) + DisplayTitleOnOSD( p_vout ); vlc_object_release( p_vout ); } } @@ -228,7 +234,6 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) vout_thread_t * p_vout; /* thread descriptor */ input_thread_t * p_input_thread; int i_index; /* loop variable */ - char * psz_plugin; vlc_value_t val, text; unsigned int i_width = p_fmt->i_width; @@ -236,6 +241,10 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) vlc_fourcc_t i_chroma = p_fmt->i_chroma; unsigned int i_aspect = p_fmt->i_aspect; + config_chain_t *p_cfg; + char *psz_parser; + char *psz_name; + /* Allocate descriptor */ p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT ); if( p_vout == NULL ) @@ -308,6 +317,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) /* Initialize locks */ vlc_mutex_init( p_vout, &p_vout->picture_lock ); vlc_mutex_init( p_vout, &p_vout->change_lock ); + vlc_mutex_init( p_vout, &p_vout->vfilter_lock ); /* Mouse coordinates */ var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER ); @@ -347,12 +357,15 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) else { /* continue the parent's filter chain */ - char *psz_end; + char *psz_tmp; - psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' ); - if( psz_end && *(psz_end+1) ) - p_vout->psz_filter_chain = strdup( psz_end+1 ); - else p_vout->psz_filter_chain = NULL; + /* Ugly hack to jump to our configuration chain */ + p_vout->psz_filter_chain + = ((vout_thread_t *)p_parent)->psz_filter_chain; + p_vout->psz_filter_chain + = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain ); + config_ChainDestroy( p_cfg ); + free( psz_tmp ); /* Create a video filter2 var ... but don't inherit values */ var_Create( p_vout, "video-filter", VLC_VAR_STRING ); @@ -368,32 +381,27 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) { var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_vout, "vout", &val ); - psz_plugin = val.psz_string; + psz_parser = val.psz_string; } else { - /* the filter chain is a string list of filters separated by double - * colons */ - char *psz_end; - - psz_end = strchr( p_vout->psz_filter_chain, ':' ); - if( psz_end ) - psz_plugin = strndup( p_vout->psz_filter_chain, - psz_end - p_vout->psz_filter_chain ); - else psz_plugin = strdup( p_vout->psz_filter_chain ); + psz_parser = strdup( p_vout->psz_filter_chain ); } /* Create the vout thread */ + config_ChainCreate( &psz_name, &p_cfg, psz_parser ); + free( psz_parser ); + p_vout->p_cfg = p_cfg; p_vout->p_module = module_Need( p_vout, ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ? - "video filter" : "video output", psz_plugin, 0 ); + "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain ); + free( psz_name ); - if( psz_plugin ) free( psz_plugin ); if( p_vout->p_module == NULL ) { msg_Err( p_vout, "no suitable vout module" ); vlc_object_detach( p_vout ); - vlc_object_destroy( p_vout ); + vlc_object_release( p_vout ); return NULL; } @@ -401,29 +409,28 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) 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 = ""; text.psz_string = _("Disable"); + val.psz_string = (char *)""; text.psz_string = _("Disable"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "discard"; text.psz_string = _("Discard"); + val.psz_string = (char *)"discard"; text.psz_string = _("Discard"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "blend"; text.psz_string = _("Blend"); + val.psz_string = (char *)"blend"; text.psz_string = _("Blend"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "mean"; text.psz_string = _("Mean"); + val.psz_string = (char *)"mean"; text.psz_string = _("Mean"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "bob"; text.psz_string = _("Bob"); + val.psz_string = (char *)"bob"; text.psz_string = _("Bob"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "linear"; text.psz_string = _("Linear"); + val.psz_string = (char *)"linear"; text.psz_string = _("Linear"); var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text ); - val.psz_string = "x"; text.psz_string = "X"; + 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 ); - if( val.psz_string ) free( val.psz_string ); + 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 ); @@ -447,8 +454,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) { msg_Err( p_vout, "out of memory" ); module_Unneed( p_vout, p_vout->p_module ); - vlc_object_detach( p_vout ); - vlc_object_destroy( p_vout ); + vlc_object_release( p_vout ); return NULL; } @@ -457,15 +463,12 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) msg_Err( p_vout, "video output creation failed" ); /* Make sure the thread is destroyed */ - p_vout->b_die = VLC_TRUE; - - vlc_thread_join( p_vout ); - - vlc_object_detach( p_vout ); - vlc_object_destroy( p_vout ); + vlc_object_release( p_vout ); return NULL; } + vlc_object_set_destructor( p_vout, vout_Destructor ); + return p_vout; } @@ -479,25 +482,29 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) *****************************************************************************/ void vout_Destroy( vout_thread_t *p_vout ) { - vout_thread_t *p_another_vout; - playlist_t *p_playlist = pl_Yield( p_vout ); + /* XXX: should go in the destructor */ + var_Destroy( p_vout, "intf-change" ); - /* Request thread destruction */ - p_vout->b_die = VLC_TRUE; - vlc_thread_join( p_vout ); + vlc_object_release( p_vout ); +} - var_Destroy( p_vout, "intf-change" ); +static void vout_Destructor( vlc_object_t * p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; - if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain ); + free( p_vout->psz_filter_chain ); + + config_ChainDestroy( p_vout->p_cfg ); - /* Free structure */ - vlc_object_destroy( p_vout ); #ifndef __APPLE__ + vout_thread_t *p_another_vout; + playlist_t *p_playlist = pl_Yield( p_vout ); + /* This is a dirty hack for mostly 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_playlist, + p_another_vout = vlc_object_find( p_this->p_libvlc, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_another_vout == NULL ) { @@ -509,8 +516,8 @@ void vout_Destroy( vout_thread_t *p_vout ) { vlc_object_release( p_another_vout ); } -#endif vlc_object_release( p_playlist ); +#endif } /***************************************************************************** @@ -751,6 +758,9 @@ static void RunThread( vout_thread_t *p_vout) return; } + if( p_vout->b_title_show ) + DisplayTitleOnOSD( p_vout ); + /* * Main loop - it is not executed if an error occurred during * initialization @@ -769,8 +779,6 @@ static void RunThread( vout_thread_t *p_vout) } i_loops++; - if( i_loops % 20 == 0 ) - { if( !p_input ) { p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, @@ -787,7 +795,6 @@ static void RunThread( vout_thread_t *p_vout) i_displayed = i_lost = 0; vlc_mutex_unlock( &p_input->p->counters.counters_lock ); } - } #if 0 p_vout->c_loops++; if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) ) @@ -942,6 +949,7 @@ static void RunThread( vout_thread_t *p_vout) if( p_vout->b_vfilter_change == VLC_TRUE ) { int i; + vlc_mutex_lock( &p_vout->vfilter_lock ); RemoveVideoFilters2( p_vout ); for( i = 0; i < p_vout->i_vfilters_cfg; i++ ) { @@ -968,7 +976,8 @@ static void RunThread( vout_thread_t *p_vout) p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i]; p_vfilter->p_module = module_Need( p_vfilter, "video filter2", - p_vout->psz_vfilters[i], 0 ); + p_vout->psz_vfilters[i], + VLC_TRUE ); if( p_vfilter->p_module ) { @@ -984,10 +993,11 @@ static void RunThread( vout_thread_t *p_vout) msg_Err( p_vout, "no video filter found (%s)", p_vout->psz_vfilters[i] ); vlc_object_detach( p_vfilter ); - vlc_object_destroy( p_vfilter ); + vlc_object_release( p_vfilter ); } } p_vout->b_vfilter_change = VLC_FALSE; + vlc_mutex_unlock( &p_vout->vfilter_lock ); } if( p_picture ) @@ -1284,6 +1294,7 @@ static void DestroyThread( vout_thread_t *p_vout ) /* Destroy the locks */ vlc_mutex_destroy( &p_vout->picture_lock ); vlc_mutex_destroy( &p_vout->change_lock ); + vlc_mutex_destroy( &p_vout->vfilter_lock ); /* Release the module */ if( p_vout && p_vout->p_module ) @@ -1392,11 +1403,12 @@ static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask ) * vout_VarCallback: generic callback for intf variables *****************************************************************************/ int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable, - vlc_value_t old_value, vlc_value_t new_value, - void * unused ) + vlc_value_t oldval, vlc_value_t newval, + void *p_data ) { vout_thread_t * p_vout = (vout_thread_t *)p_this; vlc_value_t val; + (void)psz_variable; (void)newval; (void)oldval; (void)p_data; val.b_bool = VLC_TRUE; var_Set( p_vout, "intf-change", val ); return VLC_SUCCESS; @@ -1431,11 +1443,7 @@ static void SuxorRestartVideoES( suxor_thread_t *p_this ) vlc_object_release( p_this->p_input ); -#ifdef WIN32 - CloseHandle( p_this->thread_id ); -#endif - - vlc_object_destroy( p_this ); + vlc_object_release( p_this ); } /***************************************************************************** @@ -1451,6 +1459,7 @@ static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, 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; @@ -1491,7 +1500,7 @@ static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd, val.psz_string = psz_filter; var_Set( p_vout, "vout-filter", val ); - if( psz_filter ) free( psz_filter ); + free( psz_filter ); return VLC_SUCCESS; } @@ -1502,6 +1511,7 @@ static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, 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, FIND_PARENT ); @@ -1550,6 +1560,7 @@ static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters ) p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg]; config_ChainDestroy( p_cfg ); free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] ); + p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL; } p_vout->i_vfilters_cfg = 0; if( psz_vfilters && *psz_vfilters ) @@ -1565,7 +1576,7 @@ static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters ) msg_Dbg( p_vout, "adding vfilter: %s", p_vout->psz_vfilters[p_vout->i_vfilters_cfg] ); p_vout->i_vfilters_cfg++; - if( psz_parser && psz_parser ) + if( psz_parser && *psz_parser ) { if( p_vout->i_vfilters_cfg == MAX_VFILTERS ) { @@ -1584,9 +1595,12 @@ static int VideoFilter2Callback( 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; + (void)psz_cmd; (void)oldval; (void)p_data; + vlc_mutex_lock( &p_vout->vfilter_lock ); ParseVideoFilter2Chain( p_vout, newval.psz_string ); p_vout->b_vfilter_change = VLC_TRUE; + vlc_mutex_unlock( &p_vout->vfilter_lock ); return VLC_SUCCESS; } @@ -1604,7 +1618,73 @@ static void RemoveVideoFilters2( vout_thread_t *p_vout ) } free( p_vout->pp_vfilters[i]->p_owner ); - vlc_object_destroy( p_vout->pp_vfilters[i] ); + vlc_object_release( p_vout->pp_vfilters[i] ); } p_vout->i_vfilters = 0; } + +static void DisplayTitleOnOSD( vout_thread_t *p_vout ) +{ + input_thread_t *p_input; + mtime_t i_now, i_stop; + + 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->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->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->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->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 ); + } +} +