From ebf27e98de4b870e3f4d8033b3918e417e738bd7 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Tue, 13 Oct 2009 21:05:06 +0200 Subject: [PATCH] Fixed ES frame rate estimation in mp4 file. --- modules/demux/mp4/mp4.c | 82 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index 43539125fe..8cf0e3b0d3 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -77,7 +77,8 @@ typedef struct much memory and with fast access */ /* with this we can calculate dts/pts without waste memory */ - uint64_t i_first_dts; + uint64_t i_first_dts; /* DTS of the first sample */ + uint64_t i_last_dts; /* DTS of the last sample */ uint32_t *p_sample_count_dts; uint32_t *p_sample_delta_dts; /* dts delta */ @@ -1204,7 +1205,7 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, int64_t i_index; int64_t i_index_sample_used; - int64_t i_last_dts; + int64_t i_next_dts; /* Find stsz * Gives the sample size for each samples. There is also a stz2 table @@ -1259,15 +1260,16 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, * for fast research (problem with raw stream where a sample is sometime * just channels*bits_per_sample/8 */ - i_last_dts = 0; + i_next_dts = 0; 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; - /* save last dts */ - ck->i_first_dts = i_last_dts; + /* save first dts */ + ck->i_first_dts = i_next_dts; + ck->i_last_dts = i_next_dts; /* count how many entries are needed for this chunk * for p_sample_delta_dts and p_sample_count_dts */ @@ -1304,11 +1306,12 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, i_index_sample_used += i_used; i_sample_count -= i_used; + i_next_dts += i_used * stts->i_sample_delta[i_index]; ck->p_sample_count_dts[i] = i_used; ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index]; - - i_last_dts += i_used * ck->p_sample_delta_dts[i]; + if( i_used > 0 ) + ck->i_last_dts = i_next_dts - ck->p_sample_delta_dts[i]; if( i_index_sample_used >= stts->i_sample_count[i_index] ) { @@ -1386,11 +1389,53 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:%"PRId64"s", p_demux_track->i_track_ID, p_demux_track->i_sample_count, - i_last_dts / p_demux_track->i_timescale ); + i_next_dts / p_demux_track->i_timescale ); return VLC_SUCCESS; } +/** + * It computes the sample rate for a video track using the given sample + * description index + */ +static void TrackGetESSampleRate( unsigned *pi_num, unsigned *pi_den, + const mp4_track_t *p_track, + unsigned i_sd_index, + unsigned i_chunk ) +{ + *pi_num = 0; + *pi_den = 0; + + if( p_track->i_chunk_count <= 0 ) + return; + + /* */ + const mp4_chunk_t *p_chunk = &p_track->chunk[i_chunk]; + while( p_chunk > &p_track->chunk[0] && + p_chunk[-1].i_sample_description_index == i_sd_index ) + { + p_chunk--; + } + + uint64_t i_sample = 0; + uint64_t i_first_dts = p_chunk->i_first_dts; + uint64_t i_last_dts; + do + { + i_sample += p_chunk->i_sample_count; + i_last_dts = p_chunk->i_last_dts; + p_chunk++; + } + while( p_chunk < &p_track->chunk[p_track->i_chunk_count] && + p_chunk->i_sample_description_index == i_sd_index ); + + if( i_sample > 1 && i_first_dts < i_last_dts ) + vlc_ureduce( pi_num, pi_den, + ( i_sample - 1) * p_track->i_timescale, + i_last_dts - i_first_dts, + UINT16_MAX); +} + /* * TrackCreateES: * Create ES and PES to init decoder if needed, for a track starting at i_chunk @@ -1398,15 +1443,16 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, unsigned int i_chunk, es_out_id_t **pp_es ) { + const unsigned i_sample_description_index = + p_track->chunk[i_chunk].i_sample_description_index; MP4_Box_t *p_sample; MP4_Box_t *p_esds; - MP4_Box_t *p_box; MP4_Box_t *p_frma; if( pp_es ) *pp_es = NULL; - if( !p_track->chunk[i_chunk].i_sample_description_index ) + if( !i_sample_description_index ) { msg_Warn( p_demux, "invalid SampleEntry index (track[Id 0x%x])", p_track->i_track_ID ); @@ -1414,7 +1460,7 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, } p_sample = MP4_BoxGet( p_track->p_stsd, "[%d]", - p_track->chunk[i_chunk].i_sample_description_index - 1 ); + i_sample_description_index - 1 ); if( !p_sample || ( !p_sample->data.p_data && p_track->fmt.i_cat != SPU_ES ) ) @@ -1513,17 +1559,9 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.video.i_visible_height = p_track->fmt.video.i_height; /* Frame rate */ - p_track->fmt.video.i_frame_rate = p_track->i_timescale; - p_track->fmt.video.i_frame_rate_base = 1; - - if( p_track->fmt.video.i_frame_rate && - (p_box = MP4_BoxGet( p_track->p_stbl, "stts" )) && - p_box->data.p_stts->i_entry_count >= 1 ) - { - p_track->fmt.video.i_frame_rate_base = - p_box->data.p_stts->i_sample_delta[0]; - } - + TrackGetESSampleRate( &p_track->fmt.video.i_frame_rate, + &p_track->fmt.video.i_frame_rate_base, + p_track, i_sample_description_index, i_chunk ); break; case AUDIO_ES: -- 2.11.4.GIT