提交 683a1599 编写于 作者: P Paul B Mahol

avfilter/af_ladspa: add latency compensation

上级 842bc312
...@@ -4197,6 +4197,9 @@ If not specified, or the expressed duration is negative, the audio is ...@@ -4197,6 +4197,9 @@ If not specified, or the expressed duration is negative, the audio is
supposed to be generated forever. supposed to be generated forever.
Only used if plugin have zero inputs. Only used if plugin have zero inputs.
@item latency, l
Enable latency compensation, by default is disabled.
Only used if plugin have inputs.
@end table @end table
@subsection Examples @subsection Examples
......
...@@ -64,6 +64,9 @@ typedef struct LADSPAContext { ...@@ -64,6 +64,9 @@ typedef struct LADSPAContext {
int nb_samples; int nb_samples;
int64_t pts; int64_t pts;
int64_t duration; int64_t duration;
int in_trim;
int out_pad;
int latency;
} LADSPAContext; } LADSPAContext;
#define OFFSET(x) offsetof(LADSPAContext, x) #define OFFSET(x) offsetof(LADSPAContext, x)
...@@ -81,11 +84,28 @@ static const AVOption ladspa_options[] = { ...@@ -81,11 +84,28 @@ static const AVOption ladspa_options[] = {
{ "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
{ "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS },
{ "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS },
{ "latency", "enable latency compensation", OFFSET(latency), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
{ "l", "enable latency compensation", OFFSET(latency), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
{ NULL } { NULL }
}; };
AVFILTER_DEFINE_CLASS(ladspa); AVFILTER_DEFINE_CLASS(ladspa);
static int find_latency(AVFilterContext *ctx, LADSPAContext *s)
{
int latency = 0;
for (int ctl = 0; ctl < s->nb_outputcontrols; ctl++) {
if (av_strcasecmp("latency", s->desc->PortNames[s->ocmap[ctl]]))
continue;
latency = lrintf(s->octlv[ctl]);
break;
}
return latency;
}
static void print_ctl_info(AVFilterContext *ctx, int level, static void print_ctl_info(AVFilterContext *ctx, int level,
LADSPAContext *s, int ctl, unsigned long *map, LADSPAContext *s, int ctl, unsigned long *map,
LADSPA_Data *values, int print) LADSPA_Data *values, int print)
...@@ -143,12 +163,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) ...@@ -143,12 +163,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
LADSPAContext *s = ctx->priv; LADSPAContext *s = ctx->priv;
AVFrame *out; AVFrame *out;
int i, h, p; int i, h, p, new_out_samples;
av_assert0(in->channels == (s->nb_inputs * s->nb_handles)); av_assert0(in->channels == (s->nb_inputs * s->nb_handles));
if (!s->nb_outputs || if (!s->nb_outputs ||
(av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs && (av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs &&
s->in_trim == 0 && s->out_pad == 0 &&
!(s->desc->Properties & LADSPA_PROPERTY_INPLACE_BROKEN))) { !(s->desc->Properties & LADSPA_PROPERTY_INPLACE_BROKEN))) {
out = in; out = in;
} else { } else {
...@@ -176,6 +197,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) ...@@ -176,6 +197,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
} }
s->desc->run(s->handles[h], in->nb_samples); s->desc->run(s->handles[h], in->nb_samples);
if (s->latency)
s->in_trim = s->out_pad = find_latency(ctx, s);
s->latency = 0;
} }
for (i = 0; i < s->nb_outputcontrols; i++) for (i = 0; i < s->nb_outputcontrols; i++)
...@@ -184,6 +208,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) ...@@ -184,6 +208,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
if (out != in) if (out != in)
av_frame_free(&in); av_frame_free(&in);
new_out_samples = out->nb_samples;
if (s->in_trim > 0) {
int trim = FFMIN(new_out_samples, s->in_trim);
new_out_samples -= trim;
s->in_trim -= trim;
}
if (new_out_samples <= 0) {
av_frame_free(&out);
return 0;
} else if (new_out_samples < out->nb_samples) {
int offset = out->nb_samples - new_out_samples;
for (int ch = 0; ch < out->channels; ch++)
memmove(out->extended_data[ch], out->extended_data[ch] + sizeof(float) * offset,
sizeof(float) * new_out_samples);
out->nb_samples = new_out_samples;
}
return ff_filter_frame(ctx->outputs[0], out); return ff_filter_frame(ctx->outputs[0], out);
} }
...@@ -195,8 +238,19 @@ static int request_frame(AVFilterLink *outlink) ...@@ -195,8 +238,19 @@ static int request_frame(AVFilterLink *outlink)
int64_t t; int64_t t;
int i; int i;
if (ctx->nb_inputs) if (ctx->nb_inputs) {
return ff_request_frame(ctx->inputs[0]); int ret = ff_request_frame(ctx->inputs[0]);
if (ret == AVERROR_EOF && s->out_pad > 0) {
AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(2048, s->out_pad));
if (!frame)
return AVERROR(ENOMEM);
s->out_pad -= frame->nb_samples;
return filter_frame(ctx->inputs[0], frame);
}
return ret;
}
t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate); t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate);
if (s->duration >= 0 && t >= s->duration) if (s->duration >= 0 && t >= s->duration)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册