FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/asrc_afdelaysrc.c
Date: 2024-07-17 14:05:47
Exec Total Coverage
Lines: 0 44 0.0%
Functions: 0 4 0.0%
Branches: 0 18 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2023 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/channel_layout.h"
22 #include "libavutil/opt.h"
23
24 #include "audio.h"
25 #include "avfilter.h"
26 #include "filters.h"
27 #include "formats.h"
28 #include "internal.h"
29
30 typedef struct AFDelaySrcContext {
31 const AVClass *class;
32
33 double delay;
34 int sample_rate;
35 int nb_samples;
36 int nb_taps;
37 AVChannelLayout chlayout;
38
39 int64_t pts;
40 } AFDelaySrcContext;
41
42 static float sincf(float x)
43 {
44 if (x == 0.f)
45 return 1.f;
46 return sinf(M_PI * x) / (M_PI * x);
47 }
48
49 static int activate(AVFilterContext *ctx)
50 {
51 AVFilterLink *outlink = ctx->outputs[0];
52 AFDelaySrcContext *s = ctx->priv;
53 AVFrame *frame = NULL;
54 int nb_samples;
55 float *dst;
56
57 if (!ff_outlink_frame_wanted(outlink))
58 return FFERROR_NOT_READY;
59
60 nb_samples = FFMIN(s->nb_samples, s->nb_taps - s->pts);
61 if (nb_samples <= 0) {
62 ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
63 return 0;
64 }
65
66 if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
67 return AVERROR(ENOMEM);
68
69 dst = (float *)frame->extended_data[0];
70 for (int n = 0; n < nb_samples; n++) {
71 float x = s->pts + n;
72 dst[n] = sincf(x - s->delay) * cosf(M_PI * (x - s->delay) / s->nb_taps) / sincf((x - s->delay) / s->nb_taps);
73 }
74
75 for (int ch = 1; ch < frame->ch_layout.nb_channels; ch++)
76 memcpy(frame->extended_data[ch], dst, sizeof(*dst) * nb_samples);
77
78 frame->pts = s->pts;
79 s->pts += nb_samples;
80
81 return ff_filter_frame(outlink, frame);
82 }
83
84 static int query_formats(AVFilterContext *ctx)
85 {
86 AFDelaySrcContext *s = ctx->priv;
87 AVChannelLayout chlayouts[] = { s->chlayout, { 0 } };
88 int sample_rates[] = { s->sample_rate, -1 };
89 static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP,
90 AV_SAMPLE_FMT_NONE };
91 int ret = ff_set_common_formats_from_list(ctx, sample_fmts);
92 if (ret < 0)
93 return ret;
94
95 ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts);
96 if (ret < 0)
97 return ret;
98
99 return ff_set_common_samplerates_from_list(ctx, sample_rates);
100 }
101
102 static int config_output(AVFilterLink *outlink)
103 {
104 AVFilterContext *ctx = outlink->src;
105 AFDelaySrcContext *s = ctx->priv;
106
107 outlink->sample_rate = s->sample_rate;
108 s->pts = 0;
109 if (s->nb_taps <= 0)
110 s->nb_taps = s->delay * 8 + 1;
111
112 return 0;
113 }
114
115 static const AVFilterPad afdelaysrc_outputs[] = {
116 {
117 .name = "default",
118 .type = AVMEDIA_TYPE_AUDIO,
119 .config_props = config_output,
120 },
121 };
122
123 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
124 #define OFFSET(x) offsetof(AFDelaySrcContext, x)
125
126 static const AVOption afdelaysrc_options[] = {
127 { "delay", "set fractional delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE,{.dbl=0}, 0, INT16_MAX, AF },
128 { "d", "set fractional delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE,{.dbl=0}, 0, INT16_MAX, AF },
129 { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF },
130 { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF },
131 { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF },
132 { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF },
133 { "taps", "set number of taps for delay filter", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF },
134 { "t", "set number of taps for delay filter", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF },
135 { "channel_layout", "set channel layout", OFFSET(chlayout), AV_OPT_TYPE_CHLAYOUT,{.str="stereo"},0, 0, AF },
136 { "c", "set channel layout", OFFSET(chlayout), AV_OPT_TYPE_CHLAYOUT,{.str="stereo"},0, 0, AF },
137 { NULL }
138 };
139
140 AVFILTER_DEFINE_CLASS(afdelaysrc);
141
142 const AVFilter ff_asrc_afdelaysrc = {
143 .name = "afdelaysrc",
144 .description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."),
145 .priv_size = sizeof(AFDelaySrcContext),
146 .priv_class = &afdelaysrc_class,
147 .activate = activate,
148 .inputs = NULL,
149 FILTER_OUTPUTS(afdelaysrc_outputs),
150 FILTER_QUERY_FUNC(query_formats),
151 };
152