speex_header.c 5.81 KB
Newer Older
Tristan Matthews's avatar
Tristan Matthews committed
1
/* Copyright (C) 2002 Jean-Marc Valin
jmvalin's avatar
jmvalin committed
2 3 4
   File: speex_header.c
   Describes the Speex header

jm's avatar
jm committed
5 6 7
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
Tristan Matthews's avatar
Tristan Matthews committed
8

jm's avatar
jm committed
9 10
   - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
Tristan Matthews's avatar
Tristan Matthews committed
11

jm's avatar
jm committed
12 13 14
   - Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
Tristan Matthews's avatar
Tristan Matthews committed
15

jm's avatar
jm committed
16 17 18
   - Neither the name of the Xiph.org Foundation nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.
Tristan Matthews's avatar
Tristan Matthews committed
19

jm's avatar
jm committed
20 21 22 23 24 25 26 27 28 29 30
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jmvalin's avatar
jmvalin committed
31 32 33

*/

34 35 36 37
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

jm's avatar
jm committed
38
#include "arch.h"
Ron's avatar
Ron committed
39 40
#include "speex/speex_header.h"
#include "speex/speex.h"
41
#include "os_support.h"
42 43 44 45

#ifndef NULL
#define NULL 0
#endif
jmvalin's avatar
jmvalin committed
46

jm's avatar
jm committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/** Convert little endian */
static inline spx_int32_t le_int(spx_int32_t i)
{
#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
   spx_uint32_t ui, ret;
   ui = i;
   ret =  ui>>24;
   ret |= (ui>>8)&0x0000ff00;
   ret |= (ui<<8)&0x00ff0000;
   ret |= (ui<<24);
   return ret;
#else
   return i;
#endif
}

jmvalin's avatar
jmvalin committed
63
#define ENDIAN_SWITCH(x) {x=le_int(x);}
64 65


jmvalin's avatar
jmvalin committed
66 67
/*
typedef struct SpeexHeader {
68
   char speex_string[8];
jmvalin's avatar
jmvalin committed
69
   char speex_version[SPEEX_HEADER_VERSION_LENGTH];
70
   int speex_version_id;
jmvalin's avatar
jmvalin committed
71 72 73
   int header_size;
   int rate;
   int mode;
74
   int mode_bitstream_version;
jmvalin's avatar
jmvalin committed
75 76 77 78
   int nb_channels;
   int bitrate;
   int frame_size;
   int vbr;
jmvalin's avatar
jmvalin committed
79
   int frames_per_packet;
80
   int extra_headers;
jmvalin's avatar
jmvalin committed
81 82 83 84 85
   int reserved1;
   int reserved2;
} SpeexHeader;
*/

86
EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
jmvalin's avatar
jmvalin committed
87
{
88
   int i;
89
   const char *h="Speex   ";
90
   /*
jmvalin's avatar
jmvalin committed
91
   strncpy(header->speex_string, "Speex   ", 8);
92
   strncpy(header->speex_version, SPEEX_VERSION, SPEEX_HEADER_VERSION_LENGTH-1);
jmvalin's avatar
jmvalin committed
93
   header->speex_version[SPEEX_HEADER_VERSION_LENGTH-1]=0;
94 95 96
   */
   for (i=0;i<8;i++)
      header->speex_string[i]=h[i];
97 98
   for (i=0;i<SPEEX_HEADER_VERSION_LENGTH-1 && SPEEX_VERSION[i];i++)
      header->speex_version[i]=SPEEX_VERSION[i];
99 100
   for (;i<SPEEX_HEADER_VERSION_LENGTH;i++)
      header->speex_version[i]=0;
Tristan Matthews's avatar
Tristan Matthews committed
101

102
   header->speex_version_id = 1;
jmvalin's avatar
jmvalin committed
103
   header->header_size = sizeof(SpeexHeader);
Tristan Matthews's avatar
Tristan Matthews committed
104

jmvalin's avatar
jmvalin committed
105
   header->rate = rate;
jmvalin's avatar
jmvalin committed
106
   header->mode = m->modeID;
107
   header->mode_bitstream_version = m->bitstream_version;
jmvalin's avatar
jmvalin committed
108
   if (m->modeID<0)
109
      speex_warning("This mode is meant to be used alone");
jmvalin's avatar
jmvalin committed
110
   header->nb_channels = nb_channels;
111 112 113
   header->bitrate = -1;
   speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size);
   header->vbr = 0;
Tristan Matthews's avatar
Tristan Matthews committed
114

jmvalin's avatar
jmvalin committed
115
   header->frames_per_packet = 0;
jm's avatar
oops...  
jm committed
116
   header->extra_headers = 0;
jmvalin's avatar
jmvalin committed
117 118 119 120
   header->reserved1 = 0;
   header->reserved2 = 0;
}

121
EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size)
jmvalin's avatar
jmvalin committed
122 123
{
   SpeexHeader *le_header;
124
   le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
Tristan Matthews's avatar
Tristan Matthews committed
125

126
   SPEEX_COPY(le_header, header, 1);
Tristan Matthews's avatar
Tristan Matthews committed
127

jmvalin's avatar
jmvalin committed
128
   /*Make sure everything is now little-endian*/
129
   ENDIAN_SWITCH(le_header->speex_version_id);
jmvalin's avatar
jmvalin committed
130 131 132
   ENDIAN_SWITCH(le_header->header_size);
   ENDIAN_SWITCH(le_header->rate);
   ENDIAN_SWITCH(le_header->mode);
133
   ENDIAN_SWITCH(le_header->mode_bitstream_version);
jmvalin's avatar
jmvalin committed
134 135 136 137
   ENDIAN_SWITCH(le_header->nb_channels);
   ENDIAN_SWITCH(le_header->bitrate);
   ENDIAN_SWITCH(le_header->frame_size);
   ENDIAN_SWITCH(le_header->vbr);
jmvalin's avatar
jmvalin committed
138
   ENDIAN_SWITCH(le_header->frames_per_packet);
139
   ENDIAN_SWITCH(le_header->extra_headers);
jmvalin's avatar
jmvalin committed
140 141 142 143 144

   *size = sizeof(SpeexHeader);
   return (char *)le_header;
}

145
EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size)
jmvalin's avatar
jmvalin committed
146
{
147
   int i;
jmvalin's avatar
jmvalin committed
148
   SpeexHeader *le_header;
149
   const char *h = "Speex   ";
150

151
   /*FIXME: Do we allow larger headers?*/
152
   if (size < (int)sizeof(SpeexHeader))
jmvalin's avatar
jmvalin committed
153
   {
154
      speex_notify("Speex header too small");
jmvalin's avatar
jmvalin committed
155
      return NULL;
jmvalin's avatar
jmvalin committed
156
   }
157 158 159 160 161


   for (i=0;i<8;i++)
      if (packet[i]!=h[i])
      {
162
         /* This doesn't look like a Speex file */
163 164 165
         return NULL;
      }

166
   le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
Tristan Matthews's avatar
Tristan Matthews committed
167

168
   SPEEX_COPY(le_header, (SpeexHeader*)packet, 1);
Tristan Matthews's avatar
Tristan Matthews committed
169

jmvalin's avatar
jmvalin committed
170
   /*Make sure everything is converted correctly from little-endian*/
171
   ENDIAN_SWITCH(le_header->speex_version_id);
jmvalin's avatar
jmvalin committed
172 173 174
   ENDIAN_SWITCH(le_header->header_size);
   ENDIAN_SWITCH(le_header->rate);
   ENDIAN_SWITCH(le_header->mode);
175
   ENDIAN_SWITCH(le_header->mode_bitstream_version);
jmvalin's avatar
jmvalin committed
176 177 178 179
   ENDIAN_SWITCH(le_header->nb_channels);
   ENDIAN_SWITCH(le_header->bitrate);
   ENDIAN_SWITCH(le_header->frame_size);
   ENDIAN_SWITCH(le_header->vbr);
jmvalin's avatar
jmvalin committed
180
   ENDIAN_SWITCH(le_header->frames_per_packet);
181
   ENDIAN_SWITCH(le_header->extra_headers);
jmvalin's avatar
jmvalin committed
182

183 184 185 186 187 188 189
   if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0)
   {
      speex_notify("Invalid mode specified in Speex header");
      speex_free (le_header);
      return NULL;
   }

190 191 192 193 194
   if (le_header->nb_channels>2)
      le_header->nb_channels = 2;
   if (le_header->nb_channels<1)
      le_header->nb_channels = 1;

jmvalin's avatar
jmvalin committed
195 196 197
   return le_header;

}
198

199
EXPORT void speex_header_free(void *ptr)
200 201 202
{
   speex_free(ptr);
}