X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fts.c;h=9a10ca87cfc89d3c60c692866cca44f040e81e28;hb=cb3db8092e5ce3e0e2f87d4003b7c7215519172f;hp=35c97937d8e85ca8d03301d7f07f2c01a7cb2513;hpb=0c78fd64e763a07d0170d1975ba82c8d5b3b6902;p=vlc diff --git a/modules/demux/ts.c b/modules/demux/ts.c index 35c97937d8..9a10ca87cf 100644 --- a/modules/demux/ts.c +++ b/modules/demux/ts.c @@ -209,7 +209,7 @@ typedef struct uint8_t i_objectTypeIndication; uint8_t i_streamType; - int i_extra; + unsigned i_extra; uint8_t *p_extra; } decoder_config_descriptor_t; @@ -263,6 +263,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 +274,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 +314,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 +333,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 +378,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; @@ -420,7 +408,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; @@ -498,6 +497,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 ); @@ -896,23 +896,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++; } @@ -934,13 +939,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; @@ -957,23 +963,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, @@ -1029,16 +1037,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; @@ -1054,7 +1055,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 ); @@ -1071,24 +1072,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; } @@ -1193,24 +1194,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 ) { @@ -1234,6 +1226,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 ); } @@ -1268,7 +1273,7 @@ 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 */ @@ -1289,12 +1294,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 ); @@ -1308,7 +1313,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 */ @@ -1401,7 +1406,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; @@ -1435,7 +1440,7 @@ static void UpdatePESFilters( demux_t *p_demux, bool b_all ) /* Select pcr last in case it is handled by unselected ES */ if( p_pmt->i_pid_pcr > 0 ) { - SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], b_program_selected ); + 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 ); } @@ -1455,9 +1460,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++ ) { @@ -1638,7 +1643,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 ); @@ -1728,10 +1733,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 */ @@ -1745,7 +1750,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 ) @@ -1767,9 +1772,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 ) @@ -2231,7 +2236,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 && @@ -2345,7 +2350,7 @@ 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( pid->u.p_pes->es.id && (p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable) ) @@ -2354,6 +2359,8 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes ) { 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; } @@ -2397,7 +2404,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 ); @@ -2625,7 +2632,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; @@ -2705,8 +2712,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 */ ) @@ -2760,12 +2767,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); @@ -2794,7 +2851,7 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_ } const int i_pid = PIDGet( p_pkt ); - ts_pid_t *p_pid = &p_sys->pid[i_pid]; + ts_pid_t *p_pid = PID(p_sys, i_pid); p_pid->i_flags |= FLAG_SEEN; @@ -2833,7 +2890,7 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_ if( *pi_pcr != -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; iprograms.i_size; i++ ) { ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; @@ -2933,11 +2990,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; @@ -2987,11 +3044,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; @@ -3026,7 +3083,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 */ @@ -3057,24 +3114,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 ); - UpdatePESFilters( p_demux, p_demux->p_sys->b_es_all ); + 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; + } } } @@ -3341,7 +3403,7 @@ static void PIDFillFormat( es_format_t *fmt, int i_stream_type ) /***************************************************************************** * MP4 specific functions (IOD parser) *****************************************************************************/ -static int IODDescriptorLength( int *pi_data, uint8_t **pp_data ) +static unsigned IODDescriptorLength( unsigned *pi_data, uint8_t **pp_data ) { unsigned int i_b; unsigned int i_len = 0; @@ -3360,9 +3422,9 @@ static int IODDescriptorLength( int *pi_data, uint8_t **pp_data ) return i_len; } -static int IODGetBytes( int *pi_data, uint8_t **pp_data, size_t bytes ) +static unsigned IODGetBytes( unsigned *pi_data, uint8_t **pp_data, size_t bytes ) { - uint32_t res = 0; + unsigned res = 0; while( *pi_data > 0 && bytes-- ) { res <<= 8; @@ -3374,9 +3436,9 @@ static int IODGetBytes( int *pi_data, uint8_t **pp_data, size_t bytes ) return res; } -static char* IODGetURL( int *pi_data, uint8_t **pp_data ) +static char* IODGetURL( unsigned *pi_data, uint8_t **pp_data ) { - int len = IODGetBytes( pi_data, pp_data, 1 ); + unsigned len = IODGetBytes( pi_data, pp_data, 1 ); if (len > *pi_data) len = *pi_data; char *url = strndup( (char*)*pp_data, len ); @@ -3385,7 +3447,7 @@ static char* IODGetURL( int *pi_data, uint8_t **pp_data ) return url; } -static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data ) +static iod_descriptor_t *IODNew( unsigned i_data, uint8_t *p_data ) { uint8_t i_iod_tag, i_iod_label, byte1, byte2, byte3; @@ -3446,17 +3508,17 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data ) IODGetBytes( &i_data, &p_data, 1 ); /* visual */ IODGetBytes( &i_data, &p_data, 1 ); /* graphics */ - int i_length = 0; - int i_data_sav = i_data; + unsigned i_length = 0; + unsigned i_data_sav = i_data; uint8_t *p_data_sav = p_data; - for (int i = 0; i_data > 0 && i < ES_DESCRIPTOR_COUNT; i++) + for (unsigned 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 ); + uint8_t i_tag = IODGetBytes( &i_data, &p_data, 1 ); i_length = IODDescriptorLength( &i_data, &p_data ); i_data_sav = i_data; @@ -3471,7 +3533,7 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data ) } es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 ); - int i_flags = IODGetBytes( &i_data, &p_data, 1 ); + uint8_t 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 */ @@ -3488,7 +3550,7 @@ static iod_descriptor_t *IODNew( int i_data, uint8_t *p_data ) ts_debug( "\n* ERR missing DecoderConfigDescr" ); continue; } - int i_config_desc_length = IODDescriptorLength( &i_data, &p_data ); /* DecoderConfigDescr_length */ + unsigned 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 ); @@ -3585,9 +3647,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; } @@ -3643,7 +3705,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" ); @@ -4078,7 +4140,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 ); @@ -4086,7 +4148,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 */ { @@ -4100,7 +4162,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)", @@ -4161,7 +4223,7 @@ static void PMTSetupEsISO14496( demux_t *p_demux, ts_pes_es_t *p_es, /* 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 ) + if( p_dr && p_dr->i_length == 2 && p_pmt->iod ) { const int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1]; @@ -4267,7 +4329,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 ); @@ -5063,7 +5125,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; @@ -5098,13 +5160,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++ ) @@ -5156,7 +5218,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; @@ -5242,7 +5304,7 @@ 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 ); @@ -5349,7 +5411,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 */ @@ -5558,14 +5620,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; @@ -5600,7 +5662,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 ); @@ -5716,6 +5778,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; } @@ -5770,7 +5834,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++ ) {