Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
738f8358
Commit
738f8358
authored
Feb 26, 2014
by
Andrew Kelley
Committed by
Anton Khirnov
Feb 26, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavfi: add compand audio filter
Signed-off-by:
Anton Khirnov
<
anton@khirnov.net
>
parent
4ec33648
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
668 additions
and
2 deletions
+668
-2
Changelog
Changelog
+4
-0
filters.texi
doc/filters.texi
+73
-0
Makefile
libavfilter/Makefile
+1
-0
af_compand.c
libavfilter/af_compand.c
+587
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
version.h
libavfilter/version.h
+2
-2
No files found.
Changelog
View file @
738f8358
Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version <next>:
- compand audio filter
version 10:
- av_strnstr
- support ID3v2 tags in ASF files
...
...
doc/filters.texi
View file @
738f8358
...
...
@@ -467,6 +467,79 @@ To fix a 5.1 WAV improperly encoded in AAC's native channel order
avconv -i in.wav -filter 'channelmap=1|2|0|5|3|4:channel_layout=5.1' out.wav
@end example
@section compand
Compress or expand audio dynamic range.
A description of the accepted options follows.
@table @option
@item attacks
@item decays
Set list of times in seconds for each channel over which the instantaneous level
of the input signal is averaged to determine its volume. @var{attacks} refers to
increase of volume and @var{decays} refers to decrease of volume. For most
situations, the attack time (response to the audio getting louder) should be
shorter than the decay time because the human ear is more sensitive to sudden
loud audio than sudden soft audio. A typical value for attack is 0.3 seconds and
a typical value for decay is 0.8 seconds.
@item points
Set list of points for the transfer function, specified in dB relative to the
maximum possible signal amplitude. Each key points list must be defined using
the following syntax: @code{x0/y0|x1/y1|x2/y2|....}
The input values must be in strictly increasing order but the transfer function
does not have to be monotonically rising. The point @code{0/0} is assumed but
may be overridden (by @code{0/out-dBn}). Typical values for the transfer
function are @code{-70/-70|-60/-20}.
@item soft-knee
Set the curve radius in dB for all joints. Defaults to 0.01.
@item gain
Set additional gain in dB to be applied at all points on the transfer function.
This allows easy adjustment of the overall gain. Defaults to 0.
@item volume
Set initial volume in dB to be assumed for each channel when filtering starts.
This permits the user to supply a nominal level initially, so that, for
example, a very large gain is not applied to initial signal levels before the
companding has begun to operate. A typical value for audio which is initially
quiet is -90 dB. Defaults to 0.
@item delay
Set delay in seconds. The input audio is analyzed immediately, but audio is
delayed before being fed to the volume adjuster. Specifying a delay
approximately equal to the attack/decay times allows the filter to effectively
operate in predictive rather than reactive mode. Defaults to 0.
@end table
@subsection Examples
@itemize
@item
Make music with both quiet and loud passages suitable for listening in a noisy
environment:
@example
compand=.3|.3:1|1:-90/-60|-60/-40|-40/-30|-20/-20:6:0:-90:0.2
@end example
@item
Noise gate for when the noise is at a lower level than the signal:
@example
compand=.1|.1:.2|.2:-900/-900|-50.1/-900|-50/-50:.01:0:-90:.1
@end example
@item
Here is another noise gate, this time for when the noise is at a higher level
than the signal (making it, in some ways, similar to squelch):
@example
compand=.1|.1:.1|.1:-45.1/-45.1|-45/-900|0/-900:.01:45:-90:.1
@end example
@end itemize
@section join
Join multiple input streams into one multi-channel stream.
...
...
libavfilter/Makefile
View file @
738f8358
...
...
@@ -34,6 +34,7 @@ OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o
OBJS-$(CONFIG_ATRIM_FILTER)
+=
trim.o
OBJS-$(CONFIG_CHANNELMAP_FILTER)
+=
af_channelmap.o
OBJS-$(CONFIG_CHANNELSPLIT_FILTER)
+=
af_channelsplit.o
OBJS-$(CONFIG_COMPAND_FILTER)
+=
af_compand.o
OBJS-$(CONFIG_JOIN_FILTER)
+=
af_join.o
OBJS-$(CONFIG_RESAMPLE_FILTER)
+=
af_resample.o
OBJS-$(CONFIG_VOLUME_FILTER)
+=
af_volume.o
...
...
libavfilter/af_compand.c
0 → 100644
View file @
738f8358
/*
* Copyright (c) 1999 Chris Bagwell
* Copyright (c) 1999 Nick Bailey
* Copyright (c) 2007 Rob Sykes <robs@users.sourceforge.net>
* Copyright (c) 2013 Paul B Mahol
* Copyright (c) 2014 Andrew Kelley
*
* This file is part of libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* audio compand filter
*/
#include <string.h>
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "audio.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
typedef
struct
ChanParam
{
float
attack
;
float
decay
;
float
volume
;
}
ChanParam
;
typedef
struct
CompandSegment
{
float
x
,
y
;
float
a
,
b
;
}
CompandSegment
;
typedef
struct
CompandContext
{
const
AVClass
*
class
;
int
nb_channels
;
int
nb_segments
;
char
*
attacks
,
*
decays
,
*
points
;
CompandSegment
*
segments
;
ChanParam
*
channels
;
float
in_min_lin
;
float
out_min_lin
;
double
curve_dB
;
double
gain_dB
;
double
initial_volume
;
double
delay
;
AVFrame
*
delay_frame
;
int
delay_samples
;
int
delay_count
;
int
delay_index
;
int64_t
pts
;
int
(
*
compand
)(
AVFilterContext
*
ctx
,
AVFrame
*
frame
);
}
CompandContext
;
#define OFFSET(x) offsetof(CompandContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
static
const
AVOption
compand_options
[]
=
{
{
"attacks"
,
"set time over which increase of volume is determined"
,
OFFSET
(
attacks
),
AV_OPT_TYPE_STRING
,
{
.
str
=
"0.3"
},
0
,
0
,
A
},
{
"decays"
,
"set time over which decrease of volume is determined"
,
OFFSET
(
decays
),
AV_OPT_TYPE_STRING
,
{
.
str
=
"0.8"
},
0
,
0
,
A
},
{
"points"
,
"set points of transfer function"
,
OFFSET
(
points
),
AV_OPT_TYPE_STRING
,
{
.
str
=
"-70/-70|-60/-20"
},
0
,
0
,
A
},
{
"soft-knee"
,
"set soft-knee"
,
OFFSET
(
curve_dB
),
AV_OPT_TYPE_DOUBLE
,
{
.
dbl
=
0
.
01
},
0
.
01
,
900
,
A
},
{
"gain"
,
"set output gain"
,
OFFSET
(
gain_dB
),
AV_OPT_TYPE_DOUBLE
,
{
.
dbl
=
0
},
-
900
,
900
,
A
},
{
"volume"
,
"set initial volume"
,
OFFSET
(
initial_volume
),
AV_OPT_TYPE_DOUBLE
,
{
.
dbl
=
0
},
-
900
,
0
,
A
},
{
"delay"
,
"set delay for samples before sending them to volume adjuster"
,
OFFSET
(
delay
),
AV_OPT_TYPE_DOUBLE
,
{
.
dbl
=
0
},
0
,
20
,
A
},
{
NULL
}
};
static
const
AVClass
compand_class
=
{
.
class_name
=
"compand filter"
,
.
item_name
=
av_default_item_name
,
.
option
=
compand_options
,
.
version
=
LIBAVUTIL_VERSION_INT
,
};
static
av_cold
int
init
(
AVFilterContext
*
ctx
)
{
CompandContext
*
s
=
ctx
->
priv
;
s
->
pts
=
AV_NOPTS_VALUE
;
return
0
;
}
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
{
CompandContext
*
s
=
ctx
->
priv
;
av_freep
(
&
s
->
channels
);
av_freep
(
&
s
->
segments
);
av_frame_free
(
&
s
->
delay_frame
);
}
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
AVFilterChannelLayouts
*
layouts
;
AVFilterFormats
*
formats
;
static
const
enum
AVSampleFormat
sample_fmts
[]
=
{
AV_SAMPLE_FMT_FLTP
,
AV_SAMPLE_FMT_NONE
};
layouts
=
ff_all_channel_layouts
();
if
(
!
layouts
)
return
AVERROR
(
ENOMEM
);
ff_set_common_channel_layouts
(
ctx
,
layouts
);
formats
=
ff_make_format_list
(
sample_fmts
);
if
(
!
formats
)
return
AVERROR
(
ENOMEM
);
ff_set_common_formats
(
ctx
,
formats
);
formats
=
ff_all_samplerates
();
if
(
!
formats
)
return
AVERROR
(
ENOMEM
);
ff_set_common_samplerates
(
ctx
,
formats
);
return
0
;
}
static
void
count_items
(
char
*
item_str
,
int
*
nb_items
)
{
char
*
p
;
*
nb_items
=
1
;
for
(
p
=
item_str
;
*
p
;
p
++
)
{
if
(
*
p
==
'|'
)
(
*
nb_items
)
++
;
}
}
static
void
update_volume
(
ChanParam
*
cp
,
float
in
)
{
float
delta
=
in
-
cp
->
volume
;
if
(
delta
>
0
.
0
)
cp
->
volume
+=
delta
*
cp
->
attack
;
else
cp
->
volume
+=
delta
*
cp
->
decay
;
}
static
float
get_volume
(
CompandContext
*
s
,
float
in_lin
)
{
CompandSegment
*
cs
;
float
in_log
,
out_log
;
int
i
;
if
(
in_lin
<
s
->
in_min_lin
)
return
s
->
out_min_lin
;
in_log
=
logf
(
in_lin
);
for
(
i
=
1
;
i
<
s
->
nb_segments
;
i
++
)
if
(
in_log
<=
s
->
segments
[
i
].
x
)
break
;
cs
=
&
s
->
segments
[
i
-
1
];
in_log
-=
cs
->
x
;
out_log
=
cs
->
y
+
in_log
*
(
cs
->
a
*
in_log
+
cs
->
b
);
return
expf
(
out_log
);
}
static
int
compand_nodelay
(
AVFilterContext
*
ctx
,
AVFrame
*
frame
)
{
CompandContext
*
s
=
ctx
->
priv
;
AVFilterLink
*
inlink
=
ctx
->
inputs
[
0
];
const
int
channels
=
s
->
nb_channels
;
const
int
nb_samples
=
frame
->
nb_samples
;
AVFrame
*
out_frame
;
int
chan
,
i
;
int
err
;
if
(
av_frame_is_writable
(
frame
))
{
out_frame
=
frame
;
}
else
{
out_frame
=
ff_get_audio_buffer
(
inlink
,
nb_samples
);
if
(
!
out_frame
)
{
av_frame_free
(
&
frame
);
return
AVERROR
(
ENOMEM
);
}
err
=
av_frame_copy_props
(
out_frame
,
frame
);
if
(
err
<
0
)
{
av_frame_free
(
&
out_frame
);
av_frame_free
(
&
frame
);
return
err
;
}
}
for
(
chan
=
0
;
chan
<
channels
;
chan
++
)
{
const
float
*
src
=
(
float
*
)
frame
->
extended_data
[
chan
];
float
*
dst
=
(
float
*
)
out_frame
->
extended_data
[
chan
];
ChanParam
*
cp
=
&
s
->
channels
[
chan
];
for
(
i
=
0
;
i
<
nb_samples
;
i
++
)
{
update_volume
(
cp
,
fabs
(
src
[
i
]));
dst
[
i
]
=
av_clipf
(
src
[
i
]
*
get_volume
(
s
,
cp
->
volume
),
-
1
.
0
f
,
1
.
0
f
);
}
}
if
(
frame
!=
out_frame
)
av_frame_free
(
&
frame
);
return
ff_filter_frame
(
ctx
->
outputs
[
0
],
out_frame
);
}
#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
static
int
compand_delay
(
AVFilterContext
*
ctx
,
AVFrame
*
frame
)
{
CompandContext
*
s
=
ctx
->
priv
;
AVFilterLink
*
inlink
=
ctx
->
inputs
[
0
];
const
int
channels
=
s
->
nb_channels
;
const
int
nb_samples
=
frame
->
nb_samples
;
int
chan
,
i
,
dindex
=
0
,
oindex
,
count
=
0
;
AVFrame
*
out_frame
=
NULL
;
int
err
;
if
(
s
->
pts
==
AV_NOPTS_VALUE
)
{
s
->
pts
=
(
frame
->
pts
==
AV_NOPTS_VALUE
)
?
0
:
frame
->
pts
;
}
for
(
chan
=
0
;
chan
<
channels
;
chan
++
)
{
AVFrame
*
delay_frame
=
s
->
delay_frame
;
const
float
*
src
=
(
float
*
)
frame
->
extended_data
[
chan
];
float
*
dbuf
=
(
float
*
)
delay_frame
->
extended_data
[
chan
];
ChanParam
*
cp
=
&
s
->
channels
[
chan
];
float
*
dst
;
count
=
s
->
delay_count
;
dindex
=
s
->
delay_index
;
for
(
i
=
0
,
oindex
=
0
;
i
<
nb_samples
;
i
++
)
{
const
float
in
=
src
[
i
];
update_volume
(
cp
,
fabs
(
in
));
if
(
count
>=
s
->
delay_samples
)
{
if
(
!
out_frame
)
{
out_frame
=
ff_get_audio_buffer
(
inlink
,
nb_samples
-
i
);
if
(
!
out_frame
)
{
av_frame_free
(
&
frame
);
return
AVERROR
(
ENOMEM
);
}
err
=
av_frame_copy_props
(
out_frame
,
frame
);
if
(
err
<
0
)
{
av_frame_free
(
&
out_frame
);
av_frame_free
(
&
frame
);
return
err
;
}
out_frame
->
pts
=
s
->
pts
;
s
->
pts
+=
av_rescale_q
(
nb_samples
-
i
,
(
AVRational
){
1
,
inlink
->
sample_rate
},
inlink
->
time_base
);
}
dst
=
(
float
*
)
out_frame
->
extended_data
[
chan
];
dst
[
oindex
++
]
=
av_clipf
(
dbuf
[
dindex
]
*
get_volume
(
s
,
cp
->
volume
),
-
1
.
0
f
,
1
.
0
f
);
}
else
{
count
++
;
}
dbuf
[
dindex
]
=
in
;
dindex
=
MOD
(
dindex
+
1
,
s
->
delay_samples
);
}
}
s
->
delay_count
=
count
;
s
->
delay_index
=
dindex
;
av_frame_free
(
&
frame
);
return
out_frame
?
ff_filter_frame
(
ctx
->
outputs
[
0
],
out_frame
)
:
0
;
}
static
int
compand_drain
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
CompandContext
*
s
=
ctx
->
priv
;
const
int
channels
=
s
->
nb_channels
;
AVFrame
*
frame
=
NULL
;
int
chan
,
i
,
dindex
;
/* 2048 is to limit output frame size during drain */
frame
=
ff_get_audio_buffer
(
outlink
,
FFMIN
(
2048
,
s
->
delay_count
));
if
(
!
frame
)
return
AVERROR
(
ENOMEM
);
frame
->
pts
=
s
->
pts
;
s
->
pts
+=
av_rescale_q
(
frame
->
nb_samples
,
(
AVRational
){
1
,
outlink
->
sample_rate
},
outlink
->
time_base
);
for
(
chan
=
0
;
chan
<
channels
;
chan
++
)
{
AVFrame
*
delay_frame
=
s
->
delay_frame
;
float
*
dbuf
=
(
float
*
)
delay_frame
->
extended_data
[
chan
];
float
*
dst
=
(
float
*
)
frame
->
extended_data
[
chan
];
ChanParam
*
cp
=
&
s
->
channels
[
chan
];
dindex
=
s
->
delay_index
;
for
(
i
=
0
;
i
<
frame
->
nb_samples
;
i
++
)
{
dst
[
i
]
=
av_clipf
(
dbuf
[
dindex
]
*
get_volume
(
s
,
cp
->
volume
),
-
1
.
0
f
,
1
.
0
f
);
dindex
=
MOD
(
dindex
+
1
,
s
->
delay_samples
);
}
}
s
->
delay_count
-=
frame
->
nb_samples
;
s
->
delay_index
=
dindex
;
return
ff_filter_frame
(
outlink
,
frame
);
}
static
int
config_output
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
CompandContext
*
s
=
ctx
->
priv
;
const
int
sample_rate
=
outlink
->
sample_rate
;
double
radius
=
s
->
curve_dB
*
M_LN10
/
20
.
0
;
char
*
p
,
*
saveptr
=
NULL
;
const
int
channels
=
av_get_channel_layout_nb_channels
(
outlink
->
channel_layout
);
int
nb_attacks
,
nb_decays
,
nb_points
;
int
new_nb_items
,
num
;
int
i
;
int
err
;
count_items
(
s
->
attacks
,
&
nb_attacks
);
count_items
(
s
->
decays
,
&
nb_decays
);
count_items
(
s
->
points
,
&
nb_points
);
if
(
channels
<=
0
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Invalid number of channels: %d
\n
"
,
channels
);
return
AVERROR
(
EINVAL
);
}
if
(
nb_attacks
>
channels
||
nb_decays
>
channels
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Number of attacks/decays bigger than number of channels.
\n
"
);
return
AVERROR
(
EINVAL
);
}
uninit
(
ctx
);
s
->
nb_channels
=
channels
;
s
->
channels
=
av_mallocz_array
(
channels
,
sizeof
(
*
s
->
channels
));
s
->
nb_segments
=
(
nb_points
+
4
)
*
2
;
s
->
segments
=
av_mallocz_array
(
s
->
nb_segments
,
sizeof
(
*
s
->
segments
));
if
(
!
s
->
channels
||
!
s
->
segments
)
{
uninit
(
ctx
);
return
AVERROR
(
ENOMEM
);
}
p
=
s
->
attacks
;
for
(
i
=
0
,
new_nb_items
=
0
;
i
<
nb_attacks
;
i
++
)
{
char
*
tstr
=
strtok_r
(
p
,
"|"
,
&
saveptr
);
p
=
NULL
;
new_nb_items
+=
sscanf
(
tstr
,
"%f"
,
&
s
->
channels
[
i
].
attack
)
==
1
;
if
(
s
->
channels
[
i
].
attack
<
0
)
{
uninit
(
ctx
);
return
AVERROR
(
EINVAL
);
}
}
nb_attacks
=
new_nb_items
;
p
=
s
->
decays
;
for
(
i
=
0
,
new_nb_items
=
0
;
i
<
nb_decays
;
i
++
)
{
char
*
tstr
=
strtok_r
(
p
,
"|"
,
&
saveptr
);
p
=
NULL
;
new_nb_items
+=
sscanf
(
tstr
,
"%f"
,
&
s
->
channels
[
i
].
decay
)
==
1
;
if
(
s
->
channels
[
i
].
decay
<
0
)
{
uninit
(
ctx
);
return
AVERROR
(
EINVAL
);
}
}
nb_decays
=
new_nb_items
;
if
(
nb_attacks
!=
nb_decays
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Number of attacks %d differs from number of decays %d.
\n
"
,
nb_attacks
,
nb_decays
);
uninit
(
ctx
);
return
AVERROR
(
EINVAL
);
}
#define S(x) s->segments[2 * ((x) + 1)]
p
=
s
->
points
;
for
(
i
=
0
,
new_nb_items
=
0
;
i
<
nb_points
;
i
++
)
{
char
*
tstr
=
strtok_r
(
p
,
"|"
,
&
saveptr
);
p
=
NULL
;
if
(
sscanf
(
tstr
,
"%f/%f"
,
&
S
(
i
).
x
,
&
S
(
i
).
y
)
!=
2
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Invalid and/or missing input/output value.
\n
"
);
uninit
(
ctx
);
return
AVERROR
(
EINVAL
);
}
if
(
i
&&
S
(
i
-
1
).
x
>
S
(
i
).
x
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Transfer function input values must be increasing.
\n
"
);
uninit
(
ctx
);
return
AVERROR
(
EINVAL
);
}
S
(
i
).
y
-=
S
(
i
).
x
;
av_log
(
ctx
,
AV_LOG_DEBUG
,
"%d: x=%f y=%f
\n
"
,
i
,
S
(
i
).
x
,
S
(
i
).
y
);
new_nb_items
++
;
}
num
=
new_nb_items
;
/* Add 0,0 if necessary */
if
(
num
==
0
||
S
(
num
-
1
).
x
)
num
++
;
#undef S
#define S(x) s->segments[2 * (x)]
/* Add a tail off segment at the start */
S
(
0
).
x
=
S
(
1
).
x
-
2
*
s
->
curve_dB
;
S
(
0
).
y
=
S
(
1
).
y
;
num
++
;
/* Join adjacent colinear segments */
for
(
i
=
2
;
i
<
num
;
i
++
)
{
double
g1
=
(
S
(
i
-
1
).
y
-
S
(
i
-
2
).
y
)
*
(
S
(
i
-
0
).
x
-
S
(
i
-
1
).
x
);
double
g2
=
(
S
(
i
-
0
).
y
-
S
(
i
-
1
).
y
)
*
(
S
(
i
-
1
).
x
-
S
(
i
-
2
).
x
);
int
j
;
/* here we purposefully lose precision so that we can compare floats */
if
(
fabs
(
g1
-
g2
))
continue
;
num
--
;
for
(
j
=
--
i
;
j
<
num
;
j
++
)
S
(
j
)
=
S
(
j
+
1
);
}
for
(
i
=
0
;
!
i
||
s
->
segments
[
i
-
2
].
x
;
i
+=
2
)
{
s
->
segments
[
i
].
y
+=
s
->
gain_dB
;
s
->
segments
[
i
].
x
*=
M_LN10
/
20
;
s
->
segments
[
i
].
y
*=
M_LN10
/
20
;
}
#define L(x) s->segments[i - (x)]
for
(
i
=
4
;
s
->
segments
[
i
-
2
].
x
;
i
+=
2
)
{
double
x
,
y
,
cx
,
cy
,
in1
,
in2
,
out1
,
out2
,
theta
,
len
,
r
;
L
(
4
).
a
=
0
;
L
(
4
).
b
=
(
L
(
2
).
y
-
L
(
4
).
y
)
/
(
L
(
2
).
x
-
L
(
4
).
x
);
L
(
2
).
a
=
0
;
L
(
2
).
b
=
(
L
(
0
).
y
-
L
(
2
).
y
)
/
(
L
(
0
).
x
-
L
(
2
).
x
);
theta
=
atan2
(
L
(
2
).
y
-
L
(
4
).
y
,
L
(
2
).
x
-
L
(
4
).
x
);
len
=
sqrt
(
pow
(
L
(
2
).
x
-
L
(
4
).
x
,
2
.)
+
pow
(
L
(
2
).
y
-
L
(
4
).
y
,
2
.));
r
=
FFMIN
(
radius
,
len
);
L
(
3
).
x
=
L
(
2
).
x
-
r
*
cos
(
theta
);
L
(
3
).
y
=
L
(
2
).
y
-
r
*
sin
(
theta
);
theta
=
atan2
(
L
(
0
).
y
-
L
(
2
).
y
,
L
(
0
).
x
-
L
(
2
).
x
);
len
=
sqrt
(
pow
(
L
(
0
).
x
-
L
(
2
).
x
,
2
.)
+
pow
(
L
(
0
).
y
-
L
(
2
).
y
,
2
.));
r
=
FFMIN
(
radius
,
len
/
2
);
x
=
L
(
2
).
x
+
r
*
cos
(
theta
);
y
=
L
(
2
).
y
+
r
*
sin
(
theta
);
cx
=
(
L
(
3
).
x
+
L
(
2
).
x
+
x
)
/
3
;
cy
=
(
L
(
3
).
y
+
L
(
2
).
y
+
y
)
/
3
;
L
(
2
).
x
=
x
;
L
(
2
).
y
=
y
;
in1
=
cx
-
L
(
3
).
x
;
out1
=
cy
-
L
(
3
).
y
;
in2
=
L
(
2
).
x
-
L
(
3
).
x
;
out2
=
L
(
2
).
y
-
L
(
3
).
y
;
L
(
3
).
a
=
(
out2
/
in2
-
out1
/
in1
)
/
(
in2
-
in1
);
L
(
3
).
b
=
out1
/
in1
-
L
(
3
).
a
*
in1
;
}
L
(
3
).
x
=
0
;
L
(
3
).
y
=
L
(
2
).
y
;
s
->
in_min_lin
=
exp
(
s
->
segments
[
1
].
x
);
s
->
out_min_lin
=
exp
(
s
->
segments
[
1
].
y
);
for
(
i
=
0
;
i
<
channels
;
i
++
)
{
ChanParam
*
cp
=
&
s
->
channels
[
i
];
if
(
cp
->
attack
>
1
.
0
/
sample_rate
)
cp
->
attack
=
1
.
0
-
exp
(
-
1
.
0
/
(
sample_rate
*
cp
->
attack
));
else
cp
->
attack
=
1
.
0
;
if
(
cp
->
decay
>
1
.
0
/
sample_rate
)
cp
->
decay
=
1
.
0
-
exp
(
-
1
.
0
/
(
sample_rate
*
cp
->
decay
));
else
cp
->
decay
=
1
.
0
;
cp
->
volume
=
pow
(
10
.
0
,
s
->
initial_volume
/
20
);
}
s
->
delay_samples
=
s
->
delay
*
sample_rate
;
if
(
s
->
delay_samples
<=
0
)
{
s
->
compand
=
compand_nodelay
;
return
0
;
}
s
->
delay_frame
=
av_frame_alloc
();
if
(
!
s
->
delay_frame
)
{
uninit
(
ctx
);
return
AVERROR
(
ENOMEM
);
}
s
->
delay_frame
->
format
=
outlink
->
format
;
s
->
delay_frame
->
nb_samples
=
s
->
delay_samples
;
s
->
delay_frame
->
channel_layout
=
outlink
->
channel_layout
;
err
=
av_frame_get_buffer
(
s
->
delay_frame
,
32
);
if
(
err
)
return
err
;
s
->
compand
=
compand_delay
;
return
0
;
}
static
int
filter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
frame
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
CompandContext
*
s
=
ctx
->
priv
;
return
s
->
compand
(
ctx
,
frame
);
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
CompandContext
*
s
=
ctx
->
priv
;
int
ret
;
ret
=
ff_request_frame
(
ctx
->
inputs
[
0
]);
if
(
ret
==
AVERROR_EOF
&&
s
->
delay_count
)
ret
=
compand_drain
(
outlink
);
return
ret
;
}
static
const
AVFilterPad
compand_inputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
.
filter_frame
=
filter_frame
,
},
{
NULL
}
};
static
const
AVFilterPad
compand_outputs
[]
=
{
{
.
name
=
"default"
,
.
request_frame
=
request_frame
,
.
config_props
=
config_output
,
.
type
=
AVMEDIA_TYPE_AUDIO
,
},
{
NULL
}
};
AVFilter
ff_af_compand
=
{
.
name
=
"compand"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Compress or expand audio dynamic range."
),
.
query_formats
=
query_formats
,
.
priv_size
=
sizeof
(
CompandContext
),
.
priv_class
=
&
compand_class
,
.
init
=
init
,
.
uninit
=
uninit
,
.
inputs
=
compand_inputs
,
.
outputs
=
compand_outputs
,
};
libavfilter/allfilters.c
View file @
738f8358
...
...
@@ -54,6 +54,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
ATRIM
,
atrim
,
af
);
REGISTER_FILTER
(
CHANNELMAP
,
channelmap
,
af
);
REGISTER_FILTER
(
CHANNELSPLIT
,
channelsplit
,
af
);
REGISTER_FILTER
(
COMPAND
,
compand
,
af
);
REGISTER_FILTER
(
JOIN
,
join
,
af
);
REGISTER_FILTER
(
RESAMPLE
,
resample
,
af
);
REGISTER_FILTER
(
VOLUME
,
volume
,
af
);
...
...
libavfilter/version.h
View file @
738f8358
...
...
@@ -30,8 +30,8 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 4
#define LIBAVFILTER_VERSION_MINOR
1
#define LIBAVFILTER_VERSION_MICRO
1
#define LIBAVFILTER_VERSION_MINOR
2
#define LIBAVFILTER_VERSION_MICRO
0
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment