From 14106cb194892aa236d51c5837dda77e69663264 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Fri, 25 Mar 2005 09:16:24 +0000 Subject: [PATCH] * vlc_meta.h: added a few const * es_out: added ES_OUT_SET_GROUP_META to add on the fly meta for a program (it's not yet really clean). * demux/ts: parse SI tables of DVB (channel names + events), it needs last libdvbpsi svn (set TS_USE_DVB_SI to 1 in modules/demux/ts.c to use it). --- include/vlc_es_out.h | 2 + include/vlc_meta.h | 5 +- modules/demux/ts.c | 362 ++++++++++++++++++++++++++++++++++++++++++- src/input/es_out.c | 30 ++++ 4 files changed, 393 insertions(+), 6 deletions(-) diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h index 5af2b77fc8..c774212f2b 100644 --- a/include/vlc_es_out.h +++ b/include/vlc_es_out.h @@ -78,6 +78,8 @@ enum es_out_query_e /* Allow preroll of data (data with dts/pts < i_pts for one ES will be decoded but not displayed */ ES_OUT_SET_NEXT_DISPLAY_TIME, /* arg1=es_out_id_t* arg2=int64_t i_pts(microsecond) */ + /* Set meta data for group (dynamic) */ + ES_OUT_SET_GROUP_META, /* arg1=int i_group arg2=vlc_meta_t */ }; struct es_out_t diff --git a/include/vlc_meta.h b/include/vlc_meta.h index 419a19dc40..e7198fe543 100644 --- a/include/vlc_meta.h +++ b/include/vlc_meta.h @@ -108,7 +108,8 @@ static inline void vlc_meta_Delete( vlc_meta_t *m ) free( m ); } -static inline void vlc_meta_Add( vlc_meta_t *m, char *name, char *value ) +static inline void vlc_meta_Add( vlc_meta_t *m, + const char *name, const char *value ) { m->name = (char**)realloc( m->name, sizeof(char*) * ( m->i_meta + 1 ) ); m->name[m->i_meta] = strdup( name ); @@ -156,7 +157,7 @@ static inline void vlc_meta_Merge( vlc_meta_t *dst, vlc_meta_t *src ) } } -static inline char *vlc_meta_GetValue( vlc_meta_t *m, char *name ) +static inline char *vlc_meta_GetValue( vlc_meta_t *m, const char *name ) { int i; diff --git a/modules/demux/ts.c b/modules/demux/ts.c index 4c33e1ea8c..96f7438871 100644 --- a/modules/demux/ts.c +++ b/modules/demux/ts.c @@ -34,23 +34,35 @@ #include "../mux/mpeg/csa.h" +#define TS_USE_DVB_SI 0 + +/* Undef it to disable sdt/eit parsing */ +#define TS_USE_DVB_SI 0 + /* Include dvbpsi headers */ #ifdef HAVE_DVBPSI_DR_H # include +# include # include # include # include +# include +# include # include # include #else # include "dvbpsi.h" +# include "demux.h" # include "descriptor.h" # include "tables/pat.h" # include "tables/pmt.h" +# include "tables/sdt.h" +# include "tables/eit.h" # include "descriptors/dr.h" # include "psi.h" #endif + /* TODO: * - XXX: do not mark options message to be translated, they are too osbcure for now ... * - test it @@ -206,14 +218,27 @@ typedef struct typedef struct { - /* for special PAT case */ - dvbpsi_handle handle; + demux_t *p_demux; /* Hack */ + int i_table_id; + int i_version; + int i_service_id; +} ts_eit_psi_t; + +typedef struct +{ + /* for special PAT/SDT case */ + dvbpsi_handle handle; /* PAT/SDT/EIT */ int i_pat_version; + int i_sdt_version; /* For PMT */ int i_prg; ts_prg_psi_t **prg; + /* For EIT */ + int i_eit; + ts_eit_psi_t **eit; + } ts_psi_t; typedef struct @@ -280,6 +305,9 @@ struct demux_sys_t vlc_bool_t b_dvb_control; int i_dvb_program; vlc_list_t *p_programs_list; + + /* */ + vlc_bool_t b_meta; }; static int Demux ( demux_t *p_demux ); @@ -292,6 +320,9 @@ static int PIDFillFormat( ts_pid_t *pid, int i_stream_type ); static void PATCallBack( demux_t *, dvbpsi_pat_t * ); static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt ); +static void PSINewTableCallBack( demux_t *, dvbpsi_handle, + uint8_t i_table_id, uint16_t i_extension ); + static inline int PIDGet( block_t *p ) { @@ -382,6 +413,11 @@ static int Open( vlc_object_t *p_this ) memset( p_sys, 0, sizeof( demux_sys_t ) ); /* Init p_sys field */ +#if TS_USE_DVB_SI + p_sys->b_meta = VLC_TRUE; +#else + p_sys->b_meta = VLC_TRUE; +#endif p_sys->b_dvb_control = VLC_TRUE; p_sys->i_dvb_program = 0; for( i = 0; i < 8192; i++ ) @@ -402,6 +438,27 @@ static int Open( vlc_object_t *p_this ) PIDInit( pat, VLC_TRUE, NULL ); pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_demux ); +#if TS_USE_DVB_SI + if( p_sys->b_meta ) + { + ts_pid_t *sdt = &p_sys->pid[0x11]; + ts_pid_t *eit = &p_sys->pid[0x12]; + + PIDInit( sdt, VLC_TRUE, NULL ); + sdt->psi->handle = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, + p_demux ); + PIDInit( eit, VLC_TRUE, NULL ); + eit->psi->handle = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, + p_demux ); + if( p_sys->b_dvb_control ) + { + stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, + ACCESS_SET_PRIVATE_ID_STATE, 0x11, VLC_TRUE ); + stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, + ACCESS_SET_PRIVATE_ID_STATE, 0x12, VLC_TRUE ); + } + } +#endif /* Init PMT array */ p_sys->i_pmt = 0; @@ -594,6 +651,7 @@ static void Close( vlc_object_t *p_this ) if( pid->b_valid && pid->psi ) { + int j; switch( pid->i_pid ) { case 0: /* PAT */ @@ -603,6 +661,20 @@ static void Close( vlc_object_t *p_this ) case 1: /* CAT */ free( pid->psi ); break; + case 0x11: /* SDT */ + dvbpsi_DetachDemux( pid->psi->handle ); + free( pid->psi ); + break; + case 0x12: /* EIT */ + dvbpsi_DetachDemux( pid->psi->handle ); + for( j = 0; j < pid->psi->i_eit; j++ ) + { + free( pid->psi->eit[j] ); + } + if( pid->psi->i_eit ) + free( pid->psi->eit ); + free( pid->psi ); + break; default: PIDClean( p_demux->out, pid ); break; @@ -728,7 +800,7 @@ static int Demux( demux_t *p_demux ) { if( p_pid->psi ) { - if( p_pid->i_pid == 0 ) + if( p_pid->i_pid == 0 || p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 ) { dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer ); } @@ -990,11 +1062,14 @@ static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner ) if( !b_old_valid ) { pid->psi = malloc( sizeof( ts_psi_t ) ); + pid->psi->handle= NULL; pid->psi->i_prg = 0; pid->psi->prg = NULL; - pid->psi->handle= NULL; + pid->psi->i_eit = 0; + pid->psi->eit = NULL; } pid->psi->i_pat_version = -1; + pid->psi->i_sdt_version = -1; if( p_owner ) { ts_prg_psi_t *prg = malloc( sizeof( ts_prg_psi_t ) ); @@ -1949,6 +2024,285 @@ static vlc_bool_t DVBProgramIsSelected( demux_t *p_demux, uint16_t i_pgrm ) return VLC_FALSE; } +#if TS_USE_DVB_SI +static void SDTCallBack( demux_t *p_demux, dvbpsi_sdt_t *p_sdt ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + ts_pid_t *sdt = &p_sys->pid[0x11]; + dvbpsi_sdt_service_t *p_srv; + + msg_Dbg( p_demux, "SDTCallBack called" ); + + if( sdt->psi->i_sdt_version != -1 && + ( !p_sdt->b_current_next || + p_sdt->i_version == sdt->psi->i_sdt_version ) ) + { + dvbpsi_DeleteSDT( p_sdt ); + return; + } + + msg_Dbg( p_demux, "new SDT ts_id=%d version=%d current_next=%d network_id=%d", + p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next, p_sdt->i_network_id ); + + for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next ) + { + vlc_meta_t *p_meta = vlc_meta_New(); + dvbpsi_descriptor_t *p_dr; + + msg_Dbg( p_demux, " * service id=%d eit schedule=%d present=%d runing=%d free_ca=%d", + p_srv->i_service_id, + p_srv->b_eit_schedule, p_srv->b_eit_present, p_srv->i_running_status, + p_srv->b_free_ca ); + + for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) + { + if( p_dr->i_tag == 0x48 ) + { + static const char *psz_type[0x11] = { + "Reserved", + "Digital television service", + "Digital radio sound service", + "Teletext service", + "NVOD reference service", + "NVOD time-shifted service", + "Mosaic service", + "PAL coded signal", + "SECAM coded signal", + "D/D2-MAC", + "FM Radio", + "NTSC coded signal", + "Data broadcast service", + "Reserved for Common Interface Usage", + "RCS Map (see EN 301 790 [35])", + "RCS FLS (see EN 301 790 [35])", + "DVB MHP service" + }; + dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr ); + char str1[257]; + char str2[257]; + + memcpy( str1, pD->i_service_provider_name, pD->i_service_provider_name_length ); + str1[pD->i_service_provider_name_length] = '\0'; + memcpy( str2, pD->i_service_name, pD->i_service_name_length ); + str2[pD->i_service_name_length] = '\0'; + + msg_Dbg( p_demux, " - type=%d provider=%s name=%s", + pD->i_service_type, str1, str2 ); + + vlc_meta_Add( p_meta, "Name", str2 ); + vlc_meta_Add( p_meta, "Provider", str1 ); + if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 ) + vlc_meta_Add( p_meta, "Type", psz_type[pD->i_service_type] ); + } + } + + if( p_srv->i_running_status == 0x01 ) + vlc_meta_Add( p_meta, "Status", "Not running" ); + else if( p_srv->i_running_status == 0x02 ) + vlc_meta_Add( p_meta, "Status", "Starts in a few seconds" ); + else if( p_srv->i_running_status == 0x03 ) + vlc_meta_Add( p_meta, "Status", "Pausing" ); + else if( p_srv->i_running_status == 0x04 ) + vlc_meta_Add( p_meta, "Status", "Running" ); + else + vlc_meta_Add( p_meta, "Status", "Unknown" ); + + + es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, + p_srv->i_service_id, p_meta ); + vlc_meta_Delete( p_meta ); + } + + sdt->psi->i_sdt_version = p_sdt->i_version; + dvbpsi_DeleteSDT( p_sdt ); +} +#if 0 +static void DecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d ) +{ + int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 ); + int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 ); + + *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001); + + if( mp == 14 || mp == 15 ) + { + *p_y = yp + 1; + *p_m = mp - 1 + 12; + } + else + { + *p_y = yp; + *p_m = mp - 1; + } +} +#endif + +static void EITCallBack( ts_eit_psi_t *psi, dvbpsi_eit_t *p_eit ) +{ + demux_t *p_demux = psi->p_demux; + + dvbpsi_eit_event_t *p_evt; + + msg_Dbg( p_demux, "EITCallBack called" ); + if( psi->i_version != -1 && + ( !p_eit->b_current_next || psi->i_version == p_eit->i_version ) ) + { + dvbpsi_DeleteEIT( p_eit ); + return; + } + + msg_Dbg( p_demux, "new EIT service_id=%d version=%d current_next=%d ts_id=%d network_id=%d" + "segment_last_section_number=%d last_table_id=%d", + p_eit->i_service_id, p_eit->i_version, p_eit->b_current_next, p_eit->i_ts_id, + p_eit->i_network_id, p_eit->i_segment_last_section_number, p_eit->i_last_table_id ); + + for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next ) + { + vlc_meta_t *p_meta = vlc_meta_New(); + dvbpsi_descriptor_t *p_dr; + char *psz_cat = malloc( strlen("Event")+10 ); + char psz_start[15]; + char psz_duration[15]; + char psz_name[256]; + char psz_text[256]; + char *psz_extra = strdup(""); + char *psz_value; + + sprintf( psz_cat, "Event %d", p_evt->i_event_id ); + sprintf( psz_start, "%d%d:%d%d:%d%d", + (int)(p_evt->i_start_time >> 20)&0xf, + (int)(p_evt->i_start_time >> 16)&0xf, + (int)(p_evt->i_start_time >> 12)&0xf, + (int)(p_evt->i_start_time >> 8)&0xf, + (int)(p_evt->i_start_time >> 4)&0xf, + (int)(p_evt->i_start_time )&0xf ); + sprintf( psz_duration, "%d%d:%d%d:%d%d", + (p_evt->i_duration >> 20)&0xf, (p_evt->i_duration >> 16)&0xf, + (p_evt->i_duration >> 12)&0xf, (p_evt->i_duration >> 8)&0xf, + (p_evt->i_duration >> 4)&0xf, (p_evt->i_duration )&0xf ); + psz_name[0] = psz_text[0] = '\0'; + + msg_Dbg( p_demux, " * event id=%d start_time:mjd=%d %s duration=%s " + "running=%d free_ca=%d", + p_evt->i_event_id, + (int)(p_evt->i_start_time >> 24), + psz_start, psz_duration, + p_evt->i_running_status, p_evt->b_free_ca ); + + for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) + { + if( p_dr->i_tag == 0x4d ) + { + dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr ); + + if( pE ) + { + memcpy( psz_name, pE->i_event_name, pE->i_event_name_length); + psz_name[pE->i_event_name_length] = '\0'; + memcpy( psz_text, pE->i_text, pE->i_text_length ); + psz_text[pE->i_text_length] = '\0'; + + msg_Dbg( p_demux, " - short event lang=%3.3s '%s' : '%s'", + pE->i_iso_639_code, psz_name, psz_text ); + } + } + else if( p_dr->i_tag == 0x4e ) + { + dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr ); + char str1[257]; + char str2[257]; + + if( pE ) + { + int i; + msg_Dbg( p_demux, " - extended event lang=%3.3s", + pE->i_iso_639_code ); + for( i = 0; i < pE->i_entry_count; i++ ) + { + memcpy( str1, pE->i_item_description[i], + pE->i_item_description_length[i] ); + str1[pE->i_item_description_length[i]] = '\0'; + + memcpy( str1, pE->i_item[i], + pE->i_item_length[i] ); + str2[pE->i_item_length[i]] = '\0'; + + msg_Dbg( p_demux, " - desc='%s' item='%s'", str1, str2 ); + psz_extra = realloc( psz_extra, + strlen(psz_extra) + + strlen(str1) +strlen(str2) + 1 + 3 ); + strcat( psz_extra, str1 ); + strcat( psz_extra, "(" ); + strcat( psz_extra, str2 ); + strcat( psz_extra, ") " ); + } + + memcpy( str1, pE->i_text, pE->i_text_length ); + str1[pE->i_text_length] = '\0'; + msg_Dbg( p_demux, " - text='%s'", str1 ); + psz_extra = realloc( psz_extra, + strlen(psz_extra) + strlen(str1) + 2 ); + strcat( psz_extra, str1 ); + strcat( psz_extra, " " ); + } + } + else + { + msg_Dbg( p_demux, " - tag=0x%x(%d)", p_dr->i_tag, p_dr->i_tag ); + } + } + + asprintf( &psz_value, "%s: %s (+%s) %s (%s)", + psz_start, + psz_name, + psz_duration, + psz_text, psz_extra ); + vlc_meta_Add( p_meta, psz_cat, psz_value ); + free( psz_value ); + + es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, + p_eit->i_service_id, p_meta ); + vlc_meta_Delete( p_meta ); + + free( psz_cat ); + free( psz_extra ); + } + psi->i_version = p_eit->i_version; + dvbpsi_DeleteEIT( p_eit ); +} + +static void PSINewTableCallBack( demux_t *p_demux, dvbpsi_handle h, + uint8_t i_table_id, uint16_t i_extension ) +{ +#if 0 + msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)", + i_table_id, i_table_id, i_extension, i_extension ); +#endif + if( i_table_id == 0x42 ) + { + msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)", + i_table_id, i_table_id, i_extension, i_extension ); + + dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_demux ); + } + else if( i_table_id == 0x4e || /* Current/Following */ + ( i_table_id >= 0x50 && i_table_id <= 0x5f ) ) /* Schedule */ + { + ts_eit_psi_t *psi = malloc( sizeof(ts_eit_psi_t) ); + + msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)", + i_table_id, i_table_id, i_extension, i_extension ); + + psi->p_demux = p_demux; + psi->i_table_id = i_table_id; + psi->i_version = -1; + psi->i_service_id = i_extension; + + dvbpsi_AttachEIT( h, i_table_id, i_extension, (dvbpsi_eit_callback)EITCallBack, psi ); + } +} +#endif + static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt ) { demux_sys_t *p_sys = p_demux->p_sys; diff --git a/src/input/es_out.c b/src/input/es_out.c index 0ded702022..1eef5393d7 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -479,6 +479,28 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) return p_pgrm; } +/* EsOutProgramMeta: + */ +static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta ) +{ + es_out_sys_t *p_sys = out->p_sys; + input_thread_t *p_input = p_sys->p_input; + char *psz_cat = malloc( strlen(_("Program")) + 10 ); + 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++ ) + { + 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] ); + } + free( psz_cat ); +} + /* EsOutAdd: * Add an es_out */ @@ -1211,6 +1233,14 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) return VLC_SUCCESS; } + 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 * ); + + EsOutProgramMeta( out, i_group, p_meta ); + return VLC_SUCCESS; + } default: msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); -- 2.39.2