FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/asrc_afdelaysrc.c
Date: 2024-11-20 23:03:26
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
29 typedef struct AFDelaySrcContext {
30 const AVClass *class;
31
32 double delay;
33 int sample_rate;
34 int nb_samples;
35 int nb_taps;
36 AVChannelLayout chlayout;
37
38 int64_t pts;
39 } AFDelaySrcContext;
40
41 static float sincf(float x)
42 {
43 if (x == 0.f)
44 return 1.f;
45 return sinf(M_PI * x) / (M_PI * x);
46 }
47
48 static int activate(AVFilterContext *ctx)
49 {
50 AVFilterLink *outlink = ctx->outputs[0];
51 AFDelaySrcContext *s = ctx->priv;
52 AVFrame *frame = NULL;
53 int nb_samples;
54 float *dst;
55
56 if (!ff_outlink_frame_wanted(outlink))
57 return FFERROR_NOT_READY;
58
59 nb_samples = FFMIN(s->nb_samples, s->nb_taps - s->pts);
60 if (nb_samples <= 0) {
61 ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
62 return 0;
63 }
64
65 if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
66 return AVERROR(ENOMEM);
67
68 dst = (float *)frame->extended_data[0];
69 for (int n = 0; n < nb_samples; n++) {
70 float x = s->pts + n;
71 dst[n] = sincf(x - s->delay) * cosf(M_PI * (x - s->delay) / s->nb_taps) / sincf((x - s->delay) / s->nb_taps);
72 }
73
74 for (int ch = 1; ch < frame->ch_layout.nb_channels; ch++)
75 memcpy(frame->extended_data[ch], dst, sizeof(*dst) * nb_samples);
76
77 frame->pts = s->pts;
78 s->pts += nb_samples;
79
80 return ff_filter_frame(outlink, frame);
81 }
82
83 static int query_formats(const AVFilterContext *ctx,
84 AVFilterFormatsConfig **cfg_in,
85 AVFilterFormatsConfig **cfg_out)
86 {
87 const AFDelaySrcContext *s = ctx->priv;
88 AVChannelLayout chlayouts[] = { s->chlayout, { 0 } };
89 int sample_rates[] = { s->sample_rate, -1 };
90 static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP,
91 AV_SAMPLE_FMT_NONE };
92 int ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts);
93 if (ret < 0)
94 return ret;
95
96 ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, chlayouts);
97 if (ret < 0)
98 return ret;
99
100 return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates);
101 }
102
103 static int config_output(AVFilterLink *outlink)
104 {
105 AVFilterContext *ctx = outlink->src;
106 AFDelaySrcContext *s = ctx->priv;
107
108 outlink->sample_rate = s->sample_rate;
109 s->pts = 0;
110 if (s->nb_taps <= 0)
111 s->nb_taps = s->delay * 8 + 1;
112
113 return 0;
114 }
115
116 static const AVFilterPad afdelaysrc_outputs[] = {
117 {
118 .name = "default",
119 .type = AVMEDIA_TYPE_AUDIO,
120 .config_props = config_output,
121 },
122 };
123
124 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
125 #define OFFSET(x) offsetof(AFDelaySrcContext, x)
126
127 static const AVOption afdelaysrc_options[] = {
128 { "delay", "set fractional delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE,{.dbl=0}, 0, INT16_MAX, AF },
129 { "d", "set fractional delay", OFFSET(delay), AV_OPT_TYPE_DOUBLE,{.dbl=0}, 0, INT16_MAX, AF },
130 { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF },
131 { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF },
132 { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF },
133 { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF },
134 { "taps", "set number of taps for delay filter", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF },
135 { "t", "set number of taps for delay filter", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF },
136 { "channel_layout", "set channel layout", OFFSET(chlayout), AV_OPT_TYPE_CHLAYOUT,{.str="stereo"},0, 0, AF },
137 { "c", "set channel layout", OFFSET(chlayout), AV_OPT_TYPE_CHLAYOUT,{.str="stereo"},0, 0, AF },
138 { NULL }
139 };
140
141 AVFILTER_DEFINE_CLASS(afdelaysrc);
142
143 const AVFilter ff_asrc_afdelaysrc = {
144 .name = "afdelaysrc",
145 .description = NULL_IF_CONFIG_SMALL("Generate a Fractional delay FIR coefficients."),
146 .priv_size = sizeof(AFDelaySrcContext),
147 .priv_class = &afdelaysrc_class,
148 .activate = activate,
149 .inputs = NULL,
150 FILTER_OUTPUTS(afdelaysrc_outputs),
151 FILTER_QUERY_FUNC2(query_formats),
152 };
153