Update opusfile from 0.5 to 0.8

This commit is contained in:
Zack Middleton 2017-05-23 11:03:07 -05:00
parent ef8ad54421
commit 7139094355
5 changed files with 479 additions and 154 deletions

View file

@ -156,8 +156,8 @@ static int op_get_data(OggOpusFile *_of,int _nbytes){
/*Save a tiny smidge of verbosity to make the code more readable.*/
static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
if(_offset==_of->offset)return 0;
if(_of->callbacks.seek==NULL||
(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){
if(_of->callbacks.seek==NULL
||(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){
return OP_EREAD;
}
_of->offset=_offset;
@ -237,7 +237,9 @@ static int op_add_serialno(const ogg_page *_og,
nserialnos=*_nserialnos;
cserialnos=*_cserialnos;
if(OP_UNLIKELY(nserialnos>=cserialnos)){
if(OP_UNLIKELY(cserialnos>INT_MAX-1>>1))return OP_EFAULT;
if(OP_UNLIKELY(cserialnos>INT_MAX/(int)sizeof(*serialnos)-1>>1)){
return OP_EFAULT;
}
cserialnos=2*cserialnos+1;
OP_ASSERT(nserialnos<cserialnos);
serialnos=(ogg_uint32_t *)_ogg_realloc(serialnos,
@ -317,7 +319,7 @@ struct OpusSeekRecord{
static int op_get_prev_page_serial(OggOpusFile *_of,OpusSeekRecord *_sr,
opus_int64 _offset,ogg_uint32_t _serialno,
const ogg_uint32_t *_serialnos,int _nserialnos){
OpusSeekRecord preferred_sr={0};
OpusSeekRecord preferred_sr;
ogg_page og;
opus_int64 begin;
opus_int64 end;
@ -496,30 +498,26 @@ static int op_fetch_headers_impl(OggOpusFile *_of,OpusHead *_head,
ogg_stream_pagein(&_of->os,_og);
if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){
ret=opus_head_parse(_head,op.packet,op.bytes);
/*If it's just a stream type we don't recognize, ignore it.*/
if(ret==OP_ENOTFORMAT)continue;
/*Everything else is fatal.*/
if(OP_UNLIKELY(ret<0))return ret;
/*Found a valid Opus header.
Continue setup.*/
_of->ready_state=OP_STREAMSET;
if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET;
/*If it's just a stream type we don't recognize, ignore it.
Everything else is fatal.*/
else if(ret!=OP_ENOTFORMAT)return ret;
}
/*TODO: Should a BOS page with no packets be an error?*/
}
/*Get the next page.
No need to clamp the boundary offset against _of->end, as all errors
become OP_ENOTFORMAT.*/
become OP_ENOTFORMAT or OP_EBADHEADER.*/
if(OP_UNLIKELY(op_get_next_page(_of,_og,
OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
return OP_ENOTFORMAT;
}
/*If this page also belongs to our Opus stream, submit it and break.*/
if(_of->ready_state==OP_STREAMSET
&&_of->os.serialno==ogg_page_serialno(_og)){
ogg_stream_pagein(&_of->os,_og);
break;
return _of->ready_state<OP_STREAMSET?OP_ENOTFORMAT:OP_EBADHEADER;
}
}
if(OP_UNLIKELY(_of->ready_state!=OP_STREAMSET))return OP_ENOTFORMAT;
/*If the first non-header page belonged to our Opus stream, submit it.*/
if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og);
/*Loop getting packets.*/
for(;;){
switch(ogg_stream_packetout(&_of->os,&op)){
@ -830,6 +828,7 @@ static opus_int32 op_collect_audio_packets(OggOpusFile *_of,
static int op_find_initial_pcm_offset(OggOpusFile *_of,
OggOpusLink *_link,ogg_page *_og){
ogg_page og;
opus_int64 page_offset;
ogg_int64_t pcm_start;
ogg_int64_t prev_packet_gp;
ogg_int64_t cur_page_gp;
@ -847,13 +846,12 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
least once.*/
total_duration=0;
do{
opus_int64 llret;
llret=op_get_next_page(_of,_og,_of->end);
page_offset=op_get_next_page(_of,_og,_of->end);
/*We should get a page unless the file is truncated or mangled.
Otherwise there are no audio data packets in the whole logical stream.*/
if(OP_UNLIKELY(llret<0)){
if(OP_UNLIKELY(page_offset<0)){
/*Fail if there was a read error.*/
if(llret<OP_FALSE)return (int)llret;
if(page_offset<OP_FALSE)return (int)page_offset;
/*Fail if the pre-skip is non-zero, since it's asking us to skip more
samples than exist.*/
if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
@ -954,6 +952,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
_of->op_count=pi;
_of->cur_discard_count=_link->head.pre_skip;
_of->prev_packet_gp=_link->pcm_start=pcm_start;
_of->prev_page_offset=page_offset;
return 0;
}
@ -1128,7 +1127,7 @@ static int op_bisect_forward_serialno(OggOpusFile *_of,
opus_int64 bisect;
opus_int64 next;
opus_int64 last;
ogg_int64_t end_offset=0;
ogg_int64_t end_offset;
ogg_int64_t end_gp;
int sri;
serialnos=*_serialnos;
@ -1309,13 +1308,20 @@ static void op_update_gain(OggOpusFile *_of){
track gain must lie in the range [-32768,32767], and the user-supplied
offset has been pre-clamped to [-98302,98303].*/
switch(_of->gain_type){
case OP_ALBUM_GAIN:{
int album_gain_q8;
album_gain_q8=0;
opus_tags_get_album_gain(&_of->links[li].tags,&album_gain_q8);
gain_q8+=album_gain_q8;
gain_q8+=head->output_gain;
}break;
case OP_TRACK_GAIN:{
int track_gain_q8;
track_gain_q8=0;
opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8);
gain_q8+=track_gain_q8;
}
/*Fall through.*/
gain_q8+=head->output_gain;
}break;
case OP_HEADER_GAIN:gain_q8+=head->output_gain;break;
case OP_ABSOLUTE_GAIN:break;
default:OP_ASSERT(0);
@ -1407,6 +1413,7 @@ static int op_open_seekable2(OggOpusFile *_of){
ogg_sync_state oy_start;
ogg_stream_state os_start;
ogg_packet *op_start;
opus_int64 prev_page_offset;
opus_int64 start_offset;
int start_op_count;
int ret;
@ -1426,6 +1433,7 @@ static int op_open_seekable2(OggOpusFile *_of){
if(op_start==NULL)return OP_EFAULT;
*&oy_start=_of->oy;
*&os_start=_of->os;
prev_page_offset=_of->prev_page_offset;
start_offset=_of->offset;
memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of));
@ -1442,6 +1450,7 @@ static int op_open_seekable2(OggOpusFile *_of){
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->prev_page_offset=prev_page_offset;
_of->cur_discard_count=_of->links[0].head.pre_skip;
if(OP_UNLIKELY(ret<0))return ret;
/*And restore the position indicator.*/
@ -1456,6 +1465,7 @@ static void op_decode_clear(OggOpusFile *_of){
_of->op_count=0;
_of->od_buffer_size=0;
_of->prev_packet_gp=-1;
_of->prev_page_offset=-1;
if(!_of->seekable){
OP_ASSERT(_of->ready_state>=OP_INITSET);
opus_tags_clear(&_of->links[0].tags);
@ -1814,13 +1824,11 @@ opus_int32 op_bitrate_instant(OggOpusFile *_of){
This handles the case where we're at a bitstream boundary and dumps the
decoding machine.
If the decoding machine is unloaded, it loads it.
It also keeps prev_packet_gp up to date (seek and read both use this; seek
uses a special hack with _readp).
It also keeps prev_packet_gp up to date (seek and read both use this).
Return: <0) Error, OP_HOLE (lost packet), or OP_EOF.
0) Need more data (only if _readp==0).
1) Got at least one audio data packet.*/
0) Got at least one audio data packet.*/
static int op_fetch_and_process_page(OggOpusFile *_of,
ogg_page *_og,opus_int64 _page_pos,int _readp,int _spanp,int _ignore_holes){
ogg_page *_og,opus_int64 _page_offset,int _spanp,int _ignore_holes){
OggOpusLink *links;
ogg_uint32_t cur_serialno;
int seekable;
@ -1828,7 +1836,6 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
int ret;
/*We shouldn't get here if we have unprocessed packets.*/
OP_ASSERT(_of->ready_state<OP_INITSET||_of->op_pos>=_of->op_count);
if(!_readp)return 0;
seekable=_of->seekable;
links=_of->links;
cur_link=seekable?_of->cur_link:0;
@ -1837,36 +1844,27 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
for(;;){
ogg_page og;
OP_ASSERT(_of->ready_state>=OP_OPENED);
/*This loop is not strictly necessary, but there's no sense in doing the
extra checks of the larger loop for the common case in a multiplexed
bistream where the page is simply part of a different logical
bitstream.*/
do{
/*If we were given a page to use, use it.*/
if(_og!=NULL){
*&og=*_og;
_og=NULL;
}
/*Keep reading until we get a page with the correct serialno.*/
else _page_pos=op_get_next_page(_of,&og,_of->end);
/*EOF: Leave uninitialized.*/
if(_page_pos<0)return _page_pos<OP_FALSE?(int)_page_pos:OP_EOF;
if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)){
if(cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){
/*Two possibilities:
1) Another stream is multiplexed into this logical section, or*/
if(OP_LIKELY(!ogg_page_bos(&og)))continue;
/* 2) Our decoding just traversed a bitstream boundary.*/
if(!_spanp)return OP_EOF;
if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of);
break;
}
}
/*Bitrate tracking: add the header's bytes here.
The body bytes are counted when we consume the packets.*/
_of->bytes_tracked+=og.header_len;
/*If we were given a page to use, use it.*/
if(_og!=NULL){
*&og=*_og;
_og=NULL;
}
while(0);
/*Keep reading until we get a page with the correct serialno.*/
else _page_offset=op_get_next_page(_of,&og,_of->end);
/*EOF: Leave uninitialized.*/
if(_page_offset<0)return _page_offset<OP_FALSE?(int)_page_offset:OP_EOF;
if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)
&&cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){
/*Two possibilities:
1) Another stream is multiplexed into this logical section, or*/
if(OP_LIKELY(!ogg_page_bos(&og)))continue;
/* 2) Our decoding just traversed a bitstream boundary.*/
if(!_spanp)return OP_EOF;
if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of);
}
/*Bitrate tracking: add the header's bytes here.
The body bytes are counted when we consume the packets.*/
else _of->bytes_tracked+=og.header_len;
/*Do we need to load a new machine before submitting the page?
This is different in the seekable and non-seekable cases.
In the seekable case, we already have all the header information loaded
@ -1895,8 +1893,9 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
_of->ready_state=OP_STREAMSET;
/*If we're at the start of this link, initialize the granule position
and pre-skip tracking.*/
if(_page_pos<=links[cur_link].data_offset){
if(_page_offset<=links[cur_link].data_offset){
_of->prev_packet_gp=links[cur_link].pcm_start;
_of->prev_page_offset=-1;
_of->cur_discard_count=links[cur_link].head.pre_skip;
/*Ignore a hole at the start of a new link (this is common for
streams joined in the middle) or after seeking.*/
@ -1923,10 +1922,12 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
/*If we didn't get any packets out of op_find_initial_pcm_offset(),
keep going (this is possible if end-trimming trimmed them all).*/
if(_of->op_count<=0)continue;
/*Otherwise, we're done.*/
/*Otherwise, we're done.
TODO: This resets bytes_tracked, which misses the header bytes
already processed by op_find_initial_pcm_offset().*/
ret=op_make_decode_ready(_of);
if(OP_UNLIKELY(ret<0))return ret;
return 1;
return 0;
}
}
/*The buffered page is the data we want, and we're ready for it.
@ -2044,7 +2045,8 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration)
should succeed and give prev_packet_gp==cur_page_gp.
But we don't bother to check that, as there isn't much we can do
if it's not true.
if it's not true, and it actually will not be true on the first
page after a seek, if there was a continued packet.
The only thing we guarantee is that the start and end granule
positions of the packets are valid, and that they are monotonic
within a page.
@ -2073,9 +2075,10 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
OP_ASSERT(total_duration==0);
}
_of->prev_packet_gp=prev_packet_gp;
_of->prev_page_offset=_page_offset;
_of->op_count=pi;
/*If end-trimming didn't trim all the packets, we're done.*/
if(OP_LIKELY(pi>0))return 1;
if(OP_LIKELY(pi>0))return 0;
}
}
}
@ -2093,7 +2096,7 @@ int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){
_of->samples_tracked=0;
ret=op_seek_helper(_of,_pos);
if(OP_UNLIKELY(ret<0))return OP_EREAD;
ret=op_fetch_and_process_page(_of,NULL,-1,1,1,1);
ret=op_fetch_and_process_page(_of,NULL,-1,1,1);
/*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized.
Instead, jump to the end.*/
if(ret==OP_EOF){
@ -2105,7 +2108,6 @@ int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){
_of->cur_discard_count=0;
ret=0;
}
else if(ret>0)ret=0;
return ret;
}
@ -2146,6 +2148,27 @@ static ogg_int64_t op_get_granulepos(const OggOpusFile *_of,
return -1;
}
/*A small helper to determine if an Ogg page contains data that continues onto
a subsequent page.*/
static int op_page_continues(const ogg_page *_og){
int nlacing;
OP_ASSERT(_og->header_len>=27);
nlacing=_og->header[26];
OP_ASSERT(_og->header_len>=27+nlacing);
/*This also correctly handles the (unlikely) case of nlacing==0, because
0!=255.*/
return _og->header[27+nlacing-1]==255;
}
/*A small helper to buffer the continued packet data from a page.*/
static void op_buffer_continued_data(OggOpusFile *_of,ogg_page *_og){
ogg_packet op;
ogg_stream_pagein(&_of->os,_og);
/*Drain any packets that did end on this page (and ignore holes).
We only care about the continued packet data.*/
while(ogg_stream_packetout(&_of->os,&op));
}
/*This controls how close the target has to be to use the current stream
position to subdivide the initial range.
Two minutes seems to be a good default.*/
@ -2170,18 +2193,20 @@ static int op_pcm_seek_page(OggOpusFile *_of,
ogg_int64_t pcm_start;
ogg_int64_t pcm_end;
ogg_int64_t best_gp;
ogg_int64_t diff=0;
ogg_int64_t diff;
ogg_uint32_t serialno;
opus_int32 pre_skip;
opus_int64 begin;
opus_int64 end;
opus_int64 boundary;
opus_int64 best;
opus_int64 best_start;
opus_int64 page_offset;
opus_int64 d0;
opus_int64 d1;
opus_int64 d2;
int force_bisect;
int buffering;
int ret;
_of->bytes_tracked=0;
_of->samples_tracked=0;
@ -2189,8 +2214,9 @@ static int op_pcm_seek_page(OggOpusFile *_of,
best_gp=pcm_start=link->pcm_start;
pcm_end=link->pcm_end;
serialno=link->serialno;
best=begin=link->data_offset;
best=best_start=begin=link->data_offset;
page_offset=-1;
buffering=0;
/*We discard the first 80 ms of data after a seek, so seek back that much
farther.
If we can't, simply seek to the beginning of the link.*/
@ -2236,6 +2262,18 @@ static int op_pcm_seek_page(OggOpusFile *_of,
if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){
best=begin=offset;
best_gp=pcm_start=gp;
/*If we have buffered data from a continued packet, remember the
offset of the previous page's start, so that if we do wind up
having to seek back here later, we can prime the stream with
the continued packet data.
With no continued packet, we remember the end of the page.*/
best_start=_of->os.body_returned<_of->os.body_fill?
_of->prev_page_offset:best;
/*If there's completed packets and data in the stream state,
prev_page_offset should always be set.*/
OP_ASSERT(best_start>=0);
/*Buffer any continued packet data starting from here.*/
buffering=1;
}
}
else{
@ -2247,13 +2285,14 @@ static int op_pcm_seek_page(OggOpusFile *_of,
generally 1 second or less), we can loop them continuously
without seeking at all.*/
OP_ALWAYS_TRUE(!op_granpos_add(&prev_page_gp,_of->op[0].granulepos,
op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes)));
-op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes)));
if(op_granpos_cmp(prev_page_gp,_target_gp)<=0){
/*Don't call op_decode_clear(), because it will dump our
packets.*/
_of->op_pos=0;
_of->od_buffer_size=0;
_of->prev_packet_gp=prev_page_gp;
/*_of->prev_page_offset already points to the right place.*/
_of->ready_state=OP_STREAMSET;
return op_make_decode_ready(_of);
}
@ -2274,6 +2313,9 @@ static int op_pcm_seek_page(OggOpusFile *_of,
Vinen)" from libvorbisfile.
It has been modified substantially since.*/
op_decode_clear(_of);
if(!buffering)ogg_stream_reset_serialno(&_of->os,serialno);
_of->cur_link=_li;
_of->ready_state=OP_STREAMSET;
/*Initialize the interval size history.*/
d2=d1=d0=end-begin;
force_bisect=0;
@ -2289,7 +2331,7 @@ static int op_pcm_seek_page(OggOpusFile *_of,
d2=end-begin>>1;
if(force_bisect)bisect=begin+(end-begin>>1);
else{
ogg_int64_t diff2=0;
ogg_int64_t diff2;
OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start));
/*Take a (pretty decent) guess.*/
@ -2299,12 +2341,23 @@ static int op_pcm_seek_page(OggOpusFile *_of,
force_bisect=0;
}
if(bisect!=_of->offset){
/*Discard any buffered continued packet data.*/
if(buffering)ogg_stream_reset(&_of->os);
buffering=0;
page_offset=-1;
ret=op_seek_helper(_of,bisect);
if(OP_UNLIKELY(ret<0))return ret;
}
chunk_size=OP_CHUNK_SIZE;
next_boundary=boundary;
/*Now scan forward and figure out where we landed.
In the ideal case, we will see a page with a granule position at or
before our target, followed by a page with a granule position after our
target (or the end of the search interval).
Then we can just drop out and will have all of the data we need with no
additional seeking.
If we landed too far before, or after, we'll break out and do another
bisection.*/
while(begin<end){
page_offset=op_get_next_page(_of,&og,boundary);
if(page_offset<0){
@ -2314,7 +2367,10 @@ static int op_pcm_seek_page(OggOpusFile *_of,
/*If we scanned the whole interval, we're done.*/
if(bisect<=begin+1)end=begin;
else{
/*Otherwise, back up one chunk.*/
/*Otherwise, back up one chunk.
First, discard any data from a continued packet.*/
if(buffering)ogg_stream_reset(&_of->os);
buffering=0;
bisect=OP_MAX(bisect-chunk_size,begin);
ret=op_seek_helper(_of,bisect);
if(OP_UNLIKELY(ret<0))return ret;
@ -2327,12 +2383,32 @@ static int op_pcm_seek_page(OggOpusFile *_of,
}
else{
ogg_int64_t gp;
int has_packets;
/*Save the offset of the first page we found after the seek, regardless
of the stream it came from or whether or not it has a timestamp.*/
next_boundary=OP_MIN(page_offset,next_boundary);
if(serialno!=(ogg_uint32_t)ogg_page_serialno(&og))continue;
gp=ogg_page_granulepos(&og);
if(gp==-1)continue;
has_packets=ogg_page_packets(&og)>0;
/*Force the gp to -1 (as it should be per spec) if no packets end on
this page.
Otherwise we might get confused when we try to pull out a packet
with that timestamp and can't find it.*/
gp=has_packets?ogg_page_granulepos(&og):-1;
if(gp==-1){
if(buffering){
if(OP_LIKELY(!has_packets))ogg_stream_pagein(&_of->os,&og);
else{
/*If packets did end on this page, but we still didn't have a
valid granule position (in violation of the spec!), stop
buffering continued packet data.
Otherwise we might continue past the packet we actually
wanted.*/
ogg_stream_reset(&_of->os);
buffering=0;
}
}
continue;
}
if(op_granpos_cmp(gp,_target_gp)<0){
/*We found a page that ends before our target.
Advance to the raw offset of the next page.*/
@ -2345,7 +2421,22 @@ static int op_pcm_seek_page(OggOpusFile *_of,
}
/*Save the byte offset of the end of the page with this granule
position.*/
best=begin;
best=best_start=begin;
/*Buffer any data from a continued packet, if necessary.
This avoids the need to seek back here if the next timestamp we
encounter while scanning forward lies after our target.*/
if(buffering)ogg_stream_reset(&_of->os);
if(op_page_continues(&og)){
op_buffer_continued_data(_of,&og);
/*If we have a continued packet, remember the offset of this
page's start, so that if we do wind up having to seek back here
later, we can prime the stream with the continued packet data.
With no continued packet, we remember the end of the page.*/
best_start=page_offset;
}
/*Then force buffering on, so that if a packet starts (but does not
end) on the next page, we still avoid the extra seek back.*/
buffering=1;
best_gp=pcm_start=gp;
OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
/*If we're more than a second away from our target, break out and
@ -2377,28 +2468,40 @@ static int op_pcm_seek_page(OggOpusFile *_of,
}
}
}
/*Found our page.
Seek to the end of it and update prev_packet_gp.
Our caller will set cur_discard_count.
This is an easier case than op_raw_seek(), as we don't need to keep any
packets from the page we found.*/
/*Seek, if necessary.*/
if(best!=page_offset){
page_offset=-1;
ret=op_seek_helper(_of,best);
if(OP_UNLIKELY(ret<0))return ret;
}
/*Found our page.*/
OP_ASSERT(op_granpos_cmp(best_gp,pcm_start)>=0);
_of->cur_link=_li;
_of->ready_state=OP_STREAMSET;
/*Seek, if necessary.
If we were buffering data from a continued packet, we should be able to
continue to scan forward to get the rest of the data (even if
page_offset==-1).
Otherwise, we need to seek back to best_start.*/
if(!buffering){
if(best_start!=page_offset){
page_offset=-1;
ret=op_seek_helper(_of,best_start);
if(OP_UNLIKELY(ret<0))return ret;
}
if(best_start<best){
/*Retrieve the page at best_start, if we do not already have it.*/
if(page_offset<0){
page_offset=op_get_next_page(_of,&og,link->end_offset);
if(OP_UNLIKELY(page_offset<OP_FALSE))return (int)page_offset;
if(OP_UNLIKELY(page_offset!=best_start))return OP_EBADLINK;
}
op_buffer_continued_data(_of,&og);
page_offset=-1;
}
}
/*Update prev_packet_gp to allow per-packet granule position assignment.*/
_of->prev_packet_gp=best_gp;
ogg_stream_reset_serialno(&_of->os,serialno);
ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,1,0,1);
if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
_of->prev_page_offset=best_start;
ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,0,1);
if(OP_UNLIKELY(ret<0))return OP_EBADLINK;
/*Verify result.*/
if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){
return OP_EBADLINK;
}
/*Our caller will set cur_discard_count to handle pre-roll.*/
return 0;
}
@ -2475,8 +2578,8 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){
if(op_pos<op_count)break;
/*We skipped all the packets on this page.
Fetch another.*/
ret=op_fetch_and_process_page(_of,NULL,-1,1,0,1);
if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
ret=op_fetch_and_process_page(_of,NULL,-1,0,1);
if(OP_UNLIKELY(ret<0))return OP_EBADLINK;
}
OP_ALWAYS_TRUE(!op_granpos_diff(&diff,prev_packet_gp,pcm_start));
/*We skipped too far.
@ -2559,8 +2662,8 @@ void op_set_decode_callback(OggOpusFile *_of,
int op_set_gain_offset(OggOpusFile *_of,
int _gain_type,opus_int32 _gain_offset_q8){
if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_TRACK_GAIN
&&_gain_type!=OP_ABSOLUTE_GAIN){
if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_ALBUM_GAIN
&&_gain_type!=OP_TRACK_GAIN&&_gain_type!=OP_ABSOLUTE_GAIN){
return OP_EINVAL;
}
_of->gain_type=_gain_type;
@ -2740,7 +2843,7 @@ static int op_read_native(OggOpusFile *_of,
}
}
/*Suck in another page.*/
ret=op_fetch_and_process_page(_of,NULL,-1,1,1,0);
ret=op_fetch_and_process_page(_of,NULL,-1,1,0);
if(OP_UNLIKELY(ret==OP_EOF)){
if(_li!=NULL)*_li=_of->cur_link;
return 0;