FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_tremolo.c
Date: 2024-07-16 12:46:59
Exec Total Coverage
Lines: 37 44 84.1%
Functions: 3 3 100.0%
Branches: 11 16 68.8%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2015 Kyle Swanson <k@ylo.ph>.
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/mem.h"
22 #include "libavutil/opt.h"
23 #include "avfilter.h"
24 #include "internal.h"
25 #include "audio.h"
26
27 typedef struct TremoloContext {
28 const AVClass *class;
29 double freq;
30 double depth;
31 double *table;
32 int table_size;
33 int index;
34 } TremoloContext;
35
36 #define OFFSET(x) offsetof(TremoloContext, x)
37 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
38
39 static const AVOption tremolo_options[] = {
40 { "f", "set frequency in hertz", OFFSET(freq), AV_OPT_TYPE_DOUBLE, {.dbl = 5.0}, 0.1, 20000.0, FLAGS },
41 { "d", "set depth as percentage", OFFSET(depth), AV_OPT_TYPE_DOUBLE, {.dbl = 0.5}, 0.0, 1.0, FLAGS },
42 { NULL }
43 };
44
45 AVFILTER_DEFINE_CLASS(tremolo);
46
47 6 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
48 {
49 6 AVFilterContext *ctx = inlink->dst;
50 6 AVFilterLink *outlink = ctx->outputs[0];
51 6 TremoloContext *s = ctx->priv;
52 6 const double *src = (const double *)in->data[0];
53 6 const int channels = inlink->ch_layout.nb_channels;
54 6 const int nb_samples = in->nb_samples;
55 AVFrame *out;
56 double *dst;
57 int n, c;
58
59
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (av_frame_is_writable(in)) {
60 6 out = in;
61 } else {
62 out = ff_get_audio_buffer(outlink, in->nb_samples);
63 if (!out) {
64 av_frame_free(&in);
65 return AVERROR(ENOMEM);
66 }
67 av_frame_copy_props(out, in);
68 }
69 6 dst = (double *)out->data[0];
70
71
2/2
✓ Branch 0 taken 24576 times.
✓ Branch 1 taken 6 times.
24582 for (n = 0; n < nb_samples; n++) {
72
2/2
✓ Branch 0 taken 49152 times.
✓ Branch 1 taken 24576 times.
73728 for (c = 0; c < channels; c++)
73 49152 dst[c] = src[c] * s->table[s->index];
74 24576 dst += channels;
75 24576 src += channels;
76 24576 s->index++;
77
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24574 times.
24576 if (s->index >= s->table_size)
78 2 s->index = 0;
79 }
80
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (in != out)
82 av_frame_free(&in);
83
84 6 return ff_filter_frame(outlink, out);
85 }
86
87 2 static av_cold void uninit(AVFilterContext *ctx)
88 {
89 2 TremoloContext *s = ctx->priv;
90 2 av_freep(&s->table);
91 2 }
92
93 1 static int config_input(AVFilterLink *inlink)
94 {
95 1 AVFilterContext *ctx = inlink->dst;
96 1 TremoloContext *s = ctx->priv;
97 1 const double offset = 1. - s->depth / 2.;
98 int i;
99
100 1 s->table_size = lrint(inlink->sample_rate / s->freq + 0.5);
101 1 s->table = av_malloc_array(s->table_size, sizeof(*s->table));
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->table)
103 return AVERROR(ENOMEM);
104
105
2/2
✓ Branch 0 taken 8820 times.
✓ Branch 1 taken 1 times.
8821 for (i = 0; i < s->table_size; i++) {
106 8820 double env = s->freq * i / inlink->sample_rate;
107 8820 env = sin(2 * M_PI * fmod(env + 0.25, 1.0));
108 8820 s->table[i] = env * (1 - fabs(offset)) + offset;
109 }
110
111 1 s->index = 0;
112
113 1 return 0;
114 }
115
116 static const AVFilterPad avfilter_af_tremolo_inputs[] = {
117 {
118 .name = "default",
119 .type = AVMEDIA_TYPE_AUDIO,
120 .config_props = config_input,
121 .filter_frame = filter_frame,
122 },
123 };
124
125 const AVFilter ff_af_tremolo = {
126 .name = "tremolo",
127 .description = NULL_IF_CONFIG_SMALL("Apply tremolo effect."),
128 .priv_size = sizeof(TremoloContext),
129 .priv_class = &tremolo_class,
130 .uninit = uninit,
131 FILTER_INPUTS(avfilter_af_tremolo_inputs),
132 FILTER_OUTPUTS(ff_audio_default_filterpad),
133 FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL),
134 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
135 };
136