#include <vlc_es_out.h>
#include <vlc_block.h>
#include <vlc_aout.h>
+#include <vlc_fourcc.h>
#include "input_internal.h"
#include "clock.h"
int i_es;
bool b_selected;
+ bool b_scrambled;
/* Clock for this program */
input_clock_t *p_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
int i_id;
es_out_pgrm_t *p_pgrm;
+ /* */
+ bool b_scrambled;
+
/* Channel in the track type */
int i_channel;
es_format_t fmt;
int64_t i_audio_delay;
int64_t i_spu_delay;
- /* Rate used for clock */
+ /* Clock configuration */
+ mtime_t i_pts_delay;
+ int i_cr_average;
int i_rate;
/* */
static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date );
static void EsOutProgramsChangeRate( es_out_t *out );
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 );
}
return -1;
}
-
+static inline bool EsFmtIsTeletext( const es_format_t *p_fmt )
+{
+ return p_fmt->i_cat == SPU_ES && p_fmt->i_codec == VLC_CODEC_TELETEXT;
+}
/*****************************************************************************
* input_EsOutNew:
*****************************************************************************/
es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
{
- vlc_value_t val;
- int i;
-
es_out_t *out = malloc( sizeof( *out ) );
if( !out )
return NULL;
p_sys->i_sub = 0;
/* */
- var_Get( p_input, "audio-track", &val );
- p_sys->i_audio_last = val.i_int;
+ p_sys->i_audio_last = var_GetInteger( p_input, "audio-track" );
- var_Get( p_input, "sub-track", &val );
- p_sys->i_sub_last = val.i_int;
+ p_sys->i_sub_last = var_GetInteger( p_input, "sub-track" );
p_sys->i_default_sub_id = -1;
if( !p_input->b_preparsing )
{
- var_Get( p_input, "audio-language", &val );
- p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
+ char *psz_string;
+
+ psz_string = var_GetString( p_input, "audio-language" );
+ p_sys->ppsz_audio_language = LanguageSplit( psz_string );
if( p_sys->ppsz_audio_language )
{
- for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
+ for( int 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] );
}
- free( val.psz_string );
+ free( psz_string );
- var_Get( p_input, "sub-language", &val );
- p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
+ psz_string = var_GetString( p_input, "sub-language" );
+ p_sys->ppsz_sub_language = LanguageSplit( psz_string );
if( p_sys->ppsz_sub_language )
{
- for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
+ for( int 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] );
}
- free( val.psz_string );
+ free( psz_string );
}
else
{
p_sys->ppsz_audio_language = NULL;
}
- var_Get( p_input, "audio-track-id", &val );
- p_sys->i_audio_id = val.i_int;
+ p_sys->i_audio_id = var_GetInteger( p_input, "audio-track-id" );
- var_Get( p_input, "sub-track-id", &val );
- p_sys->i_sub_id = val.i_int;
+ p_sys->i_sub_id = var_GetInteger( p_input, "sub-track-id" );
p_sys->p_es_audio = NULL;
p_sys->p_es_video = NULL;
p_sys->i_pause_date = -1;
p_sys->i_rate = i_rate;
+ p_sys->i_pts_delay = 0;
+ p_sys->i_cr_average = 0;
p_sys->b_buffering = true;
p_sys->i_buffering_extra_initial = 0;
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 );
free( p_pgrm );
}
TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
+
+ input_item_SetEpgOffline( p_sys->p_input->p->p_item );
+ input_SendEventMetaEpg( p_sys->p_input );
+
vlc_mutex_destroy( &p_sys->lock );
free( p_sys );
/* 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 ||
+ * FIXME for !p_input->p->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */
+ if( !p_input->p->b_can_pace_control ||
p_input->p->b_out_pace_control ||
p_sys->b_buffering )
return 0;
if( b_record )
{
- char *psz_path = var_CreateGetString( p_input, "input-record-path" );
- if( !psz_path || *psz_path == '\0' )
+ char *psz_path = var_CreateGetNonEmptyString( p_input, "input-record-path" );
+ if( !psz_path )
{
- free( psz_path );
- psz_path = strdup( config_GetHomeDir() );
+ if( var_CountChoices( p_input, "video-es" ) )
+ psz_path = config_GetUserDir( VLC_VIDEOS_DIR );
+ else if( var_CountChoices( p_input, "audio-es" ) )
+ psz_path = config_GetUserDir( VLC_MUSIC_DIR );
+ else
+ psz_path = config_GetUserDir( VLC_DOWNLOAD_DIR );
}
char *psz_sout = NULL; // TODO conf
if( !i_ret )
{
/* FIXME pcr != exactly what wanted */
- const mtime_t i_used = /*(i_stream_duration - p_sys->p_input->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
+ const mtime_t i_used = /*(i_stream_duration - p_sys->p_input->p->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
i_date -= i_used;
}
p_sys->i_buffering_extra_initial = 0;
es_out_sys_t *p_sys = out->p_sys;
p_sys->i_rate = i_rate;
-
- if( !p_sys->b_paused )
- EsOutProgramsChangeRate( out );
+ EsOutProgramsChangeRate( out );
}
static void EsOutChangePosition( es_out_t *out )
input_DecoderStartBuffering( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderStartBuffering( p_es->p_dec );
+ input_DecoderStartBuffering( p_es->p_dec_record );
}
for( int i = 0; i < p_sys->i_pgrm; i++ )
if( p_sys->i_preroll_end >= 0 )
i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
- const mtime_t i_buffering_duration = p_sys->p_input->i_pts_delay +
+ const mtime_t i_buffering_duration = p_sys->i_pts_delay +
i_preroll_duration +
p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
(int)(mdate() - i_decoder_buffering_start)/1000 );
/* Here is a good place to destroy unused vout with every demuxer */
- input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+ input_resource_TerminateVout( p_sys->p_input->p->p_resource );
/* */
const mtime_t i_wakeup_delay = 10*1000; /* FIXME CLEANUP thread wake up time*/
input_DecoderStopBuffering( p_es->p_dec );
if( p_es->p_dec_record )
- input_DecoderStopBuffering( p_es->p_dec );
+ input_DecoderStopBuffering( p_es->p_dec_record );
}
}
static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
}
}
}
+
+static bool EsOutIsExtraBufferingAllowed( es_out_t *out )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+
+ size_t i_size = 0;
+ 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 )
+ i_size += input_DecoderGetFifoSize( p_es->p_dec );
+ if( p_es->p_dec_record )
+ i_size += input_DecoderGetFifoSize( p_es->p_dec_record );
+ }
+ //fprintf( stderr, "----- EsOutIsExtraBufferingAllowed =% 5d kbytes -- ", i_size / 1024 );
+
+ /* TODO maybe we want to be able to tune it ? */
+#if defined(OPTIMIZE_MEMORY)
+ const size_t i_level_high = 500000; /* 0.5 Mbytes */
+#else
+ const size_t i_level_high = 10000000; /* 10 Mbytes */
+#endif
+ return i_size < i_level_high;
+}
+
static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
{
es_out_sys_t *p_sys = out->p_sys;
if( i_ret )
return;
- p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->p_input->i_pts_delay; /* FIXME < 0 ? */
+ p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
p_sys->i_buffering_extra_system =
p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
}
}
const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
- i_delay = p_sys->p_input->i_pts_delay - i_consumed;
+ i_delay = p_sys->i_pts_delay - i_consumed;
}
if( i_delay < 0 )
return 0;
return i_delay;
}
-static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
+static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id,
+ const es_format_t *fmt, const char *psz_language,
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;
if( b_delete )
{
- /* TODO it should probably be a list */
- if( b_teletext )
- input_SendEventTeletext( p_sys->p_input, -1 );
+ if( EsFmtIsTeletext( fmt ) )
+ input_SendEventTeletextDel( p_sys->p_input, i_id );
- input_SendEventEsDel( p_input, SPU_ES, i_id );
+ input_SendEventEsDel( p_input, fmt->i_cat, i_id );
return;
}
{
if( psz_language && *psz_language )
{
- text.psz_string = malloc( strlen( fmt->psz_description) +
- strlen( psz_language ) + 10 );
- sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
- psz_language );
+ if( asprintf( &text.psz_string, "%s - [%s]", fmt->psz_description,
+ psz_language ) == -1 )
+ text.psz_string = NULL;
}
else text.psz_string = strdup( fmt->psz_description );
}
}
input_SendEventEsAdd( p_input, fmt->i_cat, i_id, text.psz_string );
-
- free( text.psz_string );
-
- if( b_teletext )
+ if( EsFmtIsTeletext( fmt ) )
{
- /* TODO it should probably be a list */
- if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 )
- input_SendEventTeletext( p_sys->p_input, i_id );
+ char psz_page[3+1];
+ snprintf( psz_page, sizeof(psz_page), "%d%2.2x",
+ fmt->subs.teletext.i_magazine,
+ fmt->subs.teletext.i_page );
+ input_SendEventTeletextAdd( p_sys->p_input,
+ i_id, fmt->subs.teletext.i_magazine >= 0 ? psz_page : NULL );
}
+
+ free( text.psz_string );
}
static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
input_SendEventEsDel( p_input, AUDIO_ES, -1 );
input_SendEventEsDel( p_input, VIDEO_ES, -1 );
input_SendEventEsDel( p_input, SPU_ES, -1 );
+ input_SendEventTeletextDel( p_input, -1 );
+ input_SendEventProgramScrambled( p_input, p_pgrm->i_id, p_pgrm->b_scrambled );
/* TODO event */
var_SetInteger( p_input, "teletext-es", -1 );
p_pgrm->i_id = i_group;
p_pgrm->i_es = 0;
p_pgrm->b_selected = false;
+ p_pgrm->b_scrambled = false;
p_pgrm->psz_name = NULL;
p_pgrm->psz_now_playing = NULL;
p_pgrm->psz_publisher = NULL;
- p_pgrm->p_epg = NULL;
- p_pgrm->p_clock = input_clock_New( p_input->p->i_cr_average, p_sys->i_rate );
+ p_pgrm->p_clock = input_clock_New( p_sys->i_rate );
if( !p_pgrm->p_clock )
{
free( p_pgrm );
return NULL;
}
+ if( p_sys->b_paused )
+ input_clock_ChangePause( p_pgrm->p_clock, p_sys->b_paused, p_sys->i_pause_date );
+ input_clock_SetJitter( p_pgrm->p_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
/* Append it */
TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
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 );
/* Update "program" variable */
return VLC_SUCCESS;
}
+/* EsOutProgramFind
+ */
+static es_out_pgrm_t *EsOutProgramFind( es_out_t *p_out, int i_group )
+{
+ es_out_sys_t *p_sys = p_out->p_sys;
+
+ for( int i = 0; i < p_sys->i_pgrm; i++ )
+ {
+ if( p_sys->pgrm[i]->i_id == i_group )
+ return p_sys->pgrm[i];
+ }
+ return EsOutProgramAdd( p_out, i_group );
+}
+
/* EsOutProgramMeta:
*/
static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
return psz;
}
-static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
+static void EsOutProgramMeta( es_out_t *out, int i_group, const vlc_meta_t *p_meta )
{
es_out_sys_t *p_sys = out->p_sys;
- es_out_pgrm_t *p_pgrm = NULL;
+ es_out_pgrm_t *p_pgrm;
input_thread_t *p_input = p_sys->p_input;
char *psz_cat;
const char *psz_title = NULL;
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 )
+ vlc_meta_GetExtraCount( p_meta ) <= 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 */
+ p_pgrm = EsOutProgramFind( out, i_group );
+ if( !p_pgrm )
+ return;
/* */
psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
/* Remove old entries */
input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
- /* TODO update epg name */
+ /* TODO update epg name ?
+ * TODO update scrambled info name ? */
free( psz_cat );
}
free( p_pgrm->psz_name );
{
input_SendEventProgramDel( p_input, i_group );
input_SendEventProgramAdd( p_input, i_group, psz_text );
-
+ if( p_sys->p_pgrm == p_pgrm )
+ input_SendEventProgramSelect( p_input, i_group );
free( psz_text );
}
}
input_item_SetPublisher( p_input->p->p_item, psz_provider );
input_SendEventMeta( p_input );
}
- input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher), psz_provider );
}
- char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
+ char ** ppsz_all_keys = vlc_meta_CopyExtraNames(p_meta );
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] ) );
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat,
+ vlc_gettext(ppsz_all_keys[i]),
+ vlc_meta_GetExtra( p_meta, 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];
- 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 = false;
- break;
- }
- if( p_dst->pp_event[j]->i_start > p_evt->i_start )
- break;
- }
- if( b_add )
- {
- vlc_epg_event_t *p_copy = calloc( 1, sizeof(vlc_epg_event_t) );
- if( !p_copy )
- break;
- 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 )
+static void EsOutProgramEpg( es_out_t *out, int i_group, const 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;
+ input_item_t *p_item = p_input->p->p_item;
+ es_out_pgrm_t *p_pgrm;
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 );
+ p_pgrm = EsOutProgramFind( out, i_group );
+ if( !p_pgrm )
+ return;
/* 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
+ msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, psz_cat );
+
+ /* Merge EPG */
+ vlc_epg_t epg;
+
+ epg = *p_epg;
+ epg.psz_name = psz_cat;
+
+ input_item_SetEpg( p_item, &epg );
+ input_SendEventMetaEpg( p_sys->p_input );
+
/* Update 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 );
+
+ vlc_mutex_lock( &p_item->lock );
+ for( int i = 0; i < p_item->i_epg; i++ )
+ {
+ const vlc_epg_t *p_tmp = p_item->pp_epg[i];
+
+ if( p_tmp->psz_name && !strcmp(p_tmp->psz_name, psz_cat) )
+ {
+ if( p_tmp->p_current && p_tmp->p_current->psz_name && *p_tmp->p_current->psz_name )
+ p_pgrm->psz_now_playing = strdup( p_tmp->p_current->psz_name );
+ break;
+ }
+ }
+ vlc_mutex_unlock( &p_item->lock );
if( p_pgrm == p_sys->p_pgrm )
{
if( p_pgrm->psz_now_playing )
{
input_Control( p_input, INPUT_ADD_INFO, psz_cat,
- input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
+ vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying),
p_pgrm->psz_now_playing );
}
else
{
input_Control( p_input, INPUT_DEL_INFO, psz_cat,
- input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
+ vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying) );
}
free( psz_cat );
}
+static void EsOutProgramUpdateScrambled( es_out_t *p_out, es_out_pgrm_t *p_pgrm )
+{
+ es_out_sys_t *p_sys = p_out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+ bool b_scrambled = false;
+
+ for( int i = 0; i < p_sys->i_es; i++ )
+ {
+ if( p_sys->es[i]->p_pgrm == p_pgrm && p_sys->es[i]->b_scrambled )
+ {
+ b_scrambled = true;
+ break;
+ }
+ }
+ if( !p_pgrm->b_scrambled == !b_scrambled )
+ return;
+
+ p_pgrm->b_scrambled = b_scrambled;
+ char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
+
+ if( b_scrambled )
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Scrambled"), _("Yes") );
+ else
+ input_Control( p_input, INPUT_DEL_INFO, psz_cat, _("Scrambled") );
+
+ input_SendEventProgramScrambled( p_input, p_pgrm->i_id, b_scrambled );
+}
+
+static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta )
+{
+ es_out_sys_t *p_sys = p_out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+
+ input_item_t *p_item = input_GetItem( p_input );
+
+ char *psz_title = NULL;
+ char *psz_arturl = input_item_GetArtURL( p_item );
+
+ vlc_mutex_lock( &p_item->lock );
+
+ if( vlc_meta_Get( p_meta, vlc_meta_Title ) && !p_item->b_fixed_name )
+ psz_title = strdup( vlc_meta_Get( p_meta, vlc_meta_Title ) );
+
+ vlc_meta_Merge( p_item->p_meta, p_meta );
+
+ if( !psz_arturl || *psz_arturl == '\0' )
+ {
+ const char *psz_tmp = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL );
+ if( psz_tmp )
+ psz_arturl = strdup( psz_tmp );
+ }
+ vlc_mutex_unlock( &p_item->lock );
+
+ if( psz_arturl && *psz_arturl )
+ {
+ input_item_SetArtURL( p_item, psz_arturl );
+
+ if( !strncmp( psz_arturl, "attachment://", strlen("attachment") ) )
+ {
+ /* Don't look for art cover if sout
+ * XXX It can change when sout has meta data support */
+ if( p_out->b_sout && !p_input->b_preparsing )
+ input_item_SetArtURL( p_item, "" );
+ else
+ input_ExtractAttachmentAndCacheArt( p_input );
+ }
+ }
+ free( psz_arturl );
+
+ if( psz_title )
+ {
+ input_item_SetName( p_item, psz_title );
+ free( psz_title );
+ }
+ input_item_SetPreparsed( p_item, true );
+
+ input_SendEventMeta( p_input );
+ /* TODO handle sout meta ? */
+}
+
/* EsOutAdd:
* Add an es_out
*/
return NULL;
}
- es_out_id_t *es = malloc( sizeof( *es ) );
- es_out_pgrm_t *p_pgrm = NULL;
+ es_out_id_t *es = malloc( sizeof( *es ) );
+ es_out_pgrm_t *p_pgrm;
int i;
if( !es )
vlc_mutex_lock( &p_sys->lock );
/* Search the program */
- for( i = 0; i < p_sys->i_pgrm; i++ )
- {
- if( fmt->i_group == p_sys->pgrm[i]->i_id )
- {
- p_pgrm = p_sys->pgrm[i];
- break;
- }
- }
- if( p_pgrm == NULL )
+ p_pgrm = EsOutProgramFind( out, fmt->i_group );
+ if( !p_pgrm )
{
- /* Create a new one */
- p_pgrm = EsOutProgramAdd( out, fmt->i_group );
+ vlc_mutex_unlock( &p_sys->lock );
+ free( es );
+ return NULL;
}
/* Increase ref count for program */
es_format_Copy( &es->fmt, fmt );
if( es->fmt.i_id < 0 )
es->fmt.i_id = out->p_sys->i_id;
+ if( !es->fmt.i_original_fourcc )
+ es->fmt.i_original_fourcc = es->fmt.i_codec;
+ es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
+
es->i_id = es->fmt.i_id;
es->i_meta_id = out->p_sys->i_id;
+ es->b_scrambled = false;
switch( es->fmt.i_cat )
{
EsOutUpdateInfo( out, es, &es->fmt, NULL );
+ if( es->b_scrambled )
+ EsOutProgramUpdateScrambled( out, es->p_pgrm );
+
vlc_mutex_unlock( &p_sys->lock );
return es;
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
- vlc_value_t val;
if( EsIsSelected( es ) )
{
}
else if( es->fmt.i_cat == AUDIO_ES )
{
- var_Get( p_input, "audio", &val );
if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
{
msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
}
if( es->fmt.i_cat == SPU_ES )
{
- var_Get( p_input, "spu", &val );
if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
{
msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
/* Mark it as selected */
input_SendEventEsSelect( p_input, es->fmt.i_cat, es->i_id );
+ input_SendEventTeletextSelect( p_input, EsFmtIsTeletext( &es->fmt ) ? es->i_id : -1 );
}
static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
if( !b_update )
return;
- /* Update var */
- if( es->p_dec == NULL )
- return;
-
/* Mark it as unselected */
input_SendEventEsSelect( p_input, es->fmt.i_cat, -1 );
+ if( EsFmtIsTeletext( &es->fmt ) )
+ input_SendEventTeletextSelect( p_input, -1 );
}
/**
break;
}
}
- var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
+ var_FreeList( &val, NULL );
}
else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
{
p_block->i_buffer, &i_total );
stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
(float)i_total, NULL );
+
+ /* Update number of corrupted data packats */
+ if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
+ {
+ stats_UpdateInteger( p_input, p_input->p->counters.p_demux_corrupted,
+ 1, NULL );
+ }
+ /* Update number of discontinuities */
+ if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
+ {
+ stats_UpdateInteger( p_input, p_input->p->counters.p_demux_discontinuity,
+ 1, NULL );
+ }
vlc_mutex_unlock( &p_input->p->counters.counters_lock );
}
if( p_sys->i_preroll_end >= 0 )
{
int64_t i_date = p_block->i_pts;
- if( i_date <= 0 )
+ if( p_block->i_pts <= VLC_TS_INVALID )
i_date = p_block->i_dts;
if( i_date < p_sys->i_preroll_end )
return VLC_SUCCESS;
}
+ /* Check for sout mode */
+ if( out->b_sout )
+ {
+ /* FIXME review this, proper lock may be missing */
+ if( p_input->p->p_sout->i_out_pace_nocontrol > 0 &&
+ p_input->p->b_out_pace_control )
+ {
+ msg_Dbg( p_input, "switching to sync mode" );
+ p_input->p->b_out_pace_control = false;
+ }
+ else if( p_input->p->p_sout->i_out_pace_nocontrol <= 0 &&
+ !p_input->p->b_out_pace_control )
+ {
+ msg_Dbg( p_input, "switching to async mode" );
+ p_input->p->b_out_pace_control = true;
+ }
+ }
+
/* Decode */
if( es->p_dec_record )
{
block_t *p_dup = block_Duplicate( p_block );
if( p_dup )
- input_DecoderDecode( es->p_dec_record, p_dup );
+ input_DecoderDecode( es->p_dec_record, p_dup,
+ p_input->p->b_out_pace_control );
}
- input_DecoderDecode( es->p_dec, p_block );
+ input_DecoderDecode( es->p_dec, p_block,
+ p_input->p->b_out_pace_control );
es_format_t fmt_dsc;
vlc_meta_t *p_meta_dsc;
input_DecoderIsCcPresent( es->p_dec, pb_cc );
for( int 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', ' '),
- };
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] );
+ es_format_Init( &fmt, SPU_ES, EsOutFourccClosedCaptions[i] );
fmt.i_group = es->fmt.i_group;
if( asprintf( &fmt.psz_description,
_("Closed captions %u"), 1 + i ) == -1 )
TAB_REMOVE( p_sys->i_es, p_sys->es, es );
+ /* Update program */
es->p_pgrm->i_es--;
if( es->p_pgrm->i_es == 0 )
- {
msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
- }
+ if( es->b_scrambled )
+ EsOutProgramUpdateScrambled( out, es->p_pgrm );
+
+ /* */
if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
p_sys->p_es_sub == es ) b_reselect = true;
break;
}
if( i >= p_sys->i_es )
- input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+ input_resource_TerminateVout( p_sys->p_input->p->p_resource );
}
p_sys->b_active = b;
return VLC_SUCCESS;
int i_group = 0;
int64_t i_pcr;
+ /* Search program */
if( i_query == ES_OUT_SET_PCR )
{
p_pgrm = p_sys->p_pgrm;
+ if( !p_pgrm )
+ p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
}
else
{
- int i;
i_group = (int)va_arg( args, int );
- 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;
- }
- }
+ p_pgrm = EsOutProgramFind( out, i_group );
}
- if( p_pgrm == NULL )
- p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
+ if( !p_pgrm )
+ return VLC_EGENERIC;
i_pcr = (int64_t)va_arg( args, int64_t );
- /* search program
- * TODO do not use mdate() but proper stream acquisition date */
+ if( i_pcr <= VLC_TS_INVALID )
+ {
+ msg_Err( p_sys->p_input, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
+ return VLC_EGENERIC;
+ }
+
+ /* TODO do not use mdate() but proper stream acquisition date */
+ bool b_late;
input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
- p_sys->p_input->b_can_pace_control || p_sys->b_buffering, i_pcr, mdate() );
- /* Check buffering state on master clock update */
- if( p_sys->b_buffering && p_pgrm == p_sys->p_pgrm )
- EsOutDecodersStopBuffering( out, false );
+ &b_late,
+ p_sys->p_input->p->b_can_pace_control || p_sys->b_buffering,
+ EsOutIsExtraBufferingAllowed( out ),
+ i_pcr, mdate() );
+
+ if( p_pgrm == p_sys->p_pgrm )
+ {
+ if( p_sys->b_buffering )
+ {
+ /* Check buffering state on master clock update */
+ EsOutDecodersStopBuffering( out, false );
+ }
+ else if( b_late && ( !out->b_sout ||
+ !p_sys->p_input->p->b_out_pace_control ) )
+ {
+ mtime_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_clock );
+ /* Avoid dangerously high value */
+ const mtime_t i_pts_delay_max = 30000000;
+ if( i_pts_delay > i_pts_delay_max )
+ i_pts_delay = __MAX( i_pts_delay_max, p_sys->i_pts_delay );
+
+ /* Force a rebufferization when we are too late */
+ msg_Err( p_sys->p_input,
+ "ES_OUT_SET_(GROUP_)PCR is called too late, increasing pts_delay to %d ms",
+ (int)(i_pts_delay/1000) );
+
+ /* It is not really good, as we throw away already buffered data
+ * TODO have a mean to correctly reenter bufferization */
+ es_out_Control( out, ES_OUT_RESET_PCR );
+
+ es_out_Control( out, ES_OUT_SET_JITTER, i_pts_delay, p_sys->i_cr_average );
+ }
+ }
return VLC_SUCCESS;
}
EsOutChangePosition( out );
return VLC_SUCCESS;
- case ES_OUT_GET_TS:
- if( p_sys->p_pgrm )
- {
- 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_clock_GetTS( p_sys->p_pgrm->p_clock, NULL,
- p_sys->p_input->i_pts_delay, i_ts );
- return VLC_SUCCESS;
- }
- return VLC_EGENERIC;
-
case ES_OUT_SET_GROUP:
{
int j;
if( p_fmt->i_extra )
{
es->fmt.i_extra = p_fmt->i_extra;
- es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
+ es->fmt.p_extra = xrealloc( 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 )
#else
es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
es->p_dec->fmt_in.p_extra =
- realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
+ xrealloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
memcpy( es->p_dec->fmt_in.p_extra,
p_fmt->p_extra, p_fmt->i_extra );
#endif
return VLC_SUCCESS;
}
+ case ES_OUT_SET_ES_SCRAMBLED_STATE:
+ {
+ es = (es_out_id_t*) va_arg( args, es_out_id_t * );
+ bool b_scrambled = (bool)va_arg( args, int );
+
+ if( !es->b_scrambled != !b_scrambled )
+ {
+ es->b_scrambled = b_scrambled;
+ EsOutProgramUpdateScrambled( out, es->p_pgrm );
+ }
+ return VLC_SUCCESS;
+ }
+
case ES_OUT_SET_NEXT_DISPLAY_TIME:
{
const int64_t i_date = (int64_t)va_arg( args, int64_t );
case ES_OUT_SET_GROUP_META:
{
int i_group = (int)va_arg( args, int );
- vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
+ const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
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 * );
+ const vlc_epg_t *p_epg = va_arg( args, const 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 );
}
+ case ES_OUT_SET_META:
+ {
+ const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
+
+ EsOutMeta( out, p_meta );
+ return VLC_SUCCESS;
+ }
+
case ES_OUT_GET_WAKE_UP:
{
mtime_t *pi_wakeup = (mtime_t*)va_arg( args, mtime_t* );
/* Clean up vout after user action (in active mode only).
* FIXME it does not work well with multiple video windows */
if( p_sys->b_active )
- input_ressource_TerminateVout( p_sys->p_input->p->p_ressource );
+ input_resource_TerminateVout( p_sys->p_input->p->p_resource );
return i_ret;
}
mtime_t i_time = (mtime_t)va_arg( args, mtime_t );
mtime_t i_length = (mtime_t)va_arg( args, mtime_t );
- /* Fix for buffering delay */
- const mtime_t i_delay = EsOutGetBuffering( out );
+ input_SendEventLength( p_sys->p_input, i_length );
+
+ if( !p_sys->b_buffering )
+ {
+ mtime_t i_delay;
+
+ /* Fix for buffering delay */
+ if( !out->b_sout || !p_sys->p_input->p->b_out_pace_control )
+ i_delay = EsOutGetBuffering( out );
+ else
+ i_delay = 0;
+
+ i_time -= i_delay;
+ if( i_time < 0 )
+ i_time = 0;
+
+ if( i_length > 0 )
+ f_position -= (double)i_delay / i_length;
+ if( f_position < 0 )
+ f_position = 0;
- i_time -= i_delay;
- if( i_time < 0 )
- i_time = 0;
+ input_SendEventPosition( p_sys->p_input, f_position, i_time );
+ }
+ return VLC_SUCCESS;
+ }
+ case ES_OUT_SET_JITTER:
+ {
+ mtime_t i_pts_delay = (mtime_t)va_arg( args, mtime_t );
+ int i_cr_average = (int)va_arg( args, int );
- if( i_length > 0 )
- f_position -= (double)i_delay / i_length;
- if( f_position < 0 )
- f_position = 0;
+ if( i_pts_delay == p_sys->i_pts_delay &&
+ i_cr_average == p_sys->i_cr_average )
+ return VLC_SUCCESS;
+
+ p_sys->i_pts_delay = i_pts_delay;
+ p_sys->i_cr_average = i_cr_average;
- input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length );
+ for( int i = 0; i < p_sys->i_pgrm; i++ )
+ input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
+ i_pts_delay, i_cr_average );
+ return VLC_SUCCESS;
+ }
+
+ case ES_OUT_GET_PCR_SYSTEM:
+ {
+ if( p_sys->b_buffering )
+ return VLC_EGENERIC;
+
+ es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
+ if( !p_pgrm )
+ return VLC_EGENERIC;
+
+ mtime_t *pi_system = va_arg( args, mtime_t *);
+ *pi_system = input_clock_GetSystemOrigin( p_pgrm->p_clock );
return VLC_SUCCESS;
}
if( psz_lang == NULL || *psz_lang == '\0' )
return strdup("??");
- for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
+ for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
{
if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
!strcasecmp( pl->psz_native_name, psz_lang ) ||
break;
}
- if( pl->psz_iso639_1 != NULL )
+ if( pl->psz_eng_name != NULL )
return strdup( pl->psz_iso639_1 );
return strdup("??");
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Original ID"),
"%d", es->i_id );
- input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
- "%.4s", (char*)&p_fmt_es->i_codec );
+ const char *psz_codec_description =
+ vlc_fourcc_GetDescription( p_fmt_es->i_cat, p_fmt_es->i_codec );
+ const vlc_fourcc_t i_codec_fourcc = p_fmt_es->i_original_fourcc ?: p_fmt_es->i_codec;
+ if( psz_codec_description )
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
+ "%s (%.4s)", psz_codec_description, (char*)&i_codec_fourcc );
+ else
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
+ "%.4s", (char*)&i_codec_fourcc );
if( es->psz_language && *es->psz_language )
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
if( fmt->audio.i_physical_channels & AOUT_CHAN_PHYSMASK )
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
- "%s", aout_FormatPrintChannels( &fmt->audio ) );
+ "%s", _( aout_FormatPrintChannels( &fmt->audio ) ) );
else if( fmt->audio.i_channels > 0 )
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
"%u", fmt->audio.i_channels );
/* Append generic meta */
if( p_meta )
{
- char **ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
+ char **ppsz_all_keys = vlc_meta_CopyExtraNames( p_meta );
for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
{
char *psz_key = ppsz_all_keys[i];
- char *psz_value = vlc_dictionary_value_for_key( &p_meta->extra_tags, psz_key );
+ const char *psz_value = vlc_meta_GetExtra( p_meta, psz_key );
if( psz_value )
- input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(psz_key), _(psz_value) );
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat,
+ vlc_gettext(psz_key), vlc_gettext(psz_value) );
free( psz_key );
}
free( ppsz_all_keys );