X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fts.c;h=2e36f05ba63187b56a3e817602684341b486d7b1;hb=febea59322289ec7d45aa8bb8128703ba65ea726;hp=35e0626900547cdc9b44f5f26c4adabed3e76a0e;hpb=bdb00d6ecff5e0dea59a6c8210151472bfdb4c61;p=vlc diff --git a/modules/demux/ts.c b/modules/demux/ts.c index 35e0626900..2e36f05ba6 100644 --- a/modules/demux/ts.c +++ b/modules/demux/ts.c @@ -70,18 +70,7 @@ #include "opus.h" -#undef TS_DEBUG -VLC_FORMAT(1, 2) static void ts_debug(const char *format, ...) -{ -#ifdef TS_DEBUG - va_list ap; - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); -#else - (void)format; -#endif -} +#include "mpeg4_iod.h" #ifdef HAVE_ARIBB24 #include @@ -204,37 +193,6 @@ static const char *const ppsz_teletext_type[] = { typedef struct ts_pid_t ts_pid_t; -typedef struct -{ - uint8_t i_objectTypeIndication; - uint8_t i_streamType; - - int i_extra; - uint8_t *p_extra; - -} decoder_config_descriptor_t; - -typedef struct -{ - bool b_ok; - uint16_t i_es_id; - - char *psz_url; - - decoder_config_descriptor_t dec_descr; - -} es_mpeg4_descriptor_t; - -#define ES_DESCRIPTOR_COUNT 255 -typedef struct -{ - /* IOD */ - char *psz_url; - - es_mpeg4_descriptor_t es_descr[ES_DESCRIPTOR_COUNT]; - -} iod_descriptor_t; - typedef struct { int i_version; @@ -263,6 +221,7 @@ typedef struct mtime_t i_first_dts; mtime_t i_pcroffset; bool b_disable; /* ignore PCR field, use dts */ + bool b_fix_done; } pcr; mtime_t i_last_dts; @@ -273,7 +232,7 @@ typedef struct { es_format_t fmt; es_out_id_t *id; - es_mpeg4_descriptor_t *p_mpeg4desc; + const es_mpeg4_descriptor_t *p_mpeg4desc; } ts_pes_es_t; typedef enum @@ -313,21 +272,6 @@ typedef enum TS_PMT_REGISTRATION_HDMV } ts_pmt_registration_type_t; -typedef struct -{ - es_format_t fmt; - es_out_id_t *id; - ts_es_data_type_t data_type; - int i_data_size; - int i_data_gathered; - block_t *p_data; - block_t **pp_last; - - es_mpeg4_descriptor_t *p_mpeg4desc; - - block_t * p_prepcr_outqueue; -} ts_es_t; - typedef enum { TYPE_FREE = 0, @@ -347,7 +291,7 @@ enum FLAG_FILTERED = 4 }; -#define SEEN(x) ((x).i_flags & FLAG_SEEN) +#define SEEN(x) ((x)->i_flags & FLAG_SEEN) #define SCRAMBLED(x) ((x).i_flags & FLAG_SCRAMBLED) struct ts_pid_t @@ -392,6 +336,8 @@ typedef struct #define FROM_SCALE(x) (VLC_TS_0 + ((x) * 100 / 9)) #define TO_SCALE(x) (((x) - VLC_TS_0) * 9 / 100) +#define PID_ALLOC_CHUNK 16 + struct demux_sys_t { stream_t *stream; @@ -400,13 +346,13 @@ struct demux_sys_t vlc_mutex_t csa_lock; /* TS packet size (188, 192, 204) */ - int i_packet_size; + unsigned i_packet_size; /* Additional TS packet header size (BluRay TS packets have 4-byte header before sync byte) */ - int i_packet_header_size; + unsigned i_packet_header_size; /* how many TS packet we read at once */ - int i_ts_read; + unsigned i_ts_read; bool b_force_seek_per_percent; @@ -420,7 +366,18 @@ struct demux_sys_t } arib; /* All pid */ - ts_pid_t pid[8192]; + struct + { + ts_pid_t pat; + ts_pid_t dummy; + /* all non commons ones, dynamically allocated */ + ts_pid_t **pp_all; + int i_all; + int i_all_alloc; + /* last recently used */ + uint16_t i_last_pid; + ts_pid_t *p_last; + } pids; bool b_user_pmt; int i_pmt_es; @@ -436,6 +393,8 @@ struct demux_sys_t /* */ bool b_es_id_pid; + uint16_t i_next_extraid; + csa_t *csa; int i_csa_pkt_size; bool b_split_es; @@ -496,6 +455,7 @@ static ts_psi_t *ts_psi_New( demux_t * ); static void ts_psi_Del( demux_t *, ts_psi_t * ); /* Helpers */ +static ts_pid_t *PID( demux_sys_t *, uint16_t i_pid ); static ts_pmt_t * GetProgramByID( demux_sys_t *, int i_program ); static bool ProgramIsSelected( demux_sys_t *, uint16_t i_pgrm ); static void UpdatePESFilters( demux_t *p_demux, bool b_all ); @@ -519,8 +479,6 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * ); static void PCRFixHandle( demux_t *, ts_pmt_t *, block_t * ); static int64_t TimeStampWrapAround( ts_pmt_t *, int64_t ); -static void IODFree( iod_descriptor_t * ); - #define TS_USER_PMT_NUMBER (0) static int UserPmt( demux_t *p_demux, const char * ); @@ -532,7 +490,7 @@ static int SetPIDFilter( demux_sys_t *, ts_pid_t *, bool b_selected ); #define TS_PACKET_SIZE_MAX 204 #define TS_HEADER_SIZE 4 -static int DetectPacketSize( demux_t *p_demux, int *pi_header_size, int i_offset ) +static int DetectPacketSize( demux_t *p_demux, unsigned *pi_header_size, int i_offset ) { const uint8_t *p_peek; @@ -587,7 +545,7 @@ static int DetectPacketSize( demux_t *p_demux, int *pi_header_size, int i_offset #define TOPFIELD_HEADER_SIZE 3712 -static int DetectPVRHeadersAndHeaderSize( demux_t *p_demux, int *pi_header_size, vdr_info_t *p_vdr ) +static int DetectPVRHeadersAndHeaderSize( demux_t *p_demux, unsigned *pi_header_size, vdr_info_t *p_vdr ) { const uint8_t *p_peek; *pi_header_size = 0; @@ -894,23 +852,28 @@ static void MissingPATPMTFixup( demux_t *p_demux ) int i_pcr_pid = 0x1FFF; int i_num_pes = 0; - if( SEEN(p_sys->pid[i_program_pid]) ) + ts_pid_t *p_program_pid = PID( p_sys, i_program_pid ); + if( SEEN(p_program_pid) ) { /* Find a free one */ for( i_program_pid = MIN_ES_PID; - i_program_pid <= MAX_ES_PID && SEEN(p_sys->pid[i_program_pid]); - i_program_pid++ ); + i_program_pid <= MAX_ES_PID && SEEN(p_program_pid); + i_program_pid++ ) + { + p_program_pid = PID( p_sys, i_program_pid ); + } } - for( int i = MIN_ES_PID; i <= MAX_ES_PID; i++ ) + for( int i=0; ipids.i_all; i++ ) { - if( !SEEN(p_sys->pid[i]) || - p_sys->pid[i].probed.i_type == -1 ) + const ts_pid_t *p_pid = p_sys->pids.pp_all[i]; + if( !SEEN(p_pid) || + p_pid->probed.i_type == -1 ) continue; - if( i_pcr_pid == 0x1FFF && ( p_sys->pid[i].probed.i_type == 0x03 || - p_sys->pid[i].probed.i_pcr_count ) ) - i_pcr_pid = p_sys->pid[i].i_pid; + if( i_pcr_pid == 0x1FFF && ( p_pid->probed.i_type == 0x03 || + p_pid->probed.i_pcr_count ) ) + i_pcr_pid = p_pid->i_pid; i_num_pes++; } @@ -932,13 +895,14 @@ static void MissingPATPMTFixup( demux_t *p_demux ) .b_discontinuity = false }; - BuildPAT( p_sys->pid[0].u.p_pat->handle, - &p_sys->pid[0], BuildPATCallback, + BuildPAT( PID(p_sys, 0)->u.p_pat->handle, + &p_sys->pids.pat, BuildPATCallback, 0, 1, &patstream, 1, &pmtprogramstream, &i_program_number ); - if( p_sys->pid[i_program_pid].type != TYPE_PMT ) + /* PAT callback should have been triggered */ + if( p_program_pid->type != TYPE_PMT ) { msg_Err( p_demux, "PAT creation failed" ); return; @@ -955,23 +919,25 @@ static void MissingPATPMTFixup( demux_t *p_demux ) if( esstreams && mapped ) { int j=0; - for( int i = MIN_ES_PID; i <= MAX_ES_PID; i++ ) + for( int i=0; ipids.i_all; i++ ) { - if( !SEEN(p_sys->pid[i]) || - p_sys->pid[i].probed.i_type == -1 ) + const ts_pid_t *p_pid = p_sys->pids.pp_all[i]; + + if( !SEEN(p_pid) || + p_pid->probed.i_type == -1 ) continue; - esstreams[j].pes.i_stream_type = p_sys->pid[i].probed.i_type; - esstreams[j].pes.i_stream_type = p_sys->pid[i].probed.i_type; - esstreams[j].ts.i_pid = p_sys->pid[i].i_pid; + esstreams[j].pes.i_stream_type = p_pid->probed.i_type; + esstreams[j].pes.i_stream_type = p_pid->probed.i_type; + esstreams[j].ts.i_pid = p_pid->i_pid; mapped[j].pes = &esstreams[j].pes; mapped[j].ts = &esstreams[j].ts; mapped[j].fmt = &esfmt; j++; } - BuildPMT( p_sys->pid[0].u.p_pat->handle, VLC_OBJECT(p_demux), - &p_sys->pid[i_program_pid], BuildPMTCallback, + BuildPMT( PID(p_sys, 0)->u.p_pat->handle, VLC_OBJECT(p_demux), + p_program_pid, BuildPMTCallback, 0, 1, i_pcr_pid, NULL, @@ -990,7 +956,8 @@ static int Open( vlc_object_t *p_this ) demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; - int i_packet_size, i_packet_header_size = 0; + int i_packet_size; + unsigned i_packet_header_size = 0; ts_pid_t *patpid; vdr_info_t vdr = {0}; @@ -1026,16 +993,9 @@ static int Open( vlc_object_t *p_this ) p_sys->b_broken_charset = false; - for( int i = 0; i < 8192; i++ ) - { - ts_pid_t *pid = &p_sys->pid[i]; - pid->i_pid = i; - pid->i_flags = FLAGS_NONE; - pid->probed.i_fourcc = 0; - pid->probed.i_type = 0; - } - /* PID 8191 is padding */ - p_sys->pid[8191].i_flags = FLAG_SEEN; + p_sys->pids.dummy.i_pid = 8191; + p_sys->pids.dummy.i_flags = FLAG_SEEN; + p_sys->i_packet_size = i_packet_size; p_sys->i_packet_header_size = i_packet_header_size; p_sys->i_ts_read = 50; @@ -1051,7 +1011,7 @@ static int Open( vlc_object_t *p_this ) } while (0) /* Init PAT handler */ - patpid = &p_sys->pid[0]; + patpid = PID(p_sys, 0); if ( !PIDSetup( p_demux, TYPE_PAT, patpid, NULL ) ) { vlc_mutex_destroy( &p_sys->csa_lock ); @@ -1068,24 +1028,24 @@ static int Open( vlc_object_t *p_this ) if( p_sys->b_dvb_meta ) { - if( !PIDSetup( p_demux, TYPE_SDT, &p_sys->pid[0x11], NULL ) || - !PIDSetup( p_demux, TYPE_EIT, &p_sys->pid[0x12], NULL ) || - !PIDSetup( p_demux, TYPE_TDT, &p_sys->pid[0x14], NULL ) ) + if( !PIDSetup( p_demux, TYPE_SDT, PID(p_sys, 0x11), NULL ) || + !PIDSetup( p_demux, TYPE_EIT, PID(p_sys, 0x12), NULL ) || + !PIDSetup( p_demux, TYPE_TDT, PID(p_sys, 0x14), NULL ) ) { - PIDRelease( p_demux, &p_sys->pid[0x11] ); - PIDRelease( p_demux, &p_sys->pid[0x12] ); - PIDRelease( p_demux, &p_sys->pid[0x14] ); + PIDRelease( p_demux, PID(p_sys, 0x11) ); + PIDRelease( p_demux, PID(p_sys, 0x12) ); + PIDRelease( p_demux, PID(p_sys, 0x14) ); p_sys->b_dvb_meta = false; } else { - VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x11], p_demux); - VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x12], p_demux); - VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x14], p_demux); + VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x11), p_demux); + VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x12), p_demux); + VLC_DVBPSI_DEMUX_TABLE_INIT(PID(p_sys, 0x14), p_demux); if( p_sys->b_access_control && - ( SetPIDFilter( p_sys, &p_sys->pid[0x11], true ) || - SetPIDFilter( p_sys, &p_sys->pid[0x14], true ) || - SetPIDFilter( p_sys, &p_sys->pid[0x12], true ) ) + ( SetPIDFilter( p_sys, PID(p_sys, 0x11), true ) || + SetPIDFilter( p_sys, PID(p_sys, 0x14), true ) || + SetPIDFilter( p_sys, PID(p_sys, 0x12), true ) ) ) p_sys->b_access_control = false; } @@ -1098,6 +1058,7 @@ static int Open( vlc_object_t *p_this ) /* Read config */ p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" ); + p_sys->i_next_extraid = 1; p_sys->b_trust_pcr = var_CreateGetBool( p_demux, "ts-trust-pcr" ); @@ -1189,24 +1150,15 @@ static void Close( vlc_object_t *p_this ) demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; - PIDRelease( p_demux, &p_sys->pid[0] ); + PIDRelease( p_demux, PID(p_sys, 0) ); if( p_sys->b_dvb_meta ) { - PIDRelease( p_demux, &p_sys->pid[0x11] ); - PIDRelease( p_demux, &p_sys->pid[0x12] ); - PIDRelease( p_demux, &p_sys->pid[0x14] ); + PIDRelease( p_demux, PID(p_sys, 0x11) ); + PIDRelease( p_demux, PID(p_sys, 0x12) ); + PIDRelease( p_demux, PID(p_sys, 0x14) ); } -#ifndef NDEBUG - for( int i = 0; i < 8192; i++ ) - { - ts_pid_t *pid = &p_sys->pid[i]; - if( pid->type != TYPE_FREE ) - msg_Err( p_demux, "PID %d type %d not freed", pid->i_pid, pid->type ); - } -#endif - vlc_mutex_lock( &p_sys->csa_lock ); if( p_sys->csa ) { @@ -1230,6 +1182,19 @@ static void Close( vlc_object_t *p_this ) } vlc_mutex_destroy( &p_sys->csa_lock ); + + /* Release all non default pids */ + for( int i = 0; i < p_sys->pids.i_all; i++ ) + { + ts_pid_t *pid = p_sys->pids.pp_all[i]; +#ifndef NDEBUG + if( pid->type != TYPE_FREE ) + msg_Err( p_demux, "PID %d type %d not freed", pid->i_pid, pid->type ); +#endif + free( pid ); + } + free( p_sys->pids.pp_all ); + free( p_sys ); } @@ -1264,11 +1229,11 @@ static int Demux( demux_t *p_demux ) bool b_wait_es = p_sys->i_pmt_es <= 0; /* If we had no PAT within MIN_PAT_INTERVAL, create PAT/PMT from probed streams */ - if( p_sys->i_pmt_es == 0 && !SEEN(p_sys->pid[0]) && p_sys->patfix.b_pat_deadline ) + if( p_sys->i_pmt_es == 0 && !SEEN(PID(p_sys, 0)) && p_sys->patfix.b_pat_deadline ) MissingPATPMTFixup( p_demux ); /* We read at most 100 TS packet or until a frame is completed */ - for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ ) + for( unsigned i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ ) { bool b_frame = false; block_t *p_pkt; @@ -1285,12 +1250,12 @@ static int Demux( demux_t *p_demux ) } /* Parse the TS packet */ - ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )]; + ts_pid_t *p_pid = PID( p_sys, PIDGet( p_pkt ) ); if( SCRAMBLED(*p_pid) != !!(p_pkt->p_buffer[3] & 0x80) ) UpdateScrambledState( p_demux, p_pid, p_pkt->p_buffer[3] & 0x80 ); - if( !SEEN(*p_pid) ) + if( !SEEN(p_pid) ) { if( p_pid->type == TYPE_FREE ) msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid ); @@ -1304,7 +1269,7 @@ static int Demux( demux_t *p_demux ) } /* Probe streams to build PAT/PMT after MIN_PAT_INTERVAL in case we don't see any PAT */ - if( !SEEN(p_sys->pid[0]) && + if( !SEEN( PID( p_sys, 0 ) ) && (p_pid->probed.i_type == 0 || p_pid->i_pid == p_sys->patfix.i_timesourcepid) && (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */ (p_pkt->p_buffer[3] & 0xD0) == 0x10 ) /* Has payload but is not encrypted */ @@ -1397,7 +1362,7 @@ static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_ static void UpdatePESFilters( demux_t *p_demux, bool b_all ) { demux_sys_t *p_sys = p_demux->p_sys; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i=0; i< p_pat->programs.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -1408,12 +1373,6 @@ static void UpdatePESFilters( demux_t *p_demux, bool b_all ) b_program_selected = ProgramIsSelected( p_sys, p_pmt->i_number ); SetPIDFilter( p_sys, p_pat->programs.p_elems[i], b_program_selected ); - if( p_pmt->i_pid_pcr > 0 ) - { - SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], b_program_selected ); - if( b_program_selected ) - msg_Dbg( p_demux, "enabling pcr pid %d from program %d", p_pmt->i_pid_pcr, p_pmt->i_number ); - } for( int j=0; je_streams.i_size; j++ ) { @@ -1434,6 +1393,13 @@ static void UpdatePESFilters( demux_t *p_demux, bool b_all ) FlushESBuffer( espid->u.p_pes ); } + /* Select pcr last in case it is handled by unselected ES */ + if( p_pmt->i_pid_pcr > 0 ) + { + SetPIDFilter( p_sys, PID(p_sys, p_pmt->i_pid_pcr), b_program_selected ); + if( b_program_selected ) + msg_Dbg( p_demux, "enabling pcr pid %d from program %d", p_pmt->i_pid_pcr, p_pmt->i_number ); + } } } @@ -1450,9 +1416,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) if( PREPARSING || !i_first_program || p_sys->b_default_selection ) { - if( likely(p_sys->pid[0].type == TYPE_PAT) ) + if( likely(PID(p_sys, 0)->type == TYPE_PAT) ) { - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; /* Set default program for preparse time (no program has been selected) */ for( int i = 0; i < p_pat->programs.i_size; i++ ) { @@ -1633,7 +1599,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) else // All ES Mode { p_sys->b_es_all = true; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i = 0; i < p_pat->programs.i_size; i++ ) ARRAY_APPEND( p_sys->programs, p_pat->programs.p_elems[i]->i_pid ); UpdatePESFilters( p_demux, true ); @@ -1723,10 +1689,10 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt ) i_number = strtol( &psz[1], &psz, 0 ); /* */ - ts_pid_t *pmtpid = &p_sys->pid[i_pid]; + ts_pid_t *pmtpid = PID(p_sys, i_pid); msg_Dbg( p_demux, "user pmt specified (pid=%d,number=%d)", i_pid, i_number ); - if ( !PIDSetup( p_demux, TYPE_PMT, pmtpid, &p_sys->pid[0] ) ) + if ( !PIDSetup( p_demux, TYPE_PMT, pmtpid, PID(p_sys, 0) ) ) goto error; /* Dummy PMT */ @@ -1740,7 +1706,7 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt ) goto error; } - ARRAY_APPEND( p_sys->pid[0].u.p_pat->programs, pmtpid ); + ARRAY_APPEND( PID(p_sys, 0)->u.p_pat->programs, pmtpid ); psz = strchr( psz, '=' ); if( psz ) @@ -1762,9 +1728,9 @@ static int UserPmt( demux_t *p_demux, const char *psz_fmt ) { p_pmt->i_pid_pcr = i_pid; } - else if( p_sys->pid[i_pid].type == TYPE_FREE ) + else if( PID(p_sys, i_pid)->type == TYPE_FREE ) { - ts_pid_t *pid = &p_sys->pid[i_pid]; + ts_pid_t *pid = PID(p_sys, i_pid); char *psz_arg = strchr( psz_opt, '=' ); if( psz_arg ) @@ -2055,7 +2021,7 @@ static block_t *Opus_Parse(demux_t *demux, block_t *block) last = &au->p_next; au->i_nb_samples = opus_frame_duration(buf, au_size); - if (end_trim && end_trim <= au->i_nb_samples) + if (end_trim && (uint16_t) end_trim <= au->i_nb_samples) au->i_length = end_trim; /* Blatant abuse of the i_length field. */ else au->i_length = 0; @@ -2226,7 +2192,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes ) else if( pid->u.p_pes->es.fmt.i_codec == VLC_CODEC_SUBT && pid->u.p_pes->es.p_mpeg4desc ) { - decoder_config_descriptor_t *dcd = &pid->u.p_pes->es.p_mpeg4desc->dec_descr; + const decoder_config_descriptor_t *dcd = &pid->u.p_pes->es.p_mpeg4desc->dec_descr; if( dcd->i_extra > 2 && dcd->p_extra[0] == 0x10 && @@ -2340,15 +2306,17 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes ) block_t *p_next = p_block->p_next; p_block->p_next = NULL; - if( p_pmt->pcr.i_first == -1 ) /* Not seen yet */ + if( !p_pmt->pcr.b_fix_done ) /* Not seen yet */ PCRFixHandle( p_demux, p_pmt, p_block ); - if( p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable ) + if( pid->u.p_pes->es.id && (p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable) ) { if( pid->u.p_pes->p_prepcr_outqueue ) { block_ChainAppend( &pid->u.p_pes->p_prepcr_outqueue, p_block ); p_block = pid->u.p_pes->p_prepcr_outqueue; + p_next = p_block->p_next; + p_block->p_next = NULL; pid->u.p_pes->p_prepcr_outqueue = NULL; } @@ -2392,7 +2360,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes ) } else { - if( p_pmt->pcr.i_first == -1 ) /* Not seen yet */ + if( !p_pmt->pcr.b_fix_done ) /* Not seen yet */ PCRFixHandle( p_demux, p_pmt, p_block ); block_ChainAppend( &pid->u.p_pes->p_prepcr_outqueue, p_block ); @@ -2516,11 +2484,12 @@ static block_t* ReadTSPacket( demux_t *p_demux ) for( ;; ) { const uint8_t *p_peek; - int i_peek, i_skip = 0; + int i_peek = 0; + unsigned i_skip = 0; i_peek = stream_Peek( p_sys->stream, &p_peek, p_sys->i_packet_size * 10 ); - if( i_peek < p_sys->i_packet_size + 1 ) + if( i_peek < 0 || (unsigned)i_peek < p_sys->i_packet_size + 1 ) { msg_Dbg( p_demux, "eof ?" ); return NULL; @@ -2619,7 +2588,7 @@ static void ReadyQueuesPostSeek( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i=0; i< p_pat->programs.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -2630,7 +2599,7 @@ static void ReadyQueuesPostSeek( demux_t *p_demux ) if( pid->type != TYPE_PES ) continue; - if( !pid->u.p_pes->es.id ) + if( pid->u.p_pes->es.id ) { block_t *p_block = block_Alloc(1); if( p_block ) @@ -2699,8 +2668,8 @@ static int SeekToTime( demux_t *p_demux, ts_pmt_t *p_pmt, int64_t i_scaledtime ) i_pos = stream_Tell( p_sys->stream ); int i_pid = PIDGet( p_pkt ); - if( i_pid != 0x1FFF && p_sys->pid[i_pid].type == TYPE_PES && - p_sys->pid[i_pid].p_parent->u.p_pmt == p_pmt && + if( i_pid != 0x1FFF && PID(p_sys, i_pid)->type == TYPE_PES && + PID(p_sys, i_pid)->p_parent->u.p_pmt == p_pmt && (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */ (p_pkt->p_buffer[3] & 0xD0) == 0x10 /* Has payload but is not encrypted */ ) @@ -2754,12 +2723,62 @@ static int SeekToTime( demux_t *p_demux, ts_pmt_t *p_pmt, int64_t i_scaledtime ) return VLC_SUCCESS; } +static ts_pid_t *PID( demux_sys_t *p_sys, uint16_t i_pid ) +{ + switch( i_pid ) + { + case 0: + return &p_sys->pids.pat; + case 0x1FFF: + return &p_sys->pids.dummy; + default: + if( p_sys->pids.i_last_pid == i_pid ) + return p_sys->pids.p_last; + break; + } + + for( int i=0; i < p_sys->pids.i_all; i++ ) + { + if( p_sys->pids.pp_all[i]->i_pid == i_pid ) + { + p_sys->pids.p_last = p_sys->pids.pp_all[i]; + p_sys->pids.i_last_pid = i_pid; + return p_sys->pids.p_last; + } + } + + if( p_sys->pids.i_all >= p_sys->pids.i_all_alloc ) + { + ts_pid_t **p_realloc = realloc( p_sys->pids.pp_all, + (p_sys->pids.i_all_alloc + PID_ALLOC_CHUNK) * sizeof(ts_pid_t *) ); + if( !p_realloc ) + return NULL; + p_sys->pids.pp_all = p_realloc; + p_sys->pids.i_all_alloc += PID_ALLOC_CHUNK; + } + + ts_pid_t *p_pid = calloc( 1, sizeof(*p_pid) ); + if( !p_pid ) + { + abort(); + //return NULL; + } + + p_pid->i_pid = i_pid; + p_sys->pids.pp_all[p_sys->pids.i_all++] = p_pid; + + p_sys->pids.p_last = p_pid; + p_sys->pids.i_last_pid = i_pid; + + return p_pid; +} + static ts_pmt_t * GetProgramByID( demux_sys_t *p_sys, int i_program ) { - if(unlikely(p_sys->pid[0].type != TYPE_PAT)) + if(unlikely(PID(p_sys, 0)->type != TYPE_PAT)) return NULL; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i = 0; i < p_pat->programs.i_size; i++ ) { assert(p_pat->programs.p_elems[i]->type == TYPE_PMT); @@ -2777,35 +2796,41 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_ demux_sys_t *p_sys = p_demux->p_sys; int i_count = 0; block_t *p_pkt = NULL; - *pi_pcr = -1; for( ;; ) { + *pi_pcr = -1; + if( i_count++ > PROBE_CHUNK_COUNT || !( p_pkt = ReadTSPacket( p_demux ) ) ) { break; } - int i_pid = PIDGet( p_pkt ); - p_sys->pid[i_pid].i_flags |= FLAG_SEEN; + const int i_pid = PIDGet( p_pkt ); + ts_pid_t *p_pid = PID(p_sys, i_pid); + + p_pid->i_flags |= FLAG_SEEN; - if( i_pid != 0x1FFF && p_sys->pid[i_pid].type == TYPE_PES && - (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */ - (p_pkt->p_buffer[3] & 0xD0) == 0x10 /* Has payload but is not encrypted */ - ) + if( i_pid != 0x1FFF && (p_pkt->p_buffer[1] & 0x80) == 0 ) /* not corrupt */ { bool b_pcrresult = true; + bool b_adaptfield = p_pkt->p_buffer[3] & 0x20; - if( p_pkt->i_buffer >= 4 + 2 + 5 ) + if( b_adaptfield && p_pkt->i_buffer >= 4 + 2 + 5 ) *pi_pcr = GetPCR( p_pkt ); - if( *pi_pcr == -1 ) + if( *pi_pcr == -1 && + (p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* payload start */ + (p_pkt->p_buffer[3] & 0xD0) == 0x10 && /* Has payload but is not encrypted */ + p_pid->type == TYPE_PES && + p_pid->u.p_pes->es.fmt.i_cat != UNKNOWN_ES + ) { b_pcrresult = false; mtime_t i_dts = -1; mtime_t i_pts = -1; unsigned i_skip = 4; - if ( p_pkt->p_buffer[3] & 0x20 ) // adaptation field + if ( b_adaptfield ) // adaptation field i_skip += 1 + p_pkt->p_buffer[4]; if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip], @@ -2819,27 +2844,32 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_ } } - if( *pi_pcr != -1 ) // TODO: non ES PCR + if( *pi_pcr != -1 ) { - ts_pid_t *pmtpid = p_sys->pid[i_pid].p_parent; - assert(pmtpid->type == TYPE_PMT); - - if( i_program == 0 || i_program == pmtpid->u.p_pmt->i_number ) + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; + for( int i=0; iprograms.i_size; i++ ) { - if( b_end ) - { - pmtpid->u.p_pmt->i_last_dts = *pi_pcr; - } - /* Start, only keep first */ - else if( b_pcrresult && pmtpid->u.p_pmt->pcr.i_first == -1 ) - { - pmtpid->u.p_pmt->pcr.i_first = *pi_pcr; - } - else if( pmtpid->u.p_pmt->pcr.i_first_dts < VLC_TS_0 ) + ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; + if( ( p_pmt->i_pid_pcr == p_pid->i_pid || + ( p_pmt->i_pid_pcr == 0x1FFF && p_pid->p_parent == p_pat->programs.p_elems[i] ) ) ) { - pmtpid->u.p_pmt->pcr.i_first_dts = VLC_TS_0 + *pi_pcr * 100 / 9; + if( b_end ) + { + p_pmt->i_last_dts = *pi_pcr; + } + /* Start, only keep first */ + else if( b_pcrresult && p_pmt->pcr.i_first == -1 ) + { + p_pmt->pcr.i_first = *pi_pcr; + } + else if( p_pmt->pcr.i_first_dts < VLC_TS_0 ) + { + p_pmt->pcr.i_first_dts = FROM_SCALE(*pi_pcr); + } + + if( i_program == 0 || i_program == p_pmt->i_number ) + *pb_found = true; } - *pb_found = true; } } } @@ -2916,11 +2946,11 @@ static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_pmt, mtime_t i_pcr ) /* Check if we have enqueued blocks waiting the/before the PCR barrier, and then adapt pcr so they have valid PCR when dequeuing */ - if( p_pmt->pcr.i_current == -1 ) + if( p_pmt->pcr.i_current == -1 && p_pmt->pcr.b_fix_done ) { mtime_t i_mindts = -1; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i=0; i< p_pat->programs.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -2970,11 +3000,11 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk ) pid->probed.i_pcr_count++; - if(unlikely(p_sys->pid[0].type != TYPE_PAT)) + if(unlikely(PID(p_sys, 0)->type != TYPE_PAT)) return; /* Search program and set the PCR */ - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i = 0; i < p_pat->programs.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -2982,16 +3012,11 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk ) if( p_pmt->i_pid_pcr == 0x1FFF ) /* That program has no dedicated PCR pid ISO/IEC 13818-1 2.4.4.9 */ { - if( pid->p_parent ) /* PCR shall be on pid itself */ + if( pid->p_parent == p_pat->programs.p_elems[i] ) /* PCR shall be on pid itself */ { /* ? update PCR for the whole group program ? */ ProgramSetPCR( p_demux, p_pmt, i_program_pcr ); } - else - { - msg_Warn(p_demux, "discarding PCR update from pid %d which has no owner", pid->i_pid); - } - break; } else /* set PCR provided by current pid to program(s) referencing it */ { @@ -3014,7 +3039,7 @@ static int FindPCRCandidate( ts_pmt_t *p_pmt ) for( int i=0; ie_streams.i_size; i++ ) { ts_pid_t *p_pid = p_pmt->e_streams.p_elems[i]; - if( SEEN(*p_pid) && + if( SEEN(p_pid) && (!p_cand || p_cand->i_pid != i_previous) ) { if( p_pid->probed.i_pcr_count ) /* check PCR frequency first */ @@ -3045,23 +3070,29 @@ static int FindPCRCandidate( ts_pmt_t *p_pmt ) return 0x1FFF; } +/* Tries to reselect a new PCR when none has been received */ static void PCRFixHandle( demux_t *p_demux, ts_pmt_t *p_pmt, block_t *p_block ) { - if( p_pmt->pcr.i_first > -1 || p_pmt->pcr.b_disable ) + if ( p_pmt->pcr.b_disable || p_pmt->pcr.b_fix_done ) + { return; - + } /* Record the first data packet timestamp in case there wont be any PCR */ - if( !p_pmt->pcr.i_first_dts ) + else if( !p_pmt->pcr.i_first_dts ) { p_pmt->pcr.i_first_dts = p_block->i_dts; } - else if( p_block->i_dts - p_pmt->pcr.i_first_dts > CLOCK_FREQ / 2 ) /* "shall not exceed 100ms" */ + else if( p_block->i_dts - p_pmt->pcr.i_first_dts > CLOCK_FREQ / 2 ) /* "PCR repeat rate shall not exceed 100ms" */ { - int i_cand = FindPCRCandidate( p_pmt ); - p_pmt->i_pid_pcr = i_cand; - p_pmt->pcr.b_disable = true; /* So we do not wait packet PCR flag as there might be none on the pid */ - msg_Warn( p_demux, "No PCR received for program %d, set up workaround using pid %d", - p_pmt->i_number, i_cand ); + if( p_pmt->pcr.i_current < 0 ) + { + int i_cand = FindPCRCandidate( p_pmt ); + p_pmt->i_pid_pcr = i_cand; + msg_Warn( p_demux, "No PCR received for program %d, set up workaround using pid %d", + p_pmt->i_number, i_cand ); + UpdatePESFilters( p_demux, p_demux->p_sys->b_es_all ); + p_pmt->pcr.b_fix_done = true; + } } } @@ -3168,7 +3199,7 @@ static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk ) PCRHandle( p_demux, pid, p_bk ); - if( i_skip >= 188 || pid->u.p_pes->es.id == NULL ) + if( i_skip >= 188 ) { block_Release( p_bk ); return i_ret; @@ -3325,227 +3356,6 @@ static void PIDFillFormat( es_format_t *fmt, int i_stream_type ) fmt->b_packetized = false; } -/***************************************************************************** - * MP4 specific functions (IOD parser) - *****************************************************************************/ -static int IODDescriptorLength( int *pi_data, uint8_t **pp_data ) -{ - unsigned int i_b; - unsigned int i_len = 0; - do - { - i_b = **pp_data; - (*pp_data)++; - (*pi_data)--; - i_len = ( i_len << 7 ) + ( i_b&0x7f ); - - } while( i_b&0x80 && *pi_data > 0 ); - - if (i_len > *pi_data) - i_len = *pi_data; - - return i_len; -} - -static int IODGetBytes( int *pi_data, uint8_t **pp_data, size_t bytes ) -{ - uint32_t res = 0; - while( *pi_data > 0 && bytes-- ) - { - res <<= 8; - res |= **pp_data; - (*pp_data)++; - (*pi_data)--; - } - - return res; -} - -static char* IODGetURL( int *pi_data, uint8_t **pp_data ) -{ - int len = IODGetBytes( pi_data, pp_data, 1 ); - if (len > *pi_data) - len = *pi_data; - char *url = strndup( (char*)*pp_data, len ); - *pp_data += len; - *pi_data -= len; - return url; -} - -static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data ) -{ - uint8_t i_iod_tag, i_iod_label, byte1, byte2, byte3; - - iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) ); - if( !p_iod ) - return NULL; - - if( i_data < 3 ) - { - return p_iod; - } - - byte1 = IODGetBytes( &i_data, &p_data, 1 ); - byte2 = IODGetBytes( &i_data, &p_data, 1 ); - byte3 = IODGetBytes( &i_data, &p_data, 1 ); - if( byte2 == 0x02 ) //old vlc's buggy implementation of the IOD_descriptor - { - i_iod_label = byte1; - i_iod_tag = byte2; - } - else //correct implementation of the IOD_descriptor - { - i_iod_label = byte2; - i_iod_tag = byte3; - } - - ts_debug( "\n* iod label:%d tag:0x%x", i_iod_label, i_iod_tag ); - - if( i_iod_tag != 0x02 ) - { - ts_debug( "\n ERR: tag %02x != 0x02", i_iod_tag ); - return p_iod; - } - - IODDescriptorLength( &i_data, &p_data ); - - uint16_t i_od_id = ( IODGetBytes( &i_data, &p_data, 1 ) << 2 ); - uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 ); - i_od_id |= i_flags >> 6; - ts_debug( "\n* od_id:%d", i_od_id ); - ts_debug( "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 ); - if ((i_flags >> 5) & 0x01) - { - p_iod->psz_url = IODGetURL( &i_data, &p_data ); - ts_debug( "\n* url string:%s", p_iod->psz_url ); - ts_debug( "\n*****************************\n" ); - return p_iod; - } - else - { - p_iod->psz_url = NULL; - } - - /* Profile Level Indication */ - IODGetBytes( &i_data, &p_data, 1 ); /* OD */ - IODGetBytes( &i_data, &p_data, 1 ); /* scene */ - IODGetBytes( &i_data, &p_data, 1 ); /* audio */ - IODGetBytes( &i_data, &p_data, 1 ); /* visual */ - IODGetBytes( &i_data, &p_data, 1 ); /* graphics */ - - int i_length = 0; - int i_data_sav = i_data; - uint8_t *p_data_sav = p_data; - for (int i = 0; i_data > 0 && i < ES_DESCRIPTOR_COUNT; i++) - { - es_mpeg4_descriptor_t *es_descr = &p_iod->es_descr[i]; - - p_data = p_data_sav + i_length; - i_data = i_data_sav - i_length; - - int i_tag = IODGetBytes( &i_data, &p_data, 1 ); - i_length = IODDescriptorLength( &i_data, &p_data ); - - i_data_sav = i_data; - p_data_sav = p_data; - - i_data = i_length; - - if ( i_tag != 0x03 ) - { - ts_debug( "\n* - OD tag:0x%x Unsupported", i_tag ); - continue; - } - - es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 ); - int i_flags = IODGetBytes( &i_data, &p_data, 1 ); - bool b_streamDependenceFlag = ( i_flags >> 7 )&0x01; - if( b_streamDependenceFlag ) - IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */ - - if( (i_flags >> 6) & 0x01 ) - es_descr->psz_url = IODGetURL( &i_data, &p_data ); - - bool b_OCRStreamFlag = ( i_flags >> 5 )&0x01; - if( b_OCRStreamFlag ) - IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */ - - if( IODGetBytes( &i_data, &p_data, 1 ) != 0x04 ) - { - ts_debug( "\n* ERR missing DecoderConfigDescr" ); - continue; - } - int i_config_desc_length = IODDescriptorLength( &i_data, &p_data ); /* DecoderConfigDescr_length */ - decoder_config_descriptor_t *dec_descr = &es_descr->dec_descr; - dec_descr->i_objectTypeIndication = IODGetBytes( &i_data, &p_data, 1 ); - i_flags = IODGetBytes( &i_data, &p_data, 1 ); - dec_descr->i_streamType = i_flags >> 2; - - IODGetBytes( &i_data, &p_data, 3); /* bufferSizeDB */ - IODGetBytes( &i_data, &p_data, 4); /* maxBitrate */ - IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */ - - if( i_config_desc_length > 13 && IODGetBytes( &i_data, &p_data, 1 ) == 0x05 ) - { - dec_descr->i_extra = IODDescriptorLength( &i_data, &p_data ); - if( dec_descr->i_extra > 0 ) - { - dec_descr->p_extra = xmalloc( dec_descr->i_extra ); - memcpy(dec_descr->p_extra, p_data, dec_descr->i_extra); - p_data += dec_descr->i_extra; - i_data -= dec_descr->i_extra; - } - } - else - { - dec_descr->i_extra = 0; - dec_descr->p_extra = NULL; - } - - if( IODGetBytes( &i_data, &p_data, 1 ) != 0x06 ) - { - ts_debug( "\n* ERR missing SLConfigDescr" ); - continue; - } - IODDescriptorLength( &i_data, &p_data ); /* SLConfigDescr_length */ - switch( IODGetBytes( &i_data, &p_data, 1 ) /* predefined */ ) - { - default: - ts_debug( "\n* ERR unsupported SLConfigDescr predefined" ); - case 0x01: - // FIXME - break; - } - es_descr->b_ok = true; - } - - return p_iod; -} - -static void IODFree( iod_descriptor_t *p_iod ) -{ - if( p_iod->psz_url ) - { - free( p_iod->psz_url ); - free( p_iod ); - return; - } - - for( int i = 0; i < 255; i++ ) - { -#define es_descr p_iod->es_descr[i] - if( es_descr.b_ok ) - { - if( es_descr.psz_url ) - free( es_descr.psz_url ); - else - free( es_descr.dec_descr.p_extra ); - } -#undef es_descr - } - free( p_iod ); -} - /**************************************************************************** **************************************************************************** ** libdvbpsi callbacks @@ -3572,9 +3382,9 @@ static void ValidateDVBMeta( demux_t *p_demux, int i_pid ) /* This doesn't look like a DVB stream so don't try * parsing the SDT/EDT/TDT */ - PIDRelease( p_demux, &p_sys->pid[0x11] ); - PIDRelease( p_demux, &p_sys->pid[0x12] ); - PIDRelease( p_demux, &p_sys->pid[0x14] ); + PIDRelease( p_demux, PID(p_sys, 0x11) ); + PIDRelease( p_demux, PID(p_sys, 0x12) ); + PIDRelease( p_demux, PID(p_sys, 0x14) ); p_sys->b_dvb_meta = false; } @@ -3630,7 +3440,7 @@ static char *EITConvertToUTF8( demux_t *p_demux, 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]; + ts_pid_t *sdt = PID(p_sys, 0x11); dvbpsi_sdt_service_t *p_srv; msg_Dbg( p_demux, "SDTCallBack called" ); @@ -4065,7 +3875,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, 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_sys->pid[0].u.p_pat->i_version != -1 && i_table_id == 0x42 ) + if( PID(p_sys, 0)->u.p_pat->i_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 ); @@ -4073,7 +3883,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_demux ) ) msg_Err( p_demux, "PSINewTableCallback: failed attaching SDTCallback" ); } - else if( p_sys->pid[0x11].u.p_psi->i_version != -1 && + else if( PID(p_sys, 0x11)->u.p_psi->i_version != -1 && ( i_table_id == 0x4e || /* Current/Following */ (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */ { @@ -4087,7 +3897,7 @@ static void PSINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, if( !dvbpsi_eit_attach( h, i_table_id, i_extension, cb, p_demux ) ) msg_Err( p_demux, "PSINewTableCallback: failed attaching EITCallback" ); } - else if( p_demux->p_sys->pid[0x11].u.p_psi->i_version != -1 && + else if( PID(p_sys, 0x11)->u.p_psi->i_version != -1 && (i_table_id == 0x70 /* TDT */ || i_table_id == 0x73 /* TOT */) ) { msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)", @@ -4140,35 +3950,75 @@ static bool PMTEsHasComponentTag( const dvbpsi_pmt_es_t *p_es, return p_si->i_component_tag == i_component_tag; } +static const es_mpeg4_descriptor_t * GetMPEG4DescByEsId( const iod_descriptor_t *iod, + uint16_t i_es_id ) +{ + if( iod ) + for( int i = 0; i < ES_DESCRIPTOR_COUNT; i++ ) + { + if( iod->es_descr[i].i_es_id == i_es_id ) + { + if ( iod->es_descr[i].b_ok ) + return &iod->es_descr[i]; + } + } + return NULL; +} + static void PMTSetupEsISO14496( demux_t *p_demux, ts_pes_es_t *p_es, const ts_pmt_t *p_pmt, const dvbpsi_pmt_es_t *p_dvbpsies ) { es_format_t *p_fmt = &p_es->fmt; - /* MPEG-4 stream: search FMC_DESCRIPTOR (SL Packetized stream) */ - dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_dvbpsies, 0x1f ); - - if( p_dr && p_dr->i_length == 2 ) + const dvbpsi_descriptor_t *p_dr = p_dvbpsies->p_first_descriptor; + while( p_dr ) { - const int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1]; + const es_mpeg4_descriptor_t *p_esdescr = NULL; + uint16_t i_es_id; + uint8_t i_length = p_dr->i_length; - msg_Dbg( p_demux, "found FMC_descriptor declaring sl packetization on es_id=%d", i_es_id ); - - p_es->p_mpeg4desc = NULL; + switch( p_dr->i_tag ) + { + case 0x1f: /* FMC Descriptor */ + while( i_length >= 3 && !p_esdescr ) + { + i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1]; + p_esdescr = GetMPEG4DescByEsId( p_pmt->iod, i_es_id ); + /* FIXME: add flexmux channel */ + i_length -= 3; + if( p_esdescr ) + msg_Dbg( p_demux, "found FMC_descriptor declaring sl packetization on es_id=%"PRIu16, i_es_id ); + } + break; + case 0x1e: /* SL Descriptor */ + if( i_length == 2 ) + { + i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1]; + p_esdescr = GetMPEG4DescByEsId( p_pmt->iod, i_es_id ); + if( p_esdescr ) + msg_Dbg( p_demux, "found SL_descriptor declaring sl packetization on es_id=%"PRIu16, i_es_id ); + } + break; + default: + break; + } - for( int i = 0; i < ES_DESCRIPTOR_COUNT; i++ ) + if( p_esdescr ) { - iod_descriptor_t *iod = p_pmt->iod; - if( iod->es_descr[i].i_es_id == i_es_id ) + if( !p_esdescr->b_ok ) { - if ( iod->es_descr[i].b_ok ) - p_es->p_mpeg4desc = &iod->es_descr[i]; - else - msg_Dbg( p_demux, "MPEG-4 descriptor not yet available on es_id=%d", i_es_id ); + msg_Dbg( p_demux, "MPEG-4 descriptor not yet available on es_id=%"PRIu16, i_es_id ); + } + else + { + p_es->p_mpeg4desc = p_esdescr; break; } } + + p_dr = p_dr->p_next; } + if( !p_es->p_mpeg4desc ) { switch( p_dvbpsies->i_type ) @@ -4254,7 +4104,7 @@ static void PMTSetupEsISO14496( demux_t *p_demux, ts_pes_es_t *p_es, if( p_fmt->i_cat != UNKNOWN_ES ) { - p_fmt->i_extra = dcd->i_extra; + p_fmt->i_extra = __MIN(dcd->i_extra, INT32_MAX); if( p_fmt->i_extra > 0 ) { p_fmt->p_extra = malloc( p_fmt->i_extra ); @@ -4382,7 +4232,7 @@ static void PMTSetupEsTeletext( demux_t *p_demux, ts_pes_t *p_pes, } else { - p_page_es = malloc( sizeof(*p_page_es) ); + p_page_es = calloc( 1, sizeof(*p_page_es) ); if( !p_page_es ) break; @@ -5010,6 +4860,14 @@ static void PMTParseEsIso639( demux_t *p_demux, ts_pes_es_t *p_es, #endif } +static inline void SetExtraESGroupAndID( demux_sys_t *p_sys, es_format_t *p_fmt, + const es_format_t *p_parent_fmt ) +{ + if ( p_sys->b_es_id_pid ) /* pid is 13 bits */ + p_fmt->i_id = (p_sys->i_next_extraid++ << 13) | p_parent_fmt->i_id; + p_fmt->i_group = p_parent_fmt->i_group; +} + static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delayed ) { demux_sys_t *p_sys = p_demux->p_sys; @@ -5019,11 +4877,13 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay if( pid && p_sys->es_creation == CREATE_ES ) { + /* FIXME: other owners / shared pid */ pid->u.p_pes->es.id = es_out_Add( p_demux->out, &pid->u.p_pes->es.fmt ); for( int i = 0; i < pid->u.p_pes->extra_es.i_size; i++ ) { - pid->u.p_pes->extra_es.p_elems[i]->id = - es_out_Add( p_demux->out, &pid->u.p_pes->extra_es.p_elems[i]->fmt ); + es_format_t *p_fmt = &pid->u.p_pes->extra_es.p_elems[i]->fmt; + SetExtraESGroupAndID( p_sys, p_fmt, &pid->u.p_pes->es.fmt ); + pid->u.p_pes->extra_es.p_elems[i]->id = es_out_Add( p_demux->out, p_fmt ); } p_sys->i_pmt_es += 1 + pid->u.p_pes->extra_es.i_size; @@ -5040,7 +4900,7 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay if( b_create_delayed ) { - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; for( int i=0; i< p_pat->programs.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -5053,8 +4913,9 @@ static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delay pid->u.p_pes->es.id = es_out_Add( p_demux->out, &pid->u.p_pes->es.fmt ); for( int k = 0; k < pid->u.p_pes->extra_es.i_size; k++ ) { - pid->u.p_pes->extra_es.p_elems[k]->id = - es_out_Add( p_demux->out, &pid->u.p_pes->extra_es.p_elems[k]->fmt ); + es_format_t *p_fmt = &pid->u.p_pes->extra_es.p_elems[k]->fmt; + SetExtraESGroupAndID( p_sys, p_fmt, &pid->u.p_pes->es.fmt ); + pid->u.p_pes->extra_es.p_elems[k]->id = es_out_Add( p_demux->out, p_fmt ); } p_sys->i_pmt_es += 1 + pid->u.p_pes->extra_es.i_size; } @@ -5074,13 +4935,13 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) msg_Dbg( p_demux, "PMTCallBack called" ); - if (unlikely(p_sys->pid[0].type != TYPE_PAT)) + if (unlikely(PID(p_sys, 0)->type != TYPE_PAT)) { - assert(p_sys->pid[0].type == TYPE_PAT); + assert(PID(p_sys, 0)->type == TYPE_PAT); dvbpsi_pmt_delete(p_dvbpsipmt); } - const ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + const ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; /* First find this PMT declared in PAT */ for( int i = 0; !pmtpid && i < p_pat->programs.i_size; i++ ) @@ -5122,6 +4983,8 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) { IODFree( p_pmt->iod ); p_pmt->iod = NULL; + for( int i=0; iu.p_pes->es.p_mpeg4desc = NULL; } msg_Dbg( p_demux, "new PMT program number=%d version=%d pid_pcr=%d", @@ -5132,7 +4995,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) ValidateDVBMeta( p_demux, p_pmt->i_pid_pcr ); if( ProgramIsSelected( p_sys, p_pmt->i_number ) ) - SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], true ); /* Set demux filter */ + SetPIDFilter( p_sys, PID(p_sys, p_pmt->i_pid_pcr), true ); /* Set demux filter */ /* Parse PMT descriptors */ ts_pmt_registration_type_t registration_type = TS_PMT_REGISTRATION_NONE; @@ -5173,7 +5036,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) { case 0x1d: /* We have found an IOD descriptor */ msg_Dbg( p_demux, " * PMT descriptor : IOD (0x1d)" ); - p_pmt->iod = IODNew( p_dr->i_length, p_dr->p_data ); + p_pmt->iod = IODNew( VLC_OBJECT(p_demux), p_dr->i_length, p_dr->p_data ); break; case 0x9: @@ -5218,7 +5081,12 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) bool b_reusing_pid = false; ts_pes_t *p_pes; - ts_pid_t *pespid = &p_sys->pid[p_dvbpsies->i_pid]; + ts_pid_t *pespid = PID(p_sys, p_dvbpsies->i_pid); + if ( pespid->type == TYPE_PES && pespid->p_parent->u.p_pmt->i_number != p_pmt->i_number ) + { + msg_Warn( p_demux, " * PMT wants to get a share or pid %d (unsupported)", pespid->i_pid ); + continue; + } /* Find out if the PID was already declared */ for( int i = 0; i < old_es_rm.i_size; i++ ) @@ -5320,7 +5188,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) PIDFillFormat( &p_pes->es.fmt, p_dvbpsies->i_type ); - pespid->i_flags |= SEEN(p_sys->pid[p_dvbpsies->i_pid]); + pespid->i_flags |= SEEN(PID(p_sys, p_dvbpsies->i_pid)); bool b_registration_applied = false; if ( p_dvbpsies->i_type >= 0x80 ) /* non standard, extensions */ @@ -5389,9 +5257,10 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) break; } + /* Set Groups / ID */ p_pes->es.fmt.i_group = p_dvbpsipmt->i_program_number; - for( int i = 0; i < p_pes->extra_es.i_size; i++ ) - p_pes->extra_es.p_elems[i]->fmt.i_group = p_dvbpsipmt->i_program_number; + if( p_sys->b_es_id_pid ) + p_pes->es.fmt.i_id = p_dvbpsies->i_pid; if( p_pes->es.fmt.i_cat == UNKNOWN_ES ) { @@ -5404,8 +5273,6 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) msg_Dbg( p_demux, " => pid %d has now es fcc=%4.4s", p_dvbpsies->i_pid, (char*)&p_pes->es.fmt.i_codec ); - if( p_sys->b_es_id_pid ) p_pes->es.fmt.i_id = p_dvbpsies->i_pid; - /* Check if we can avoid restarting the ES */ if( b_reusing_pid ) { @@ -5473,7 +5340,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt ) else if( stream_Control( p_sys->stream, STREAM_SET_PRIVATE_ID_CA, p_dvbpsipmt ) != VLC_SUCCESS ) { - if ( p_sys->arib.e_mode == ARIBMODE_ENABLED ) + if ( p_sys->arib.e_mode == ARIBMODE_ENABLED && !p_sys->arib.b25stream ) { p_sys->arib.b25stream = stream_FilterNew( p_demux->s, "aribcam" ); p_sys->stream = ( p_sys->arib.b25stream ) ? p_sys->arib.b25stream : p_demux->s; @@ -5530,14 +5397,14 @@ static void PATCallBack( void *data, dvbpsi_pat_t *p_dvbpsipat ) demux_t *p_demux = data; demux_sys_t *p_sys = p_demux->p_sys; dvbpsi_pat_program_t *p_program; - ts_pid_t *patpid = &p_sys->pid[0]; - ts_pat_t *p_pat = p_sys->pid[0].u.p_pat; + ts_pid_t *patpid = PID(p_sys, 0); + ts_pat_t *p_pat = PID(p_sys, 0)->u.p_pat; patpid->i_flags |= FLAG_SEEN; msg_Dbg( p_demux, "PATCallBack called" ); - if(unlikely( p_sys->pid[0].type != TYPE_PAT )) + if(unlikely( PID(p_sys, 0)->type != TYPE_PAT )) { msg_Warn( p_demux, "PATCallBack called on invalid pid" ); return; @@ -5572,7 +5439,7 @@ static void PATCallBack( void *data, dvbpsi_pat_t *p_dvbpsipat ) if( p_program->i_number == 0 ) continue; - ts_pid_t *pmtpid = &p_sys->pid[p_program->i_pid]; + ts_pid_t *pmtpid = PID(p_sys, p_program->i_pid); ValidateDVBMeta( p_demux, p_program->i_pid ); @@ -5677,7 +5544,7 @@ static ts_pmt_t *ts_pmt_New( demux_t *p_demux ) pmt->i_version = -1; pmt->i_number = -1; - pmt->i_pid_pcr = -1; + pmt->i_pid_pcr = 0x1FFF; pmt->iod = NULL; pmt->i_last_dts = -1; @@ -5688,6 +5555,8 @@ static ts_pmt_t *ts_pmt_New( demux_t *p_demux ) pmt->pcr.i_first_dts = VLC_TS_INVALID; pmt->pcr.i_pcroffset = -1; + pmt->pcr.b_fix_done = false; + return pmt; } @@ -5742,7 +5611,6 @@ static void ts_pes_Del( demux_t *p_demux, ts_pes_t *pes ) block_ChainRelease( pes->p_prepcr_outqueue ); es_format_Clean( &pes->es.fmt ); - free( pes->es.p_mpeg4desc ); for( int i = 0; i < pes->extra_es.i_size; i++ ) {