X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Faf_rubberband.c;h=b42e67f09ba5b8629479c295275991d1d3ea630a;hb=985c0dac674846721ec8ff23344c16ac7d1c9a1e;hp=ea6f4ff2c9c85bdcc69b77a6060f5944e87af851;hpb=a12063b118ad05409ff775ba30fab00265ad3031;p=ffmpeg diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index ea6f4ff2c9c..b42e67f09ba 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -24,6 +24,7 @@ #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "internal.h" @@ -36,15 +37,17 @@ typedef struct RubberBandContext { smoothing, formant, opitch, channels; int64_t nb_samples_out; int64_t nb_samples_in; - int flushed; + int64_t first_pts; + int nb_samples; } RubberBandContext; #define OFFSET(x) offsetof(RubberBandContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define AT AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM static const AVOption rubberband_options[] = { - { "tempo", "set tempo scale factor", OFFSET(tempo), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, A }, - { "pitch", "set pitch scale factor", OFFSET(pitch), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, A }, + { "tempo", "set tempo scale factor", OFFSET(tempo), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, AT }, + { "pitch", "set pitch scale factor", OFFSET(pitch), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 100, AT }, { "transients", "set transients", OFFSET(transients), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, A, "transients" }, { "crisp", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsCrisp}, 0, 0, A, "transients" }, { "mixed", 0, 0, AV_OPT_TYPE_CONST, {.i64=RubberBandOptionTransientsMixed}, 0, 0, A, "transients" }, @@ -118,12 +121,16 @@ static int query_formats(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *in) { - RubberBandContext *s = inlink->dst->priv; - AVFilterLink *outlink = inlink->dst->outputs[0]; + AVFilterContext *ctx = inlink->dst; + RubberBandContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; int ret = 0, nb_samples; - rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, 0); + if (s->first_pts == AV_NOPTS_VALUE) + s->first_pts = in->pts; + + rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, ff_outlink_get_status(inlink)); s->nb_samples_in += in->nb_samples; nb_samples = rubberband_available(s->rbs); @@ -133,7 +140,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_free(&in); return AVERROR(ENOMEM); } - out->pts = av_rescale_q(s->nb_samples_out, + out->pts = s->first_pts + av_rescale_q(s->nb_samples_out, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples); @@ -143,7 +150,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_free(&in); - return ret; + if (ff_inlink_queued_samples(inlink) >= s->nb_samples) + ff_filter_set_ready(ctx, 100); + return ret < 0 ? ret : nb_samples; } static int config_input(AVFilterLink *inlink) @@ -157,84 +166,53 @@ static int config_input(AVFilterLink *inlink) if (s->rbs) rubberband_delete(s->rbs); s->rbs = rubberband_new(inlink->sample_rate, inlink->channels, opts, 1. / s->tempo, s->pitch); + if (!s->rbs) + return AVERROR(ENOMEM); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = rubberband_get_samples_required(s->rbs); + s->nb_samples = rubberband_get_samples_required(s->rbs); + s->first_pts = AV_NOPTS_VALUE; return 0; } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; - RubberBandContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - int ret = 0; - - ret = ff_request_frame(ctx->inputs[0]); - - if (ret == AVERROR_EOF && !s->flushed) { - if (rubberband_available(s->rbs) > 0) { - AVFrame *out = ff_get_audio_buffer(inlink, 1); - int nb_samples; - - if (!out) - return AVERROR(ENOMEM); - - rubberband_process(s->rbs, (const float *const *)out->data, 1, 1); - av_frame_free(&out); - nb_samples = rubberband_available(s->rbs); - - if (nb_samples > 0) { - out = ff_get_audio_buffer(outlink, nb_samples); - if (!out) - return AVERROR(ENOMEM); - out->pts = av_rescale_q(s->nb_samples_out, - (AVRational){ 1, outlink->sample_rate }, - outlink->time_base); - nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples); - out->nb_samples = nb_samples; - ret = ff_filter_frame(outlink, out); - s->nb_samples_out += nb_samples; - } - } - s->flushed = 1; - av_log(ctx, AV_LOG_DEBUG, "nb_samples_in %"PRId64" nb_samples_out %"PRId64"\n", - s->nb_samples_in, s->nb_samples_out); + AVFilterLink *outlink = ctx->outputs[0]; + RubberBandContext *s = ctx->priv; + AVFrame *in = NULL; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) { + ret = filter_frame(inlink, in); + if (ret != 0) + return ret; } - return ret; + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags) { RubberBandContext *s = ctx->priv; + int ret; - if (!strcmp(cmd, "tempo")) { - double arg; - - sscanf(args, "%lf", &arg); - if (arg < 0.01 || arg > 100) { - av_log(ctx, AV_LOG_ERROR, - "Tempo scale factor '%f' out of range\n", arg); - return AVERROR(EINVAL); - } - rubberband_set_time_ratio(s->rbs, 1. / arg); - } - - if (!strcmp(cmd, "pitch")) { - double arg; + ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); + if (ret < 0) + return ret; - sscanf(args, "%lf", &arg); - if (arg < 0.01 || arg > 100) { - av_log(ctx, AV_LOG_ERROR, - "Pitch scale factor '%f' out of range\n", arg); - return AVERROR(EINVAL); - } - rubberband_set_pitch_scale(s->rbs, arg); - } + rubberband_set_time_ratio(s->rbs, 1. / s->tempo); + rubberband_set_pitch_scale(s->rbs, s->pitch); + s->nb_samples = rubberband_get_samples_required(s->rbs); return 0; } @@ -244,7 +222,6 @@ static const AVFilterPad rubberband_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -253,7 +230,6 @@ static const AVFilterPad rubberband_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = request_frame, }, { NULL } }; @@ -265,6 +241,7 @@ AVFilter ff_af_rubberband = { .priv_size = sizeof(RubberBandContext), .priv_class = &rubberband_class, .uninit = uninit, + .activate = activate, .inputs = rubberband_inputs, .outputs = rubberband_outputs, .process_command = process_command,