/***************************************************************************** * ts_psi_eit.c : TS demuxer SI handling ***************************************************************************** * Copyright (C) 2014-2016 - VideoLAN Authors * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include /* FromCharset, for EIT */ #include #ifndef _DVBPSI_DVBPSI_H_ #include #endif #include #include #include #include /* EIT support */ #include /* TDT support */ #include #include #include "ts_si.h" #include "ts_arib.h" #include "ts_decoders.h" #include "ts_pid.h" #include "ts_streams_private.h" #include "ts.h" #include "../dvb-text.h" #ifdef HAVE_ARIBB24 #include #endif #include #include #include #ifndef SI_DEBUG_EIT #define SI_DEBUG_TIMESHIFT(t) #else static time_t i_eit_debug_offset = 0; #define SI_DEBUG_TIMESHIFT(t) \ do {\ if( i_eit_debug_offset == 0 )\ i_eit_debug_offset = time(NULL) - t;\ t = t + i_eit_debug_offset;\ } while(0); #endif static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, uint16_t i_extension, void *p_pid_cbdata ); void ts_si_Packet_Push( ts_pid_t *p_pid, const uint8_t *p_pktbuffer ) { if( likely(p_pid->type == TYPE_SI) && dvbpsi_decoder_present( p_pid->u.p_si->handle ) ) dvbpsi_packet_push( p_pid->u.p_si->handle, (uint8_t *) p_pktbuffer ); } static char *EITConvertToUTF8( demux_t *p_demux, const unsigned char *psz_instring, size_t i_length, bool b_broken ) { demux_sys_t *p_sys = p_demux->p_sys; #ifdef HAVE_ARIBB24 if( p_sys->standard == TS_STANDARD_ARIB ) { if ( !p_sys->arib.p_instance ) p_sys->arib.p_instance = arib_instance_new( p_demux ); if ( !p_sys->arib.p_instance ) return NULL; arib_decoder_t *p_decoder = arib_get_decoder( p_sys->arib.p_instance ); if ( !p_decoder ) return NULL; char *psz_outstring = NULL; size_t i_out; i_out = i_length * 4; psz_outstring = (char*) calloc( i_out + 1, sizeof(char) ); if( !psz_outstring ) return NULL; arib_initialize_decoder( p_decoder ); i_out = arib_decode_buffer( p_decoder, psz_instring, i_length, psz_outstring, i_out ); arib_finalize_decoder( p_decoder ); return psz_outstring; } #else VLC_UNUSED(p_sys); #endif /* Deal with no longer broken providers (no switch byte but sending ISO_8859-1 instead of ISO_6937) without removing them from the broken providers table (keep the entry for correctly handling recorded TS). */ b_broken = b_broken && i_length && *psz_instring > 0x20; if( b_broken ) return FromCharset( "ISO_8859-1", psz_instring, i_length ); return vlc_from_EIT( psz_instring, i_length ); } #define attach_SI_decoders(i_pid, name, member) do {\ ts_pid_t *pid = GetPID(p_sys, i_pid);\ if ( PIDSetup( p_demux, TYPE_SI, pid, NULL ) )\ {\ if( !ts_attach_SI_Tables_Decoders( pid ) )\ {\ msg_Err( p_demux, "Can't attach SI table decoders for pid %d", i_pid );\ PIDRelease( p_demux, pid );\ }\ else\ {\ sdt->u.p_si->member = pid;\ SetPIDFilter( p_demux->p_sys, pid, true );\ msg_Dbg( p_demux, " * pid=%d listening for "name, i_pid );\ }\ }\ } while(0)\ 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 = GetPID(p_sys, TS_SI_SDT_PID); ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat; dvbpsi_sdt_service_t *p_srv; msg_Dbg( p_demux, "SDTCallBack called" ); if( p_sys->es_creation != CREATE_ES || !p_sdt->b_current_next || p_sdt->i_version == sdt->u.p_si->i_version ) { dvbpsi_sdt_delete( p_sdt ); return; } /* First callback */ if( sdt->u.p_si->i_version == -1 ) { attach_SI_decoders( TS_SI_EIT_PID, "EIT", eitpid ); attach_SI_decoders( TS_SI_TDT_PID, "TDT", tdtpid ); if( p_sys->standard == TS_STANDARD_ARIB ) attach_SI_decoders( TS_ARIB_CDT_PID, "CDT", cdtpid ); } msg_Dbg( p_demux, "new SDT ts_id=%"PRIu16" version=%"PRIu8" current_next=%d " "network_id=%"PRIu16, p_sdt->i_extension, p_sdt->i_version, p_sdt->b_current_next, p_sdt->i_network_id ); p_sys->b_broken_charset = false; for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next ) { ts_pmt_t *p_pmt = ts_pat_Get_pmt( p_pat, p_srv->i_service_id ); vlc_meta_t *p_meta; dvbpsi_descriptor_t *p_dr; const char *psz_type = NULL; const char *psz_status = NULL; msg_Dbg( p_demux, " * service id=%"PRIu16" eit schedule=%d present=%d " "running=%"PRIu8" 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 ); if( p_sys->vdr.i_service && p_srv->i_service_id != p_sys->vdr.i_service ) { msg_Dbg( p_demux, " * service id=%d skipped (not declared in vdr header)", p_sys->vdr.i_service ); continue; } p_meta = vlc_meta_New(); 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 *ppsz_type[17] = { "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 = NULL; char *str2 = NULL; /* Workarounds for broadcasters with broken EPG */ if( p_sdt->i_network_id == 133 ) p_sys->b_broken_charset = true; /* SKY DE & BetaDigital use ISO8859-1 */ /* List of providers using ISO8859-1 */ static const char ppsz_broken_providers[][8] = { "CSAT", /* CanalSat FR */ "GR1", /* France televisions */ "MULTI4", /* NT1 */ "MR5", /* France 2/M6 HD */ "" }; for( int i = 0; *ppsz_broken_providers[i]; i++ ) { const size_t i_length = strlen(ppsz_broken_providers[i]); if( pD->i_service_provider_name_length == i_length && !strncmp( (char *)pD->i_service_provider_name, ppsz_broken_providers[i], i_length ) ) p_sys->b_broken_charset = true; } /* FIXME: Digital+ ES also uses ISO8859-1 */ str1 = EITConvertToUTF8(p_demux, pD->i_service_provider_name, pD->i_service_provider_name_length, p_sys->b_broken_charset ); str2 = EITConvertToUTF8(p_demux, pD->i_service_name, pD->i_service_name_length, p_sys->b_broken_charset ); msg_Dbg( p_demux, " - type=%"PRIu8" provider=%s name=%s", pD->i_service_type, str1, str2 ); if( !str2 || strcmp( "Service01", str2 ) ) /* Skip bogus libav/ffmpeg SDT */ { vlc_meta_SetTitle( p_meta, str2 ); vlc_meta_SetPublisher( p_meta, str1 ); if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 ) psz_type = ppsz_type[pD->i_service_type]; } free( str1 ); free( str2 ); } else if( p_sys->standard == TS_STANDARD_ARIB && p_dr->i_tag == TS_ARIB_DR_LOGO_TRANSMISSION && p_pmt ) { ts_arib_logo_dr_t *p_logodr = ts_arib_logo_dr_Decode( p_dr->p_data, p_dr->i_length ); if( p_logodr ) { if( p_logodr->i_transmission_mode == 0 ) { p_pmt->arib.i_logo_id = p_logodr->i_logo_id; p_pmt->arib.i_download_id = p_logodr->i_download_data_id; } else if( p_logodr->i_transmission_mode == 1 ) { p_pmt->arib.i_logo_id = p_logodr->i_logo_id; } else /* TODO simple logo identifier */ { } if( p_pmt->arib.i_logo_id > -1 ) { char *psz_name; if( asprintf( &psz_name, "attachment://onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]", p_sdt->i_network_id, p_logodr->i_logo_id, TS_ARIB_LOGO_TYPE_HD_LARGE ) > -1 ) { vlc_meta_SetArtURL( p_meta, psz_name ); vlc_meta_AddExtra( p_meta, "ARTURL", psz_name ); free( psz_name ); } } ts_arib_logo_dr_Delete( p_logodr ); } } } if( p_srv->i_running_status >= 0x01 && p_srv->i_running_status <= 0x04 ) { static const char *ppsz_status[5] = { "Unknown", "Not running", "Starts in a few seconds", "Pausing", "Running" }; psz_status = ppsz_status[p_srv->i_running_status]; } if( psz_type ) vlc_meta_AddExtra( p_meta, "Type", psz_type ); if( psz_status ) vlc_meta_AddExtra( p_meta, "Status", psz_status ); es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, p_srv->i_service_id, p_meta ); vlc_meta_Delete( p_meta ); } sdt->u.p_si->i_version = p_sdt->i_version; dvbpsi_sdt_delete( p_sdt ); } static void EITDecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d ) { const int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 ); const int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 ); const int c = ( mp == 14 || mp == 15 ) ? 1 : 0; *p_y = 1900 + yp + c*1; *p_m = mp - 1 - c*12; *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001); } #define CVT_FROM_BCD(v) ((((v) >> 4)&0xf)*10 + ((v)&0xf)) static int64_t EITConvertStartTime( uint64_t i_date ) { const int i_mjd = i_date >> 24; struct tm tm; tm.tm_hour = CVT_FROM_BCD(i_date >> 16); tm.tm_min = CVT_FROM_BCD(i_date >> 8); tm.tm_sec = CVT_FROM_BCD(i_date ); /* if all 40 bits are 1, the start is unknown */ if( i_date == UINT64_C(0xffffffffff) ) return -1; EITDecodeMjd( i_mjd, &tm.tm_year, &tm.tm_mon, &tm.tm_mday ); tm.tm_year -= 1900; tm.tm_mon--; tm.tm_isdst = 0; return timegm( &tm ); } static int EITConvertDuration( uint32_t i_duration ) { return CVT_FROM_BCD(i_duration >> 16) * 3600 + CVT_FROM_BCD(i_duration >> 8 ) * 60 + CVT_FROM_BCD(i_duration ); } #undef CVT_FROM_BCD static void TDTCallBack( demux_t *p_demux, dvbpsi_tot_t *p_tdt ) { demux_sys_t *p_sys = p_demux->p_sys; p_sys->i_network_time = EITConvertStartTime( p_tdt->i_utc_time ); p_sys->i_network_time_update = time(NULL); if( p_sys->standard == TS_STANDARD_ARIB ) { /* All ARIB-B10 times are in JST time, where DVB is UTC. (spec being a fork) DVB TOT should include DTS offset in descriptor 0x58 (including DST), but as there's no DST in JAPAN (since Showa 27/1952) and considering that no-one seems to send TDT or desc 0x58, falling back on fixed offset is safe */ p_sys->i_network_time += 9 * 3600; } /* Because libdvbpsi is broken and deduplicating timestamp tables, * we need to reset it to get next timestamp callback */ ts_pid_t *pid = ts_pid_Get( &p_sys->pids, TS_SI_TDT_PID ); dvbpsi_decoder_reset( pid->u.p_si->handle->p_decoder, true ); dvbpsi_tot_delete(p_tdt); es_out_Control( p_demux->out, ES_OUT_SET_EPG_TIME, (int64_t) p_sys->i_network_time ); } static void EITExtractDrDescItems( demux_t *p_demux, const dvbpsi_extended_event_dr_t *pE, vlc_epg_event_t *p_evt ) { demux_sys_t *p_sys = p_demux->p_sys; if( pE->i_entry_count ) { char **ppsz_prev = NULL; /* Continued items from previous descriptor (ARIB) */ if( p_evt->i_description_items > 0 ) ppsz_prev = &p_evt->description_items[p_evt->i_description_items - 1].psz_value; for( int i = 0; i < pE->i_entry_count; i++ ) { char *psz_key = NULL; /* Continued items have NULL key */ const bool b_appending = ( pE->i_item_description_length[i] == 0 ); if( !b_appending ) { void *p_realloc = NULL; if( (size_t)p_evt->i_description_items < SIZE_MAX / sizeof(*p_evt->description_items) ) { p_realloc = realloc( p_evt->description_items, (p_evt->i_description_items + 1) * sizeof(*p_evt->description_items) ); } if( !p_realloc ) { free( psz_key ); break; } p_evt->description_items = p_realloc; psz_key = EITConvertToUTF8( p_demux, pE->i_item_description[i], pE->i_item_description_length[i], p_sys->b_broken_charset ); if( !psz_key ) { ppsz_prev = NULL; continue; } } else if( ppsz_prev == NULL ) continue; char *psz_itm = EITConvertToUTF8( p_demux, pE->i_item[i], pE->i_item_length[i], p_sys->b_broken_charset ); if( !psz_itm ) { free( psz_key ); ppsz_prev = NULL; continue; } msg_Dbg( p_demux, " - desc='%s' item='%s'", psz_key, psz_itm ); if( b_appending ) { /* Continued items */ size_t i_total = strlen(*ppsz_prev) + strlen(psz_itm) + 1; char *psz_realloc = realloc( *ppsz_prev, i_total ); if( psz_realloc ) { *ppsz_prev = psz_realloc; strcat( *ppsz_prev, psz_itm ); } free( psz_itm ); } else { p_evt->description_items[p_evt->i_description_items].psz_key = psz_key; p_evt->description_items[p_evt->i_description_items].psz_value = psz_itm; ppsz_prev = &p_evt->description_items[p_evt->i_description_items].psz_value; p_evt->i_description_items++; } } } } static void EITCallBack( demux_t *p_demux, dvbpsi_eit_t *p_eit ) { demux_sys_t *p_sys = p_demux->p_sys; const dvbpsi_eit_event_t *p_evt; uint64_t i_runevt = 0; uint64_t i_fallbackevt = 0; vlc_epg_t *p_epg; msg_Dbg( p_demux, "EITCallBack called" ); if( !p_eit->b_current_next ) { dvbpsi_eit_delete( p_eit ); return; } msg_Dbg( p_demux, "new EIT service_id=%"PRIu16" version=%"PRIu8" current_next=%d " "ts_id=%"PRIu16" network_id=%"PRIu16" segment_last_section_number=%"PRIu8" " "last_table_id=%"PRIu8, p_eit->i_extension, 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 ); /* Use table ID for segmenting our EPG tables updates. 1 table id has 256 sections which * represents 8 segments of 32 sections each. Thus a max of 24 hours per table ID * (Should be even better with tableid+segmentid compound if dvbpsi would export segment id) * see TS 101 211, 4.1.4.2.1 */ p_epg = vlc_epg_New( p_eit->i_table_id, p_eit->i_extension ); if( !p_epg ) { dvbpsi_eit_delete( p_eit ); return; } for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next ) { dvbpsi_descriptor_t *p_dr; int64_t i_start; int i_duration; i_start = EITConvertStartTime( p_evt->i_start_time ); SI_DEBUG_TIMESHIFT(i_start); i_duration = EITConvertDuration( p_evt->i_duration ); /* We have to fix ARIB-B10 as all timestamps are JST */ if( p_sys->standard == TS_STANDARD_ARIB ) { /* See comments on TDT callback */ i_start += 9 * 3600; } msg_Dbg( p_demux, " * event id=%"PRIu16" start_time:%"PRId64" duration=%d " "running=%"PRIu8" free_ca=%d", p_evt->i_event_id, i_start, i_duration, p_evt->i_running_status, p_evt->b_free_ca ); /* */ if( i_start <= 0 ) continue; vlc_epg_event_t *p_epgevt = vlc_epg_event_New( p_evt->i_event_id, i_start, i_duration ); if( !p_epgevt ) continue; if( !vlc_epg_AddEvent( p_epg, p_epgevt ) ) { vlc_epg_event_Delete( p_epgevt ); continue; } for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) { switch(p_dr->i_tag) { case 0x4d: { dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr ); /* Only take first description, as we don't handle language-info for epg atm*/ if( pE ) { char **ppsz = &p_epgevt->psz_name; free( *ppsz ); *ppsz = EITConvertToUTF8( p_demux, pE->i_event_name, pE->i_event_name_length, p_sys->b_broken_charset ); ppsz = &p_epgevt->psz_short_description; free( *ppsz ); *ppsz = EITConvertToUTF8( p_demux, pE->i_text, pE->i_text_length, p_sys->b_broken_charset ); msg_Dbg( p_demux, " - short event lang=%3.3s '%s' : '%s'", pE->i_iso_639_code, p_epgevt->psz_name, *ppsz ); } } break; case 0x4e: { dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr ); if( pE ) { msg_Dbg( p_demux, " - extended event lang=%3.3s [%"PRIu8"/%"PRIu8"]", pE->i_iso_639_code, pE->i_descriptor_number, pE->i_last_descriptor_number ); if( pE->i_text_length > 0 ) { char *psz_text = EITConvertToUTF8( p_demux, pE->i_text, pE->i_text_length, p_sys->b_broken_charset ); if( psz_text ) { msg_Dbg( p_demux, " - text='%s'", psz_text ); if( p_epgevt->psz_description ) { size_t i_total = strlen( p_epgevt->psz_description ) + strlen( psz_text ) + 1; char *psz_realloc = realloc( p_epgevt->psz_description, i_total ); if( psz_realloc ) { p_epgevt->psz_description = psz_realloc; strcat( psz_realloc, psz_text ); } free( psz_text ); } else { p_epgevt->psz_description = psz_text; } } } EITExtractDrDescItems( p_demux, pE, p_epgevt ); } } break; case 0x55: { dvbpsi_parental_rating_dr_t *pR = dvbpsi_DecodeParentalRatingDr( p_dr ); if ( pR ) { int i_min_age = 0; for ( int i = 0; i < pR->i_ratings_number; i++ ) { const dvbpsi_parental_rating_t *p_rating = & pR->p_parental_rating[ i ]; if ( p_rating->i_rating > 0x00 && p_rating->i_rating <= 0x0F ) { if ( p_rating->i_rating + 3 > i_min_age ) i_min_age = p_rating->i_rating + 3; msg_Dbg( p_demux, " - parental control set to %d years", i_min_age ); } } p_epgevt->i_rating = i_min_age; } } break; default: msg_Dbg( p_demux, " - event unknown dr 0x%"PRIx8"(%"PRIu8")", p_dr->i_tag, p_dr->i_tag ); break; } } switch ( p_evt->i_running_status ) { case TS_SI_RUNSTATUS_RUNNING: if( i_runevt == 0 ) i_runevt = i_start; break; case TS_SI_RUNSTATUS_UNDEFINED: { if( i_fallbackevt == 0 && i_start <= p_sys->i_network_time && p_sys->i_network_time < i_start + i_duration ) i_fallbackevt = i_start; break; } default: break; } } /* Update "now playing" field */ if( i_runevt || i_fallbackevt ) vlc_epg_SetCurrent( p_epg, (i_runevt) ? i_runevt : i_fallbackevt ); if( p_epg->i_event > 0 ) { if( p_epg->b_present && p_epg->p_current ) { ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat; ts_pmt_t *p_pmt = ts_pat_Get_pmt(p_pat, p_eit->i_extension); if(p_pmt) { p_pmt->eit.i_event_start = p_epg->p_current->i_start; p_pmt->eit.i_event_length = p_epg->p_current->i_duration; } } p_epg->b_present = (p_eit->i_table_id == 0x4e); es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_extension, p_epg ); } vlc_epg_Delete( p_epg ); dvbpsi_eit_delete( p_eit ); } static void ARIB_CDT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section, void *p_cdtpid ) { VLC_UNUSED(p_cdtpid); demux_t *p_demux = (demux_t *) p_handle->p_sys; demux_sys_t *p_sys = p_demux->p_sys; const ts_pat_t *p_pat = GetPID(p_demux->p_sys, 0)->u.p_pat; while( p_section ) { const uint8_t *p_data = p_section->p_payload_start; size_t i_data = p_section->p_payload_end - p_section->p_payload_start; if( i_data < (6U + 7 + 1) || p_data[2] != TS_ARIB_CDT_DATA_TYPE_LOGO ) continue; uint16_t i_onid = (p_data[0] << 8) | p_data[1]; uint16_t i_dr_len = ((p_data[3] & 0x0F) << 4) | p_data[4]; if( i_data < i_dr_len + (6U + 7 + 1) ) continue; /* STD-B21 A.5.4 (Japanese spec only) */ const uint8_t *p_dmb = &p_data[5 + i_dr_len]; size_t i_dmb = i_data - 5 - i_dr_len; while( i_dmb > 7 ) { uint8_t i_logo_type = p_dmb[0]; uint16_t i_logo_id = ((p_dmb[1] & 0x01) << 8) | p_dmb[2]; uint16_t i_size = (p_dmb[5] << 8) | p_dmb[6]; if( 7U + i_size > i_dmb ) break; for( int i=0; iprograms.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; if( p_pmt->arib.i_logo_id == i_logo_id && i_logo_type == TS_ARIB_LOGO_TYPE_HD_LARGE ) { char *psz_name; if( asprintf( &psz_name, "onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]", i_onid, i_logo_id, i_logo_type ) > -1 ) { uint8_t *p_png; size_t i_png; if( !vlc_dictionary_has_key( &p_sys->attachments, psz_name ) && ts_arib_inject_png_palette( &p_dmb[7], i_size, &p_png, &i_png ) ) { input_attachment_t *p_att = vlc_input_attachment_New( psz_name, "image/png", NULL, p_png, i_png ); if( p_att ) { vlc_dictionary_insert( &p_sys->attachments, psz_name, p_att ); p_demux->info.i_update |= INPUT_UPDATE_META; } free( p_png ); } free( psz_name ); } } } i_dmb -= 7 + i_size; p_dmb += 7 + i_size; } p_section = p_section->p_next; } } static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, uint16_t i_extension, void *p_pid_cbdata ) { assert( h ); ts_pid_t *p_pid = (ts_pid_t *) p_pid_cbdata; demux_t *p_demux = (demux_t *) h->p_sys; #if 0 msg_Dbg( p_demux, "SINewTableCallback: table 0x%"PRIx8"(%"PRIu16") ext=0x%"PRIx16"(%"PRIu16")", i_table_id, i_table_id, i_extension, i_extension ); #endif if( p_pid->i_pid == TS_SI_SDT_PID && i_table_id == 0x42 ) { if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_demux ) ) msg_Err( p_demux, "SINewTableCallback: failed attaching SDTCallback" ); } else if( p_pid->i_pid == TS_SI_EIT_PID && ( i_table_id == 0x4e || /* Current/Following */ (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */ { if( !dvbpsi_eit_attach( h, i_table_id, i_extension, (dvbpsi_eit_callback)EITCallBack, p_demux ) ) msg_Err( p_demux, "SINewTableCallback: failed attaching EITCallback" ); } else if( p_pid->i_pid == TS_SI_TDT_PID && (i_table_id == TS_SI_TDT_TABLE_ID || i_table_id == TS_SI_TOT_TABLE_ID) ) { if( !dvbpsi_tot_attach( h, i_table_id, i_extension, (dvbpsi_tot_callback)TDTCallBack, p_demux ) ) msg_Err( p_demux, "SINewTableCallback: failed attaching TDTCallback" ); } else if( p_pid->i_pid == TS_ARIB_CDT_PID && i_table_id == TS_ARIB_CDT_TABLE_ID ) { if( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) h->p_decoder, i_table_id, i_extension ) == NULL && !ts_dvbpsi_AttachRawSubDecoder( h, i_table_id, i_extension, ARIB_CDT_RawCallback, p_pid ) ) msg_Err( p_demux, "SINewTableCallback: failed attaching ARIB_CDT_RawCallback" ); } } bool ts_attach_SI_Tables_Decoders( ts_pid_t *p_pid ) { if( p_pid->type != TYPE_SI ) return false; if( dvbpsi_decoder_present( p_pid->u.p_si->handle ) ) return true; return dvbpsi_AttachDemux( p_pid->u.p_si->handle, SINewTableCallBack, p_pid ); }