diff --git a/libavcodec/opus.h b/libavcodec/opus.h index c3cbaec35d..90b87ba5c4 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus.h @@ -150,7 +150,9 @@ typedef struct ChannelMap { } ChannelMap; typedef struct OpusContext { + AVClass *av_class; OpusStreamContext *streams; + int apply_phase_inv; /* current output buffers for each streams */ float **out; diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c index 2bbb96bded..72b299a19c 100644 --- a/libavcodec/opus_celt.c +++ b/libavcodec/opus_celt.c @@ -997,7 +997,8 @@ void ff_celt_free(CeltFrame **f) av_freep(f); } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv) { CeltFrame *frm; int i, ret; @@ -1014,6 +1015,7 @@ int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) frm->avctx = avctx; frm->output_channels = output_channels; + frm->apply_phase_inv = apply_phase_inv; for (i = 0; i < FF_ARRAY_ELEMS(frm->imdct); i++) if ((ret = ff_mdct15_init(&frm->imdct[i], 1, i + 3, -1.0f/32768)) < 0) diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h index 45d50ab27b..9289a1867a 100644 --- a/libavcodec/opus_celt.h +++ b/libavcodec/opus_celt.h @@ -98,6 +98,7 @@ struct CeltFrame { CeltPVQ *pvq; int channels; int output_channels; + int apply_phase_inv; enum CeltBlockSize size; int start_band; @@ -156,7 +157,8 @@ static av_always_inline void celt_renormalize_vector(float *X, int N, float gain X[i] *= g; } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels); +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv); void ff_celt_free(CeltFrame **f); diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c index 2f7aa74da4..449215f814 100644 --- a/libavcodec/opus_pvq.c +++ b/libavcodec/opus_pvq.c @@ -643,6 +643,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, } } else { inv = (b > 2 << 3 && f->remaining2 > 2 << 3) ? ff_opus_rc_dec_log(rc, 2) : 0; + inv = f->apply_phase_inv ? inv : 0; } itheta = 0; } diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c index 5a7ba9dbb4..03086dea99 100644 --- a/libavcodec/opusdec.c +++ b/libavcodec/opusdec.c @@ -687,7 +687,7 @@ static av_cold int opus_decode_init(AVCodecContext *avctx) if (ret < 0) goto fail; - ret = ff_celt_init(avctx, &s->celt, s->output_channels); + ret = ff_celt_init(avctx, &s->celt, s->output_channels, c->apply_phase_inv); if (ret < 0) goto fail; @@ -712,9 +712,24 @@ fail: return ret; } +#define OFFSET(x) offsetof(OpusContext, x) +#define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption opus_options[] = { + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AD }, + { NULL }, +}; + +static const AVClass opus_class = { + .class_name = "Opus Decoder", + .item_name = av_default_item_name, + .option = opus_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_opus_decoder = { .name = "opus", .long_name = NULL_IF_CONFIG_SMALL("Opus"), + .priv_class = &opus_class, .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_OPUS, .priv_data_size = sizeof(OpusContext),