********************************************************************
function: maintain the info structure, info <-> header packets
- last mod: $Id: info.c,v 1.14 2000/01/05 03:10:58 xiphmont Exp $
+ last mod: $Id: info.c,v 1.15 2000/01/19 08:57:55 xiphmont Exp $
********************************************************************/
-/* This fills in a vorbis_info structure with settings from a few
- pre-defined encoding modes. Also handles choosing/blowing in the
- codebook */
+/* general handling of the header and the vorbis_info structure (and
+ substructures) */
#include <stdlib.h>
#include <string.h>
-#include "vorbis/modes.h"
+#include "vorbis/codec.h"
#include "bitwise.h"
+#include "bookinternal.h"
+
+/* these modules were split out only to make this file more readable.
+ I don't want to expose the symbols */
+#include "infomap.c"
+
+/* helpers */
static int ilog2(unsigned int v){
int ret=0;
}
return(ret);
}
-
-void vorbis_info_init(vorbis_info *vi){
- memset(vi,0,sizeof(vorbis_info));
-}
-
-/* one test mode for now; temporary of course */
-int vorbis_info_modeset(vorbis_info *vi, int mode){
- if(mode<0 || mode>predef_mode_max)return(-1);
- /* handle the flat settings first */
- memcpy(vi,&(predef_modes[mode]),sizeof(vorbis_info));
- vi->user_comments=calloc(1,sizeof(char *));
- vi->vendor=strdup("Xiphophorus libVorbis I 19991230");
+static void _v_writestring(oggpack_buffer *o,char *s){
+ while(*s){
+ _oggpack_write(o,*s++,8);
+ }
+}
- return(0);
+static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
+ while(bytes--){
+ *buf++=_oggpack_read(o,8);
+ }
}
-/* convenience function */
+/* convenience functions for the interface */
int vorbis_info_addcomment(vorbis_info *vi,char *comment){
vi->user_comments=realloc(vi->user_comments,
(vi->comments+2)*sizeof(char *));
return(0);
}
-static void _v_writestring(oggpack_buffer *o,char *s){
- while(*s){
- _oggpack_write(o,*s++,8);
+int vorbis_info_addvendor(vorbis_info *vi,char *vendor){
+ if(vi->vendor)free(vi->vendor);
+ vi->vendor=strdup(vendor);
+ return(0);
+}
+
+/* libVorbis expects modes to be submitted in an already valid
+ vorbis_info structure, but also expects some of the elements to be
+ allocated storage. To make this easier, the Vorbis distribution
+ includes a number of modes in static storage as headers. To
+ allocate a copy, run it through vorbis_info_dup */
+
+/* note that due to codebook size, codebooks are not fully duplicated.
+ The info structure (aside from the embedded codebook elements) will
+ be fully dupped */
+
+int vorbis_info_dup(vorbis_info *dest,vorbis_info *source){
+ int i;
+ memcpy(dest,source,sizeof(vorbis_info));
+
+ /* also dup individual pieces that need to be allocated */
+ /* dup user comments (unlikely to have any, but for completeness */
+ if(source->comments>0){
+ dest->user_comments=calloc(source->comments+1,sizeof(char *));
+ for(i=0;i<source->comments;i++)
+ dest->user_comments[i]=strdup(source->user_comments[i]);
+ }
+ /* dup vendor */
+ if(source->vendor)
+ dest->vendor=strdup(source->vendor);
+
+ /* dup mode maps, blockflags and map types */
+ if(source->modes){
+ dest->blockflags=malloc(source->modes*sizeof(int));
+ dest->maptypes=malloc(source->modes*sizeof(int));
+ dest->maplist=calloc(source->modes,sizeof(void *));
+
+ memcpy(dest->blockflags,source->blockflags,sizeof(int)*dest->modes);
+ memcpy(dest->maptypes,source->maptypes,sizeof(int)*dest->modes);
+ for(i=0;i<source->modes;i++){
+ void *dup;
+ if(dest->maptypes[i]<0|| dest->maptypes[i]>=VI_MAPB)goto err_out;
+ if(!(dup=vorbis_map_dup_P[dest->maptypes[i]](source->maplist[i])))
+ goto err_out;
+ dest->maplist[i]=dup;
+ }
+ }
+
+ /* dup (partially) books */
+ if(source->books){
+ dest->booklist=malloc(source->books*sizeof(codebook *));
+ for(i=0;i<source->books;i++){
+ dest->booklist[i]=calloc(1,sizeof(codebook));
+ vorbis_book_dup(dest->booklist[i],source->booklist[i]);
+ }
}
+ /* we do *not* dup local storage */
+ dest->header=NULL;
+ dest->header1=NULL;
+ dest->header2=NULL;
+
+ return(0);
+err_out:
+ vorbis_info_clear(dest);
+ return(-1);
}
-static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
- while(bytes--){
- *buf++=_oggpack_read(o,8);
+void vorbis_info_clear(vorbis_info *vi){
+ int i;
+ if(vi->comments){
+ for(i=0;i<vi->comments;i++)
+ if(vi->user_comments[i])free(vi->user_comments[i]);
+ free(vi->user_comments);
}
+ if(vi->vendor)free(vi->vendor);
+ if(vi->modes){
+ for(i=0;i<vi->modes;i++)
+ if(vi->maptypes[i]>=0 && vi->maptypes[i]<VI_MAPB)
+ vorbis_map_free_P[vi->maptypes[i]](vi->maplist[i]);
+ free(vi->maplist);
+ free(vi->maptypes);
+ free(vi->blockflags);
+ }
+ if(vi->books){
+ for(i=0;i<vi->books;i++){
+ if(vi->booklist[i]){
+ vorbis_book_clear(vi->booklist[i]);
+ free(vi->booklist[i]);
+ }
+ }
+ free(vi->booklist);
+ }
+
+ if(vi->header)free(vi->header);
+ if(vi->header1)free(vi->header1);
+ if(vi->header2)free(vi->header2);
+
+ memset(vi,0,sizeof(vorbis_info));
+}
+
+/* Header packing/unpacking ********************************************/
+
+static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
+ vi->version=_oggpack_read(opb,32);
+ if(vi->version!=0)return(-1);
+
+ vi->channels=_oggpack_read(opb,8);
+ vi->rate=_oggpack_read(opb,32);
+
+ vi->bitrate_upper=_oggpack_read(opb,32);
+ vi->bitrate_nominal=_oggpack_read(opb,32);
+ vi->bitrate_lower=_oggpack_read(opb,32);
+
+ vi->blocksizes[0]=1<<_oggpack_read(opb,4);
+ vi->blocksizes[1]=1<<_oggpack_read(opb,4);
+
+ if(vi->rate<1)goto err_out;
+ if(vi->channels<1)goto err_out;
+ if(vi->blocksizes[0]<8)goto err_out;
+ if(vi->blocksizes[1]<vi->blocksizes[0])
+ goto err_out; /* doubles as EOF check */
+
+ return(0);
+ err_out:
+ vorbis_info_clear(vi);
+ return(-1);
+}
+
+static int _vorbis_unpack_comments(vorbis_info *vi,oggpack_buffer *opb){
+ int i;
+ int vendorlen=_oggpack_read(opb,32);
+ if(vendorlen<0)goto err_out;
+ vi->vendor=calloc(vendorlen+1,1);
+ _v_readstring(opb,vi->vendor,vendorlen);
+ vi->comments=_oggpack_read(opb,32);
+ if(vi->comments<0)goto err_out;
+ vi->user_comments=calloc(vi->comments+1,sizeof(char **));
+
+ for(i=0;i<vi->comments;i++){
+ int len=_oggpack_read(opb,32);
+ if(len<0)goto err_out;
+ vi->user_comments[i]=calloc(len+1,1);
+ _v_readstring(opb,vi->user_comments[i],len);
+ }
+ return(0);
+ err_out:
+ vorbis_info_clear(vi);
+ return(-1);
+}
+
+/* all of the real encoding details are here. The modes, books,
+ everything */
+static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
+ int i;
+
+ vi->modes=_oggpack_read(opb,16);
+ vi->blockflags=malloc(vi->modes*sizeof(int));
+ vi->maptypes=malloc(vi->modes*sizeof(int));
+ vi->maplist=calloc(vi->modes,sizeof(void *));
+
+ for(i=0;i<vi->modes;i++){
+ vi->blockflags[i]=_oggpack_read(opb,1);
+ vi->maptypes[i]=_oggpack_read(opb,8);
+ if(vi->maptypes[i]<0 || vi->maptypes[i]>VI_MAPB)goto err_out;
+ vi->maplist[i]=vorbis_map_unpack_P[vi->maptypes[i]](opb);
+ if(!vi->maplist[i])goto err_out;
+ }
+
+ vi->books=_oggpack_read(opb,16);
+ vi->booklist=calloc(vi->books,sizeof(codebook *));
+ for(i=0;i<vi->books;i++){
+ vi->booklist[i]=calloc(1,sizeof(codebook));
+ if(vorbis_book_unpack(opb,vi->booklist[i]))goto err_out;
+ }
+ return(0);
+err_out:
+ vorbis_info_clear(vi);
+ return(-1);
}
/* The Vorbis header is in three packets; the initial small packet in
with bitstream comments and a third packet that holds the
codebook. */
+/* call before header in, or just to zero out uninitialized mem */
+void vorbis_info_init(vorbis_info *vi){
+ memset(vi,0,sizeof(vorbis_info));
+}
+
int vorbis_info_headerin(vorbis_info *vi,ogg_packet *op){
oggpack_buffer opb;
return(-1);
}
- if(_oggpack_read(&opb,32)!=0){
- return(-1);
- }
- vi->channels=_oggpack_read(&opb,8);
- vi->rate=_oggpack_read(&opb,32);
-
- vi->bitrate_upper=_oggpack_read(&opb,32);
- vi->bitrate_nominal=_oggpack_read(&opb,32);
- vi->bitrate_lower=_oggpack_read(&opb,32);
-
- vi->blocksize[0]=1<<_oggpack_read(&opb,4);
- vi->blocksize[1]=1<<_oggpack_read(&opb,4);
-
- vi->floororder[0]=_oggpack_read(&opb,8);
- vi->floororder[1]=_oggpack_read(&opb,8);
- vi->floormap[0]=_oggpack_read(&opb,16);
- vi->floormap[1]=_oggpack_read(&opb,16);
- vi->floorch=_oggpack_read(&opb,8);
-
- if(vi->rate<1)return(-1);
- if(vi->floorch<1 || vi->floorch>vi->channels)return(-1);
+ return(_vorbis_unpack_info(vi,&opb));
- return(0);
case 0x81:
if(vi->rate==0){
- /* um... we didn;t get the initial header */
+ /* um... we didn't get the initial header */
return(-1);
}
- {
- int vendorlen=_oggpack_read(&opb,32);
- vi->vendor=calloc(vendorlen+1,1);
- _v_readstring(&opb,vi->vendor,vendorlen);
- }
- {
- int i;
- vi->comments=_oggpack_read(&opb,32);
- vi->user_comments=calloc(vi->comments+1,sizeof(char **));
-
- for(i=0;i<vi->comments;i++){
- int len=_oggpack_read(&opb,32);
- vi->user_comments[i]=calloc(len+1,1);
- _v_readstring(&opb,vi->user_comments[i],len);
- }
- }
- return(0);
+ return(_vorbis_unpack_comments(vi,&opb));
+
case 0x82:
- if(vi->rate==0){
- /* um... we didn;t get the initial header */
+ if(vi->rate==0 || vi->vendor==NULL){
+ /* um... we didn;t get the initial header or comments yet */
return(-1);
}
- /* not implemented quite yet */
+ return(_vorbis_unpack_books(vi,&opb));
- return(0);
default:
/* Not a valid vorbis header type */
return(-1);
return(-1);
}
+/* pack side **********************************************************/
+
+static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
+ /* preamble */
+ _v_writestring(opb,"vorbis");
+ _oggpack_write(opb,0x80,8);
+
+ /* basic information about the stream */
+ _oggpack_write(opb,0x00,32);
+ _oggpack_write(opb,vi->channels,8);
+ _oggpack_write(opb,vi->rate,32);
+
+ _oggpack_write(opb,vi->bitrate_upper,32);
+ _oggpack_write(opb,vi->bitrate_nominal,32);
+ _oggpack_write(opb,vi->bitrate_lower,32);
+
+ _oggpack_write(opb,ilog2(vi->blocksizes[0]),4);
+ _oggpack_write(opb,ilog2(vi->blocksizes[1]),4);
+
+ return(0);
+}
+
+static int _vorbis_pack_comments(oggpack_buffer *opb,vorbis_info *vi){
+ char temp[]="Xiphophorus libVorbis I 20000114";
+
+ /* preamble */
+ _v_writestring(opb,"vorbis");
+ _oggpack_write(opb,0x81,8);
+
+ /* vendor */
+ _oggpack_write(opb,strlen(temp),32);
+ _v_writestring(opb,temp);
+
+ /* comments */
+
+ _oggpack_write(opb,vi->comments,32);
+ if(vi->comments){
+ int i;
+ for(i=0;i<vi->comments;i++){
+ if(vi->user_comments[i]){
+ _oggpack_write(opb,strlen(vi->user_comments[i]),32);
+ _v_writestring(opb,vi->user_comments[i]);
+ }else{
+ _oggpack_write(opb,0,32);
+ }
+ }
+ }
+
+ return(0);
+}
+
+static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
+ int i;
+ _v_writestring(opb,"vorbis");
+ _oggpack_write(opb,0x82,8);
+
+ _oggpack_write(opb,vi->modes,16);
+ for(i=0;i<vi->modes;i++){
+ _oggpack_write(opb,vi->blockflags[i],1);
+ _oggpack_write(opb,vi->maptypes[i],8);
+ if(vi->maptypes[i]<0 || vi->maptypes[i]>VI_MAPB)goto err_out;
+ vorbis_map_pack_P[vi->maptypes[i]](opb,vi->maplist[i]);
+ }
+
+ _oggpack_write(opb,vi->books,16);
+ for(i=0;i<vi->books;i++)
+ if(vorbis_book_pack(vi->booklist[i],opb))goto err_out;
+ return(0);
+err_out:
+ return(-1);
+}
+
int vorbis_info_headerout(vorbis_info *vi,
ogg_packet *op,
ogg_packet *op_comm,
ogg_packet *op_code){
oggpack_buffer opb;
- /* initial header:
-
- codec id "vorbis"
- header id 0x80 (byte)
- codec ver (4 octets, lsb first: currently 0x00)
- pcm channels (4 octets, lsb first)
- pcm rate (4 octets, lsb first)
-
- small block (4 octets, lsb first)
- large block (4 octets, lsb first)
- floor order for small block (octet)
- floor order for large block (octet)
- floor octaves for small block (octet)
- floor octaves for large block (octet)
- floorch (4 octets, lsb first)
- */
-
- _oggpack_writeinit(&opb);
- _v_writestring(&opb,"vorbis");
- _oggpack_write(&opb,0x80,8);
-
- _oggpack_write(&opb,0x00,32);
- _oggpack_write(&opb,vi->channels,8);
- _oggpack_write(&opb,vi->rate,32);
+ /* first header packet **********************************************/
- _oggpack_write(&opb,vi->bitrate_upper,32);
- _oggpack_write(&opb,vi->bitrate_nominal,32);
- _oggpack_write(&opb,vi->bitrate_lower,32);
-
- _oggpack_write(&opb,ilog2(vi->blocksize[0]),4);
- _oggpack_write(&opb,ilog2(vi->blocksize[1]),4);
- _oggpack_write(&opb,vi->floororder[0],8);
- _oggpack_write(&opb,vi->floororder[1],8);
- _oggpack_write(&opb,vi->floormap[0],16);
- _oggpack_write(&opb,vi->floormap[1],16);
- _oggpack_write(&opb,vi->floorch,8);
+ _oggpack_writeinit(&opb);
+ if(_vorbis_pack_info(&opb,vi))goto err_out;
/* build the packet */
if(vi->header)free(vi->header);
op->e_o_s=0;
op->frameno=0;
- /* comment header:
- codec id "vorbis"
- header id 0x81 (byte)
- vendor len (4 octets, lsb first)
- vendor and id (n octects as above)
- comments (4 octets, lsb first)
- comment 0 len (4 octets, lsb first)
- comment 0 len (n octets as above)
- ...
- comment n-1 len (4 octets, lsb first)
- comment 0-1 len (n octets as above)
- */
+ /* second header packet (comments) **********************************/
_oggpack_reset(&opb);
_v_writestring(&opb,"vorbis");
_oggpack_write(&opb,0x81,8);
+ if(_vorbis_pack_comments(&opb,vi))goto err_out;
- if(vi->vendor){
- _oggpack_write(&opb,strlen(vi->vendor),32);
- _v_writestring(&opb,vi->vendor);
- }else{
- _oggpack_write(&opb,0,32);
- }
-
- _oggpack_write(&opb,vi->comments,32);
- if(vi->comments){
- int i;
- for(i=0;i<vi->comments;i++){
- if(vi->user_comments[i]){
- _oggpack_write(&opb,strlen(vi->user_comments[i]),32);
- _v_writestring(&opb,vi->user_comments[i]);
- }else{
- _oggpack_write(&opb,0,32);
- }
- }
- }
-
if(vi->header1)free(vi->header1);
vi->header1=malloc(_oggpack_bytes(&opb));
memcpy(vi->header1,opb.buffer,_oggpack_bytes(&opb));
op_comm->e_o_s=0;
op_comm->frameno=0;
- /* codebook header:
- codec id "vorbis"
- header id 0x82 (byte)
- nul so far; not encoded yet */
+ /* third header packet (modes/codebooks) ****************************/
_oggpack_reset(&opb);
_v_writestring(&opb,"vorbis");
_oggpack_write(&opb,0x82,8);
+ if(_vorbis_pack_books(&opb,vi))goto err_out;
if(vi->header2)free(vi->header2);
vi->header2=malloc(_oggpack_bytes(&opb));
op_code->frameno=0;
_oggpack_writeclear(&opb);
-
return(0);
+ err_out:
+ _oggpack_writeclear(&opb);
+ memset(op,0,sizeof(ogg_packet));
+ memset(op_comm,0,sizeof(ogg_packet));
+ memset(op_code,0,sizeof(ogg_packet));
+ return(-1);
}
-void vorbis_info_clear(vorbis_info *vi){
- /* clear the non-flat storage before zeroing */
-
- /* comments */
- if(vi->user_comments){
- char **ptr=vi->user_comments;
- while(*ptr){
- free(*(ptr++));
- }
- free(vi->user_comments);
- }
-
- /* vendor string */
- if(vi->vendor)free(vi->vendor);
-
- /* local encoding storage */
- if(vi->header)free(vi->header);
- if(vi->header1)free(vi->header1);
- if(vi->header2)free(vi->header2);
-
- memset(vi,0,sizeof(vorbis_info));
-}
-
-
--- /dev/null
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: pack/unpack/dup/clear the various channel mapping setups
+ last mod: $Id: infomap.c,v 1.1 2000/01/19 08:57:56 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "vorbis/codec.h"
+#include "bitwise.h"
+#include "bookinternal.h"
+
+/* these modules were split out only to make this file more readable.
+ I don't want to expose the symbols */
+#include "infotime.c"
+#include "infofloor.c"
+#include "infores.c"
+#include "infopsy.c"
+
+/* Handlers for mapping 0 *******************************************/
+static void *_vorbis_map0_dup(void *source){
+ vorbis_info_mapping0 *d=malloc(sizeof(vorbis_info_mapping0));
+ vorbis_info_mapping0 *s=(vorbis_info_mapping0 *)source;
+ memcpy(d,s,sizeof(vorbis_info_mapping0));
+
+ if(d->timetype<0 || d->timetype>=VI_TIMEB)goto err_out;
+ if(d->floortype<0 || d->floortype>=VI_FLOORB)goto err_out;
+ if(d->restype<0 || d->restype>=VI_RESB)goto err_out;
+
+ d->time=vorbis_time_dup_P[d->timetype](s->time);
+ d->floor=vorbis_floor_dup_P[d->floortype](s->floor);
+ d->res=vorbis_res_dup_P[d->restype](s->res);
+ d->psy=vorbis_psy_dup(s->psy);
+
+ return(d);
+err_out:
+ memset(d,0,sizeof(vorbis_info_mapping0));
+ free(d);
+ return(NULL);
+}
+
+static void _vorbis_map0_free(void *i){
+ vorbis_info_mapping0 *d=(vorbis_info_mapping0 *)i;
+
+ if(d){
+ if(d->timetype>=0 && d->timetype<VI_TIMEB)
+ vorbis_time_free_P[d->timetype](d->time);
+ if(d->floortype>=0 && d->floortype<VI_FLOORB)
+ vorbis_floor_free_P[d->floortype](d->floor);
+ if(d->restype>=0 && d->restype<VI_RESB)
+ vorbis_res_free_P[d->restype](d->res);
+ vorbis_psy_free(d->psy);
+
+ memset(d,0,sizeof(vorbis_info_mapping0));
+ free(d);
+ }
+}
+
+static void _vorbis_map0_pack(oggpack_buffer *opb,void *i){
+ vorbis_info_mapping0 *d=(vorbis_info_mapping0 *)i;
+ _oggpack_write(opb,d->timetype,8);
+ _oggpack_write(opb,d->floortype,8);
+ _oggpack_write(opb,d->restype,8);
+
+ vorbis_time_pack_P[d->timetype](opb,d->time);
+ vorbis_floor_pack_P[d->floortype](opb,d->floor);
+ vorbis_res_pack_P[d->restype](opb,d->res);
+}
+
+static void *_vorbis_map0_unpack(oggpack_buffer *opb){
+ vorbis_info_mapping0 d;
+ memset(&d,0,sizeof(d));
+
+ d.timetype=_oggpack_read(opb,8);
+ d.floortype=_oggpack_read(opb,8);
+ d.restype=_oggpack_read(opb,8);
+
+ if(d.timetype<0 || d.timetype>=VI_TIMEB)goto err_out;
+ if(d.floortype<0 || d.floortype>=VI_FLOORB)goto err_out;
+ if(d.restype<0 || d.restype>=VI_RESB)goto err_out;
+
+ d.time=vorbis_time_unpack_P[d.timetype](opb);
+ d.floor=vorbis_floor_unpack_P[d.floortype](opb);
+ d.res=vorbis_res_unpack_P[d.restype](opb);
+ d.psy=NULL;
+
+ return _vorbis_map0_dup(&d);
+
+ err_out:
+ /* the null check protects against type out of range */
+ if(d.time)vorbis_time_free_P[d.timetype](d.time);
+ if(d.floor)vorbis_floor_free_P[d.floortype](d.floor);
+ if(d.res)vorbis_res_free_P[d.restype](d.res);
+
+ return(NULL);
+}
+
+/* stuff em into arrays ************************************************/
+#define VI_MAPB 1
+
+static void *(*vorbis_map_dup_P[])(void *)={
+ _vorbis_map0_dup,
+};
+
+static void (*vorbis_map_free_P[])(void *)={
+ _vorbis_map0_free,
+};
+
+static void (*vorbis_map_pack_P[])(oggpack_buffer *,void *)={
+ _vorbis_map0_pack,
+};
+
+static void *(*vorbis_map_unpack_P[])(oggpack_buffer *)={
+ _vorbis_map0_unpack,
+};
+