X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out.c;h=b92d0d84b2ca8d0ad229932893c1fbe7705161ae;hb=f485214f09dd284cbb85674e937fbbb0a6032a2e;hp=280eedf3a9835ff75100b19bd0580f5040bc4257;hpb=45cd6d75350e2f9f3d1e7c30a7f34c119acb5ec8;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index 280eedf3a9..b92d0d84b2 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -1,10 +1,11 @@ /***************************************************************************** * es_out.c: Es Out handler for input. ***************************************************************************** - * Copyright (C) 2003-2004 VideoLAN + * Copyright (C) 2003-2004 the VideoLAN team * $Id$ * * Authors: Laurent Aimar + * Jean-Paul Saman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,15 +19,17 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ +#include + +#include #include -#include #include #include @@ -63,7 +66,10 @@ struct es_out_id_t int i_id; es_out_pgrm_t *p_pgrm; - /* */ + /* Signal a discontinuity in the timeline for every PID */ + vlc_bool_t b_discontinuity; + + /* Misc. */ int64_t i_preroll_end; /* Channel in the track type */ @@ -99,8 +105,8 @@ struct es_out_sys_t int i_sub; /* es to select */ - int i_audio_last; - int i_sub_last; + int i_audio_last, i_audio_id; + int i_sub_last, i_sub_id; char **ppsz_audio_language; char **ppsz_sub_language; @@ -175,7 +181,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) if( p_sys->ppsz_audio_language ) { for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) - msg_Dbg( p_input, "select audio in language[%d] %s", + msg_Dbg( p_input, "selected audio language[%d] %s", i, p_sys->ppsz_audio_language[i] ); } if( val.psz_string ) free( val.psz_string ); @@ -185,11 +191,17 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) if( p_sys->ppsz_sub_language ) { for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) - msg_Dbg( p_input, "select subtitle in language[%d] %s", + msg_Dbg( p_input, "selected subtitle language[%d] %s", i, p_sys->ppsz_sub_language[i] ); } if( val.psz_string ) free( val.psz_string ); + var_Get( p_input, "audio-track-id", &val ); + p_sys->i_audio_id = val.i_int; + + var_Get( p_input, "sub-track-id", &val ); + p_sys->i_sub_id = val.i_int; + p_sys->p_es_audio = NULL; p_sys->p_es_video = NULL; p_sys->p_es_sub = NULL; @@ -276,6 +288,7 @@ void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio ) for( i = 0; i < p_sys->i_es; i++ ) { es_out_id_t *es = p_sys->es[i]; + es->b_discontinuity = VLC_TRUE; /* signal discontinuity */ /* Send a dummy block to let decoder know that * there is a discontinuity */ @@ -357,8 +370,10 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, { if( es->psz_language && *es->psz_language ) { - text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 ); - sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language ); + text.psz_string = malloc( strlen( es->fmt.psz_description) + + strlen( es->psz_language ) + 10 ); + sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, + es->psz_language ); } else text.psz_string = strdup( es->fmt.psz_description ); } @@ -367,7 +382,8 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, if( es->psz_language && *es->psz_language ) { char *temp; - text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 ); + text.psz_string = malloc( strlen( _("Track %i") )+ + strlen( es->psz_language ) + 30 ); asprintf( &temp, _("Track %i"), val.i_int ); sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language ); free( temp ); @@ -451,8 +467,8 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) char *psz_cat = malloc( strlen(_("Program")) + 10 ); sprintf( psz_cat, "%s %d", _("Program"), p_pgrm->i_id ); - input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"), - VLC_META_NOW_PLAYING, "%s", p_pgrm->psz_now_playing ); + input_Control( p_input, INPUT_ADD_INFO, _(VLC_META_INFO_CAT), + _(VLC_META_NOW_PLAYING), "%s", p_pgrm->psz_now_playing ); free( psz_cat ); } @@ -496,6 +512,53 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) return p_pgrm; } +/* EsOutDelProgram: + * Delete a program + */ +static int EsOutProgramDel( es_out_t *out, int i_group ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + es_out_pgrm_t *p_pgrm = NULL; + vlc_value_t val; + int i; + + for( i = 0; i < p_sys->i_pgrm; i++ ) + { + if( p_sys->pgrm[i]->i_id == i_group ) + { + p_pgrm = p_sys->pgrm[i]; + break; + } + } + + if( p_pgrm == NULL ) + return VLC_EGENERIC; + + if( p_pgrm->i_es ) + { + msg_Dbg( p_input, "can't delete program %d which still has %i ES", + i_group, p_pgrm->i_es ); + return VLC_EGENERIC; + } + + 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 = 0; + + if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing ); + free( p_pgrm ); + + /* Update "program" variable */ + 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 ); + + return VLC_SUCCESS; +} + /* EsOutProgramMeta: */ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) @@ -504,7 +567,7 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) es_out_pgrm_t *p_pgrm = NULL; input_thread_t *p_input = p_sys->p_input; char *psz_cat = malloc( strlen(_("Program")) + 10 ); - char *psz_name = NULL; + char *psz_title = NULL; char *psz_now_playing = NULL; char *psz_provider = NULL; int i; @@ -512,21 +575,11 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group ); sprintf( psz_cat, "%s %d", _("Program"), i_group ); - for( i = 0; i < p_meta->i_meta; i++ ) - { - msg_Dbg( p_input, " - %s = %s", p_meta->name[i], p_meta->value[i] ); - - input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _(p_meta->name[i]), "%s", p_meta->value[i] ); - if( !strcasecmp( p_meta->name[i], "Name" ) ) - psz_name = p_meta->value[i]; - else if( !strcasecmp( p_meta->name[i], "Provider" ) ) - psz_provider = p_meta->value[i]; - else if( !strcasecmp( p_meta->name[i], VLC_META_NOW_PLAYING ) ) - psz_now_playing = p_meta->value[i]; - } + if( p_meta->psz_title ) psz_title = p_meta->psz_title; + if( p_meta->psz_publisher ) psz_provider = p_meta->psz_publisher; + if( p_meta->psz_nowplaying ) psz_now_playing = p_meta->psz_nowplaying; - if( !psz_name && !psz_now_playing ) + if( !psz_title && !psz_now_playing ) { free( psz_cat ); return; @@ -545,7 +598,7 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) p_pgrm = EsOutProgramAdd( out, i_group ); /* Update the description text of the program */ - if( psz_name && *psz_name ) + if( psz_title && *psz_title ) { vlc_value_t val; vlc_value_t text; @@ -556,24 +609,25 @@ 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_name, 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 ); } else { - text.psz_string = psz_name; + text.psz_string = psz_title; var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); } } if( psz_now_playing ) { + if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing ); p_pgrm->psz_now_playing = strdup(psz_now_playing); if( p_sys->p_pgrm == p_pgrm ) { - input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"), - VLC_META_NOW_PLAYING, "%s", psz_now_playing ); + vlc_meta_SetNowPlaying( p_input->input.p_item->p_meta, + psz_now_playing ); } } free( psz_cat ); @@ -622,6 +676,7 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) es->p_pgrm = p_pgrm; es_format_Copy( &es->fmt, fmt ); es->i_preroll_end = -1; + es->b_discontinuity = VLC_FALSE; switch( fmt->i_cat ) { @@ -631,6 +686,11 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) case VIDEO_ES: es->i_channel = p_sys->i_video; + if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base ) + vlc_ureduce( &es->fmt.video.i_frame_rate, + &es->fmt.video.i_frame_rate_base, + fmt->video.i_frame_rate, + fmt->video.i_frame_rate_base, 0 ); break; case SPU_ES: @@ -706,6 +766,17 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) return; } } + if( es->fmt.i_cat == SPU_ES ) + { + var_Get( p_input, "spu", &val ); + if( !var_GetBool( p_input, "spu" ) || + ( p_input->p_sout && !var_GetBool( p_input, "sout-spu" ) ) ) + { + msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x", + es->i_id ); + return; + } + } es->i_preroll_end = -1; es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); @@ -845,6 +916,14 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) if( p_sys->i_audio_last >= 0 ) i_wanted = p_sys->i_audio_last; + + if( p_sys->i_audio_id >= 0 ) + { + if( es->i_id == p_sys->i_audio_id ) + i_wanted = es->i_channel; + else + return; + } } else if( i_cat == SPU_ES ) { @@ -875,6 +954,14 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) } if( p_sys->i_sub_last >= 0 ) i_wanted = p_sys->i_sub_last; + + if( p_sys->i_sub_id >= 0 ) + { + if( es->i_id == p_sys->i_sub_id ) + i_wanted = es->i_channel; + else + return; + } } else if( i_cat == VIDEO_ES ) { @@ -930,6 +1017,7 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) 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; @@ -938,6 +1026,16 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) else i_delay = 0; + if( p_input->p_libvlc_global->b_stats ) + { + vlc_mutex_lock( &p_input->counters.counters_lock ); + stats_UpdateInteger( p_input, p_input->counters.p_demux_read, + p_block->i_buffer, &i_total ); + stats_UpdateFloat( p_input , p_input->counters.p_demux_bitrate, + (float)i_total, NULL ); + vlc_mutex_unlock( &p_input->counters.counters_lock ); + } + /* Mark preroll blocks */ if( es->i_preroll_end >= 0 ) { @@ -1000,6 +1098,8 @@ 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; + int i; /* We don't try to reselect */ if( es->p_dec ) @@ -1013,10 +1113,12 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) es->p_pgrm->i_es--; if( es->p_pgrm->i_es == 0 ) { - msg_Warn( p_sys->p_input, "Program doesn't contain anymore ES, " - "TODO cleaning ?" ); + msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" ); } + if( p_sys->p_es_audio == es || p_sys->p_es_video == es || + p_sys->p_es_sub == es ) b_reselect = VLC_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; if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL; @@ -1034,6 +1136,14 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es ) break; } + /* Re-select another track when needed */ + if( b_reselect ) + 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 ); + } + if( es->psz_language ) free( es->psz_language ); if( es->psz_language_code ) @@ -1319,6 +1429,12 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) EsOutProgramMeta( out, i_group, p_meta ); return VLC_SUCCESS; } + case ES_OUT_DEL_GROUP: + { + int i_group = (int)va_arg( args, int ); + + return EsOutProgramDel( out, i_group ); + } default: msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); @@ -1452,6 +1568,7 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) input_thread_t *p_input = p_sys->p_input; es_format_t *fmt = &es->fmt; char *psz_cat; + lldiv_t div; /* Add stream info */ asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ); @@ -1474,8 +1591,11 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) "%d", fmt->audio.i_channels ); if( fmt->audio.i_rate > 0 ) + { input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"), _("%d Hz"), fmt->audio.i_rate ); + var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate ); + } if( fmt->audio.i_bitspersample > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, @@ -1483,8 +1603,11 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) fmt->audio.i_bitspersample ); if( fmt->i_bitrate > 0 ) + { input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"), _("%d kb/s"), fmt->i_bitrate / 1000 ); + var_SetInteger( p_input, "bit-rate", fmt->i_bitrate ); + } break; case VIDEO_ES: @@ -1503,12 +1626,16 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) fmt->video.i_visible_width, fmt->video.i_visible_height); if( fmt->video.i_frame_rate > 0 && - fmt->video.i_frame_rate_base > 0 ) - input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Frame rate"), "%f", - (float)fmt->video.i_frame_rate / - fmt->video.i_frame_rate_base ); - break; + fmt->video.i_frame_rate_base > 0 ) + { + div = lldiv( (float)fmt->video.i_frame_rate / + fmt->video.i_frame_rate_base * 1000000, + 1000000 ); + input_Control( p_input, INPUT_ADD_INFO, psz_cat, + _("Frame rate"), I64Fd".%06u", + div.quot, (unsigned int )div.rem ); + } + break; case SPU_ES: input_Control( p_input, INPUT_ADD_INFO, psz_cat,