vorbis_info *vi=ov_info(&ov,i);
printf("\tlogical bitstream section %d information:\n",i+1);
printf("\t\t%ldHz %d channels serial number=%ld\n",
- vi->rate,vi->channels,ov.serialnos[i]);
- printf("\t\tcompressed length: %ldbytes ",ov_raw_total(&ov,i));
+ vi->rate,vi->channels,ov_serialnumber(&ov,i));
+ printf("\t\tcompressed length: %ld bytes ",ov_raw_total(&ov,i));
printf(" play time: %lds\n",(long)ov_time_total(&ov,i));
}
function: codec headers
author: Monty <xiphmont@mit.edu>
modifications by: Monty
- last modification date: Oct 22 1999
+ last modification date: Nov 04 1999
********************************************************************/
long rate;
int version;
+ /* The below bitrate declarations are *hints*.
+ Combinations of the three values carry the following implications:
+
+ all three set to the same value:
+ implies a fixed rate bitstream
+ only nominal set:
+ implies a VBR stream that averages the nominal bitrate. No hard
+ upper/lower limit
+ upper and or lower set:
+ implies a VBR bitstream that obeys the bitrate limits. nominal
+ may also be set to give a nominal rate.
+ none set:
+ the coder does not care to speculate.
+ */
+
+ long bitrate_upper;
+ long bitrate_nominal;
+ long bitrate_lower;
+
char **user_comments;
int comments;
- char *vendor;
+ char *vendor;
int blocksize[2];
int floororder[2];
function: maintain the info structure, info <-> header packets
author: Monty <xiphmont@mit.edu>
modifications by: Monty
- last modification date: Oct 22 1999
+ last modification date: Nov 04 1999
********************************************************************/
#include "modes.h"
#include "bitwise.h"
+static int ilog2(unsigned int v){
+ int ret=0;
+ while(v>1){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
void vorbis_info_init(vorbis_info *vi){
memset(vi,0,sizeof(vorbis_info));
}
memcpy(vi,&(predef_modes[mode]),sizeof(vorbis_info));
vi->threshhold_points=threshhold_points;
vi->user_comments=calloc(1,sizeof(char *));
- vi->vendor=strdup("Xiphophorus libVorbis I 19991022");
+ vi->vendor=strdup("Xiphophorus libVorbis I 19991104");
return(0);
}
if(_oggpack_read(&opb,32)!=0){
return(-1);
}
- vi->channels=_oggpack_read(&opb,32);
+ vi->channels=_oggpack_read(&opb,8);
vi->rate=_oggpack_read(&opb,32);
- vi->blocksize[0]=_oggpack_read(&opb,32);
- vi->blocksize[1]=_oggpack_read(&opb,32);
+ vi->bitrate_upper=_oggpack_read(&opb,32);
+ vi->bitrate_nominal=_oggpack_read(&opb,32);
+ vi->bitrate_lower=_oggpack_read(&opb,32);
+
+ vi->blocksize[0]=1<<_oggpack_read(&opb,4);
+ vi->blocksize[1]=1<<_oggpack_read(&opb,4);
vi->floororder[0]=_oggpack_read(&opb,8);
vi->floororder[1]=_oggpack_read(&opb,8);
vi->flooroctaves[0]=_oggpack_read(&opb,8);
vi->flooroctaves[1]=_oggpack_read(&opb,8);
- vi->floorch=_oggpack_read(&opb,16);
+ vi->floorch=_oggpack_read(&opb,8);
+
+ if(vi->rate<1)return(-1);
+ if(vi->floorch<1 || vi->floorch>vi->channels)return(-1);
return(0);
case 0x81:
_oggpack_write(&opb,0x00,32);
- _oggpack_write(&opb,vi->channels,32);
+ _oggpack_write(&opb,vi->channels,8);
_oggpack_write(&opb,vi->rate,32);
- _oggpack_write(&opb,vi->blocksize[0],32);
- _oggpack_write(&opb,vi->blocksize[1],32);
+
+ _oggpack_write(&opb,vi->bitrate_upper,32);
+ _oggpack_write(&opb,vi->bitrate_nominal,32);
+ _oggpack_write(&opb,vi->bitrate_lower,32);
+
+ _oggpack_write(&opb,ilog2(vi->blocksize[0]),4);
+ _oggpack_write(&opb,ilog2(vi->blocksize[1]),4);
_oggpack_write(&opb,vi->floororder[0],8);
_oggpack_write(&opb,vi->floororder[1],8);
_oggpack_write(&opb,vi->flooroctaves[0],8);
_oggpack_write(&opb,vi->flooroctaves[1],8);
- _oggpack_write(&opb,vi->floorch,16);
+ _oggpack_write(&opb,vi->floorch,8);
/* build the packet */
if(vi->header)free(vi->header);
vorbis_info predef_modes[]={
/* CD quality stereo, no channel coupling */
- /* channels, sample rate, dummy, dummy, dummy, dummy */
- { 2, 44100, 0, NULL, 0, NULL,
+ /* channels, sample rate, upperkbps, nominalkbps, lowerkbps */
+ { 2, 44100, 0,0,0,
+ /* dummy, dummy, dummy, dummy */
+ 0, NULL, 0, NULL,
/* smallblock, largeblock, LPC order (small, large) */
{512, 4096}, {16,16},
/* spectral octaves (small, large), spectral channels */
#include <stdlib.h>
#include <stdio.h>
+#include <math.h>
#include "codec.h"
#include "vorbisfile.h"
int result=ogg_stream_packetout(&vf->os,&op);
if(result==0)break;
if(result==-1){
- fprintf(stderr,"Corrupt header in logical bitstream. "
- "Exiting.\n");
+ fprintf(stderr,"Corrupt header in logical bitstream.\n");
goto bail_header;
}
if(vorbis_info_headerin(vi,&op)){
- fprintf(stderr,"Illegal header in logical bitstream. "
- "Exiting.\n");
+ fprintf(stderr,"Illegal header in logical bitstream.\n");
goto bail_header;
}
i++;
}
if(i<3)
if(_get_next_page(vf,&og,1)<0){
- fprintf(stderr,"Missing header in logical bitstream. "
- "Exiting.\n");
+ fprintf(stderr,"Missing header in logical bitstream.\n");
goto bail_header;
}
}
int i,ret;
vf->vi=malloc(vf->links*sizeof(vorbis_info));
+ vf->dataoffsets=malloc(vf->links*sizeof(long));
vf->pcmlengths=malloc(vf->links*sizeof(size64));
vf->serialnos=malloc(vf->links*sizeof(long));
be called in a non-seekable stream
(in which case, we need to preserve
the stream local storage) */
- }
+ vf->dataoffsets[i]=-1;
+ }else
+ vf->dataoffsets[i]=vf->offset;
}
/* get the serial number and PCM length of this link. To do this,
/* we can seek, so set out learning all about this file */
vf->seekable=1;
- fseek(vf->f,0,SEEK_END); /* Yes, I know I used lseek earlier. */
+ fseek(vf->f,0,SEEK_END);
vf->offset=vf->end=ftell(vf->f);
/* We get the offset for the last page of the physical bitstream.
vorbis_info_clear(vf->vi+i);
free(vf->vi);
}
+ if(vf->dataoffsets)free(vf->dataoffsets);
if(vf->pcmlengths)free(vf->pcmlengths);
if(vf->serialnos)free(vf->serialnos);
if(vf->offsets)free(vf->offsets);
*/
int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
- long offset=lseek(fileno(f),0,SEEK_CUR);
+ long offset=fseek(f,0,SEEK_CUR);
int ret;
memset(vf,0,sizeof(OggVorbis_File));
return vf->seekable;
}
+/* returns the bitrate for a given logical bitstream or the entire
+ physical bitstream. If the file is open for random access, it will
+ find the *actual* average bitrate. If the file is streaming, it
+ returns the nominal bitrate (if set) else the average of the
+ upper/lower bounds (if set) else -1 (unset).
+
+ If you want the actual bitrate field settings, get them from the
+ vorbis_info structs */
+
+long ov_bitrate(OggVorbis_File *vf,int i){
+ if(i>=vf->links)return(-1);
+ if(!vf->seekable)return(ov_bitrate(vf,0));
+ if(i<0){
+ size64 bits;
+ int i;
+ for(i=0;i<vf->links;i++)
+ bits+=vf->offsets[i+1]-vf->dataoffsets[i];
+ return(rint(bits/ov_time_total(vf,-1)));
+ }else{
+ if(vf->seekable){
+ /* return the actual bitrate */
+ return(rint((vf->offsets[i+1]-vf->dataoffsets[i])/ov_time_total(vf,i)));
+ }else{
+ /* return nominal if set */
+ if(vf->vi[i].bitrate_nominal>0){
+ return vf->vi[i].bitrate_nominal;
+ }else{
+ if(vf->vi[i].bitrate_upper>0){
+ if(vf->vi[i].bitrate_lower>0){
+ return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
+ }else{
+ return vf->vi[i].bitrate_upper;
+ }
+ }
+ return(-1);
+ }
+ }
+ }
+}
+
+/* Guess */
+long ov_serialnumber(OggVorbis_File *vf,int i){
+ if(i>=vf->links)return(-1);
+ if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
+ if(i<0){
+ return(vf->current_serialno);
+ }else{
+ return(vf->serialnos[i]);
+ }
+}
+
/* returns: total raw (compressed) length of content if i==-1
raw (compressed) length of that logical bitstream for i==0 to n
-1 if the stream is not seekable (we can't know the length)
*/
long ov_raw_total(OggVorbis_File *vf,int i){
- if(!vf->seekable)return(-1);
- if(i<0 || i>=vf->links){
+ if(!vf->seekable || i>=vf->links)return(-1);
+ if(i<0){
long acc=0;
int i;
for(i=0;i<vf->links;i++)
-1 if the stream is not seekable (we can't know the length)
*/
size64 ov_pcm_total(OggVorbis_File *vf,int i){
- if(!vf->seekable)return(-1);
- if(i<0 || i>=vf->links){
+ if(!vf->seekable || i>=vf->links)return(-1);
+ if(i<0){
size64 acc=0;
int i;
for(i=0;i<vf->links;i++)
-1 if the stream is not seekable (we can't know the length)
*/
double ov_time_total(OggVorbis_File *vf,int i){
- if(!vf->seekable)return(-1);
- if(i<0 || i>=vf->links){
+ if(!vf->seekable || i>=vf->links)return(-1);
+ if(i<0){
double acc=0;
int i;
for(i=0;i<vf->links;i++)
returns zero on success, nonzero on failure */
int ov_raw_seek(OggVorbis_File *vf,long pos){
- int link;
if(!vf->seekable)return(-1); /* don't dump machine if we can't seek */
if(pos<0 || pos>vf->offsets[vf->links])goto seek_error;
returns zero on success, nonzero on failure */
int ov_pcm_seek(OggVorbis_File *vf,size64 pos){
- int i,link=-1;
+ int link=-1;
size64 total=ov_pcm_total(vf,-1);
if(!vf->seekable)return(-1); /* don't dump machine if we can't seek */
int ov_time_seek(OggVorbis_File *vf,double seconds){
/* translate time to PCM position and call ov_pcm_seek */
- int i,link=-1;
+ int link=-1;
size64 pcm_total=ov_pcm_total(vf,-1);
double time_total=ov_time_total(vf,-1);
stream appears */
int links;
long *offsets;
+ long *dataoffsets;
long *serialnos;
size64 *pcmlengths;
vorbis_info *vi;
extern int ov_clear(OggVorbis_File *vf);
extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
+extern long ov_bitrate(OggVorbis_File *vf,int i);
extern long ov_streams(OggVorbis_File *vf);
extern long ov_seekable(OggVorbis_File *vf);
+extern long ov_serialnumber(OggVorbis_File *vf,int i);
extern long ov_raw_total(OggVorbis_File *vf,int i);
extern size64 ov_pcm_total(OggVorbis_File *vf,int i);