From: Laurent Aimar Date: Mon, 21 Feb 2005 09:03:07 +0000 (+0000) Subject: * block: added X-Git-Tag: 0.8.2~1100 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=70ee5fbf988a94c0c2e394f3346a3dc6eeb18d72;p=vlc * 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. --- diff --git a/include/vlc_block.h b/include/vlc_block.h index 831f37269c..cb589016e6 100644 --- a/include/vlc_block.h +++ b/include/vlc_block.h @@ -68,6 +68,10 @@ typedef struct block_sys_t block_sys_t; #define BLOCK_FLAG_CLOCK 0x0200 /** This block is scrambled */ #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_SHIFT 16 diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h index 13dc518cc5..5af2b77fc8 100644 --- a/include/vlc_es_out.h +++ b/include/vlc_es_out.h @@ -59,7 +59,12 @@ enum es_out_query_e ES_OUT_SET_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_GROUP_PCR, /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ ES_OUT_RESET_PCR, /* no arg */ @@ -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 */ /* 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 diff --git a/modules/codec/a52.c b/modules/codec/a52.c index 6c37c8798c..82a8610fbe 100644 --- a/modules/codec/a52.c +++ b/modules/codec/a52.c @@ -174,7 +174,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) 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; } diff --git a/modules/codec/dts.c b/modules/codec/dts.c index 6c651c9000..c6adbc0700 100644 --- a/modules/codec/dts.c +++ b/modules/codec/dts.c @@ -175,7 +175,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) 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; } diff --git a/modules/codec/faad.c b/modules/codec/faad.c index cc75d8a2d3..6cc457b986 100644 --- a/modules/codec/faad.c +++ b/modules/codec/faad.c @@ -181,7 +181,7 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **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 ); return NULL; diff --git a/modules/codec/ffmpeg/audio.c b/modules/codec/ffmpeg/audio.c index 5b33b95931..1a3c3b5edc 100644 --- a/modules/codec/ffmpeg/audio.c +++ b/modules/codec/ffmpeg/audio.c @@ -209,7 +209,7 @@ aout_buffer_t *E_( DecodeAudio )( decoder_t *p_dec, block_t **pp_block ) 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 ); return NULL; diff --git a/modules/codec/ffmpeg/video.c b/modules/codec/ffmpeg/video.c index 9207138863..8e58d370e4 100644 --- a/modules/codec/ffmpeg/video.c +++ b/modules/codec/ffmpeg/video.c @@ -438,7 +438,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **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_pts = 0; /* To make sure we recover properly */ @@ -450,6 +450,14 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) 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 && 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 ) continue; } - /* Update frame late count*/ - if( p_sys->i_pts && p_sys->i_pts <= mdate() ) + /* Update frame late count (except when doing preroll) */ + if( p_sys->i_pts && p_sys->i_pts <= mdate() && + !(p_block->i_flags & BLOCK_FLAG_PREROLL) ) { p_sys->i_late_frames++; if( p_sys->i_late_frames == 1 ) @@ -630,6 +639,10 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) { 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 */ if( p_sys->p_context->frame_rate > 0 ) { @@ -657,6 +670,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) else { p_dec->pf_vout_buffer_del( p_dec, p_pic ); + msg_Dbg( p_dec, "pts=0" ); } } diff --git a/modules/codec/flac.c b/modules/codec/flac.c index ded735afff..8c7b95faef 100644 --- a/modules/codec/flac.c +++ b/modules/codec/flac.c @@ -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 ); } - 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; } diff --git a/modules/codec/libmpeg2.c b/modules/codec/libmpeg2.c index 1fa676171d..167c754b22 100644 --- a/modules/codec/libmpeg2.c +++ b/modules/codec/libmpeg2.c @@ -65,6 +65,8 @@ struct decoder_sys_t * the sequence header ? */ vlc_bool_t b_slice_i; /* intra-slice refresh stream */ + vlc_bool_t b_preroll; + /* * Output properties */ @@ -137,6 +139,7 @@ static int OpenDecoder( vlc_object_t *p_this ) p_sys->b_garbage_pic = 0; p_sys->b_slice_i = 0; p_sys->b_skip = 0; + p_sys->b_preroll = VLC_FALSE; #if defined( __i386__ ) 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 ) 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_info->sequence && p_sys->p_info->sequence->width != (unsigned)-1 ) @@ -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 if( p_block->i_pts ) { @@ -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->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->p_info->current_picture->flags & PIC_MASK_CODING_TYPE) == P_CODING_TYPE)) diff --git a/modules/codec/mpeg_audio.c b/modules/codec/mpeg_audio.c index 2a1d1a1fcd..f7dbd4635d 100644 --- a/modules/codec/mpeg_audio.c +++ b/modules/codec/mpeg_audio.c @@ -196,7 +196,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) 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; } diff --git a/modules/codec/theora.c b/modules/codec/theora.c index 92fb2796a7..d242516eef 100644 --- a/modules/codec/theora.c +++ b/modules/codec/theora.c @@ -386,7 +386,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t *p_block = *pp_block; 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 * theora_decode, otherwise we get purple/green display artifacts diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index 6c7bf87286..f912ecaf03 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -74,7 +74,10 @@ typedef struct /* with this we can calculate dts/pts without waste memory */ uint64_t i_first_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 but quickly *add* support for edts and seeking */ @@ -162,7 +165,7 @@ static int MP4_TrackNextSample( demux_t *, mp4_track_t * ); static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t ); /* 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] @@ -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; } +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 ) { return I64C(1000000) * p_sys->i_time / p_sys->i_timescale; @@ -604,17 +625,18 @@ static int Demux( demux_t *p_demux ) continue; } - while( MP4_TrackGetPTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) ) + while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) ) { #if 0 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 ) ); #endif if( MP4_TrackSampleSize( tk ) > 0 ) { block_t *p_block; + int64_t i_delta; /* go,go go ! */ if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) ) @@ -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 ? - 0 : p_block->i_dts + 1; + if( tk->fmt.i_cat == VIDEO_ES ) + 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 ) ) - { es_out_Send( p_demux->out, tk->p_es, p_block ); - } } /* Next sample */ @@ -918,8 +947,15 @@ static int TrackCreateChunksIndex( demux_t *p_demux, /* first we read chunk offset */ for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { - p_demux_track->chunk[i_chunk].i_offset = - p_co64->data.p_co64->i_chunk_offset[i_chunk]; + mp4_chunk_t *ck = &p_demux_track->chunk[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 ...) @@ -963,12 +999,9 @@ static int TrackCreateChunksIndex( demux_t *p_demux, static int TrackCreateSamplesIndex( demux_t *p_demux, mp4_track_t *p_demux_track ) { - MP4_Box_t *p_stts; /* makes mapping between sample and decoding time, - ctts make same mapping but for composition time, - not yet used and probably not usefull */ - 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 */ + MP4_Box_t *p_box; + MP4_Box_data_stsz_t *stsz; + MP4_Box_data_stts_t *stts; /* TODO use also stss and stsh table for seeking */ /* FIXME use edit table */ int64_t i_sample; @@ -979,23 +1012,35 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, int64_t i_last_dts; - p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" ); - p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */ - - if( ( !p_stts )||( !p_stsz ) ) + /* Find stsz + * Gives the sample size for each samples. There is also a stz2 table + * (compressed form) that we need to implement TODO */ + p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); + if( !p_box ) { - msg_Warn( p_demux, "cannot read sample table" ); - return( VLC_EGENERIC ); + /* FIXME and stz2 */ + 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 */ - if( p_stsz->data.p_stsz->i_sample_size ) + /* Use stsz table to create a sample number -> sample size table */ + 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 */ - 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; } else @@ -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++ ) { 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 - the box! so each chunk will contain an "extract" of this table - for fast research */ + /* Use stts table to crate a sample number -> dts table. + * XXX: if we don't want to waste too much memory, we can't expand + * 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_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++ ) { - + mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk]; int64_t i_entry, i_sample_count, i; /* 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 * 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; while( i_sample_count > 0 ) { - i_sample_count -= - p_stts->data.p_stts->i_sample_count[i_index+i_entry]; + i_sample_count -= stts->i_sample_count[i_index+i_entry]; + /* don't count already used sample in this entry */ if( i_entry == 0 ) - { - /* don't count already used sample in this entry */ i_sample_count += i_index_sample_used; - } + i_entry++; } /* allocate them */ - p_demux_track->chunk[i_chunk].p_sample_count_dts = - calloc( i_entry, sizeof( uint32_t ) ); - p_demux_track->chunk[i_chunk].p_sample_delta_dts = - calloc( i_entry, sizeof( uint32_t ) ); + ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) ); + ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) ); /* 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++ ) { int64_t i_used; int64_t i_rest; - i_rest = p_stts->data.p_stts->i_sample_count[i_index] - - i_index_sample_used; + i_rest = stts->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; - 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] = - p_stts->data.p_stts->i_sample_delta[i_index]; + i_last_dts += i_used * ck->p_sample_delta_dts[i]; - i_last_dts += i_used * - 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] ) + if( i_index_sample_used >= stts->i_sample_count[i_index] ) { i_index++; i_index_sample_used = 0; @@ -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", p_demux_track->i_track_ID, p_demux_track->i_sample_count, 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 ) { 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_count_pts); + FREE(p_track->chunk[i_chunk].p_sample_offset_pts ); } } FREE( p_track->chunk ); @@ -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; 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; 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 ) elst->i_segment_duration[p_track->i_elst] ) { MP4_TrackSetELST( p_demux, p_track, - MP4_TrackGetPTS( p_demux, p_track ) ); + MP4_TrackGetDTS( p_demux, p_track ) ); } } diff --git a/modules/demux/ts.c b/modules/demux/ts.c index 75cd306c20..dac70576f0 100644 --- a/modules/demux/ts.c +++ b/modules/demux/ts.c @@ -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 * dropping full frames */ - pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY; + pid->es->p_pes->i_flags |= BLOCK_FLAG_CORRUPTED; } } } diff --git a/src/input/decoder.c b/src/input/decoder.c index 6447ccedfe..3eee4294d7 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -60,6 +60,8 @@ struct decoder_owner_sys_t { vlc_bool_t b_own_thread; + int64_t i_preroll_end; + input_thread_t *p_input; aout_instance_t *p_aout; @@ -276,6 +278,11 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ) 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 /** * 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, return NULL; } 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_aout = NULL; p_dec->p_owner->p_aout_input = NULL; @@ -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, &p_packetized_block )) ) { - aout_DecPlay( p_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, - p_aout_buf ); + /* FIXME the best would be to handle the case start_date < preroll < end_date + * but that's not easy with non raw audio stream */ + 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; @@ -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 )) ) { - aout_DecPlay( p_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, 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 ); + } } } 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 ) while( (p_pic = p_dec->pf_decode_video( p_dec, &p_packetized_block )) ) { - vout_DatePicture( p_dec->p_owner->p_vout, p_pic, - p_pic->date ); - vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); + if( p_dec->p_owner->i_preroll_end > 0 && + 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 ); + } } p_packetized_block = p_next; @@ -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 )) ) { - vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date ); - vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); + if( p_dec->p_owner->i_preroll_end > 0 && + 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 ) @@ -667,6 +716,15 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) subpicture_t *p_spu; 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 ); if( p_vout ) { diff --git a/src/input/es_out.c b/src/input/es_out.c index e0ca0886b8..0c562fb7e6 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -61,6 +61,9 @@ struct es_out_id_t int i_id; es_out_pgrm_t *p_pgrm; + /* */ + int64_t i_preroll_end; + /* Channel in the track type */ int i_channel; 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->p_pgrm = p_pgrm; es_format_Copy( &es->fmt, fmt ); + es->i_preroll_end = -1; + switch( fmt->i_cat ) { case AUDIO_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 ); if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm ) return; @@ -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; + /* 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 */ 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 ) 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: msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); return VLC_EGENERIC; diff --git a/src/input/input.c b/src/input/input.c index 4543c48605..436bff7911 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -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 > 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, f_pos ) ) { @@ -1221,8 +1224,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( p_input->i_slave > 0 ) SlaveSeek( p_input ); - input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); - es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR ); + //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); + //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR ); b_force_update = VLC_TRUE; } break; @@ -1246,6 +1249,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, i_time += val.i_time; } 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, DEMUX_SET_TIME, i_time ); if( i_ret ) @@ -1272,9 +1280,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( p_input->i_slave > 0 ) SlaveSeek( p_input ); - input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); - - es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR ); + //input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE ); + //es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR ); b_force_update = VLC_TRUE; } break; diff --git a/src/input/input_internal.h b/src/input/input_internal.h index 78adb94e4d..7846f91106 100644 --- a/src/input/input_internal.h +++ b/src/input/input_internal.h @@ -110,6 +110,7 @@ void stream_AccessUpdate( stream_t *s ); /* decoder.c FIXME make it public ?*/ void input_DecoderDiscontinuity( 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_t *input_EsOutNew( input_thread_t * );