More init code, silencing warnings
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Tue, 25 Apr 2017 04:33:41 +0000 (00:33 -0400)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Tue, 25 Apr 2017 04:40:33 +0000 (00:40 -0400)
Makefile.am
include/opusenc.h
src/opus_header.c [new file with mode: 0644]
src/opus_header.h [new file with mode: 0644]
src/opusenc.c

index a0d91a4..22ed680 100644 (file)
@@ -9,6 +9,7 @@ opusinclude_HEADERS = include/opusenc.h
 
 lib_LTLIBRARIES = libopusenc.la
 libopusenc_la_SOURCES = \
+       src/opus_header.c \
        src/opusenc.c
 libopusenc_la_LIBADD = $(DEPS_LIBS) $(lrintf_lib)
 libopusenc_la_LDFLAGS = -no-undefined \
index f26cc04..23914eb 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 
 #define OPE_OK 0
 #define OPE_ERROR_CANNOT_OPEN -10
+#define OPE_ERROR_UNIMPLEMENTED -11
 
 typedef int (*ope_write_func)(void *user_data, const unsigned char *ptr, int len);
 
@@ -70,7 +71,7 @@ int ope_write(OggOpusEnc *enc, opus_int16 *pcm, int samples_per_channel);
 int ope_close_and_free(OggOpusEnc *enc);
 
 /** Ends the stream and create a new stream within the same file. */
-int ope_chain_current(OggOpusEnc *enc);
+int ope_chain_current(OggOpusEnc *enc, const OggOpusComments *comments);
 
 /** Ends the stream and create a new file. */
 int ope_continue_new_file(OggOpusEnc *enc, const OggOpusComments *comments, const char *path);
diff --git a/src/opus_header.c b/src/opus_header.c
new file mode 100644 (file)
index 0000000..3861405
--- /dev/null
@@ -0,0 +1,171 @@
+/* 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 "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 = total 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;
+}
+
+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) */
+};
diff --git a/src/opus_header.h b/src/opus_header.h
new file mode 100644 (file)
index 0000000..b0ab2fb
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C)2012 Xiph.Org Foundation
+   File: opus_header.h
+
+   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.
+*/
+
+#ifndef OPUS_HEADER_H
+#define OPUS_HEADER_H
+
+#include <ogg/ogg.h>
+
+typedef struct {
+   int version;
+   int channels; /* Number of channels: 1..255 */
+   int preskip;
+   ogg_uint32_t input_sample_rate;
+   int gain; /* in dB S7.8 should be zero whenever possible */
+   int channel_mapping;
+   /* The rest is only used if channel_mapping != 0 */
+   int nb_streams;
+   int nb_coupled;
+   unsigned char stream_map[255];
+} OpusHeader;
+
+int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len);
+
+extern const int wav_permute_matrix[8][8];
+
+#endif
index 22e0d70..0b072c9 100644 (file)
 
 #include <stdlib.h>
 #include <stdio.h>
-#include "opusenc.h"
 #include <opus_multistream.h>
+#include "opusenc.h"
+#include "opus_header.h"
 
 struct StdioObject {
   FILE *file;
 };
 
 struct OggOpusEnc {
-  OpusMSEncoder *enc;
+  OpusMSEncoder *st;
+  float *buffer;
+  OpusEncCallbacks callbacks;
+  void *user_data;
 };
 
 int stdio_write(void *user_data, const unsigned char *ptr, int len) {
   struct StdioObject *obj = (struct StdioObject*)user_data;
-  return fwrite(ptr, 1, len, obj->file) != len;
+  return fwrite(ptr, 1, len, obj->file) != (size_t)len;
 }
 
 int stdio_close(void *user_data) {
@@ -58,7 +62,7 @@ int stdio_close(void *user_data) {
 
 static const OpusEncCallbacks stdio_callbacks = {
   stdio_write,
-  fclose
+  stdio_close
 };
 
 /* Create a new OggOpus file. */
@@ -84,50 +88,100 @@ OggOpusEnc *ope_create_file(const char *path, const OggOpusComments *comments,
 /* Create a new OggOpus file (callback-based). */
 OggOpusEnc *ope_create_callbacks(const OpusEncCallbacks *callbacks, void *user_data,
     const OggOpusComments *comments, int rate, int channels, int family, int *error) {
+  OpusMSEncoder *st=NULL;
+  OggOpusEnc *enc=NULL;
+  OpusHeader header;
+  int ret;
+  if (family != 0 && family != 1 && family != 255) {
+    if (error) *error = OPE_ERROR_UNIMPLEMENTED;
+    return NULL;
+  }
+  header.channels=channels;
+  header.channel_mapping=family;
+  header.input_sample_rate=rate;
+  header.gain=0;
+  st=opus_multistream_surround_encoder_create(48000, channels, header.channel_mapping, &header.nb_streams, &header.nb_coupled,
+     header.stream_map, OPUS_APPLICATION_AUDIO, &ret);
+  if (! (ret == OPUS_OK && st != NULL) ) {
+    goto fail;
+  }
+  if ( (enc = malloc(sizeof(*enc))) == NULL) goto fail;
+  enc->st = st;
+  enc->callbacks = *callbacks;
+  enc->user_data = user_data;
+  (void)comments;
+  return enc;
+fail:
+  if (enc) {
+    free(enc);
+  }
+  if (st) {
+    opus_multistream_encoder_destroy(st);
+  }
   return NULL;
 }
 
 /* Add/encode any number of float samples to the file. */
 int ope_write_float(OggOpusEnc *enc, float *pcm, int samples_per_channel) {
+  (void)enc;
+  (void)pcm;
+  (void)samples_per_channel;
   return 0;
 }
 
 /* Add/encode any number of int16 samples to the file. */
 int ope_write(OggOpusEnc *enc, opus_int16 *pcm, int samples_per_channel) {
+  (void)enc;
+  (void)pcm;
+  (void)samples_per_channel;
   return 0;
 }
 
 static void finalize_stream(OggOpusEnc *enc) {
+  (void)enc;
 }
 
 /* Close/finalize the stream. */
 int ope_close_and_free(OggOpusEnc *enc) {
   finalize_stream(enc);
-  opus_encoder_destroy(enc);
+  free(enc->buffer);
+  opus_multistream_encoder_destroy(enc->st);
   return OPE_OK;
 }
 
 /* Ends the stream and create a new stream within the same file. */
-int ope_chain_current(OggOpusEnc *enc) {
+int ope_chain_current(OggOpusEnc *enc, const OggOpusComments *comments) {
+  (void)enc;
+  (void)comments;
   return 0;
 }
 
 /* Ends the stream and create a new file. */
 int ope_continue_new_file(OggOpusEnc *enc, const OggOpusComments *comments, const char *path) {
+  (void)enc;
+  (void)comments;
+  (void)path;
   return 0;
 }
 
 /* Ends the stream and create a new file (callback-based). */
 int ope_continue_new_callbacks(OggOpusEnc *enc, const OggOpusComments *comments, void *user_data) {
+  (void)enc;
+  (void)comments;
+  (void)user_data;
   return 0;
 }
 
 /* Goes straight to the libopus ctl() functions. */
 int ope_encoder_ctl(OggOpusEnc *enc, int request, ...) {
+  (void)enc;
+  (void)request;
   return 0;
 }
 
 /* ctl()-type call for the OggOpus layer. */
 int ope_set_params(OggOpusEnc *enc, int request, ...) {
+  (void)enc;
+  (void)request;
   return 0;
 }