ref: ba73b31b9d98584ef704552e0488e8a0a479cbed
parent: ccd67677f91db97d1d65f79ae05ba4df224cb75b
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Fri Feb 2 14:42:14 EST 2018
Add ope_encoder_deferred_init_with_mapping() Makes it possible to manually specify a channel mapping
--- a/include/opusenc.h
+++ b/include/opusenc.h
@@ -264,6 +264,17 @@
*/
OPE_EXPORT OggOpusEnc *ope_encoder_create_pull(OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error);
+/** Deferred initialization of the encoder to force an explicit channel mapping.
+ \param[in,out] enc Encoder
+ \param family Mapping family (0 for mono/stereo, 1 for surround)
+ \param streams Total number of streams
+ \param coupled_streams Number of coupled streams
+ \param mapping Channel mapping
+ \return Error code
+ */
+OPE_EXPORT int ope_encoder_deferred_init_with_mapping(OggOpusEnc *enc, int family, int streams,
+ int coupled_streams, const unsigned char *mapping);
+
/** Add/encode any number of float samples to the stream.
\param[in,out] enc Encoder
\param pcm Floating-point PCM values in the +/-1 range (interleaved if multiple channels)
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -283,7 +283,7 @@
OpusMSEncoder *st=NULL;
OggOpusEnc *enc=NULL;
int ret;
- if (family != 0 && family != 1 && family != 255) {
+ if (family != 0 && family != 1 && family != 255 && family != -1) {
if (error) *error = OPE_UNIMPLEMENTED;
return NULL;
}
@@ -302,7 +302,8 @@
if ( (enc->streams = stream_create(comments)) == NULL) goto fail;
enc->last_stream = enc->streams;
enc->oggp = NULL;
- enc->unrecoverable = 0;
+ /* Not initializing anything is an unrecoverable error. */
+ enc->unrecoverable = family == -1;
enc->pull_api = 0;
enc->packet_callback = NULL;
enc->rate = rate;
@@ -317,11 +318,15 @@
enc->header.channel_mapping=family;
enc->header.input_sample_rate=rate;
enc->header.gain=0;
- st=opus_multistream_surround_encoder_create(48000, channels, enc->header.channel_mapping,
- &enc->header.nb_streams, &enc->header.nb_coupled,
- enc->header.stream_map, OPUS_APPLICATION_AUDIO, &ret);
- if (! (ret == OPUS_OK && st != NULL) ) {
- goto fail;
+ if (family != -1) {
+ st=opus_multistream_surround_encoder_create(48000, channels, enc->header.channel_mapping,
+ &enc->header.nb_streams, &enc->header.nb_coupled,
+ enc->header.stream_map, OPUS_APPLICATION_AUDIO, &ret);
+ if (! (ret == OPUS_OK && st != NULL) ) {
+ goto fail;
+ }
+ enc->st = st;
+ opus_multistream_encoder_ctl(st, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
}
if (rate != 48000) {
enc->re = speex_resampler_init(channels, rate, 48000, 5, NULL);
@@ -330,7 +335,6 @@
} else {
enc->re = NULL;
}
- opus_multistream_encoder_ctl(st, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
enc->global_granule_offset = -1;
enc->curr_granule = 0;
enc->write_granule = 0;
@@ -343,7 +347,6 @@
memset(enc->lpc_buffer, 0, sizeof(*enc->lpc_buffer)*LPC_INPUT*channels);
}
enc->buffer_start = enc->buffer_end = 0;
- enc->st = st;
if (callbacks != NULL)
{
enc->callbacks = *callbacks;
@@ -372,6 +375,32 @@
return enc;
}
+int ope_encoder_deferred_init_with_mapping(OggOpusEnc *enc, int family, int streams,
+ int coupled_streams, const unsigned char *mapping) {
+ int ret;
+ int i;
+ OpusMSEncoder *st;
+ if (enc->st!=NULL) {
+ return OPE_TOO_LATE;
+ }
+ if (streams <= 0 || streams>255 || coupled_streams<0 || coupled_streams >= 128 || streams+coupled_streams > 255) return OPE_BAD_ARG;
+ st=opus_multistream_encoder_create(48000, enc->channels, streams, coupled_streams, mapping, OPUS_APPLICATION_AUDIO, &ret);
+ if (! (ret == OPUS_OK && st != NULL) ) {
+ goto fail;
+ }
+ enc->st = st;
+ opus_multistream_encoder_ctl(st, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS));
+ enc->unrecoverable = 0;
+ enc->header.channel_mapping=family;
+ enc->header.nb_streams = streams;
+ enc->header.nb_coupled = coupled_streams;
+ for (i=0;i<streams+coupled_streams;i++)
+ enc->header.stream_map[i] = mapping[i];
+ return OPE_OK;
+fail:
+ return OPE_ALLOC_FAIL;
+}
+
static void init_stream(OggOpusEnc *enc) {
assert(!enc->streams->stream_is_init);
if (!enc->streams->serialno_is_set) {
@@ -699,7 +728,7 @@
if (enc->chaining_keyframe) free(enc->chaining_keyframe);
free(enc->buffer);
if (enc->oggp) oggp_destroy(enc->oggp);
- opus_multistream_encoder_destroy(enc->st);
+ if (enc->st) opus_multistream_encoder_destroy(enc->st);
if (enc->re) speex_resampler_destroy(enc->re);
if (enc->lpc_buffer) free(enc->lpc_buffer);
free(enc);