Commit 70ee5fbf authored by Laurent Aimar's avatar Laurent Aimar

* block: added

    - BLOCK_FLAG_CORRUPTED : signal corrupted data (do not use anymore
 BLOCK_FLAG_DISCONTINUITY in that case)
    - BLOCK_FLAG_PREROLL : mark this block to be decoded (no matter what).
 * ffmpeg, libmpeg2: support BLOCK_FLAG_PREROLL (ie disable frame dropping).
 * input: added ES_OUT_SET_NEXT_DISPLAY_TIME to ease the work for preroll
 (untested).
 * mp4: added support for CTTS table (pts, needed for h264+bframe).
 * decoders: for now handle discontinuity and corrupted block the same way.
parent 26b8ba09
...@@ -68,6 +68,10 @@ typedef struct block_sys_t block_sys_t; ...@@ -68,6 +68,10 @@ typedef struct block_sys_t block_sys_t;
#define BLOCK_FLAG_CLOCK 0x0200 #define BLOCK_FLAG_CLOCK 0x0200
/** This block is scrambled */ /** This block is scrambled */
#define BLOCK_FLAG_SCRAMBLED 0x0400 #define BLOCK_FLAG_SCRAMBLED 0x0400
/** This block has to be decoded but not be displayed */
#define BLOCK_FLAG_PREROLL 0x0800
/** This block is corrupted and/or there is data loss */
#define BLOCK_FLAG_CORRUPTED 0x1000
#define BLOCK_FLAG_PRIVATE_MASK 0xffff0000 #define BLOCK_FLAG_PRIVATE_MASK 0xffff0000
#define BLOCK_FLAG_PRIVATE_SHIFT 16 #define BLOCK_FLAG_PRIVATE_SHIFT 16
......
...@@ -59,7 +59,12 @@ enum es_out_query_e ...@@ -59,7 +59,12 @@ enum es_out_query_e
ES_OUT_SET_GROUP, /* arg1= int */ ES_OUT_SET_GROUP, /* arg1= int */
ES_OUT_GET_GROUP, /* arg1= int* */ ES_OUT_GET_GROUP, /* arg1= int* */
/* PCR handling, dts/pts will be automatically computed using thoses PCR */ /* PCR handling, dts/pts will be automatically computed using thoses PCR
* XXX: SET_PCR(_GROUP) is in charge of the pace control. They will wait to slow
* down the demuxer to read at the right speed.
* XXX: if you want PREROLL just call RESET_PCR and ES_OUT_SET_NEXT_DISPLAY_TIME and send
* data to the decoder *without* calling SET_PCR until preroll is finished.
*/
ES_OUT_SET_PCR, /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/ ES_OUT_SET_PCR, /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
ES_OUT_SET_GROUP_PCR, /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ ES_OUT_SET_GROUP_PCR, /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/
ES_OUT_RESET_PCR, /* no arg */ ES_OUT_RESET_PCR, /* no arg */
...@@ -69,7 +74,10 @@ enum es_out_query_e ...@@ -69,7 +74,10 @@ enum es_out_query_e
ES_OUT_GET_TS, /* arg1=int64_t i_ts(microsecond!) (using default group 0), arg2=int64_t* converted i_ts */ ES_OUT_GET_TS, /* arg1=int64_t i_ts(microsecond!) (using default group 0), arg2=int64_t* converted i_ts */
/* Try not to use this one as it is a bit hacky */ /* Try not to use this one as it is a bit hacky */
ES_OUT_SET_FMT /* arg1= es_out_id_t* arg2=es_format_t* */ ES_OUT_SET_FMT, /* arg1= es_out_id_t* arg2=es_format_t* */
/* Allow preroll of data (data with dts/pts < i_pts for one ES will be decoded but not displayed */
ES_OUT_SET_NEXT_DISPLAY_TIME, /* arg1=es_out_id_t* arg2=int64_t i_pts(microsecond) */
}; };
struct es_out_t struct es_out_t
......
...@@ -174,7 +174,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -174,7 +174,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY ) if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
p_sys->i_state = STATE_NOSYNC; p_sys->i_state = STATE_NOSYNC;
} }
......
...@@ -175,7 +175,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -175,7 +175,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY ) if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
p_sys->i_state = STATE_NOSYNC; p_sys->i_state = STATE_NOSYNC;
} }
......
...@@ -181,7 +181,7 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -181,7 +181,7 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
p_block = *pp_block; p_block = *pp_block;
if( p_block->i_flags&BLOCK_FLAG_DISCONTINUITY ) if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
block_Release( p_block ); block_Release( p_block );
return NULL; return NULL;
......
...@@ -209,7 +209,7 @@ aout_buffer_t *E_( DecodeAudio )( decoder_t *p_dec, block_t **pp_block ) ...@@ -209,7 +209,7 @@ aout_buffer_t *E_( DecodeAudio )( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( p_block->i_buffer <= 0 || p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) if( p_block->i_buffer <= 0 || ( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) )
{ {
block_Release( p_block ); block_Release( p_block );
return NULL; return NULL;
......
...@@ -438,7 +438,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) ...@@ -438,7 +438,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
p_block = *pp_block; p_block = *pp_block;
if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
p_sys->i_buffer = 0; p_sys->i_buffer = 0;
p_sys->i_pts = 0; /* To make sure we recover properly */ p_sys->i_pts = 0; /* To make sure we recover properly */
...@@ -450,6 +450,14 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) ...@@ -450,6 +450,14 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( p_block->i_flags & BLOCK_FLAG_PREROLL )
{
/* Do not care about late frames when prerolling
* TODO avoid decoding of non reference frame
* (ie all B except for H264 where it depends only on nal_ref_idc) */
p_sys->i_late_frames = 0;
}
if( !p_dec->b_pace_control && p_sys->i_late_frames > 0 && if( !p_dec->b_pace_control && p_sys->i_late_frames > 0 &&
mdate() - p_sys->i_late_frames_start > I64C(5000000) ) mdate() - p_sys->i_late_frames_start > I64C(5000000) )
{ {
...@@ -579,8 +587,9 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) ...@@ -579,8 +587,9 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
continue; continue;
} }
/* Update frame late count*/ /* Update frame late count (except when doing preroll) */
if( p_sys->i_pts && p_sys->i_pts <= mdate() ) if( p_sys->i_pts && p_sys->i_pts <= mdate() &&
!(p_block->i_flags & BLOCK_FLAG_PREROLL) )
{ {
p_sys->i_late_frames++; p_sys->i_late_frames++;
if( p_sys->i_late_frames == 1 ) if( p_sys->i_late_frames == 1 )
...@@ -630,6 +639,10 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) ...@@ -630,6 +639,10 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
{ {
p_pic->date = p_sys->i_pts; p_pic->date = p_sys->i_pts;
static int64_t i_old = 0;
msg_Dbg( p_dec, "pts=%lld diff=%lld", p_pic->date, p_pic->date - i_old );
i_old = p_pic->date;
/* interpolate the next PTS */ /* interpolate the next PTS */
if( p_sys->p_context->frame_rate > 0 ) if( p_sys->p_context->frame_rate > 0 )
{ {
...@@ -657,6 +670,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) ...@@ -657,6 +670,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block )
else else
{ {
p_dec->pf_vout_buffer_del( p_dec, p_pic ); p_dec->pf_vout_buffer_del( p_dec, p_pic );
msg_Dbg( p_dec, "pts=0" );
} }
} }
......
...@@ -295,7 +295,7 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -295,7 +295,7 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts ); aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts );
} }
if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY ) if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
p_sys->i_state = STATE_NOSYNC; p_sys->i_state = STATE_NOSYNC;
} }
......
...@@ -65,6 +65,8 @@ struct decoder_sys_t ...@@ -65,6 +65,8 @@ struct decoder_sys_t
* the sequence header ? */ * the sequence header ? */
vlc_bool_t b_slice_i; /* intra-slice refresh stream */ vlc_bool_t b_slice_i; /* intra-slice refresh stream */
vlc_bool_t b_preroll;
/* /*
* Output properties * Output properties
*/ */
...@@ -137,6 +139,7 @@ static int OpenDecoder( vlc_object_t *p_this ) ...@@ -137,6 +139,7 @@ static int OpenDecoder( vlc_object_t *p_this )
p_sys->b_garbage_pic = 0; p_sys->b_garbage_pic = 0;
p_sys->b_slice_i = 0; p_sys->b_slice_i = 0;
p_sys->b_skip = 0; p_sys->b_skip = 0;
p_sys->b_preroll = VLC_FALSE;
#if defined( __i386__ ) #if defined( __i386__ )
if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMX ) if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
...@@ -213,7 +216,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -213,7 +216,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( (p_block->i_flags&BLOCK_FLAG_DISCONTINUITY) && if( (p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) &&
p_sys->p_synchro && p_sys->p_synchro &&
p_sys->p_info->sequence && p_sys->p_info->sequence &&
p_sys->p_info->sequence->width != (unsigned)-1 ) p_sys->p_info->sequence->width != (unsigned)-1 )
...@@ -244,6 +247,17 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -244,6 +247,17 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
} }
} }
if( p_block->i_flags & BLOCK_FLAG_PREROLL )
{
p_sys->b_preroll = VLC_TRUE;
}
else if( p_sys->b_preroll )
{
p_sys->b_preroll = VLC_FALSE;
/* Reset synchro */
vout_SynchroReset( p_sys->p_synchro );
}
#ifdef PIC_FLAG_PTS #ifdef PIC_FLAG_PTS
if( p_block->i_pts ) if( p_block->i_pts )
{ {
...@@ -432,7 +446,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -432,7 +446,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
p_sys->p_info->current_picture->nb_fields, i_pts, i_dts, p_sys->p_info->current_picture->nb_fields, i_pts, i_dts,
p_sys->i_current_rate ); p_sys->i_current_rate );
if( !p_dec->b_pace_control && if( !p_dec->b_pace_control && !p_sys->b_preroll &&
!(p_sys->b_slice_i !(p_sys->b_slice_i
&& ((p_sys->p_info->current_picture->flags && ((p_sys->p_info->current_picture->flags
& PIC_MASK_CODING_TYPE) == P_CODING_TYPE)) & PIC_MASK_CODING_TYPE) == P_CODING_TYPE))
......
...@@ -196,7 +196,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -196,7 +196,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY ) if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{ {
p_sys->i_state = STATE_NOSYNC; p_sys->i_state = STATE_NOSYNC;
} }
......
...@@ -386,7 +386,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, ...@@ -386,7 +386,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
block_t *p_block = *pp_block; block_t *p_block = *pp_block;
void *p_buf; void *p_buf;
if( ( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) != 0 ) if( ( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) != 0 )
{ {
/* Don't send the the first packet after a discontinuity to /* Don't send the the first packet after a discontinuity to
* theora_decode, otherwise we get purple/green display artifacts * theora_decode, otherwise we get purple/green display artifacts
......
...@@ -74,7 +74,10 @@ typedef struct ...@@ -74,7 +74,10 @@ typedef struct
/* with this we can calculate dts/pts without waste memory */ /* with this we can calculate dts/pts without waste memory */
uint64_t i_first_dts; uint64_t i_first_dts;
uint32_t *p_sample_count_dts; uint32_t *p_sample_count_dts;
uint32_t *p_sample_delta_dts; /* dts delta */ uint32_t *p_sample_delta_dts; /* dts delta */
uint32_t *p_sample_count_pts;
uint32_t *p_sample_offset_pts; /* pts-dts */
/* TODO if needed add pts /* TODO if needed add pts
but quickly *add* support for edts and seeking */ but quickly *add* support for edts and seeking */
...@@ -162,7 +165,7 @@ static int MP4_TrackNextSample( demux_t *, mp4_track_t * ); ...@@ -162,7 +165,7 @@ static int MP4_TrackNextSample( demux_t *, mp4_track_t * );
static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t ); static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
/* Return time in s of a track */ /* Return time in s of a track */
static inline int64_t MP4_TrackGetPTS( demux_t *p_demux, mp4_track_t *p_track ) static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
{ {
#define chunk p_track->chunk[p_track->i_chunk] #define chunk p_track->chunk[p_track->i_chunk]
...@@ -213,6 +216,24 @@ static inline int64_t MP4_TrackGetPTS( demux_t *p_demux, mp4_track_t *p_track ) ...@@ -213,6 +216,24 @@ static inline int64_t MP4_TrackGetPTS( demux_t *p_demux, mp4_track_t *p_track )
return I64C(1000000) * i_dts / p_track->i_timescale; return I64C(1000000) * i_dts / p_track->i_timescale;
} }
static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track )
{
mp4_chunk_t *ck = &p_track->chunk[p_track->i_chunk];
unsigned int i_index = 0;
unsigned int i_sample = p_track->i_sample - ck->i_sample_first;
if( ck->p_sample_count_pts == NULL || ck->p_sample_offset_pts == NULL )
return -1;
for( i_index = 0;; i_index++ )
{
if( i_sample < ck->p_sample_count_pts[i_index] )
return ck->p_sample_offset_pts[i_index] * I64C(1000000) / p_track->i_timescale;
i_sample -= ck->p_sample_count_pts[i_index];
}
}
static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys ) static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
{ {
return I64C(1000000) * p_sys->i_time / p_sys->i_timescale; return I64C(1000000) * p_sys->i_time / p_sys->i_timescale;
...@@ -604,17 +625,18 @@ static int Demux( demux_t *p_demux ) ...@@ -604,17 +625,18 @@ static int Demux( demux_t *p_demux )
continue; continue;
} }
while( MP4_TrackGetPTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) ) while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
{ {
#if 0 #if 0
msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track, msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track,
MP4_TrackGetPTS( p_demux, tk ), MP4_TrackGetDTS( p_demux, tk ),
MP4_GetMoviePTS( p_sys ) ); MP4_GetMoviePTS( p_sys ) );
#endif #endif
if( MP4_TrackSampleSize( tk ) > 0 ) if( MP4_TrackSampleSize( tk ) > 0 )
{ {
block_t *p_block; block_t *p_block;
int64_t i_delta;
/* go,go go ! */ /* go,go go ! */
if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) ) if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
...@@ -669,15 +691,22 @@ static int Demux( demux_t *p_demux ) ...@@ -669,15 +691,22 @@ static int Demux( demux_t *p_demux )
} }
} }
} }
p_block->i_dts = MP4_TrackGetPTS( p_demux, tk ) + 1; /* dts */
p_block->i_dts = MP4_TrackGetDTS( p_demux, tk ) + 1;
/* pts */
i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
if( i_delta >= 0 )
p_block->i_pts = p_block->i_dts + i_delta;
else if( tk->fmt.i_cat != VIDEO_ES )
p_block->i_pts = p_block->i_dts;
else
p_block->i_pts = 0;
p_block->i_pts = tk->fmt.i_cat == VIDEO_ES ? if( tk->fmt.i_cat == VIDEO_ES )
0 : p_block->i_dts + 1; msg_Dbg( p_demux, "pts=%lld dts=%lld", p_block->i_pts, p_block->i_dts );
if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) ) if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) )
{
es_out_Send( p_demux->out, tk->p_es, p_block ); es_out_Send( p_demux->out, tk->p_es, p_block );
}
} }
/* Next sample */ /* Next sample */
...@@ -918,8 +947,15 @@ static int TrackCreateChunksIndex( demux_t *p_demux, ...@@ -918,8 +947,15 @@ static int TrackCreateChunksIndex( demux_t *p_demux,
/* first we read chunk offset */ /* first we read chunk offset */
for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
{ {
p_demux_track->chunk[i_chunk].i_offset = mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
p_co64->data.p_co64->i_chunk_offset[i_chunk];
ck->i_offset = p_co64->data.p_co64->i_chunk_offset[i_chunk];
ck->i_first_dts = 0;
ck->p_sample_count_dts = NULL;
ck->p_sample_delta_dts = NULL;
ck->p_sample_count_pts = NULL;
ck->p_sample_offset_pts = NULL;
} }
/* now we read index for SampleEntry( soun vide mp4a mp4v ...) /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
...@@ -963,12 +999,9 @@ static int TrackCreateChunksIndex( demux_t *p_demux, ...@@ -963,12 +999,9 @@ static int TrackCreateChunksIndex( demux_t *p_demux,
static int TrackCreateSamplesIndex( demux_t *p_demux, static int TrackCreateSamplesIndex( demux_t *p_demux,
mp4_track_t *p_demux_track ) mp4_track_t *p_demux_track )
{ {
MP4_Box_t *p_stts; /* makes mapping between sample and decoding time, MP4_Box_t *p_box;
ctts make same mapping but for composition time, MP4_Box_data_stsz_t *stsz;
not yet used and probably not usefull */ MP4_Box_data_stts_t *stts;
MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2
that uses a compressed form FIXME make them in libmp4
as a unique type */
/* TODO use also stss and stsh table for seeking */ /* TODO use also stss and stsh table for seeking */
/* FIXME use edit table */ /* FIXME use edit table */
int64_t i_sample; int64_t i_sample;
...@@ -979,23 +1012,35 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, ...@@ -979,23 +1012,35 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
int64_t i_last_dts; int64_t i_last_dts;
p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" ); /* Find stsz
p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */ * Gives the sample size for each samples. There is also a stz2 table
* (compressed form) that we need to implement TODO */
if( ( !p_stts )||( !p_stsz ) ) p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" );
if( !p_box )
{ {
msg_Warn( p_demux, "cannot read sample table" ); /* FIXME and stz2 */
return( VLC_EGENERIC ); msg_Warn( p_demux, "cannot find STSZ box" );
return VLC_EGENERIC;
} }
stsz = p_box->data.p_stsz;
p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count; /* Find stts
* Gives mapping between sample and decoding time
*/
p_box = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
if( !p_box )
{
msg_Warn( p_demux, "cannot find STTS box" );
return VLC_EGENERIC;
}
stts = p_box->data.p_stts;
/* for sample size, there are 2 case */ /* Use stsz table to create a sample number -> sample size table */
if( p_stsz->data.p_stsz->i_sample_size ) p_demux_track->i_sample_count = stsz->i_sample_count;
if( stsz->i_sample_size )
{ {
/* 1: all sample have the same size, so no need to construct a table */ /* 1: all sample have the same size, so no need to construct a table */
p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size; p_demux_track->i_sample_size = stsz->i_sample_size;
p_demux_track->p_sample_size = NULL; p_demux_track->p_sample_size = NULL;
} }
else else
...@@ -1008,75 +1053,65 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, ...@@ -1008,75 +1053,65 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ ) for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
{ {
p_demux_track->p_sample_size[i_sample] = p_demux_track->p_sample_size[i_sample] =
p_stsz->data.p_stsz->i_entry_size[i_sample]; stsz->i_entry_size[i_sample];
} }
} }
/* we have extracted all the information from stsz, now use stts */
/* if we don't want to waste too much memory, we can't expand /* Use stts table to crate a sample number -> dts table.
the box! so each chunk will contain an "extract" of this table * XXX: if we don't want to waste too much memory, we can't expand
for fast research */ * the box! so each chunk will contain an "extract" of this table
* for fast research (problem with raw stream where a sample is sometime
* just channels*bits_per_sample/8 */
i_last_dts = 0; i_last_dts = 0;
i_index = 0; i_index_sample_used = 0; i_index = 0; i_index_sample_used = 0;
/* create and init last data for each chunk */
for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
{ {
mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
int64_t i_entry, i_sample_count, i; int64_t i_entry, i_sample_count, i;
/* save last dts */ /* save last dts */
p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts; ck->i_first_dts = i_last_dts;
/* count how many entries are needed for this chunk /* count how many entries are needed for this chunk
* for p_sample_delta_dts and p_sample_count_dts */ * for p_sample_delta_dts and p_sample_count_dts */
i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count; i_sample_count = ck->i_sample_count;
i_entry = 0; i_entry = 0;
while( i_sample_count > 0 ) while( i_sample_count > 0 )
{ {
i_sample_count -= i_sample_count -= stts->i_sample_count[i_index+i_entry];
p_stts->data.p_stts->i_sample_count[i_index+i_entry]; /* don't count already used sample in this entry */
if( i_entry == 0 ) if( i_entry == 0 )
{
/* don't count already used sample in this entry */
i_sample_count += i_index_sample_used; i_sample_count += i_index_sample_used;
}
i_entry++; i_entry++;
} }
/* allocate them */ /* allocate them */
p_demux_track->chunk[i_chunk].p_sample_count_dts = ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) );
calloc( i_entry, sizeof( uint32_t ) ); ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) );
p_demux_track->chunk[i_chunk].p_sample_delta_dts =
calloc( i_entry, sizeof( uint32_t ) );
/* now copy */ /* now copy */
i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count; i_sample_count = ck->i_sample_count;
for( i = 0; i < i_entry; i++ ) for( i = 0; i < i_entry; i++ )
{ {
int64_t i_used; int64_t i_used;
int64_t i_rest; int64_t i_rest;
i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_rest = stts->i_sample_count[i_index] - i_index_sample_used;
i_index_sample_used;
i_used = __MIN( i_rest, i_sample_count ); i_used = __MIN( i_rest, i_sample_count );
i_index_sample_used += i_used; i_index_sample_used += i_used;
i_sample_count -= i_used; i_sample_count -= i_used;
p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used; ck->p_sample_count_dts[i] = i_used;
ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index];
p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] = i_last_dts += i_used * ck->p_sample_delta_dts[i];
p_stts->data.p_stts->i_sample_delta[i_index];
i_last_dts += i_used * if( i_index_sample_used >= stts->i_sample_count[i_index] )
p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];
if( i_index_sample_used >=
p_stts->data.p_stts->i_sample_count[i_index] )
{ {
i_index++; i_index++;
i_index_sample_used = 0; i_index_sample_used = 0;
...@@ -1084,6 +1119,70 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, ...@@ -1084,6 +1119,70 @@ static int TrackCreateSamplesIndex( demux_t *p_demux,
} }
} }
/* Find ctts
* Gives the delta between decoding time (dts) and composition table (pts)
*/
p_box = MP4_BoxGet( p_demux_track->p_stbl, "ctts" );
if( p_box )
{
MP4_Box_data_ctts_t *ctts = p_box->data.p_ctts;
msg_Warn( p_demux, "CTTS table" );
/* Create pts-dts table per chunk */
i_index = 0; i_index_sample_used = 0;
for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
{
mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
int64_t i_entry, i_sample_count, i;
/* count how many entries are needed for this chunk
* for p_sample_delta_dts and p_sample_count_dts */
i_sample_count = ck->i_sample_count;
i_entry = 0;
while( i_sample_count > 0 )
{
i_sample_count -= ctts->i_sample_count[i_index+i_entry];
/* don't count already used sample in this entry */
if( i_entry == 0 )
i_sample_count += i_index_sample_used;
i_entry++;
}
/* allocate them */
ck->p_sample_count_pts = calloc( i_entry, sizeof( uint32_t ) );
ck->p_sample_offset_pts = calloc( i_entry, sizeof( uint32_t ) );
/* now copy */
i_sample_count = ck->i_sample_count;
for( i = 0; i < i_entry; i++ )
{
int64_t i_used;
int64_t i_rest;
i_rest = ctts->i_sample_count[i_index] -
i_index_sample_used;
i_used = __MIN( i_rest, i_sample_count );
i_index_sample_used += i_used;
i_sample_count -= i_used;
ck->p_sample_count_pts[i] = i_used;
ck->p_sample_offset_pts[i] = ctts->i_sample_offset[i_index];
if( i_index_sample_used >= ctts->i_sample_count[i_index] )
{
i_index++;
i_index_sample_used = 0;
}
}
}
}
msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:"I64Fd"s", msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:"I64Fd"s",
p_demux_track->i_track_ID, p_demux_track->i_sample_count, p_demux_track->i_track_ID, p_demux_track->i_sample_count,
i_last_dts / p_demux_track->i_timescale ); i_last_dts / p_demux_track->i_timescale );
...@@ -1821,6 +1920,9 @@ static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track ) ...@@ -1821,6 +1920,9 @@ static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track )
{ {
FREE(p_track->chunk[i_chunk].p_sample_count_dts); FREE(p_track->chunk[i_chunk].p_sample_count_dts);
FREE(p_track->chunk[i_chunk].p_sample_delta_dts ); FREE(p_track->chunk[i_chunk].p_sample_delta_dts );
FREE(p_track->chunk[i_chunk].p_sample_count_pts);
FREE(p_track->chunk[i_chunk].p_sample_offset_pts );
} }
} }
FREE( p_track->chunk ); FREE( p_track->chunk );
...@@ -2055,7 +2157,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track ) ...@@ -2055,7 +2157,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst; MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst;
int64_t i_mvt = MP4_TrackGetPTS( p_demux, p_track ) * int64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) *
p_sys->i_timescale / (int64_t)1000000; p_sys->i_timescale / (int64_t)1000000;
if( p_track->i_elst < elst->i_entry_count && if( p_track->i_elst < elst->i_entry_count &&
...@@ -2063,7 +2165,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track ) ...@@ -2063,7 +2165,7 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
elst->i_segment_duration[p_track->i_elst] ) elst->i_segment_duration[p_track->i_elst] )
{ {
MP4_TrackSetELST( p_demux, p_track, MP4_TrackSetELST( p_demux, p_track,
MP4_TrackGetPTS( p_demux, p_track ) ); MP4_TrackGetDTS( p_demux, p_track ) );
} }
} }
......
...@@ -1420,7 +1420,7 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk ) ...@@ -1420,7 +1420,7 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
{ {
/* Small video artifacts are usually better then /* Small video artifacts are usually better then
* dropping full frames */ * dropping full frames */
pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY; pid->es->p_pes->i_flags |= BLOCK_FLAG_CORRUPTED;
} }
} }
} }
......
...@@ -60,6 +60,8 @@ struct decoder_owner_sys_t ...@@ -60,6 +60,8 @@ struct decoder_owner_sys_t
{ {
vlc_bool_t b_own_thread; vlc_bool_t b_own_thread;
int64_t i_preroll_end;
input_thread_t *p_input; input_thread_t *p_input;
aout_instance_t *p_aout; aout_instance_t *p_aout;
...@@ -276,6 +278,11 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ) ...@@ -276,6 +278,11 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec )
return VLC_TRUE; return VLC_TRUE;
} }
void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end )
{
p_dec->p_owner->i_preroll_end = i_preroll_end;
}
#if 0 #if 0
/** /**
* Create a NULL packet for padding in case of a data loss * Create a NULL packet for padding in case of a data loss
...@@ -392,6 +399,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -392,6 +399,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
return NULL; return NULL;
} }
p_dec->p_owner->b_own_thread = VLC_TRUE; p_dec->p_owner->b_own_thread = VLC_TRUE;
p_dec->p_owner->i_preroll_end = -1;
p_dec->p_owner->p_input = p_input; p_dec->p_owner->p_input = p_input;
p_dec->p_owner->p_aout = NULL; p_dec->p_owner->p_aout = NULL;
p_dec->p_owner->p_aout_input = NULL; p_dec->p_owner->p_aout_input = NULL;
...@@ -610,9 +618,21 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -610,9 +618,21 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, while( (p_aout_buf = p_dec->pf_decode_audio( p_dec,
&p_packetized_block )) ) &p_packetized_block )) )
{ {
aout_DecPlay( p_dec->p_owner->p_aout, /* FIXME the best would be to handle the case start_date < preroll < end_date
p_dec->p_owner->p_aout_input, * but that's not easy with non raw audio stream */
p_aout_buf ); if( p_dec->p_owner->i_preroll_end > 0 &&
p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
{
aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input, p_aout_buf );
}
else
{
p_dec->p_owner->i_preroll_end = -1;
aout_DecPlay( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input,
p_aout_buf );
}
} }
p_packetized_block = p_next; p_packetized_block = p_next;
...@@ -621,8 +641,19 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -621,8 +641,19 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
} }
else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
{ {
aout_DecPlay( p_dec->p_owner->p_aout, if( p_dec->p_owner->i_preroll_end > 0 &&
p_dec->p_owner->p_aout_input, p_aout_buf ); p_aout_buf->start_date < p_dec->p_owner->i_preroll_end )
{
aout_DecDeleteBuffer( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input, p_aout_buf );
}
else
{
p_dec->p_owner->i_preroll_end = -1;
aout_DecPlay( p_dec->p_owner->p_aout,
p_dec->p_owner->p_aout_input,
p_aout_buf );
}
} }
} }
else if( p_dec->fmt_in.i_cat == VIDEO_ES ) else if( p_dec->fmt_in.i_cat == VIDEO_ES )
...@@ -646,9 +677,18 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -646,9 +677,18 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
while( (p_pic = p_dec->pf_decode_video( p_dec, while( (p_pic = p_dec->pf_decode_video( p_dec,
&p_packetized_block )) ) &p_packetized_block )) )
{ {
vout_DatePicture( p_dec->p_owner->p_vout, p_pic, if( p_dec->p_owner->i_preroll_end > 0 &&
p_pic->date ); p_pic->date < p_dec->p_owner->i_preroll_end )
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); {
vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
}
else
{
p_dec->p_owner->i_preroll_end = -1;
vout_DatePicture( p_dec->p_owner->p_vout, p_pic,
p_pic->date );
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
}
} }
p_packetized_block = p_next; p_packetized_block = p_next;
...@@ -657,8 +697,17 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -657,8 +697,17 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
} }
else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) ) else while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
{ {
vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date ); if( p_dec->p_owner->i_preroll_end > 0 &&
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); p_pic->date < p_dec->p_owner->i_preroll_end )
{
vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic );
}
else
{
p_dec->p_owner->i_preroll_end = -1;
vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date );
vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic );
}
} }
} }
else if( p_dec->fmt_in.i_cat == SPU_ES ) else if( p_dec->fmt_in.i_cat == SPU_ES )
...@@ -667,6 +716,15 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -667,6 +716,15 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
subpicture_t *p_spu; subpicture_t *p_spu;
while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) ) while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) )
{ {
if( p_dec->p_owner->i_preroll_end > 0 &&
p_spu->i_start < p_dec->p_owner->i_preroll_end &&
( p_spu->i_stop <= 0 || p_spu->i_stop <= p_dec->p_owner->i_preroll_end ) )
{
spu_DestroySubpicture( p_dec->p_owner->p_vout->p_spu, p_spu );
continue;
}
p_dec->p_owner->i_preroll_end = -1;
p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
if( p_vout ) if( p_vout )
{ {
......
...@@ -61,6 +61,9 @@ struct es_out_id_t ...@@ -61,6 +61,9 @@ struct es_out_id_t
int i_id; int i_id;
es_out_pgrm_t *p_pgrm; es_out_pgrm_t *p_pgrm;
/* */
int64_t i_preroll_end;
/* Channel in the track type */ /* Channel in the track type */
int i_channel; int i_channel;
es_format_t fmt; es_format_t fmt;
...@@ -517,6 +520,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt ) ...@@ -517,6 +520,8 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
es->i_id = fmt->i_id; es->i_id = fmt->i_id;
es->p_pgrm = p_pgrm; es->p_pgrm = p_pgrm;
es_format_Copy( &es->fmt, fmt ); es_format_Copy( &es->fmt, fmt );
es->i_preroll_end = -1;
switch( fmt->i_cat ) switch( fmt->i_cat )
{ {
case AUDIO_ES: case AUDIO_ES:
...@@ -601,6 +606,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es ) ...@@ -601,6 +606,7 @@ static void EsSelect( es_out_t *out, es_out_id_t *es )
} }
} }
es->i_preroll_end = -1;
es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE ); es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
return; return;
...@@ -859,6 +865,18 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block ) ...@@ -859,6 +865,18 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
} }
p_block->i_rate = p_input->i_rate; p_block->i_rate = p_input->i_rate;
/* Mark preroll blocks */
if( es->i_preroll_end >= 0 )
{
int64_t i_date = p_block->i_pts;
if( i_date <= 0 )
i_date = p_block->i_dts;
if( i_date < es->i_preroll_end )
p_block->i_flags |= BLOCK_FLAG_PREROLL;
else
es->i_preroll_end = -1;
}
/* TODO handle mute */ /* TODO handle mute */
if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
...@@ -1169,6 +1187,22 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args ) ...@@ -1169,6 +1187,22 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
return VLC_SUCCESS; return VLC_SUCCESS;
} }
case ES_OUT_SET_NEXT_DISPLAY_TIME:
{
int64_t i_date;
es = (es_out_id_t*) va_arg( args, es_out_id_t * );
i_date = (int64_t)va_arg( args, int64_t );
if( !es || !es->p_dec )
return VLC_EGENERIC;
es->i_preroll_end = i_date;
input_DecoderPreroll( es->p_dec, i_date );
return VLC_SUCCESS;
}
default: default:
msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
return VLC_EGENERIC; return VLC_EGENERIC;
......
...@@ -1210,6 +1210,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, ...@@ -1210,6 +1210,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
} }
if( f_pos < 0.0 ) f_pos = 0.0; if( f_pos < 0.0 ) f_pos = 0.0;
if( f_pos > 1.0 ) f_pos = 1.0; if( f_pos > 1.0 ) f_pos = 1.0;
/* Reset the decoders states and clock synch (before calling the demuxer */
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION, if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
f_pos ) ) f_pos ) )
{ {
...@@ -1221,8 +1224,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, ...@@ -1221,8 +1224,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( p_input->i_slave > 0 ) if( p_input->i_slave > 0 )
SlaveSeek( p_input ); SlaveSeek( p_input );
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR ); //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
b_force_update = VLC_TRUE; b_force_update = VLC_TRUE;
} }
break; break;
...@@ -1246,6 +1249,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, ...@@ -1246,6 +1249,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
i_time += val.i_time; i_time += val.i_time;
} }
if( i_time < 0 ) i_time = 0; if( i_time < 0 ) i_time = 0;
/* Reset the decoders states and clock synch (before calling the demuxer */
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
i_ret = demux2_Control( p_input->input.p_demux, i_ret = demux2_Control( p_input->input.p_demux,
DEMUX_SET_TIME, i_time ); DEMUX_SET_TIME, i_time );
if( i_ret ) if( i_ret )
...@@ -1272,9 +1280,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, ...@@ -1272,9 +1280,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
if( p_input->i_slave > 0 ) if( p_input->i_slave > 0 )
SlaveSeek( p_input ); SlaveSeek( p_input );
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
//es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
b_force_update = VLC_TRUE; b_force_update = VLC_TRUE;
} }
break; break;
......
...@@ -110,6 +110,7 @@ void stream_AccessUpdate( stream_t *s ); ...@@ -110,6 +110,7 @@ void stream_AccessUpdate( stream_t *s );
/* decoder.c FIXME make it public ?*/ /* decoder.c FIXME make it public ?*/
void input_DecoderDiscontinuity( decoder_t * p_dec ); void input_DecoderDiscontinuity( decoder_t * p_dec );
vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ); vlc_bool_t input_DecoderEmpty( decoder_t * p_dec );
void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end );
/* es_out.c */ /* es_out.c */
es_out_t *input_EsOutNew( input_thread_t * ); es_out_t *input_EsOutNew( input_thread_t * );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment