From patchwork Thu Apr 18 21:17:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 12799 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 2F0CD448B07 for ; Fri, 19 Apr 2019 00:17:49 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 17F8B6808E8; Fri, 19 Apr 2019 00:17:49 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3FF9A6808C1 for ; Fri, 19 Apr 2019 00:17:46 +0300 (EEST) Received: by mail-wm1-f67.google.com with SMTP id q16so4253202wmj.3 for ; Thu, 18 Apr 2019 14:17:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=uH2PLNQw1PsprjyoU7GFUvxWdNJcnISfsE8wqgdq9yI=; b=TLBG19BOQwLjNY+MbDLVEG+pMTxEcCk+o2p7VoWjoURbNnPts0Sj/JBvqERudM7nSK ODgUpiCZ3CWL7nZqrUvRsQeUHyXqIVYMTKqpTL0dI+XDByQTg0lTyvlwPjN2Rdr+kZik HEHXDBm1Dc8g20AtXLzbWrbZU85Isd7tO4KTV7mLZn3wB+ExdBGeOd8GeDHvLcywcVat sKn5f/rlktdv/1Usx9g+LG7ghrBTMHmBys70hnCLjAmgn/W9qQ4WkYZ4o7P1OQZdMHTS ZgmPm8xwNt2LXH0PgOa3fFRYWj+Stmaxq9fouhzxX1RmOktQvWsh0GGiLgagbfaTukFG GlCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=uH2PLNQw1PsprjyoU7GFUvxWdNJcnISfsE8wqgdq9yI=; b=FCSjKMBpP0Pw670yHe31xgdfkuGYbl3ymayyYvBeNjv8DFXVV1YWKFMZrwJCOnmo3F qgKS950CFg/ulNDULFLWqYu1jBBtMfSpyIqtB8r7yw14qledekSckS2GZ5naOhV8DkAA Bu7S1TkOFwk+ZnqfI+5r4fp96ziHNwWTdzXdxaqtnHth1Z3mhUnHrOPGC9GqGrcBmByi wlthrzYXtn9PFYd81tiZAaD5gJXgWdpLeTttpH8lE1ZyUNnovfUTcCFtw48X0asEug6y ACcfJ+DIhe1iZ08U3yajUgm68UWNkS6BDttMrs0+5FssZINM1+/QJq7te9xukLDzPHm5 Eecg== X-Gm-Message-State: APjAAAWp8ERYPfs4MWi3wNjljGba3es1u9dPVTUleP0St589uxwOjhoK WC5ggoDi06DaLquVXKm7/y8SApsC X-Google-Smtp-Source: APXvYqzdRRb5FnGnoBUUgghgW2pvVxfnVVQBZMD7AkSYKp9DrCGmhnwp0Y2nqUttqZY95CoGOn8T+A== X-Received: by 2002:a1c:9617:: with SMTP id y23mr245107wmd.31.1555622265309; Thu, 18 Apr 2019 14:17:45 -0700 (PDT) Received: from localhost.localdomain ([37.244.238.255]) by smtp.gmail.com with ESMTPSA id v190sm3845906wme.18.2019.04.18.14.17.44 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 18 Apr 2019 14:17:44 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Thu, 18 Apr 2019 23:17:34 +0200 Message-Id: <20190418211734.11300-3-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190418211734.11300-1-onemda@gmail.com> References: <20190418211734.11300-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH 3/3] avfilter: add audio downsample filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- doc/filters.texi | 15 +++ libavfilter/Makefile | 1 + libavfilter/af_adownsample.c | 171 +++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 188 insertions(+) create mode 100644 libavfilter/af_adownsample.c diff --git a/doc/filters.texi b/doc/filters.texi index 465eeb4732..d6aac5730d 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -714,6 +714,21 @@ Compute derivative/integral of audio stream. Applying both filters one after another produces original audio. +@section adownsample, aupsample +Downsample or upsample audio by integer factor. + +For downsampling only the first out of each factor samples is retained, +the others are discarded +For upsampling, factor-1 zero-value samples are inserted between each pair of input samples. +As a result, the original spectrum is replicated into the new frequency space and attenuated. + +A description of the accepted parameters follows. + +@table @option +@item factor +Set factor of downsampling/upsampling. Default is @code{1}. +@end table + @section aecho Apply echoing to the input audio. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index a38bc35231..ed36454f9e 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -43,6 +43,7 @@ OBJS-$(CONFIG_ADECLICK_FILTER) += af_adeclick.o OBJS-$(CONFIG_ADECLIP_FILTER) += af_adeclick.o OBJS-$(CONFIG_ADELAY_FILTER) += af_adelay.o OBJS-$(CONFIG_ADERIVATIVE_FILTER) += af_aderivative.o +OBJS-$(CONFIG_ADOWNSAMPLE_FILTER) += af_adownsample.o OBJS-$(CONFIG_AECHO_FILTER) += af_aecho.o OBJS-$(CONFIG_AEMPHASIS_FILTER) += af_aemphasis.o OBJS-$(CONFIG_AEVAL_FILTER) += aeval.o diff --git a/libavfilter/af_adownsample.c b/libavfilter/af_adownsample.c new file mode 100644 index 0000000000..1ee661e383 --- /dev/null +++ b/libavfilter/af_adownsample.c @@ -0,0 +1,171 @@ +/* + * 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 AudioDownSampleContext { + const AVClass *class; + int factor; + + int64_t next_pts; +} AudioDownSampleContext; + +#define OFFSET(x) offsetof(AudioDownSampleContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption adownsample_options[] = { + { "factor", "set downsampling factor", OFFSET(factor), AV_OPT_TYPE_INT, {.i64=1}, 1, 64, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(adownsample); + +static int query_formats(AVFilterContext *ctx) +{ + AudioDownSampleContext *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; + AudioDownSampleContext *s = ctx->priv; + + s->next_pts = AV_NOPTS_VALUE; + + return 0; +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioDownSampleContext *s = ctx->priv; + const int factor = s->factor; + AVFrame *in, *out; + int nb_samples; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + nb_samples = ff_inlink_queued_samples(inlink); + + if (nb_samples >= s->factor) { + nb_samples = (nb_samples / factor) * factor; + ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &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 < out->nb_samples; n++) + dst[n] = src[n * factor]; + } + + 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(outlink, out); + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static const AVFilterPad adownsample_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad adownsample_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_adownsample = { + .name = "adownsample", + .description = NULL_IF_CONFIG_SMALL("Downsample audio by integer factor."), + .query_formats = query_formats, + .priv_size = sizeof(AudioDownSampleContext), + .priv_class = &adownsample_class, + .activate = activate, + .inputs = adownsample_inputs, + .outputs = adownsample_outputs, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 29b372a1db..ddff0741a4 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -35,6 +35,7 @@ extern AVFilter ff_af_adeclick; extern AVFilter ff_af_adeclip; extern AVFilter ff_af_adelay; extern AVFilter ff_af_aderivative; +extern AVFilter ff_af_adownsample; extern AVFilter ff_af_aecho; extern AVFilter ff_af_aemphasis; extern AVFilter ff_af_aeval;