2 * Copyright (c) 2011 Stefano Sabatini
4 * This file is part of FFmpeg.
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.
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.
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
24 * based on ffmpeg.c code
27 #include "libavutil/audioconvert.h"
28 #include "libavutil/eval.h"
38 static av_cold int init(AVFilterContext *ctx, const char *args)
40 VolumeContext *vol = ctx->priv;
47 /* parse the number as a decimal number */
48 double d = strtod(args, &tail);
51 if (!strcmp(tail, "dB")) {
52 /* consider the argument an adjustement in decibels */
55 /* parse the argument as an expression */
56 ret = av_expr_parse_and_eval(&d, args, NULL, NULL,
57 NULL, NULL, NULL, NULL,
63 av_log(ctx, AV_LOG_ERROR,
64 "Invalid volume argument '%s'\n", args);
65 return AVERROR(EINVAL);
68 if (d < 0 || d > 65536) { /* 65536 = INT_MIN / (128 * 256) */
69 av_log(ctx, AV_LOG_ERROR,
70 "Negative or too big volume value %f\n", d);
71 return AVERROR(EINVAL);
77 vol->volume_i = (int)(vol->volume * 256 + 0.5);
78 av_log(ctx, AV_LOG_VERBOSE, "volume=%f\n", vol->volume);
82 static int query_formats(AVFilterContext *ctx)
84 AVFilterFormats *formats = NULL;
85 AVFilterChannelLayouts *layouts;
86 enum AVSampleFormat sample_fmts[] = {
95 layouts = ff_all_channel_layouts();
97 return AVERROR(ENOMEM);
98 ff_set_common_channel_layouts(ctx, layouts);
100 formats = ff_make_format_list(sample_fmts);
102 return AVERROR(ENOMEM);
103 ff_set_common_formats(ctx, formats);
105 formats = ff_all_samplerates();
107 return AVERROR(ENOMEM);
108 ff_set_common_samplerates(ctx, formats);
113 static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
115 VolumeContext *vol = inlink->dst->priv;
116 AVFilterLink *outlink = inlink->dst->outputs[0];
117 const int nb_samples = insamples->audio->nb_samples *
118 av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
119 const double volume = vol->volume;
120 const int volume_i = vol->volume_i;
123 if (volume_i != 256) {
124 switch (insamples->format) {
125 case AV_SAMPLE_FMT_U8:
127 uint8_t *p = (void *)insamples->data[0];
128 for (i = 0; i < nb_samples; i++) {
129 int v = (((*p - 128) * volume_i + 128) >> 8) + 128;
130 *p++ = av_clip_uint8(v);
134 case AV_SAMPLE_FMT_S16:
136 int16_t *p = (void *)insamples->data[0];
137 for (i = 0; i < nb_samples; i++) {
138 int v = ((int64_t)*p * volume_i + 128) >> 8;
139 *p++ = av_clip_int16(v);
143 case AV_SAMPLE_FMT_S32:
145 int32_t *p = (void *)insamples->data[0];
146 for (i = 0; i < nb_samples; i++) {
147 int64_t v = (((int64_t)*p * volume_i + 128) >> 8);
148 *p++ = av_clipl_int32(v);
152 case AV_SAMPLE_FMT_FLT:
154 float *p = (void *)insamples->data[0];
155 float scale = (float)volume;
156 for (i = 0; i < nb_samples; i++) {
161 case AV_SAMPLE_FMT_DBL:
163 double *p = (void *)insamples->data[0];
164 for (i = 0; i < nb_samples; i++) {
172 return ff_filter_samples(outlink, insamples);
175 AVFilter avfilter_af_volume = {
177 .description = NULL_IF_CONFIG_SMALL("Change input volume."),
178 .query_formats = query_formats,
179 .priv_size = sizeof(VolumeContext),
182 .inputs = (const AVFilterPad[]) {{ .name = "default",
183 .type = AVMEDIA_TYPE_AUDIO,
184 .filter_samples = filter_samples,
185 .min_perms = AV_PERM_READ|AV_PERM_WRITE},
188 .outputs = (const AVFilterPad[]) {{ .name = "default",
189 .type = AVMEDIA_TYPE_AUDIO, },