X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out.c;h=84f356d0da8dc50293611ae5bd994d89f80690bf;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=3e875da76a6dabfd066e48b077eb21ea69abc2fc;hpb=fb217d8936a52dc1373e8ff28e434745b83875af;p=vlc diff --git a/src/input/es_out.c b/src/input/es_out.c index 3e875da76a..84f356d0da 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,24 +19,27 @@ * * 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 +#include +#include +#include #include "input_internal.h" #include "vlc_playlist.h" #include "iso_lang.h" /* FIXME we should find a better way than including that */ -#include "../misc/iso-639_def.h" +#include "../text/iso-639_def.h" /***************************************************************************** * Local prototypes @@ -53,6 +57,11 @@ typedef struct /* Clock for this program */ input_clock_t clock; + char *psz_name; + char *psz_now_playing; + char *psz_publisher; + + vlc_epg_t *p_epg; } es_out_pgrm_t; struct es_out_id_t @@ -61,7 +70,7 @@ 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 */ @@ -97,8 +106,9 @@ 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; + int i_default_sub_id; /* As specified in container; if applicable */ char **ppsz_audio_language; char **ppsz_sub_language; @@ -127,6 +137,8 @@ static char *LanguageGetCode( const char *psz_lang ); static char **LanguageSplit( const char *psz_langs ); static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang ); +static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm ); + /***************************************************************************** * input_EsOutNew: *****************************************************************************/ @@ -142,6 +154,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) 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); p_sys->p_input = p_input; @@ -149,13 +162,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) p_sys->i_mode = ES_OUT_MODE_AUTO; - p_sys->i_pgrm = 0; - p_sys->pgrm = NULL; + TAB_INIT( p_sys->i_pgrm, p_sys->pgrm ); p_sys->p_pgrm = NULL; p_sys->i_id = 0; - p_sys->i_es = 0; - p_sys->es = NULL; + + TAB_INIT( p_sys->i_es, p_sys->es ); p_sys->i_audio = 0; p_sys->i_video = 0; @@ -168,25 +180,41 @@ es_out_t *input_EsOutNew( input_thread_t *p_input ) var_Get( p_input, "sub-track", &val ); p_sys->i_sub_last = val.i_int; - var_Get( p_input, "audio-language", &val ); - p_sys->ppsz_audio_language = LanguageSplit(val.psz_string); - if( p_sys->ppsz_audio_language ) + p_sys->i_default_sub_id = -1; + + if( !p_input->b_preparsing ) { - for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) - msg_Dbg( p_input, "select audio in language[%d] %s", - i, p_sys->ppsz_audio_language[i] ); - } - if( val.psz_string ) free( val.psz_string ); + var_Get( p_input, "audio-language", &val ); + p_sys->ppsz_audio_language = LanguageSplit(val.psz_string); + if( p_sys->ppsz_audio_language ) + { + for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) + msg_Dbg( p_input, "selected audio language[%d] %s", + i, p_sys->ppsz_audio_language[i] ); + } + if( val.psz_string ) free( val.psz_string ); - var_Get( p_input, "sub-language", &val ); - p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); - if( p_sys->ppsz_sub_language ) + var_Get( p_input, "sub-language", &val ); + p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); + if( p_sys->ppsz_sub_language ) + { + for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) + msg_Dbg( p_input, "selected subtitle language[%d] %s", + i, p_sys->ppsz_sub_language[i] ); + } + if( val.psz_string ) free( val.psz_string ); + } + else { - for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) - msg_Dbg( p_input, "select subtitle in language[%d] %s", - i, p_sys->ppsz_sub_language[i] ); + p_sys->ppsz_sub_language = NULL; + p_sys->ppsz_audio_language = NULL; } - 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; @@ -236,12 +264,22 @@ void input_EsOutDelete( es_out_t *out ) if( 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++ ) { - free( p_sys->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 ); + if( p_pgrm->p_epg ) + vlc_epg_Delete( p_pgrm->p_epg ); + + free( p_pgrm ); } - if( p_sys->pgrm ) - free( p_sys->pgrm ); + TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm ); free( p_sys ); free( out ); @@ -264,7 +302,7 @@ es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id ) return NULL; } -void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio ) +void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_flush, vlc_bool_t b_audio ) { es_out_sys_t *p_sys = out->p_sys; int i; @@ -276,11 +314,17 @@ void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio ) /* 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 ); - } + input_DecoderDiscontinuity( es->p_dec, b_flush ); } } +void input_EsOutSetRate( es_out_t *out ) +{ + es_out_sys_t *p_sys = out->p_sys; + int i; + + for( i = 0; i < p_sys->i_pgrm; i++ ) + input_ClockSetRate( p_sys->p_input, &p_sys->pgrm[i]->clock ); +} void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) { @@ -317,7 +361,7 @@ static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, input_thread_t *p_input = p_sys->p_input; vlc_value_t val, text; - char *psz_var; + const char *psz_var; if( es->fmt.i_cat == AUDIO_ES ) psz_var = "audio-es"; @@ -353,8 +397,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 ); } @@ -363,7 +409,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 ); @@ -441,6 +488,12 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ) EsOutSelect( out, p_sys->es[i], VLC_FALSE ); } + /* Update now playing */ + input_item_SetNowPlaying( p_input->p->input.p_item, + p_pgrm->psz_now_playing ); + input_item_SetPublisher( p_input->p->input.p_item, + p_pgrm->psz_publisher ); + var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } @@ -459,7 +512,11 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) p_pgrm->i_id = i_group; p_pgrm->i_es = 0; p_pgrm->b_selected = VLC_FALSE; - input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average ); + 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 ); /* Append it */ TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); @@ -479,25 +536,280 @@ 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 = NULL; + + 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 ); + if( p_pgrm->p_epg ) + vlc_epg_Delete( p_pgrm->p_epg ); + 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 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 ); + else + asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ); + return psz; +} + static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) { es_out_sys_t *p_sys = out->p_sys; + 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_cat; + const char *psz_title = NULL; + const char *psz_provider = NULL; int i; 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++ ) + /* Check against empty meta data (empty for what we handle) */ + if( !vlc_meta_Get( p_meta, vlc_meta_Title) && + !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) && + !vlc_meta_Get( p_meta, vlc_meta_Publisher) && + vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 ) + return; + /* Find program */ + 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 ) + p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */ + + /* */ + psz_title = vlc_meta_Get( p_meta, vlc_meta_Title); + psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher); + + /* Update the description text of the program */ + if( psz_title && *psz_title ) { - msg_Dbg( p_input, " - %s = %s", p_meta->name[i], p_meta->value[i] ); + vlc_value_t val; + vlc_value_t text; + if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) ) + { + char *psz_cat = EsOutProgramGetMetaName( p_pgrm ); + + /* Remove old entries */ + input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL ); + /* TODO update epg name */ + free( psz_cat ); + } + if( p_pgrm->psz_name ) free( p_pgrm->psz_name ); + p_pgrm->psz_name = strdup( psz_title ); + + /* ugly but it works */ + val.i_int = i_group; + var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL ); + + 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 ); + } + else + { + text.psz_string = (char *)psz_title; + var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text ); + } + } + + psz_cat = EsOutProgramGetMetaName( p_pgrm ); + if( psz_provider ) + { + if( p_sys->p_pgrm == p_pgrm ) + input_item_SetPublisher( p_input->p->input.p_item, psz_provider ); + input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider ); + } + char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags ); + for( i = 0; ppsz_all_keys[i]; i++ ) + { + input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]), + vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) ); + free( ppsz_all_keys[i] ); + } + free( ppsz_all_keys ); + + free( psz_cat ); +} + +static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src ) +{ + int i; + + /* Add new event */ + 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; + 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; + break; + } + if( p_dst->pp_event[j]->i_start > p_evt->i_start ) + break; + } + if( b_add ) + { + vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) ); + if( !p_copy ) + break; + memset( p_copy, 0, sizeof(vlc_epg_event_t) ); + p_copy->i_start = p_evt->i_start; + p_copy->i_duration = p_evt->i_duration; + p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL; + p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL; + p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL; + TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j ); + } + } + /* Update current */ + vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 ); + + /* Keep only 1 old event */ + if( p_dst->p_current ) + { + while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current ) + TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] ); + } +} + +static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg ) +{ + 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; + char *psz_cat; + int i; + + /* Find program */ + 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 ) + p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */ + + /* Merge EPG */ + if( !p_pgrm->p_epg ) + p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name ); + vlc_epg_Merge( p_pgrm->p_epg, p_epg ); + + /* Update info */ + psz_cat = EsOutProgramGetMetaName( p_pgrm ); +#ifdef HAVE_LOCALTIME_R + char *psz_epg; + if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 ) + psz_epg = NULL; + input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL ); + msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name ); + for( i = 0; i < p_pgrm->p_epg->i_event; i++ ) + { + const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i]; + time_t t_start = (time_t)p_evt->i_start; + struct tm tm_start; + char psz_start[128]; + + localtime_r( &t_start, &tm_start ); + + snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec ); + if( p_evt->psz_short_description || p_evt->psz_description ) + input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s", + p_evt->psz_name, + p_evt->i_duration/60/60, (p_evt->i_duration/60)%60, + p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description ); + else + input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)", + p_evt->psz_name, + p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 ); + } + free( psz_epg ); +#endif + /* Update now playing */ + if( 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 ); + + if( p_pgrm == p_sys->p_pgrm ) + input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing ); + + if( p_pgrm->psz_now_playing ) + { input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _(p_meta->name[i]), "%s", p_meta->value[i] ); + input_MetaTypeToLocalizedString(vlc_meta_NowPlaying), + p_pgrm->psz_now_playing ); } + else + { + input_Control( p_input, INPUT_DEL_INFO, psz_cat, + input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) ); + } + free( psz_cat ); } @@ -553,6 +865,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: @@ -599,7 +916,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val; - char *psz_var; + const char *psz_var; if( es->p_dec ) { @@ -610,7 +927,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES ) { if( !var_GetBool( p_input, "video" ) || - ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) ) + ( p_input->p->p_sout && !var_GetBool( p_input, "sout-video" ) ) ) { msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", es->i_id ); @@ -621,13 +938,24 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) { var_Get( p_input, "audio", &val ); if( !var_GetBool( p_input, "audio" ) || - ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) ) + ( p_input->p->p_sout && !var_GetBool( p_input, "sout-audio" ) ) ) { msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", es->i_id ); return; } } + 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" ) ) ) + { + 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 ); @@ -656,7 +984,7 @@ static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update ) es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val; - char *psz_var; + const char *psz_var; if( es->p_dec == NULL ) { @@ -767,6 +1095,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 ) { @@ -795,8 +1131,22 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force ) i_wanted = es->i_channel; } + else if( p_sys->i_default_sub_id >= 0 ) + { + if( es->i_id == p_sys->i_default_sub_id ) + i_wanted = es->i_channel; + } + 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 ) { @@ -852,6 +1202,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; @@ -860,6 +1211,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->b_stats ) + { + vlc_mutex_lock( &p_input->p->counters.counters_lock ); + stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read, + p_block->i_buffer, &i_total ); + stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate, + (float)i_total, NULL ); + vlc_mutex_unlock( &p_input->p->counters.counters_lock ); + } + /* Mark preroll blocks */ if( es->i_preroll_end >= 0 ) { @@ -873,18 +1234,23 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) es->i_preroll_end = -1; } - /* +11 -> avoid null value with non null dts/pts */ - if( p_block->i_dts > 0 ) + 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 + 11 ) * 9 / 100 ) + i_delay; + 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; } - if( p_block->i_pts > 0 ) + else if( p_block->i_pts > 0 ) { p_block->i_pts = - input_ClockGetTS( p_input, &p_pgrm->clock, - ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay; + input_ClockGetTS( p_input, &p_pgrm->clock, p_block->i_pts ) + i_delay; } if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) ) { @@ -900,11 +1266,13 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) } } - p_block->i_rate = p_input->i_rate; + p_block->i_rate = p_input->p->i_rate; /* TODO handle mute */ - if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || - p_input->i_rate == INPUT_RATE_DEFAULT ) ) + 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_DecoderDecode( es->p_dec, p_block ); } @@ -922,10 +1290,20 @@ 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 ) + { + while( !out->p_sys->p_input->b_die && es->p_dec ) + { + if( input_DecoderEmpty( es->p_dec ) ) + break; + msleep( 20*1000 ); + } EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm ); + } if( es->p_pgrm == p_sys->p_pgrm ) EsOutESVarUpdate( out, es, VLC_TRUE ); @@ -935,10 +1313,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; @@ -956,6 +1336,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 ) @@ -1103,7 +1491,51 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) } } } + { + playlist_t * p_playlist = pl_Yield( p_sys->p_input ); + PL_LOCK; + p_playlist->gc_date = mdate(); + vlc_cond_signal( &p_playlist->object_wait ); + PL_UNLOCK; + pl_Release( p_playlist ); + } + return VLC_SUCCESS; + + case ES_OUT_SET_DEFAULT: + { + es = (es_out_id_t*) va_arg( args, es_out_id_t * ); + + if( es == NULL ) + { + /*p_sys->i_default_video_id = -1;*/ + /*p_sys->i_default_audio_id = -1;*/ + p_sys->i_default_sub_id = -1; + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) ) + { + /*p_sys->i_default_video_id = -1;*/ + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) ) + { + /*p_sys->i_default_audio_id = -1;*/ + } + else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) ) + { + p_sys->i_default_sub_id = -1; + } + else + { + /*if( es->fmt.i_cat == VIDEO_ES ) + p_sys->i_default_video_id = es->i_id; + else + if( es->fmt.i_cat == AUDIO_ES ) + p_sys->i_default_audio_id = es->i_id; + else*/ + if( es->fmt.i_cat == SPU_ES ) + p_sys->i_default_sub_id = es->i_id; + } return VLC_SUCCESS; + } case ES_OUT_SET_PCR: case ES_OUT_SET_GROUP_PCR: @@ -1134,9 +1566,7 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) i_pcr = (int64_t)va_arg( args, int64_t ); /* search program */ - /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */ - input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, - (i_pcr + 11 ) * 9 / 100); + input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, i_pcr ); return VLC_SUCCESS; } @@ -1154,8 +1584,7 @@ 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 + 11 ) * 9 / 100 ); + &p_sys->p_pgrm->clock, i_ts ); return VLC_SUCCESS; } return VLC_EGENERIC; @@ -1228,8 +1657,10 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) if( !es || !es->p_dec ) 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; - input_DecoderPreroll( es->p_dec, i_date ); return VLC_SUCCESS; } @@ -1241,6 +1672,20 @@ 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_SET_GROUP_EPG: + { + int i_group = (int)va_arg( args, int ); + vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * ); + + EsOutProgramEpg( out, i_group, p_epg ); + 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" ); @@ -1374,6 +1819,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 ); @@ -1393,20 +1839,26 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) if( fmt->audio.i_channels > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"), - "%d", fmt->audio.i_channels ); + "%u", 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 ); + _("%u 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, - _("Bits per sample"), "%d", + _("Bits per sample"), "%u", 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 ); + _("%u kb/s"), fmt->i_bitrate / 1000 ); + var_SetInteger( p_input, "bit-rate", fmt->i_bitrate ); + } break; case VIDEO_ES: @@ -1415,22 +1867,26 @@ static void EsOutAddInfo( es_out_t *out, es_out_id_t *es ) if( fmt->video.i_width > 0 && fmt->video.i_height > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Resolution"), "%dx%d", + _("Resolution"), "%ux%u", fmt->video.i_width, fmt->video.i_height ); if( fmt->video.i_visible_width > 0 && fmt->video.i_visible_height > 0 ) input_Control( p_input, INPUT_ADD_INFO, psz_cat, - _("Display resolution"), "%dx%d", + _("Display resolution"), "%ux%u", 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,