********************************************************************
function: simple example encoder
- last mod: $Id: encoder_example.c,v 1.36 2002/01/23 16:04:55 segher Exp $
+ last mod: $Id: encoder_example.c,v 1.37 2002/02/28 04:12:47 xiphmont Exp $
********************************************************************/
/* (quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR) */
vorbis_info_init(&vi);
- vorbis_encode_init_vbr(&vi,2,44100,.1); /* max compression */
+ vorbis_encode_init_vbr(&vi,2,44100,.4); /* max compression */
/* add a comment */
vorbis_comment_init(&vc);
********************************************************************
function: illustrate seeking, and test it too
- last mod: $Id: seeking_example.c,v 1.12 2001/12/20 01:00:24 segher Exp $
+ last mod: $Id: seeking_example.c,v 1.13 2002/02/28 04:12:47 xiphmont Exp $
********************************************************************/
for(j=0;j<bread;j++){
if(buffer[j]!=bigassbuffer[j+pos*2]){
printf("data position after seek doesn't match pcm position\n");
+
+ {
+ FILE *f=fopen("a.m","w");
+ for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)buffer[j]);
+ fclose(f);
+ f=fopen("b.m","w");
+ for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)bigassbuffer[j+pos*2]);
+ fclose(f);
+ }
+
exit(1);
}
}
/* because we want to do sample-level verification that the seek
does what it claimed, decode the entire file into memory */
- printf("loading....\n");
fflush(stdout);
pcmlength=ov_pcm_total(&ov,-1);
bigassbuffer=malloc(pcmlength*2); /* w00t */
}else{
pcmlength=i/2;
}
+ fprintf(stderr,"\rloading.... [%ld left] ",
+ (long)(pcmlength*2-i));
}
/* Exercise all the real seeking cases; ov_raw_seek,
on pcm_seek */
{
ogg_int64_t length=ov.end;
- printf("testing raw seeking to random places in %ld bytes....\n",
+ printf("\rtesting raw seeking to random places in %ld bytes....\n",
(long)length);
for(i=0;i<1000;i++){
exit(1);
}
if(ov_pcm_tell(&ov)!=val){
- printf("Decalred position didn't perfectly match request: %ld != %ld\n",
+ printf("Declared position didn't perfectly match request: %ld != %ld\n",
(long)val,(long)ov_pcm_tell(&ov));
exit(1);
}
********************************************************************
function: libvorbis codec headers
- last mod: $Id: codec.h,v 1.39 2001/12/12 09:45:23 xiphmont Exp $
+ last mod: $Id: codec.h,v 1.40 2002/02/28 04:12:47 xiphmont Exp $
********************************************************************/
extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
+extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm);
extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
********************************************************************
function: PCM data vector blocking, windowing and dis/reassembly
- last mod: $Id: block.c,v 1.58 2002/01/22 11:59:00 xiphmont Exp $
+ last mod: $Id: block.c,v 1.59 2002/02/28 04:12:48 xiphmont Exp $
Handle windowing, overlap-add, etc of the PCM vectors. This is made
more amusing by Vorbis' current two allowed block sizes.
codec_setup_info *ci=vi->codec_setup;
int i,j;
+ if(!vb)return(OV_EINVAL);
if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
-
+
v->lW=v->W;
v->W=vb->W;
v->nW=-1;
-
- v->glue_bits+=vb->glue_bits;
- v->time_bits+=vb->time_bits;
- v->floor_bits+=vb->floor_bits;
- v->res_bits+=vb->res_bits;
-
+
if(v->sequence+1 != vb->sequence)v->granulepos=-1; /* out of sequence;
- lose count */
-
+ lose count */
v->sequence=vb->sequence;
- {
+ if(vb->pcm){ /* not pcm to process if vorbis_synthesis_trackonly
+ was called on block */
int n=ci->blocksizes[v->W]/2;
int n0=ci->blocksizes[0]/2;
int n1=ci->blocksizes[1]/2;
int thisCenter;
int prevCenter;
+ v->glue_bits+=vb->glue_bits;
+ v->time_bits+=vb->time_bits;
+ v->floor_bits+=vb->floor_bits;
+ v->res_bits+=vb->res_bits;
+
if(v->centerW){
thisCenter=n1;
prevCenter=0;
}else{
- thisCenter=0;
- prevCenter=n1;
+ thisCenter=0;
+ prevCenter=n1;
}
/* v->pcm is now used like a two-stage double buffer. We don't want
/* deal with initial packet state; we do this using the explicit
pcm_returned==-1 flag otherwise we're sensitive to first block
being short or long */
-
+
if(v->pcm_returned==-1){
v->pcm_returned=thisCenter;
v->pcm_current=thisCenter;
ci->blocksizes[v->lW]/4+
ci->blocksizes[v->W]/4;
}
+
+ }
- /* track the frame number... This is for convenience, but also
- making sure our last packet doesn't end with added padding. If
- the last packet is partial, the number of samples we'll have to
- return will be past the vb->granulepos.
-
- This is not foolproof! It will be confused if we begin
- decoding at the last page after a seek or hole. In that case,
- we don't have a starting point to judge where the last frame
- is. For this reason, vorbisfile will always try to make sure
- it reads the last two marked pages in proper sequence */
-
- if(v->granulepos==-1)
- if(vb->granulepos==-1){
- v->granulepos=0;
- }else{
- v->granulepos=vb->granulepos;
- }
- else{
- v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
- if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
-
- if(v->granulepos>vb->granulepos){
- long extra=v->granulepos-vb->granulepos;
-
- if(vb->eofflag){
- /* partial last frame. Strip the extra samples off */
- v->pcm_current-=extra;
- }else if(vb->sequence == 1){
- /* ^^^ argh, this can be 1 from seeking! */
-
-
- /* partial first frame. Discard extra leading samples */
- v->pcm_returned+=extra;
- if(v->pcm_returned>v->pcm_current)
- v->pcm_returned=v->pcm_current;
-
- }
+ /* track the frame number... This is for convenience, but also
+ making sure our last packet doesn't end with added padding. If
+ the last packet is partial, the number of samples we'll have to
+ return will be past the vb->granulepos.
+
+ This is not foolproof! It will be confused if we begin
+ decoding at the last page after a seek or hole. In that case,
+ we don't have a starting point to judge where the last frame
+ is. For this reason, vorbisfile will always try to make sure
+ it reads the last two marked pages in proper sequence */
+
+ if(v->granulepos==-1){
+ if(vb->granulepos!=-1){ /* only set if we have a position to set to */
+ v->granulepos=vb->granulepos;
+ }
+ }else{
+ v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+ if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
+
+ if(v->granulepos>vb->granulepos){
+ long extra=v->granulepos-vb->granulepos;
+
+ if(vb->eofflag){
+ /* partial last frame. Strip the extra samples off */
+ v->pcm_current-=extra;
+ }else if(vb->sequence == 1){
+ /* ^^^ argh, this can be 1 from seeking! */
- }/* else{ Shouldn't happen *unless* the bitstream is out of
- spec. Either way, believe the bitstream } */
- v->granulepos=vb->granulepos;
- }
+
+ /* partial first frame. Discard extra leading samples */
+ v->pcm_returned+=extra;
+ if(v->pcm_returned>v->pcm_current)
+ v->pcm_returned=v->pcm_current;
+
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ v->granulepos=vb->granulepos;
}
-
- /* Update, cleanup */
-
- if(vb->eofflag)v->eofflag=1;
}
+ /* Update, cleanup */
+
+ if(vb->eofflag)v->eofflag=1;
return(0);
+
}
/* pcm==NULL indicates we just want the pending samples, no more */
return(0);
}
-int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
- if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
- v->pcm_returned+=bytes;
+int vorbis_synthesis_read(vorbis_dsp_state *v,int n){
+ if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL);
+ v->pcm_returned+=n;
return(0);
}
********************************************************************
function: channel mapping 0 implementation
- last mod: $Id: mapping0.c,v 1.44 2002/01/22 11:59:00 xiphmont Exp $
+ last mod: $Id: mapping0.c,v 1.45 2002/02/28 04:12:48 xiphmont Exp $
********************************************************************/
pcm[j]=0.f;
}
-
+
/* all done! */
return(0);
}
&mapping0_forward,
&mapping0_inverse
};
+
********************************************************************
function: single-block PCM synthesis
- last mod: $Id: synthesis.c,v 1.25 2001/12/20 01:00:30 segher Exp $
+ last mod: $Id: synthesis.c,v 1.26 2002/02/28 04:12:48 xiphmont Exp $
********************************************************************/
return(_mapping_P[type]->inverse(vb,b->mode[mode]));
}
+/* used to track pcm position without actually performing decode.
+ Useful for sequential 'fast forward' */
+int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
+ vorbis_dsp_state *vd=vb->vd;
+ backend_lookup_state *b=vd->backend_state;
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=vi->codec_setup;
+ oggpack_buffer *opb=&vb->opb;
+ int mode;
+
+ /* first things first. Make sure decode is ready */
+ _vorbis_block_ripcord(vb);
+ oggpack_readinit(opb,op->packet,op->bytes);
+
+ /* Check the packet type */
+ if(oggpack_read(opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(opb,b->modebits);
+ if(mode==-1)return(OV_EBADPACKET);
+
+ vb->mode=mode;
+ vb->W=ci->mode_param[mode]->blockflag;
+ if(vb->W){
+ vb->lW=oggpack_read(opb,1);
+ vb->nW=oggpack_read(opb,1);
+ if(vb->nW==-1) return(OV_EBADPACKET);
+ }else{
+ vb->lW=0;
+ vb->nW=0;
+ }
+
+ /* more setup */
+ vb->granulepos=op->granulepos;
+ vb->sequence=op->packetno-3; /* first block is third packet */
+ vb->eofflag=op->e_o_s;
+
+ /* no pcm */
+ vb->pcmend=0;
+ vb->pcm=NULL;
+
+ return(0);
+}
+
long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
codec_setup_info *ci=vi->codec_setup;
oggpack_buffer opb;
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.c,v 1.55 2002/01/22 08:06:08 xiphmont Exp $
+ last mod: $Id: vorbisfile.c,v 1.56 2002/02/28 04:12:48 xiphmont Exp $
********************************************************************/
1) got a packet
*/
-static int _process_packet(OggVorbis_File *vf,int readp){
+static int _fetch_and_process_packet(OggVorbis_File *vf,
+ ogg_packet *op_in,
+ int readp){
ogg_page og;
/* handle one packet. Try to fetch it from current stream state */
if(vf->ready_state==INITSET){
while(1) {
ogg_packet op;
- int result=ogg_stream_packetout(&vf->os,&op);
+ ogg_packet *op_ptr=(op_in?op_in:&op);
+ int result=ogg_stream_packetout(&vf->os,op_ptr);
ogg_int64_t granulepos;
+ op_in=NULL;
if(result==-1)return(OV_HOLE); /* hole in the data. */
if(result>0){
/* got a packet. process it */
- granulepos=op.granulepos;
- if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy
- header handling. The
- header packets aren't
- audio, so if/when we
- submit them,
- vorbis_synthesis will
- reject them */
+ granulepos=op_ptr->granulepos;
+ if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
+ header handling. The
+ header packets aren't
+ audio, so if/when we
+ submit them,
+ vorbis_synthesis will
+ reject them */
/* suck in the synthesis data and track bitrate */
{
int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+ /* for proper use of libvorbis within libvorbisfile,
+ oldsamples will always be zero. */
+ if(oldsamples)return(OV_EFAULT);
+
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
- vf->bittrack+=op.bytes*8;
+ vf->bittrack+=op_ptr->bytes*8;
}
/* update the pcm offset. */
- if(granulepos!=-1 && !op.e_o_s){
+ if(granulepos!=-1 && !op_ptr->e_o_s){
int link=(vf->seekable?vf->current_link:0);
int i,samples;
granulepos declares the last frame in the stream, and the
last packet of the last page may be a partial frame.
So, we need a previous granulepos from an in-sequence page
- to have a reference point. Thus the !op.e_o_s clause
+ to have a reference point. Thus the !op_ptr->e_o_s clause
above */
samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
int thisblock,lastblock=0;
int ret=ov_pcm_seek_page(vf,pos);
if(ret<0)return(ret);
+ _make_decode_ready(vf);
/* discard leading packets we don't need for the lapping of the
position we want; don't decode them */
int ret=ogg_stream_packetpeek(&vf->os,&op);
if(ret>0){
thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+ if(thisblock<0)thisblock=0; /* non audio packet */
if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
-
+
if(vf->pcm_offset+((thisblock+
vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
-
+
+ /* remove the packet from packet queue and track its granulepos */
ogg_stream_packetout(&vf->os,NULL);
+ vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with
+ only tracking, no
+ pcm_decode */
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
-
/* end of logical stream case is hard, especially with exact
- length positioning. */
-
+ length positioning. */
+
if(op.granulepos>-1){
int i;
/* always believe the stream markers */
for(i=0;i<vf->current_link;i++)
vf->pcm_offset+=vf->pcmlengths[i];
}
-
+
lastblock=thisblock;
-
+
}else{
if(ret<0 && ret!=OV_HOLE)break;
ogg_stream_init(&vf->os,vf->current_serialno);
ogg_stream_reset(&vf->os);
vf->ready_state=STREAMSET;
+ _make_decode_ready(vf);
lastblock=0;
}
+
ogg_stream_pagein(&vf->os,&og);
}
}
/* discard samples until we reach the desired position. Crossing a
logical bitstream boundary with abandon is OK. */
- _make_decode_ready(vf);
while(vf->pcm_offset<pos){
float **pcm;
long target=pos-vf->pcm_offset;
vf->pcm_offset+=samples;
if(samples<target)
- if(_process_packet(vf,1)<=0)
+ if(_fetch_and_process_packet(vf,NULL,1)<=0)
vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
}
return 0;
/* suck in another packet */
{
- int ret=_process_packet(vf,1);
+ int ret=_fetch_and_process_packet(vf,NULL,1);
if(ret==OV_EOF)return(0);
if(ret<=0)return(ret);
}
/* suck in another packet */
{
- int ret=_process_packet(vf,1);
+ int ret=_fetch_and_process_packet(vf,NULL,1);
if(ret==OV_EOF)return(0);
if(ret<=0)return(ret);
}