uint8_t i_objectTypeIndication;
uint8_t i_streamType;
- int i_extra;
+ unsigned i_extra;
uint8_t *p_extra;
} decoder_config_descriptor_t;
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;
{
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
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
#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;
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;
} 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;
/* */
bool b_es_id_pid;
+ uint16_t i_next_extraid;
+
csa_t *csa;
int i_csa_pkt_size;
bool b_split_es;
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 );
#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;
#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;
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; i<p_sys->pids.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++;
}
.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;
if( esstreams && mapped )
{
int j=0;
- for( int i = MIN_ES_PID; i <= MAX_ES_PID; i++ )
+ for( int i=0; i<p_sys->pids.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,
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};
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;
} 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 );
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;
}
/* 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" );
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 )
{
}
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 );
}
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;
}
/* 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 );
}
/* 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 */
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;
/* 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 );
}
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++ )
{
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 );
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 */
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 )
{
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 )
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;
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 &&
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;
}
}
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 );
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;
{
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;
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 )
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 */
)
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);
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],
}
}
- 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; i<p_pat->programs.i_size; i++ )
{
- if( b_end )
+ 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->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 )
- {
- 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;
}
}
}
/* 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;
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;
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 */
{
for( int i=0; i<p_pmt->e_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 */
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;
+ }
}
}
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;
/*****************************************************************************
* 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;
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;
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 );
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;
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;
}
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 */
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 );
/* 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;
}
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" );
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 );
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 */
{
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)",
/* 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];
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 );
}
else
{
- p_page_es = malloc( sizeof(*p_page_es) );
+ p_page_es = calloc( 1, sizeof(*p_page_es) );
if( !p_page_es )
break;
#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;
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;
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;
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;
}
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++ )
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;
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++ )
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 */
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 )
{
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 )
{
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;
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 );
pmt->pcr.i_first_dts = VLC_TS_INVALID;
pmt->pcr.i_pcroffset = -1;
+ pmt->pcr.b_fix_done = false;
+
return pmt;
}
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++ )
{