+ }
+ else
+ {
+ msg_Dbg( p_demux, " - tag=0x%x(%d)", p_dr->i_tag, p_dr->i_tag );
+ }
+ }
+
+ /* */
+ if( i_start > 0 )
+ vlc_epg_AddEvent( p_epg, i_start, i_duration, psz_name, psz_text, psz_extra );
+
+ /* Update "now playing" field */
+ if( p_evt->i_running_status == 0x04 && i_start > 0 )
+ vlc_epg_SetCurrent( p_epg, i_start );
+
+ free( psz_name );
+ free( psz_text );
+
+ free( psz_extra );
+ }
+ if( p_epg->i_event > 0 )
+ {
+ if( p_eit->i_service_id == p_sys->i_current_program )
+ {
+ p_sys->i_dvb_length = 0;
+ p_sys->i_dvb_start = 0;
+
+ if( p_epg->p_current )
+ {
+ p_sys->i_dvb_start = p_epg->p_current->i_start;
+ p_sys->i_dvb_length = p_epg->p_current->i_duration;
+ }
+ }
+ es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_service_id, p_epg );
+ }
+ vlc_epg_Delete( p_epg );
+
+ 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( p_demux->p_sys->pid[0].psi->i_pat_version != -1 && 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( p_demux->p_sys->pid[0x11].psi->i_sdt_version != -1 &&
+ ( i_table_id == 0x4e || /* Current/Following */
+ (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */
+ {
+ msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
+ i_table_id, i_table_id, i_extension, i_extension );
+
+ dvbpsi_AttachEIT( h, i_table_id, i_extension,
+ (dvbpsi_eit_callback)EITCallBack, p_demux );
+ }
+}
+#endif
+
+/*****************************************************************************
+ * PMT callback and helpers
+ *****************************************************************************/
+static dvbpsi_descriptor_t *PMTEsFindDescriptor( const dvbpsi_pmt_es_t *p_es,
+ int i_tag )
+{
+ dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;;
+ while( p_dr && ( p_dr->i_tag != i_tag ) )
+ p_dr = p_dr->p_next;
+ return p_dr;
+}
+static bool PMTEsHasRegistration( demux_t *p_demux,
+ const dvbpsi_pmt_es_t *p_es,
+ const char *psz_tag )
+{
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x05 );
+ if( !p_dr )
+ return false;
+
+ if( p_dr->i_length < 4 )
+ {
+ msg_Warn( p_demux, "invalid Registration Descriptor" );
+ return false;
+ }
+
+ assert( strlen(psz_tag) == 4 );
+ return !memcmp( p_dr->p_data, psz_tag, 4 );
+}
+static void PMTSetupEsISO14496( demux_t *p_demux, ts_pid_t *pid,
+ const ts_prg_psi_t *prg, const dvbpsi_pmt_es_t *p_es )
+{
+ es_format_t *p_fmt = &pid->es->fmt;
+
+ /* MPEG-4 stream: search SL_DESCRIPTOR */
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x1f );
+
+ if( p_dr && p_dr->i_length == 2 )
+ {
+ const int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+
+ msg_Warn( p_demux, "found SL_descriptor es_id=%d", i_es_id );
+
+ pid->es->p_mpeg4desc = NULL;
+
+ for( int i = 0; i < 255; i++ )
+ {
+ iod_descriptor_t *iod = prg->iod;
+
+ if( iod->es_descr[i].b_ok &&
+ iod->es_descr[i].i_es_id == i_es_id )
+ {
+ pid->es->p_mpeg4desc = &iod->es_descr[i];
+ break;
+ }
+ }
+ }
+ if( !pid->es->p_mpeg4desc )
+ {
+ msg_Err( p_demux, "MPEG-4 descriptor not found" );
+ return;
+ }
+
+ const decoder_config_descriptor_t *dcd = &pid->es->p_mpeg4desc->dec_descr;
+ if( dcd->i_streamType == 0x04 ) /* VisualStream */
+ {
+ p_fmt->i_cat = VIDEO_ES;
+ switch( dcd->i_objectTypeIndication )
+ {
+ case 0x0B: /* mpeg4 sub */
+ p_fmt->i_cat = SPU_ES;
+ p_fmt->i_codec = VLC_FOURCC('s','u','b','t');
+ break;
+
+ case 0x20: /* mpeg4 */
+ p_fmt->i_codec = VLC_FOURCC('m','p','4','v');
+ break;
+ case 0x21: /* h264 */
+ p_fmt->i_codec = VLC_FOURCC('h','2','6','4');
+ break;
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65: /* mpeg2 */
+ p_fmt->i_codec = VLC_FOURCC( 'm','p','g','v' );
+ break;
+ case 0x6a: /* mpeg1 */
+ p_fmt->i_codec = VLC_FOURCC( 'm','p','g','v' );
+ break;
+ case 0x6c: /* mpeg1 */
+ p_fmt->i_codec = VLC_FOURCC( 'j','p','e','g' );
+ break;
+ default:
+ p_fmt->i_cat = UNKNOWN_ES;
+ break;
+ }
+ }
+ else if( dcd->i_streamType == 0x05 ) /* AudioStream */
+ {
+ p_fmt->i_cat = AUDIO_ES;
+ switch( dcd->i_objectTypeIndication )
+ {
+ case 0x40: /* mpeg4 */
+ p_fmt->i_codec = VLC_FOURCC('m','p','4','a');
+ break;
+ case 0x66:
+ case 0x67:
+ case 0x68: /* mpeg2 aac */
+ p_fmt->i_codec = VLC_FOURCC('m','p','4','a');
+ break;
+ case 0x69: /* mpeg2 */
+ p_fmt->i_codec = VLC_FOURCC('m','p','g','a');
+ break;
+ case 0x6b: /* mpeg1 */
+ p_fmt->i_codec = VLC_FOURCC('m','p','g','a');
+ break;
+ default:
+ p_fmt->i_cat = UNKNOWN_ES;
+ break;
+ }
+ }
+ else
+ {
+ p_fmt->i_cat = UNKNOWN_ES;
+ }
+
+ if( p_fmt->i_cat != UNKNOWN_ES )
+ {
+ p_fmt->i_extra = dcd->i_decoder_specific_info_len;
+ if( p_fmt->i_extra > 0 )
+ {
+ p_fmt->p_extra = malloc( p_fmt->i_extra );
+ if( p_fmt->p_extra )
+ memcpy( p_fmt->p_extra,
+ dcd->p_decoder_specific_info,
+ p_fmt->i_extra );
+ else
+ p_fmt->i_extra = 0;
+ }
+ }
+}
+
+typedef struct
+{
+ int i_type;
+ int i_magazine;
+ int i_page;
+ char p_iso639[3];
+} ts_teletext_page_t;
+
+static void PMTSetupEsTeletext( demux_t *p_demux, ts_pid_t *pid,
+ const dvbpsi_pmt_es_t *p_es )
+{
+ es_format_t *p_fmt = &pid->es->fmt;
+
+ ts_teletext_page_t p_page[2 * 64 + 20];
+ int i_page = 0;
+
+ /* Gather pages informations */
+#if defined _DVBPSI_DR_56_H_ && \
+ defined DVBPSI_VERSION && DVBPSI_VERSION_INT > ((0<<16)+(1<<8)+5)
+ for( int i_tag_idx = 0; i_tag_idx < 2; i_tag_idx++ )
+ {
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, i_tag_idx == 0 ? 0x46 : 0x56 );
+ if( !p_dr )
+ continue;
+
+ dvbpsi_teletext_dr_t *p_sub = dvbpsi_DecodeTeletextDr( p_dr );
+ if( !p_sub )
+ continue;
+
+ for( int i = 0; i < p_sub->i_pages_number; i++ )
+ {
+ const dvbpsi_teletextpage_t *p_src = &p_sub->p_pages[i];
+
+ if( p_src->i_teletext_type < 0 || p_src->i_teletext_type >= 0x06 )
+ continue;
+
+ assert( i_page < sizeof(p_page)/sizeof(*p_page) );
+
+ ts_teletext_page_t *p_dst = &p_page[i_page++];
+
+ p_dst->i_type = p_src->i_teletext_type;
+ p_dst->i_magazine = p_src->i_teletext_magazine_number ? : 8;
+ p_dst->i_page = p_src->i_teletext_page_number;
+ memcpy( p_dst->p_iso639, p_src->i_iso6392_language_code, 3 );
+ }
+ }
+#endif
+
+#ifdef _DVBPSI_DR_59_H_
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+ if( p_dr )
+ {
+ dvbpsi_subtitling_dr_t *p_sub = dvbpsi_DecodeSubtitlingDr( p_dr );
+ for( int i = 0; p_sub && i < p_sub->i_subtitles_number; i++ )
+ {
+ dvbpsi_subtitle_t *p_src = &p_sub->p_subtitle[i];
+
+ if( p_src->i_subtitling_type < 0x01 || p_src->i_subtitling_type > 0x03 )
+ continue;
+
+ assert( i_page < sizeof(p_page)/sizeof(*p_page) );
+
+ ts_teletext_page_t *p_dst = &p_page[i_page++];
+
+ switch( p_src->i_subtitling_type )
+ {
+ case 0x01:
+ p_dst->i_type = 0x02;
+ break;
+ default:
+ p_dst->i_type = 0x03;
+ break;
+ }
+ /* FIXME check if it is the right split */
+ p_dst->i_magazine = (p_src->i_composition_page_id >> 8) ? : 8;
+ p_dst->i_page = p_src->i_composition_page_id & 0xff;
+ memcpy( p_dst->p_iso639, p_src->i_iso6392_language_code, 3 );
+ }
+ }
+#endif
+
+ /* */
+ es_format_Init( p_fmt, SPU_ES, VLC_FOURCC( 't', 'e', 'l', 'x' ) );
+
+ /* In stream output mode, do not separate the stream by page */
+ if( p_demux->out->b_sout || i_page <= 0 )
+ {
+ p_fmt->subs.teletext.i_magazine = -1;
+ p_fmt->subs.teletext.i_page = 0;
+ p_fmt->psz_description = strdup( gettext(ppsz_teletext_type[1]) );
+
+ dvbpsi_descriptor_t *p_dr;
+ p_dr = PMTEsFindDescriptor( p_es, 0x46 );
+ if( !p_dr )
+ p_dr = PMTEsFindDescriptor( p_es, 0x56 );
+
+ if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+ {
+ /* Descriptor pass-through for sout */
+ p_fmt->p_extra = malloc( p_dr->i_length );
+ if( p_fmt->p_extra )
+ {
+ p_fmt->i_extra = p_dr->i_length;
+ memcpy( p_fmt->p_extra, p_dr->p_data, p_dr->i_length );
+ }
+ }
+ }
+ else
+ {
+ for( int i = 0; i < i_page; i++ )
+ {
+ ts_es_t *p_es;
+
+ /* */
+ if( i == 0 )
+ {
+ p_es = pid->es;
+ }
+ else
+ {
+ p_es = malloc( sizeof(*p_es) );
+ if( !p_es )
+ break;
+
+ es_format_Copy( &p_es->fmt, &pid->es->fmt );
+ free( p_es->fmt.psz_language );
+ free( p_es->fmt.psz_description );
+ p_es->fmt.psz_language = NULL;
+ p_es->fmt.psz_description = NULL;
+
+ p_es->id = NULL;
+ p_es->p_pes = NULL;
+ p_es->i_pes_size = 0;
+ p_es->i_pes_gathered = 0;
+ p_es->pp_last = &p_es->p_pes;
+ p_es->p_mpeg4desc = NULL;
+ p_es->b_gather = false;
+
+ TAB_APPEND( pid->i_extra_es, pid->extra_es, p_es );
+ }
+
+ /* */
+ const ts_teletext_page_t *p = &p_page[i];
+ p_es->fmt.psz_language = strndup( p->p_iso639, 3 );
+ p_es->fmt.psz_description = strdup(gettext(ppsz_teletext_type[p->i_type]));
+ p_es->fmt.subs.teletext.i_magazine = p->i_magazine;
+ p_es->fmt.subs.teletext.i_page = p->i_page;
+
+ msg_Dbg( p_demux,
+ " * ttxt type=%s lan=%s page=%d%02x",
+ p_es->fmt.psz_description,
+ p_es->fmt.psz_language,
+ p->i_magazine, p->i_page );
+ }
+ }
+}
+static void PMTSetupEsDvbSubtitle( demux_t *p_demux, ts_pid_t *pid,
+ const dvbpsi_pmt_es_t *p_es )
+{
+ es_format_t *p_fmt = &pid->es->fmt;
+
+ es_format_Init( p_fmt, SPU_ES, VLC_FOURCC( 'd', 'v', 'b', 's' ) );
+
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+ int i_page = 0;
+#ifdef _DVBPSI_DR_59_H_
+ dvbpsi_subtitling_dr_t *p_sub = dvbpsi_DecodeSubtitlingDr( p_dr );
+ for( int i = 0; p_sub && i < p_sub->i_subtitles_number; i++ )
+ {
+ const int i_type = p_sub->p_subtitle[i].i_subtitling_type;
+ if( ( i_type >= 0x10 && i_type <= 0x13 ) ||
+ ( i_type >= 0x20 && i_type <= 0x23 ) )
+ i_page++;
+ }
+#endif
+
+ /* In stream output mode, do not separate the stream by page */
+ if( p_demux->out->b_sout || i_page <= 0 )
+ {
+ p_fmt->subs.dvb.i_id = -1;
+ p_fmt->psz_description = strdup( _("DVB subtitles") );
+
+ if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+ {
+ /* Descriptor pass-through for sout */
+ p_fmt->p_extra = malloc( p_dr->i_length );
+ if( p_fmt->p_extra )
+ {
+ p_fmt->i_extra = p_dr->i_length;
+ memcpy( p_fmt->p_extra, p_dr->p_data, p_dr->i_length );
+ }
+ }
+ }
+ else
+ {
+#ifdef _DVBPSI_DR_59_H_
+ for( int i = 0; i < p_sub->i_subtitles_number; i++ )
+ {
+ ts_es_t *p_es;
+
+ /* */
+ if( i == 0 )
+ {
+ p_es = pid->es;
+ }
+ else
+ {
+ p_es = malloc( sizeof(*p_es) );
+ if( !p_es )
+ break;
+
+ es_format_Copy( &p_es->fmt, &pid->es->fmt );
+ free( p_es->fmt.psz_language );
+ free( p_es->fmt.psz_description );
+ p_es->fmt.psz_language = NULL;
+ p_es->fmt.psz_description = NULL;
+
+ p_es->id = NULL;
+ p_es->p_pes = NULL;
+ p_es->i_pes_size = 0;
+ p_es->i_pes_gathered = 0;
+ p_es->pp_last = &p_es->p_pes;
+ p_es->p_mpeg4desc = NULL;
+ p_es->b_gather = false;
+
+ TAB_APPEND( pid->i_extra_es, pid->extra_es, p_es );
+ }
+
+ /* */
+ const dvbpsi_subtitle_t *p = &p_sub->p_subtitle[i];
+ p_es->fmt.psz_language = strndup( p->i_iso6392_language_code, 3 );
+ switch( p->i_subtitling_type )
+ {
+ case 0x10: /* unspec. */
+ case 0x11: /* 4:3 */
+ case 0x12: /* 16:9 */
+ case 0x13: /* 2.21:1 */
+ p_es->fmt.psz_description = strdup( _("DVB subtitles") );
+ break;
+ case 0x20: /* Hearing impaired unspec. */
+ case 0x21: /* h.i. 4:3 */
+ case 0x22: /* h.i. 16:9 */
+ case 0x23: /* h.i. 2.21:1 */
+ p_es->fmt.psz_description = strdup( _("DVB subtitles: hearing impaired") );
+ break;
+ default:
+ break;
+ }
+
+ /* Hack, FIXME */
+ p_es->fmt.subs.dvb.i_id = ( p->i_composition_page_id << 0 ) |
+ ( p->i_ancillary_page_id << 16 );
+ }
+#endif
+ }
+}
+static void PMTSetupEs0x06( demux_t *p_demux, ts_pid_t *pid,
+ const dvbpsi_pmt_es_t *p_es )
+{
+ es_format_t *p_fmt = &pid->es->fmt;
+
+ if( PMTEsHasRegistration( p_demux, p_es, "AC-3" ) ||
+ PMTEsFindDescriptor( p_es, 0x6a ) ||
+ PMTEsFindDescriptor( p_es, 0x81 ) )
+ {
+ p_fmt->i_cat = AUDIO_ES;
+ p_fmt->i_codec = VLC_FOURCC('a','5','2',' ');
+ }
+ else if( PMTEsFindDescriptor( p_es, 0x7a ) )
+ {
+ /* DVB with stream_type 0x06 (ETS EN 300 468) */
+ p_fmt->i_cat = AUDIO_ES;
+ p_fmt->i_codec = VLC_FOURCC( 'e', 'a', 'c', '3' );
+ }
+ else if( PMTEsHasRegistration( p_demux, p_es, "DTS1" ) ||
+ PMTEsHasRegistration( p_demux, p_es, "DTS2" ) ||
+ PMTEsHasRegistration( p_demux, p_es, "DTS3" ) ||
+ PMTEsFindDescriptor( p_es, 0x73 ) )
+ {
+ /*registration descriptor(ETSI TS 101 154 Annex F)*/
+ p_fmt->i_cat = AUDIO_ES;
+ p_fmt->i_codec = VLC_FOURCC('d','t','s',' ');
+ }
+ else if( PMTEsHasRegistration( p_demux, p_es, "BSSD" ) )
+ {
+ p_fmt->i_cat = AUDIO_ES;
+ p_fmt->b_packetized = true;
+ p_fmt->i_codec = VLC_FOURCC('a','e','s','3');
+ }
+ else
+ {
+ /* Subtitle/Teletext/VBI fallbacks */
+ dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+
+#ifdef _DVBPSI_DR_59_H_
+ dvbpsi_subtitling_dr_t *p_sub;
+ if( p_dr && ( p_sub = dvbpsi_DecodeSubtitlingDr( p_dr ) ) )
+ {
+ for( int i = 0; i < p_sub->i_subtitles_number; i++ )
+ {
+ if( p_fmt->i_cat != UNKNOWN_ES )
+ break;
+
+ switch( p_sub->p_subtitle[i].i_subtitling_type )