return idx;
}
-
-
-/* add a theora entry to our list; format is highest granulepos -> page offset of
- keyframe start */
-
-const demux_index_entry_t *oggseek_theora_index_entry_add ( logical_stream_t *p_stream,
- int64_t i_granule,
- int64_t i_pagepos)
-{
- /* add or update entry for keyframe */
- demux_index_entry_t *idx;
- demux_index_entry_t *oidx;
- demux_index_entry_t *last_idx = NULL;
- int64_t i_gpos;
- int64_t i_frame;
- int64_t i_kframe;
- int64_t i_tframe;
- int64_t i_tkframe;
-
- if ( p_stream == NULL ) return NULL;
-
- oidx = idx = p_stream->idx;
-
- i_tkframe = i_granule >> p_stream->i_granule_shift;
- i_tframe = i_tkframe + i_granule - ( i_tkframe << p_stream->i_granule_shift );
-
- if ( i_tkframe < 1 ) return NULL;
-
- if ( idx == NULL )
- {
- demux_index_entry_t *ie = index_entry_new();
- ie->i_value = i_granule;
- ie->i_pagepos = i_pagepos;
- p_stream->idx = ie;
- return ie;
- }
-
-
- while ( idx != NULL )
- {
- i_gpos = idx->i_value;
-
- i_kframe = i_gpos >> p_stream->i_granule_shift;
- if ( i_kframe > i_tframe ) break;
-
- if ( i_kframe == i_tkframe )
- {
- /* entry exists, update it if applicable, and return it */
- i_frame = i_kframe + i_gpos - ( i_kframe << p_stream->i_granule_shift );
- if ( i_frame < i_tframe )
- {
- idx->i_value = i_granule;
- idx->i_pagepos = i_pagepos;
- }
-
- return idx;
- }
-
- last_idx = idx;
- idx = idx->p_next;
- }
-
-
- /* new entry; insert after last_idx */
-
- idx = index_entry_new();
-
- if ( last_idx != NULL )
- {
- idx->p_next = last_idx->p_next;
- last_idx->p_next = idx;
- idx->p_prev = last_idx;
- }
- else
- {
- idx->p_next = oidx;
- oidx = idx;
- }
-
- if ( idx->p_next != NULL )
- {
- idx->p_next->p_prev = idx;
- }
-
- idx->i_value = i_granule;
- idx->i_pagepos = i_pagepos;
-
- return idx;
-}
-
/* We insert into index, sorting by pagepos (as a page can match multiple
time stamps) */
const demux_index_entry_t *OggSeek_IndexAdd ( logical_stream_t *p_stream,
int64_t *pi_pos_lower, int64_t *pi_pos_upper )
{
demux_index_entry_t *idx = p_stream->idx;
- *pi_pos_lower = *pi_pos_upper = -1;
while ( idx != NULL )
{
i_result = stream_Read( p_demux->s, buf, i_bytes_to_read );
- p_sys->b_page_waiting = false;
-
ogg_sync_wrote( &p_sys->oy, i_result );
return i_result;
}
-/* Find the first first ogg page for p_stream between offsets i_pos1 and i_pos2,
- return file offset in bytes; -1 is returned on failure */
-
-static int64_t find_first_page( demux_t *p_demux, int64_t i_pos1, int64_t i_pos2,
- logical_stream_t *p_stream,
- int64_t *pi_kframe, int64_t *pi_frame )
-{
- int64_t i_result;
- int64_t i_granulepos;
- int64_t i_bytes_to_read = i_pos2 - i_pos1 + 1;
- int64_t i_bytes_read;
- int64_t i_pages_checked = 0;
- int64_t i_packets_checked;
-
- demux_sys_t *p_sys = p_demux->p_sys;
-
- ogg_packet op;
-
- seek_byte( p_demux, i_pos1 );
-
- if ( i_pos1 == p_stream->i_data_start )
- {
- /* set a dummy granulepos at data_start */
- *pi_kframe = p_stream->i_keyframe_offset;
- *pi_frame = p_stream->i_keyframe_offset;
-
- p_sys->b_page_waiting = true;
- return p_sys->i_input_position;
- }
-
- if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ;
-
- while ( 1 )
- {
-
- if ( p_sys->i_input_position >= i_pos2 )
- {
- /* we reached the end and found no pages */
- *pi_frame=-1;
- return -1;
- }
-
- /* read next chunk */
- if ( ! ( i_bytes_read = get_data( p_demux, i_bytes_to_read ) ) )
- {
- /* EOF */
- *pi_frame = -1;
- return -1;
- }
-
- i_bytes_to_read = OGGSEEK_BYTES_TO_READ;
-
- i_result = ogg_sync_pageseek( &p_sys->oy, &p_sys->current_page );
-
- if ( i_result < 0 )
- {
- /* found a page, sync to page start */
- p_sys->i_input_position -= i_result;
- i_pos1 = p_sys->i_input_position;
- continue;
- }
-
- if ( i_result > 0 || ( i_result == 0 && p_sys->oy.fill > 3 &&
- ! strncmp( (char *)p_sys->oy.data, "OggS" , 4 ) ) )
- {
- i_pos1 = p_sys->i_input_position;
- break;
- }
-
- p_sys->i_input_position += i_bytes_read;
-
- };
-
- seek_byte( p_demux, p_sys->i_input_position );
- ogg_stream_reset( &p_stream->os );
-
- while( 1 )
- {
-
- if ( p_sys->i_input_position >= i_pos2 )
- {
- /* reached the end of the search region and nothing was found */
- *pi_frame = -1;
- return p_sys->i_input_position;
- }
-
- p_sys->b_page_waiting = false;
-
- if ( ! ( i_result = oggseek_read_page( p_demux ) ) )
- {
- /* EOF */
- *pi_frame = -1;
- return p_sys->i_input_position;
- }
-
- // found a page
- if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) )
- {
- /* page is not for this stream */
- p_sys->i_input_position += i_result;
- if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position;
- continue;
- }
-
-
- ogg_stream_pagein( &p_stream->os, &p_sys->current_page );
-
- i_pages_checked++;
- i_packets_checked = 0;
-
- if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
- {
- i_packets_checked++;
- }
-
- if ( i_packets_checked )
- {
- i_granulepos = ogg_page_granulepos( &p_sys->current_page );
-
- oggseek_theora_index_entry_add( p_stream, i_granulepos, i_pos1 );
-
- *pi_kframe =
- i_granulepos >> p_stream->i_granule_shift;
-
- *pi_frame = *pi_kframe +
- i_granulepos - ( *pi_kframe << p_stream->i_granule_shift );
-
- p_sys->b_page_waiting = true;
- return i_pos1;
-
- }
-
- /* -> start of next page */
- p_sys->i_input_position += i_result;
- }
-}
void Oggseek_ProbeEnd( demux_t *p_demux )
{
}
-/* convert a theora frame to a granulepos */
-
-static inline int64_t frame_to_gpos( logical_stream_t *p_stream, int64_t i_kframe,
- int64_t i_frame )
-{
- if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
- {
- return ( i_kframe << p_stream->i_granule_shift ) + ( i_frame - i_kframe );
- }
-
- return i_kframe;
-}
-
-
-
-
-
-/* seek to a suitable point to begin decoding for i_tframe. We can pre-set bounding positions
- i_pos_lower and i_pos_higher to narrow the search domain. */
-
-
-static int64_t ogg_seek( demux_t *p_demux, logical_stream_t *p_stream, int64_t i_tframe,
- int64_t i_pos_lower, int64_t i_pos_upper, int64_t *pi_pagepos,
- bool b_exact )
-{
- /* For theora:
- * We do two passes here, first with b_exact set, then with b_exact unset.
- *
- * If b_exact is set, we find the highest granulepos <= the target granulepos
- * from this we extract an estimate of the keyframe (note that there could be other
- * "hidden" keyframes between the found granulepos and the target).
- *
- * On the second pass we find the highest granulepos < target. This places us just before or
- * at the start of the target keyframe.
- *
- * When we come to decode, we start from this second position, discarding any completed
- * packets on that page, and read pages discarding packets until we get to the target frame.
- *
- * The function returns the granulepos which is found,
- * sets the page offset in pi_pagepos. -1 is returned on error.
- *
- * for dirac:
- *
- * we find the highest sync frame <= target frame, and return the sync_frame number
- * b_exact should be set to true
- *
- *
- * the method used is bi-sections:
- * - we check the lower keyframe
- * if this is == target we return
- * if > target, or we find no keyframes, we go to the lower segment
- * if < target we divide the segment in two and check the upper half
- *
- * This is then repeated until the segment size is too small to hold a packet,
- * at which point we return our best match
- *
- * Two optimisations are made: - anything we discover about keyframes is added to our index
- * - before calling this function we get approximate bounds from the index
- *
- * therefore, subsequent searches become more rapid.
- *
- */
-
- int64_t i_start_pos;
- int64_t i_end_pos;
- int64_t i_pagepos;
- int64_t i_segsize;
- int64_t i_frame;
- int64_t i_kframe;
-
- int64_t i_best_kframe = -1;
- int64_t i_best_frame = -1;
- int64_t i_best_pagepos = -1;
-
- demux_sys_t *p_sys = p_demux->p_sys;
-
- if ( i_tframe < p_stream->i_keyframe_offset )
- {
- *pi_pagepos = p_stream->i_data_start;
-
- if ( ! b_exact ) {
- seek_byte( p_demux, p_stream->i_data_start );
- return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 1 );
- }
- return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 0 );
- }
-
- if ( i_pos_lower < p_stream->i_data_start )
- {
- i_pos_lower = p_stream->i_data_start;
- }
-
- if ( i_pos_upper < 0 )
- {
- i_pos_upper = p_sys->i_total_length;
- }
-
- if ( i_pos_upper > p_sys->i_total_length )
- {
- i_pos_upper = p_sys->i_total_length;
- }
-
- i_start_pos = i_pos_lower;
- i_end_pos = i_pos_upper;
-
- i_segsize = ( i_end_pos - i_start_pos + 1 ) >> 1;
-
- do
- {
- /* see if the frame lies in current segment */
- if ( i_start_pos < i_pos_lower )
- {
- i_start_pos = i_pos_lower;
- }
- if ( i_end_pos > i_pos_upper )
- {
- i_end_pos = i_pos_upper;
- }
-
- if ( i_start_pos >= i_end_pos )
- {
- if ( i_start_pos == i_pos_lower)
- {
- if ( ! b_exact ) seek_byte( p_demux, i_start_pos );
- *pi_pagepos = i_start_pos;
- return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 1 );
- }
- break;
- }
-
- if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA || p_stream->fmt.i_codec == VLC_CODEC_OPUS )
- {
- i_pagepos = find_first_page( p_demux, i_start_pos, i_end_pos, p_stream,
- &i_kframe, &i_frame );
- }
- else return -1;
-
- if ( i_pagepos != -1 && i_kframe != -1 )
- {
- /* found a page */
-
- if ( b_exact && i_frame >= i_tframe && i_kframe <= i_tframe )
- {
- /* got it ! */
- *pi_pagepos = i_start_pos;
- return frame_to_gpos( p_stream, i_kframe, i_frame );
- }
-
- if ( ( i_kframe < i_tframe || ( b_exact && i_kframe == i_tframe ) )
- && i_kframe > i_best_kframe )
- {
- i_best_kframe = i_kframe;
- i_best_frame = i_frame;
- i_best_pagepos = i_pagepos;
- }
-
- if ( i_frame >= i_tframe )
- {
- /* check lower half of segment */
- i_start_pos -= i_segsize;
- i_end_pos -= i_segsize;
- }
-
- else i_start_pos = i_pagepos;
- }
- else
- {
- /* no keyframe found, check lower segment */
- i_end_pos -= i_segsize;
- i_start_pos -= i_segsize;
- }
-
- i_segsize = ( i_end_pos - i_start_pos + 1 ) >> 1;
- i_start_pos += i_segsize;
-
- } while ( i_segsize > 64 );
-
- if ( i_best_kframe >- 1 )
- {
- if ( !b_exact )
- {
- seek_byte( p_demux, i_best_pagepos );
- }
- *pi_pagepos = i_best_pagepos;
- return frame_to_gpos( p_stream, i_best_kframe, i_best_frame );
- }
-
- return -1;
-}
-
static int64_t find_first_page_granule( demux_t *p_demux,
int64_t i_pos1, int64_t i_pos2,
logical_stream_t *p_stream,
seek_byte( p_demux, i_pos1 );
if ( i_pos1 == p_stream->i_data_start )
- {
- p_sys->b_page_waiting = true;
return p_sys->i_input_position;
- }
if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ;
return p_sys->i_input_position;
}
+ if ( ogg_page_granulepos( &p_sys->current_page ) <= 0 )
+ {
+ p_sys->i_input_position += i_result;
+ i_bytes_to_read += OGGSEEK_BYTES_TO_READ;
+ continue;
+ }
+
// found a page
- if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) )
+ if ( ogg_stream_pagein( &p_stream->os, &p_sys->current_page ) != 0 )
{
- /* page is not for this stream */
+ /* page is not for this stream or incomplete */
p_sys->i_input_position += i_result;
if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position;
continue;
}
- ogg_stream_pagein( &p_stream->os, &p_sys->current_page );
-
i_pages_checked++;
i_packets_checked = 0;
- if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
+ while ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
{
i_packets_checked++;
}
if ( i_packets_checked )
{
*i_granulepos = ogg_page_granulepos( &p_sys->current_page );
- p_sys->b_page_waiting = true;
return i_pos1;
-
}
/* -> start of next page */
{
return ( p_packet->bytes > 0 && p_packet->packet[0] & PACKET_IS_SYNCPOINT );
}
- else if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
+ else switch ( p_stream->fmt.i_codec )
{
+ case VLC_CODEC_THEORA:
+ case VLC_CODEC_DAALA: /* Same convention used in daala */
if ( p_packet->bytes <= 0 || p_packet->packet[0] & THEORA_FTYPE_NOTDATA )
return false;
else
return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME );
+ case VLC_CODEC_VP8:
+ return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 );
+ case VLC_CODEC_DIRAC:
+ return ( p_packet->granulepos & 0xFF8000FF );
+ default:
+ return true;
}
- return true;
}
int64_t Ogg_GetKeyframeGranule( logical_stream_t *p_stream, int64_t i_granule )
{
return -1; /* We have no way to know */
}
- else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
+ else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
+ p_stream->fmt.i_codec == VLC_CODEC_DAALA )
{
return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift;
}
{
ogg_packet op;
demux_sys_t *p_sys = p_demux->p_sys;
- ogg_stream_pagein( &p_stream->os, &p_sys->current_page );
+ if ( ogg_stream_pagein( &p_stream->os, &p_sys->current_page ) != 0 )
+ return false;
+ p_sys->b_page_waiting = true;
int i=0;
int64_t itarget_frame = Ogg_GetKeyframeGranule( p_stream, i_granulepos );
if ( b_exact && iframe > itarget_frame )
{
while( ogg_stream_packetout( &p_stream->os, &op ) > 0 ) {};
+ p_sys->b_page_waiting = false;
return false;
}
p_lastpacketcoords->i_pos = p_sys->i_input_position;
p_lastpacketcoords->i_skip = i;
}
-
return true;
}
/* remove that packet and go sync to next */
ogg_stream_packetout( &p_stream->os, &op );
}
+
return false;
}
seek_byte( p_demux, p_sys->i_input_position );
ogg_stream_reset( &p_stream->os );
+ ogg_packet op;
+ while( ogg_stream_packetout( &p_stream->os, &op ) > 0 ) {};
+
packetStartCoordinates lastpacket = { -1, -1, -1 };
while( 1 )
{
p_sys->i_input_position = lastpacket.i_pos;
p_stream->i_skip_frames = 0;
- p_sys->b_page_waiting = true;
return p_sys->i_input_position;
}
int64_t i_granule, bool b_presentation )
{
int64_t i_timestamp = -1;
+ if ( i_granule < 1 )
+ return -1;
if ( p_stream->b_oggds )
{
- i_timestamp = i_granule * INT64_C(1000000) / p_stream->f_rate;
+ if ( b_presentation ) i_granule--;
+ i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
}
- else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
- p_stream->fmt.i_codec == VLC_CODEC_KATE )
+ else switch( p_stream->fmt.i_codec )
+ {
+ case VLC_CODEC_THEORA:
+ case VLC_CODEC_DAALA:
+ case VLC_CODEC_KATE:
{
ogg_int64_t iframe = i_granule >> p_stream->i_granule_shift;
ogg_int64_t pframe = i_granule - ( iframe << p_stream->i_granule_shift );
/* See Theora A.2.3 */
if ( b_presentation ) pframe -= p_stream->i_keyframe_offset;
- i_timestamp = ( iframe + pframe ) * INT64_C(1000000) / p_stream->f_rate;
+ i_timestamp = ( iframe + pframe ) * CLOCK_FREQ / p_stream->f_rate;
+ break;
}
- else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
+ case VLC_CODEC_VP8:
+ {
+ ogg_int64_t frame = i_granule >> p_stream->i_granule_shift;
+ if ( b_presentation ) frame--;
+ i_timestamp = frame * CLOCK_FREQ / p_stream->f_rate;
+ break;
+ }
+ case VLC_CODEC_DIRAC:
{
ogg_int64_t i_dts = i_granule >> 31;
+ ogg_int64_t delay = (i_granule >> 9) & 0x1fff;
/* NB, OggDirac granulepos values are in units of 2*picturerate */
- i_timestamp = (i_dts/2) * INT64_C(1000000) / p_stream->f_rate;
+ double f_rate = p_stream->f_rate;
+ if ( !p_stream->special.dirac.b_interlaced ) f_rate *= 2;
+ if ( b_presentation ) i_dts += delay;
+ i_timestamp = i_dts * CLOCK_FREQ / f_rate;
+ break;
}
- else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
+ case VLC_CODEC_OPUS:
{
- i_timestamp = p_stream->i_pre_skip + i_granule * INT64_C(1000000) / 48000;
+ if ( b_presentation ) return VLC_TS_INVALID;
+ i_timestamp = ( i_granule - p_stream->i_pre_skip ) * CLOCK_FREQ / 48000;
+ break;
}
- else if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS )
+ case VLC_CODEC_VORBIS:
+ case VLC_CODEC_FLAC:
{
- i_timestamp = i_granule * INT64_C(1000000) / p_stream->f_rate;
+ if ( b_presentation ) return VLC_TS_INVALID;
+ i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
+ break;
}
-
- return i_timestamp;
-}
-
-bool Oggseek_PacketPCRFixup( logical_stream_t *p_stream, ogg_page *p_page,
- ogg_packet *p_packet )
-{
- if ( p_packet->granulepos != -1 )
- return false;
- else
- if ( p_stream->b_oggds )
+ case VLC_CODEC_SPEEX:
{
- p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream,
- ogg_page_granulepos( p_page ), true );
- return true;
+ if ( b_presentation )
+ i_granule -= p_stream->special.speex.i_framesize *
+ p_stream->special.speex.i_framesperpacket;
+ i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
+ break;
}
- else if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
- {
- p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream,
- ogg_page_granulepos( p_page ), false );
- /* Computes the presentation time of the first packet on page */
- p_stream->i_pcr -= INT64_C(1000000) *
- ogg_page_packets( p_page ) / p_stream->f_rate;
- return true;
}
- return false;
+ return i_timestamp;
}
/* returns pos */
int64_t i_pos;
int64_t i_timestamp;
int64_t i_granule;
- } bestlower = { p_stream->i_data_start, 0, p_stream->i_keyframe_offset },
- current = { -1, -1, -1 };
+ } bestlower = { p_stream->i_data_start, -1, -1 },
+ current = { -1, -1, -1 },
+ lowestupper = { -1, -1, -1 };
demux_sys_t *p_sys = p_demux->p_sys;
current.i_timestamp = Oggseek_GranuleToAbsTimestamp( p_stream,
current.i_granule, false );
- if ( current.i_timestamp == -1 )
+ if ( current.i_timestamp == -1 && current.i_granule > 0 )
{
msg_Err( p_demux, "Unmatched granule. New codec ?" );
return -1;
}
+ else if ( current.i_timestamp < -1 ) /* due to preskip with some codecs */
+ {
+ current.i_timestamp = 0;
+ }
if ( current.i_pos != -1 && current.i_granule != -1 )
{
}
else if ( current.i_timestamp > i_targettime )
{
+ if ( lowestupper.i_timestamp == -1 || current.i_timestamp < lowestupper.i_timestamp )
+ lowestupper = current;
/* check lower half of segment */
i_start_pos -= i_segsize;
i_end_pos -= i_segsize;
i_start_pos -= i_segsize;
}
- OggDebug( msg_Dbg(p_demux, "Bisect restart i_segsize=%"PRId64" between %"PRId64" and %"PRId64,
- i_segsize, i_start_pos, i_end_pos ) );
+ OggDebug( msg_Dbg(p_demux, "Bisect restart i_segsize=%"PRId64" between %"PRId64
+ " and %"PRId64 " bl %"PRId64" lu %"PRId64,
+ i_segsize, i_start_pos, i_end_pos, bestlower.i_granule, lowestupper.i_granule ) );
i_segsize = ( i_end_pos - i_start_pos + 1 ) >> 1;
i_start_pos += i_segsize;
- } while ( i_segsize > 64 && current.i_granule != -1 );
+ } while ( i_segsize > 64 );
+ if ( bestlower.i_granule == -1 )
+ {
+ if ( lowestupper.i_granule == -1 )
+ return -1;
+ else
+ bestlower = lowestupper;
+ }
if ( p_stream->b_oggds )
{
i_keyframegranule >> p_stream->i_granule_shift,
bestlower.i_granule,
i_pos_upper,
- Oggseek_GranuleToAbsTimestamp( p_stream, i_keyframegranule, true ) ) );
+ Oggseek_GranuleToAbsTimestamp( p_stream, i_keyframegranule, false ) ) );
OggDebug( msg_Dbg( p_demux, "Seeking back to %"PRId64, __MAX ( bestlower.i_pos - OGGSEEK_BYTES_TO_READ, p_stream->i_data_start ) ) );
* public functions
*************************************************************************/
+int Oggseek_BlindSeektoAbsoluteTime( demux_t *p_demux, logical_stream_t *p_stream,
+ int64_t i_time, bool b_fastseek )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int64_t i_lowerpos = -1;
+ int64_t i_upperpos = -1;
+ bool b_found = false;
+
+ /* Search in skeleton */
+ Ogg_GetBoundsUsingSkeletonIndex( p_stream, i_time, &i_lowerpos, &i_upperpos );
+ if ( i_lowerpos != -1 ) b_found = true;
+
+ /* And also search in our own index */
+ if ( !b_found && OggSeekIndexFind( p_stream, i_time, &i_lowerpos, &i_upperpos ) )
+ {
+ b_found = true;
+ }
+
+ /* Or try to be smart with audio fixed bitrate streams */
+ if ( !b_found && p_stream->fmt.i_cat == AUDIO_ES && p_sys->i_streams == 1
+ && p_sys->i_bitrate && Ogg_GetKeyframeGranule( p_stream, 0xFF00FF00 ) == 0xFF00FF00 )
+ {
+ /* But only if there's no keyframe/preload requirements */
+ /* FIXME: add function to get preload time by codec, ex: opus */
+ i_lowerpos = i_time * p_sys->i_bitrate / INT64_C(8000000);
+ b_found = true;
+ }
+
+ /* or search */
+ if ( !b_found && b_fastseek )
+ {
+ i_lowerpos = OggBisectSearchByTime( p_demux, p_stream, i_time,
+ p_stream->i_data_start, p_sys->i_total_length );
+ b_found = ( i_lowerpos != -1 );
+ }
+
+ if ( !b_found ) return -1;
+
+ if ( i_lowerpos < p_stream->i_data_start || i_upperpos > p_sys->i_total_length )
+ return -1;
+
+ /* And really do seek */
+ p_sys->i_input_position = i_lowerpos;
+ seek_byte( p_demux, p_sys->i_input_position );
+ ogg_stream_reset( &p_stream->os );
+
+ return i_lowerpos;
+}
int Oggseek_BlindSeektoPosition( demux_t *p_demux, logical_stream_t *p_stream,
double f, bool b_canfastseek )
demux_sys_t *p_sys = p_demux->p_sys;
OggDebug( msg_Dbg( p_demux, "=================== Seeking To Absolute Time %"PRId64, i_time ) );
- int64_t i_offset_lower = p_stream->i_data_start;
- int64_t i_offset_upper = p_sys->i_total_length;
+ int64_t i_offset_lower = -1;
+ int64_t i_offset_upper = -1;
+
+ if ( Ogg_GetBoundsUsingSkeletonIndex( p_stream, i_time, &i_offset_lower, &i_offset_upper ) )
+ {
+ /* Exact match */
+ OggDebug( msg_Dbg( p_demux, "Found keyframe at %"PRId64" using skeleton index", i_offset_lower ) );
+ if ( i_offset_lower == -1 ) i_offset_lower = p_stream->i_data_start;
+ p_sys->i_input_position = i_offset_lower;
+ seek_byte( p_demux, p_sys->i_input_position );
+ ogg_stream_reset( &p_stream->os );
+ return i_offset_lower;
+ }
+ OggDebug( msg_Dbg( p_demux, "Search bounds set to %"PRId64" %"PRId64" using skeleton index", i_offset_lower, i_offset_upper ) );
OggNoDebug(
OggSeekIndexFind( p_stream, i_time, &i_offset_lower, &i_offset_upper )
int64_t i_pagepos = OggBisectSearchByTime( p_demux, p_stream, i_time,
i_offset_lower, i_offset_upper);
-
+ if ( i_pagepos >= 0 )
+ {
+ /* be sure to clear any state or read+pagein() will fail on same # */
+ ogg_stream_reset( &p_stream->os );
+ seek_byte( p_demux, p_sys->i_input_position );
+ }
/* Insert keyframe position into index */
OggNoDebug(
if ( i_pagepos >= p_stream->i_data_start )
return 0;
}
- p_sys->b_page_waiting = false;
-
return i_result + PAGE_HEADER_BYTES + i_nsegs;
}
-