Info struct needs initializer so that we know if we've not gotten the
[platform/upstream/libvorbis.git] / lib / info.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE.  *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5  * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE.    *
6  * PLEASE READ THESE TERMS DISTRIBUTING.                            *
7  *                                                                  *
8  * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999             *
9  * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company       *
10  * http://www.xiph.org/                                             *
11  *                                                                  *
12  ********************************************************************
13
14  function: maintain the info structure, info <-> header packets
15  author: Monty <xiphmont@mit.edu>
16  modifications by: Monty
17  last modification date: Oct 04 1999
18
19  ********************************************************************/
20
21 /* This fills in a vorbis_info structure with settings from a few
22    pre-defined encoding modes.  Also handles choosing/blowing in the
23    codebook */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include "modes.h"
28 #include "bitwise.h"
29
30 void vorbis_info_init(vorbis_info *vi){
31   memset(vi,0,sizeof(vorbis_info));
32 }
33
34 /* one test mode for now; temporary of course */
35 int vorbis_info_modeset(vorbis_info *vi, int mode){
36   if(mode<0 || mode>predef_mode_max)return(-1);
37
38   /* handle the flat settings first */
39   memcpy(vi,&(predef_modes[mode]),sizeof(vorbis_info));
40   vi->user_comments=calloc(1,sizeof(char *));
41   vi->vendor=strdup("Xiphophorus libVorbis I 19991003");
42
43   return(0);
44 }
45
46 /* convenience function */
47 int vorbis_info_add_comment(vorbis_info *vi,char *comment){
48   vi->user_comments=realloc(vi->user_comments,
49                             (vi->comments+1)*sizeof(char *));
50   vi->user_comments[vi->comments]=strdup(comment);
51   vi->comments++;
52   vi->user_comments[vi->comments]=NULL;
53   return(0);
54 }
55
56 static void _v_writestring(oggpack_buffer *o,char *s){
57   while(*s){
58     _oggpack_write(o,*s++,8);
59   }
60 }
61
62 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
63   while(bytes--){
64     *buf++=_oggpack_read(o,8);
65   }
66 }
67
68 /* The Vorbis header is in three packets; the initial small packet in
69    the first page that identifies basic parameters, a second packet
70    with bitstream comments and a third packet that holds the
71    codebook. */
72
73 int vorbis_info_headerin(vorbis_info *vi,ogg_packet *op){
74
75   oggpack_buffer opb;
76   
77   if(op){
78     _oggpack_readinit(&opb,op->packet,op->bytes);
79
80     /* Which of the three types of header is this? */
81     /* Also verify header-ness, vorbis */
82     {
83       char buffer[6];
84       int type;
85       memset(buffer,0,6);
86       _v_readstring(&opb,buffer,6);
87       if(memcmp(buffer,"vorbis",6)){
88         /* not a vorbis header */
89         return(-1);
90       }
91       switch(_oggpack_read(&opb,8)){
92       case 0:
93         if(!op->b_o_s){
94           /* Not the initial packet */
95           return(-1);
96         }
97         if(vi->rate!=0){
98           /* previously initialized info header */
99           return(-1);
100         }
101
102         vi->channels=_oggpack_read(&opb,32);
103         vi->rate=_oggpack_read(&opb,32);
104         vi->smallblock=_oggpack_read(&opb,32);
105         vi->largeblock=_oggpack_read(&opb,32);
106         vi->envelopesa=_oggpack_read(&opb,32);
107         vi->envelopech=_oggpack_read(&opb,16);
108         vi->floororder=_oggpack_read(&opb,8);
109         vi->flooroctaves=_oggpack_read(&opb,8);
110         vi->floorch=_oggpack_read(&opb,16);
111
112         return(0);
113       case 1:
114         if(vi->rate==0){
115           /* um... we didn;t get the initial header */
116           return(-1);
117         }
118         {
119           int vendorlen=_oggpack_read(&opb,32);
120           vi->vendor=calloc(vendorlen+1,1);
121           _v_readstring(&opb,vi->vendor,vendorlen);
122         }
123         {
124           int i;
125           vi->comments=_oggpack_read(&opb,32);
126           vi->user_comments=calloc(vi->comments+1,sizeof(char **));
127             
128           for(i=0;i<=vi->comments;i++){
129             int len=_oggpack_read(&opb,32);
130             vi->user_comments[i]=calloc(len+1,1);
131             _v_readstring(&opb,vi->user_comments[i],len);
132           }       
133         }
134
135         return(0);
136       case 2:
137         if(vi->rate==0){
138           /* um... we didn;t get the initial header */
139           return(-1);
140         }
141
142         /* not implemented quite yet */
143
144         return(0);
145       default:
146         /* Not a valid vorbis header type */
147         return(-1);
148         break;
149       }
150     }
151   }
152   return(-1);
153 }
154
155 int vorbis_info_headerout(vorbis_info *vi,
156                           ogg_packet *op,
157                           ogg_packet *op_comm,
158                           ogg_packet *op_code){
159
160   oggpack_buffer opb;
161   /* initial header:
162
163      codec id     "vorbis"
164      header id    0 (byte)
165      codec ver    (4 octets, lsb first: currently 0x00)
166      pcm channels (4 octets, lsb first)
167      pcm rate     (4 octets, lsb first)
168      
169      small block  (4 octets, lsb first)
170      large block  (4 octets, lsb first)
171      envelopesa   (4 octets, lsb first)
172      envelopech   (4 octets, lsb first)
173      floororder   octet
174      flooroctaves octet
175      floorch      (4 octets, lsb first)
176    */
177
178   _oggpack_writeinit(&opb);
179   _v_writestring(&opb,"vorbis");
180   _oggpack_write(&opb,0x00,8);
181
182   _oggpack_write(&opb,0x00,32);
183
184   _oggpack_write(&opb,vi->channels,32);
185   _oggpack_write(&opb,vi->rate,32);
186   _oggpack_write(&opb,vi->smallblock,32);
187   _oggpack_write(&opb,vi->largeblock,32);
188   _oggpack_write(&opb,vi->envelopesa,32);
189   _oggpack_write(&opb,vi->envelopech,16);
190   _oggpack_write(&opb,vi->floororder,8);
191   _oggpack_write(&opb,vi->flooroctaves,8);
192   _oggpack_write(&opb,vi->floorch,16);
193
194   /* build the packet */
195   if(vi->header)free(vi->header);
196   memcpy(vi->header,opb.buffer,_oggpack_bytes(&opb));
197   op->packet=vi->header;
198   op->bytes=_oggpack_bytes(&opb);
199   op->b_o_s=1;
200   op->e_o_s=0;
201   op->frameno=0;
202
203   /* comment header:
204      codec id       "vorbis"
205      header id      1 (byte)
206      vendor len     (4 octets, lsb first)
207      vendor and id  (n octects as above)
208      comments       (4 octets, lsb first)
209      comment 0 len  (4 octets, lsb first)
210      comment 0 len  (n octets as above)
211      ...
212      comment n-1 len  (4 octets, lsb first)
213      comment 0-1 len  (n octets as above)
214   */
215
216   _oggpack_reset(&opb);
217   _v_writestring(&opb,"vorbis");
218   _oggpack_write(&opb,0x01,8);
219
220   if(vi->vendor){
221     _oggpack_write(&opb,strlen(vi->vendor),32);
222     _v_writestring(&opb,vi->vendor);
223   }else{
224     _oggpack_write(&opb,0,32);
225   }
226   
227   _oggpack_write(&opb,vi->comments,32);
228   if(vi->comments){
229     int i;
230     for(i=0;i<vi->comments;i++){
231       if(vi->user_comments[i]){
232         _oggpack_write(&opb,strlen(vi->user_comments[i]),32);
233         _v_writestring(&opb,vi->user_comments[i]);
234       }else{
235         _oggpack_write(&opb,0,32);
236       }
237     }
238   }
239   
240   if(vi->header1)free(vi->header1);
241   memcpy(vi->header1,opb.buffer,_oggpack_bytes(&opb));
242   op_comm->packet=vi->header1;
243   op_comm->bytes=_oggpack_bytes(&opb);
244   op_comm->b_o_s=0;
245   op_comm->e_o_s=0;
246   op_comm->frameno=0;
247
248   /* codebook header:
249      codec id       "vorbis"
250      header id      2 (byte)
251      nul so far; not encoded yet */
252
253   _oggpack_reset(&opb);
254   _v_writestring(&opb,"vorbis");
255   _oggpack_write(&opb,0x02,8);
256
257   if(vi->header2)free(vi->header2);
258   memcpy(vi->header2,opb.buffer,_oggpack_bytes(&opb));
259   op_code->packet=vi->header2;
260   op_code->bytes=_oggpack_bytes(&opb);
261   op_code->b_o_s=0;
262   op_code->e_o_s=0;
263   op_code->frameno=0;
264
265   _oggpack_writefree(&opb);
266
267   return(0);
268 }
269
270 int vorbis_info_clear(vorbis_info *vi){
271   /* clear the non-flat storage before zeroing */
272
273   /* comments */
274   if(vi->user_comments){
275     char **ptr=vi->user_comments;
276     while(*ptr){
277       free(*(ptr++));
278     }
279     free(vi->user_comments);
280   }
281
282   /* vendor string */
283   if(vi->vendor)free(vi->vendor);
284
285   /* local encoding storage */
286   if(vi->header)free(vi->header);
287   if(vi->header1)free(vi->header1);
288   if(vi->header2)free(vi->header2);
289
290   memset(vi,0,sizeof(vorbis_info));
291 }
292   
293