1 /*****************************************************************************
2 * oggseek.c : ogg seeking functions for ogg demuxer vlc
3 *****************************************************************************
4 * Copyright (C) 2008 - 2010 Gabriel Finch <salsaman@gmail.com>
6 * Authors: Gabriel Finch <salsaman@gmail.com>
7 * adapted from: http://lives.svn.sourceforge.net/viewvc/lives/trunk/lives-plugins
8 * /plugins/decoders/ogg_theora_decoder.c
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_demux.h>
41 //#define OGG_SEEK_DEBUG 1
42 /************************************************************
44 *************************************************************/
46 /* free all entries in index list */
48 void oggseek_index_entries_free ( demux_index_entry_t *idx )
50 demux_index_entry_t *idx_next;
54 idx_next = idx->p_next;
61 /* internal function to create a new list member */
63 static demux_index_entry_t *index_entry_new( void )
65 demux_index_entry_t *idx = xmalloc( sizeof( demux_index_entry_t ) );
66 idx->p_next = idx->p_prev = NULL;
67 idx->i_pagepos_end = -1;
73 /* add a theora entry to our list; format is highest granulepos -> page offset of
76 const demux_index_entry_t *oggseek_theora_index_entry_add ( logical_stream_t *p_stream,
80 /* add or update entry for keyframe */
81 demux_index_entry_t *idx;
82 demux_index_entry_t *oidx;
83 demux_index_entry_t *last_idx = NULL;
90 if ( p_stream == NULL ) return NULL;
92 oidx = idx = p_stream->idx;
94 i_tkframe = i_granule >> p_stream->i_granule_shift;
95 i_tframe = i_tkframe + i_granule - ( i_tkframe << p_stream->i_granule_shift );
97 if ( i_tkframe < 1 ) return NULL;
101 demux_index_entry_t *ie = index_entry_new();
102 ie->i_value = i_granule;
103 ie->i_pagepos = i_pagepos;
109 while ( idx != NULL )
111 i_gpos = idx->i_value;
113 i_kframe = i_gpos >> p_stream->i_granule_shift;
114 if ( i_kframe > i_tframe ) break;
116 if ( i_kframe == i_tkframe )
118 /* entry exists, update it if applicable, and return it */
119 i_frame = i_kframe + i_gpos - ( i_kframe << p_stream->i_granule_shift );
120 if ( i_frame < i_tframe )
122 idx->i_value = i_granule;
123 idx->i_pagepos = i_pagepos;
134 /* new entry; insert after last_idx */
136 idx = index_entry_new();
138 if ( last_idx != NULL )
140 idx->p_next = last_idx->p_next;
141 last_idx->p_next = idx;
142 idx->p_prev = last_idx;
150 if ( idx->p_next != NULL )
152 idx->p_next->p_prev = idx;
155 idx->i_value = i_granule;
156 idx->i_pagepos = i_pagepos;
164 /*********************************************************************
166 **********************************************************************/
168 /* seek in ogg file to offset i_pos and update the sync */
170 static void seek_byte( demux_t *p_demux, int64_t i_pos )
172 demux_sys_t *p_sys = p_demux->p_sys;
174 if ( ! stream_Seek( p_demux->s, i_pos ) )
176 ogg_sync_reset( &p_sys->oy );
178 p_sys->i_input_position = i_pos;
179 p_sys->b_page_waiting = false;
185 /* read bytes from the ogg file to try to find a page start */
187 static int64_t get_data( demux_t *p_demux, int64_t i_bytes_to_read )
189 demux_sys_t *p_sys = p_demux->p_sys;
194 if ( p_sys->i_total_length > 0 )
196 if ( p_sys->i_input_position + i_bytes_to_read > p_sys->i_total_length )
198 i_bytes_to_read = p_sys->i_total_length - p_sys->i_input_position;
199 if ( i_bytes_to_read <= 0 ) {
205 seek_byte ( p_demux, p_sys->i_input_position );
207 buf = ogg_sync_buffer( &p_sys->oy, i_bytes_to_read );
209 i_result = stream_Read( p_demux->s, buf, i_bytes_to_read );
211 p_sys->b_page_waiting = false;
213 ogg_sync_wrote( &p_sys->oy, i_result );
217 /* Find the first first ogg page for p_stream between offsets i_pos1 and i_pos2,
218 return file offset in bytes; -1 is returned on failure */
220 static int64_t find_first_page( demux_t *p_demux, int64_t i_pos1, int64_t i_pos2,
221 logical_stream_t *p_stream,
222 int64_t *pi_kframe, int64_t *pi_frame )
225 int64_t i_granulepos;
226 int64_t i_bytes_to_read = i_pos2 - i_pos1 + 1;
227 int64_t i_bytes_read;
228 int64_t i_pages_checked = 0;
229 int64_t i_packets_checked;
231 demux_sys_t *p_sys = p_demux->p_sys;
235 seek_byte( p_demux, i_pos1 );
237 if ( i_pos1 == p_stream->i_data_start )
239 /* set a dummy granulepos at data_start */
240 *pi_kframe = p_stream->i_keyframe_offset;
241 *pi_frame = p_stream->i_keyframe_offset;
243 p_sys->b_page_waiting = true;
244 return p_sys->i_input_position;
247 if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ;
252 if ( p_sys->i_input_position >= i_pos2 )
254 /* we reached the end and found no pages */
259 /* read next chunk */
260 if ( ! ( i_bytes_read = get_data( p_demux, i_bytes_to_read ) ) )
267 i_bytes_to_read = OGGSEEK_BYTES_TO_READ;
269 i_result = ogg_sync_pageseek( &p_sys->oy, &p_sys->current_page );
273 /* found a page, sync to page start */
274 p_sys->i_input_position -= i_result;
275 i_pos1 = p_sys->i_input_position;
279 if ( i_result > 0 || ( i_result == 0 && p_sys->oy.fill > 3 &&
280 ! strncmp( (char *)p_sys->oy.data, "OggS" , 4 ) ) )
282 i_pos1 = p_sys->i_input_position;
286 p_sys->i_input_position += i_bytes_read;
290 seek_byte( p_demux, p_sys->i_input_position );
291 ogg_stream_reset( &p_stream->os );
296 if ( p_sys->i_input_position >= i_pos2 )
298 /* reached the end of the search region and nothing was found */
300 return p_sys->i_input_position;
303 p_sys->b_page_waiting = false;
305 if ( ! ( i_result = oggseek_read_page( p_demux ) ) )
309 return p_sys->i_input_position;
313 if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) )
315 /* page is not for this stream */
316 p_sys->i_input_position += i_result;
317 if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position;
322 ogg_stream_pagein( &p_stream->os, &p_sys->current_page );
325 i_packets_checked = 0;
327 if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
332 if ( i_packets_checked )
334 i_granulepos = ogg_page_granulepos( &p_sys->current_page );
336 oggseek_theora_index_entry_add( p_stream, i_granulepos, i_pos1 );
339 i_granulepos >> p_stream->i_granule_shift;
341 *pi_frame = *pi_kframe +
342 i_granulepos - ( *pi_kframe << p_stream->i_granule_shift );
344 p_sys->b_page_waiting = true;
349 /* -> start of next page */
350 p_sys->i_input_position += i_result;
356 /* Find the last frame for p_stream,
357 -1 is returned on failure */
359 static int64_t find_last_frame (demux_t *p_demux, logical_stream_t *p_stream)
364 int64_t i_frame = -1;
365 int64_t i_last_frame = -1;
366 int64_t i_kframe = 0;
370 demux_sys_t *p_sys = p_demux->p_sys;
372 i_pos1 = p_stream->i_data_start;
373 i_pos2 = p_sys->i_total_length;
375 i_start_pos = i_pos2 - OGGSEEK_BYTES_TO_READ;
380 if ( i_start_pos < i_pos1 ) i_start_pos = i_pos1;
382 i_page_pos = find_first_page( p_demux, i_start_pos, i_pos2, p_stream, &i_kframe, &i_frame );
386 /* no pages found in range */
387 if ( i_last_frame >= 0 )
389 /* No more pages in range -> return last one */
392 if ( i_start_pos <= i_pos1 )
398 i_pos2 -= i_start_pos;
399 i_start_pos -= OGGSEEK_BYTES_TO_READ;
400 if ( i_start_pos < i_pos1 ) i_start_pos = i_pos1;
401 i_pos2 += i_start_pos;
405 /* found a page, see if we can find another one */
406 i_last_frame = i_frame;
407 i_start_pos = i_page_pos + 1;
418 /* convert a theora frame to a granulepos */
420 static inline int64_t frame_to_gpos( logical_stream_t *p_stream, int64_t i_kframe,
423 if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
425 return ( i_kframe << p_stream->i_granule_shift ) + ( i_frame - i_kframe );
435 /* seek to a suitable point to begin decoding for i_tframe. We can pre-set bounding positions
436 i_pos_lower and i_pos_higher to narrow the search domain. */
439 static int64_t ogg_seek( demux_t *p_demux, logical_stream_t *p_stream, int64_t i_tframe,
440 int64_t i_pos_lower, int64_t i_pos_upper, int64_t *pi_pagepos,
444 * We do two passes here, first with b_exact set, then with b_exact unset.
446 * If b_exact is set, we find the highest granulepos <= the target granulepos
447 * from this we extract an estimate of the keyframe (note that there could be other
448 * "hidden" keyframes between the found granulepos and the target).
450 * On the second pass we find the highest granulepos < target. This places us just before or
451 * at the start of the target keyframe.
453 * When we come to decode, we start from this second position, discarding any completed
454 * packets on that page, and read pages discarding packets until we get to the target frame.
456 * The function returns the granulepos which is found,
457 * sets the page offset in pi_pagepos. -1 is returned on error.
461 * we find the highest sync frame <= target frame, and return the sync_frame number
462 * b_exact should be set to true
465 * the method used is bi-sections:
466 * - we check the lower keyframe
467 * if this is == target we return
468 * if > target, or we find no keyframes, we go to the lower segment
469 * if < target we divide the segment in two and check the upper half
471 * This is then repeated until the segment size is too small to hold a packet,
472 * at which point we return our best match
474 * Two optimisations are made: - anything we discover about keyframes is added to our index
475 * - before calling this function we get approximate bounds from the index
477 * therefore, subsequent searches become more rapid.
488 int64_t i_best_kframe = -1;
489 int64_t i_best_frame = -1;
490 int64_t i_best_pagepos = -1;
492 demux_sys_t *p_sys = p_demux->p_sys;
494 if ( i_tframe < p_stream->i_keyframe_offset )
496 *pi_pagepos = p_stream->i_data_start;
499 seek_byte( p_demux, p_stream->i_data_start );
500 return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 1 );
502 return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 0 );
505 if ( i_pos_lower < p_stream->i_data_start )
507 i_pos_lower = p_stream->i_data_start;
510 if ( i_pos_upper < 0 )
512 i_pos_upper = p_sys->i_total_length;
515 if ( i_pos_upper > p_sys->i_total_length )
517 i_pos_upper = p_sys->i_total_length;
520 i_start_pos = i_pos_lower;
521 i_end_pos = i_pos_upper;
523 i_segsize = ( i_end_pos - i_start_pos + 1 ) >> 1;
527 /* see if the frame lies in current segment */
528 if ( i_start_pos < i_pos_lower )
530 i_start_pos = i_pos_lower;
532 if ( i_end_pos > i_pos_upper )
534 i_end_pos = i_pos_upper;
537 if ( i_start_pos >= i_end_pos )
539 if ( i_start_pos == i_pos_lower)
541 if ( ! b_exact ) seek_byte( p_demux, i_start_pos );
542 *pi_pagepos = i_start_pos;
543 return frame_to_gpos( p_stream, p_stream->i_keyframe_offset, 1 );
547 #ifdef OGG_SEEK_DEBUG
548 msg_Dbg( p_demux, "Bisecting startpos=%ld endpos=%ld kframe=%ld iframe=%ld",
549 i_start_pos, i_end_pos, i_kframe, i_frame);
551 if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA || p_stream->fmt.i_codec == VLC_CODEC_OPUS )
553 i_pagepos = find_first_page( p_demux, i_start_pos, i_end_pos, p_stream,
554 &i_kframe, &i_frame );
557 #ifdef OGG_SEEK_DEBUG
558 msg_Dbg( p_demux, "Page Found startpos=%ld endpos=%ld kframe=%ld iframe=%ld pagepos=%ld",
559 i_start_pos, i_end_pos, i_kframe, i_frame, i_pagepos);
561 if ( i_pagepos != -1 && i_kframe != -1 )
565 if ( b_exact && i_frame >= i_tframe && i_kframe <= i_tframe )
568 *pi_pagepos = i_start_pos;
569 return frame_to_gpos( p_stream, i_kframe, i_frame );
572 if ( ( i_kframe < i_tframe || ( b_exact && i_kframe == i_tframe ) )
573 && i_kframe > i_best_kframe )
575 i_best_kframe = i_kframe;
576 i_best_frame = i_frame;
577 i_best_pagepos = i_pagepos;
580 if ( i_frame >= i_tframe )
582 /* check lower half of segment */
583 i_start_pos -= i_segsize;
584 i_end_pos -= i_segsize;
587 else i_start_pos = i_pagepos;
591 /* no keyframe found, check lower segment */
592 i_end_pos -= i_segsize;
593 i_start_pos -= i_segsize;
596 i_segsize = ( i_end_pos - i_start_pos + 1 ) >> 1;
597 i_start_pos += i_segsize;
599 } while ( i_segsize > 64 );
601 if ( i_best_kframe >- 1 )
605 seek_byte( p_demux, i_best_pagepos );
607 *pi_pagepos = i_best_pagepos;
608 return frame_to_gpos( p_stream, i_best_kframe, i_best_frame );
619 /* find upper and lower pagepos for i_tframe; if we find an exact match, we return it */
621 static demux_index_entry_t *get_bounds_for ( logical_stream_t *p_stream, int64_t i_tframe,
622 int64_t *pi_pos_lower, int64_t *pi_pos_upper)
628 demux_index_entry_t *idx = p_stream->idx;
630 *pi_pos_lower = *pi_pos_upper = -1;
632 while ( idx != NULL )
634 if ( idx-> i_pagepos < 0 )
636 /* kframe was found to be invalid */
641 if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA || p_stream->fmt.i_codec == VLC_CODEC_OPUS )
643 i_gpos = idx->i_value;
644 i_kframe = i_gpos >> p_stream->i_granule_shift;
645 i_frame = i_kframe + i_gpos - ( i_kframe << p_stream->i_granule_shift );
650 if ( i_kframe > i_tframe )
652 *pi_pos_upper = idx->i_pagepos;
656 if ( i_frame < i_tframe )
658 *pi_pos_lower = idx->i_pagepos;
670 /* get highest frame in theora and opus streams */
672 static int64_t get_last_frame ( demux_t *p_demux, logical_stream_t *p_stream )
674 demux_sys_t *p_sys = p_demux->p_sys;
678 /* Backup the stream state. We get called during header processing, and our
679 * caller expects its header packet to remain valid after the call. If we
680 * let find_last_frame() reuse the same stream state, then it will
681 * invalidate the pointers in that packet. */
682 memcpy(&os, &p_stream->os, sizeof(os));
683 ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
685 i_frame = find_last_frame ( p_demux, p_stream );
687 /* We need to reset back to the start here, otherwise packets cannot be decoded.
688 * I think this is due to the fact that we seek to the end and then we must reset
689 * all logical streams, which causes remaining headers not to be read correctly.
690 * Seeking to 0 is the only value which seems to work, and it appears to have no
691 * adverse effects. */
693 seek_byte( p_demux, 0 );
694 /* Reset stream states */
695 p_sys->i_streams = 0;
696 ogg_stream_clear( &p_stream->os );
697 memcpy( &p_stream->os, &os, sizeof(os) );
704 /************************************************************************
706 *************************************************************************/
711 /* return highest frame number for p_stream (which must be a theora, dirac or opus stream) */
713 int64_t oggseek_get_last_frame ( demux_t *p_demux, logical_stream_t *p_stream )
715 int64_t i_frame = -1;
717 if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
718 p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
719 p_stream->fmt.i_codec == VLC_CODEC_OPUS )
721 i_frame = get_last_frame ( p_demux, p_stream );
723 if ( i_frame < 0 ) return -1;
727 /* unhandled video format */
736 /* seek to target frame in p_stream; actually we will probably end up just before it
739 * range for i_tframe is 0 -> p_sys->i_total_frames - 1
742 int oggseek_find_frame ( demux_t *p_demux, logical_stream_t *p_stream, int64_t i_tframe )
745 const demux_index_entry_t *fidx;
747 /* lower and upper bounds for search domain */
751 int64_t i_granulepos;
754 /* keyframe for i_tframe ( <= i_tframe ) */
757 /* keyframe for i_kframe ( <= i_kframe ) */
760 /* next frame to be decoded ( >= i_xkframe ) */
763 demux_sys_t *p_sys = p_demux->p_sys;
765 i_tframe += p_stream->i_keyframe_offset;
768 /* For Opus, seek back 80 ms before the target playback position. */
769 if ( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
771 if ( i_tframe <= p_stream->i_pre_skip )
773 else if ( i_tframe < 80*48 )
776 i_cframe = i_tframe - 80*48;
779 /* reduce the search domain */
780 fidx = get_bounds_for( p_stream, i_cframe, &i_pos_lower, &i_pos_upper );
784 /* no exact match found; search the domain for highest keyframe <= i_cframe */
785 #ifdef OGG_SEEK_DEBUG
786 msg_Dbg( p_demux, "Not found in index, searching");
788 i_granulepos = ogg_seek ( p_demux, p_stream, i_cframe, i_pos_lower, i_pos_upper,
790 if ( i_granulepos == -1 )
792 #ifdef OGG_SEEK_DEBUG
793 msg_Err( p_demux, "Unable to find the requested frame");
799 i_granulepos = fidx->i_value;
802 if ( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
804 #ifdef OGG_SEEK_DEBUG
805 msg_Dbg( p_demux, "OPUS seeks to granulepos %ld (%ld frames)", i_granulepos, i_tframe - i_cframe );
807 oggseek_theora_index_entry_add( p_stream, i_granulepos, p_sys->i_input_position );
810 if ( p_stream->fmt.i_codec == VLC_CODEC_THEORA )
812 i_kframe = i_granulepos >> p_stream->i_granule_shift;
813 if ( i_kframe < p_stream->i_keyframe_offset )
815 i_kframe = p_stream->i_keyframe_offset;
818 /* we found a keyframe, but we don't know where its packet starts, so search for a
819 frame just before it */
821 /* reduce search domain */
822 get_bounds_for( p_stream, i_kframe-1, &i_pos_lower, &i_pos_upper );
824 i_granulepos = ogg_seek( p_demux, p_stream, i_kframe-1, i_pos_lower, i_pos_upper,
827 /* i_cframe will be the next frame we decode */
828 i_xkframe = i_granulepos >> p_stream->i_granule_shift;
829 i_cframe = i_xkframe + i_granulepos - ( i_xkframe << p_stream->i_granule_shift) + 1;
831 if ( p_sys->i_input_position == p_stream->i_data_start )
833 i_cframe = i_kframe = p_stream->i_keyframe_offset;
837 oggseek_theora_index_entry_add( p_stream, i_granulepos, p_sys->i_input_position );
841 else return VLC_EGENERIC;
843 p_stream->i_skip_frames = i_tframe - i_cframe;
845 ogg_stream_reset( &p_stream->os );
855 /****************************************************************************
856 * oggseek_read_page: Read a full Ogg page from the physical bitstream.
857 ****************************************************************************
858 * Returns number of bytes read. This should always be > 0
859 * unless we are at the end of stream.
861 ****************************************************************************/
862 int64_t oggseek_read_page( demux_t *p_demux )
864 demux_sys_t *p_ogg = p_demux->p_sys ;
865 uint8_t header[PAGE_HEADER_BYTES+255];
873 demux_sys_t *p_sys = p_demux->p_sys;
875 /* store position of this page */
876 i_in_pos = p_ogg->i_input_position = stream_Tell( p_demux->s );
878 if ( p_sys->b_page_waiting) {
879 msg_Warn( p_demux, "Ogg page already loaded" );
883 if ( stream_Read ( p_demux->s, header, PAGE_HEADER_BYTES ) < PAGE_HEADER_BYTES )
885 stream_Seek( p_demux->s, i_in_pos );
886 msg_Dbg ( p_demux, "Reached clean EOF in ogg file" );
890 i_nsegs = header[ PAGE_HEADER_BYTES - 1 ];
892 if ( stream_Read ( p_demux->s, header+PAGE_HEADER_BYTES, i_nsegs ) < i_nsegs )
894 stream_Seek( p_demux->s, i_in_pos );
895 msg_Warn ( p_demux, "Reached broken EOF in ogg file" );
899 i_page_size = PAGE_HEADER_BYTES + i_nsegs;
901 for ( i = 0; i < i_nsegs; i++ )
903 i_page_size += header[ PAGE_HEADER_BYTES + i ];
906 ogg_sync_reset( &p_ogg->oy );
908 buf = ogg_sync_buffer( &p_ogg->oy, i_page_size );
910 memcpy( buf, header, PAGE_HEADER_BYTES + i_nsegs );
912 i_result = stream_Read ( p_demux->s, (uint8_t*)buf + PAGE_HEADER_BYTES + i_nsegs,
913 i_page_size - PAGE_HEADER_BYTES - i_nsegs );
915 ogg_sync_wrote( &p_ogg->oy, i_result + PAGE_HEADER_BYTES + i_nsegs );
920 if ( ogg_sync_pageout( &p_ogg->oy, &p_ogg->current_page ) != 1 )
922 msg_Err( p_demux , "Got invalid packet, read %"PRId64" of %i: %s",i_result,i_page_size,
927 p_sys->b_page_waiting = false;
929 return i_result + PAGE_HEADER_BYTES + i_nsegs;