ref: 17acb8ae08eec813d4ad6cab36d5dd62a0eeeecd
parent: de802c33bd4bbddddc9b34421cb5278d5720e8d4
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Mon Apr 24 20:33:41 EDT 2017
More init code, silencing warnings
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,6 +9,7 @@
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 \
--- a/include/opusenc.h
+++ b/include/opusenc.h
@@ -36,6 +36,7 @@
#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_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);
--- /dev/null
+++ b/src/opus_header.c
@@ -1,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) */
+};
--- /dev/null
+++ b/src/opus_header.h
@@ -1,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
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -33,8 +33,9 @@
#include <stdlib.h>
#include <stdio.h>
-#include "opusenc.h"
#include <opus_multistream.h>
+#include "opusenc.h"
+#include "opus_header.h"
struct StdioObject {
FILE *file;
@@ -41,12 +42,15 @@
};
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 @@
static const OpusEncCallbacks stdio_callbacks = {
stdio_write,
- fclose
+ stdio_close
};
/* Create a new OggOpus file. */
@@ -84,50 +88,100 @@
/* 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;
}