bugfixes, vorbisfile API tweaks/additions
authorMonty <xiphmont@xiph.org>
Fri, 5 Nov 1999 05:25:20 +0000 (05:25 +0000)
committerMonty <xiphmont@xiph.org>
Fri, 5 Nov 1999 05:25:20 +0000 (05:25 +0000)
Monty

svn path=/trunk/vorbis/; revision=162

lib/chaining_example.c
lib/codec.h
lib/info.c
lib/modes.h
lib/vorbisfile.c
lib/vorbisfile.h

index 24f9b97..b310266 100644 (file)
@@ -47,8 +47,8 @@ int main(){
     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));
   }
   
index c6df51a..5099da7 100644 (file)
@@ -14,7 +14,7 @@
  function: codec headers
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Oct 22 1999
+ last modification date: Nov 04 1999
 
  ********************************************************************/
 
@@ -105,9 +105,28 @@ typedef struct vorbis_info{
   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];
index d15d95c..d8cbec5 100644 (file)
@@ -14,7 +14,7 @@
  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));
 }
@@ -39,7 +48,7 @@ int vorbis_info_modeset(vorbis_info *vi, int mode){
   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);
 }
@@ -102,17 +111,24 @@ int vorbis_info_headerin(vorbis_info *vi,ogg_packet *op){
        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:
@@ -186,15 +202,20 @@ int vorbis_info_headerout(vorbis_info *vi,
 
   _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);
index 42f99b7..d39c837 100644 (file)
@@ -32,8 +32,10 @@ double threshhold_points[THRESH_POINTS]=
 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 */
index f996a58..2b7304a 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <math.h>
 #include "codec.h"
 #include "vorbisfile.h"
 
@@ -218,21 +219,18 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,long *serialno){
       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;
       }
   }
@@ -253,6 +251,7 @@ static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first){
   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));
   
@@ -276,7 +275,9 @@ static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first){
                                      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,
@@ -317,7 +318,7 @@ static int _open_seekable(OggVorbis_File *vf){
   
   /* 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.
@@ -488,6 +489,7 @@ int ov_clear(OggVorbis_File *vf){
        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);
@@ -507,7 +509,7 @@ int ov_clear(OggVorbis_File *vf){
 */
 
 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));
@@ -554,13 +556,64 @@ long ov_seekable(OggVorbis_File *vf){
   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++)
@@ -576,8 +629,8 @@ long ov_raw_total(OggVorbis_File *vf,int 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++)
@@ -593,8 +646,8 @@ size64 ov_pcm_total(OggVorbis_File *vf,int 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++)
@@ -614,7 +667,6 @@ double ov_time_total(OggVorbis_File *vf,int 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;
@@ -672,7 +724,7 @@ int ov_raw_seek(OggVorbis_File *vf,long pos){
    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 */  
@@ -766,7 +818,7 @@ int ov_pcm_seek(OggVorbis_File *vf,size64 pos){
 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);
 
index 0502de2..506d1ae 100644 (file)
@@ -35,6 +35,7 @@ typedef struct {
      stream appears */
   int              links;
   long             *offsets;
+  long             *dataoffsets;
   long             *serialnos;
   size64           *pcmlengths;
   vorbis_info      *vi;
@@ -55,8 +56,10 @@ typedef struct {
 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);