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_prg_psi_t *, int64_t time );
+static void ReadyQueuesPostSeek( demux_sys_t *p_sys );
static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
static void PCRFixHandle( demux_t *, ts_prg_psi_t *, block_t * );
static int64_t TimeStampWrapAround( ts_prg_psi_t *, int64_t );
if( !DVBEventInformation( p_demux, &i_time, &i_length ) &&
i_length > 0 && !SeekToTime( p_demux, p_prg, TO_SCALE(i_length) * f ) )
{
+ ReadyQueuesPostSeek( p_sys );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
TO_SCALE(i_length) * f );
return VLC_SUCCESS;
p_prg->i_last_dts ) - p_prg->pcr.i_first;
if( !SeekToTime( p_demux, p_prg, p_prg->pcr.i_first + i_length * f ) )
{
+ ReadyQueuesPostSeek( p_sys );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
FROM_SCALE(p_prg->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 );
+ return VLC_SUCCESS;
+ }
+ break;
+
+ case DEMUX_SET_TIME:
+ i64 = (int64_t)va_arg( args, int64_t );
+
+ if( p_sys->b_canseek &&
+ (p_prg = GetProgramByID( p_sys, i_first_program )) &&
+ p_prg->pcr.i_first > -1 &&
+ !SeekToTime( p_demux, p_prg, p_prg->pcr.i_first + TO_SCALE(i64) ) )
+ {
+ ReadyQueuesPostSeek( p_sys );
+ es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
+ FROM_SCALE(p_prg->pcr.i_first) + i64 - VLC_TS_0 );
return VLC_SUCCESS;
}
break;
/****************************************************************************
* gathering stuff
****************************************************************************/
-static int ParsePESHeader( demux_t *p_demux, const uint8_t *p_header,
+static int ParsePESHeader( demux_t *p_demux, const uint8_t *p_header, size_t i_header,
unsigned *pi_skip, mtime_t *pi_dts, mtime_t *pi_pts )
{
unsigned i_skip;
+ if ( i_header < 9 )
+ return VLC_EGENERIC;
+
switch( p_header[3] )
{
case 0xBC: /* Program stream map */
{
/* mpeg2 PES */
i_skip = p_header[8] + 9;
+ if( i_header < i_skip )
+ return VLC_EGENERIC;
if( p_header[7]&0x80 ) /* has pts */
{
+ if( i_header < 9 + 5 )
+ return VLC_EGENERIC;
*pi_pts = ExtractPESTimestamp( &p_header[9] );
if( p_header[7]&0x40 ) /* has dts */
+ {
+ if( i_header < 14 + 5 )
+ return VLC_EGENERIC;
*pi_dts = ExtractPESTimestamp( &p_header[14] );
+ }
}
}
else
{
i_skip = 6;
+ if( i_header < i_skip + 1 )
+ return VLC_EGENERIC;
while( i_skip < 23 && p_header[i_skip] == 0xff )
{
i_skip++;
+ if( i_header < i_skip + 1 )
+ return VLC_EGENERIC;
}
if( i_skip == 23 )
{
i_skip += 2;
}
+ if( i_header < i_skip + 1 )
+ return VLC_EGENERIC;
+
if( p_header[i_skip]&0x20 )
{
+ if( i_header < i_skip + 5 )
+ return VLC_EGENERIC;
*pi_pts = ExtractPESTimestamp( &p_header[i_skip] );
if( p_header[i_skip]&0x10 ) /* has dts */
{
+ if( i_header < i_skip + 10 )
+ return VLC_EGENERIC;
*pi_dts = ExtractPESTimestamp( &p_header[i_skip+5] );
i_skip += 10;
}
break;
}
+ if( i_header < i_skip )
+ return VLC_EGENERIC;
+
*pi_skip = i_skip;
return VLC_SUCCESS;
}
mtime_t i_pts = -1;
mtime_t i_length = 0;
- /* FIXME find real max size */
const int i_max = block_ChainExtract( p_pes, header, 34 );
- assert(i_max >= 34);
- if (unlikely(i_max < 34))
+ if ( i_max < 4 )
{
block_ChainRelease( p_pes );
return;
return;
}
- /* TODO check size */
- if( ParsePESHeader( p_demux, (uint8_t*)&header, &i_skip, &i_dts, &i_pts ) == VLC_EGENERIC )
+ if( ParsePESHeader( p_demux, (uint8_t*)&header, i_max, &i_skip, &i_dts, &i_pts ) == VLC_EGENERIC )
{
block_ChainRelease( p_pes );
return;
return i_pcr;
}
+static inline void FlushESBuffer( ts_es_t *p_es )
+{
+ if( p_es->p_data )
+ {
+ p_es->i_data_gathered = p_es->i_data_size = 0;
+ block_ChainRelease( p_es->p_data );
+ p_es->p_data = NULL;
+ p_es->pp_last = &p_es->p_data;
+ }
+}
+
+static void ReadyQueuesPostSeek( demux_sys_t *p_sys )
+{
+ for( int i=MIN_ES_PID; i<=MAX_ES_PID; i++ )
+ {
+ ts_pid_t *pid = &p_sys->pid[i];
+
+ if( !pid->es )
+ continue;
+
+ pid->i_cc = 0xff;
+
+ if( pid->es->p_prepcr_outqueue )
+ {
+ block_ChainRelease( pid->es->p_prepcr_outqueue );
+ pid->es->p_prepcr_outqueue = NULL;
+ }
+
+ FlushESBuffer( pid->es );
+
+ for( int j = 0; j < pid->i_extra_es; j++ )
+ FlushESBuffer( pid->extra_es[j] );
+ }
+
+ for( int i=0; i<p_sys->i_pmt; i++ )
+ for( int j=0; j<p_sys->pmt[i]->psi->i_prg; j++ )
+ p_sys->pmt[i]->psi->prg[j]->pcr.i_current = -1;
+}
+
static int SeekToTime( demux_t *p_demux, ts_prg_psi_t *p_prg, int64_t i_scaledtime )
{
demux_sys_t *p_sys = p_demux->p_sys;
unsigned i_skip = 4;
if ( p_pkt->p_buffer[3] & 0x20 ) // adaptation field
{
- i_pcr = GetPCR( p_pkt );
- i_skip += 1 + p_pkt->p_buffer[4];
+ if( p_pkt->i_buffer >= 4 + 2 + 5 )
+ {
+ i_pcr = GetPCR( p_pkt );
+ i_skip += 1 + p_pkt->p_buffer[4];
+ }
}
else
{
mtime_t i_dts = -1;
mtime_t i_pts = -1;
- if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip], &i_skip, &i_dts, &i_pts ) )
+ if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip],
+ p_pkt->i_buffer - i_skip, &i_skip, &i_dts, &i_pts ) )
{
if( i_dts > -1 )
i_pcr = i_dts;
}
int i_pid = PIDGet( p_pkt );
+ p_sys->pid[i_pid].b_seen = true;
if( i_pid != 0x1FFF && p_sys->pid[i_pid].b_valid && p_sys->pid[i_pid].p_owner &&
(p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */
{
bool b_pcrresult = true;
- *pi_pcr = GetPCR( p_pkt );
+ if( p_pkt->i_buffer >= 4 + 2 + 5 )
+ *pi_pcr = GetPCR( p_pkt );
if( *pi_pcr == -1 )
{
if ( p_pkt->p_buffer[3] & 0x20 ) // adaptation field
i_skip += 1 + p_pkt->p_buffer[4];
- if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip], &i_skip, &i_dts, &i_pts ) )
+ if ( VLC_SUCCESS == ParsePESHeader( p_demux, &p_pkt->p_buffer[i_skip],
+ p_pkt->i_buffer - i_skip,
+ &i_skip, &i_dts, &i_pts ) )
{
if( i_dts != -1 )
*pi_pcr = i_dts;
{
demux_sys_t *p_sys = p_demux->p_sys;
+ /* 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_prg->pcr.i_current == -1 )
+ {
+ mtime_t i_mindts = -1;
+ for( int i=MIN_ES_PID; i<=MAX_ES_PID; i++ )
+ {
+ ts_pid_t *p_pid = &p_sys->pid[i];
+ if( p_pid->b_valid && p_pid->i_owner_number == p_prg->i_number && p_pid->es )
+ {
+ block_t *p_block = p_pid->es->p_prepcr_outqueue;
+ while( p_block && p_block->i_dts == VLC_TS_INVALID )
+ p_block = p_block->p_next;
+
+ if( p_block )
+ msg_Warn( p_demux, "Program %ld %ld *******", i_mindts, p_block->i_dts );
+
+ if( p_block && ( i_mindts == -1 || p_block->i_dts < i_mindts ) )
+ {
+ i_mindts = p_block->i_dts;
+ msg_Warn( p_demux, "Program %ld %ld *******", i_mindts, p_block->i_dts );
+ }
+ }
+ }
+
+ if( i_mindts > VLC_TS_INVALID )
+ {
+ msg_Dbg( p_demux, "Program %d PCR prequeue fixup %"PRId64"->%"PRId64,
+ p_prg->i_number, TO_SCALE(i_mindts), i_pcr );
+ i_pcr = TO_SCALE(i_mindts);
+ }
+ }
+
p_prg->pcr.i_current = i_pcr;
if( p_prg->pcr.i_first == -1 )
{
static int FindPCRCandidate( demux_sys_t *p_sys, ts_prg_psi_t *p_prg )
{
ts_pid_t *p_cand = NULL;
+ int i_previous = p_prg->i_pid_pcr;
for( int i=MIN_ES_PID; i<=MAX_ES_PID; i++ )
{
ts_pid_t *p_pid = &p_sys->pid[i];
if( p_pid->b_seen && p_pid->es && p_pid->es->id &&
- p_pid->i_owner_number == p_prg->i_number )
+ p_pid->i_owner_number == p_prg->i_number &&
+ p_cand->i_pid != i_previous )
{
if( p_pid->probed.i_pcr_count ) /* check PCR frequency first */
{
if( i_clean )
free( pp_clean );
+ if( !p_sys->b_trust_pcr )
+ {
+ int i_cand = FindPCRCandidate( p_demux->p_sys, prg );
+ prg->i_pid_pcr = i_cand;
+ prg->pcr.b_disable = true;
+ msg_Warn( p_demux, "PCR not trusted for program %d, set up workaround using pid %d",
+ prg->i_number, i_cand );
+ }
+
/* Probe Boundaries */
if( p_sys->b_canfastseek && prg->i_last_dts == -1 )
{