info.c 19.4 KB
Newer Older
Monty's avatar
 
Monty committed
1 2
/********************************************************************
 *                                                                  *
Monty's avatar
 
Monty committed
3
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Monty's avatar
 
Monty committed
4 5 6
 * 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.       *
Monty's avatar
 
Monty committed
7
 *                                                                  *
Ralph Giles's avatar
Ralph Giles committed
8
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015             *
9
 * by the Xiph.Org Foundation https://xiph.org/                     *
10
 *                                                                  *
Monty's avatar
 
Monty committed
11 12 13 14 15 16
 ********************************************************************

 function: maintain the info structure, info <-> header packets

 ********************************************************************/

Monty's avatar
 
Monty committed
17 18
/* general handling of the header and the vorbis_info structure (and
   substructures) */
Monty's avatar
 
Monty committed
19 20 21

#include <stdlib.h>
#include <string.h>
Monty's avatar
 
Monty committed
22
#include <ogg/ogg.h>
Monty's avatar
 
Monty committed
23
#include "vorbis/codec.h"
Monty's avatar
 
Monty committed
24 25
#include "codec_internal.h"
#include "codebook.h"
Monty's avatar
 
Monty committed
26
#include "registry.h"
Monty's avatar
 
Monty committed
27
#include "window.h"
Monty's avatar
 
Monty committed
28
#include "psy.h"
Monty's avatar
 
Monty committed
29
#include "misc.h"
Monty's avatar
 
Monty committed
30
#include "os.h"
Monty's avatar
 
Monty committed
31

32 33
#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.7"
#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20200704 (Reducing Environment)"
34

Monty's avatar
 
Monty committed
35
/* helpers */
erikd's avatar
erikd committed
36
static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){
37 38

  while(bytes--){
Monty's avatar
 
Monty committed
39
    oggpack_write(o,*s++,8);
Monty's avatar
 
Monty committed
40 41
  }
}
Monty's avatar
 
Monty committed
42

Monty's avatar
 
Monty committed
43 44
static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
  while(bytes--){
Monty's avatar
 
Monty committed
45
    *buf++=oggpack_read(o,8);
Monty's avatar
 
Monty committed
46
  }
Monty's avatar
 
Monty committed
47 48
}

49 50 51 52
static int _v_toupper(int c) {
  return (c >= 'a' && c <= 'z') ? (c & ~('a' - 'A')) : c;
}

Monty's avatar
 
Monty committed
53
void vorbis_comment_init(vorbis_comment *vc){
54
  memset(vc,0,sizeof(*vc));
Monty's avatar
 
Monty committed
55 56
}

57
void vorbis_comment_add(vorbis_comment *vc,const char *comment){
Monty's avatar
 
Monty committed
58
  vc->user_comments=_ogg_realloc(vc->user_comments,
59
                            (vc->comments+2)*sizeof(*vc->user_comments));
Monty's avatar
 
Monty committed
60
  vc->comment_lengths=_ogg_realloc(vc->comment_lengths,
61
                                  (vc->comments+2)*sizeof(*vc->comment_lengths));
Michael Smith's avatar
 
Michael Smith committed
62
  vc->comment_lengths[vc->comments]=strlen(comment);
63 64
  vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1);
  strcpy(vc->user_comments[vc->comments], comment);
Monty's avatar
 
Monty committed
65 66
  vc->comments++;
  vc->user_comments[vc->comments]=NULL;
Monty's avatar
 
Monty committed
67 68
}

69
void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){
70 71
  /* Length for key and value +2 for = and \0 */
  char *comment=_ogg_malloc(strlen(tag)+strlen(contents)+2);
Michael Smith's avatar
 
Michael Smith committed
72
  strcpy(comment, tag);
Michael Smith's avatar
 
Michael Smith committed
73
  strcat(comment, "=");
Michael Smith's avatar
 
Michael Smith committed
74 75
  strcat(comment, contents);
  vorbis_comment_add(vc, comment);
76
  _ogg_free(comment);
Michael Smith's avatar
 
Michael Smith committed
77 78 79 80 81 82 83
}

/* This is more or less the same as strncasecmp - but that doesn't exist
 * everywhere, and this is a fairly trivial function, so we include it */
static int tagcompare(const char *s1, const char *s2, int n){
  int c=0;
  while(c < n){
84
    if(_v_toupper(s1[c]) != _v_toupper(s2[c]))
Michael Smith's avatar
 
Michael Smith committed
85 86 87 88 89 90
      return !0;
    c++;
  }
  return 0;
}

91
char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){
Michael Smith's avatar
 
Michael Smith committed
92 93
  long i;
  int found = 0;
Michael Smith's avatar
 
Michael Smith committed
94
  int taglen = strlen(tag)+1; /* +1 for the = we append */
95
  char *fulltag = _ogg_malloc(taglen+1);
Michael Smith's avatar
 
Michael Smith committed
96 97 98

  strcpy(fulltag, tag);
  strcat(fulltag, "=");
Monty's avatar
Monty committed
99

Michael Smith's avatar
 
Michael Smith committed
100
  for(i=0;i<vc->comments;i++){
Michael Smith's avatar
 
Michael Smith committed
101
    if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
102
      if(count == found) {
103
        /* We return a pointer to the data, not a copy */
104 105 106
        _ogg_free(fulltag);
        return vc->user_comments[i] + taglen;
      } else {
107
        found++;
108
      }
Michael Smith's avatar
 
Michael Smith committed
109 110
    }
  }
111
  _ogg_free(fulltag);
Michael Smith's avatar
 
Michael Smith committed
112 113 114
  return NULL; /* didn't find anything */
}

115
int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){
Michael Smith's avatar
 
Michael Smith committed
116 117
  int i,count=0;
  int taglen = strlen(tag)+1; /* +1 for the = we append */
118
  char *fulltag = _ogg_malloc(taglen+1);
Michael Smith's avatar
 
Michael Smith committed
119 120 121 122 123 124 125 126
  strcpy(fulltag,tag);
  strcat(fulltag, "=");

  for(i=0;i<vc->comments;i++){
    if(!tagcompare(vc->user_comments[i], fulltag, taglen))
      count++;
  }

127
  _ogg_free(fulltag);
Michael Smith's avatar
 
Michael Smith committed
128 129 130
  return count;
}

Monty's avatar
 
Monty committed
131 132 133
void vorbis_comment_clear(vorbis_comment *vc){
  if(vc){
    long i;
134 135
    if(vc->user_comments){
      for(i=0;i<vc->comments;i++)
136
        if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
137 138 139
      _ogg_free(vc->user_comments);
    }
    if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
Monty's avatar
 
Monty committed
140
    if(vc->vendor)_ogg_free(vc->vendor);
141
    memset(vc,0,sizeof(*vc));
Monty's avatar
 
Monty committed
142
  }
Monty's avatar
 
Monty committed
143 144
}

145
/* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long.
Monty's avatar
 
Monty committed
146 147 148 149 150 151
   They may be equal, but short will never ge greater than long */
int vorbis_info_blocksize(vorbis_info *vi,int zo){
  codec_setup_info *ci = vi->codec_setup;
  return ci ? ci->blocksizes[zo] : -1;
}

Monty's avatar
 
Monty committed
152 153
/* used by synthesis, which has a full, alloced vi */
void vorbis_info_init(vorbis_info *vi){
154
  memset(vi,0,sizeof(*vi));
Monty's avatar
 
Monty committed
155
  vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info));
Monty's avatar
 
Monty committed
156 157
}

Monty's avatar
 
Monty committed
158
void vorbis_info_clear(vorbis_info *vi){
Monty's avatar
 
Monty committed
159
  codec_setup_info     *ci=vi->codec_setup;
Monty's avatar
 
Monty committed
160
  int i;
Monty's avatar
 
Monty committed
161

Monty's avatar
 
Monty committed
162 163 164
  if(ci){

    for(i=0;i<ci->modes;i++)
Monty's avatar
 
Monty committed
165
      if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
Monty's avatar
 
Monty committed
166 167

    for(i=0;i<ci->maps;i++) /* unpack does the range checking */
168
      if(ci->map_param[i]) /* this may be cleaning up an aborted
169 170 171
                              unpack, in which case the below type
                              cannot be trusted */
        _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
Monty's avatar
 
Monty committed
172 173

    for(i=0;i<ci->floors;i++) /* unpack does the range checking */
174
      if(ci->floor_param[i]) /* this may be cleaning up an aborted
175 176 177
                                unpack, in which case the below type
                                cannot be trusted */
        _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
Monty's avatar
Monty committed
178

Monty's avatar
 
Monty committed
179
    for(i=0;i<ci->residues;i++) /* unpack does the range checking */
180
      if(ci->residue_param[i]) /* this may be cleaning up an aborted
181 182 183
                                  unpack, in which case the below type
                                  cannot be trusted */
        _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
Monty's avatar
Monty committed
184

Monty's avatar
 
Monty committed
185 186
    for(i=0;i<ci->books;i++){
      if(ci->book_param[i]){
187 188
        /* knows if the book was not alloced */
        vorbis_staticbook_destroy(ci->book_param[i]);
Monty's avatar
 
Monty committed
189
      }
Monty's avatar
 
Monty committed
190
      if(ci->fullbooks)
191
        vorbis_book_clear(ci->fullbooks+i);
Monty's avatar
 
Monty committed
192
    }
Monty's avatar
 
Monty committed
193
    if(ci->fullbooks)
194
        _ogg_free(ci->fullbooks);
Monty's avatar
Monty committed
195

Monty's avatar
 
Monty committed
196 197 198
    for(i=0;i<ci->psys;i++)
      _vi_psy_free(ci->psy_param[i]);

Monty's avatar
 
Monty committed
199
    _ogg_free(ci);
Monty's avatar
 
Monty committed
200 201
  }

202
  memset(vi,0,sizeof(*vi));
Monty's avatar
 
Monty committed
203 204 205 206 207
}

/* Header packing/unpacking ********************************************/

static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
Monty's avatar
 
Monty committed
208
  codec_setup_info     *ci=vi->codec_setup;
209
  int bs;
Monty's avatar
 
Monty committed
210 211
  if(!ci)return(OV_EFAULT);

Monty's avatar
 
Monty committed
212
  vi->version=oggpack_read(opb,32);
Monty's avatar
 
Monty committed
213
  if(vi->version!=0)return(OV_EVERSION);
Monty's avatar
 
Monty committed
214

Monty's avatar
 
Monty committed
215 216
  vi->channels=oggpack_read(opb,8);
  vi->rate=oggpack_read(opb,32);
Monty's avatar
 
Monty committed
217

218 219 220
  vi->bitrate_upper=(ogg_int32_t)oggpack_read(opb,32);
  vi->bitrate_nominal=(ogg_int32_t)oggpack_read(opb,32);
  vi->bitrate_lower=(ogg_int32_t)oggpack_read(opb,32);
Monty's avatar
 
Monty committed
221

222 223 224 225 226 227
  bs = oggpack_read(opb,4);
  if(bs<0)goto err_out;
  ci->blocksizes[0]=1<<bs;
  bs = oggpack_read(opb,4);
  if(bs<0)goto err_out;
  ci->blocksizes[1]=1<<bs;
Monty's avatar
Monty committed
228

Monty's avatar
 
Monty committed
229 230
  if(vi->rate<1)goto err_out;
  if(vi->channels<1)goto err_out;
Monty's avatar
Monty committed
231
  if(ci->blocksizes[0]<64)goto err_out;
Monty's avatar
 
Monty committed
232
  if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
233 234
  if(ci->blocksizes[1]>8192)goto err_out;

Monty's avatar
 
Monty committed
235
  if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
Monty's avatar
 
Monty committed
236 237 238 239

  return(0);
 err_out:
  vorbis_info_clear(vi);
Monty's avatar
 
Monty committed
240
  return(OV_EBADHEADER);
Monty's avatar
 
Monty committed
241 242
}

Monty's avatar
 
Monty committed
243
static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
Monty's avatar
 
Monty committed
244
  int i;
Monty's avatar
 
Monty committed
245
  int vendorlen=oggpack_read(opb,32);
Monty's avatar
 
Monty committed
246
  if(vendorlen<0)goto err_out;
247
  if(vendorlen>opb->storage-8)goto err_out;
Monty's avatar
 
Monty committed
248
  vc->vendor=_ogg_calloc(vendorlen+1,1);
Monty's avatar
 
Monty committed
249
  _v_readstring(opb,vc->vendor,vendorlen);
250 251
  i=oggpack_read(opb,32);
  if(i<0)goto err_out;
252
  if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out;
253
  vc->comments=i;
254 255
  vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
  vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
Monty's avatar
Monty committed
256

Monty's avatar
 
Monty committed
257
  for(i=0;i<vc->comments;i++){
Monty's avatar
 
Monty committed
258
    int len=oggpack_read(opb,32);
Monty's avatar
 
Monty committed
259
    if(len<0)goto err_out;
260
    if(len>opb->storage-oggpack_bytes(opb))goto err_out;
261
    vc->comment_lengths[i]=len;
Monty's avatar
 
Monty committed
262
    vc->user_comments[i]=_ogg_calloc(len+1,1);
Monty's avatar
 
Monty committed
263
    _v_readstring(opb,vc->user_comments[i],len);
Monty's avatar
Monty committed
264
  }
Monty's avatar
 
Monty committed
265
  if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
Monty's avatar
 
Monty committed
266

Monty's avatar
 
Monty committed
267 268
  return(0);
 err_out:
Monty's avatar
 
Monty committed
269
  vorbis_comment_clear(vc);
Monty's avatar
 
Monty committed
270
  return(OV_EBADHEADER);
Monty's avatar
 
Monty committed
271 272 273 274 275
}

/* all of the real encoding details are here.  The modes, books,
   everything */
static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
Monty's avatar
 
Monty committed
276
  codec_setup_info     *ci=vi->codec_setup;
Monty's avatar
 
Monty committed
277 278
  int i;

Monty's avatar
 
Monty committed
279
  /* codebooks */
Monty's avatar
 
Monty committed
280
  ci->books=oggpack_read(opb,8)+1;
281
  if(ci->books<=0)goto err_out;
Monty's avatar
 
Monty committed
282
  for(i=0;i<ci->books;i++){
283
    ci->book_param[i]=vorbis_staticbook_unpack(opb);
284
    if(!ci->book_param[i])goto err_out;
Monty's avatar
 
Monty committed
285 286
  }

Monty's avatar
 
Monty committed
287 288 289
  /* time backend settings; hooks are unused */
  {
    int times=oggpack_read(opb,6)+1;
290
    if(times<=0)goto err_out;
Monty's avatar
 
Monty committed
291 292 293 294
    for(i=0;i<times;i++){
      int test=oggpack_read(opb,16);
      if(test<0 || test>=VI_TIMEB)goto err_out;
    }
Monty's avatar
 
Monty committed
295
  }
Monty's avatar
 
Monty committed
296

Monty's avatar
 
Monty committed
297
  /* floor backend settings */
Monty's avatar
 
Monty committed
298
  ci->floors=oggpack_read(opb,6)+1;
299
  if(ci->floors<=0)goto err_out;
Monty's avatar
 
Monty committed
300 301 302 303 304
  for(i=0;i<ci->floors;i++){
    ci->floor_type[i]=oggpack_read(opb,16);
    if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
    ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
    if(!ci->floor_param[i])goto err_out;
Monty's avatar
 
Monty committed
305 306
  }

Monty's avatar
 
Monty committed
307
  /* residue backend settings */
Monty's avatar
 
Monty committed
308
  ci->residues=oggpack_read(opb,6)+1;
309
  if(ci->residues<=0)goto err_out;
Monty's avatar
 
Monty committed
310 311 312 313 314
  for(i=0;i<ci->residues;i++){
    ci->residue_type[i]=oggpack_read(opb,16);
    if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
    ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
    if(!ci->residue_param[i])goto err_out;
Monty's avatar
 
Monty committed
315 316
  }

Monty's avatar
 
Monty committed
317
  /* map backend settings */
Monty's avatar
 
Monty committed
318
  ci->maps=oggpack_read(opb,6)+1;
319
  if(ci->maps<=0)goto err_out;
Monty's avatar
 
Monty committed
320 321 322 323 324
  for(i=0;i<ci->maps;i++){
    ci->map_type[i]=oggpack_read(opb,16);
    if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
    ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
    if(!ci->map_param[i])goto err_out;
Monty's avatar
 
Monty committed
325
  }
Monty's avatar
Monty committed
326

Monty's avatar
 
Monty committed
327
  /* mode settings */
Monty's avatar
 
Monty committed
328
  ci->modes=oggpack_read(opb,6)+1;
329
  if(ci->modes<=0)goto err_out;
Monty's avatar
 
Monty committed
330
  for(i=0;i<ci->modes;i++){
331
    ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i]));
Monty's avatar
 
Monty committed
332 333 334 335 336 337 338 339
    ci->mode_param[i]->blockflag=oggpack_read(opb,1);
    ci->mode_param[i]->windowtype=oggpack_read(opb,16);
    ci->mode_param[i]->transformtype=oggpack_read(opb,16);
    ci->mode_param[i]->mapping=oggpack_read(opb,8);

    if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
    if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
    if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
340
    if(ci->mode_param[i]->mapping<0)goto err_out;
Monty's avatar
 
Monty committed
341
  }
Monty's avatar
Monty committed
342

Monty's avatar
 
Monty committed
343
  if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
Monty's avatar
 
Monty committed
344

Monty's avatar
 
Monty committed
345
  return(0);
Monty's avatar
 
Monty committed
346
 err_out:
Monty's avatar
 
Monty committed
347
  vorbis_info_clear(vi);
Monty's avatar
 
Monty committed
348
  return(OV_EBADHEADER);
Monty's avatar
 
Monty committed
349 350
}

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
/* Is this packet a vorbis ID header? */
int vorbis_synthesis_idheader(ogg_packet *op){
  oggpack_buffer opb;
  char buffer[6];

  if(op){
    oggpack_readinit(&opb,op->packet,op->bytes);

    if(!op->b_o_s)
      return(0); /* Not the initial packet */

    if(oggpack_read(&opb,8) != 1)
      return 0; /* not an ID header */

    memset(buffer,0,6);
    _v_readstring(&opb,buffer,6);
    if(memcmp(buffer,"vorbis",6))
      return 0; /* not vorbis */

    return 1;
  }

  return 0;
}

Monty's avatar
 
Monty committed
376
/* The Vorbis header is in three packets; the initial small packet in
Monty's avatar
 
Monty committed
377 378 379
   the first page that identifies basic parameters, a second packet
   with bitstream comments and a third packet that holds the
   codebook. */
Monty's avatar
 
Monty committed
380

Monty's avatar
 
Monty committed
381
int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
Monty's avatar
 
Monty committed
382
  oggpack_buffer opb;
Monty's avatar
Monty committed
383

Monty's avatar
 
Monty committed
384
  if(op){
Monty's avatar
 
Monty committed
385
    oggpack_readinit(&opb,op->packet,op->bytes);
Monty's avatar
 
Monty committed
386 387 388 389 390

    /* Which of the three types of header is this? */
    /* Also verify header-ness, vorbis */
    {
      char buffer[6];
Monty's avatar
 
Monty committed
391
      int packtype=oggpack_read(&opb,8);
Monty's avatar
 
Monty committed
392 393 394
      memset(buffer,0,6);
      _v_readstring(&opb,buffer,6);
      if(memcmp(buffer,"vorbis",6)){
395 396
        /* not a vorbis header */
        return(OV_ENOTVORBIS);
Monty's avatar
 
Monty committed
397
      }
Monty's avatar
 
Monty committed
398 399
      switch(packtype){
      case 0x01: /* least significant *bit* is read first */
400 401 402 403 404 405 406 407
        if(!op->b_o_s){
          /* Not the initial packet */
          return(OV_EBADHEADER);
        }
        if(vi->rate!=0){
          /* previously initialized info header */
          return(OV_EBADHEADER);
        }
Monty's avatar
 
Monty committed
408

409
        return(_vorbis_unpack_info(vi,&opb));
Monty's avatar
 
Monty committed
410

Monty's avatar
 
Monty committed
411
      case 0x03: /* least significant *bit* is read first */
412 413 414 415
        if(vi->rate==0){
          /* um... we didn't get the initial header */
          return(OV_EBADHEADER);
        }
416 417 418 419
        if(vc->vendor!=NULL){
          /* previously initialized comment header */
          return(OV_EBADHEADER);
        }
Monty's avatar
 
Monty committed
420

421
        return(_vorbis_unpack_comment(vc,&opb));
Monty's avatar
 
Monty committed
422

Monty's avatar
 
Monty committed
423
      case 0x05: /* least significant *bit* is read first */
424 425 426 427
        if(vi->rate==0 || vc->vendor==NULL){
          /* um... we didn;t get the initial header or comments yet */
          return(OV_EBADHEADER);
        }
428 429 430 431 432 433 434 435
        if(vi->codec_setup==NULL){
          /* improperly initialized vorbis_info */
          return(OV_EFAULT);
        }
        if(((codec_setup_info *)vi->codec_setup)->books>0){
          /* previously initialized setup header */
          return(OV_EBADHEADER);
        }
Monty's avatar
 
Monty committed
436

437
        return(_vorbis_unpack_books(vi,&opb));
Monty's avatar
 
Monty committed
438 439

      default:
440 441 442
        /* Not a valid vorbis header type */
        return(OV_EBADHEADER);
        break;
Monty's avatar
 
Monty committed
443 444 445
      }
    }
  }
Monty's avatar
 
Monty committed
446
  return(OV_EBADHEADER);
Monty's avatar
 
Monty committed
447 448
}

Monty's avatar
 
Monty committed
449 450 451
/* pack side **********************************************************/

static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
Monty's avatar
 
Monty committed
452
  codec_setup_info     *ci=vi->codec_setup;
453 454 455 456 457
  if(!ci||
     ci->blocksizes[0]<64||
     ci->blocksizes[1]<ci->blocksizes[0]){
    return(OV_EFAULT);
  }
Monty's avatar
 
Monty committed
458

Monty's avatar
Monty committed
459
  /* preamble */
Monty's avatar
 
Monty committed
460
  oggpack_write(opb,0x01,8);
461
  _v_writestring(opb,"vorbis", 6);
Monty's avatar
 
Monty committed
462 463

  /* basic information about the stream */
Monty's avatar
 
Monty committed
464 465 466
  oggpack_write(opb,0x00,32);
  oggpack_write(opb,vi->channels,8);
  oggpack_write(opb,vi->rate,32);
Monty's avatar
 
Monty committed
467

Monty's avatar
 
Monty committed
468 469 470
  oggpack_write(opb,vi->bitrate_upper,32);
  oggpack_write(opb,vi->bitrate_nominal,32);
  oggpack_write(opb,vi->bitrate_lower,32);
Monty's avatar
 
Monty committed
471

472 473
  oggpack_write(opb,ov_ilog(ci->blocksizes[0]-1),4);
  oggpack_write(opb,ov_ilog(ci->blocksizes[1]-1),4);
Monty's avatar
 
Monty committed
474
  oggpack_write(opb,1,1);
Monty's avatar
 
Monty committed
475

Monty's avatar
 
Monty committed
476 477 478
  return(0);
}

Monty's avatar
 
Monty committed
479
static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
480
  int bytes = strlen(ENCODE_VENDOR_STRING);
Monty's avatar
 
Monty committed
481

Monty's avatar
Monty committed
482
  /* preamble */
Monty's avatar
 
Monty committed
483
  oggpack_write(opb,0x03,8);
484
  _v_writestring(opb,"vorbis", 6);
Monty's avatar
 
Monty committed
485 486

  /* vendor */
487
  oggpack_write(opb,bytes,32);
488 489
  _v_writestring(opb,ENCODE_VENDOR_STRING, bytes);

Monty's avatar
 
Monty committed
490 491
  /* comments */

Monty's avatar
 
Monty committed
492
  oggpack_write(opb,vc->comments,32);
Monty's avatar
 
Monty committed
493
  if(vc->comments){
Monty's avatar
 
Monty committed
494
    int i;
Monty's avatar
 
Monty committed
495 496
    for(i=0;i<vc->comments;i++){
      if(vc->user_comments[i]){
497 498
        oggpack_write(opb,vc->comment_lengths[i],32);
        _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
Monty's avatar
 
Monty committed
499
      }else{
500
        oggpack_write(opb,0,32);
Monty's avatar
 
Monty committed
501 502 503
      }
    }
  }
Monty's avatar
 
Monty committed
504
  oggpack_write(opb,1,1);
Monty's avatar
 
Monty committed
505 506 507

  return(0);
}
Monty's avatar
Monty committed
508

Monty's avatar
 
Monty committed
509
static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
Monty's avatar
 
Monty committed
510
  codec_setup_info     *ci=vi->codec_setup;
Monty's avatar
 
Monty committed
511
  int i;
Monty's avatar
 
Monty committed
512 513
  if(!ci)return(OV_EFAULT);

Monty's avatar
 
Monty committed
514
  oggpack_write(opb,0x05,8);
515
  _v_writestring(opb,"vorbis", 6);
Monty's avatar
 
Monty committed
516

Monty's avatar
 
Monty committed
517
  /* books */
Monty's avatar
 
Monty committed
518 519 520
  oggpack_write(opb,ci->books-1,8);
  for(i=0;i<ci->books;i++)
    if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;
Monty's avatar
 
Monty committed
521

Monty's avatar
 
Monty committed
522 523 524
  /* times; hook placeholders */
  oggpack_write(opb,0,6);
  oggpack_write(opb,0,16);
Monty's avatar
 
Monty committed
525 526

  /* floors */
Monty's avatar
 
Monty committed
527 528 529
  oggpack_write(opb,ci->floors-1,6);
  for(i=0;i<ci->floors;i++){
    oggpack_write(opb,ci->floor_type[i],16);
Monty's avatar
 
Monty committed
530 531 532 533
    if(_floor_P[ci->floor_type[i]]->pack)
      _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
    else
      goto err_out;
Monty's avatar
 
Monty committed
534 535
  }

Monty's avatar
 
Monty committed
536
  /* residues */
Monty's avatar
 
Monty committed
537 538 539 540
  oggpack_write(opb,ci->residues-1,6);
  for(i=0;i<ci->residues;i++){
    oggpack_write(opb,ci->residue_type[i],16);
    _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
Monty's avatar
 
Monty committed
541 542
  }

Monty's avatar
 
Monty committed
543
  /* maps */
Monty's avatar
 
Monty committed
544 545 546 547
  oggpack_write(opb,ci->maps-1,6);
  for(i=0;i<ci->maps;i++){
    oggpack_write(opb,ci->map_type[i],16);
    _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
Monty's avatar
 
Monty committed
548
  }
Monty's avatar
 
Monty committed
549

Monty's avatar
 
Monty committed
550
  /* modes */
Monty's avatar
 
Monty committed
551 552 553 554 555 556
  oggpack_write(opb,ci->modes-1,6);
  for(i=0;i<ci->modes;i++){
    oggpack_write(opb,ci->mode_param[i]->blockflag,1);
    oggpack_write(opb,ci->mode_param[i]->windowtype,16);
    oggpack_write(opb,ci->mode_param[i]->transformtype,16);
    oggpack_write(opb,ci->mode_param[i]->mapping,8);
Monty's avatar
 
Monty committed
557
  }
Monty's avatar
 
Monty committed
558
  oggpack_write(opb,1,1);
Monty's avatar
 
Monty committed
559

Monty's avatar
 
Monty committed
560 561 562
  return(0);
err_out:
  return(-1);
Monty's avatar
Monty committed
563
}
Monty's avatar
 
Monty committed
564

Michael Smith's avatar
 
Michael Smith committed
565
int vorbis_commentheader_out(vorbis_comment *vc,
566
                                          ogg_packet *op){
Michael Smith's avatar
 
Michael Smith committed
567 568 569 570

  oggpack_buffer opb;

  oggpack_writeinit(&opb);
571 572 573 574
  if(_vorbis_pack_comment(&opb,vc)){
    oggpack_writeclear(&opb);
    return OV_EIMPL;
  }
Michael Smith's avatar
 
Michael Smith committed
575 576 577 578 579 580 581 582

  op->packet = _ogg_malloc(oggpack_bytes(&opb));
  memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));

  op->bytes=oggpack_bytes(&opb);
  op->b_o_s=0;
  op->e_o_s=0;
  op->granulepos=0;
583
  op->packetno=1;
Michael Smith's avatar
 
Michael Smith committed
584

585
  oggpack_writeclear(&opb);
Michael Smith's avatar
 
Michael Smith committed
586 587 588
  return 0;
}

Monty's avatar
 
Monty committed
589
int vorbis_analysis_headerout(vorbis_dsp_state *v,
590 591 592 593
                              vorbis_comment *vc,
                              ogg_packet *op,
                              ogg_packet *op_comm,
                              ogg_packet *op_code){
Monty's avatar
 
Monty committed
594
  int ret=OV_EIMPL;
Monty's avatar
 
Monty committed
595
  vorbis_info *vi=v->vi;
Monty's avatar
 
Monty committed
596
  oggpack_buffer opb;
Monty's avatar
 
Monty committed
597
  private_state *b=v->backend_state;
Monty's avatar
 
Monty committed
598

599
  if(!b||vi->channels<=0||vi->channels>256){
600
    b = NULL;
Monty's avatar
 
Monty committed
601 602 603
    ret=OV_EFAULT;
    goto err_out;
  }
Monty's avatar
 
Monty committed
604

Monty's avatar
 
Monty committed
605
  /* first header packet **********************************************/
Monty's avatar
 
Monty committed
606

Monty's avatar
 
Monty committed
607
  oggpack_writeinit(&opb);
Monty's avatar
 
Monty committed
608
  if(_vorbis_pack_info(&opb,vi))goto err_out;
Monty's avatar
 
Monty committed
609 610

  /* build the packet */
Monty's avatar
 
Monty committed
611
  if(b->header)_ogg_free(b->header);
Monty's avatar
 
Monty committed
612 613 614
  b->header=_ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
  op->packet=b->header;
Monty's avatar
 
Monty committed
615
  op->bytes=oggpack_bytes(&opb);
Monty's avatar
 
Monty committed
616 617
  op->b_o_s=1;
  op->e_o_s=0;
Monty's avatar
 
Monty committed
618
  op->granulepos=0;
619
  op->packetno=0;
Monty's avatar
 
Monty committed
620

Monty's avatar
 
Monty committed
621
  /* second header packet (comments) **********************************/
Monty's avatar
 
Monty committed
622

Monty's avatar
 
Monty committed
623
  oggpack_reset(&opb);
Monty's avatar
 
Monty committed
624
  if(_vorbis_pack_comment(&opb,vc))goto err_out;
Monty's avatar
 
Monty committed
625

Monty's avatar
 
Monty committed
626
  if(b->header1)_ogg_free(b->header1);
Monty's avatar
 
Monty committed
627 628 629
  b->header1=_ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
  op_comm->packet=b->header1;
Monty's avatar
 
Monty committed
630
  op_comm->bytes=oggpack_bytes(&opb);
Monty's avatar
 
Monty committed
631 632
  op_comm->b_o_s=0;
  op_comm->e_o_s=0;
Monty's avatar
 
Monty committed
633
  op_comm->granulepos=0;
634
  op_comm->packetno=1;
Monty's avatar
 
Monty committed
635

Monty's avatar
 
Monty committed
636
  /* third header packet (modes/codebooks) ****************************/
Monty's avatar
 
Monty committed
637

Monty's avatar
 
Monty committed
638
  oggpack_reset(&opb);
Monty's avatar
 
Monty committed
639
  if(_vorbis_pack_books(&opb,vi))goto err_out;
Monty's avatar
 
Monty committed
640

Monty's avatar
 
Monty committed
641
  if(b->header2)_ogg_free(b->header2);
Monty's avatar
 
Monty committed
642 643 644
  b->header2=_ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
  op_code->packet=b->header2;
Monty's avatar
 
Monty committed
645
  op_code->bytes=oggpack_bytes(&opb);
Monty's avatar
 
Monty committed
646 647
  op_code->b_o_s=0;
  op_code->e_o_s=0;
Monty's avatar
 
Monty committed
648
  op_code->granulepos=0;
649
  op_code->packetno=2;
Monty's avatar
 
Monty committed
650

Monty's avatar
 
Monty committed
651
  oggpack_writeclear(&opb);
Monty's avatar
 
Monty committed
652
  return(0);
Monty's avatar
 
Monty committed
653
 err_out:
654 655 656
  memset(op,0,sizeof(*op));
  memset(op_comm,0,sizeof(*op_comm));
  memset(op_code,0,sizeof(*op_code));
Monty's avatar
 
Monty committed
657

658
  if(b){
Tristan Matthews's avatar
Tristan Matthews committed
659
    if(vi->channels>0)oggpack_writeclear(&opb);
660 661 662 663 664 665 666
    if(b->header)_ogg_free(b->header);
    if(b->header1)_ogg_free(b->header1);
    if(b->header2)_ogg_free(b->header2);
    b->header=NULL;
    b->header1=NULL;
    b->header2=NULL;
  }
Monty's avatar
 
Monty committed
667
  return(ret);
Monty's avatar
 
Monty committed
668 669
}

Monty's avatar
 
Monty committed
670
double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){
671 672 673 674 675
  if(granulepos == -1) return -1;

  /* We're not guaranteed a 64 bit unsigned type everywhere, so we
     have to put the unsigned granpo in a signed type. */
  if(granulepos>=0){
Monty's avatar
 
Monty committed
676
    return((double)granulepos/v->vi->rate);
677 678 679 680 681 682
  }else{
    ogg_int64_t granuleoff=0xffffffff;
    granuleoff<<=31;
    granuleoff|=0x7ffffffff;
    return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate);
  }
Monty's avatar
 
Monty committed
683
}
684 685 686 687

const char *vorbis_version_string(void){
  return GENERAL_VENDOR_STRING;
}