[xiph-cvs] cvs commit: vorbis-tools/ogginfo ogginfo.1 ogginfo.c

Stan Seibert volsung at xiph.org
Sun Jul 8 19:01:34 PDT 2001



volsung     01/07/08 19:01:34

  Modified:    ogginfo  ogginfo.1 ogginfo.c
  Log:
  Updated ogginfo to test vorbis streams for header corruption, stream
  corruption, and truncation.

Revision  Changes    Path
1.2       +48 -10    vorbis-tools/ogginfo/ogginfo.1

Index: ogginfo.1
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogginfo/ogginfo.1,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ogginfo.1	2001/06/18 03:48:13	1.1
+++ ogginfo.1	2001/07/09 02:01:33	1.2
@@ -1,7 +1,7 @@
 .\" Process this file with
 .\" groff -man -Tascii ogginfo.1
 .\"
-.TH ogg123 1 "June 17, 2001" "" "Vorbis Tools"
+.TH ogginfo 1 "July 8, 2001" "" "Vorbis Tools"
 
 .SH NAME
 ogginfo \- gives information about Ogg files.
@@ -22,12 +22,21 @@
 .B ogginfo
 cannot accept URLs. 
 .B ogginfo
-will also print the 
-.B length
-of the file in seconds, and the
-.B playtime
-in a humanly-readable MM:SS format.
-
+will also print the following file attributes:
+.RS
+.IP header_integrity
+"pass" if the header is intact, and "fail" if it is corrupted.
+.IP stream_integrity
+"pass" if the stream contains no bad packets or holes (not counting the last 
+packet), and "fail" otherwise.
+.IP file_truncated
+"true" if the last good packet in the stream is not marked as the last packet
+and "false" if the stream is complete.
+.IP length
+Length of of the file in seconds.
+.IP playtime
+Playing time in a humanly-readable MM:SS format.
+.RE
 
 .SH OPTIONS
 None.
@@ -54,6 +63,15 @@
 filename=track14.ogg
 .br
 .B
+header_integrity=pass
+.br
+.B
+stream_integrity=pass
+.br
+.B
+file_truncated=false
+.br
+.B
 title=If I Had $1000000
 .br
 .B
@@ -87,6 +105,15 @@
 filename=track1.ogg
 .br
 .B
+header_integrity=pass
+.br
+.B
+stream_integrity=pass
+.br
+.B
+file_truncated=false
+.br
+.B
 title=The Vorbis Theme
 .br
 .B
@@ -108,6 +135,15 @@
 filename=track2.ogg
 .br
 .B
+header_integrity=pass
+.br
+.B
+stream_integrity=pass
+.br
+.B
+file_truncated=false
+.br
+.B
 title=Being for the Benefit of Mr. Fish
 .br
 .B
@@ -128,10 +164,12 @@
 
 .SH BUGS
 
-The man page is longer than the source.
+.B ogginfo
+only checks the first bitstream in a file.
 
-.SH AUTHOR
+.SH AUTHORS
 
-.TP
 .br
 JAmes Atwill <ogg at linuxstuff.org>
+.br
+Stan Seibert <indigo at aztec.asu.edu>

1.2       +247 -2    vorbis-tools/ogginfo/ogginfo.c

Index: ogginfo.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/ogginfo/ogginfo.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ogginfo.c	2001/06/18 02:24:25	1.1
+++ ogginfo.c	2001/07/09 02:01:33	1.2
@@ -10,10 +10,15 @@
 #include <ao/ao.h>
 
 void doinfo(char *);
+int  dointegritycheck(char *);
+int  test_header(FILE *fp, ogg_sync_state *oy, ogg_stream_state *os,
+		 vorbis_info    *vi,  vorbis_comment  *vc);
+int  test_stream(FILE *fp, ogg_sync_state *oy, ogg_stream_state *os);
 
 int main(int ac,char **av)
 {
   int i;
+  int header_state;
 
   if ( ac < 2 ) {
     fprintf(stderr,"Usage: %s [filename1.ogg] ... [filenameN.ogg]\n",av[0]);
@@ -21,7 +26,10 @@
   }
 
   for(i=1;i!=ac;i++) {
-    doinfo(av[i]);
+    printf("filename=%s\n",av[i]);
+    header_state = dointegritycheck(av[i]);
+    if (header_state == 1)
+      doinfo(av[i]);
   }
   return(0);
   
@@ -53,7 +61,6 @@
     return;
   }
   
-  printf("filename=%s\n",filename);
   vc = ov_comment(&vf,-1);
 
   for (i=0; i < vc->comments; i++) {
@@ -71,3 +78,241 @@
 
   return;
 }
+
+/* Tests the integrity of a vorbis stream.  Returns 1 if the header is good
+   (but not necessarily the rest of the stream) and 0 otherwise.
+   
+   Huge chunks of this function are from decoder_example.c (Copyright
+   1994-2001 Xiphophorus Company). */
+int dointegritycheck(char *filename)
+{
+  int header_state = -1; /* Assume the worst */
+  int stream_state = -1;
+
+  ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
+  ogg_stream_state os; /* take physical pages, weld into a logical
+			  stream of packets */
+  vorbis_info      vi; /* struct that stores all the static vorbis bitstream
+			  settings */
+  vorbis_comment   vc; /* struct that stores all the bitstream user comments */
+  
+  FILE *fp;
+  
+  /********** Decode setup ************/
+
+  fp = fopen(filename,"r");
+  if (!fp) {
+    fprintf(stderr,"Unable to open \"%s\": %s\n",
+	    filename,
+	    strerror(errno));
+    return 0;
+  }
+
+  ogg_sync_init(&oy); /* Now we can read pages */
+  
+  if ( (header_state = test_header(fp, &oy, &os, &vi, &vc)) == 1 ) {
+
+    stream_state = test_stream(fp, &oy, &os);
+  }
+
+  /* Output test results */
+  if (header_state == 1)
+    printf("header_integrity=pass\n");
+  else
+    printf("header_integrity=fail\n");
+
+  if (stream_state >= 0)
+    printf("stream_integrity=pass\n");
+  else
+    printf("stream_integrity=fail\n");
+
+  if (stream_state > 0)
+    printf("file_truncated=false\n");
+  else
+    printf("file_truncated=true\n");
+
+  
+  /* clean up this logical bitstream; before exit we see if we're
+     followed by another [chained] */
+
+  if (header_state == 0) {
+    /* We got far enough to initialize these structures */
+
+    ogg_stream_clear(&os);
+    
+    /* ogg_page and ogg_packet structs always point to storage in
+       libvorbis.  They're never freed or manipulated directly */
+    
+    vorbis_comment_clear(&vc);
+    vorbis_info_clear(&vi);  /* must be called last */
+  }
+
+  /* OK, clean up the framer */
+  ogg_sync_clear(&oy);
+  
+  fclose(fp);
+
+  return header_state > 0 ? 1 : 0;
+}
+
+/* Test the integrity of the stream header.  
+   Return:
+     1 if it is good
+     0 if it is corrupted and os, vi, and vc were initialized
+    -1 if it is corrupted and os, vi, and vc were not initialized 
+       (don't clear them) */
+int test_header (FILE *fp, ogg_sync_state *oy, ogg_stream_state *os,
+		 vorbis_info *vi,  vorbis_comment  *vc)
+{
+  ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
+  ogg_packet       op; /* one raw packet of data for decode */
+  char *buffer;
+  int bytes;
+  int eos=0;
+  int i;
+  
+  /* grab some data at the head of the stream.  We want the first page
+     (which is guaranteed to be small and only contain the Vorbis
+     stream initial header) We need the first page to get the stream
+     serialno. */
+  
+  /* submit a 4k block to libvorbis' Ogg layer */
+  buffer=ogg_sync_buffer(oy,4096);
+  bytes=fread(buffer,1,4096,fp);
+  ogg_sync_wrote(oy,bytes);
+  
+  /* Get the first page. */
+  if(ogg_sync_pageout(oy,&og)!=1){
+    /* error case.  Must not be Vorbis data */
+    return -1;
+  }
+  
+  /* Get the serial number and set up the rest of decode. */
+  /* serialno first; use it to set up a logical stream */
+  ogg_stream_init(os,ogg_page_serialno(&og));
+  
+  /* extract the initial header from the first page and verify that the
+     Ogg bitstream is in fact Vorbis data */
+  
+  /* I handle the initial header first instead of just having the code
+     read all three Vorbis headers at once because reading the initial
+     header is an easy way to identify a Vorbis bitstream and it's
+     useful to see that functionality seperated out. */
+  
+  vorbis_info_init(vi);
+  vorbis_comment_init(vc);
+  if(ogg_stream_pagein(os,&og)<0){ 
+    /* error; stream version mismatch perhaps */
+    return 0;
+  }
+    
+  if(ogg_stream_packetout(os,&op)!=1){ 
+    /* no page? must not be vorbis */
+    return 0;
+  }
+  
+  if(vorbis_synthesis_headerin(vi,vc,&op)<0){ 
+    /* error case; not a vorbis header */
+    return 0;
+  }
+    
+  /* At this point, we're sure we're Vorbis.  We've set up the logical
+     (Ogg) bitstream decoder.  Get the comment and codebook headers and
+     set up the Vorbis decoder */
+  
+  /* The next two packets in order are the comment and codebook headers.
+     They're likely large and may span multiple pages.  Thus we reead
+     and submit data until we get our two pacakets, watching that no
+     pages are missing.  If a page is missing, error out; losing a
+     header page is the only place where missing data is fatal. */
+  
+  i=0;
+  while(i<2){
+    while(i<2){
+      int result=ogg_sync_pageout(oy,&og);
+      if(result==0)break; /* Need more data */
+      /* Don't complain about missing or corrupt data yet.  We'll
+	 catch it at the packet output phase */
+      if(result==1){
+	ogg_stream_pagein(os,&og); /* we can ignore any errors here
+				       as they'll also become apparent
+				       at packetout */
+	while(i<2){
+	  result=ogg_stream_packetout(os,&op);
+	  if(result==0)break;
+	  if(result<0){
+	    /* Uh oh; data at some point was corrupted or missing!
+	       We can't tolerate that in a header. */
+	    return 0;
+	  }
+	  vorbis_synthesis_headerin(vi,vc,&op);
+	  i++;
+	}
+      }
+    }
+
+    /* no harm in not checking before adding more */
+    buffer=ogg_sync_buffer(oy,4096);
+    bytes=fread(buffer,1,4096,fp);
+    if(bytes==0 && i<2){
+      return 0;
+    }
+    ogg_sync_wrote(oy,bytes);
+  }
+  
+  /* If we made it this far, the header must be good. */
+  return 1;
+}
+
+/* Test the integrity of the vorbis stream after the header.
+   Return:
+     >0 if the stream is correct and complete
+     0 if the stream is correct but truncated
+    -1 if the stream is corrupted somewhere in the middle */
+int test_stream (FILE *fp, ogg_sync_state *oy, ogg_stream_state *os)
+{
+  int eos = 0;
+  ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
+  ogg_packet       op; /* one raw packet of data for decode */
+  int bytes;
+  char *buffer;
+
+  /* Just a straight decode loop until end of stream */
+    while(!eos){
+      while(!eos){
+	int result=ogg_sync_pageout(oy,&og);
+	if(result==0)break; /* need more data */
+	if(result<0){ /* missing or corrupt data at this page position */
+	  return -1;
+	}else{
+	  if (ogg_stream_pagein(os,&og) < 0) {
+	    return -1;
+	  }
+
+	  while(1){
+	    result=ogg_stream_packetout(os,&op);
+
+	    if(result==0)break; /* need more data */
+	    if(result<0){ /* missing or corrupt data at this page position */
+	      return -1;
+	    }else{
+	      /* Normally we would do decode here, but we're just checking
+		 packet integrity */
+	    }
+	  }
+	  if(ogg_page_eos(&og))eos=1;
+	}
+      }
+      if(!eos){
+	buffer=ogg_sync_buffer(oy,4096);
+	bytes=fread(buffer,1,4096,fp);
+	ogg_sync_wrote(oy,bytes);
+	if(bytes==0)eos=1;
+      }
+    }
+
+    /* Make sure that the last page is marked as the end-of-stream */
+    return ogg_page_eos(&og);
+}
+
+

--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list