summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRostislav Pehlivanov <atomnuker@gmail.com>2017-12-04 06:36:42 +0000
committerRostislav Pehlivanov <atomnuker@gmail.com>2017-12-04 07:28:45 +0000
commit1b8649c2ce95da0a12d90f6acf7171b4fc6580db (patch)
tree40eeb3616dea4963f080594b996cd906524f95ef
parentfe05f93013c4a3616926fa9370be2d9c93a94659 (diff)
downloadffmpeg-1b8649c2ce95da0a12d90f6acf7171b4fc6580db.tar.gz
opus: add an option to toggle intensity stereo phase inversion
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>
-rw-r--r--libavcodec/opus.h2
-rw-r--r--libavcodec/opus_celt.c4
-rw-r--r--libavcodec/opus_celt.h4
-rw-r--r--libavcodec/opus_pvq.c1
-rw-r--r--libavcodec/opusdec.c17
5 files changed, 25 insertions, 3 deletions
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),