[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