[vlc-commits] demux: flac: add refined non packetized vbr seek
Francois Cartegnie
git at videolan.org
Sun Apr 9 21:01:15 CEST 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | 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 )
{
More information about the vlc-commits
mailing list