Recognizes if input is ogg or not.
[xiph/unicode.git] / w3d / info.c
blob3ae3534aff991b23a72c1c65a3ecfd9aa5bddcd2
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
9 * by the XIPHOPHORUS Company http://www.xiph.org/ *
11 ********************************************************************
13 function: maintain the info structure, info <-> header packets
14 last mod: $Id: info.c,v 1.3 2002/03/11 09:24:17 holger Exp $
16 ********************************************************************/
18 /* general handling of the header and the TarkinInfo structure (and
19 substructures) */
21 #include <malloc.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <ogg/ogg.h>
26 #include "tarkin.h"
27 #include "yuv.h"
28 #include "mem.h"
30 /* helpers */
31 static void _v_writestring(oggpack_buffer *o,char *s, int bytes){
32 while(bytes--){
33 oggpack_write(o,*s++,8);
37 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
38 while(bytes--){
39 *buf++=oggpack_read(o,8);
43 void tarkin_comment_init(TarkinComment *vc){
44 memset(vc,0,sizeof(*vc));
47 void tarkin_comment_add(TarkinComment *vc,char *comment){
48 vc->user_comments=REALLOC(vc->user_comments,
49 (vc->comments+2)*sizeof(*vc->user_comments));
50 vc->comment_lengths=REALLOC(vc->comment_lengths,
51 (vc->comments+2)*sizeof(*vc->comment_lengths));
52 vc->comment_lengths[vc->comments]=strlen(comment);
53 vc->user_comments[vc->comments]=MALLOC(vc->comment_lengths[vc->comments]+1);
54 strcpy(vc->user_comments[vc->comments], comment);
55 vc->comments++;
56 vc->user_comments[vc->comments]=NULL;
59 void tarkin_comment_add_tag(TarkinComment *vc, char *tag, char *contents){
60 char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */
61 strcpy(comment, tag);
62 strcat(comment, "=");
63 strcat(comment, contents);
64 tarkin_comment_add(vc, comment);
67 /* This is more or less the same as strncasecmp - but that doesn't exist
68 * everywhere, and this is a fairly trivial function, so we include it */
69 static int tagcompare(const char *s1, const char *s2, int n){
70 int c=0;
71 while(c < n){
72 if(toupper(s1[c]) != toupper(s2[c]))
73 return !0;
74 c++;
76 return 0;
79 char *tarkin_comment_query(TarkinComment *vc, char *tag, int count){
80 long i;
81 int found = 0;
82 int taglen = strlen(tag)+1; /* +1 for the = we append */
83 char *fulltag = alloca(taglen+ 1);
85 strcpy(fulltag, tag);
86 strcat(fulltag, "=");
88 for(i=0;i<vc->comments;i++){
89 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
90 if(count == found)
91 /* We return a pointer to the data, not a copy */
92 return vc->user_comments[i] + taglen;
93 else
94 found++;
97 return NULL; /* didn't find anything */
100 int tarkin_comment_query_count(TarkinComment *vc, char *tag){
101 int i,count=0;
102 int taglen = strlen(tag)+1; /* +1 for the = we append */
103 char *fulltag = alloca(taglen+1);
104 strcpy(fulltag,tag);
105 strcat(fulltag, "=");
107 for(i=0;i<vc->comments;i++){
108 if(!tagcompare(vc->user_comments[i], fulltag, taglen))
109 count++;
112 return count;
115 void tarkin_comment_clear(TarkinComment *vc){
116 if(vc){
117 long i;
118 for(i=0;i<vc->comments;i++)
119 if(vc->user_comments[i])FREE(vc->user_comments[i]);
120 if(vc->user_comments)FREE(vc->user_comments);
121 if(vc->comment_lengths)FREE(vc->comment_lengths);
122 if(vc->vendor)FREE(vc->vendor);
124 memset(vc,0,sizeof(*vc));
127 /* used by synthesis, which has a full, alloced vi */
128 void tarkin_info_init(TarkinInfo *vi){
129 memset(vi,0,sizeof(*vi));
132 void tarkin_info_clear(TarkinInfo *vi){
133 memset(vi,0,sizeof(*vi));
136 /* Header packing/unpacking ********************************************/
138 static int _tarkin_unpack_info(TarkinInfo *vi,oggpack_buffer *opb)
140 #ifdef DBG_OGG
141 printf("dbg_ogg: Decoding Info: ");
142 #endif
143 vi->version=oggpack_read(opb,32);
144 if(vi->version!=0)return(-TARKIN_VERSION);
146 vi->n_layers=oggpack_read(opb,8);
147 vi->inter.numerator=oggpack_read(opb,32);
148 vi->inter.denominator=oggpack_read(opb,32);
150 vi->bitrate_upper=oggpack_read(opb,32);
151 vi->bitrate_nominal=oggpack_read(opb,32);
152 vi->bitrate_lower=oggpack_read(opb,32);
154 #ifdef DBG_OGG
155 printf(" n_layers %d, interleave: %d/%d, ",
156 vi->n_layers, vi->inter.numerator, vi->inter.denominator);
157 #endif
159 if(vi->inter.numerator<1)goto err_out;
160 if(vi->inter.denominator<1)goto err_out;
161 if(vi->n_layers<1)goto err_out;
163 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
165 #ifdef DBG_OGG
166 printf("Success\n");
167 #endif
168 return(0);
169 err_out:
170 #ifdef DBG_OGG
171 printf("Failed\n");
172 #endif
173 tarkin_info_clear(vi);
174 return(-TARKIN_BAD_HEADER);
177 static int _tarkin_unpack_comment(TarkinComment *vc,oggpack_buffer *opb)
179 int i;
180 int vendorlen=oggpack_read(opb,32);
182 #ifdef DBG_OGG
183 printf("dbg_ogg: Decoding comment: ");
184 #endif
185 if(vendorlen<0)goto err_out;
186 vc->vendor=_ogg_calloc(vendorlen+1,1);
187 _v_readstring(opb,vc->vendor,vendorlen);
188 vc->comments=oggpack_read(opb,32);
189 if(vc->comments<0)goto err_out;
190 vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
191 vc->comment_lengths=_ogg_calloc(vc->comments+1,
192 sizeof(*vc->comment_lengths));
194 for(i=0;i<vc->comments;i++){
195 int len=oggpack_read(opb,32);
196 if(len<0)goto err_out;
197 vc->comment_lengths[i]=len;
198 vc->user_comments[i]=_ogg_calloc(len+1,1);
199 _v_readstring(opb,vc->user_comments[i],len);
201 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
203 #ifdef DBG_OGG
204 printf("Success, read %d comments\n", vc->comments);
205 #endif
206 return(0);
207 err_out:
208 #ifdef DBG_OGG
209 printf("Failed\n");
210 #endif
211 tarkin_comment_clear(vc);
212 return(-TARKIN_BAD_HEADER);
215 /* the real encoding details are here, currently TarkinVideoLayerDesc. */
216 static int _tarkin_unpack_layer_desc(TarkinInfo *vi,oggpack_buffer *opb){
217 int i,j;
218 vi->layer = CALLOC (vi->n_layers, (sizeof(*vi->layer)));
219 memset(vi->layer,0, vi->n_layers * sizeof(*vi->layer));
221 #ifdef DBG_OGG
222 printf("ogg: Decoding layers description: ");
223 #endif
224 for(i=0;i<vi->n_layers;i++){
225 TarkinVideoLayer *layer = vi->layer + i;
226 layer->desc.width = oggpack_read(opb,32);
227 layer->desc.height = oggpack_read(opb,32);
228 layer->desc.a_moments = oggpack_read(opb,32);
229 layer->desc.s_moments = oggpack_read(opb,32);
230 layer->desc.frames_per_buf = oggpack_read(opb,32);
231 layer->desc.bitstream_len = oggpack_read(opb,32);
232 layer->desc.format = oggpack_read(opb,32);
234 switch (layer->desc.format) {
235 case TARKIN_GRAYSCALE:
236 layer->n_comp = 1;
237 layer->color_fwd_xform = grayscale_to_y;
238 layer->color_inv_xform = y_to_grayscale;
239 break;
240 case TARKIN_RGB24:
241 layer->n_comp = 3;
242 layer->color_fwd_xform = rgb24_to_yuv;
243 layer->color_inv_xform = yuv_to_rgb24;
244 break;
245 case TARKIN_RGB32:
246 layer->n_comp = 3;
247 layer->color_fwd_xform = rgb32_to_yuv;
248 layer->color_inv_xform = yuv_to_rgb32;
249 break;
250 case TARKIN_RGBA:
251 layer->n_comp = 4;
252 layer->color_fwd_xform = rgba_to_yuv;
253 layer->color_inv_xform = yuv_to_rgba;
254 break;
255 default:
256 return -TARKIN_INVALID_COLOR_FORMAT;
259 layer->waveletbuf = (Wavelet3DBuf**) CALLOC (layer->n_comp,
260 sizeof(Wavelet3DBuf*));
262 layer->packet = MALLOC (layer->n_comp * sizeof(*layer->packet));
263 memset(layer->packet, 0, layer->n_comp * sizeof(*layer->packet));
265 for (j=0; j<layer->n_comp; j++){
266 layer->waveletbuf[j] = wavelet_3d_buf_new (layer->desc.width,
267 layer->desc.height,
268 layer->desc.frames_per_buf);
269 layer->packet[j].data = MALLOC(layer->desc.bitstream_len);
270 layer->packet[j].storage = layer->desc.bitstream_len;
273 vi->max_bitstream_len += layer->desc.bitstream_len
274 + 2 * 10 * sizeof(uint32_t) * layer->n_comp; // truncation tables
276 #ifdef DBG_OGG
277 printf("\n layer%d: size %dx%dx%d, format %d, a_m %d, s_m %d, %d fpb\n",
278 i, layer->desc.width, layer->desc.height, layer->n_comp,
279 layer->desc.format, layer->desc.a_moments, layer->desc.s_moments,
280 layer->desc.frames_per_buf);
281 #endif
282 } /* for each layer */
284 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
286 #ifdef DBG_OGG
287 printf("Success\n");
288 #endif
290 return(0);
291 err_out:
292 #ifdef DBG_OGG
293 printf("Failed\n");
294 #endif
295 tarkin_info_clear(vi);
296 return(-TARKIN_BAD_HEADER);
299 /* The Tarkin header is in three packets; the initial small packet in
300 the first page that identifies basic parameters, a second packet
301 with bitstream comments and a third packet that holds the
302 layer description structures. */
304 TarkinError tarkin_synthesis_headerin(TarkinInfo *vi,TarkinComment *vc,ogg_packet *op){
305 oggpack_buffer opb;
307 if(op){
308 oggpack_readinit(&opb,op->packet,op->bytes);
310 /* Which of the three types of header is this? */
311 /* Also verify header-ness, tarkin */
313 char buffer[6];
314 int packtype=oggpack_read(&opb,8);
315 memset(buffer,0,6);
316 _v_readstring(&opb,buffer,6);
317 if(memcmp(buffer,"tarkin",6)){
318 /* not a tarkin header */
319 return(-TARKIN_NOT_TARKIN);
321 switch(packtype){
322 case 0x01: /* least significant *bit* is read first */
323 if(!op->b_o_s){
324 /* Not the initial packet */
325 return(-TARKIN_BAD_HEADER);
327 if(vi->inter.numerator!=0){
328 /* previously initialized info header */
329 return(-TARKIN_BAD_HEADER);
332 return(_tarkin_unpack_info(vi,&opb));
334 case 0x03: /* least significant *bit* is read first */
335 if(vi->inter.denominator==0){
336 /* um... we didn't get the initial header */
337 return(-TARKIN_BAD_HEADER);
340 return(_tarkin_unpack_comment(vc,&opb));
342 case 0x05: /* least significant *bit* is read first */
343 if(vi->inter.numerator == 0 || vc->vendor==NULL){
344 /* um... we didn;t get the initial header or comments yet */
345 return(-TARKIN_BAD_HEADER);
348 return(_tarkin_unpack_layer_desc(vi,&opb));
350 default:
351 /* Not a valid tarkin header type */
352 return(-TARKIN_BAD_HEADER);
353 break;
357 return(-TARKIN_BAD_HEADER);
360 /* pack side **********************************************************/
362 static int _tarkin_pack_info(oggpack_buffer *opb,TarkinInfo *vi){
364 /* preamble */
365 oggpack_write(opb,0x01,8);
366 _v_writestring(opb,"tarkin", 6);
368 /* basic information about the stream */
369 oggpack_write(opb,0x00,32);
370 oggpack_write(opb,vi->n_layers,8);
371 oggpack_write(opb,vi->inter.numerator,32);
372 oggpack_write(opb,vi->inter.denominator,32);
374 oggpack_write(opb,vi->bitrate_upper,32);
375 oggpack_write(opb,vi->bitrate_nominal,32);
376 oggpack_write(opb,vi->bitrate_lower,32);
378 oggpack_write(opb,1,1);
380 #ifdef DBG_OGG
381 printf("dbg_ogg: Putting out info, inter %d/%d, n_layers %d\n",
382 vi->inter.numerator,vi->inter.denominator,vi->n_layers);
383 #endif
384 return(0);
387 static int _tarkin_pack_comment(oggpack_buffer *opb,TarkinComment *vc){
388 char temp[]="libTarkin debugging edition 20011104";
389 int bytes = strlen(temp);
391 /* preamble */
392 oggpack_write(opb,0x03,8);
393 _v_writestring(opb,"tarkin", 6);
395 /* vendor */
396 oggpack_write(opb,bytes,32);
397 _v_writestring(opb,temp, bytes);
399 /* comments */
401 oggpack_write(opb,vc->comments,32);
402 if(vc->comments){
403 int i;
404 for(i=0;i<vc->comments;i++){
405 if(vc->user_comments[i]){
406 oggpack_write(opb,vc->comment_lengths[i],32);
407 _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
408 }else{
409 oggpack_write(opb,0,32);
413 oggpack_write(opb,1,1);
415 #ifdef DBG_OGG
416 printf("dbg_ogg: Putting out %d comments\n", vc->comments);
417 #endif
419 return(0);
422 static int _tarkin_pack_layer_desc(oggpack_buffer *opb,TarkinInfo *vi)
424 int i;
425 TarkinVideoLayer *layer;
427 #ifdef DBG_OGG
428 printf("dbg_ogg: Putting out layers description:\n");
429 #endif
431 oggpack_write(opb,0x05,8);
432 _v_writestring(opb,"tarkin", 6);
434 for(i=0;i<vi->n_layers;i++){
435 layer = vi->layer + i;
436 oggpack_write(opb,layer->desc.width,32);
437 oggpack_write(opb,layer->desc.height,32);
438 oggpack_write(opb,layer->desc.a_moments,32);
439 oggpack_write(opb,layer->desc.s_moments,32);
440 oggpack_write(opb,layer->desc.frames_per_buf,32);
441 oggpack_write(opb,layer->desc.bitstream_len,32);
442 oggpack_write(opb,layer->desc.format,32);
444 #ifdef DBG_OGG
445 printf(" res. %dx%d, format %d, a_m %d, s_m %d, fpb %d\n",
446 layer->desc.width, layer->desc.height, layer->desc.format,
447 layer->desc.a_moments, layer->desc.s_moments,
448 layer->desc.frames_per_buf);
449 #endif
452 oggpack_write(opb,1,1);
454 #ifdef DBG_OGG
455 printf(" wrote %ld bytes.\n", oggpack_bytes(opb));
456 #endif
458 return(0);
461 int tarkin_comment_header_out(TarkinComment *vc, ogg_packet *op)
464 oggpack_buffer opb;
466 oggpack_writeinit(&opb);
467 if(_tarkin_pack_comment(&opb,vc)) return -TARKIN_NOT_IMPLEMENTED;
469 op->packet = MALLOC(oggpack_bytes(&opb));
470 memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));
472 op->bytes=oggpack_bytes(&opb);
473 op->b_o_s=0;
474 op->e_o_s=0;
475 op->granulepos=0;
477 return 0;
480 TarkinError tarkin_analysis_headerout(TarkinStream *v,
481 TarkinComment *vc,
482 ogg_packet *op,
483 ogg_packet *op_comm,
484 ogg_packet *op_code)
486 int ret=-TARKIN_NOT_IMPLEMENTED;
487 TarkinInfo * vi;
488 oggpack_buffer opb;
489 tarkin_header_store *b=&v->headers;
491 vi = v->ti;
493 /* first header packet **********************************************/
495 oggpack_writeinit(&opb);
496 if(_tarkin_pack_info(&opb,vi))goto err_out;
498 /* build the packet */
499 if(b->header)FREE(b->header);
500 b->header=MALLOC(oggpack_bytes(&opb));
501 memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
502 op->packet=b->header;
503 op->bytes=oggpack_bytes(&opb);
504 op->b_o_s=1;
505 op->e_o_s=0;
506 op->granulepos=0;
508 /* second header packet (comments) **********************************/
510 oggpack_reset(&opb);
511 if(_tarkin_pack_comment(&opb,vc))goto err_out;
513 if(b->header1)FREE(b->header1);
514 b->header1=MALLOC(oggpack_bytes(&opb));
515 memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
516 op_comm->packet=b->header1;
517 op_comm->bytes=oggpack_bytes(&opb);
518 op_comm->b_o_s=0;
519 op_comm->e_o_s=0;
520 op_comm->granulepos=0;
522 /* third header packet (modes/codebooks) ****************************/
524 oggpack_reset(&opb);
525 if(_tarkin_pack_layer_desc(&opb,vi))goto err_out;
527 if(b->header2)FREE(b->header2);
528 b->header2=MALLOC(oggpack_bytes(&opb));
529 memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
530 op_code->packet=b->header2;
531 op_code->bytes=oggpack_bytes(&opb);
532 op_code->b_o_s=0;
533 op_code->e_o_s=0;
534 op_code->granulepos=0;
536 oggpack_writeclear(&opb);
537 return(0);
538 err_out:
539 oggpack_writeclear(&opb);
540 memset(op,0,sizeof(*op));
541 memset(op_comm,0,sizeof(*op_comm));
542 memset(op_code,0,sizeof(*op_code));
544 if(b->header)FREE(b->header);
545 if(b->header1)FREE(b->header1);
546 if(b->header2)FREE(b->header2);
547 b->header=NULL;
548 b->header1=NULL;
549 b->header2=NULL;
550 return(ret);