On 4/19/19, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
2019-04-18 23:17 GMT+02:00, Paul B Mahol <onemda@gmail.com>:
Signed-off-by: Paul B Mahol <onemda@gmail.com> --- libavfilter/Makefile | 1 + libavfilter/af_aupsample.c | 159 +++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 3 files changed, 161 insertions(+) create mode 100644 libavfilter/af_aupsample.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 682df45ef5..a38bc35231 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -86,6 +86,7 @@ OBJS-$(CONFIG_ASTATS_FILTER) += af_astats.o OBJS-$(CONFIG_ASTREAMSELECT_FILTER) += f_streamselect.o framesync.o OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o OBJS-$(CONFIG_ATRIM_FILTER) += trim.o +OBJS-$(CONFIG_AUPSAMPLE_FILTER) += af_aupsample.o OBJS-$(CONFIG_AZMQ_FILTER) += f_zmq.o OBJS-$(CONFIG_BANDPASS_FILTER) += af_biquads.o OBJS-$(CONFIG_BANDREJECT_FILTER) += af_biquads.o diff --git a/libavfilter/af_aupsample.c b/libavfilter/af_aupsample.c new file mode 100644 index 0000000000..ee35b9c0c6 --- /dev/null +++ b/libavfilter/af_aupsample.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "libavutil/samplefmt.h" +#include "avfilter.h" +#include "audio.h" +#include "filters.h" +#include "internal.h" + +typedef struct AudioUpSampleContext { + const AVClass *class; + int factor; + + int64_t next_pts; +} AudioUpSampleContext; + +#define OFFSET(x) offsetof(AudioUpSampleContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption aupsample_options[] = { + { "factor", "set upsampling factor", OFFSET(factor), AV_OPT_TYPE_INT, {.i64=1}, 1, 64, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(aupsample); + +static int query_formats(AVFilterContext *ctx) +{ + AudioUpSampleContext *s = ctx->priv; + AVFilterChannelLayouts *layouts; + AVFilterFormats *formats; + int sample_rates[] = { 44100, -1 }; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + AVFilterFormats *avff; + int ret; + + if (!ctx->inputs[0]->in_samplerates || + !ctx->inputs[0]->in_samplerates->nb_formats) { + return AVERROR(EAGAIN); + } + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + avff = ctx->inputs[0]->in_samplerates; + sample_rates[0] = avff->formats[0]; + if (!ctx->inputs[0]->out_samplerates) + if ((ret = ff_formats_ref(ff_make_format_list(sample_rates), + &ctx->inputs[0]->out_samplerates)) < 0) + return ret; + + sample_rates[0] = avff->formats[0] * s->factor; + return ff_formats_ref(ff_make_format_list(sample_rates), + &ctx->outputs[0]->in_samplerates); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioUpSampleContext *s = ctx->priv; + + s->next_pts = AV_NOPTS_VALUE; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioUpSampleContext *s = ctx->priv; + const int factor = s->factor; + AVFrame *out; + + if (s->factor == 1) + return ff_filter_frame(outlink, in); + + out = ff_get_audio_buffer(outlink, in->nb_samples * s->factor); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + if (s->next_pts == AV_NOPTS_VALUE) + s->next_pts = in->pts; + + for (int c = 0; c < in->channels; c++) { + const double *src = (const double *)in->extended_data[c]; + double *dst = (double *)out->extended_data[c]; + + for (int n = 0; n < in->nb_samples; n++) + dst[n*factor] = src[n]; + } + + out->pts = s->next_pts; + s->next_pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); + av_frame_free(&in); + return ff_filter_frame(ctx->outputs[0], out); +} + +static const AVFilterPad aupsample_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad aupsample_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_aupsample = { + .name = "aupsample", + .description = NULL_IF_CONFIG_SMALL("Upsample audio by integer factor."),
Is it faster? Better quality?
This is not same as resampling. This is used as part of other filtering. Namely when filter needs to oversample audio when processing - it then upsample audio before processing and downsample it by same factor after processing it.