X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out.c;h=8940e046c60640e2673099d2953b3a7c07583862;hb=426932330da5ef5182008c6331fe504870c57ce8;hp=3efc3661afb0cb771dd14beea4ac75529ab99362;hpb=327782b2b7ba8666e5533ea584224df6e356af6b;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index 3efc3661af..8940e046c6 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -25,9 +25,13 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include +#include +#include #include #include @@ -35,9 +39,12 @@ #include #include "input_internal.h" +#include "input_clock.h" +#include "input_decoder.h" + +#include "../stream_output/stream_output.h" -#include "vlc_playlist.h" -#include "iso_lang.h" +#include /* FIXME we should find a better way than including that */ #include "../text/iso-639_def.h" @@ -52,10 +59,10 @@ typedef struct /* Number of es for this pgrm */ int i_es; - vlc_bool_t b_selected; + bool b_selected; /* Clock for this program */ - input_clock_t clock; + input_clock_t *p_clock; char *psz_name; char *psz_now_playing; @@ -70,9 +77,6 @@ struct es_out_id_t int i_id; es_out_pgrm_t *p_pgrm; - /* Misc. */ - int64_t i_preroll_end; - /* Channel in the track type */ int i_channel; es_format_t fmt; @@ -80,9 +84,10 @@ struct es_out_id_t char *psz_language_code; decoder_t *p_dec; + decoder_t *p_dec_record; /* Fields for Video with CC */ - vlc_bool_t pb_cc_present[4]; + bool pb_cc_present[4]; es_out_id_t *pp_cc_es[4]; /* Field for CC track from a master video */ @@ -105,7 +110,7 @@ struct es_out_sys_t es_out_id_t **es; /* mode gestion */ - vlc_bool_t b_active; + bool b_active; int i_mode; /* es count */ @@ -128,19 +133,35 @@ struct es_out_sys_t /* delay */ int64_t i_audio_delay; int64_t i_spu_delay; + + /* Rate used for clock */ + int i_rate; + + /* Current preroll */ + int64_t i_preroll_end; + + /* Used for buffering */ + bool b_buffering; + + /* Record */ + sout_instance_t *p_sout_record; }; static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * ); static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * ); static void EsOutDel ( es_out_t *, es_out_id_t * ); -static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ); +static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force ); static int EsOutControl( es_out_t *, int i_query, va_list ); static void EsOutAddInfo( es_out_t *, es_out_id_t *es ); -static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es ); +static bool EsIsSelected( es_out_id_t *es ); static void EsSelect( es_out_t *out, es_out_id_t *es ); -static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ); +static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update ); +static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es ); +static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date ); +static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date ); +static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced ); static char *LanguageGetName( const char *psz_code ); static char *LanguageGetCode( const char *psz_lang ); static char **LanguageSplit( const char *psz_langs ); @@ -169,23 +190,31 @@ static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc ) /***************************************************************************** * input_EsOutNew: *****************************************************************************/ -es_out_t *input_EsOutNew( input_thread_t *p_input ) +es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate ) { - es_out_t *out = malloc( sizeof( es_out_t ) ); - es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) ); vlc_value_t val; int i; + es_out_t *out = malloc( sizeof( es_out_t ) ); + if( !out ) return NULL; + + es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) ); + if( !p_sys ) + { + free( out ); + return NULL; + } + out->pf_add = EsOutAdd; out->pf_send = EsOutSend; out->pf_del = EsOutDel; out->pf_control = EsOutControl; out->p_sys = p_sys; - out->b_sout = (p_input->p->p_sout != NULL ? VLC_TRUE : VLC_FALSE); + out->b_sout = p_input->p->p_sout != NULL; p_sys->p_input = p_input; - p_sys->b_active = VLC_FALSE; + p_sys->b_active = false; p_sys->i_mode = ES_OUT_MODE_AUTO; @@ -219,7 +248,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) msg_Dbg( p_input, "selected audio language[%d] %s", i, p_sys->ppsz_audio_language[i] ); } - if( val.psz_string ) free( val.psz_string ); + free( val.psz_string ); var_Get( p_input, "sub-language", &val ); p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); @@ -229,7 +258,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) msg_Dbg( p_input, "selected subtitle language[%d] %s", i, p_sys->ppsz_sub_language[i] ); } - if( val.psz_string ) free( val.psz_string ); + free( val.psz_string ); } else { @@ -250,6 +279,13 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) p_sys->i_audio_delay= 0; p_sys->i_spu_delay = 0; + p_sys->i_rate = i_rate; + + p_sys->b_buffering = true; + p_sys->i_preroll_end = -1; + + p_sys->p_sout_record = NULL; + return out; } @@ -261,16 +297,16 @@ void input_EsOutDelete( es_out_t *out ) es_out_sys_t *p_sys = out->p_sys; int i; + if( p_sys->p_sout_record ) + input_EsOutSetRecord( out, false ); + for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_dec ) - { input_DecoderDelete( p_sys->es[i]->p_dec ); - } - if( p_sys->es[i]->psz_language ) - free( p_sys->es[i]->psz_language ); - if( p_sys->es[i]->psz_language_code ) - free( p_sys->es[i]->psz_language_code ); + + free( p_sys->es[i]->psz_language ); + free( p_sys->es[i]->psz_language_code ); es_format_Clean( &p_sys->es[i]->fmt ); free( p_sys->es[i] ); @@ -287,20 +323,16 @@ void input_EsOutDelete( es_out_t *out ) free( p_sys->ppsz_sub_language[i] ); free( p_sys->ppsz_sub_language ); } - - if( p_sys->es ) - free( p_sys->es ); + free( p_sys->es ); /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */ for( i = 0; i < p_sys->i_pgrm; i++ ) { es_out_pgrm_t *p_pgrm = p_sys->pgrm[i]; - if( p_pgrm->psz_now_playing ) - free( p_pgrm->psz_now_playing ); - if( p_pgrm->psz_publisher ) - free( p_pgrm->psz_publisher ); - if( p_pgrm->psz_name ) - free( p_pgrm->psz_name ); + input_clock_Delete( p_pgrm->p_clock ); + free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_publisher ); + free( p_pgrm->psz_name ); if( p_pgrm->p_epg ) vlc_epg_Delete( p_pgrm->p_epg ); @@ -329,32 +361,110 @@ es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id ) return NULL; } -static void EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio ) +mtime_t input_EsOutGetWakeup( es_out_t *out ) { - es_out_sys_t *p_sys = out->p_sys; - int i; + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; - for( i = 0; i < p_sys->i_es; i++ ) - { - es_out_id_t *es = p_sys->es[i]; + if( !p_sys->p_pgrm ) + return 0; - /* Send a dummy block to let decoder know that - * there is a discontinuity */ - if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) ) - input_DecoderDiscontinuity( es->p_dec, b_flush ); - } + /* We do not have a wake up date if the input cannot have its speed + * controlled or sout is imposing its own or while buffering + * + * FIXME for !p_input->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */ + if( !p_input->b_can_pace_control || + p_input->p->b_out_pace_control || + p_sys->b_buffering ) + return 0; + + return input_clock_GetWakeup( p_sys->p_pgrm->p_clock ); } -void input_EsOutChangeRate( es_out_t *out ) + +void input_EsOutChangeRate( es_out_t *out, int i_rate ) { es_out_sys_t *p_sys = out->p_sys; int i; - EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE ); + p_sys->i_rate = i_rate; for( i = 0; i < p_sys->i_pgrm; i++ ) - input_ClockSetRate( p_sys->p_input, &p_sys->pgrm[i]->clock ); + input_clock_ChangeRate( p_sys->pgrm[i]->p_clock, i_rate ); } +int input_EsOutSetRecord( es_out_t *out, bool b_record ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + + assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) ); + + if( b_record ) + { + char *psz_path = var_CreateGetString( p_input, "input-record-path" ); + if( !psz_path || *psz_path == '\0' ) + { + free( psz_path ); + psz_path = strdup( config_GetHomeDir() ); + } + + char *psz_sout = NULL; // TODO conf + + if( !psz_sout && psz_path ) + { + char *psz_file = input_CreateFilename( VLC_OBJECT(p_input), psz_path, INPUT_RECORD_PREFIX, NULL ); + if( psz_file ) + { + if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file ) < 0 ) + psz_sout = NULL; + free( psz_file ); + } + } + free( psz_path ); + + if( !psz_sout ) + return VLC_EGENERIC; + +#ifdef ENABLE_SOUT + p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout ); +#endif + free( psz_sout ); + + if( !p_sys->p_sout_record ) + return VLC_EGENERIC; + + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec || p_es->p_master ) + continue; + + p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record ); + if( p_es->p_dec_record && p_sys->b_buffering ) + input_DecoderStartBuffering( p_es->p_dec_record ); + } + } + else + { + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec_record ) + continue; + + input_DecoderDelete( p_es->p_dec_record ); + p_es->p_dec_record = NULL; + } +#ifdef ENABLE_SOUT + sout_DeleteInstance( p_sys->p_sout_record ); +#endif + p_sys->p_sout_record = NULL; + } + + return VLC_SUCCESS; +} void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) { es_out_sys_t *p_sys = out->p_sys; @@ -363,55 +473,196 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) p_sys->i_audio_delay = i_delay; else if( i_cat == SPU_ES ) p_sys->i_spu_delay = i_delay; + + for( int i = 0; i < p_sys->i_es; i++ ) + EsOutDecoderChangeDelay( out, p_sys->es[i] ); } -void input_EsOutChangeState( es_out_t *out ) +void input_EsOutChangePause( es_out_t *out, bool b_paused, mtime_t i_date ) { - es_out_sys_t *p_sys = out->p_sys; - input_thread_t *p_input = p_sys->p_input; - - if( p_input->i_state == PAUSE_S ) + /* XXX the order is important */ + if( b_paused ) { - /* Send discontinuity to decoders (it will allow them to flush - * * if implemented */ - EsOutDiscontinuity( out, VLC_FALSE, VLC_FALSE ); + EsOutDecodersChangePause( out, true, i_date ); + EsOutProgramChangePause( out, true, i_date ); } else { - /* Out of pause, reset pcr */ - es_out_Control( out, ES_OUT_RESET_PCR ); + EsOutProgramChangePause( out, false, i_date ); + EsOutDecodersChangePause( out, false, i_date ); } } void input_EsOutChangePosition( es_out_t *out ) { - //es_out_sys_t *p_sys = out->p_sys; + es_out_sys_t *p_sys = out->p_sys; + + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec ) + continue; + + input_DecoderStartBuffering( p_es->p_dec ); - es_out_Control( out, ES_OUT_RESET_PCR ); - EsOutDiscontinuity( out, VLC_TRUE, VLC_FALSE ); + if( p_es->p_dec_record ) + input_DecoderStartBuffering( p_es->p_dec ); + } + + for( int i = 0; i < p_sys->i_pgrm; i++ ) + input_clock_Reset( p_sys->pgrm[i]->p_clock ); + + p_sys->b_buffering = true; + p_sys->i_preroll_end = -1; } -vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out ) +bool input_EsOutDecodersIsEmpty( es_out_t *out ) { es_out_sys_t *p_sys = out->p_sys; int i; + if( p_sys->b_buffering && p_sys->p_pgrm ) + { + EsOutDecodersStopBuffering( out, true ); + if( p_sys->b_buffering ) + return true; + } + for( i = 0; i < p_sys->i_es; i++ ) { es_out_id_t *es = p_sys->es[i]; - if( es->p_dec && !input_DecoderEmpty( es->p_dec ) ) - return VLC_FALSE; + if( es->p_dec && !input_DecoderIsEmpty( es->p_dec ) ) + return false; + if( es->p_dec_record && !input_DecoderIsEmpty( es->p_dec_record ) ) + return false; } - return VLC_TRUE; + return true; +} + +bool input_EsOutIsBuffering( es_out_t *out ) +{ + return out->p_sys->b_buffering; } /***************************************************************************** * *****************************************************************************/ +static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced ) +{ + es_out_sys_t *p_sys = out->p_sys; + int i_ret; + + mtime_t i_stream_start; + mtime_t i_system_start; + mtime_t i_stream_duration; + mtime_t i_system_duration; + i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock, + &i_stream_start, &i_system_start, + &i_stream_duration, &i_system_duration ); + assert( !i_ret || b_forced ); + if( i_ret ) + return; + + mtime_t i_preroll_duration = 0; + if( p_sys->i_preroll_end >= 0 ) + i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 ); + + if( i_stream_duration <= p_sys->p_input->i_pts_delay + i_preroll_duration && !b_forced ) + { + msg_Dbg( p_sys->p_input, "Buffering %d%%", (int)(100 * i_stream_duration / ( p_sys->p_input->i_pts_delay + i_preroll_duration )) ); + return; + } + + msg_Dbg( p_sys->p_input, "Stream buffering done (%d ms in %d ms)", + (int)(i_stream_duration/1000), (int)(i_system_duration/1000) ); + p_sys->b_buffering = false; + p_sys->i_preroll_end = -1; + + const mtime_t i_decoder_buffering_start = mdate(); + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec ) + continue; + input_DecoderWaitBuffering( p_es->p_dec ); + if( p_es->p_dec_record ) + input_DecoderWaitBuffering( p_es->p_dec_record ); + } + + msg_Dbg( p_sys->p_input, "Decoder buffering done in %d ms", + (int)(mdate() - i_decoder_buffering_start)/1000 ); + + const mtime_t i_ts_delay = 10*1000 + /* FIXME CLEANUP thread wake up time*/ + mdate(); + //msg_Dbg( p_sys->p_input, "==> %lld", i_ts_delay - p_sys->p_input->i_pts_delay ); + input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_clock, i_ts_delay - p_sys->p_input->i_pts_delay - i_preroll_duration ); + + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *p_es = p_sys->es[i]; + + if( !p_es->p_dec ) + continue; + + input_DecoderStopBuffering( p_es->p_dec ); + if( p_es->p_dec_record ) + input_DecoderStopBuffering( p_es->p_dec ); + } +} +static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date ) +{ + es_out_sys_t *p_sys = out->p_sys; + + /* Pause decoders first */ + for( int i = 0; i < p_sys->i_es; i++ ) + { + es_out_id_t *es = p_sys->es[i]; + + /* Send a dummy block to let decoder know that + * there is a discontinuity */ + if( es->p_dec ) + { + input_DecoderChangePause( es->p_dec, b_paused, i_date ); + if( es->p_dec_record ) + input_DecoderChangePause( es->p_dec_record, b_paused, i_date ); + } + } +} +static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date ) +{ + es_out_sys_t *p_sys = out->p_sys; + + for( int i = 0; i < p_sys->i_pgrm; i++ ) + input_clock_ChangePause( p_sys->pgrm[i]->p_clock, b_paused, i_date ); +} + +static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es ) +{ + es_out_sys_t *p_sys = out->p_sys; + + mtime_t i_delay = 0; + if( p_es->fmt.i_cat == AUDIO_ES ) + i_delay = p_sys->i_audio_delay; + else if( p_es->fmt.i_cat == SPU_ES ) + i_delay = p_sys->i_spu_delay; + + if( i_delay != 0 ) + { + if( p_es->p_dec ) + input_DecoderChangeDelay( p_es->p_dec, i_delay ); + if( p_es->p_dec_record ) + input_DecoderChangeDelay( p_es->p_dec_record, i_delay ); + } +} + + static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language, - vlc_bool_t b_delete ) + bool b_delete ) { es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; + const bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ); vlc_value_t val, text; const char *psz_var; @@ -427,9 +678,13 @@ static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, if( b_delete ) { + if( b_teletext ) + var_SetInteger( p_sys->p_input, "teletext-es", -1 ); + val.i_int = i_id; var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + + var_SetBool( p_sys->p_input, "intf-change", true ); return; } @@ -461,17 +716,13 @@ static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, { if( psz_language && *psz_language ) { - char *temp; - text.psz_string = malloc( strlen( _("Track %i") )+ - strlen( psz_language ) + 30 ); - asprintf( &temp, _("Track %i"), val.i_int ); - sprintf( text.psz_string, "%s - [%s]", temp, psz_language ); - free( temp ); + if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 ) + text.psz_string = NULL; } else { - text.psz_string = malloc( strlen( _("Track %i") ) + 20 ); - sprintf( text.psz_string, _("Track %i"), val.i_int ); + if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 ) + text.psz_string = NULL; } } @@ -480,11 +731,17 @@ static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, free( text.psz_string ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + if( b_teletext ) + { + if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 ) + var_SetInteger( p_sys->p_input, "teletext-es", i_id ); + } + + var_SetBool( p_sys->p_input, "intf-change", true ); } static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, - vlc_bool_t b_delete ) + bool b_delete ) { EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete ); } @@ -509,9 +766,9 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) for( i = 0; i < p_sys->i_es; i++ ) { - if( p_sys->es[i]->p_pgrm == old && EsIsSelected( out, p_sys->es[i] ) && + if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) && p_sys->i_mode != ES_OUT_MODE_ALL ) - EsUnselect( out, p_sys->es[i], VLC_TRUE ); + EsUnselect( out, p_sys->es[i], true ); } p_sys->p_es_audio = NULL; @@ -522,14 +779,9 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id ); /* Mark it selected */ - p_pgrm->b_selected = VLC_TRUE; + p_pgrm->b_selected = true; /* Switch master stream */ - if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master ) - { - p_sys->p_pgrm->clock.b_master = VLC_FALSE; - } - p_pgrm->clock.b_master = VLC_TRUE; p_sys->p_pgrm = p_pgrm; /* Update "program" */ @@ -540,11 +792,12 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); + var_SetInteger( p_input, "teletext-es", -1 ); for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm ) - EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE ); - EsOutSelect( out, p_sys->es[i], VLC_FALSE ); + EsOutESVarUpdate( out, p_sys->es[i], false ); + EsOutSelect( out, p_sys->es[i], false ); } /* Update now playing */ @@ -553,7 +806,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) input_item_SetPublisher( p_input->p->input.p_item, p_pgrm->psz_publisher ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); } /* EsOutAddProgram: @@ -566,16 +819,23 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) vlc_value_t val; es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) ); + if( !p_pgrm ) + return NULL; /* Init */ p_pgrm->i_id = i_group; p_pgrm->i_es = 0; - p_pgrm->b_selected = VLC_FALSE; + p_pgrm->b_selected = false; p_pgrm->psz_name = NULL; p_pgrm->psz_now_playing = NULL; p_pgrm->psz_publisher = NULL; p_pgrm->p_epg = NULL; - input_ClockInit( p_input, &p_pgrm->clock, VLC_FALSE, p_input->p->input.i_cr_average ); + p_pgrm->p_clock = input_clock_New( p_input->p->input.i_cr_average, p_sys->i_rate ); + if( !p_pgrm->p_clock ) + { + free( p_pgrm ); + return NULL; + } /* Append it */ TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); @@ -590,7 +850,7 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) } else { - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); } return p_pgrm; } @@ -628,11 +888,14 @@ static int EsOutProgramDel( es_out_t *out, int i_group ) TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); /* If program is selected we need to unselect it */ - if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = NULL; + if( p_sys->p_pgrm == p_pgrm ) + p_sys->p_pgrm = NULL; + + input_clock_Delete( p_pgrm->p_clock ); - if( p_pgrm->psz_name ) free( p_pgrm->psz_name ); - if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing ); - if( p_pgrm->psz_publisher ) free( p_pgrm->psz_publisher ); + free( p_pgrm->psz_name ); + free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_publisher ); if( p_pgrm->p_epg ) vlc_epg_Delete( p_pgrm->p_epg ); free( p_pgrm ); @@ -641,7 +904,7 @@ static int EsOutProgramDel( es_out_t *out, int i_group ) val.i_int = i_group; var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); return VLC_SUCCESS; } @@ -652,9 +915,15 @@ static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm ) { char *psz = NULL; if( p_pgrm->psz_name ) - asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ); + { + if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 ) + return NULL; + } else - asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ); + { + if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 ) + return NULL; + } return psz; } @@ -709,7 +978,7 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) /* TODO update epg name */ free( psz_cat ); } - if( p_pgrm->psz_name ) free( p_pgrm->psz_name ); + free( p_pgrm->psz_name ); p_pgrm->psz_name = strdup( psz_title ); /* ugly but it works */ @@ -718,9 +987,11 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) if( psz_provider && *psz_provider ) { - asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ); - var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); - free( text.psz_string ); + if( asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ) != -1 ) + { + var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); + free( text.psz_string ); + } } else { @@ -756,14 +1027,14 @@ static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src ) for( i = 0; i < p_src->i_event; i++ ) { vlc_epg_event_t *p_evt = p_src->pp_event[i]; - vlc_bool_t b_add = VLC_TRUE; + bool b_add = true; int j; for( j = 0; j < p_dst->i_event; j++ ) { if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration ) { - b_add = VLC_FALSE; + b_add = false; break; } if( p_dst->pp_event[j]->i_start > p_evt->i_start ) @@ -850,8 +1121,7 @@ static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg ) free( psz_epg ); #endif /* Update now playing */ - if( p_pgrm->psz_now_playing ) - free( p_pgrm->psz_now_playing ); + free( p_pgrm->psz_now_playing ); p_pgrm->psz_now_playing = NULL; if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name ) p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name ); @@ -886,9 +1156,12 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es_out_pgrm_t *p_pgrm = NULL; int i; + if( !es ) return NULL; + if( fmt->i_group < 0 ) { msg_Err( p_input, "invalid group number" ); + free( es ); return NULL; } @@ -916,7 +1189,6 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->i_id = fmt->i_id; es->p_pgrm = p_pgrm; es_format_Copy( &es->fmt, fmt ); - es->i_preroll_end = -1; switch( fmt->i_cat ) { @@ -926,8 +1198,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->i_channel = p_sys->i_audio; - vlc_mutex_lock( &p_input->p->input.p_item->lock ); memset( &rg, 0, sizeof(rg) ); + vlc_mutex_lock( &p_input->p->input.p_item->lock ); vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta ); vlc_mutex_unlock( &p_input->p->input.p_item->lock ); @@ -967,15 +1239,16 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */ es->psz_language_code = LanguageGetCode( fmt->psz_language ); es->p_dec = NULL; + es->p_dec_record = NULL; for( i = 0; i < 4; i++ ) - es->pb_cc_present[i] = VLC_FALSE; - es->p_master = VLC_FALSE; + es->pb_cc_present[i] = false; + es->p_master = NULL; if( es->p_pgrm == p_sys->p_pgrm ) - EsOutESVarUpdate( out, es, VLC_FALSE ); + EsOutESVarUpdate( out, es, false ); /* Select it if needed */ - EsOutSelect( out, es, VLC_FALSE ); + EsOutSelect( out, es, false ); TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es ); @@ -998,11 +1271,11 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) return es; } -static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es ) +static bool EsIsSelected( es_out_id_t *es ) { if( es->p_master ) { - vlc_bool_t b_decode = VLC_FALSE; + bool b_decode = false; if( es->p_master->p_dec ) { int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); @@ -1016,6 +1289,44 @@ static vlc_bool_t EsIsSelected( es_out_t *out, es_out_id_t *es ) return es->p_dec != NULL; } } +static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + + p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_input->p->p_sout ); + if( p_es->p_dec ) + { + if( p_sys->b_buffering ) + input_DecoderStartBuffering( p_es->p_dec ); + + if( !p_es->p_master && p_sys->p_sout_record ) + { + p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record ); + if( p_es->p_dec_record && p_sys->b_buffering ) + input_DecoderStartBuffering( p_es->p_dec_record ); + } + } + + EsOutDecoderChangeDelay( out, p_es ); +} +static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es ) +{ + VLC_UNUSED(out); + + if( !p_es->p_dec ) + return; + + input_DecoderDelete( p_es->p_dec ); + p_es->p_dec = NULL; + + if( p_es->p_dec_record ) + { + input_DecoderDelete( p_es->p_dec_record ); + p_es->p_dec_record = NULL; + } +} + static void EsSelect( es_out_t *out, es_out_id_t *es ) { es_out_sys_t *p_sys = out->p_sys; @@ -1023,7 +1334,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) vlc_value_t val; const char *psz_var; - if( EsIsSelected( out, es ) ) + if( EsIsSelected( es ) ) { msg_Warn( p_input, "ES 0x%x is already selected", es->i_id ); return; @@ -1036,15 +1347,14 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) return; i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); - if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, VLC_TRUE, i_channel ) ) + if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) ) return; } else { if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES ) { - if( !var_GetBool( p_input, "video" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) ) + if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) ) { msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", es->i_id ); @@ -1054,8 +1364,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) else if( es->fmt.i_cat == AUDIO_ES ) { var_Get( p_input, "audio", &val ); - if( !var_GetBool( p_input, "audio" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) ) + if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) ) { msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", es->i_id ); @@ -1065,8 +1374,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) if( es->fmt.i_cat == SPU_ES ) { var_Get( p_input, "spu", &val ); - if( !var_GetBool( p_input, "spu" ) || - ( p_input->p->p_sout && !var_GetBool( p_input, "sout-spu" ) ) ) + if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) ) { msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x", es->i_id ); @@ -1074,8 +1382,8 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) } } - es->i_preroll_end = -1; - es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); + EsCreateDecoder( out, es ); + if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) return; } @@ -1093,17 +1401,17 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) val.i_int = es->i_id; var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); } -static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) +static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update ) { es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val; const char *psz_var; - if( !EsIsSelected( out, es ) ) + if( !EsIsSelected( es ) ) { msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id ); return; @@ -1115,7 +1423,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) { int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec ); if( i_channel != -1 ) - input_DecoderSetCcState( es->p_master->p_dec, VLC_FALSE, i_channel ); + input_DecoderSetCcState( es->p_master->p_dec, false, i_channel ); } } else @@ -1133,14 +1441,13 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) val.i_int = -1; var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL ); if( !b_update ) - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); } EsOutDel( out, es->pp_cc_es[i] ); - es->pb_cc_present[i] = VLC_FALSE; + es->pb_cc_present[i] = false; } - input_DecoderDelete( es->p_dec ); - es->p_dec = NULL; + EsDestroyDecoder( out, es ); } if( !b_update ) @@ -1162,7 +1469,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) val.i_int = -1; var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL ); - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); } /** @@ -1174,7 +1481,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) * \param b_force ... * \return nothing */ -static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) +static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force ) { es_out_sys_t *p_sys = out->p_sys; @@ -1188,7 +1495,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force ) { - if( !EsIsSelected( out, es ) ) + if( !EsIsSelected( es ) ) EsSelect( out, es ); } else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL ) @@ -1200,7 +1507,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) { if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force ) { - if( !EsIsSelected( out, es ) ) + if( !EsIsSelected( es ) ) EsSelect( out, es ); break; } @@ -1301,21 +1608,21 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) i_wanted = es->i_channel; } - if( i_wanted == es->i_channel && !EsIsSelected( out, es ) ) + if( i_wanted == es->i_channel && !EsIsSelected( es ) ) EsSelect( out, es ); } /* FIXME TODO handle priority here */ - if( EsIsSelected( out, es ) ) + if( EsIsSelected( es ) ) { if( i_cat == AUDIO_ES ) { if( p_sys->i_mode == ES_OUT_MODE_AUTO && p_sys->p_es_audio && p_sys->p_es_audio != es && - EsIsSelected( out, p_sys->p_es_audio ) ) + EsIsSelected( p_sys->p_es_audio ) ) { - EsUnselect( out, p_sys->p_es_audio, VLC_FALSE ); + EsUnselect( out, p_sys->p_es_audio, false ); } p_sys->p_es_audio = es; } @@ -1324,9 +1631,9 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( p_sys->i_mode == ES_OUT_MODE_AUTO && p_sys->p_es_sub && p_sys->p_es_sub != es && - EsIsSelected( out, p_sys->p_es_sub ) ) + EsIsSelected( p_sys->p_es_sub ) ) { - EsUnselect( out, p_sys->p_es_sub, VLC_FALSE ); + EsUnselect( out, p_sys->p_es_sub, false ); } p_sys->p_es_sub = es; } @@ -1346,20 +1653,11 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) */ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) { - es_out_sys_t *p_sys = out->p_sys; - input_thread_t *p_input = p_sys->p_input; - es_out_pgrm_t *p_pgrm = es->p_pgrm; - int64_t i_delay; - int i_total=0; - - if( es->fmt.i_cat == AUDIO_ES ) - i_delay = p_sys->i_audio_delay; - else if( es->fmt.i_cat == SPU_ES ) - i_delay = p_sys->i_spu_delay; - else - i_delay = 0; + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + int i_total = 0; - if( p_input->p_libvlc->b_stats ) + if( libvlc_stats( p_input ) ) { vlc_mutex_lock( &p_input->p->counters.counters_lock ); stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read, @@ -1370,103 +1668,67 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) } /* Mark preroll blocks */ - if( es->i_preroll_end >= 0 ) + if( p_sys->i_preroll_end >= 0 ) { int64_t i_date = p_block->i_pts; if( i_date <= 0 ) i_date = p_block->i_dts; - if( i_date < es->i_preroll_end ) + if( i_date < p_sys->i_preroll_end ) p_block->i_flags |= BLOCK_FLAG_PREROLL; - else - es->i_preroll_end = -1; } - if( p_block->i_dts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) ) - { - p_block->i_dts += i_delay; - } - else if( p_block->i_dts > 0 ) - { - p_block->i_dts = - input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_dts ) + i_delay; - } - if( p_block->i_pts > 0 && (p_block->i_flags&BLOCK_FLAG_PREROLL) ) - { - p_block->i_pts += i_delay; - } - else if( p_block->i_pts > 0 ) + p_block->i_rate = 0; + + if( !es->p_dec ) { - p_block->i_pts = - input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay; + block_Release( p_block ); + return VLC_SUCCESS; } - if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) ) + + /* Decode */ + if( es->p_dec_record ) { - mtime_t current_date = mdate(); - if( !p_block->i_pts - || p_block->i_pts > current_date + 10000000 - || current_date > p_block->i_pts ) - { - /* ETSI EN 300 472 Annex A : do not take into account the PTS - * for teletext streams. */ - p_block->i_pts = current_date + 400000 - + p_input->i_pts_delay + i_delay; - } + block_t *p_dup = block_Duplicate( p_block ); + if( p_dup ) + input_DecoderDecode( es->p_dec_record, p_dup ); } + input_DecoderDecode( es->p_dec, p_block ); - p_block->i_rate = p_input->p->i_rate; + /* Check CC status */ + bool pb_cc[4]; + bool b_cc_new = false; - /* TODO handle mute */ - if( es->p_dec && - ( es->fmt.i_cat != AUDIO_ES || - ( p_input->p->i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE && - p_input->p->i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) ) ) + input_DecoderIsCcPresent( es->p_dec, pb_cc ); + for( int i = 0; i < 4; i++ ) { - vlc_bool_t pb_cc[4]; - vlc_bool_t b_cc_new = VLC_FALSE; - int i; - input_DecoderDecode( es->p_dec, p_block ); + static const vlc_fourcc_t fcc[4] = { + VLC_FOURCC('c', 'c', '1', ' '), + VLC_FOURCC('c', 'c', '2', ' '), + VLC_FOURCC('c', 'c', '3', ' '), + VLC_FOURCC('c', 'c', '4', ' '), + }; + es_format_t fmt; - /* Check CC status */ - input_DecoderIsCcPresent( es->p_dec, pb_cc ); - for( i = 0; i < 4; i++ ) - { - static const vlc_fourcc_t fcc[4] = { - VLC_FOURCC('c', 'c', '1', ' '), - VLC_FOURCC('c', 'c', '2', ' '), - VLC_FOURCC('c', 'c', '3', ' '), - VLC_FOURCC('c', 'c', '4', ' '), - }; - static const char *ppsz_description[4] = { - N_("Closed captions 1"), - N_("Closed captions 2"), - N_("Closed captions 3"), - N_("Closed captions 4"), - }; - es_format_t fmt; - - if( es->pb_cc_present[i] || !pb_cc[i] ) - continue; - msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id ); - - es_format_Init( &fmt, SPU_ES, fcc[i] ); - fmt.i_group = es->fmt.i_group; - fmt.psz_description = strdup( _(ppsz_description[i] ) ); - es->pp_cc_es[i] = EsOutAdd( out, &fmt ); - es->pp_cc_es[i]->p_master = es; - es_format_Clean( &fmt ); - - /* */ - es->pb_cc_present[i] = VLC_TRUE; - b_cc_new = VLC_TRUE; - } - if( b_cc_new ) - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); - } - else - { - block_Release( p_block ); + if( es->pb_cc_present[i] || !pb_cc[i] ) + continue; + msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id ); + + es_format_Init( &fmt, SPU_ES, fcc[i] ); + fmt.i_group = es->fmt.i_group; + if( asprintf( &fmt.psz_description, + _("Closed captions %u"), 1 + i ) == -1 ) + fmt.psz_description = NULL; + es->pp_cc_es[i] = EsOutAdd( out, &fmt ); + es->pp_cc_es[i]->p_master = es; + es_format_Clean( &fmt ); + + /* */ + es->pb_cc_present[i] = true; + b_cc_new = true; } + if( b_cc_new ) + var_SetBool( p_sys->p_input, "intf-change", true ); return VLC_SUCCESS; } @@ -1477,15 +1739,16 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) static void EsOutDel( es_out_t *out, es_out_id_t *es ) { es_out_sys_t *p_sys = out->p_sys; - vlc_bool_t b_reselect = VLC_FALSE; + bool b_reselect = false; int i; /* We don't try to reselect */ if( es->p_dec ) { - while( !out->p_sys->p_input->b_die && es->p_dec ) + while( !p_sys->p_input->b_die && !p_sys->b_buffering && es->p_dec ) { - if( input_DecoderEmpty( es->p_dec ) ) + if( input_DecoderIsEmpty( es->p_dec ) && + ( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) )) break; msleep( 20*1000 ); } @@ -1493,7 +1756,7 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) } if( es->p_pgrm == p_sys->p_pgrm ) - EsOutESVarUpdate( out, es, VLC_TRUE ); + EsOutESVarUpdate( out, es, true ); TAB_REMOVE( p_sys->i_es, p_sys->es, es ); @@ -1504,7 +1767,7 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) } if( p_sys->p_es_audio == es || p_sys->p_es_video == es || - p_sys->p_es_sub == es ) b_reselect = VLC_TRUE; + p_sys->p_es_sub == es ) b_reselect = true; if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL; if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL; @@ -1528,13 +1791,11 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) for( i = 0; i < p_sys->i_es; i++ ) { if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat ) - EsOutSelect( out, p_sys->es[i], VLC_FALSE ); + EsOutSelect( out, p_sys->es[i], false ); } - if( es->psz_language ) - free( es->psz_language ); - if( es->psz_language_code ) - free( es->psz_language_code ); + free( es->psz_language ); + free( es->psz_language_code ); es_format_Clean( &es->fmt ); @@ -1552,7 +1813,7 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) static int EsOutControl( es_out_t *out, int i_query, va_list args ) { es_out_sys_t *p_sys = out->p_sys; - vlc_bool_t b, *pb; + bool b, *pb; int i, *pi; es_out_id_t *es; @@ -1561,13 +1822,13 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { case ES_OUT_SET_ES_STATE: es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - b = (vlc_bool_t) va_arg( args, vlc_bool_t ); - if( b && !EsIsSelected( out, es ) ) + b = (bool) va_arg( args, int ); + if( b && !EsIsSelected( es ) ) { EsSelect( out, es ); - return EsIsSelected( out, es ) ? VLC_SUCCESS : VLC_EGENERIC; + return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC; } - else if( !b && EsIsSelected( out, es ) ) + else if( !b && EsIsSelected( es ) ) { EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm ); return VLC_SUCCESS; @@ -1576,23 +1837,23 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) case ES_OUT_GET_ES_STATE: es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); + pb = (bool*) va_arg( args, bool * ); - *pb = EsIsSelected( out, es ); + *pb = EsIsSelected( es ); return VLC_SUCCESS; case ES_OUT_SET_ACTIVE: { - b = (vlc_bool_t) va_arg( args, vlc_bool_t ); + b = (bool) va_arg( args, int ); p_sys->b_active = b; /* Needed ? */ if( b ) - var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); + var_SetBool( p_sys->p_input, "intf-change", true ); return VLC_SUCCESS; } case ES_OUT_GET_ACTIVE: - pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * ); + pb = (bool*) va_arg( args, bool * ); *pb = p_sys->b_active; return VLC_SUCCESS; @@ -1606,7 +1867,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) /* Reapply policy mode */ for( i = 0; i < p_sys->i_es; i++ ) { - if( EsIsSelected( out, p_sys->es[i] ) ) + if( EsIsSelected( p_sys->es[i] ) ) { EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); @@ -1614,7 +1875,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) } for( i = 0; i < p_sys->i_es; i++ ) { - EsOutSelect( out, p_sys->es[i], VLC_FALSE ); + EsOutSelect( out, p_sys->es[i], false ); } return VLC_SUCCESS; } @@ -1626,67 +1887,64 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) return VLC_SUCCESS; case ES_OUT_SET_ES: + case ES_OUT_RESTART_ES: + { + int i_cat; + es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - /* Special case NULL, NULL+i_cat */ + if( es == NULL ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( EsIsSelected( out, p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = UNKNOWN_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == AUDIO_ES && - EsIsSelected( out, p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = AUDIO_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == VIDEO_ES && - EsIsSelected( out, p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = VIDEO_ES; else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) ) - { - for( i = 0; i < p_sys->i_es; i++ ) - { - if( p_sys->es[i]->fmt.i_cat == SPU_ES && - EsIsSelected( out, p_sys->es[i] ) ) - EsUnselect( out, p_sys->es[i], - p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); - } - } + i_cat = SPU_ES; else + i_cat = -1; + + for( i = 0; i < p_sys->i_es; i++ ) { - for( i = 0; i < p_sys->i_es; i++ ) + if( i_cat == -1 ) { if( es == p_sys->es[i] ) { - EsOutSelect( out, es, VLC_TRUE ); + EsOutSelect( out, es, true ); break; } } + else + { + if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat ) + { + if( EsIsSelected( p_sys->es[i] ) ) + { + if( i_query == ES_OUT_RESTART_ES ) + { + if( p_sys->es[i]->p_dec ) + { + EsDestroyDecoder( out, p_sys->es[i] ); + EsCreateDecoder( out, p_sys->es[i] ); + } + } + else + { + EsUnselect( out, p_sys->es[i], + p_sys->es[i]->p_pgrm == p_sys->p_pgrm ); + } + } + } + } } + if( i_query == ES_OUT_SET_ES ) { - playlist_t * p_playlist = pl_Yield( p_sys->p_input ); - PL_LOCK; - p_playlist->gc_date = mdate(); - vlc_object_signal_unlocked( p_playlist ); - PL_UNLOCK; - pl_Release( p_playlist ); + vlc_event_t event; + event.type = vlc_InputSelectedStreamChanged; + vlc_event_send( &p_sys->p_input->p->event_manager, &event ); } return VLC_SUCCESS; + } case ES_OUT_SET_DEFAULT: { @@ -1752,14 +2010,20 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */ i_pcr = (int64_t)va_arg( args, int64_t ); - /* search program */ - input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr ); + /* search program + * TODO do not use mdate() but proper stream acquisition date */ + input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input), + p_sys->p_input->b_can_pace_control, i_pcr, mdate() ); + /* Check buffering state on master clock update */ + if( p_sys->b_buffering && p_pgrm == p_sys->p_pgrm ) + EsOutDecodersStopBuffering( out, false ); + return VLC_SUCCESS; } case ES_OUT_RESET_PCR: - for( i = 0; i < p_sys->i_pgrm; i++ ) - input_ClockResetPCR( p_sys->p_input, &p_sys->pgrm[i]->clock ); + msg_Err( p_sys->p_input, "ES_OUT_RESET_PCR called" ); + input_EsOutChangePosition( out ); return VLC_SUCCESS; case ES_OUT_GET_TS: @@ -1767,8 +2031,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) { int64_t i_ts = (int64_t)va_arg( args, int64_t ); int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * ); - *pi_ts = input_ClockGetTS( p_sys->p_input, - &p_sys->p_pgrm->clock, i_ts ); + *pi_ts = input_clock_GetTS( p_sys->p_pgrm->p_clock, NULL, + p_sys->p_input->i_pts_delay, i_ts ); return VLC_SUCCESS; } return VLC_EGENERIC; @@ -1804,7 +2068,8 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) es_format_t *p_fmt; es = (es_out_id_t*) va_arg( args, es_out_id_t * ); p_fmt = (es_format_t*) va_arg( args, es_format_t * ); - if( es == NULL ) return VLC_EGENERIC; + if( es == NULL ) + return VLC_EGENERIC; if( p_fmt->i_extra ) { @@ -1812,13 +2077,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra ); memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra ); - if( !es->p_dec ) return VLC_SUCCESS; - + if( !es->p_dec ) + return VLC_SUCCESS; #if 1 - input_DecoderDelete( es->p_dec ); - es->p_dec = input_DecoderNew( p_sys->p_input, - &es->fmt, VLC_FALSE ); + EsDestroyDecoder( out, es ); + EsCreateDecoder( out, es ); #else es->p_dec->fmt_in.i_extra = p_fmt->i_extra; es->p_dec->fmt_in.p_extra = @@ -1833,18 +2097,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) case ES_OUT_SET_NEXT_DISPLAY_TIME: { - int64_t i_date; - - es = (es_out_id_t*) va_arg( args, es_out_id_t * ); - i_date = (int64_t)va_arg( args, int64_t ); + const int64_t i_date = (int64_t)va_arg( args, int64_t ); - if( !es || !es->p_dec ) + if( i_date < 0 ) return VLC_EGENERIC; - /* XXX We should call input_ClockGetTS but PCR has been reseted - * and it will return 0, so we won't call input_ClockGetTS on all preroll samples - * but that's ugly(more time discontinuity), it need to be improved -- fenrir */ - es->i_preroll_end = i_date; + p_sys->i_preroll_end = i_date; return VLC_SUCCESS; } @@ -2023,7 +2281,8 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) lldiv_t div; /* Add stream info */ - asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ); + if( asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ) == -1 ) + return; input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"), "%.4s", (char*)&fmt->i_codec ); @@ -2084,7 +2343,7 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) fmt->video.i_frame_rate_base * 1000000, 1000000 ); input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Frame rate"), I64Fd".%06u", + _("Frame rate"), "%"PRId64".%06u", div.quot, (unsigned int )div.rem ); } break;