Add ov_fopen() (like ov_open, but does the fopen within libvorbisfile)
authorMonty <xiphmont@xiph.org>
Mon, 23 Jul 2007 20:17:41 +0000 (20:17 +0000)
committerMonty <xiphmont@xiph.org>
Mon, 23 Jul 2007 20:17:41 +0000 (20:17 +0000)
and extend ov_open_callbacks() mechanism as means of encouraging use
over ov_open().

Use of ov_open() now strongly discouraged under Windows;
ov_open_callbacks(fd,vf,NULL,0,OV_CALLBACKS_NOCLOSE) as a direct
replacement or ov_fopen() as a convenient substitute.

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

examples/seeking_example.c
examples/vorbisfile_example.c
include/vorbis/vorbisfile.h
lib/vorbisfile.c

index ca465ddec5c966ab48e39e854922b37dc1925643..591a4085dff6b5245fe0c40a0118881af0f8eb9a 100644 (file)
@@ -37,29 +37,29 @@ void _verify(OggVorbis_File *ov,
 
   /* verify the raw position, the pcm position and position decode */
   if(val!=-1 && ov_raw_tell(ov)<val){
-    printf("raw position out of tolerance: requested %ld, got %ld\n",
+    fprintf(stderr,"raw position out of tolerance: requested %ld, got %ld\n",
           (long)val,(long)ov_raw_tell(ov));
     exit(1);
   }
   if(pcmval!=-1 && ov_pcm_tell(ov)>pcmval){
-    printf("pcm position out of tolerance: requested %ld, got %ld\n",
+    fprintf(stderr,"pcm position out of tolerance: requested %ld, got %ld\n",
           (long)pcmval,(long)ov_pcm_tell(ov));
     exit(1);
   }
   if(timeval!=-1 && ov_time_tell(ov)>timeval){
-    printf("time position out of tolerance: requested %f, got %f\n",
+    fprintf(stderr,"time position out of tolerance: requested %f, got %f\n",
           timeval,ov_time_tell(ov));
     exit(1);
   }
   pos=ov_pcm_tell(ov);
   if(pos<0 || pos>pcmlength){
-    printf("pcm position out of bounds: got %ld\n",(long)pos);
+    fprintf(stderr,"pcm position out of bounds: got %ld\n",(long)pos);
     exit(1);
   }
   bread=ov_read(ov,buffer,4096,1,1,1,&dummy);
   for(j=0;j<bread;j++){
     if(buffer[j]!=bigassbuffer[j+pos*2]){
-      printf("data position after seek doesn't match pcm position\n");
+      fprintf(stderr,"data position after seek doesn't match pcm position\n");
 
       {
        FILE *f=fopen("a.m","w");
@@ -85,13 +85,12 @@ int main(){
 
 #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
   _setmode( _fileno( stdin ), _O_BINARY );
-  _setmode( _fileno( stdout ), _O_BINARY );
 #endif
 
 
   /* open the file/pipe on stdin */
-  if(ov_open(stdin,&ov,NULL,-1)<0){
-    printf("Could not open input as an OggVorbis file.\n\n");
+  if(ov_open_callbacks(stdin,&ov,NULL,-1,OV_CALLBACKS_NOCLOSE)<0){
+    fprintf(stderr,"Could not open input as an OggVorbis file.\n\n");
     exit(1);
   }
 
@@ -103,7 +102,7 @@ int main(){
     for(i=0;i<ov.links;i++){
       vorbis_info *vi=ov_info(&ov,i);
       if(vi->channels!=2){
-       printf("Sorry; right now seeking_test can only use Vorbis files\n"
+       fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n"
               "that are entirely stereo.\n\n");
        exit(1);
       }
@@ -111,7 +110,6 @@ int main(){
     
     /* because we want to do sample-level verification that the seek
        does what it claimed, decode the entire file into memory */
-    fflush(stdout);
     pcmlength=ov_pcm_total(&ov,-1);
     timelength=ov_time_total(&ov,-1);
     bigassbuffer=malloc(pcmlength*2); /* w00t */
@@ -130,16 +128,15 @@ int main(){
     
     {
       ogg_int64_t length=ov.end;
-      printf("\rtesting raw seeking to random places in %ld bytes....\n",
+      fprintf(stderr,"\rtesting raw seeking to random places in %ld bytes....\n",
             (long)length);
     
       for(i=0;i<1000;i++){
        ogg_int64_t val=(double)rand()/RAND_MAX*length;
-       printf("\r\t%d [raw position %ld]...     ",i,(long)val);
-       fflush(stdout);
+       fprintf(stderr,"\r\t%d [raw position %ld]...     ",i,(long)val);
        ret=ov_raw_seek(&ov,val);
        if(ret<0){
-         printf("seek failed: %d\n",ret);
+         fprintf(stderr,"seek failed: %d\n",ret);
          exit(1);
        }
 
@@ -148,18 +145,17 @@ int main(){
       }
     }
 
-    printf("\r");
+    fprintf(stderr,"\r");
     {
-      printf("testing pcm page seeking to random places in %ld samples....\n",
+      fprintf(stderr,"testing pcm page seeking to random places in %ld samples....\n",
             (long)pcmlength);
     
       for(i=0;i<1000;i++){
        ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength;
-       printf("\r\t%d [pcm position %ld]...     ",i,(long)val);
-       fflush(stdout);
+       fprintf(stderr,"\r\t%d [pcm position %ld]...     ",i,(long)val);
        ret=ov_pcm_seek_page(&ov,val);
        if(ret<0){
-         printf("seek failed: %d\n",ret);
+         fprintf(stderr,"seek failed: %d\n",ret);
          exit(1);
        }
 
@@ -168,22 +164,21 @@ int main(){
       }
     }
     
-    printf("\r");
+    fprintf(stderr,"\r");
     {
-      printf("testing pcm exact seeking to random places in %ld samples....\n",
+      fprintf(stderr,"testing pcm exact seeking to random places in %ld samples....\n",
             (long)pcmlength);
     
       for(i=0;i<1000;i++){
        ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength;
-       printf("\r\t%d [pcm position %ld]...     ",i,(long)val);
-       fflush(stdout);
+       fprintf(stderr,"\r\t%d [pcm position %ld]...     ",i,(long)val);
        ret=ov_pcm_seek(&ov,val);
        if(ret<0){
-         printf("seek failed: %d\n",ret);
+         fprintf(stderr,"seek failed: %d\n",ret);
          exit(1);
        }
        if(ov_pcm_tell(&ov)!=val){
-         printf("Declared position didn't perfectly match request: %ld != %ld\n",
+         fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n",
                 (long)val,(long)ov_pcm_tell(&ov));
          exit(1);
        }
@@ -193,18 +188,17 @@ int main(){
       }
     }
 
-    printf("\r");
+    fprintf(stderr,"\r");
     {
-      printf("testing time page seeking to random places in %f seconds....\n",
+      fprintf(stderr,"testing time page seeking to random places in %f seconds....\n",
             timelength);
     
       for(i=0;i<1000;i++){
        double val=(double)rand()/RAND_MAX*timelength;
-       printf("\r\t%d [time position %f]...     ",i,val);
-       fflush(stdout);
+       fprintf(stderr,"\r\t%d [time position %f]...     ",i,val);
        ret=ov_time_seek_page(&ov,val);
        if(ret<0){
-         printf("seek failed: %d\n",ret);
+         fprintf(stderr,"seek failed: %d\n",ret);
          exit(1);
        }
 
@@ -213,22 +207,21 @@ int main(){
       }
     }
 
-    printf("\r");
+    fprintf(stderr,"\r");
     {
-      printf("testing time exact seeking to random places in %f seconds....\n",
+      fprintf(stderr,"testing time exact seeking to random places in %f seconds....\n",
             timelength);
     
       for(i=0;i<1000;i++){
        double val=(double)rand()/RAND_MAX*timelength;
-       printf("\r\t%d [time position %f]...     ",i,val);
-       fflush(stdout);
+       fprintf(stderr,"\r\t%d [time position %f]...     ",i,val);
        ret=ov_time_seek(&ov,val);
        if(ret<0){
-         printf("seek failed: %d\n",ret);
+         fprintf(stderr,"seek failed: %d\n",ret);
          exit(1);
        }
        if(ov_time_tell(&ov)<val-1 || ov_time_tell(&ov)>val+1){
-         printf("Declared position didn't perfectly match request: %f != %f\n",
+         fprintf(stderr,"Declared position didn't perfectly match request: %f != %f\n",
                 val,ov_time_tell(&ov));
          exit(1);
        }
@@ -238,11 +231,11 @@ int main(){
       }
     }
     
-    printf("\r                                           \nOK.\n\n");
+    fprintf(stderr,"\r                                           \nOK.\n\n");
 
 
   }else{
-    printf("Standard input was not seekable.\n");
+    fprintf(stderr,"Standard input was not seekable.\n");
   }
 
   ov_clear(&ov);
index 36e679e0f3959e5c279e88033e2607068565caf0..1a07010fd0e9834eb5e2bc8c7963e1c645057680 100644 (file)
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: simple example decoder using vorbisfile
- last mod: $Id: vorbisfile_example.c,v 1.10 2002/07/11 06:40:47 xiphmont Exp $
+ last mod: $Id$
 
  ********************************************************************/
 
@@ -44,7 +44,7 @@ int main(){
   _setmode( _fileno( stdout ), _O_BINARY );
 #endif
 
-  if(ov_open(stdin, &vf, NULL, 0) < 0) {
+  if(ov_open_callbacks(stdin, &vf, NULL, 0, OV_CALLBACKS_NOCLOSE) < 0) {
       fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
       exit(1);
   }
index 6592cfe908e0e85f83eb3cc8373f67b7c417885d..bac56298c4b850aec93e0dbffe7668cafca2620d 100644 (file)
@@ -5,7 +5,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
@@ -43,6 +43,44 @@ typedef struct {
   long   (*tell_func)  (void *datasource);
 } ov_callbacks;
 
+/* a few sets of convenient callbacks, especially for use under
+ * Windows where ov_open_callbacks() should always be used instead of
+ * ov_open() to avoid problems with incompatable crt.o version linking
+ * issues. */
+
+static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){
+  if(f==NULL)return(-1);
+  return fseek(f,off,whence);
+}
+
+static ov_callbacks OV_CALLBACKS_DEFAULT = {
+  (size_t (*)(void *, size_t, size_t, void *))  fread,
+  (int (*)(void *, ogg_int64_t, int))           _ov_header_fseek_wrap,
+  (int (*)(void *))                             fclose,
+  (long (*)(void *))                            ftell
+};
+
+static ov_callbacks OV_CALLBACKS_NOCLOSE = {
+  (size_t (*)(void *, size_t, size_t, void *))  fread,
+  (int (*)(void *, ogg_int64_t, int))           _ov_header_fseek_wrap,
+  (int (*)(void *))                             NULL,
+  (long (*)(void *))                            ftell
+};
+
+static ov_callbacks OV_CALLBACKS_STREAMONLY = {
+  (size_t (*)(void *, size_t, size_t, void *))  fread,
+  (int (*)(void *, ogg_int64_t, int))           NULL,
+  (int (*)(void *))                             fclose,
+  (long (*)(void *))                            NULL
+};
+
+static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = {
+  (size_t (*)(void *, size_t, size_t, void *))  fread,
+  (int (*)(void *, ogg_int64_t, int))           NULL,
+  (int (*)(void *))                             NULL,
+  (long (*)(void *))                            NULL
+};
+
 #define  NOTOPEN   0
 #define  PARTOPEN  1
 #define  OPENED    2
@@ -88,6 +126,7 @@ typedef struct OggVorbis_File {
 
 
 extern int ov_clear(OggVorbis_File *vf);
+extern int ov_fopen(char *path,OggVorbis_File *vf);
 extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
 extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
                char *initial, long ibytes, ov_callbacks callbacks);
index f5710e8080b0f0ca892c7211f19b36e98427e961..e631aaeec2817cf28e692c0c0000cf44e2deba69 100644 (file)
@@ -5,7 +5,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
@@ -62,6 +62,7 @@
 
 static long _get_data(OggVorbis_File *vf){
   errno=0;
+  if(!(vf->callbacks.read_func))return(-1);
   if(vf->datasource){
     char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
     long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
@@ -75,7 +76,8 @@ static long _get_data(OggVorbis_File *vf){
 /* save a tiny smidge of verbosity to make the code more readable */
 static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
   if(vf->datasource){ 
-    if((vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
+    if(!(vf->callbacks.seek_func)||
+       (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
       return OV_EREAD;
     vf->offset=offset;
     ogg_sync_reset(&vf->oy);
@@ -551,8 +553,12 @@ static int _open_seekable2(OggVorbis_File *vf){
   /* we're partially open and have a first link header state in
      storage in vf */
   /* we can seek, so set out learning all about this file */
-  (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
-  vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
+  if(vf->callbacks.seek_func){
+    (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
+    vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
+  }else{
+    vf->offset=vf->end=-1;
+  }
 
   /* If seek_func is implemented, tell_func must also be implemented */
   if(vf->end==-1) return(OV_EINVAL);
@@ -796,7 +802,7 @@ static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
 
 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
                     long ibytes, ov_callbacks callbacks){
-  int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
+  int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
   int ret;
   
   memset(vf,0,sizeof(*vf));
@@ -873,7 +879,8 @@ int ov_clear(OggVorbis_File *vf){
     if(vf->serialnos)_ogg_free(vf->serialnos);
     if(vf->offsets)_ogg_free(vf->offsets);
     ogg_sync_clear(&vf->oy);
-    if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
+    if(vf->datasource && vf->callbacks.close_func)
+      (vf->callbacks.close_func)(vf->datasource);
     memset(vf,0,sizeof(*vf));
   }
 #ifdef DEBUG_LEAKS
@@ -907,6 +914,17 @@ int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
 
   return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
 }
+
+int ov_fopen(char *path,OggVorbis_File *vf){
+  int ret;
+  FILE *f = fopen(path,"rb");
+  if(!f) return -1;
+
+  ret = ov_open(f,vf,NULL,0);
+  if(ret) fclose(f);
+  return ret;
+}
+
  
 /* cheap hack for game usage where downsampling is desirable; there's
    no need for SRC as we can just do it cheaply in libvorbis. */
@@ -1130,7 +1148,7 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
   vorbis_synthesis_restart(&vf->vd);
     
   ret=_seek_helper(vf,pos);
-  if(ret)return(ret);
+  if(ret)goto seek_error;
 
   /* we need to make sure the pcm_offset is set, but we don't want to
      advance the raw cursor past good packets just to get to the first