FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/asrc_afdelaysrc.c
Date: 2024-03-28 14:59:00
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/avassert.h"
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/opt.h"
24
25 #include "audio.h"
26 #include "avfilter.h"
27 #include "filters.h"
28 #include "formats.h"
29 #include "internal.h"
30
31 typedef struct AFDelaySrcContext {
32 const AVClass *class;
33
34 double delay;
35 int sample_rate;
36 int nb_samples;
37 int nb_taps;
38 AVChannelLayout chlayout;
39
40 int64_t pts;
41 } AFDelaySrcContext;
42
43 static float sincf(float x)
44 {
45 if (x == 0.f)
46 return 1.f;
47 return sinf(M_PI * x) / (M_PI * x);
48 }
49
50 static int activate(AVFilterContext *ctx)
51 {
52 AVFilterLink *outlink = ctx->outputs[0];
53 AFDelaySrcContext *s = ctx->priv;
54 AVFrame *frame = NULL;
55 int nb_samples;
56 float *dst;
57
58 if (!ff_outlink_frame_wanted(outlink))
59 return FFERROR_NOT_READY;
60
61 nb_samples = FFMIN(s->nb_samples, s->nb_taps - s->pts);
62 if (nb_samples <= 0) {
63 ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
64 return 0;
65 }
66
67 if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
68 return AVERROR(ENOMEM);
69
70 dst = (float *)frame->extended_data[0];
71 for (int n = 0; n < nb_samples; n++) {
72 float x = s->pts + n;
73 dst[n] = sincf(x - s->delay) * cosf(M_PI * (x - s->delay) / s->nb_taps) / sincf((x - s->delay) / s->nb_taps);
74 }
75
76 for (int ch = 1; ch < frame->ch_layout.nb_channels; ch++)
77 memcpy(frame->extended_data[ch], dst, sizeof(*dst) * nb_samples);
78
79 frame->pts = s->pts;
80 s->pts += nb_samples;
81
82 return ff_filter_frame(outlink, frame);
83 }
84
85 static int query_formats(AVFilterContext *ctx)
86 {
87 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_list(ctx, sample_fmts);
93 if (ret < 0)
94 return ret;
95
96 ret = ff_set_common_channel_layouts_from_list(ctx, chlayouts);
97 if (ret < 0)
98 return ret;
99
100 return ff_set_common_samplerates_from_list(ctx, 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_FUNC(query_formats),
152 };
153