diff options
Diffstat (limited to 'lib/rbcodec/codecs/libopus/opus_header.c')
| -rw-r--r-- | lib/rbcodec/codecs/libopus/opus_header.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libopus/opus_header.c b/lib/rbcodec/codecs/libopus/opus_header.c new file mode 100644 index 0000000..ed07c9a --- /dev/null +++ b/lib/rbcodec/codecs/libopus/opus_header.c @@ -0,0 +1,286 @@ +/* Copyright (C)2012 Xiph.Org Foundation + File: opus_header.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - 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. + + 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. +*/ + +#ifdef HAVE_CONFIG_H +# include "opus_config.h" +#endif + +#include "opus_header.h" +#include <string.h> +#include <stdio.h> + +/* Header contents: + - "OpusHead" (64 bits) + - version number (8 bits) + - Channels C (8 bits) + - Pre-skip (16 bits) + - Sampling rate (32 bits) + - Gain in dB (16 bits, S7.8) + - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping, + 2..254: reserved, 255: multistream with no mapping) + + - if (mapping != 0) + - N = totel number of streams (8 bits) + - M = number of paired streams (8 bits) + - C times channel origin + - if (C<2*M) + - stream = byte/2 + - if (byte&0x1 == 0) + - left + else + - right + - else + - stream = byte-M +*/ + +typedef struct { + unsigned char *data; + int maxlen; + int pos; +} Packet; + +typedef struct { + const unsigned char *data; + int maxlen; + int pos; +} ROPacket; + +static int write_uint32(Packet *p, ogg_uint32_t val) +{ + if (p->pos>p->maxlen-4) + return 0; + p->data[p->pos ] = (val ) & 0xFF; + p->data[p->pos+1] = (val>> 8) & 0xFF; + p->data[p->pos+2] = (val>>16) & 0xFF; + p->data[p->pos+3] = (val>>24) & 0xFF; + p->pos += 4; + return 1; +} + +static int write_uint16(Packet *p, ogg_uint16_t val) +{ + if (p->pos>p->maxlen-2) + return 0; + p->data[p->pos ] = (val ) & 0xFF; + p->data[p->pos+1] = (val>> 8) & 0xFF; + p->pos += 2; + return 1; +} + +static int write_chars(Packet *p, const unsigned char *str, int nb_chars) +{ + int i; + if (p->pos>p->maxlen-nb_chars) + return 0; + for (i=0;i<nb_chars;i++) + p->data[p->pos++] = str[i]; + return 1; +} + +static int read_uint32(ROPacket *p, ogg_uint32_t *val) +{ + if (p->pos>p->maxlen-4) + return 0; + *val = (ogg_uint32_t)p->data[p->pos ]; + *val |= (ogg_uint32_t)p->data[p->pos+1]<< 8; + *val |= (ogg_uint32_t)p->data[p->pos+2]<<16; + *val |= (ogg_uint32_t)p->data[p->pos+3]<<24; + p->pos += 4; + return 1; +} + +static int read_uint16(ROPacket *p, ogg_uint16_t *val) +{ + if (p->pos>p->maxlen-2) + return 0; + *val = (ogg_uint16_t)p->data[p->pos ]; + *val |= (ogg_uint16_t)p->data[p->pos+1]<<8; + p->pos += 2; + return 1; +} + +static int read_chars(ROPacket *p, unsigned char *str, int nb_chars) +{ + int i; + if (p->pos>p->maxlen-nb_chars) + return 0; + for (i=0;i<nb_chars;i++) + str[i] = p->data[p->pos++]; + return 1; +} + +int opus_header_parse(const unsigned char *packet, int len, OpusHeader *h) +{ + int i; + char str[9]; + ROPacket p; + unsigned char ch; + ogg_uint16_t shortval; + + p.data = packet; + p.maxlen = len; + p.pos = 0; + str[8] = 0; + if (len<19)return 0; + read_chars(&p, (unsigned char*)str, 8); + if (memcmp(str, "OpusHead", 8)!=0) + return 0; + + if (!read_chars(&p, &ch, 1)) + return 0; + h->version = ch; + if((h->version&240) != 0) /* Only major version 0 supported. */ + return 0; + + if (!read_chars(&p, &ch, 1)) + return 0; + h->channels = ch; + if (h->channels == 0) + return 0; + + if (!read_uint16(&p, &shortval)) + return 0; + h->preskip = shortval; + + if (!read_uint32(&p, &h->input_sample_rate)) + return 0; + + if (!read_uint16(&p, &shortval)) + return 0; + h->gain = (short)shortval; + + if (!read_chars(&p, &ch, 1)) + return 0; + h->channel_mapping = ch; + + if (h->channel_mapping != 0) + { + if (!read_chars(&p, &ch, 1)) + return 0; + + if (ch<1) + return 0; + h->nb_streams = ch; + + if (!read_chars(&p, &ch, 1)) + return 0; + + if (ch>h->nb_streams || (ch+h->nb_streams)>255) + return 0; + h->nb_coupled = ch; + + /* Multi-stream support */ + for (i=0;i<h->channels;i++) + { + if (!read_chars(&p, &h->stream_map[i], 1)) + return 0; + if (h->stream_map[i]>(h->nb_streams+h->nb_coupled) && h->stream_map[i]!=255) + return 0; + } + } else { + if(h->channels>2) + return 0; + h->nb_streams = 1; + h->nb_coupled = h->channels>1; + h->stream_map[0]=0; + h->stream_map[1]=1; + } + /*For version 0/1 we know there won't be any more data + so reject any that have data past the end.*/ + if ((h->version==0 || h->version==1) && p.pos != len) + return 0; + return 1; +} + +int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len) +{ + int i; + Packet p; + unsigned char ch; + + p.data = packet; + p.maxlen = len; + p.pos = 0; + if (len<19)return 0; + if (!write_chars(&p, (const unsigned char*)"OpusHead", 8)) + return 0; + /* Version is 1 */ + ch = 1; + if (!write_chars(&p, &ch, 1)) + return 0; + + ch = h->channels; + if (!write_chars(&p, &ch, 1)) + return 0; + + if (!write_uint16(&p, h->preskip)) + return 0; + + if (!write_uint32(&p, h->input_sample_rate)) + return 0; + + if (!write_uint16(&p, h->gain)) + return 0; + + ch = h->channel_mapping; + if (!write_chars(&p, &ch, 1)) + return 0; + + if (h->channel_mapping != 0) + { + ch = h->nb_streams; + if (!write_chars(&p, &ch, 1)) + return 0; + + ch = h->nb_coupled; + if (!write_chars(&p, &ch, 1)) + return 0; + + /* Multi-stream support */ + for (i=0;i<h->channels;i++) + { + if (!write_chars(&p, &h->stream_map[i], 1)) + return 0; + } + } + + return p.pos; +} + +/* This is just here because it's a convenient file linked by both opusenc and + opusdec (to guarantee this maps stays in sync). */ +const int wav_permute_matrix[8][8] = +{ + {0}, /* 1.0 mono */ + {0,1}, /* 2.0 stereo */ + {0,2,1}, /* 3.0 channel ('wide') stereo */ + {0,1,2,3}, /* 4.0 discrete quadraphonic */ + {0,2,1,3,4}, /* 5.0 surround */ + {0,2,1,4,5,3}, /* 5.1 surround */ + {0,2,1,5,6,4,3}, /* 6.1 surround */ + {0,2,1,6,7,4,5,3} /* 7.1 surround (classic theater 8-track) */ +}; |