mirror of
https://github.com/librempeg/librempeg
synced 2024-11-22 00:51:37 +00:00
opusdsp: add ability to modify deemphasis constant
xHE-AAC relies on the same postfilter mechanism that Opus uses to improve clarity (albeit with a steeper deemphasis filter). The code to apply it is identical, it's still just a simple IIR low-pass filter. This commit makes it possible to use alternative constants. Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
7f0b68425d
commit
4298e719c4
@ -23,7 +23,7 @@
|
|||||||
#include "libavcodec/opusdsp.h"
|
#include "libavcodec/opusdsp.h"
|
||||||
|
|
||||||
void ff_opus_postfilter_neon(float *data, int period, float *gains, int len);
|
void ff_opus_postfilter_neon(float *data, int period, float *gains, int len);
|
||||||
float ff_opus_deemphasis_neon(float *out, float *in, float coeff, int len);
|
float ff_opus_deemphasis_neon(float *out, float *in, float coeff, const float *weights, int len);
|
||||||
|
|
||||||
av_cold void ff_opus_dsp_init_aarch64(OpusDSP *ctx)
|
av_cold void ff_opus_dsp_init_aarch64(OpusDSP *ctx)
|
||||||
{
|
{
|
||||||
|
@ -18,29 +18,11 @@
|
|||||||
|
|
||||||
#include "libavutil/aarch64/asm.S"
|
#include "libavutil/aarch64/asm.S"
|
||||||
|
|
||||||
// 0.85..^1 0.85..^2 0.85..^3 0.85..^4
|
|
||||||
const tab_st, align=4
|
|
||||||
.word 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f
|
|
||||||
endconst
|
|
||||||
const tab_x0, align=4
|
|
||||||
.word 0x0, 0x3f599a00, 0x3f38f671, 0x3f1d382a
|
|
||||||
endconst
|
|
||||||
const tab_x1, align=4
|
|
||||||
.word 0x0, 0x0, 0x3f599a00, 0x3f38f671
|
|
||||||
endconst
|
|
||||||
const tab_x2, align=4
|
|
||||||
.word 0x0, 0x0, 0x0, 0x3f599a00
|
|
||||||
endconst
|
|
||||||
|
|
||||||
function ff_opus_deemphasis_neon, export=1
|
function ff_opus_deemphasis_neon, export=1
|
||||||
movrel x4, tab_st
|
ld1 {v4.4s}, [x2], #16
|
||||||
ld1 {v4.4s}, [x4]
|
ld1 {v5.4s}, [x2], #16
|
||||||
movrel x4, tab_x0
|
ld1 {v6.4s}, [x2], #16
|
||||||
ld1 {v5.4s}, [x4]
|
ld1 {v7.4s}, [x2]
|
||||||
movrel x4, tab_x1
|
|
||||||
ld1 {v6.4s}, [x4]
|
|
||||||
movrel x4, tab_x2
|
|
||||||
ld1 {v7.4s}, [x4]
|
|
||||||
|
|
||||||
fmul v0.4s, v4.4s, v0.s[0]
|
fmul v0.4s, v4.4s, v0.s[0]
|
||||||
|
|
||||||
@ -63,7 +45,7 @@ function ff_opus_deemphasis_neon, export=1
|
|||||||
st1 {v1.4s, v2.4s}, [x0], #32
|
st1 {v1.4s, v2.4s}, [x0], #32
|
||||||
fmul v0.4s, v4.4s, v2.s[3]
|
fmul v0.4s, v4.4s, v2.s[3]
|
||||||
|
|
||||||
subs w2, w2, #8
|
subs w3, w3, #8
|
||||||
b.gt 1b
|
b.gt 1b
|
||||||
|
|
||||||
mov s0, v2.s[3]
|
mov s0, v2.s[3]
|
||||||
|
@ -460,7 +460,9 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
|
|||||||
/* deemphasis */
|
/* deemphasis */
|
||||||
block->emph_coeff = f->opusdsp.deemphasis(output[i],
|
block->emph_coeff = f->opusdsp.deemphasis(output[i],
|
||||||
&block->buf[1024 - frame_size],
|
&block->buf[1024 - frame_size],
|
||||||
block->emph_coeff, frame_size);
|
block->emph_coeff,
|
||||||
|
ff_opus_deemph_weights,
|
||||||
|
frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channels == 1)
|
if (channels == 1)
|
||||||
@ -516,7 +518,7 @@ void ff_celt_flush(CeltFrame *f)
|
|||||||
* a lesser discontinuity when seeking.
|
* a lesser discontinuity when seeking.
|
||||||
* The deemphasis functions differ from libopus in that they require
|
* The deemphasis functions differ from libopus in that they require
|
||||||
* an initial state divided by the coefficient. */
|
* an initial state divided by the coefficient. */
|
||||||
block->emph_coeff = 0.0f / CELT_EMPH_COEFF;
|
block->emph_coeff = 0.0f / ff_opus_deemph_weights[0];
|
||||||
}
|
}
|
||||||
f->seed = 0;
|
f->seed = 0;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libavutil/attributes.h"
|
#include "libavutil/attributes.h"
|
||||||
|
#include "libavutil/mem_internal.h"
|
||||||
#include "opusdsp.h"
|
#include "opusdsp.h"
|
||||||
|
|
||||||
static void postfilter_c(float *data, int period, float *gains, int len)
|
static void postfilter_c(float *data, int period, float *gains, int len)
|
||||||
@ -43,10 +44,11 @@ static void postfilter_c(float *data, int period, float *gains, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float deemphasis_c(float *y, float *x, float coeff, int len)
|
static float deemphasis_c(float *y, float *x, float coeff, const float *weights, int len)
|
||||||
{
|
{
|
||||||
|
const float c = weights[0];
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
coeff = y[i] = x[i] + coeff*CELT_EMPH_COEFF;
|
coeff = y[i] = x[i] + coeff*c;
|
||||||
|
|
||||||
return coeff;
|
return coeff;
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,9 @@
|
|||||||
#ifndef AVCODEC_OPUSDSP_H
|
#ifndef AVCODEC_OPUSDSP_H
|
||||||
#define AVCODEC_OPUSDSP_H
|
#define AVCODEC_OPUSDSP_H
|
||||||
|
|
||||||
#define CELT_EMPH_COEFF 0.8500061035f
|
|
||||||
|
|
||||||
typedef struct OpusDSP {
|
typedef struct OpusDSP {
|
||||||
void (*postfilter)(float *data, int period, float *gains, int len);
|
void (*postfilter)(float *data, int period, float *gains, int len);
|
||||||
float (*deemphasis)(float *out, float *in, float coeff, int len);
|
float (*deemphasis)(float *out, float *in, float coeff, const float *weights, int len);
|
||||||
} OpusDSP;
|
} OpusDSP;
|
||||||
|
|
||||||
void ff_opus_dsp_init(OpusDSP *ctx);
|
void ff_opus_dsp_init(OpusDSP *ctx);
|
||||||
|
@ -164,6 +164,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f)
|
|||||||
{
|
{
|
||||||
const int subframesize = s->avctx->frame_size;
|
const int subframesize = s->avctx->frame_size;
|
||||||
const int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize;
|
const int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize;
|
||||||
|
const float c = ff_opus_deemph_weights[0];
|
||||||
|
|
||||||
/* Filter overlap */
|
/* Filter overlap */
|
||||||
for (int ch = 0; ch < f->channels; ch++) {
|
for (int ch = 0; ch < f->channels; ch++) {
|
||||||
@ -172,7 +173,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f)
|
|||||||
for (int i = 0; i < CELT_OVERLAP; i++) {
|
for (int i = 0; i < CELT_OVERLAP; i++) {
|
||||||
float sample = b->overlap[i];
|
float sample = b->overlap[i];
|
||||||
b->overlap[i] = sample - m;
|
b->overlap[i] = sample - m;
|
||||||
m = sample * CELT_EMPH_COEFF;
|
m = sample * c;
|
||||||
}
|
}
|
||||||
b->emph_coeff = m;
|
b->emph_coeff = m;
|
||||||
}
|
}
|
||||||
@ -185,7 +186,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f)
|
|||||||
for (int i = 0; i < subframesize; i++) {
|
for (int i = 0; i < subframesize; i++) {
|
||||||
float sample = b->samples[sf*subframesize + i];
|
float sample = b->samples[sf*subframesize + i];
|
||||||
b->samples[sf*subframesize + i] = sample - m;
|
b->samples[sf*subframesize + i] = sample - m;
|
||||||
m = sample * CELT_EMPH_COEFF;
|
m = sample * c;
|
||||||
}
|
}
|
||||||
if (sf != (subframes - 1))
|
if (sf != (subframes - 1))
|
||||||
b->emph_coeff = m;
|
b->emph_coeff = m;
|
||||||
|
@ -1159,3 +1159,31 @@ const uint32_t * const ff_celt_pvq_u_row[15] = {
|
|||||||
celt_pvq_u + 1207, celt_pvq_u + 1226, celt_pvq_u + 1240,
|
celt_pvq_u + 1207, celt_pvq_u + 1226, celt_pvq_u + 1240,
|
||||||
celt_pvq_u + 1248, celt_pvq_u + 1254, celt_pvq_u + 1257
|
celt_pvq_u + 1248, celt_pvq_u + 1254, celt_pvq_u + 1257
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Deemphasis constant (alpha_p), as specified in RFC6716 as 0.8500061035.
|
||||||
|
* libopus uses a slighly rounded constant, set to 0.85 exactly,
|
||||||
|
* to simplify its fixed-point version, but it's not significant to impact
|
||||||
|
* compliance. */
|
||||||
|
#define CELT_EMPH_COEFF 0.8500061035f
|
||||||
|
|
||||||
|
DECLARE_ALIGNED(16, const float, ff_opus_deemph_weights)[] = {
|
||||||
|
CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
|
||||||
|
0,
|
||||||
|
CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
CELT_EMPH_COEFF,
|
||||||
|
CELT_EMPH_COEFF*CELT_EMPH_COEFF,
|
||||||
|
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
CELT_EMPH_COEFF,
|
||||||
|
};
|
||||||
|
@ -161,6 +161,8 @@ extern const float ff_celt_window2[120];
|
|||||||
extern const float ff_celt_window_padded[];
|
extern const float ff_celt_window_padded[];
|
||||||
static const float *const ff_celt_window = &ff_celt_window_padded[8];
|
static const float *const ff_celt_window = &ff_celt_window_padded[8];
|
||||||
|
|
||||||
|
extern const float ff_opus_deemph_weights[];
|
||||||
|
|
||||||
extern const uint32_t * const ff_celt_pvq_u_row[15];
|
extern const uint32_t * const ff_celt_pvq_u_row[15];
|
||||||
FF_VISIBILITY_POP_HIDDEN
|
FF_VISIBILITY_POP_HIDDEN
|
||||||
|
|
||||||
|
@ -22,16 +22,13 @@
|
|||||||
|
|
||||||
SECTION_RODATA
|
SECTION_RODATA
|
||||||
|
|
||||||
; 0.85..^1 0.85..^2 0.85..^3 0.85..^4
|
|
||||||
tab_st: dd 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f
|
|
||||||
|
|
||||||
SECTION .text
|
SECTION .text
|
||||||
|
|
||||||
INIT_XMM fma3
|
INIT_XMM fma3
|
||||||
%if UNIX64
|
%if UNIX64
|
||||||
cglobal opus_deemphasis, 3, 3, 8, out, in, len
|
cglobal opus_deemphasis, 4, 4, 8, out, in, weights, len
|
||||||
%else
|
%else
|
||||||
cglobal opus_deemphasis, 4, 4, 8, out, in, coeff, len
|
cglobal opus_deemphasis, 5, 5, 8, out, in, coeff, weights, len
|
||||||
%endif
|
%endif
|
||||||
%if ARCH_X86_32
|
%if ARCH_X86_32
|
||||||
VBROADCASTSS m0, coeffm
|
VBROADCASTSS m0, coeffm
|
||||||
@ -41,7 +38,7 @@ cglobal opus_deemphasis, 4, 4, 8, out, in, coeff, len
|
|||||||
shufps m0, m0, 0
|
shufps m0, m0, 0
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
movaps m4, [tab_st]
|
movaps m4, [weightsq]
|
||||||
VBROADCASTSS m5, m4
|
VBROADCASTSS m5, m4
|
||||||
shufps m6, m4, m4, q1111
|
shufps m6, m4, m4, q1111
|
||||||
shufps m7, m4, m4, q2222
|
shufps m7, m4, m4, q2222
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "libavcodec/opusdsp.h"
|
#include "libavcodec/opusdsp.h"
|
||||||
|
|
||||||
void ff_opus_postfilter_fma3(float *data, int period, float *gains, int len);
|
void ff_opus_postfilter_fma3(float *data, int period, float *gains, int len);
|
||||||
float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, int len);
|
float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, const float *weights, int len);
|
||||||
|
|
||||||
av_cold void ff_opus_dsp_init_x86(OpusDSP *ctx)
|
av_cold void ff_opus_dsp_init_x86(OpusDSP *ctx)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "libavutil/mem_internal.h"
|
#include "libavutil/mem_internal.h"
|
||||||
|
|
||||||
#include "libavcodec/opusdsp.h"
|
#include "libavcodec/opusdsp.h"
|
||||||
|
#include "libavcodec/opustab.h"
|
||||||
|
|
||||||
#include "checkasm.h"
|
#include "checkasm.h"
|
||||||
|
|
||||||
@ -69,17 +70,17 @@ static void test_deemphasis(void)
|
|||||||
LOCAL_ALIGNED(16, float, dst1, [FFALIGN(MAX_SIZE, 4)]);
|
LOCAL_ALIGNED(16, float, dst1, [FFALIGN(MAX_SIZE, 4)]);
|
||||||
float coeff0 = (float)rnd() / (UINT_MAX >> 5) - 16.0f, coeff1 = coeff0;
|
float coeff0 = (float)rnd() / (UINT_MAX >> 5) - 16.0f, coeff1 = coeff0;
|
||||||
|
|
||||||
declare_func_float(float, float *out, float *in, float coeff, int len);
|
declare_func_float(float, float *out, float *in, float coeff, const float *weights, int len);
|
||||||
|
|
||||||
randomize_float(src, MAX_SIZE);
|
randomize_float(src, MAX_SIZE);
|
||||||
|
|
||||||
coeff0 = call_ref(dst0, src, coeff0, MAX_SIZE);
|
coeff0 = call_ref(dst0, src, coeff0, ff_opus_deemph_weights, MAX_SIZE);
|
||||||
coeff1 = call_new(dst1, src, coeff1, MAX_SIZE);
|
coeff1 = call_new(dst1, src, coeff1, ff_opus_deemph_weights, MAX_SIZE);
|
||||||
|
|
||||||
if (!float_near_abs_eps(coeff0, coeff1, EPS) ||
|
if (!float_near_abs_eps(coeff0, coeff1, EPS) ||
|
||||||
!float_near_abs_eps_array(dst0, dst1, EPS, MAX_SIZE))
|
!float_near_abs_eps_array(dst0, dst1, EPS, MAX_SIZE))
|
||||||
fail();
|
fail();
|
||||||
bench_new(dst1, src, coeff1, MAX_SIZE);
|
bench_new(dst1, src, coeff1, ff_opus_deemph_weights, MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkasm_check_opusdsp(void)
|
void checkasm_check_opusdsp(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user