2 * Copyright (c) 2000 Chris Ausbrooks <weed@bucket.pp.ualr.edu>
3 * Copyright (c) 2000 Fabien COELHO <fabien@coelho.net>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/opt.h"
23 #include "libavutil/samplefmt.h"
28 typedef struct DCShiftContext
{
31 double limiterthreshold
;
35 #define OFFSET(x) offsetof(DCShiftContext, x)
36 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
38 static const AVOption dcshift_options
[] = {
39 { "shift", "set DC shift", OFFSET(dcshift
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0}, -1, 1, A
},
40 { "limitergain", "set limiter gain", OFFSET(limitergain
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0}, 0, 1, A
},
44 AVFILTER_DEFINE_CLASS(dcshift
);
46 static av_cold
int init(AVFilterContext
*ctx
)
48 DCShiftContext
*s
= ctx
->priv
;
50 s
->limiterthreshold
= INT32_MAX
* (1.0 - (fabs(s
->dcshift
) - s
->limitergain
));
55 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
57 AVFilterContext
*ctx
= inlink
->dst
;
58 AVFilterLink
*outlink
= ctx
->outputs
[0];
60 DCShiftContext
*s
= ctx
->priv
;
62 double dcshift
= s
->dcshift
;
64 if (av_frame_is_writable(in
)) {
67 out
= ff_get_audio_buffer(outlink
, in
->nb_samples
);
70 return AVERROR(ENOMEM
);
72 av_frame_copy_props(out
, in
);
75 if (s
->limitergain
> 0) {
76 for (i
= 0; i
< inlink
->ch_layout
.nb_channels
; i
++) {
77 const int32_t *src
= (int32_t *)in
->extended_data
[i
];
78 int32_t *dst
= (int32_t *)out
->extended_data
[i
];
80 for (j
= 0; j
< in
->nb_samples
; j
++) {
85 if (d
> s
->limiterthreshold
&& dcshift
> 0) {
86 d
= (d
- s
->limiterthreshold
) * s
->limitergain
/
87 (INT32_MAX
- s
->limiterthreshold
) +
88 s
->limiterthreshold
+ dcshift
;
89 } else if (d
< -s
->limiterthreshold
&& dcshift
< 0) {
90 d
= (d
+ s
->limiterthreshold
) * s
->limitergain
/
91 (INT32_MAX
- s
->limiterthreshold
) -
92 s
->limiterthreshold
+ dcshift
;
94 d
= dcshift
* INT32_MAX
+ d
;
97 dst
[j
] = av_clipl_int32(d
);
101 for (i
= 0; i
< inlink
->ch_layout
.nb_channels
; i
++) {
102 const int32_t *src
= (int32_t *)in
->extended_data
[i
];
103 int32_t *dst
= (int32_t *)out
->extended_data
[i
];
105 for (j
= 0; j
< in
->nb_samples
; j
++) {
106 double d
= dcshift
* (INT32_MAX
+ 1.) + src
[j
];
108 dst
[j
] = av_clipl_int32(d
);
115 return ff_filter_frame(outlink
, out
);
117 static const AVFilterPad dcshift_inputs
[] = {
120 .type
= AVMEDIA_TYPE_AUDIO
,
121 .filter_frame
= filter_frame
,
125 const FFFilter ff_af_dcshift
= {
127 .p
.description
= NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."),
128 .p
.priv_class
= &dcshift_class
,
129 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,
130 .priv_size
= sizeof(DCShiftContext
),
132 FILTER_INPUTS(dcshift_inputs
),
133 FILTER_OUTPUTS(ff_audio_default_filterpad
),
134 FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_S32P
),