uint8_t i_objectTypeIndication;
uint8_t i_streamType;
- int i_extra;
+ unsigned i_extra;
uint8_t *p_extra;
} decoder_config_descriptor_t;
{
FLAGS_NONE = 0,
FLAG_SEEN = 1,
- FLAG_SCRAMBLED = 2
+ FLAG_SCRAMBLED = 2,
+ FLAG_FILTERED = 4
};
#define SEEN(x) ((x).i_flags & FLAG_SEEN)
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;
bool b_user_pmt;
int i_pmt_es;
+ bool b_es_all; /* If we need to return all es/programs */
enum
{
/* */
bool b_es_id_pid;
+ uint16_t i_next_extraid;
+
csa_t *csa;
int i_csa_pkt_size;
bool b_split_es;
/* Helpers */
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 );
+static inline void FlushESBuffer( ts_pes_t *p_pes );
+static void UpdateScrambledState( demux_t *p_demux, ts_pid_t *p_pid, bool );
static inline int PIDGet( block_t *p )
{
return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
}
static bool GatherData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
-static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid );
+static void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool );
static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_prg, mtime_t i_pcr );
static block_t* ReadTSPacket( demux_t *p_demux );
static int ProbeStart( demux_t *p_demux, int i_program );
static int ProbeEnd( demux_t *p_demux, int i_program );
static int SeekToTime( demux_t *p_demux, ts_pmt_t *, int64_t time );
-static void ReadyQueuesPostSeek( demux_sys_t *p_sys );
+static void ReadyQueuesPostSeek( demux_t *p_demux );
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 );
#define TS_USER_PMT_NUMBER (0)
static int UserPmt( demux_t *p_demux, const char * );
-static int SetPIDFilter( demux_t *, int i_pid, bool b_selected );
-static void SetPrgFilter( demux_t *, int i_prg, bool b_selected );
+static int SetPIDFilter( demux_sys_t *, ts_pid_t *, bool b_selected );
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#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;
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};
VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x12], p_demux);
VLC_DVBPSI_DEMUX_TABLE_INIT(&p_sys->pid[0x14], p_demux);
if( p_sys->b_access_control &&
- ( SetPIDFilter( p_demux, 0x11, true ) ||
- SetPIDFilter( p_demux, 0x14, true ) ||
- SetPIDFilter( p_demux, 0x12, true ) )
+ ( SetPIDFilter( p_sys, &p_sys->pid[0x11], true ) ||
+ SetPIDFilter( p_sys, &p_sys->pid[0x14], true ) ||
+ SetPIDFilter( p_sys, &p_sys->pid[0x12], true ) )
)
p_sys->b_access_control = false;
}
# undef VLC_DVBPSI_DEMUX_TABLE_INIT
p_sys->i_pmt_es = 0;
+ p_sys->b_es_all = 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" );
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 )];
+ 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( p_pid->type == TYPE_FREE )
+ msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
+ p_pid->i_flags |= FLAG_SEEN;
+ }
+
+ if ( SCRAMBLED(*p_pid) && !p_demux->p_sys->csa )
+ {
+ block_Release( p_pkt );
+ continue;
+ }
+
/* Probe streams to build PAT/PMT after MIN_PAT_INTERVAL in case we don't see any PAT */
if( !SEEN(p_sys->pid[0]) &&
(p_pid->probed.i_type == 0 || p_pid->i_pid == p_sys->patfix.i_timesourcepid) &&
{
case TYPE_PAT:
dvbpsi_packet_push( p_pid->u.p_pat->handle, p_pkt->p_buffer );
+ block_Release( p_pkt );
break;
case TYPE_PMT:
dvbpsi_packet_push( p_pid->u.p_pmt->handle, p_pkt->p_buffer );
+ block_Release( p_pkt );
break;
case TYPE_PES:
p_sys->b_end_preparse = true;
+
if( p_sys->es_creation == DELAY_ES ) /* No longer delay ES since that pid's program sends data */
{
- AddAndCreateES( p_demux, NULL );
+ msg_Dbg( p_demux, "Creating delayed ES" );
+ AddAndCreateES( p_demux, p_pid, true );
}
- b_frame = GatherData( p_demux, p_pid, p_pkt );
- if( p_sys->b_default_selection )
+ if( !p_sys->b_access_control && !(p_pid->i_flags & FLAG_FILTERED) )
{
- p_sys->b_default_selection = false;
- assert(p_sys->programs.i_size == 1);
- if( p_sys->programs.p_elems[0] != p_pid->p_parent->u.p_pmt->i_number )
- {
- SetPrgFilter( p_demux, p_sys->programs.p_elems[0], false );
- SetPrgFilter( p_demux, p_pid->p_parent->u.p_pmt->i_number, true );
- p_sys->programs.p_elems[0] = p_pid->p_parent->u.p_pmt->i_number;
- }
+ /* That packet is for an unselected ES, don't waste time/memory gathering its data */
+ block_Release( p_pkt );
+ continue;
}
+
+ b_frame = GatherData( p_demux, p_pid, p_pkt );
break;
case TYPE_SDT:
case TYPE_EIT:
if( p_sys->b_dvb_meta )
dvbpsi_packet_push( p_pid->u.p_psi->handle, p_pkt->p_buffer );
+ block_Release( p_pkt );
break;
default:
- if( !SEEN(*p_pid) )
- msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
-
/* We have to handle PCR if present */
PCRHandle( p_demux, p_pid, p_pkt );
block_Release( p_pkt );
break;
}
- p_pid->i_flags |= FLAG_SEEN;
-
if( b_frame || ( b_wait_es && p_sys->i_pmt_es > 0 ) )
break;
}
return VLC_EGENERIC;
}
+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;
+ 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;
+ bool b_program_selected;
+ if( (p_sys->b_default_selection && !p_sys->b_access_control) || b_all )
+ b_program_selected = true;
+ else
+ b_program_selected = ProgramIsSelected( p_sys, p_pmt->i_number );
+
+ SetPIDFilter( p_sys, p_pat->programs.p_elems[i], b_program_selected );
+
+ for( int j=0; j<p_pmt->e_streams.i_size; j++ )
+ {
+ ts_pid_t *espid = p_pmt->e_streams.p_elems[j];
+ bool b_stream_selected = b_program_selected;
+ if( b_program_selected && !b_all && espid->u.p_pes->es.id )
+ es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
+ espid->u.p_pes->es.id, &b_stream_selected );
+
+ if( !p_sys->b_es_all && espid->u.p_pes->es.fmt.i_cat == UNKNOWN_ES )
+ b_stream_selected = false;
+
+ if( b_stream_selected )
+ msg_Dbg( p_demux, "enabling pid %d from program %d", espid->i_pid, p_pmt->i_number );
+
+ SetPIDFilter( p_sys, espid, b_stream_selected );
+ if( !b_stream_selected )
+ 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, &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 );
+ }
+ }
+}
+
static int Control( demux_t *p_demux, int i_query, va_list args )
{
demux_sys_t *p_sys = p_demux->p_sys;
if( !DVBEventInformation( p_demux, &i_time, &i_length ) &&
i_length > 0 && !SeekToTime( p_demux, p_pmt, TO_SCALE(i_length) * f ) )
{
- ReadyQueuesPostSeek( p_sys );
+ ReadyQueuesPostSeek( p_demux );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
TO_SCALE(i_length) * f );
return VLC_SUCCESS;
p_pmt->i_last_dts ) - p_pmt->pcr.i_first;
if( !SeekToTime( p_demux, p_pmt, p_pmt->pcr.i_first + i_length * f ) )
{
- ReadyQueuesPostSeek( p_sys );
+ ReadyQueuesPostSeek( p_demux );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
FROM_SCALE(p_pmt->pcr.i_first + i_length * f) );
return VLC_SUCCESS;
if( i64 > 0 &&
stream_Seek( p_sys->stream, (int64_t)(i64 * f) ) == VLC_SUCCESS )
{
- ReadyQueuesPostSeek( p_sys );
+ ReadyQueuesPostSeek( p_demux );
return VLC_SUCCESS;
}
break;
p_pmt->pcr.i_first > -1 &&
!SeekToTime( p_demux, p_pmt, p_pmt->pcr.i_first + TO_SCALE(i64) ) )
{
- ReadyQueuesPostSeek( p_sys );
+ ReadyQueuesPostSeek( p_demux );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
FROM_SCALE(p_pmt->pcr.i_first) + i64 - VLC_TS_0 );
return VLC_SUCCESS;
if( i_int != 0 ) /* If not default program */
{
/* Deselect/filter current ones */
- for( int i=0; i<p_sys->programs.i_size; i++ )
- SetPrgFilter( p_demux, p_sys->programs.p_elems[i], false );
- ARRAY_RESET( p_sys->programs );
if( i_int != -1 )
{
+ p_sys->b_es_all = false;
ARRAY_APPEND( p_sys->programs, i_int );
+ UpdatePESFilters( p_demux, false );
}
else if( likely( p_list != NULL ) )
{
+ p_sys->b_es_all = false;
for( int i = 0; i < p_list->i_count; i++ )
ARRAY_APPEND( p_sys->programs, p_list->p_values[i].i_int );
+ UpdatePESFilters( p_demux, false );
}
-
- /* Select/filter current ones */
- for( int i=0; i<p_sys->programs.i_size; i++ )
+ else // All ES Mode
{
- msg_Dbg( p_demux, "Program %d in new selection", p_sys->programs.p_elems[i] );
- SetPrgFilter( p_demux, p_sys->programs.p_elems[i], true );
+ p_sys->b_es_all = true;
+ ts_pat_t *p_pat = p_sys->pid[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 );
}
p_sys->b_default_selection = false;
return VLC_SUCCESS;
}
+ case DEMUX_SET_ES:
+ {
+ i_int = (int)va_arg( args, int );
+ msg_Dbg( p_demux, "DEMUX_SET_ES %d", i_int );
+
+ if( !p_sys->b_es_all ) /* Won't change anything */
+ UpdatePESFilters( p_demux, false );
+
+ return VLC_SUCCESS;
+ }
+
case DEMUX_GET_TITLE_INFO:
{
struct input_title_t ***v = va_arg( args, struct input_title_t*** );
return VLC_EGENERIC;
}
-static int SetPIDFilter( demux_t *p_demux, int i_pid, bool b_selected )
+static int SetPIDFilter( demux_sys_t *p_sys, ts_pid_t *p_pid, bool b_selected )
{
- demux_sys_t *p_sys = p_demux->p_sys;
+ if( b_selected )
+ p_pid->i_flags |= FLAG_FILTERED;
+ else
+ p_pid->i_flags &= ~FLAG_FILTERED;
if( !p_sys->b_access_control )
return VLC_EGENERIC;
return stream_Control( p_sys->stream, STREAM_SET_PRIVATE_ID_STATE,
- i_pid, b_selected );
-}
-
-static void SetPrgFilter( demux_t *p_demux, int i_prg_id, bool b_selected )
-{
- demux_sys_t *p_sys = p_demux->p_sys;
- ts_pmt_t *p_pmt = NULL;
- int i_pmt_pid = -1;
-
- /* Search pmt to be unselected */
- if(unlikely(p_sys->pid[0].type != TYPE_PAT))
- return;
-
- ts_pat_t *p_pat = p_sys->pid[0].u.p_pat;
- for( int i = 0; i < p_pat->programs.i_size; i++ )
- {
- ts_pid_t *pmtpid = p_pat->programs.p_elems[i];
- assert(pmtpid->type == TYPE_PMT);
-
- if( pmtpid->u.p_pmt->i_number == i_prg_id )
- {
- i_pmt_pid = pmtpid->i_pid;
- p_pmt = pmtpid->u.p_pmt;
- break;
- }
-
- if( i_pmt_pid > 0 )
- break;
- }
- if( i_pmt_pid <= 0 )
- return;
- assert( p_pmt );
-
- p_pmt->pcr.b_disable = !p_sys->b_trust_pcr;
-
- SetPIDFilter( p_demux, i_pmt_pid, b_selected );
- if( p_pmt->i_pid_pcr > 0 )
- SetPIDFilter( p_demux, p_pmt->i_pid_pcr, b_selected );
-
- /* All ES */
- for( int i = 0; i < p_pmt->e_streams.i_size; i++ )
- {
- ts_pid_t *pespid = p_pmt->e_streams.p_elems[i];
- assert( pespid->type == TYPE_PES );
- /* We only remove/select es that aren't defined by extra pmt */
- if( pespid->u.p_pes->es.id || !b_selected )
- SetPIDFilter( p_demux, i, b_selected );
- }
+ p_pid->i_pid, b_selected );
}
static void PIDReset( ts_pid_t *pid )
}
- SetPIDFilter( p_demux, pid->i_pid, false );
+ SetPIDFilter( p_demux->p_sys, pid, false );
PIDReset( pid );
}
}
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;
{
/* mpeg2 PES */
i_skip = p_header[8] + 9;
- if( i_header < i_skip )
- return VLC_EGENERIC;
if( p_header[7]&0x80 ) /* has pts */
{
break;
}
- if( i_header < i_skip )
- return VLC_EGENERIC;
-
*pi_skip = i_skip;
return VLC_SUCCESS;
}
if( p_pmt->pcr.i_first == -1 ) /* 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;
}
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;
return i_pcr;
}
+static void UpdateScrambledState( demux_t *p_demux, ts_pid_t *p_pid, bool b_scrambled )
+{
+ if( !SCRAMBLED(*p_pid) == !b_scrambled )
+ return;
+
+ msg_Warn( p_demux, "scrambled state changed on pid %d (%d->%d)",
+ p_pid->i_pid, SCRAMBLED(*p_pid), b_scrambled );
+
+ p_pid->i_flags |= (b_scrambled) ? FLAG_SCRAMBLED : FLAGS_NONE;
+
+ if( p_pid->type == TYPE_PES && p_pid->u.p_pes->es.id )
+ {
+ for( int i = 0; i < p_pid->u.p_pes->extra_es.i_size; i++ )
+ {
+ if( p_pid->u.p_pes->extra_es.p_elems[i]->id )
+ es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
+ p_pid->u.p_pes->extra_es.p_elems[i]->id, b_scrambled );
+ }
+ es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
+ p_pid->u.p_pes->es.id, b_scrambled );
+ }
+}
+
static inline void FlushESBuffer( ts_pes_t *p_pes )
{
if( p_pes->p_data )
}
}
-static void ReadyQueuesPostSeek( demux_sys_t *p_sys )
+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;
for( int i=0; i< p_pat->programs.i_size; i++ )
{
if( pid->type != TYPE_PES )
continue;
+ if( pid->u.p_pes->es.id )
+ {
+ block_t *p_block = block_Alloc(1);
+ if( p_block )
+ {
+ p_block->i_buffer = 0;
+ p_block->i_flags = BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED;
+ es_out_Send( p_demux->out, pid->u.p_pes->es.id, p_block );
+ }
+ }
+
pid->i_cc = 0xff;
if( pid->u.p_pes->p_prepcr_outqueue )
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 = &p_sys->pid[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 = p_sys->pid[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;
}
}
}
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 */
{
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 );
}
}
{
const uint8_t *p = p_bk->p_buffer;
const bool b_unit_start = p[1]&0x40;
- const bool b_scrambled = p[3]&0x80;
const bool b_adaptation = p[3]&0x20;
const bool b_payload = p[3]&0x10;
const int i_cc = p[3]&0x0f; /* continuity counter */
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;
}
- /* */
- if( !SCRAMBLED(*pid) != !b_scrambled )
- {
- msg_Warn( p_demux, "scrambled state changed on pid %d (%d->%d)",
- pid->i_pid, SCRAMBLED(*pid), b_scrambled );
-
- pid->i_flags |= (b_scrambled) ? FLAG_SCRAMBLED : FLAGS_NONE;
-
- for( int i = 0; i < pid->u.p_pes->extra_es.i_size; i++ )
- {
- es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
- pid->u.p_pes->extra_es.p_elems[i]->id, b_scrambled );
- }
- es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
- pid->u.p_pes->es.id, b_scrambled );
- }
-
/* We have to gather it */
p_bk->p_buffer += i_skip;
p_bk->i_buffer -= i_skip;
/*****************************************************************************
* 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 );
** libdvbpsi callbacks
****************************************************************************
****************************************************************************/
-static bool ProgramIsSelected( demux_t *p_demux, uint16_t i_pgrm )
+static bool ProgramIsSelected( demux_sys_t *p_sys, uint16_t i_pgrm )
{
- demux_sys_t *p_sys = p_demux->p_sys;
-
for(int i=0; i<p_sys->programs.i_size; i++)
if( p_sys->programs.p_elems[i] == i_pgrm )
return true;
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 void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid )
+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;
- bool b_create_delayed = false;
- if( pid )
+ if( b_create_delayed )
+ p_sys->es_creation = CREATE_ES;
+
+ if( pid && p_sys->es_creation == CREATE_ES )
{
- if( SEEN(*pid) && p_sys->es_creation == DELAY_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++ )
{
- p_sys->es_creation = CREATE_ES;
- b_create_delayed = true;
+ 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( p_sys->es_creation == CREATE_ES )
+ /* Update the default program == first created ES group */
+ if( p_sys->b_default_selection )
{
- 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 );
- }
- p_sys->i_pmt_es += 1 + pid->u.p_pes->extra_es.i_size;
+ p_sys->b_default_selection = false;
+ assert(p_sys->programs.i_size == 1);
+ if( p_sys->programs.p_elems[0] != pid->p_parent->u.p_pmt->i_number )
+ p_sys->programs.p_elems[0] = pid->p_parent->u.p_pmt->i_number;
+ msg_Dbg( p_demux, "Default program is %d", pid->p_parent->u.p_pmt->i_number );
}
}
- else if( p_sys->es_creation == DELAY_ES )
- {
- p_sys->es_creation = CREATE_ES;
- b_create_delayed = true;
- }
if( b_create_delayed )
{
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;
-
- if( pid->u.p_pes->es.id != NULL && ProgramIsSelected( p_demux, pid->p_parent->u.p_pmt->i_number ) )
- SetPIDFilter( p_demux, pid->i_pid, true );
}
}
}
+
+ UpdatePESFilters( p_demux, p_sys->b_es_all );
}
static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
ValidateDVBMeta( p_demux, p_pmt->i_pid_pcr );
- if( ProgramIsSelected( p_demux, p_pmt->i_number ) )
- SetPIDFilter( p_demux, p_pmt->i_pid_pcr, true ); /* Set demux filter */
+ if( ProgramIsSelected( p_sys, p_pmt->i_number ) )
+ SetPIDFilter( p_sys, &p_sys->pid[p_pmt->i_pid_pcr], true ); /* Set demux filter */
/* Parse PMT descriptors */
ts_pmt_registration_type_t registration_type = TS_PMT_REGISTRATION_NONE;
ts_pes_t *p_pes;
ts_pid_t *pespid = &p_sys->pid[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++ )
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 content is *unknown*",
p_dvbpsies->i_pid );
+ p_pes->es.fmt.psz_description = strdup( psz_typedesc );
}
else
{
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 )
{
pespid->u.p_pes = p_pes;
p_pes = e;
+ /* p_pes still tmp, but now contains old config */
+ pespid->u.p_pes->es.id = p_pes->es.id;
if( pespid->u.p_pes->es.id )
+ {
+ p_pes->es.id = NULL;
es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
- pespid->u.p_pes->es.id, p_pes->es.fmt );
+ pespid->u.p_pes->es.id, pespid->u.p_pes->es.fmt );
+ }
+
+ for( int i=0; i<pespid->u.p_pes->extra_es.i_size &&
+ i<p_pes->extra_es.i_size; i++ )
+ {
+ pespid->u.p_pes->extra_es.p_elems[i]->id = p_pes->extra_es.p_elems[i]->id;
+ if( pespid->u.p_pes->extra_es.p_elems[i]->id )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
+ pespid->u.p_pes->extra_es.p_elems[i]->id,
+ pespid->u.p_pes->extra_es.p_elems[i]->fmt );
+ p_pes->extra_es.p_elems[i]->id = NULL;
+ }
+ }
}
ts_pes_Del( p_demux, p_pes ); // delete temp
}
else
{
- AddAndCreateES( p_demux, pespid );
+ AddAndCreateES( p_demux, pespid, false );
}
}
msg_Dbg( p_demux, " * PMT descriptor : CA (0x9) SysID 0x%x",
(p_dr->p_data[0] << 8) | p_dr->p_data[1] );
}
-
- if( ProgramIsSelected( p_demux, p_pmt->i_number ) && pespid->u.p_pes->es.id != NULL )
- SetPIDFilter( p_demux, p_dvbpsies->i_pid, true ); /* Set demux filter */
}
/* Set CAM descrambling */
- if( !ProgramIsSelected( p_demux, p_pmt->i_number ) )
+ if( !ProgramIsSelected( p_sys, p_pmt->i_number ) )
{
dvbpsi_pmt_delete( 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;
PIDRelease( p_demux, old_es_rm.p_elems[i] );
ARRAY_RESET( old_es_rm );
+ UpdatePESFilters( p_demux, p_sys->b_es_all );
+
if( !p_sys->b_trust_pcr )
{
int i_cand = FindPCRCandidate( p_pmt );
/* Now select PID at access level */
if( p_sys->programs.i_size == 0 ||
- ProgramIsSelected( p_demux, p_program->i_number ) )
+ ProgramIsSelected( p_sys, p_program->i_number ) )
{
if( p_sys->programs.i_size == 0 )
{
+ msg_Dbg( p_demux, "temporary receiving program %d", p_program->i_number );
p_sys->b_default_selection = true;
ARRAY_APPEND( p_sys->programs, p_program->i_number );
}
- if( SetPIDFilter( p_demux, p_program->i_pid, true ) )
+ if( SetPIDFilter( p_sys, pmtpid, true ) )
p_sys->b_access_control = false;
else if ( p_sys->es_creation == DELAY_ES )
p_sys->es_creation = CREATE_ES;
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;
ARRAY_RESET( pmt->e_streams );
if( pmt->iod )
IODFree( pmt->iod );
- es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, pmt->i_number );
+ if( pmt->i_number > -1 )
+ es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, pmt->i_number );
free( pmt );
}