[xiph-cvs] cvs commit: vorbose/src codebook.c codec.h info.c vorbose.c
Monty
xiphmont at xiph.org
Tue Jul 22 01:24:43 PDT 2003
xiphmont 03/07/22 04:24:43
Added: src codebook.c codec.h info.c vorbose.c
Log:
Incremental checkin to avoid loss
Revision Changes Path
1.1 vorbose/src/codebook.c
Index: codebook.c
===================================================================
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: basic codebook pack/unpack/code/decode operations
********************************************************************/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ogg2/ogg.h>
#include "codec.h"
extern int codebook_p;
extern int headerinfo_p;
extern int warn_p;
/**** pack/unpack helpers ******************************************/
int _ilog(long v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
#define VQ_FEXP 10
#define VQ_FMAN 21
#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
float _float32_unpack(long unsigned val){
double mant=val&0x1fffff;
int sign=val&0x80000000;
long exp =(val&0x7fe00000L)>>VQ_FMAN;
if(sign)mant= -mant;
return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS));
}
/* given a list of word lengths, number of used entries, and byte
width of a leaf, generate the decode table */
static int _make_words(char *l,
codebook *b){
long i,j,count=0;
long top=0;
unsigned long marker[33];
b->dec_table=malloc((b->used_entries*2+1)*sizeof(*b->dec_table));
if(b->entries<2){
b->dec_table[0]=0x80000000;
}else{
memset(marker,0,sizeof(marker));
for(i=0;i<b->entries;i++){
long length=l[i];
if(length){
unsigned long entry=marker[length];
long chase=0;
if(count && !entry){
if(codebook_p || headerinfo_p || warn_p)
printf("WARN codebk: Malformed [overpopulated] Huffman tree.\n"
" Codebook is invalid.\n\n");
return -1; /* overpopulated tree! */
}
/* chase the tree as far as it's already populated, fill in past */
for(j=0;j<length-1;j++){
ogg_int16_t bit=(entry>>(length-j-1))&1;
if(chase>=top){
top++;
b->dec_table[chase*2]=top;
b->dec_table[chase*2+1]=0;
}else
if(!b->dec_table[chase*2+bit])
b->dec_table[chase*2+bit]=top;
chase=b->dec_table[chase*2+bit];
}
{
ogg_int16_t bit=(entry>>(length-j-1))&1;
if(chase>=top){
top++;
b->dec_table[chase*2+1]=0;
}
b->dec_table[chase*2+bit]= i | 0x80000000;
}
/* Look to see if the next shorter marker points to the node
above. if so, update it and repeat. */
for(j=length;j>0;j--){
if(marker[j]&1){
marker[j]=marker[j-1]<<1;
break;
}
marker[j]++;
}
/* prune the tree; the implicit invariant says all the longer
markers were dangling from our just-taken node. Dangle them
from our *new* node. */
for(j=length+1;j<33;j++)
if((marker[j]>>1) == entry){
entry=marker[j];
marker[j]=marker[j-1]<<1;
}else
break;
}
}
}
return 0;
}
long _book_maptype1_quantvals(codebook *b){
/* get us a starting hint, we'll polish it below */
int bits=_ilog(b->entries);
long vals=b->entries>>((bits-1)*(b->dim-1)/b->dim);
while(1){
long acc=1;
long acc1=1;
int i;
for(i=0;i<b->dim;i++){
acc*=vals;
acc1*=vals+1;
}
if(acc<=b->entries && acc1>b->entries){
return(vals);
}else{
if(acc>b->entries){
vals--;
}else{
vals++;
}
}
}
}
int vorbis_book_unpack(oggpack_buffer *opb,codebook *s){
char *lengthlist=0;
long quantvals=0;
long i,j;
unsigned long maptype;
unsigned long ret;
memset(s,0,sizeof(*s));
oggpack_read(opb,24,&ret);
if(oggpack_eop(opb))goto eop;
if(ret!=0x564342 && (warn_p || codebook_p || headerinfo_p)){
printf("WARN codebk: Sync sequence (0x%lx) incorrect (!=0x564342)\n"
" Corrupt codebook.\n",ret);
goto err;
}
/* first the basic parameters */
oggpack_read(opb,16,&ret);
s->dim=ret;
oggpack_read(opb,24,&ret);
s->entries=ret;
/* codeword ordering.... length ordered or unordered? */
oggpack_read(opb,1,&ret);
if(oggpack_eop(opb))goto eop;
switch(ret){
case 0:
/* unordered */
lengthlist=alloca(sizeof(*lengthlist)*s->entries);
/* allocated but unused entries? */
if(oggpack_read1(opb)){
/* yes, unused entries */
for(i=0;i<s->entries;i++){
if(oggpack_read1(opb)){
unsigned long num;
oggpack_read(opb,5,&num);
if(oggpack_eop(opb))goto eop;
lengthlist[i]=num+1;
s->used_entries++;
}else
lengthlist[i]=0;
}
if(codebook_p){
printf(" Entry encoding : 0,1 (Unordered, sparse)\n");
printf(" Entries : %d total (%d used)\n",
s->entries,s->used_entries);
}
}else{
/* all entries used; no tagging */
s->used_entries=s->entries;
for(i=0;i<s->entries;i++){
unsigned long num;
oggpack_read(opb,5,&num);
if(oggpack_eop(opb))goto eop;
lengthlist[i]=num+1;
}
if(codebook_p){
printf(" Entry encoding : 0,0 (Unordered, fully populated)\n");
printf(" Entries : %d\n",
s->entries);
}
}
break;
case 1:
/* ordered */
{
unsigned long length;
oggpack_read(opb,5,&length);
length++;
s->used_entries=s->entries;
lengthlist=alloca(sizeof(*lengthlist)*s->entries);
for(i=0;i<s->entries;){
unsigned long num;
oggpack_read(opb,_ilog(s->entries-i),&num);
if(oggpack_eop(opb))goto eop;
for(j=0;j<(signed)num && i<s->entries;j++,i++)
lengthlist[i]=length;
length++;
}
if(codebook_p){
printf(" Entry encoding : 1 (Ordered, fully populated)\n");
printf(" Entries : %d\n",
s->entries);
}
}
break;
default:
if(codebook_p)
printf("WARN codebk: Illegal entry encoding %lu. Codebook is corrupt.\n",
ret);
/* EOF */
goto err;
}
<p> /* Do we have a mapping to unpack? */
oggpack_read(opb,4,&maptype);
if(maptype>0){
unsigned long q_min,q_del,q_bits,q_seq;
quantvals=_book_maptype1_quantvals(s);
oggpack_read(opb,32,&q_min);
oggpack_read(opb,32,&q_del);
oggpack_read(opb,4,&q_bits);
q_bits++;
oggpack_read(opb,1,&q_seq);
if(oggpack_eop(opb))goto eop;
if(codebook_p)
printf(" Value mapping : %lu (%s)\n"
" Values : %ld\n"
" Min value : %f (%lx)\n"
" Delta value : %f (%lx)\n"
" Multiplier bits: %lu\n"
" Sequential flag: %s\n"
" ---------------\n",
maptype,(maptype==1?"lattice":"tessellated"),
quantvals,
_float32_unpack(q_min),q_min,
_float32_unpack(q_del),q_del,
q_bits,q_seq?"set":"unset");
for(i=0;i<quantvals;i++)
oggpack_read(opb,q_bits,&ret);
if(oggpack_eop(opb))goto eop;
}else{
if(codebook_p)
printf(" Value mapping : 0 (none)\n"
" ---------------\n");
}
if(_make_words(lengthlist,s)) goto err;
return 0;
eop:
if(codebook_p || headerinfo_p || warn_p)
printf("WARN codebk: Premature EOP while parsing codebook.\n");
err:
if(codebook_p || headerinfo_p || warn_p)
printf("WARN codebk: Invalid codebook; stream is undecodable.\n");
return -1;
}
long vorbis_book_decode(codebook *book, oggpack_buffer *b){
unsigned long chase=0;
int read=32;
unsigned long lok;
long i;
int eop=oggpack_look(b,read,&lok);
while(eop && read>1)
eop = oggpack_look(b, --read, &lok);
if(eop<0){
oggpack_adv(b,32); /* make sure to trigger EOP! */
return -1;
}
/* chase the tree with the bits we got */
for(i=0;i<read;i++){
chase=book->dec_table[chase*2+((lok>>i)&1)];
if(chase&0x80000000UL)break;
}
chase&=0x7fffffffUL;
if(i<read){
oggpack_adv(b,i+1);
return chase;
}
oggpack_adv(b,32); /* make sure to trigger EOP! */
return -1;
}
int vorbis_book_clear(codebook *b){
if(b->dec_table)free(b->dec_table);
memset(b,0,sizeof(*b));
return 0;
}
<p><p>1.1 vorbose/src/codec.h
Index: codec.h
===================================================================
typedef struct vorbis_info vorbis_info;
typedef struct{
int order;
long rate;
long barkmap;
int ampbits;
int ampdB;
int numbooks; /* <= 16 */
int books[16];
} vorbis_info_floor0;
#define VIF_POSIT 63
#define VIF_CLASS 16
#define VIF_PARTS 31
typedef struct{
int class_dim; /* 1 to 8 */
int class_subs; /* 0,1,2,3 (bits: 1<<n poss) */
int class_book; /* subs ^ dim entries */
int class_subbook[8]; /* [VIF_CLASS][subs] */
} floor1class;
typedef struct{
floor1class class[VIF_CLASS];
ogg_int16_t partitionclass[VIF_PARTS];
ogg_uint16_t postlist[VIF_POSIT+2];
ogg_int16_t forward_index[VIF_POSIT+2];
ogg_int16_t hineighbor[VIF_POSIT];
ogg_int16_t loneighbor[VIF_POSIT];
ogg_int16_t partitions; /* 0 to 31 */
ogg_int16_t posts;
ogg_int16_t mult; /* 1 2 3 or 4 */
} vorbis_info_floor1;
typedef struct vorbis_info_floor{
int type;
union {
vorbis_info_floor0 floor0;
vorbis_info_floor1 floor1;
} floor;
} vorbis_info_floor;
typedef struct vorbis_info_residue{
int type;
char stagemasks[64];
char stagebooks[64*8];
/* block-partitioned VQ coded straight residue */
long begin;
long end;
int grouping;
int partitions;
int groupbook;
int stages;
} vorbis_info_residue;
typedef struct {
int blockflag;
int mapping;
} vorbis_info_mode;
typedef struct coupling_step{
ogg_uint16_t mag;
ogg_uint16_t ang;
} coupling_step;
typedef struct submap{
ogg_int16_t floor;
ogg_int16_t residue;
} submap;
typedef struct vorbis_info_mapping{
ogg_int16_t submaps;
int chmuxlist[256];
submap submaplist[16];
int coupling_steps;
coupling_step coupling[256];
} vorbis_info_mapping;
typedef struct codebook{
int dim;
int entries;
int used_entries;
ogg_int32_t *dec_table;
} codebook;
truct vorbis_info{
int channels;
int blocksizes[2];
int modes;
int maps;
int floors;
int residues;
int books;
vorbis_info_mode mode_param[64];
vorbis_info_mapping map_param[64];
vorbis_info_floor floor_param[64];
vorbis_info_residue residue_param[64];
codebook book_param[256];
};
extern int vorbis_info_blocksize(vorbis_info *vi,ogg_int16_t zo);
extern int vorbis_info_headerin(vorbis_info *vi,ogg_packet *op);
extern int vorbis_info_clear(vorbis_info *vi);
extern int vorbis_book_clear(codebook *b);
extern int vorbis_book_unpack(oggpack_buffer *b,codebook *c);
extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
<p>extern int floor_info_unpack(vorbis_info *vi,oggpack_buffer *opb,
vorbis_info_floor *fi);
<p><p><p>1.1 vorbose/src/info.c
Index: info.c
===================================================================
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ogg2/ogg.h>
#include "codec.h"
extern int codebook_p;
extern int headerinfo_p;
extern int warn_p;
/* Header packing/unpacking ********************************************/
tatic int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
unsigned long version;
unsigned long channels;
unsigned long rate;
long bitrate_upper;
long bitrate_nominal;
long bitrate_lower;
unsigned long ret;
oggpack_read(opb,32,&version);
oggpack_read(opb,8,&channels);
oggpack_read(opb,32,&rate);
oggpack_read(opb,32,&bitrate_upper);
oggpack_read(opb,32,&bitrate_nominal);
oggpack_read(opb,32,&bitrate_lower);
oggpack_read(opb,4,&ret);
vi->blocksizes[0]=1<<ret;
oggpack_read(opb,4,&ret);
vi->blocksizes[1]=1<<ret;
ret=0;
if(headerinfo_p){
printf("info header: Vorbis identification header parsed:\n"
" Stream version : %lu\n"
" Output channels : %lu\n"
" Output sample rate : %lu Hz\n",
version,channels,rate);
printf(" Bitrate targets : ");
bitrate_lower<=0?printf("unset/"):printf("%ld/",bitrate_lower);
bitrate_nominal<=0?printf("unset/"):printf("%ld/",bitrate_nominal);
bitrate_upper<=0?printf("unset\n"):printf("%ld\n",bitrate_upper);
printf(" Block sizes : %d/%d samples\n\n",
vi->blocksizes[0],vi->blocksizes[1]);
}
if((warn_p || headerinfo_p) && rate<64000 && vi->blocksizes[1]>2048){
printf("WARN header: blocksizes greater than 2048 are limited to\n"
" sample rates over or equal to 64kHz.\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && rate<1){
printf("WARN header: declared sample rate is invalid\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && channels<1){
printf("WARN header: declared number of channels is invalid\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && vi->blocksizes[0]<64){
printf("WARN header: short block sizes less than 64 samples are invalid.\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && vi->blocksizes[1]<vi->blocksizes[0]){
printf("WARN header: long blocks may not be shorter thans hort blocks.\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && vi->blocksizes[1]>8192){
printf("WARN header: long blocks may not exceed 8192 samples.\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && oggpack_eop(opb)){
printf("WARN header: premature end of packet.\n\n");
ret=1;
}
if((warn_p || headerinfo_p) && ret==1)
printf("WARN header: invalid stream declaration; do not decode this stream.\n\n");
return(ret);
}
tatic int _vorbis_unpack_comment(oggpack_buffer *opb){
unsigned long i,j;
unsigned long temp;
unsigned long len;
unsigned long comments;
if(headerinfo_p)
printf("info header: Vorbis comment header parsed:\n");
oggpack_read(opb,32,&len);
if(oggpack_eop(opb))goto err_out;
if(headerinfo_p)
printf(" vendor length : %lu\n",len);
if(headerinfo_p)
printf(" vendor string : \"");
for(i=0;i<len;i++){
oggpack_read(opb,8,&temp);
if(headerinfo_p)
putchar((int)temp);
}
if(headerinfo_p){
putchar('"');
putchar('\n');
}
oggpack_read(opb,32,&comments);
if(oggpack_eop(opb))goto err_out;
if(headerinfo_p)
printf(" total comments : %lu (comments follow)\n\n",
comments);
for(j=0;j<comments;j++){
oggpack_read(opb,32,&len);
if(headerinfo_p)
printf(" comment %lu length: %lu\n",j,len);
if(oggpack_eop(opb))goto err_out;
if(headerinfo_p)
printf(" comment %lu key : \"",j);
for(i=0;i<len;i++){
oggpack_read(opb,8,&temp);
if(oggpack_eop(opb))goto err_out;
if(temp=='='){
i++;
break;
}
if(headerinfo_p)
putchar(temp);
}
if(headerinfo_p)
printf("\"\n comment %lu value : \"",j);
for(;i<len;i++){
oggpack_read(opb,8,&temp);
if(oggpack_eop(opb))goto err_out;
if(headerinfo_p)
putchar(temp);
}
if(headerinfo_p)
printf("\"\n\n");
}
return(0);
err_out:
if(headerinfo_p || warn_p)
printf("\nWARN header: header hit EOP prematurely.\n\n");
return(0);
}
tatic int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
int i;
unsigned long ret;
if(headerinfo_p)
printf("info header: Vorbis I setup header parsed\n\n");
/* codebooks */
oggpack_read(opb,8,&ret);
vi->books=ret+1;
if(headerinfo_p)
printf("info header: Codebooks: %d\n\n",vi->books);
for(i=0;i<vi->books;i++){
if(codebook_p)
printf("info codebk: Parsing codebook %d\n",i);
if(vorbis_book_unpack(opb,vi->book_param+i))goto err_out;
}
if(codebook_p)
printf("\n");
/* time backend settings, not actually used */
oggpack_read(opb,6,&ret);
i=ret;
for(;i>=0;i--){
oggpack_read(opb,16,&ret);
if(ret!=0){
if(headerinfo_p || warn_p)
printf("WARN header: Time %d is an illegal type (%lu).\n\n",
i,ret);
}
}
if(oggpack_eop(opb))goto eop;
/* floor backend settings */
oggpack_read(opb,6,&ret);
vi->floors=ret+1;
if(headerinfo_p)
printf("info header: Floors: %d\n\n",vi->floors);
for(i=0;i<vi->floors;i++){
if(headerinfo_p)
printf("info header: Parsing floor %d\n",i);
if(floor_info_unpack(vi,opb,vi->floor_param+i)){
if(warn_p || headerinfo_p)
printf("WARN header: Invalid floor; Vorbis stream not decodable.\n");
goto err_out;
}
}
if(headerinfo_p)
printf("\n");
#if 0
/* residue backend settings */
oggpack_read(opb,6,&ret);
vi->residues=ret+1;
for(i=0;i<vi->residues;i++)
if(res_unpack(vi->residue_param+i,vi,opb,print))goto err_out;
/* map backend settings */
oggpack_read(opb,6,&ret);
vi->maps=ret+1;
for(i=0;i<vi->maps;i++){
oggpack_read(opb,16,&ret);
if(ret!=0){
if(headerinfo_p || warn_p)
printf("WARN header: Map %d is an illegal type (%lu).\n\n",
i,ret);
goto err_out;
}
if(mapping_info_unpack(vi->map_param+i,vi,opb,print))goto err_out;
}
/* mode settings */
oggpack_read(opb,6,&ret);
vi->modes=ret+1;
for(i=0;i<vi->modes;i++){
oggpack_read(opb,1,&ret);
if(oggpack_eop(opb))goto eop;
vi->mode_param[i].blockflag=ret;
oggpack_read(opb,16,&ret);
if(ret){
if(headerinfo_p || warn_p)
printf("WARN header: Window in map %d is an illegal type (%lu).\n\n",
i,ret);
goto err_out;
}
oggpack_read(opb,16,&ret);
if(ret){
if(headerinfo_p || warn_p)
printf("WARN header: Transform in map %d is an illegal type (%lu).\n\n",
i,ret);
goto err_out;
}
oggpack_read(opb,8,&ret);
vi->mode_param[i].mapping=ret;
if(vi->mode_param[i].mapping>=vi->maps){
if(headerinfo_p || warn_p)
printf("WARN header: Mode %d requests mapping %lu when highest\n"
" numbered mapping is %d.\n\n",
i,ret,vi->maps-1);
goto err_out;
}
}
#endif
if(oggpack_eop(opb))goto eop;
return(0);
eop:
if(headerinfo_p || warn_p)
printf("WARN header: Premature EOP reading setup header.\n\n");
err_out:
return 1;
}
int vorbis_info_headerin(vorbis_info *vi,ogg_packet *op){
oggpack_buffer *opb=alloca(oggpack_buffersize());
if(op){
oggpack_readinit(opb,op->packet);
/* Which of the three types of header is this? */
/* Also verify header-ness, vorbis */
{
unsigned long temp[6];
unsigned long packtype;
int i;
oggpack_read(opb,8,&packtype);
for(i=0;i<6;i++)
oggpack_read(opb,8,temp+i);
if(temp[0]!='v' ||
temp[1]!='o' ||
temp[2]!='r' ||
temp[3]!='b' ||
temp[4]!='i' ||
temp[5]!='s'){
/* not a vorbis header */
if(headerinfo_p || warn_p)
printf("WARN header: Expecting a Vorbis stream header, got\n"
" some other packet type instead. Stream is not\n"
" decodable as Vorbis I.\n\n");
return(-1);
}
switch(packtype){
case 0x01: /* least significant *bit* is read first */
if(!op->b_o_s){
/* Not the initial packet */
if(headerinfo_p || warn_p)
printf("WARN header: Packet identifies itself as an identification header,\n"
" but does not occur on an initial stream page.\n"
" Stream is not decodable as Vorbis I.\n\n");
return(-1);
}
if(vi->blocksizes[1]!=0){
/* previously initialized info header */
if(headerinfo_p || warn_p)
printf("WARN header: Packet identifies itself as an identification header,\n"
" but an identification header has already been parsed.\n"
" Stream is not decodable as Vorbis I.\n\n");
return(-1);
}
return(_vorbis_unpack_info(vi,opb));
case 0x03: /* least significant *bit* is read first */
if(vi->blocksizes[1]==0){
/* um... we didn't get the initial header */
if(headerinfo_p || warn_p)
printf("WARN header: Packet identifies itself as comment header\n"
" but no identification header has been parsed yet.\n"
" Stream is not decodable as Vorbis I.\n\n");
return(-1);
}
return(_vorbis_unpack_comment(opb));
case 0x05: /* least significant *bit* is read first */
if(vi->blocksizes[1]==0){
/* um... we didn;t get the initial header yet */
if(headerinfo_p || warn_p)
printf("WARN header: Packet identifies itself as the setup header\n"
" but no identification header has been parsed yet.\n"
" Stream is not decodable as Vorbis I.\n\n");
return(-1);
}
return(_vorbis_unpack_books(vi,opb));
default:
/* Not a valid vorbis header type */
return(-1);
}
}
}
return(-1);
}
int vorbis_info_clear(vorbis_info *vi){
int i;
for(i=0;i<vi->books;i++)
vorbis_book_clear(vi->book_param+i);
memset(vi,0,sizeof(*vi));
return(0);
}
<p><p>1.1 vorbose/src/vorbose.c
Index: vorbose.c
===================================================================
#define _REENTRANT 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <ogg2/ogg.h>
#include "codec.h"
void usage(FILE *out){
fprintf(out,
"\nVorbose 20030722-1\n"
"Vorbis I header/stream information dump tool\n\n"
"USAGE:\n"
" vorbose [options] < vorbis-stream\n\n"
"OPTIONS:\n"
" -c --codebook-info : parse and dump detailed stream codebooks\n"
" -g --page-info : parse and dump info about each stream page\n"
" -h --help : print this usage message to stdout and exit\n"
" with status zero\n"
" -H --header-info : parse and dump high-level header contents\n"
" and decoder setup\n"
" -p --packet-info : output basic information for each Vorbis\n"
" stream packet\n"
" -s --stream-info : output basic information about Ogg stream\n"
" used as Vorbis container\n"
" -t --truncated-packets : check stream for truncated audio packets\n"
" (truncated packets are perfectly legal)\n"
" -v --verbose : turn on all reports\n"
" -w --warnings : report anything fishy in the stream\n"
"\n"
);
}
const char *optstring = "cgHhpstvw";
truct option options [] = {
{"codebook-info",no_argument,NULL,'c'},
{"page-info",no_argument,NULL,'g'},
{"help",no_argument,NULL,'h'},
{"header-info",no_argument,NULL,'H'},
{"packet-info",no_argument,NULL,'p'},
{"stream-info",no_argument,NULL,'s'},
{"truncated-packets",no_argument,NULL,'t'},
{"verbose",no_argument,NULL,'v'},
{"warnings",no_argument,NULL,'w'},
{NULL,0,NULL,0}
};
tatic ogg_sync_state *oy;
static ogg_stream_state *os;
static ogg_page og;
static ogg_packet op;
static vorbis_info vi;
int codebook_p=0;
int pageinfo_p=0;
int headerinfo_p=0;
int packetinfo_p=0;
int streaminfo_p=0;
int truncpacket_p=0;
int warn_p=0;
int get_data(){
unsigned char *buf;
int ret;
buf = ogg_sync_bufferin(oy,256);
if(!buf){
fprintf(stderr,"ERROR internal: Failed to allocate managed buffer; ogg_sync_buffer() failed.\n");
exit(1);
}
ret=fread(buf,1,256,stdin);
if(ret>0)ogg_sync_wrote(oy,ret);
return ret;
}
void dump_page(ogg_page *og){
oggpack_buffer *opb=alloca(oggpack_buffersize());
unsigned long ret,ret2,flag;
unsigned int i,count=0,postp;
unsigned long lacing[255];
oggpack_readinit(opb,og->header);
/* capture pattern */
oggpack_read(opb,32,&ret);
oggpack_read(opb,8,&ret2);
printf("INFO page: Capture pattern %c%c%c%c, ",
(char)(ret),(char)(ret>>8),(char)(ret>>16),(char)(ret>>24));
/* version */
printf("format version %lu\n",ret2);
/* flags */
oggpack_read(opb,8,&flag);
printf(" Flags: %s%s%s",
(flag&1 ?
"packet continued from previous page"
"\n ":""),
(flag&2 ?
"first page of logical stream"
"\n ":""),
(flag&4 ?
"last page of logical stream"
"\n ":""));
if(!(flag&7))printf("none\n");
/* granpos */
oggpack_read(opb,32,&ret);
oggpack_read(opb,32,&ret2);
printf("\n Granule position: 0x%08lx%08lx\n",ret2,ret);
/* serial number */
oggpack_read(opb,32,&ret);
printf(" Stream serialno : 0x%08lx\n",ret);
/* sequence number */
oggpack_read(opb,32,&ret);
printf(" Sequence number : %ld\n",ret);
/* checksum */
oggpack_read(opb,32,&ret);
printf(" Checksum : 0x%08lx\n",ret);
/* segments (packets) */
oggpack_read(opb,8,&ret);
printf(" Total segments : %ld\n",ret);
/* segment list and packet count */
for(i=0;i<ret;i++){
oggpack_read(opb,8,lacing+i);
postp=1;
if(lacing[i]<255){
count++;
postp=0;
}
}
printf(" Total packets : ");
if(flag&1){
if(count==0){
printf("single incomplete spanning packet");
}else{
if(postp){
printf("%d completed (1 cont), 1 incomplete",count);
}else{
printf("%d completed (1 cont)",count);
}
}
}else{
if(postp){
printf("%d completed, 1 incomplete",count);
}else{
printf("%d completed",count);
}
}
printf("\n (");
for(i=0;i<ret;i++){
if(i%8==0 && i!=0)
printf("\n ");
printf("%3lu",lacing[i]);
if(i+1<ret && (i+1)%8)
printf(", ");
}
printf(")\n\n");
}
int main(int argc,char *argv[]){
int c,long_option_index;
int eof=0;
int vorbiscount=0;
int syncp=1;
/* get options */
while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
switch(c){
case 'c':
codebook_p=1;
break;
case 'g':
pageinfo_p=1;
break;
case 'h':
usage(stdout);
exit(0);
case 'H':
headerinfo_p=1;
break;
case 'p':
packetinfo_p=1;
break;
case 's':
streaminfo_p=1;
break;
case 't':
truncpacket_p=1;
break;
case 'v':
codebook_p=1;
pageinfo_p=1;
headerinfo_p=1;
packetinfo_p=1;
streaminfo_p=1;
truncpacket_p=1;
warn_p=1;
break;
case 'w':
warn_p=1;
break;
default:
usage(stderr);
exit(1);
}
}
/* set up sync */
oy=ogg_sync_create();
os=ogg_stream_create(0);
<p> while(!eof){
long ret;
long garbagecounter=0;
long pagecounter=0;
long packetcounter=0;
int initialphase=0;
memset(&vi,0,sizeof(vi));
/* packet parsing loop */
while(1){
/* is there a packet available? */
if(ogg_stream_packetout(os,&op)>0){
/* yes, process it */
if(packetcounter<3){
/* header packet */
ret=vorbis_info_headerin(&vi,&op);
if(ret){
switch(packetcounter){
case 0: /* initial header packet */
if((streaminfo_p || warn_p || headerinfo_p) && syncp)
printf("WARN stream: page did not contain a valid Vorbis I "
"identification\n"
" header. Stream is not decodable as "
"Vorbis I.\n\n");
break;
case 1:
if((streaminfo_p || warn_p || headerinfo_p) && syncp)
printf("WARN stream: next packet is not a valid Vorbis I "
"comment header as expected.\n\n");
break;
case 2:
if((streaminfo_p || warn_p || headerinfo_p) && syncp)
printf("WARN stream: next packet is not a valid Vorbis I "
"setup header as expected.\n\n");
break;
}
syncp=0;
}else{
syncp=1;
packetcounter++;
if(packetcounter==3){
if(streaminfo_p || headerinfo_p)
printf("info stream: Vorbis I header triad parsed successfully.\n\n");
vorbiscount++;
}
}
}else{
/* audio packet */
<p> packetcounter++;
}
continue;
}
/* is there a page available? */
ret=ogg_sync_pageseek(oy,&og);
if(ret<0){
garbagecounter-=ret;
}
if(ret>0){
/* Garbage between pages? */
if(garbagecounter){
if(streaminfo_p || warn_p || pageinfo_p)
fprintf(stdout,"WARN stream: %ld bytes of garbage before page %ld\n\n",
garbagecounter,pagecounter);
garbagecounter=0;
}
if(initialphase && !ogg_page_bos(&og)){
/* initial header pages phase has ended */
if(streaminfo_p || headerinfo_p){
printf("info stream: All identification header pages parsed.\n"
" %d logical streams muxed in this link.\n\n",
initialphase);
if(initialphase>1 && (warn_p || streaminfo_p))
printf("WARN stream: A 'Vorbis I audio stream' must contain uninterleaved\n"
" Vorbis I logical streams only. This is a legal\n"
" multimedia Ogg stream, but not a Vorbis I audio\n"
" stream.\n\n");
}
initialphase=0;
}
if(pageinfo_p)dump_page(&og);
<p> /* is this a stream transition? */
if(ogg_page_bos(&og) || pagecounter==0){
if(initialphase){
/* we're in a muxed stream, which is illegal for Vorbis I
audio-only, but perfectly legal for Ogg. */
if(!syncp){
/* we've not yet seen the Vorbis header go past; keep trying new streams */
ogg_stream_reset_serialno(os,ogg_page_serialno(&og));
}
}else{
/* first new packet, signals new stream link. Dump the current vorbis stream, if any */
ogg_stream_reset_serialno(os,ogg_page_serialno(&og));
memset(&vi,0,sizeof(vi));
packetcounter=0;
vorbis_info_clear(&vi);
}
initialphase++;
/* got an initial page. Is it beginning of stream? */
if(!ogg_page_bos(&og) && pagecounter==0 && streaminfo_p)
if(warn_p || streaminfo_p)
fprintf(stdout,"WARN stream: first page (0) is not marked beginning of stream.\n\n");
}
ogg_stream_pagein(os,&og);
pagecounter++;
continue;
}
if(get_data()<=0){
eof=1;
break;
}
}
}
if(streaminfo_p)
fprintf(stdout, "\nHit physical end of stream at %ld bytes.\n",
ftell(stdin));
if(vorbiscount==0)
fprintf(stdout,"No logical Vorbis streams found in data.\n");
else
fprintf(stdout,"%d logical Vorbis stream%s found in data.\n",
vorbiscount,(vorbiscount==1?"":"s"));
fprintf(stdout,"Done.\n");
ogg_page_release(&og);
ogg_stream_destroy(os);
ogg_sync_destroy(oy);
return 0;
}
<p><p>--- >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