mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 13:15:18 -05:00
libtremor: hack to work around huge allocations for the comment packet in files with embedded album art. Should fix playback of such files on targets with large codec buffers.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30728 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b779fcc3ed
commit
e1ea13ee75
6 changed files with 72 additions and 38 deletions
|
|
@ -236,7 +236,7 @@ int ogg_stream_destroy(ogg_stream_state *os){
|
|||
/* Helpers for ogg_stream_encode; this keeps the structure and
|
||||
what's happening fairly clear */
|
||||
|
||||
static int _os_body_expand(ogg_stream_state *os,int needed){
|
||||
int _os_body_expand(ogg_stream_state *os,int needed){
|
||||
if(os->body_storage<=os->body_fill+needed){
|
||||
void *ret;
|
||||
ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
|
||||
|
|
@ -783,7 +783,7 @@ int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
|
|||
/* add the incoming page to the stream state; we decompose the page
|
||||
into packet segments here as well. */
|
||||
|
||||
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
|
||||
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og, bool copy_body){
|
||||
unsigned char *header=og->header;
|
||||
unsigned char *body=og->body;
|
||||
long bodysize=og->body_len;
|
||||
|
|
@ -868,8 +868,10 @@ int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
|
|||
}
|
||||
|
||||
if(bodysize){
|
||||
if(copy_body){
|
||||
if(_os_body_expand(os,bodysize)) return -1;
|
||||
memcpy(os->body_data+os->body_fill,body,bodysize);
|
||||
}
|
||||
os->body_fill+=bodysize;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void vorbis_comment_init(vorbis_comment *vc){
|
||||
memset(vc,0,sizeof(*vc));
|
||||
}
|
||||
|
|
@ -54,6 +55,7 @@ void vorbis_comment_clear(vorbis_comment *vc){
|
|||
memset(vc,0,sizeof(*vc));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
|
||||
They may be equal, but short will never ge greater than long */
|
||||
|
|
@ -141,6 +143,7 @@ static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
|
|||
return(OV_EBADHEADER);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
|
||||
int vendorlen;
|
||||
vendorlen=oggpack_read(opb,32);
|
||||
|
|
@ -156,6 +159,7 @@ static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
|
|||
vorbis_comment_clear(vc);
|
||||
return(OV_EBADHEADER);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* all of the real encoding details are here. The modes, books,
|
||||
everything */
|
||||
|
|
@ -267,7 +271,7 @@ int vorbis_synthesis_idheader(ogg_packet *op){
|
|||
with bitstream comments and a third packet that holds the
|
||||
codebook. */
|
||||
|
||||
int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
|
||||
int vorbis_synthesis_headerin(vorbis_info *vi,ogg_packet *op){
|
||||
oggpack_buffer opb;
|
||||
|
||||
if(op){
|
||||
|
|
@ -303,10 +307,11 @@ int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op)
|
|||
return(OV_EBADHEADER);
|
||||
}
|
||||
|
||||
return(_vorbis_unpack_comment(vc,&opb));
|
||||
/*return(_vorbis_unpack_comment(vc,&opb));*/
|
||||
return 0;
|
||||
|
||||
case 0x05: /* least significant *bit* is read first */
|
||||
if(vi->rate==0 || vc->vendor==NULL){
|
||||
if(vi->rate==0 /*|| vc->vendor==NULL*/){
|
||||
/* um... we didn;t get the initial header or comments yet */
|
||||
return(OV_EBADHEADER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,20 +154,20 @@ typedef struct vorbis_comment{
|
|||
extern void vorbis_info_init(vorbis_info *vi);
|
||||
extern void vorbis_info_clear(vorbis_info *vi);
|
||||
extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
|
||||
/*
|
||||
extern void vorbis_comment_init(vorbis_comment *vc);
|
||||
extern void vorbis_comment_add(vorbis_comment *vc, char *comment);
|
||||
extern void vorbis_comment_add_tag(vorbis_comment *vc,
|
||||
char *tag, char *contents);
|
||||
extern void vorbis_comment_clear(vorbis_comment *vc);
|
||||
|
||||
*/
|
||||
extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
|
||||
extern int vorbis_block_clear(vorbis_block *vb);
|
||||
extern void vorbis_dsp_clear(vorbis_dsp_state *v);
|
||||
|
||||
/* Vorbis PRIMITIVES: synthesis layer *******************************/
|
||||
extern int vorbis_synthesis_idheader(ogg_packet *op);
|
||||
extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
|
||||
ogg_packet *op);
|
||||
extern int vorbis_synthesis_headerin(vorbis_info *vi,ogg_packet *op);
|
||||
|
||||
extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
|
||||
extern int vorbis_synthesis_restart(vorbis_dsp_state *v);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ typedef struct OggVorbis_File {
|
|||
ogg_uint32_t *serialnos;
|
||||
ogg_int64_t *pcmlengths;
|
||||
vorbis_info *vi;
|
||||
vorbis_comment *vc;
|
||||
/* vorbis_comment *vc; */
|
||||
|
||||
/* Decoding working state local storage */
|
||||
ogg_int64_t pcm_offset;
|
||||
|
|
|
|||
|
|
@ -227,6 +227,8 @@ extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
|
|||
#endif
|
||||
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
|
||||
|
||||
extern int _os_body_expand(ogg_stream_state *os,int needed);
|
||||
|
||||
extern int ogg_sync_init(ogg_sync_state *oy);
|
||||
extern int ogg_sync_clear(ogg_sync_state *oy);
|
||||
extern int ogg_sync_reset(ogg_sync_state *oy);
|
||||
|
|
@ -241,7 +243,7 @@ extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
|
|||
/*
|
||||
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
|
||||
*/
|
||||
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
|
||||
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og, bool copy_body);
|
||||
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
|
||||
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,25 @@ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
|
|||
}
|
||||
}
|
||||
|
||||
/* This is a nasty hack to work around the huge allocations we get from
|
||||
huge comment packets, usually due to embedded album art */
|
||||
static int ogg_stream_discard_packet(OggVorbis_File *vf,ogg_page *og,
|
||||
ogg_int64_t boundary){
|
||||
int ret;
|
||||
while((ret = ogg_stream_packetout(&vf->os, NULL)) == 0) {
|
||||
if(_get_next_page(vf, og, boundary)<0)
|
||||
break;
|
||||
ogg_stream_pagein(&vf->os,og,false);
|
||||
}
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (vf->os.body_fill < og->body_len)
|
||||
if(_os_body_expand(&vf->os, og->body_len))
|
||||
return -1;
|
||||
memcpy(vf->os.body_data+vf->os.body_fill-og->body_len, og->body, og->body_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find the latest page beginning before the current stream cursor
|
||||
position. Much dirtier than the above as Ogg doesn't have any
|
||||
backward search linkage. no 'readp' as it will certainly have to
|
||||
|
|
@ -272,7 +291,7 @@ static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf,
|
|||
|
||||
/* uses the local ogg_stream storage in vf; this is important for
|
||||
non-streaming input sources */
|
||||
static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
||||
static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,
|
||||
ogg_uint32_t **serialno_list, int *serialno_n,
|
||||
ogg_page *og_ptr){
|
||||
ogg_page og;
|
||||
|
|
@ -288,7 +307,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
}
|
||||
|
||||
vorbis_info_init(vi);
|
||||
vorbis_comment_init(vc);
|
||||
/* vorbis_comment_init(vc); */
|
||||
vf->ready_state=OPENED;
|
||||
|
||||
/* extract the serialnos of all BOS pages + the first set of vorbis
|
||||
|
|
@ -312,13 +331,13 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
/* we don't have a vorbis stream in this link yet, so begin
|
||||
prospective stream setup. We need a stream to get packets */
|
||||
ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
|
||||
ogg_stream_pagein(&vf->os,og_ptr);
|
||||
ogg_stream_pagein(&vf->os,og_ptr,true);
|
||||
|
||||
if(ogg_stream_packetout(&vf->os,&op) > 0 &&
|
||||
vorbis_synthesis_idheader(&op)){
|
||||
/* vorbis header; continue setup */
|
||||
vf->ready_state=STREAMSET;
|
||||
if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
|
||||
if((ret=vorbis_synthesis_headerin(vi,&op))){
|
||||
ret=OV_EBADHEADER;
|
||||
goto bail_header;
|
||||
}
|
||||
|
|
@ -340,7 +359,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
/* if this page also belongs to our vorbis stream, submit it and break */
|
||||
if(vf->ready_state==STREAMSET &&
|
||||
vf->os.serialno == ogg_page_serialno(og_ptr)){
|
||||
ogg_stream_pagein(&vf->os,og_ptr);
|
||||
ogg_stream_pagein(&vf->os,og_ptr,true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -354,10 +373,16 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
while(1){
|
||||
|
||||
i=0;
|
||||
/* discard comment packet */
|
||||
if(ogg_stream_discard_packet(vf,og_ptr,CHUNKSIZE) < 0){
|
||||
ret=OV_EBADHEADER;
|
||||
goto bail_header;
|
||||
}
|
||||
i++;
|
||||
|
||||
while(i<2){ /* get a page loop */
|
||||
|
||||
while(i<2){ /* get a packet loop */
|
||||
|
||||
int result=ogg_stream_packetout(&vf->os,&op);
|
||||
if(result==0)break;
|
||||
if(result==-1){
|
||||
|
|
@ -365,7 +390,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
goto bail_header;
|
||||
}
|
||||
|
||||
if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
|
||||
if((ret=vorbis_synthesis_headerin(vi,&op)))
|
||||
goto bail_header;
|
||||
|
||||
i++;
|
||||
|
|
@ -379,7 +404,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
|
||||
/* if this page belongs to the correct stream, go parse it */
|
||||
if(vf->os.serialno == ogg_page_serialno(og_ptr)){
|
||||
ogg_stream_pagein(&vf->os,og_ptr);
|
||||
ogg_stream_pagein(&vf->os,og_ptr,true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -402,7 +427,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
|
|||
|
||||
bail_header:
|
||||
vorbis_info_clear(vi);
|
||||
vorbis_comment_clear(vc);
|
||||
/* vorbis_comment_clear(vc); */
|
||||
vf->ready_state=OPENED;
|
||||
|
||||
return ret;
|
||||
|
|
@ -428,7 +453,7 @@ static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
|
|||
if(ogg_page_serialno(&og)!= serialno) continue;
|
||||
|
||||
/* count blocksizes of all frames in the page */
|
||||
ogg_stream_pagein(&vf->os,&og);
|
||||
ogg_stream_pagein(&vf->os,&og,true);
|
||||
while((result=ogg_stream_packetout(&vf->os,&op))){
|
||||
if(result>0){ /* ignore holes */
|
||||
long thisblock=vorbis_packet_blocksize(vi,&op);
|
||||
|
|
@ -500,7 +525,7 @@ static int _bisect_forward_serialno(OggVorbis_File *vf,
|
|||
|
||||
vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
|
||||
vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
|
||||
vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
|
||||
/* vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));*/
|
||||
vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
|
||||
vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
|
||||
vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
|
||||
|
|
@ -514,7 +539,7 @@ static int _bisect_forward_serialno(OggVorbis_File *vf,
|
|||
ogg_uint32_t *next_serialno_list=NULL;
|
||||
int next_serialnos=0;
|
||||
vorbis_info vi;
|
||||
vorbis_comment vc;
|
||||
/* vorbis_comment vc; */
|
||||
|
||||
/* the below guards against garbage seperating the last and
|
||||
first pages of two links. */
|
||||
|
|
@ -559,7 +584,7 @@ static int _bisect_forward_serialno(OggVorbis_File *vf,
|
|||
if(ret)return(ret);
|
||||
}
|
||||
|
||||
ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
|
||||
ret=_fetch_headers(vf,&vi,&next_serialno_list,&next_serialnos,NULL);
|
||||
if(ret)return(ret);
|
||||
serialno = vf->os.serialno;
|
||||
dataoffset = vf->offset;
|
||||
|
|
@ -579,7 +604,7 @@ static int _bisect_forward_serialno(OggVorbis_File *vf,
|
|||
vf->dataoffsets[m+1]=dataoffset;
|
||||
|
||||
vf->vi[m+1]=vi;
|
||||
vf->vc[m+1]=vc;
|
||||
/* vf->vc[m+1]=vc; */
|
||||
|
||||
vf->pcmlengths[m*2+1]=searchgran;
|
||||
vf->pcmlengths[m*2+2]=pcmoffset;
|
||||
|
|
@ -789,7 +814,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
|
|||
|
||||
if(!vf->seekable){
|
||||
vorbis_info_clear(vf->vi);
|
||||
vorbis_comment_clear(vf->vc);
|
||||
/* vorbis_comment_clear(vf->vc); */
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -842,7 +867,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
|
|||
/* we're streaming */
|
||||
/* fetch the three header packets, build the info struct */
|
||||
|
||||
int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
|
||||
int ret=_fetch_headers(vf,vf->vi,NULL,NULL,&og);
|
||||
if(ret)return(ret);
|
||||
vf->current_serialno=vf->os.serialno;
|
||||
vf->current_link++;
|
||||
|
|
@ -853,7 +878,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
|
|||
|
||||
/* the buffered page is the data we want, and we're ready for it;
|
||||
add it to the stream state */
|
||||
ogg_stream_pagein(&vf->os,&og);
|
||||
ogg_stream_pagein(&vf->os,&og,true);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -889,12 +914,12 @@ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
|
|||
entry for partial open */
|
||||
vf->links=1;
|
||||
vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
|
||||
vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
|
||||
/* vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); */
|
||||
ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
|
||||
|
||||
/* Fetch all BOS pages, store the vorbis header and all seen serial
|
||||
numbers, load subsequent vorbis setup headers */
|
||||
if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
|
||||
if((ret=_fetch_headers(vf,vf->vi,&serialno_list,&serialno_list_size,NULL))<0){
|
||||
vf->datasource=NULL;
|
||||
ov_clear(vf);
|
||||
}else{
|
||||
|
|
@ -945,10 +970,10 @@ int ov_clear(OggVorbis_File *vf){
|
|||
int i;
|
||||
for(i=0;i<vf->links;i++){
|
||||
vorbis_info_clear(vf->vi+i);
|
||||
vorbis_comment_clear(vf->vc+i);
|
||||
/* vorbis_comment_clear(vf->vc+i); */
|
||||
}
|
||||
_ogg_free(vf->vi);
|
||||
_ogg_free(vf->vc);
|
||||
/* _ogg_free(vf->vc); */
|
||||
}
|
||||
if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
|
||||
if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
|
||||
|
|
@ -1180,8 +1205,8 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
|
|||
firstflag=(pagepos<=vf->dataoffsets[link]);
|
||||
}
|
||||
|
||||
ogg_stream_pagein(&vf->os,&og);
|
||||
ogg_stream_pagein(&work_os,&og);
|
||||
ogg_stream_pagein(&vf->os,&og,true);
|
||||
ogg_stream_pagein(&work_os,&og,true);
|
||||
lastflag=ogg_page_eos(&og);
|
||||
|
||||
}
|
||||
|
|
@ -1363,7 +1388,7 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
|
|||
}
|
||||
|
||||
ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
|
||||
ogg_stream_pagein(&vf->os,&og);
|
||||
ogg_stream_pagein(&vf->os,&og,true);
|
||||
|
||||
/* pull out all but last packet; the one with granulepos */
|
||||
while(1){
|
||||
|
|
@ -1492,7 +1517,7 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
|
|||
lastblock=0;
|
||||
}
|
||||
|
||||
ogg_stream_pagein(&vf->os,&og);
|
||||
ogg_stream_pagein(&vf->os,&og,true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue