avfilter/af_surround: add support for some upmixing of 3.0, 2.1 and 5.1 channel layout

Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
Paul B Mahol 2017-06-03 22:44:08 +02:00
parent 880504814a
commit fab1863917
2 changed files with 462 additions and 63 deletions

View File

@ -3795,7 +3795,7 @@ Set level of input signal of original channel. Default is 0.8.
@section surround
Apply audio surround upmix filter.
This filter allows to produce multichannel output from stereo audio stream.
This filter allows to produce multichannel output from audio stream.
The filter accepts the following options:
@ -3806,6 +3806,12 @@ Set output channel layout. By default, this is @var{5.1}.
See @ref{channel layout syntax,,the Channel Layout section in the ffmpeg-utils(1) manual,ffmpeg-utils}
for the required syntax.
@item chl_in
Set input channel layout. By default, this is @var{stereo}.
See @ref{channel layout syntax,,the Channel Layout section in the ffmpeg-utils(1) manual,ffmpeg-utils}
for the required syntax.
@item level_in
Set input volume level. By default, this is @var{1}.

View File

@ -30,6 +30,7 @@ typedef struct AudioSurroundContext {
const AVClass *class;
char *out_channel_layout_str;
char *in_channel_layout_str;
float level_in;
float level_out;
int output_lfe;
@ -40,6 +41,7 @@ typedef struct AudioSurroundContext {
float highcut;
uint64_t out_channel_layout;
uint64_t in_channel_layout;
int nb_in_channels;
int nb_out_channels;
@ -55,13 +57,41 @@ typedef struct AudioSurroundContext {
int64_t pts;
void (*upmix)(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float mag_total,
float x, float y,
int n);
void (*filter)(AVFilterContext *ctx);
void (*upmix_stereo)(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float mag_total,
float x, float y,
int n);
void (*upmix_2_1)(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float mag_total,
float lfe_im,
float lfe_re,
float x, float y,
int n);
void (*upmix_3_0)(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_mag,
float c_phase,
float mag_total,
float x, float y,
int n);
void (*upmix_5_1)(AVFilterContext *ctx,
float c_re, float c_im,
float lfe_re, float lfe_im,
float mag_totall, float mag_totalr,
float fl_phase, float fr_phase,
float bl_phase, float br_phase,
float sl_phase, float sr_phase,
float xl, float yl,
float xr, float yr,
int n);
} AudioSurroundContext;
static int query_formats(AVFilterContext *ctx)
@ -88,7 +118,7 @@ static int query_formats(AVFilterContext *ctx)
return ret;
layouts = NULL;
ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO);
ret = ff_add_channel_layout(&layouts, s->in_channel_layout);
if (ret)
return ret;
@ -313,6 +343,41 @@ static void upmix_3_1(AVFilterContext *ctx,
dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase);
}
static void upmix_3_1_surround(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float c_mag,
float mag_total,
float x, float y,
int n)
{
AudioSurroundContext *s = ctx->priv;
float lfe_mag, l_mag, r_mag, *dstc, *dstl, *dstr, *dstlfe;
dstl = (float *)s->output->extended_data[0];
dstr = (float *)s->output->extended_data[1];
dstc = (float *)s->output->extended_data[2];
dstlfe = (float *)s->output->extended_data[3];
get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag);
l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
dstl[2 * n ] = l_mag * cosf(l_phase);
dstl[2 * n + 1] = l_mag * sinf(l_phase);
dstr[2 * n ] = r_mag * cosf(r_phase);
dstr[2 * n + 1] = r_mag * sinf(r_phase);
dstc[2 * n ] = c_mag * cosf(c_phase);
dstc[2 * n + 1] = c_mag * sinf(c_phase);
dstlfe[2 * n ] = lfe_mag * cosf(c_phase);
dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase);
}
static void upmix_4_0(AVFilterContext *ctx,
float l_phase,
float r_phase,
@ -471,6 +536,98 @@ static void upmix_5_1_back(AVFilterContext *ctx,
dstrs[2 * n + 1] = rs_mag * sinf(r_phase);
}
static void upmix_5_1_back_surround(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float c_mag,
float mag_total,
float x, float y,
int n)
{
AudioSurroundContext *s = ctx->priv;
float lfe_mag, l_mag, r_mag, *dstc, *dstl, *dstr, *dstlfe;
float ls_mag, rs_mag, *dstls, *dstrs;
dstl = (float *)s->output->extended_data[0];
dstr = (float *)s->output->extended_data[1];
dstc = (float *)s->output->extended_data[2];
dstlfe = (float *)s->output->extended_data[3];
dstls = (float *)s->output->extended_data[4];
dstrs = (float *)s->output->extended_data[5];
get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag);
l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total;
rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total;
dstl[2 * n ] = l_mag * cosf(l_phase);
dstl[2 * n + 1] = l_mag * sinf(l_phase);
dstr[2 * n ] = r_mag * cosf(r_phase);
dstr[2 * n + 1] = r_mag * sinf(r_phase);
dstc[2 * n ] = c_mag * cosf(c_phase);
dstc[2 * n + 1] = c_mag * sinf(c_phase);
dstlfe[2 * n ] = lfe_mag * cosf(c_phase);
dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase);
dstls[2 * n ] = ls_mag * cosf(l_phase);
dstls[2 * n + 1] = ls_mag * sinf(l_phase);
dstrs[2 * n ] = rs_mag * cosf(r_phase);
dstrs[2 * n + 1] = rs_mag * sinf(r_phase);
}
static void upmix_5_1_back_2_1(AVFilterContext *ctx,
float l_phase,
float r_phase,
float c_phase,
float mag_total,
float lfe_re,
float lfe_im,
float x, float y,
int n)
{
AudioSurroundContext *s = ctx->priv;
float c_mag, l_mag, r_mag, *dstc, *dstl, *dstr, *dstlfe;
float ls_mag, rs_mag, *dstls, *dstrs;
dstl = (float *)s->output->extended_data[0];
dstr = (float *)s->output->extended_data[1];
dstc = (float *)s->output->extended_data[2];
dstlfe = (float *)s->output->extended_data[3];
dstls = (float *)s->output->extended_data[4];
dstrs = (float *)s->output->extended_data[5];
c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total;
l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total;
ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total;
rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total;
dstl[2 * n ] = l_mag * cosf(l_phase);
dstl[2 * n + 1] = l_mag * sinf(l_phase);
dstr[2 * n ] = r_mag * cosf(r_phase);
dstr[2 * n + 1] = r_mag * sinf(r_phase);
dstc[2 * n ] = c_mag * cosf(c_phase);
dstc[2 * n + 1] = c_mag * sinf(c_phase);
dstlfe[2 * n ] = lfe_re;
dstlfe[2 * n + 1] = lfe_im;
dstls[2 * n ] = ls_mag * cosf(l_phase);
dstls[2 * n + 1] = ls_mag * sinf(l_phase);
dstrs[2 * n ] = rs_mag * cosf(r_phase);
dstrs[2 * n + 1] = rs_mag * sinf(r_phase);
}
static void upmix_7_0(AVFilterContext *ctx,
float l_phase,
float r_phase,
@ -577,6 +734,217 @@ static void upmix_7_1(AVFilterContext *ctx,
dstrs[2 * n + 1] = rs_mag * sinf(r_phase);
}
static void upmix_7_1_5_1(AVFilterContext *ctx,
float c_re, float c_im,
float lfe_re, float lfe_im,
float mag_totall, float mag_totalr,
float fl_phase, float fr_phase,
float bl_phase, float br_phase,
float sl_phase, float sr_phase,
float xl, float yl,
float xr, float yr,
int n)
{
float fl_mag, fr_mag, ls_mag, rs_mag, lb_mag, rb_mag;
float *dstc, *dstl, *dstr, *dstls, *dstrs, *dstlb, *dstrb, *dstlfe;
AudioSurroundContext *s = ctx->priv;
dstl = (float *)s->output->extended_data[0];
dstr = (float *)s->output->extended_data[1];
dstc = (float *)s->output->extended_data[2];
dstlfe = (float *)s->output->extended_data[3];
dstlb = (float *)s->output->extended_data[4];
dstrb = (float *)s->output->extended_data[5];
dstls = (float *)s->output->extended_data[6];
dstrs = (float *)s->output->extended_data[7];
fl_mag = sqrtf(.5f * (xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall;
fr_mag = sqrtf(.5f * (xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr;
lb_mag = sqrtf(.5f * (-xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall;
rb_mag = sqrtf(.5f * (-xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr;
ls_mag = sqrtf(1.f - fabsf(xl)) * ((yl + 1.f) * .5f) * mag_totall;
rs_mag = sqrtf(1.f - fabsf(xr)) * ((yr + 1.f) * .5f) * mag_totalr;
dstl[2 * n ] = fl_mag * cosf(fl_phase);
dstl[2 * n + 1] = fl_mag * sinf(fl_phase);
dstr[2 * n ] = fr_mag * cosf(fr_phase);
dstr[2 * n + 1] = fr_mag * sinf(fr_phase);
dstc[2 * n ] = c_re;
dstc[2 * n + 1] = c_im;
dstlfe[2 * n ] = lfe_re;
dstlfe[2 * n + 1] = lfe_im;
dstlb[2 * n ] = lb_mag * cosf(bl_phase);
dstlb[2 * n + 1] = lb_mag * sinf(bl_phase);
dstrb[2 * n ] = rb_mag * cosf(br_phase);
dstrb[2 * n + 1] = rb_mag * sinf(br_phase);
dstls[2 * n ] = ls_mag * cosf(sl_phase);
dstls[2 * n + 1] = ls_mag * sinf(sl_phase);
dstrs[2 * n ] = rs_mag * cosf(sr_phase);
dstrs[2 * n + 1] = rs_mag * sinf(sr_phase);
}
static void filter_stereo(AVFilterContext *ctx)
{
AudioSurroundContext *s = ctx->priv;
float *srcl, *srcr;
int n;
srcl = (float *)s->input->extended_data[0];
srcr = (float *)s->input->extended_data[1];
for (n = 0; n < s->buf_size; n++) {
float l_re = srcl[2 * n], r_re = srcr[2 * n];
float l_im = srcl[2 * n + 1], r_im = srcr[2 * n + 1];
float c_phase = atan2f(l_im + r_im, l_re + r_re);
float l_mag = hypotf(l_re, l_im);
float r_mag = hypotf(r_re, r_im);
float l_phase = atan2f(l_im, l_re);
float r_phase = atan2f(r_im, r_re);
float phase_dif = fabsf(l_phase - r_phase);
float mag_dif = (l_mag - r_mag) / (l_mag + r_mag);
float mag_total = hypotf(l_mag, r_mag);
float x, y;
if (phase_dif > M_PI)
phase_dif = 2 * M_PI - phase_dif;
stereo_position(mag_dif, phase_dif, &x, &y);
s->upmix_stereo(ctx, l_phase, r_phase, c_phase, mag_total, x, y, n);
}
}
static void filter_surround(AVFilterContext *ctx)
{
AudioSurroundContext *s = ctx->priv;
float *srcl, *srcr, *srcc;
int n;
srcl = (float *)s->input->extended_data[0];
srcr = (float *)s->input->extended_data[1];
srcc = (float *)s->input->extended_data[2];
for (n = 0; n < s->buf_size; n++) {
float l_re = srcl[2 * n], r_re = srcr[2 * n];
float l_im = srcl[2 * n + 1], r_im = srcr[2 * n + 1];
float c_re = srcc[2 * n], c_im = srcc[2 * n + 1];
float c_mag = hypotf(c_re, c_im);
float c_phase = atan2f(c_im, c_re);
float l_mag = hypotf(l_re, l_im);
float r_mag = hypotf(r_re, r_im);
float l_phase = atan2f(l_im, l_re);
float r_phase = atan2f(r_im, r_re);
float phase_dif = fabsf(l_phase - r_phase);
float mag_dif = (l_mag - r_mag) / (l_mag + r_mag);
float mag_total = hypotf(l_mag, r_mag);
float x, y;
if (phase_dif > M_PI)
phase_dif = 2 * M_PI - phase_dif;
stereo_position(mag_dif, phase_dif, &x, &y);
s->upmix_3_0(ctx, l_phase, r_phase, c_phase, c_mag, mag_total, x, y, n);
}
}
static void filter_2_1(AVFilterContext *ctx)
{
AudioSurroundContext *s = ctx->priv;
float *srcl, *srcr, *srclfe;
int n;
srcl = (float *)s->input->extended_data[0];
srcr = (float *)s->input->extended_data[1];
srclfe = (float *)s->input->extended_data[2];
for (n = 0; n < s->buf_size; n++) {
float l_re = srcl[2 * n], r_re = srcr[2 * n];
float l_im = srcl[2 * n + 1], r_im = srcr[2 * n + 1];
float lfe_re = srclfe[2 * n], lfe_im = srclfe[2 * n + 1];
float c_phase = atan2f(l_im + r_im, l_re + r_re);
float l_mag = hypotf(l_re, l_im);
float r_mag = hypotf(r_re, r_im);
float l_phase = atan2f(l_im, l_re);
float r_phase = atan2f(r_im, r_re);
float phase_dif = fabsf(l_phase - r_phase);
float mag_dif = (l_mag - r_mag) / (l_mag + r_mag);
float mag_total = hypotf(l_mag, r_mag);
float x, y;
if (phase_dif > M_PI)
phase_dif = 2 * M_PI - phase_dif;
stereo_position(mag_dif, phase_dif, &x, &y);
s->upmix_2_1(ctx, l_phase, r_phase, c_phase, mag_total, lfe_re, lfe_im, x, y, n);
}
}
static void filter_5_1_back(AVFilterContext *ctx)
{
AudioSurroundContext *s = ctx->priv;
float *srcl, *srcr, *srcc, *srclfe, *srcbl, *srcbr;
int n;
srcl = (float *)s->input->extended_data[0];
srcr = (float *)s->input->extended_data[1];
srcc = (float *)s->input->extended_data[2];
srclfe = (float *)s->input->extended_data[3];
srcbl = (float *)s->input->extended_data[4];
srcbr = (float *)s->input->extended_data[5];
for (n = 0; n < s->buf_size; n++) {
float fl_re = srcl[2 * n], fr_re = srcr[2 * n];
float fl_im = srcl[2 * n + 1], fr_im = srcr[2 * n + 1];
float c_re = srcc[2 * n], c_im = srcc[2 * n + 1];
float lfe_re = srclfe[2 * n], lfe_im = srclfe[2 * n + 1];
float bl_re = srcbl[2 * n], bl_im = srcbl[2 * n + 1];
float br_re = srcbr[2 * n], br_im = srcbr[2 * n + 1];
float fl_mag = hypotf(fl_re, fl_im);
float fr_mag = hypotf(fr_re, fr_im);
float fl_phase = atan2f(fl_im, fl_re);
float fr_phase = atan2f(fr_im, fr_re);
float bl_mag = hypotf(bl_re, bl_im);
float br_mag = hypotf(br_re, br_im);
float bl_phase = atan2f(bl_im, bl_re);
float br_phase = atan2f(br_im, br_re);
float phase_difl = fabsf(fl_phase - bl_phase);
float phase_difr = fabsf(fr_phase - br_phase);
float mag_difl = (fl_mag - bl_mag) / (fl_mag + bl_mag);
float mag_difr = (fr_mag - br_mag) / (fr_mag + br_mag);
float mag_totall = hypotf(fl_mag, bl_mag);
float mag_totalr = hypotf(fr_mag, br_mag);
float sl_phase = atan2f(fl_im + bl_im, fl_re + bl_re);
float sr_phase = atan2f(fr_im + br_im, fr_re + br_re);
float xl, yl;
float xr, yr;
if (phase_difl > M_PI)
phase_difl = 2 * M_PI - phase_difl;
if (phase_difr > M_PI)
phase_difr = 2 * M_PI - phase_difr;
stereo_position(mag_difl, phase_difl, &xl, &yl);
stereo_position(mag_difr, phase_difr, &xr, &yr);
s->upmix_5_1(ctx, c_re, c_im, lfe_re, lfe_im,
mag_totall, mag_totalr,
fl_phase, fr_phase,
bl_phase, br_phase,
sl_phase, sr_phase,
xl, yl, xr, yr, n);
}
}
static int init(AVFilterContext *ctx)
{
AudioSurroundContext *s = ctx->priv;
@ -584,54 +952,101 @@ static int init(AVFilterContext *ctx)
int i;
if (!(s->out_channel_layout = av_get_channel_layout(s->out_channel_layout_str))) {
av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
av_log(ctx, AV_LOG_ERROR, "Error parsing output channel layout '%s'.\n",
s->out_channel_layout_str);
return AVERROR(EINVAL);
}
if (!(s->in_channel_layout = av_get_channel_layout(s->in_channel_layout_str))) {
av_log(ctx, AV_LOG_ERROR, "Error parsing input channel layout '%s'.\n",
s->in_channel_layout_str);
return AVERROR(EINVAL);
}
if (s->lowcutf >= s->highcutf) {
av_log(ctx, AV_LOG_ERROR, "Low cut-off '%d' should be less than high cut-off '%d'.\n",
s->lowcutf, s->highcutf);
return AVERROR(EINVAL);
}
switch (s->out_channel_layout) {
case AV_CH_LAYOUT_MONO:
s->upmix = upmix_1_0;
break;
switch (s->in_channel_layout) {
case AV_CH_LAYOUT_STEREO:
s->upmix = upmix_stereo;
s->filter = filter_stereo;
switch (s->out_channel_layout) {
case AV_CH_LAYOUT_MONO:
s->upmix_stereo = upmix_1_0;
break;
case AV_CH_LAYOUT_STEREO:
s->upmix_stereo = upmix_stereo;
break;
case AV_CH_LAYOUT_2POINT1:
s->upmix_stereo = upmix_2_1;
break;
case AV_CH_LAYOUT_SURROUND:
s->upmix_stereo = upmix_3_0;
break;
case AV_CH_LAYOUT_3POINT1:
s->upmix_stereo = upmix_3_1;
break;
case AV_CH_LAYOUT_4POINT0:
s->upmix_stereo = upmix_4_0;
break;
case AV_CH_LAYOUT_4POINT1:
s->upmix_stereo = upmix_4_1;
break;
case AV_CH_LAYOUT_5POINT0_BACK:
s->upmix_stereo = upmix_5_0_back;
break;
case AV_CH_LAYOUT_5POINT1_BACK:
s->upmix_stereo = upmix_5_1_back;
break;
case AV_CH_LAYOUT_7POINT0:
s->upmix_stereo = upmix_7_0;
break;
case AV_CH_LAYOUT_7POINT1:
s->upmix_stereo = upmix_7_1;
break;
default:
goto fail;
}
break;
case AV_CH_LAYOUT_2POINT1:
s->upmix = upmix_2_1;
s->filter = filter_2_1;
switch (s->out_channel_layout) {
case AV_CH_LAYOUT_5POINT1_BACK:
s->upmix_2_1 = upmix_5_1_back_2_1;
break;
default:
goto fail;
}
break;
case AV_CH_LAYOUT_SURROUND:
s->upmix = upmix_3_0;
break;
case AV_CH_LAYOUT_3POINT1:
s->upmix = upmix_3_1;
break;
case AV_CH_LAYOUT_4POINT0:
s->upmix = upmix_4_0;
break;
case AV_CH_LAYOUT_4POINT1:
s->upmix = upmix_4_1;
break;
case AV_CH_LAYOUT_5POINT0_BACK:
s->upmix = upmix_5_0_back;
s->filter = filter_surround;
switch (s->out_channel_layout) {
case AV_CH_LAYOUT_3POINT1:
s->upmix_3_0 = upmix_3_1_surround;
break;
case AV_CH_LAYOUT_5POINT1_BACK:
s->upmix_3_0 = upmix_5_1_back_surround;
break;
default:
goto fail;
}
break;
case AV_CH_LAYOUT_5POINT1_BACK:
s->upmix = upmix_5_1_back;
break;
case AV_CH_LAYOUT_7POINT0:
s->upmix = upmix_7_0;
break;
case AV_CH_LAYOUT_7POINT1:
s->upmix = upmix_7_1;
s->filter = filter_5_1_back;
switch (s->out_channel_layout) {
case AV_CH_LAYOUT_7POINT1:
s->upmix_5_1 = upmix_7_1_5_1;
break;
default:
goto fail;
}
break;
default:
av_log(ctx, AV_LOG_ERROR, "Unsupported output channel layout '%s'.\n",
s->out_channel_layout_str);
fail:
av_log(ctx, AV_LOG_ERROR, "Unsupported upmix: '%s' -> '%s'.\n",
s->in_channel_layout_str, s->out_channel_layout_str);
return AVERROR(EINVAL);
}
@ -714,9 +1129,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_free(&in);
while (av_audio_fifo_size(s->fifo) >= s->buf_size) {
float *srcl, *srcr;
AVFrame *out;
int n, ret;
int ret;
ret = av_audio_fifo_peek(s->fifo, (void **)s->input->extended_data, s->buf_size);
if (ret < 0)
@ -724,29 +1138,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
ctx->internal->execute(ctx, fft_channel, NULL, NULL, inlink->channels);
srcl = (float *)s->input->extended_data[0];
srcr = (float *)s->input->extended_data[1];
for (n = 0; n < s->buf_size; n++) {
float l_re = srcl[2 * n], r_re = srcr[2 * n];
float l_im = srcl[2 * n + 1], r_im = srcr[2 * n + 1];
float c_phase = atan2f(l_im + r_im, l_re + r_re);
float l_mag = hypotf(l_re, l_im);
float r_mag = hypotf(r_re, r_im);
float l_phase = atan2f(l_im, l_re);
float r_phase = atan2f(r_im, r_re);
float phase_dif = fabsf(l_phase - r_phase);
float mag_dif = (l_mag - r_mag) / (l_mag + r_mag);
float mag_total = hypotf(l_mag, r_mag);
float x, y;
if (phase_dif > M_PI)
phase_dif = 2 * M_PI - phase_dif;
stereo_position(mag_dif, phase_dif, &x, &y);
s->upmix(ctx, l_phase, r_phase, c_phase, mag_total, x, y, n);
}
s->filter(ctx);
out = ff_get_audio_buffer(outlink, s->hop_size);
if (!out)
@ -792,6 +1184,7 @@ static av_cold void uninit(AVFilterContext *ctx)
static const AVOption surround_options[] = {
{ "chl_out", "set output channel layout", OFFSET(out_channel_layout_str), AV_OPT_TYPE_STRING, {.str="5.1"}, 0, 0, FLAGS },
{ "chl_in", "set input channel layout", OFFSET(in_channel_layout_str), AV_OPT_TYPE_STRING, {.str="stereo"},0, 0, FLAGS },
{ "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS },
{ "level_out", "set output level", OFFSET(level_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS },
{ "lfe", "output LFE", OFFSET(output_lfe), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },