audiod_command.c: Trivial whitespace fix.
[paraslash.git] / opus_common.c
index e69de29..927df1f 100644 (file)
@@ -0,0 +1,169 @@
+/* Copyright (C)2012 Xiph.Org Foundation
+ *
+ * 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.
+ */
+
+/**
+ * \file opus_common.c Common functions of the opus decoder and audio format
+ * handler.
+ */
+
+#include <ogg/ogg.h>
+
+#include "para.h"
+#include "error.h"
+#include "opus_common.h"
+#include "portable_io.h"
+
+struct packet {
+       const char *data;
+       int maxlen;
+       int pos;
+};
+
+static int read_chars(struct packet *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;
+}
+
+static int read_uint32(struct packet *p, ogg_uint32_t *val)
+{
+       if (p->pos > p->maxlen - 4)
+               return 0;
+       *val = read_u32(p->data + p->pos);
+       p->pos += 4;
+       return 1;
+}
+
+static int read_uint16(struct packet *p, ogg_uint16_t *val)
+{
+       if (p->pos > p->maxlen - 2)
+               return 0;
+       *val = read_u16(p->data + p->pos);
+       p->pos += 2;
+       return 1;
+}
+
+/**
+ * Get metadata of an opus stream.
+ *
+ * This is called from both the audio format handler (which passes ogg packet
+ * 0) and from the decoder.
+ *
+ * \param packet Start of the packet.
+ * \param len Number of bytes.
+ * \param h Result.
+ *
+ * \return Standard.
+ */
+int opus_parse_header(const char *packet, int len, struct opus_header *h)
+{
+       int i;
+       char str[9];
+       struct packet p;
+       unsigned char ch, channel_mapping;
+       ogg_uint16_t shortval;
+
+       p.data = packet;
+       p.maxlen = len;
+       p.pos = 0;
+       str[8] = 0;
+       if (len < 19)
+               return -E_OPUS_HEADER;
+       read_chars(&p, (unsigned char*)str, 8);
+       if (memcmp(str, "OpusHead", 8) != 0)
+               return -E_OPUS_HEADER;
+
+       if (!read_chars(&p, &ch, 1))
+               return -E_OPUS_HEADER;
+       h->version = ch;
+       if((h->version & 240) != 0) /* Only major version 0 supported. */
+               return -E_OPUS_HEADER;
+
+       if (!read_chars(&p, &ch, 1))
+               return -E_OPUS_HEADER;
+       h->channels = ch;
+       if (h->channels == 0)
+               return -E_OPUS_HEADER;
+
+       if (!read_uint16(&p, &shortval))
+               return -E_OPUS_HEADER;
+       h->preskip = shortval;
+
+       if (!read_uint32(&p, &h->input_sample_rate))
+               return -E_OPUS_HEADER;
+
+       if (!read_uint16(&p, &shortval))
+               return -E_OPUS_HEADER;
+       h->gain = (short)shortval;
+
+       if (!read_chars(&p, &ch, 1))
+               return -E_OPUS_HEADER;
+       channel_mapping = ch;
+
+       if (channel_mapping != 0) {
+               if (!read_chars(&p, &ch, 1))
+                       return -E_OPUS_HEADER;
+
+               if (ch < 1)
+                       return -E_OPUS_HEADER;
+               h->nb_streams = ch;
+
+               if (!read_chars(&p, &ch, 1))
+                       return -E_OPUS_HEADER;
+
+               if (ch > h->nb_streams || (ch + h->nb_streams) > 255)
+                       return -E_OPUS_HEADER;
+               h->nb_coupled = ch;
+
+               /* Multi-stream support */
+               for (i = 0; i < h->channels; i++) {
+                       if (!read_chars(&p, &h->stream_map[i], 1))
+                               return -E_OPUS_HEADER;
+                       if (h->stream_map[i] > (h->nb_streams + h->nb_coupled)
+                                       && h->stream_map[i] != 255)
+                               return -E_OPUS_HEADER;
+               }
+       } else {
+               if (h->channels > 2)
+                       return -E_OPUS_HEADER;
+               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 -E_OPUS_HEADER;
+       return 1;
+}