shithub: opusfile

Download patch

ref: 28dce6b370a797cece178a12e50bdd04d599fa96
parent: 2df5f78666002cf1ea42b0f358ee1d39a403e9b5
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Sat Sep 22 14:02:12 EDT 2012

Save more stream state on seekable open.

2df5f786 did not quite save enough.
The ogg_stream_state and initial ogg_packet list also need to be
 saved, and the starting granule position and pre-skip need to be
 restored.
Otherwise, if the stream has more than one link, the first packets
 decoded will come from the wrong one.

--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -1093,21 +1093,38 @@
 }
 
 static int op_open_seekable2(OggOpusFile *_of){
-  ogg_sync_state oy_start;
-  opus_int64     start_offset;
-  int            ret;
+  ogg_sync_state    oy_start;
+  ogg_stream_state  os_start;
+  ogg_packet       *op_start;
+  opus_int64        start_offset;
+  int               start_op_count;
+  int               ret;
   /*We're partially open and have a first link header state in storage in _of.
     Save off that stream state so we can come back to it.*/
+  start_op_count=_of->op_count;
+  /*This is a bit too large to put on the stack unconditionally.*/
+  op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count);
+  if(op_start==NULL)return OP_EFAULT;
   *&oy_start=_of->oy;
+  *&os_start=_of->os;
   start_offset=_of->offset;
+  memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
   OP_ASSERT((*_of->callbacks.tell)(_of->source)==
    start_offset+oy_start.fill-oy_start.returned);
   ogg_sync_init(&_of->oy);
+  ogg_stream_init(&_of->os,-1);
   ret=op_open_seekable2_impl(_of);
-  /*Restore the old sync state.*/
+  /*Restore the old stream state.*/
+  ogg_stream_clear(&_of->os);
   ogg_sync_clear(&_of->oy);
   *&_of->oy=*&oy_start;
+  *&_of->os=*&os_start;
   _of->offset=start_offset;
+  _of->op_count=start_op_count;
+  memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count);
+  _ogg_free(op_start);
+  _of->prev_packet_gp=_of->links[0].pcm_start;
+  _of->cur_discard_count=_of->links[0].head.pre_skip;
   if(OP_UNLIKELY(ret<0))return ret;
   /*And seek back to the start of the first link.*/
   ret=(*_of->callbacks.seek)(_of->source,