Hello all, My name is Andrew Allen and I'm a contributor to Opus, supporting new channel mappings 2 and 3 for ambisonics compression. I've attached a patch to support the new OpusProjectionEncoder and OpusProjectionDecoder APIs for handling the new channel mapping 3 in OPUS.
Please let me know of any changes I should make or if there are any questions I can help answer. Cheers, Drew
From a897b4d9b1ebe9031b98a9e507c28355ef9a44ba Mon Sep 17 00:00:00 2001 From: Andrew Allen <bitll...@google.com> Date: Wed, 28 Mar 2018 14:48:46 -0700 Subject: [PATCH] Support for Ambisonics and OpusProjection* API. --- libavcodec/libopusdec.c | 160 ++++++++++++++++++++----- libavcodec/libopusenc.c | 257 ++++++++++++++++++++++++++++++++++------ libavcodec/opus.c | 18 ++- 3 files changed, 358 insertions(+), 77 deletions(-) diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index 3d2ee5b61b..d4b5a459b9 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -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,93 @@ #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 *st, 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); + st->pr = opus_projection_decoder_create(Fs, channels, nb_streams, + nb_coupled, dmatrix, size, &err); +#else + err = OPUS_UNIMPLEMENTED; +#endif + st->ms = NULL; + return err; + } +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + st->pr = NULL; +#endif + st->ms = opus_multistream_decoder_create(Fs, channels, nb_streams, + nb_coupled, mapping, &err); + return err; +} + +static void libopus_generic_decoder_cleanup(OpusGenericDecoder *st) +{ +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + if (st->pr) opus_projection_decoder_destroy(st->pr); +#endif + if (st->ms) opus_multistream_decoder_destroy(st->ms); +} + +static int libopus_generic_decode(OpusGenericDecoder *st, + const unsigned char *data, opus_int32 len, opus_int16 *pcm, + int frame_size, int decode_fec) { + int ret; + +#if defined(OPUS_HAVE_OPUS_PROJECTION_H) + if (st->pr){ + ret=opus_projection_decode(st->pr, data, len, pcm, frame_size, + decode_fec); + return ret; + } +#endif + ret=opus_multistream_decode(st->ms, data, len, pcm, frame_size, + decode_fec); + return ret; +} + +static int libopus_generic_decode_float(OpusGenericDecoder *st, + const unsigned char *data, opus_int32 len, float *pcm, int frame_size, + int decode_fec) { + int ret; + +#if defined(OPUS_HAVE_OPUS_PROJECTION_H) + if (st->pr){ + ret=opus_projection_decode_float(st->pr, data, len, pcm, frame_size, + decode_fec); + return ret; + } +#endif + ret=opus_multistream_decode_float(st->ms, data, len, pcm, frame_size, + decode_fec); + return ret; +} + +#ifdef OPUS_HAVE_OPUS_PROJECTION_H +# define libopus_generic_decoder_ctl(st, request) \ + ((st)->pr != NULL ? \ + opus_projection_decoder_ctl((st)->pr, request) : \ + opus_multistream_decoder_ctl((st)->ms, request)) +#else +# define libopus_generic_decoder_ctl(st, request) \ + opus_multistream_decoder_ctl((st)->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 +133,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 +166,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(EINVAL); + } + 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 +204,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 +220,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 +244,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,7 +262,7 @@ static av_cold int libopus_decode_close(AVCodecContext *avc) { struct libopus_context *opus = avc->priv_data; - opus_multistream_decoder_destroy(opus->dec); + libopus_generic_decoder_cleanup(&opus->dec); return 0; } @@ -178,13 +280,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", @@ -217,7 +319,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; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 4ae81b0bb2..729d86d2d7 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -21,15 +21,139 @@ #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 *st, 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; + st->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 + st->ms = NULL; + return ret; + } +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + st->pr = NULL; +#endif + st->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 *st, int Fs, + int channels, int streams, + int coupled_streams, + const unsigned char *mapping, + int application) +{ + int ret; +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + st->pr = NULL; +#endif + st->ms = opus_multistream_encoder_create(Fs, channels, streams, + coupled_streams, mapping, application, &ret); + return ret; +} + +static int libopus_generic_encode(OpusGenericEncoder *st, const opus_int16 *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + int ret; +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + if (st->pr) { + ret = opus_projection_encode(st->pr, pcm, frame_size, data, + max_data_bytes); + return ret; + } +#endif + ret = opus_multistream_encode(st->ms, pcm, frame_size, data, + max_data_bytes); + return ret; +} + +static int libopus_generic_encode_float(OpusGenericEncoder *st, + const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + int ret; +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + if (st->pr) { + ret = opus_projection_encode_float(st->pr, pcm, frame_size, data, + max_data_bytes); + return ret; + } +#endif + ret = opus_multistream_encode_float(st->ms, pcm, frame_size, data, + max_data_bytes); + return ret; +} + +static void libous_generic_encoder_cleanup(OpusGenericEncoder *st) +{ +#ifdef OPUS_HAVE_OPUS_PROJECTION_H + if (st->pr) opus_projection_encoder_destroy(st->pr); +#endif + if (st->ms) opus_multistream_encoder_destroy(st->ms); +} + +#ifdef OPUS_HAVE_OPUS_PROJECTION_H +# define libopus_generic_encoder_ctl(st, request) \ + ((st)->pr != NULL ? \ + opus_projection_encoder_ctl((st)->pr, request) : \ + opus_multistream_encoder_ctl((st)->ms, request)) +#else +# define libopus_generic_encoder_ctl(st, request) \ + opus_multistream_encoder_ctl((st)->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 +170,7 @@ typedef struct LibopusEncOpts { typedef struct LibopusEncContext { AVClass *class; - OpusMSEncoder *enc; + OpusGenericEncoder enc; int stream_count; uint8_t *samples; LibopusEncOpts opts; @@ -85,28 +209,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 +282,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 +371,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 +397,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 +431,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 +518,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 +563,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 +582,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 +653,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 +700,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); diff --git a/libavcodec/opus.c b/libavcodec/opus.c index aa827b604c..f8877233af 100644 --- a/libavcodec/opus.c +++ b/libavcodec/opus.c @@ -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.rc1.321.gba9d0f2565-goog
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel