vlc | branch: master | Francois Cartegnie <[email protected]> | Sun Apr 9 13:29:02 2017 +0200| [6897462bcf7b42691e420072d924cfbb9f2789b1] | committer: Francois Cartegnie
demux: flac: add refined non packetized vbr seek > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6897462bcf7b42691e420072d924cfbb9f2789b1 --- modules/demux/flac.c | 209 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 155 insertions(+), 54 deletions(-) diff --git a/modules/demux/flac.c b/modules/demux/flac.c index 9115244f57..575ac090db 100644 --- a/modules/demux/flac.c +++ b/modules/demux/flac.c @@ -84,7 +84,7 @@ struct demux_sys_t int64_t i_pts; int64_t i_length; /* Length from stream info */ - int64_t i_data_pos; + uint64_t i_data_pos; /* */ int i_seekpoint; @@ -103,6 +103,9 @@ struct demux_sys_t #define STREAMINFO_SIZE 34 #define FLAC_PACKET_SIZE 16384 +#define FLAC_MAX_PREROLL (CLOCK_FREQ * 4) +#define FLAC_MAX_SLOW_PREROLL (CLOCK_FREQ * 45) +#define FLAC_MIN_FRAME_SIZE ((48+(8 + 4 + 1*4)+16)/8) /***************************************************************************** * Open: initializes ES structures @@ -227,6 +230,106 @@ static void FlushPacketizer( decoder_t *p_packetizer ) } } +static void Reset( demux_sys_t *p_sys ) +{ + p_sys->i_pts = VLC_TS_INVALID; + + FlushPacketizer( p_sys->p_packetizer ); + if( p_sys->p_current_block ) + { + block_Release( p_sys->p_current_block ); + p_sys->p_current_block = NULL; + } +} + +static int RefineSeek( demux_t *p_demux, mtime_t i_time, double i_bytemicrorate, + uint64_t i_lowpos, uint64_t i_highpos ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + bool b_found = false; + block_t *p_block_out; + block_t *p_block_in; + + unsigned i_frame_size = FLAC_MIN_FRAME_SIZE; + + bool b_canfastseek = false; + (int) vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_canfastseek ); + + uint64_t i_start_pos = vlc_stream_Tell( p_demux->s ); + + while( !b_found ) + { + FlushPacketizer( p_sys->p_packetizer ); + + p_block_out = NULL; + p_block_in = NULL; + + while( !p_block_out ) + { + if( !p_block_in ) + { + if( !(p_block_in = vlc_stream_Block( p_demux->s, i_frame_size )) ) + break; + } + + p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in ); + } + + if( !p_block_out ) + { + if( p_block_in ) + block_Release( p_block_in ); + break; + } + + if( p_block_out->i_buffer > i_frame_size ) + i_frame_size = p_block_out->i_buffer; + + /* If we are further than wanted block */ + if( p_block_out->i_dts >= i_time ) + { + mtime_t i_diff = p_block_out->i_dts - i_time; + /* Not in acceptable approximation range */ + if( i_diff > CLOCK_FREQ / 10 && i_diff / i_bytemicrorate > i_frame_size ) + { + i_highpos = i_start_pos; + i_start_pos -= ( i_diff / i_bytemicrorate ); + i_start_pos = __MAX(i_start_pos, i_lowpos + i_frame_size); + } + else b_found = true; + } + else if( p_block_out->i_dts < i_time ) + { + mtime_t i_diff = i_time - p_block_out->i_dts; + /* Not in acceptable NEXT_TIME demux range */ + if( i_diff >= ((b_canfastseek) ? FLAC_MAX_PREROLL : FLAC_MAX_SLOW_PREROLL) && + i_diff / i_bytemicrorate > i_frame_size ) + { + i_lowpos = i_start_pos; + i_start_pos += ( i_diff / i_bytemicrorate ); + i_start_pos = __MIN(i_start_pos, i_highpos - i_frame_size); + } + else b_found = true; + } + + if( p_block_out ) + block_Release( p_block_out ); + if( p_block_in ) + block_Release( p_block_in ); + + if( !b_found ) + { + if( i_highpos < i_lowpos || i_highpos - i_lowpos < i_frame_size ) + break; + + if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) + break; + } + } + + return b_found ? VLC_SUCCESS : VLC_EGENERIC; +} + /***************************************************************************** * Demux: reads and demuxes data packets ***************************************************************************** @@ -319,7 +422,6 @@ static int64_t ControlGetTime( demux_t *p_demux ) static int ControlSetTime( demux_t *p_demux, int64_t i_time ) { demux_sys_t *p_sys = p_demux->p_sys; - int64_t i_delta_time; bool b_seekable; int i; @@ -328,64 +430,55 @@ static int ControlSetTime( demux_t *p_demux, int64_t i_time ) if( !b_seekable ) return VLC_EGENERIC; - /* */ - assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ - for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) - { - if( p_sys->seekpoint[i]->i_time_offset <= i_time ) - break; - } - i_delta_time = i_time - p_sys->seekpoint[i]->i_time_offset; + const mtime_t i_length = ControlGetLength( p_demux ); + if( i_length <= 0 ) + return VLC_EGENERIC; - /* XXX We do exact seek if it's not too far away(45s) */ - if( i_delta_time < CLOCK_FREQ * 45 ) - { - if( vlc_stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) ) - return VLC_EGENERIC; + const uint64_t i_stream_size = stream_Size( p_demux->s ); + if( i_stream_size <= p_sys->i_data_pos ) + return VLC_EGENERIC; - es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); - } - else - { - int64_t i_delta_offset; - int64_t i_next_time; - uint64_t i_next_offset; - uint32_t i_time_align = 1; + const double i_bytemicrorate = (double) i_length / (i_stream_size - p_sys->i_data_pos); + if( i_bytemicrorate == 0 ) + return VLC_EGENERIC; - if( i+1 < p_sys->i_seekpoint ) - { - i_next_time = p_sys->seekpoint[i+1]->i_time_offset; - i_next_offset = p_sys->seekpoint[i+1]->i_byte_offset; - } - else + uint64_t i_lower = p_sys->i_data_pos; + uint64_t i_upper = i_stream_size; + uint64_t i_start_pos; + + assert( p_sys->i_seekpoint > 0 ); /* ReadMeta ensure at least (0,0) */ + if( p_sys->i_seekpoint > 1 ) + { + /* lookup base offset */ + for( i = p_sys->i_seekpoint-1; i >= 0; i-- ) { - i_next_time = p_sys->i_length; - i_next_offset = stream_Size(p_demux->s)-p_sys->i_data_pos; + if( p_sys->seekpoint[i]->i_time_offset <= i_time ) + break; } - i_delta_offset = 0; - - if ( INT64_MAX / i_delta_time < (int64_t)(i_next_offset - p_sys->seekpoint[i]->i_byte_offset) ) - i_time_align = CLOCK_FREQ; - - if( i_next_time-p_sys->seekpoint[i]->i_time_offset > 0 ) - i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * (i_delta_time / i_time_align) / - ((i_next_time-p_sys->seekpoint[i]->i_time_offset) / i_time_align); + i_lower = p_sys->seekpoint[0]->i_byte_offset + p_sys->i_data_pos; + if( i+1 < p_sys->i_seekpoint ) + i_upper = p_sys->seekpoint[i+1]->i_byte_offset + p_sys->i_data_pos; - if( vlc_stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) ) - return VLC_EGENERIC; + i_start_pos = i_lower; + } + else + { + i_start_pos = i_time / i_bytemicrorate; } - p_sys->i_pts = VLC_TS_INVALID; - p_sys->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; - FlushPacketizer( p_sys->p_packetizer ); - if( p_sys->p_current_block ) + if( VLC_SUCCESS != vlc_stream_Seek( p_demux->s, i_start_pos ) ) + return VLC_EGENERIC; + + int i_ret = RefineSeek( p_demux, i_time, i_bytemicrorate, i_lower, i_upper ); + if( i_ret == VLC_SUCCESS ) { - block_Release( p_sys->p_current_block ); - p_sys->p_current_block = NULL; + p_sys->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; + Reset( p_sys ); + es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); } - return VLC_SUCCESS; + return i_ret; } static int Control( demux_t *p_demux, int i_query, va_list args ) @@ -419,8 +512,17 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) else if( i_query == DEMUX_SET_POSITION ) { const double f = (double)va_arg( args, double ); - int64_t i_time = f * ControlGetLength( p_demux ); - return ControlSetTime( p_demux, i_time ); + int64_t i_length = ControlGetLength( p_demux ); + if( i_length > 0 ) + return ControlSetTime( p_demux, i_length * f ); + /* just byte pos seek */ + int i_ret = vlc_stream_Seek( p_demux->s, (int64_t) (f * stream_Size( p_demux->s )) ); + if( i_ret == VLC_SUCCESS ) + { + p_sys->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; + Reset( p_sys ); + } + return i_ret; } else if( i_query == DEMUX_GET_TIME ) { @@ -430,16 +532,15 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) } else if( i_query == DEMUX_GET_POSITION ) { - double *pf = (double*)va_arg( args, double * ); const int64_t i_length = ControlGetLength(p_demux); if( i_length > 0 ) { + double *pf = (double*)va_arg( args, double * ); double current = ControlGetTime(p_demux); *pf = current / (double)i_length; + return VLC_SUCCESS; } - else - *pf= 0.0; - return VLC_SUCCESS; + /* Else fallback on byte position */ } else if( i_query == DEMUX_GET_ATTACHMENTS ) { _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
