From 35f9b25fbe5dd086b6fab0276d00491b4783cd64 Mon Sep 17 00:00:00 2001
From: Andrew Allen <bitllama@google.com>
Date: Wed, 28 Mar 2018 14:48:46 -0700
Subject: [PATCH] Support for Ambisonics and OpusProjection* API.
---
libavcodec/libopusdec.c | 159 ++++++++++++++++++++-----
libavcodec/libopusenc.c | 253 ++++++++++++++++++++++++++++++++++------
libavcodec/opus.c | 18 ++-
3 files changed, 350 insertions(+), 80 deletions(-)
@@ -21,6 +21,9 @@
#include <opus.h>
#include <opus_multistream.h>
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+#include <opus_projection.h>
+#endif
#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
@@ -33,9 +36,89 @@
#include "mathops.h"
#include "libopus.h"
+typedef struct OpusGenericDecoder {
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ OpusProjectionDecoder *pr;
+#endif
+ OpusMSDecoder *ms;
+} OpusGenericDecoder;
+
+static int libopus_generic_decoder_init(OpusGenericDecoder *enc, int Fs,
+ int channels, int nb_streams,
+ int nb_coupled, uint8_t *mapping,
+ uint8_t *dmatrix) {
+ int err;
+ if (dmatrix != NULL) {
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ opus_int32 size;
+ size = 2 * channels * (nb_streams + nb_coupled);
+ enc->pr = opus_projection_decoder_create(Fs, channels, nb_streams,
+ nb_coupled, dmatrix, size, &err);
+#else
+ err = OPUS_UNIMPLEMENTED;
+#endif
+ return err;
+ }
+ enc->ms = opus_multistream_decoder_create(Fs, channels, nb_streams,
+ nb_coupled, mapping, &err);
+ return err;
+}
+
+static void libopus_generic_decoder_cleanup(OpusGenericDecoder *enc)
+{
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr) opus_projection_decoder_destroy(enc->pr);
+#endif
+ if (enc->ms) opus_multistream_decoder_destroy(enc->ms);
+}
+
+static int libopus_generic_decode(OpusGenericDecoder *enc,
+ const unsigned char *data, opus_int32 len, opus_int16 *pcm,
+ int frame_size, int decode_fec) {
+ int ret;
+
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr){
+ ret=opus_projection_decode(enc->pr, data, len, pcm, frame_size,
+ decode_fec);
+ return ret;
+ }
+#endif
+ ret=opus_multistream_decode(enc->ms, data, len, pcm, frame_size,
+ decode_fec);
+ return ret;
+}
+
+static int libopus_generic_decode_float(OpusGenericDecoder *enc,
+ const unsigned char *data, opus_int32 len, float *pcm, int frame_size,
+ int decode_fec) {
+ int ret;
+
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr){
+ ret=opus_projection_decode_float(enc->pr, data, len, pcm, frame_size,
+ decode_fec);
+ return ret;
+ }
+#endif
+ ret=opus_multistream_decode_float(enc->ms, data, len, pcm, frame_size,
+ decode_fec);
+ return ret;
+}
+
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+# define libopus_generic_decoder_ctl(enc, request) \
+ ((enc)->pr != NULL ? \
+ opus_projection_decoder_ctl((enc)->pr, request) : \
+ opus_multistream_decoder_ctl((enc)->ms, request))
+#else
+# define libopus_generic_decoder_ctl(enc, request) \
+ opus_multistream_decoder_ctl((enc)->ms, request)
+#endif
+
struct libopus_context {
AVClass *class;
- OpusMSDecoder *dec;
+ OpusGenericDecoder dec;
int pre_skip;
#ifndef OPUS_SET_GAIN
union { int i; double d; } gain;
@@ -46,12 +129,17 @@ struct libopus_context {
};
#define OPUS_HEAD_SIZE 19
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+# define OPUS_MAX_CHANNELS 18
+#else
+# define OPUS_MAX_CHANNELS 8
+#endif
static av_cold int libopus_decode_init(AVCodecContext *avc)
{
struct libopus_context *opus = avc->priv_data;
int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled;
- uint8_t mapping_arr[8] = { 0, 1 }, *mapping;
+ uint8_t mapping_arr[OPUS_MAX_CHANNELS] = { 0, 1 }, *mapping, *dmatrix = NULL;
avc->channels = avc->extradata_size >= 10 ? avc->extradata[9] : (avc->channels == 1) ? 1 : 2;
if (avc->channels <= 0) {
@@ -74,7 +162,21 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1];
if (nb_streams + nb_coupled != avc->channels)
av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n");
- mapping = avc->extradata + OPUS_HEAD_SIZE + 2;
+ if (channel_map == 3) {
+ int ch;
+ if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + 2 * avc->channels * (nb_streams + nb_coupled)) {
+ dmatrix =avc->extradata + OPUS_HEAD_SIZE + 2;
+ } else {
+ av_log(avc, AV_LOG_ERROR,
+ "Demixing matrix not present.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (ch = 0; ch < avc->channels; ch++)
+ mapping_arr[ch] = ch;
+ mapping = mapping_arr;
+ } else {
+ mapping = avc->extradata + OPUS_HEAD_SIZE + 2;
+ }
} else {
if (avc->channels > 2 || channel_map) {
av_log(avc, AV_LOG_ERROR,
@@ -98,18 +200,15 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
mapping_arr[ch] = mapping[vorbis_offset[ch]];
mapping = mapping_arr;
}
- } else if (channel_map == 2) {
- int ambisonic_order = ff_sqrt(avc->channels) - 1;
- if (avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) &&
- avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) + 2) {
+ } else if (channel_map == 2 || channel_map == 3) {
+ int order_plus_one = ff_sqrt(avc->channels);
+ int nondiegetic_channels = avc->channels - order_plus_one * order_plus_one;
+ if (order_plus_one < 1 || order_plus_one > 15 ||
+ (nondiegetic_channels != 0 && nondiegetic_channels != 2)) {
av_log(avc, AV_LOG_ERROR,
- "Channel mapping 2 is only specified for channel counts"
- " which can be written as (n + 1)^2 or (n + 2)^2 + 2"
- " for nonnegative integer n\n");
- return AVERROR_INVALIDDATA;
- }
- if (avc->channels > 227) {
- av_log(avc, AV_LOG_ERROR, "Too many channels\n");
+ "This channel mapping is only specified for channel counts"
+ " which can be written as (n + 1)^2 + 2j, where n is a"
+ " non-negative integar from 0 to 14 and j is either 0 or 1.\n");
return AVERROR_INVALIDDATA;
}
avc->channel_layout = 0;
@@ -117,17 +216,16 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
avc->channel_layout = 0;
}
- opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels,
- nb_streams, nb_coupled,
- mapping, &ret);
- if (!opus->dec) {
+ ret = libopus_generic_decoder_init(&opus->dec, avc->sample_rate, avc->channels,
+ nb_streams, nb_coupled, mapping, dmatrix);
+ if (ret != OPUS_OK) {
av_log(avc, AV_LOG_ERROR, "Unable to create decoder: %s\n",
opus_strerror(ret));
return ff_opus_error_to_averror(ret);
}
#ifdef OPUS_SET_GAIN
- ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db));
+ ret = libopus_generic_decoder_ctl(&opus->dec, OPUS_SET_GAIN(gain_db));
if (ret != OPUS_OK)
av_log(avc, AV_LOG_WARNING, "Failed to set gain: %s\n",
opus_strerror(ret));
@@ -142,8 +240,8 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
#endif
#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST
- ret = opus_multistream_decoder_ctl(opus->dec,
- OPUS_SET_PHASE_INVERSION_DISABLED(!opus->apply_phase_inv));
+ ret = libopus_generic_decoder_ctl(&opus->dec,
+ OPUS_SET_PHASE_INVERSION_DISABLED(!opus->apply_phase_inv));
if (ret != OPUS_OK)
av_log(avc, AV_LOG_WARNING,
"Unable to set phase inversion: %s\n",
@@ -160,10 +258,7 @@ static av_cold int libopus_decode_close(AVCodecContext *avc)
{
struct libopus_context *opus = avc->priv_data;
- if (opus->dec) {
- opus_multistream_decoder_destroy(opus->dec);
- opus->dec = NULL;
- }
+ libopus_generic_decoder_cleanup(&opus->dec);
return 0;
}
@@ -181,13 +276,13 @@ static int libopus_decode(AVCodecContext *avc, void *data,
return ret;
if (avc->sample_fmt == AV_SAMPLE_FMT_S16)
- nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size,
- (opus_int16 *)frame->data[0],
- frame->nb_samples, 0);
+ nb_samples = libopus_generic_decode(&opus->dec, pkt->data, pkt->size,
+ (opus_int16 *)frame->data[0],
+ frame->nb_samples, 0);
else
- nb_samples = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size,
- (float *)frame->data[0],
- frame->nb_samples, 0);
+ nb_samples = libopus_generic_decode_float(&opus->dec, pkt->data, pkt->size,
+ (float *)frame->data[0],
+ frame->nb_samples, 0);
if (nb_samples < 0) {
av_log(avc, AV_LOG_ERROR, "Decoding error: %s\n",
@@ -220,7 +315,7 @@ static void libopus_flush(AVCodecContext *avc)
{
struct libopus_context *opus = avc->priv_data;
- opus_multistream_decoder_ctl(opus->dec, OPUS_RESET_STATE);
+ libopus_generic_decoder_ctl(&opus->dec, OPUS_RESET_STATE);
/* The stream can have been extracted by a tool that is not Opus-aware.
Therefore, any packet can become the first of the stream. */
avc->internal->skip_samples = opus->pre_skip;
@@ -21,15 +21,135 @@
#include <opus.h>
#include <opus_multistream.h>
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+#include <opus_projection.h>
+#endif
#include "libavutil/opt.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
#include "libopus.h"
+#include "mathops.h"
#include "vorbis.h"
#include "audio_frame_queue.h"
+typedef struct OpusGenericEncoder {
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ OpusProjectionEncoder *pr;
+#endif
+ OpusMSEncoder *ms;
+} OpusGenericEncoder;
+
+static int libopus_generic_encoder_surround_init(OpusGenericEncoder *enc,
+ int Fs,
+ int channels,
+ int mapping_family,
+ int *nb_streams,
+ int *nb_coupled,
+ unsigned char *stream_map,
+ int application)
+{
+ int ret;
+ if (mapping_family == 3) {
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ int ci;
+ enc->pr = opus_projection_ambisonics_encoder_create(
+ Fs, channels, mapping_family, nb_streams, nb_coupled,
+ application, &ret);
+ for (ci = 0; ci < channels; ci++)
+ stream_map[ci] = ci;
+#else
+ ret = OPUS_UNIMPLEMENTED;
+#endif
+ return ret;
+ }
+ enc->ms = opus_multistream_surround_encoder_create(
+ Fs, channels, mapping_family, nb_streams, nb_coupled, stream_map,
+ application, &ret);
+ return ret;
+}
+
+static int libopus_generic_encoder_init(OpusGenericEncoder *enc, int Fs,
+ int channels, int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application)
+{
+ int ret;
+ enc->ms = opus_multistream_encoder_create(Fs, channels, streams,
+ coupled_streams, mapping, application, &ret);
+ return ret;
+}
+
+static int libopus_generic_encode(OpusGenericEncoder *enc,
+ const opus_int16 *pcm,
+ int frame_size, unsigned char *data,
+ opus_int32 max_data_bytes)
+{
+ int ret;
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr) {
+ ret = opus_projection_encode(enc->pr, pcm, frame_size, data,
+ max_data_bytes);
+ return ret;
+ }
+#endif
+ ret = opus_multistream_encode(enc->ms, pcm, frame_size, data,
+ max_data_bytes);
+ return ret;
+}
+
+static int libopus_generic_encode_float(OpusGenericEncoder *enc,
+ const float *pcm,
+ int frame_size, unsigned char *data,
+ opus_int32 max_data_bytes)
+{
+ int ret;
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr) {
+ ret = opus_projection_encode_float(enc->pr, pcm, frame_size, data,
+ max_data_bytes);
+ return ret;
+ }
+#endif
+ ret = opus_multistream_encode_float(enc->ms, pcm, frame_size, data,
+ max_data_bytes);
+ return ret;
+}
+
+static void libous_generic_encoder_cleanup(OpusGenericEncoder *enc)
+{
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ if (enc->pr) opus_projection_encoder_destroy(enc->pr);
+#endif
+ if (enc->ms) opus_multistream_encoder_destroy(enc->ms);
+}
+
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+# define libopus_generic_encoder_ctl(enc, request) \
+ ((enc)->pr != NULL ? \
+ opus_projection_encoder_ctl((enc)->pr, request) : \
+ opus_multistream_encoder_ctl((enc)->ms, request))
+#else
+# define libopus_generic_encoder_ctl(enc, request) \
+ opus_multistream_encoder_ctl((enc)->ms, request)
+#endif
+
+static int libopus_generic_encoder_get_header_size(int mapping_family,
+ int channels, int streams,
+ int coupled_streams)
+{
+ int size = 19;
+ if (mapping_family == 1 || mapping_family == 2 || mapping_family == 255) {
+ return size + 2 + channels;
+ }
+ else if (mapping_family == 3) {
+ return size + 2 + 2 * channels * (streams + coupled_streams);
+ }
+ return size;
+}
+
typedef struct LibopusEncOpts {
int vbr;
int application;
@@ -46,7 +166,7 @@ typedef struct LibopusEncOpts {
typedef struct LibopusEncContext {
AVClass *class;
- OpusMSEncoder *enc;
+ OpusGenericEncoder enc;
int stream_count;
uint8_t *samples;
LibopusEncOpts opts;
@@ -85,28 +205,68 @@ static const uint8_t libavcodec_libopus_channel_map[8][8] = {
static void libopus_write_header(AVCodecContext *avctx, int stream_count,
int coupled_stream_count,
int mapping_family,
- const uint8_t *channel_mapping)
+ const uint8_t *channel_mapping,
+ OpusGenericEncoder *enc)
{
uint8_t *p = avctx->extradata;
int channels = avctx->channels;
+ int gain = 0;
bytestream_put_buffer(&p, "OpusHead", 8);
bytestream_put_byte(&p, 1); /* Version */
bytestream_put_byte(&p, channels);
bytestream_put_le16(&p, avctx->initial_padding); /* Lookahead samples at 48kHz */
bytestream_put_le32(&p, avctx->sample_rate); /* Original sample rate */
- bytestream_put_le16(&p, 0); /* Gain of 0dB is recommended. */
+ if (mapping_family == 3) {
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ int ret;
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(&gain));
+ if (ret != OPUS_OK) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Unable to write header, demixing matrix gain not found.\n");
+ return;
+ }
+#endif
+ }
+ bytestream_put_le16(&p, gain); /* Gain of 0dB is recommended. */
/* Channel mapping */
bytestream_put_byte(&p, mapping_family);
- if (mapping_family != 0) {
+ if (mapping_family == 3) {
+ int ret;
+ int32_t size;
+ size = 2 * channels * (stream_count + coupled_stream_count);
+ bytestream_put_byte(&p, stream_count);
+ bytestream_put_byte(&p, coupled_stream_count);
+ bytestream_put_byte(&p, stream_count);
+#ifdef OPUS_HAVE_OPUS_PROJECTION_H
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(&size));
+ if (ret != OPUS_OK) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Unable to write header, demixing matrix size not found.\n");
+ return;
+ }
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_PROJECTION_GET_DEMIXING_MATRIX(p, size));
+ if (ret != OPUS_OK) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Unable to write header, demixing matrix not found.\n");
+ return;
+ }
+ (*(&p)) += size;
+#endif
+ }
+ else if (mapping_family != 0) {
bytestream_put_byte(&p, stream_count);
bytestream_put_byte(&p, coupled_stream_count);
bytestream_put_buffer(&p, channel_mapping, channels);
}
}
-static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
+static int libopus_configure_encoder(AVCodecContext *avctx,
+ OpusGenericEncoder *enc,
LibopusEncOpts *opts)
{
int ret;
@@ -118,48 +278,48 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
return AVERROR(EINVAL);
}
- ret = opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(avctx->bit_rate));
+ ret = libopus_generic_encoder_ctl(enc, OPUS_SET_BITRATE(avctx->bit_rate));
if (ret != OPUS_OK) {
av_log(avctx, AV_LOG_ERROR,
"Failed to set bitrate: %s\n", opus_strerror(ret));
return ret;
}
- ret = opus_multistream_encoder_ctl(enc,
- OPUS_SET_COMPLEXITY(opts->complexity));
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_SET_COMPLEXITY(opts->complexity));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set complexity: %s\n", opus_strerror(ret));
- ret = opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(!!opts->vbr));
+ ret = libopus_generic_encoder_ctl(enc, OPUS_SET_VBR(!!opts->vbr));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set VBR: %s\n", opus_strerror(ret));
- ret = opus_multistream_encoder_ctl(enc,
- OPUS_SET_VBR_CONSTRAINT(opts->vbr == 2));
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_SET_VBR_CONSTRAINT(opts->vbr == 2));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set constrained VBR: %s\n", opus_strerror(ret));
- ret = opus_multistream_encoder_ctl(enc,
- OPUS_SET_PACKET_LOSS_PERC(opts->packet_loss));
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_SET_PACKET_LOSS_PERC(opts->packet_loss));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set expected packet loss percentage: %s\n",
opus_strerror(ret));
if (avctx->cutoff) {
- ret = opus_multistream_encoder_ctl(enc,
- OPUS_SET_MAX_BANDWIDTH(opts->max_bandwidth));
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_SET_MAX_BANDWIDTH(opts->max_bandwidth));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set maximum bandwidth: %s\n", opus_strerror(ret));
}
#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST
- ret = opus_multistream_encoder_ctl(enc,
- OPUS_SET_PHASE_INVERSION_DISABLED(!opts->apply_phase_inv));
+ ret = libopus_generic_encoder_ctl(enc,
+ OPUS_SET_PHASE_INVERSION_DISABLED(!opts->apply_phase_inv));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to set phase inversion: %s\n",
@@ -207,6 +367,8 @@ static int libopus_validate_layout_and_get_channel_map(
{
const uint8_t * channel_map = NULL;
int ret;
+ int order_plus_one;
+ int nondiegetic_channels;
switch (mapping_family) {
case -1:
@@ -231,6 +393,23 @@ static int libopus_validate_layout_and_get_channel_map(
channel_map = ff_vorbis_channel_layout_offsets[avctx->channels - 1];
}
break;
+ case 2:
+ case 3:
+ order_plus_one = ff_sqrt(avctx->channels);
+ nondiegetic_channels = avctx->channels - order_plus_one * order_plus_one;
+ if (order_plus_one < 1 || order_plus_one > 15 ||
+ (nondiegetic_channels != 0 && nondiegetic_channels != 2)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "This channel mapping is only specified for channel counts"
+ " which can be written as (n + 1)^2 + 2j, where n is a"
+ " non-negative integar from 0 to 14 and j is either 0 or 1.\n");
+ ret = AVERROR_INVALIDDATA;
+ } else {
+ ret = 0;
+ }
+
+ /* Channels do not need to be reordered. */
+ break;
case 255:
ret = libopus_check_max_channels(avctx, 254);
break;
@@ -248,7 +427,7 @@ static int libopus_validate_layout_and_get_channel_map(
static av_cold int libopus_encode_init(AVCodecContext *avctx)
{
LibopusEncContext *opus = avctx->priv_data;
- OpusMSEncoder *enc;
+ OpusGenericEncoder *enc = &opus->enc;
uint8_t libopus_channel_mapping[255];
int ret = OPUS_OK;
int av_ret;
@@ -335,20 +514,20 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
opus_vorbis_channel_map[avctx->channels - 1],
avctx->channels * sizeof(*libopus_channel_mapping));
- enc = opus_multistream_encoder_create(
- avctx->sample_rate, avctx->channels, opus->stream_count,
+ ret = libopus_generic_encoder_init(
+ enc, avctx->sample_rate, avctx->channels, opus->stream_count,
coupled_stream_count,
libavcodec_libopus_channel_map[avctx->channels - 1],
- opus->opts.application, &ret);
+ opus->opts.application);
} else {
/* Use the newer multistream API. The encoder will set the channel
* mapping and coupled stream counts to its internal defaults and will
* use surround masking analysis to save bits. */
mapping_family = opus->opts.mapping_family;
- enc = opus_multistream_surround_encoder_create(
- avctx->sample_rate, avctx->channels, mapping_family,
+ ret = libopus_generic_encoder_surround_init(
+ enc, avctx->sample_rate, avctx->channels, mapping_family,
&opus->stream_count, &coupled_stream_count, libopus_channel_mapping,
- opus->opts.application, &ret);
+ opus->opts.application);
}
if (ret != OPUS_OK) {
@@ -380,7 +559,9 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
}
/* Header includes channel mapping table if and only if mapping family is NOT 0 */
- header_size = 19 + (mapping_family == 0 ? 0 : 2 + avctx->channels);
+ header_size = libopus_generic_encoder_get_header_size(
+ mapping_family, avctx->channels, opus->stream_count,
+ coupled_stream_count);
avctx->extradata = av_malloc(header_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!avctx->extradata) {
av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata.\n");
@@ -397,23 +578,21 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
goto fail;
}
- ret = opus_multistream_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&avctx->initial_padding));
+ ret = libopus_generic_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&avctx->initial_padding));
if (ret != OPUS_OK)
av_log(avctx, AV_LOG_WARNING,
"Unable to get number of lookahead samples: %s\n",
opus_strerror(ret));
libopus_write_header(avctx, opus->stream_count, coupled_stream_count,
- mapping_family, libopus_channel_mapping);
+ mapping_family, libopus_channel_mapping, enc);
ff_af_queue_init(avctx, &opus->afq);
- opus->enc = enc;
-
return 0;
fail:
- opus_multistream_encoder_destroy(enc);
+ libous_generic_encoder_cleanup(enc);
av_freep(&avctx->extradata);
return ret;
}
@@ -470,13 +649,13 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
return ret;
if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT)
- ret = opus_multistream_encode_float(opus->enc, (float *)audio,
- opus->opts.packet_size,
- avpkt->data, avpkt->size);
+ ret = libopus_generic_encode_float(&opus->enc, (float *)audio,
+ opus->opts.packet_size,
+ avpkt->data, avpkt->size);
else
- ret = opus_multistream_encode(opus->enc, (opus_int16 *)audio,
- opus->opts.packet_size,
- avpkt->data, avpkt->size);
+ ret = libopus_generic_encode(&opus->enc, (opus_int16 *)audio,
+ opus->opts.packet_size,
+ avpkt->data, avpkt->size);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR,
@@ -517,7 +696,7 @@ static av_cold int libopus_encode_close(AVCodecContext *avctx)
{
LibopusEncContext *opus = avctx->priv_data;
- opus_multistream_encoder_destroy(opus->enc);
+ libous_generic_encoder_cleanup(&opus->enc);
ff_af_queue_close(&opus->afq);
@@ -373,18 +373,14 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx,
layout = ff_vorbis_channel_layouts[channels - 1];
channel_reorder = channel_reorder_vorbis;
} else if (map_type == 2) {
- int ambisonic_order = ff_sqrt(channels) - 1;
- if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1)) &&
- channels != ((ambisonic_order + 1) * (ambisonic_order + 1) + 2)) {
+ int order_plus_one = ff_sqrt(channels);
+ int nondiegetic_channels = channels - order_plus_one * order_plus_one;
+ if (order_plus_one < 1 || order_plus_one > 15 ||
+ (nondiegetic_channels != 0 && nondiegetic_channels != 2)) {
av_log(avctx, AV_LOG_ERROR,
- "Channel mapping 2 is only specified for channel counts"
- " which can be written as (n + 1)^2 or (n + 1)^2 + 2"
- " for nonnegative integer n\n");
- return AVERROR_INVALIDDATA;
- }
- if (channels > 227) {
- av_log(avctx, AV_LOG_ERROR, "Too many channels\n");
- return AVERROR_INVALIDDATA;
+ "This channel mapping is only specified for channel counts"
+ " which can be written as (n + 1)^2 + 2j, where n is a"
+ " non-negative integar from 0 to 14 and j is either 0 or 1.\n");
}
layout = 0;
} else
--
2.17.0.484.g0c8726318c-goog