[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