Update opusfile from 0.5 to 0.8
This commit is contained in:
parent
ef8ad54421
commit
7139094355
5 changed files with 479 additions and 154 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue