]> git.sesse.net Git - ffmpeg/commitdiff
opus: add an option to toggle intensity stereo phase inversion
authorRostislav Pehlivanov <atomnuker@gmail.com>
Mon, 4 Dec 2017 06:36:42 +0000 (06:36 +0000)
committerRostislav Pehlivanov <atomnuker@gmail.com>
Mon, 4 Dec 2017 07:28:45 +0000 (07:28 +0000)
Due to a somewhat high volume of complains, phase inversion has
been made optional with RFC8251. This allows for better bass
frequency response when partially downmixing to play on systems
with an LFE speaker.

Signed-off-by: Rostislav Pehlivanov <atomnuker@gmail.com>
libavcodec/opus.h
libavcodec/opus_celt.c
libavcodec/opus_celt.h
libavcodec/opus_pvq.c
libavcodec/opusdec.c

index c3cbaec35d60b67937eecf1dfa82042708d9fc26..90b87ba5c4d2f4ef16b2cdab9fa7249b83555984 100644 (file)
@@ -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;
index 2bbb96bded5c4e1b23f276df87941373e99f0656..72b299a19c00b8f9d184159f4e2b08565deeafaf 100644 (file)
@@ -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)
index 45d50ab27b9f239d896e83d07e0b5aa9f82cd8d3..9289a1867af7ec27247b01cbb29766b653120e19 100644 (file)
@@ -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);
 
index 2f7aa74da49ea2176ef57d1aec1a924779eca284..449215f814b015d2344b70e38553ef570b055d51 100644 (file)
@@ -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;
         }
index 5a7ba9dbb43546ebcf13804b92fc9d83d501ae81..03086dea99e2c3ac6a8865e1ca873082c74e2088 100644 (file)
@@ -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),