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
6728dd37
Commit
6728dd37
authored
Jan 18, 2012
by
Clément Bœsch
Committed by
Clément Bœsch
Jan 24, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pan: add channel mapping capability.
parent
66fdbcbb
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
174 additions
and
7 deletions
+174
-7
configure
configure
+1
-0
filters.texi
doc/filters.texi
+45
-0
af_pan.c
libavfilter/af_pan.c
+127
-6
version.h
libavfilter/version.h
+1
-1
No files found.
configure
View file @
6728dd37
...
...
@@ -1659,6 +1659,7 @@ mp_filter_deps="gpl avcodec"
mptestsrc_filter_deps
=
"gpl"
negate_filter_deps
=
"lut_filter"
ocv_filter_deps
=
"libopencv"
pan_filter_deps
=
"swresample"
scale_filter_deps
=
"swscale"
tinterlace_filter_deps
=
"gpl"
yadif_filter_deps
=
"gpl"
...
...
doc/filters.texi
View file @
6728dd37
...
...
@@ -315,6 +315,9 @@ Ported from SoX.
Mix channels with specific gain levels. The filter accepts the output
channel layout followed by a set of channels definitions.
This filter is also designed to remap efficiently the channels of an audio
stream.
The filter accepts parameters of the form:
"@var{l}:@var{outdef}:@var{outdef}:..."
...
...
@@ -342,6 +345,8 @@ If the `=' in a channel specification is replaced by `<', then the gains for
that specification will be renormalized so that the total is 1, thus
avoiding clipping noise.
@subsection Mixing examples
For example, if you want to down-mix from stereo to mono, but with a bigger
factor for the left channel:
@example
...
...
@@ -358,6 +363,46 @@ Note that @command{ffmpeg} integrates a default down-mix (and up-mix) system
that should be preferred (see "-ac" option) unless you have very specific
needs.
@subsection Remapping examples
The channel remapping will be effective if, and only if:
@itemize
@item gain coefficients are zeroes or ones,
@item only one input per channel output,
@item the number of output channels is supported by libswresample (16 at the
moment)
@c if SWR_CH_MAX changes, fix the line above.
@end itemize
If all these conditions are satisfied, the filter will notify the user ("Pure
channel mapping detected"), and use an optimized and lossless method to do the
remapping.
For example, if you have a 5.1 source and want a stereo audio stream by
dropping the extra channels:
@example
pan="stereo: c0=FL : c1=FR"
@end example
Given the same source, you can also switch front left and front right channels
and keep the input channel layout:
@example
pan="5.1: c0=c1 : c1=c0 : c2=c2 : c3=c3 : c4=c4 : c5=c5"
@end example
If the input is a stereo audio stream, you can mute the front left channel (and
still keep the stereo channel layout) with:
@example
pan="stereo:c1=c1"
@end example
Still with a stereo audio stream input, you can copy the right channel in both
front left and right:
@example
pan="stereo: c0=FR : c1=FR"
@end example
@section silencedetect
Detect silence in an audio stream.
...
...
libavfilter/af_pan.c
View file @
6728dd37
...
...
@@ -30,12 +30,14 @@
#include <stdio.h>
#include "libavutil/audioconvert.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "libswresample/swresample.h"
#include "avfilter.h"
#include "internal.h"
#define MAX_CHANNELS 63
typedef
struct
{
typedef
struct
PanContext
{
int64_t
out_channel_layout
;
union
{
double
d
[
MAX_CHANNELS
][
MAX_CHANNELS
];
...
...
@@ -46,6 +48,16 @@ typedef struct {
int
need_renumber
;
int
nb_input_channels
;
int
nb_output_channels
;
int
pure_gains
;
void
(
*
filter_samples
)(
struct
PanContext
*
,
AVFilterBufferRef
*
,
AVFilterBufferRef
*
,
int
);
/* channel mapping specific */
int
channel_map
[
SWR_CH_MAX
];
struct
SwrContext
*
swr
;
}
PanContext
;
static
int
parse_channel_name
(
char
**
arg
,
int
*
rchannel
,
int
*
rnamed
)
...
...
@@ -179,6 +191,31 @@ static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
return
0
;
}
static
void
filter_samples_channel_mapping
(
PanContext
*
pan
,
AVFilterBufferRef
*
outsamples
,
AVFilterBufferRef
*
insamples
,
int
n
);
static
void
filter_samples_panning
(
PanContext
*
pan
,
AVFilterBufferRef
*
outsamples
,
AVFilterBufferRef
*
insamples
,
int
n
);
static
int
are_gains_pure
(
const
PanContext
*
pan
)
{
int
i
,
j
;
for
(
i
=
0
;
i
<
MAX_CHANNELS
;
i
++
)
{
int
nb_gain
=
0
;
for
(
j
=
0
;
j
<
MAX_CHANNELS
;
j
++
)
{
double
gain
=
pan
->
gain
.
d
[
i
][
j
];
/* channel mapping is effective only if 0% or 100% of a channel is
* selected... */
if
(
gain
!=
0
.
&&
gain
!=
1
.)
return
0
;
/* ...and if the output channel is only composed of one input */
if
(
gain
&&
nb_gain
++
)
return
0
;
}
}
return
1
;
}
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
PanContext
*
pan
=
ctx
->
priv
;
...
...
@@ -186,11 +223,21 @@ static int query_formats(AVFilterContext *ctx)
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
AVFilterFormats
*
formats
;
if
(
pan
->
nb_output_channels
<=
SWR_CH_MAX
)
pan
->
pure_gains
=
are_gains_pure
(
pan
);
if
(
pan
->
pure_gains
)
{
/* libswr supports any sample and packing formats */
avfilter_set_common_sample_formats
(
ctx
,
avfilter_make_all_formats
(
AVMEDIA_TYPE_AUDIO
));
avfilter_set_common_packing_formats
(
ctx
,
avfilter_make_all_packing_formats
());
pan
->
filter_samples
=
filter_samples_channel_mapping
;
}
else
{
const
enum
AVSampleFormat
sample_fmts
[]
=
{
AV_SAMPLE_FMT_S16
,
-
1
};
const
int
packing_fmts
[]
=
{
AVFILTER_PACKED
,
-
1
};
avfilter_set_common_sample_formats
(
ctx
,
avfilter_make_format_list
(
sample_fmts
));
avfilter_set_common_packing_formats
(
ctx
,
avfilter_make_format_list
(
packing_fmts
));
pan
->
filter_samples
=
filter_samples_panning
;
}
// inlink supports any channel layout
formats
=
avfilter_make_all_channel_layouts
();
...
...
@@ -222,6 +269,44 @@ static int config_props(AVFilterLink *link)
}
}
}
// gains are pure, init the channel mapping
if
(
pan
->
pure_gains
)
{
// sanity check; can't be done in query_formats since the inlink
// channel layout is unknown at that time
if
(
pan
->
nb_input_channels
>
SWR_CH_MAX
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"libswresample support a maximum of %d channels. "
"Feel free to ask for a higher limit.
\n
"
,
SWR_CH_MAX
);
return
AVERROR_PATCHWELCOME
;
}
// get channel map from the pure gains
for
(
i
=
0
;
i
<
pan
->
nb_output_channels
;
i
++
)
{
int
ch_id
=
-
1
;
for
(
j
=
0
;
j
<
pan
->
nb_input_channels
;
j
++
)
{
if
(
pan
->
gain
.
d
[
i
][
j
])
{
ch_id
=
j
;
break
;
}
}
pan
->
channel_map
[
i
]
=
ch_id
;
}
// init libswresample context
pan
->
swr
=
swr_alloc_set_opts
(
pan
->
swr
,
pan
->
out_channel_layout
,
link
->
format
,
link
->
sample_rate
,
link
->
channel_layout
,
link
->
format
,
link
->
sample_rate
,
0
,
ctx
);
if
(
!
pan
->
swr
)
return
AVERROR
(
ENOMEM
);
av_opt_set_int
(
pan
->
swr
,
"icl"
,
pan
->
out_channel_layout
,
0
);
av_opt_set_int
(
pan
->
swr
,
"uch"
,
pan
->
nb_output_channels
,
0
);
swr_set_channel_mapping
(
pan
->
swr
,
pan
->
channel_map
);
r
=
swr_init
(
pan
->
swr
);
if
(
r
<
0
)
return
r
;
}
else
{
// renormalize
for
(
i
=
0
;
i
<
pan
->
nb_output_channels
;
i
++
)
{
if
(
!
((
pan
->
need_renorm
>>
i
)
&
1
))
...
...
@@ -239,6 +324,7 @@ static int config_props(AVFilterLink *link)
for
(
j
=
0
;
j
<
pan
->
nb_input_channels
;
j
++
)
pan
->
gain
.
d
[
i
][
j
]
/=
t
;
}
}
// summary
for
(
i
=
0
;
i
<
pan
->
nb_output_channels
;
i
++
)
{
cur
=
buf
;
...
...
@@ -249,6 +335,17 @@ static int config_props(AVFilterLink *link)
}
av_log
(
ctx
,
AV_LOG_INFO
,
"o%d = %s
\n
"
,
i
,
buf
);
}
// add channel mapping summary if possible
if
(
pan
->
pure_gains
)
{
av_log
(
ctx
,
AV_LOG_INFO
,
"Pure channel mapping detected:"
);
for
(
i
=
0
;
i
<
pan
->
nb_output_channels
;
i
++
)
if
(
pan
->
channel_map
[
i
]
<
0
)
av_log
(
ctx
,
AV_LOG_INFO
,
" M"
);
else
av_log
(
ctx
,
AV_LOG_INFO
,
" %d"
,
pan
->
channel_map
[
i
]);
av_log
(
ctx
,
AV_LOG_INFO
,
"
\n
"
);
return
0
;
}
// convert to integer
for
(
i
=
0
;
i
<
pan
->
nb_output_channels
;
i
++
)
{
for
(
j
=
0
;
j
<
pan
->
nb_input_channels
;
j
++
)
{
...
...
@@ -261,19 +358,26 @@ static int config_props(AVFilterLink *link)
return
0
;
}
static
void
filter_samples_channel_mapping
(
PanContext
*
pan
,
AVFilterBufferRef
*
outsamples
,
AVFilterBufferRef
*
insamples
,
int
n
)
{
swr_convert
(
pan
->
swr
,
outsamples
->
data
,
n
,
(
void
*
)
insamples
->
data
,
n
);
}
static
void
filter_samples
(
AVFilterLink
*
inlink
,
AVFilterBufferRef
*
insamples
)
static
void
filter_samples_panning
(
PanContext
*
pan
,
AVFilterBufferRef
*
outsamples
,
AVFilterBufferRef
*
insamples
,
int
n
)
{
PanContext
*
const
pan
=
inlink
->
dst
->
priv
;
int
i
,
o
,
n
=
insamples
->
audio
->
nb_samples
;
int
i
,
o
;
/* input */
const
int16_t
*
in
=
(
int16_t
*
)
insamples
->
data
[
0
];
const
int16_t
*
in_end
=
in
+
n
*
pan
->
nb_input_channels
;
/* output */
AVFilterLink
*
const
outlink
=
inlink
->
dst
->
outputs
[
0
];
AVFilterBufferRef
*
outsamples
=
avfilter_get_audio_buffer
(
outlink
,
AV_PERM_WRITE
,
n
);
int16_t
*
out
=
(
int16_t
*
)
outsamples
->
data
[
0
];
for
(;
in
<
in_end
;
in
+=
pan
->
nb_input_channels
)
{
...
...
@@ -284,16 +388,33 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
*
(
out
++
)
=
v
>>
8
;
}
}
}
static
void
filter_samples
(
AVFilterLink
*
inlink
,
AVFilterBufferRef
*
insamples
)
{
int
n
=
insamples
->
audio
->
nb_samples
;
AVFilterLink
*
const
outlink
=
inlink
->
dst
->
outputs
[
0
];
AVFilterBufferRef
*
outsamples
=
avfilter_get_audio_buffer
(
outlink
,
AV_PERM_WRITE
,
n
);
PanContext
*
pan
=
inlink
->
dst
->
priv
;
pan
->
filter_samples
(
pan
,
outsamples
,
insamples
,
n
);
avfilter_filter_samples
(
outlink
,
outsamples
);
avfilter_unref_buffer
(
insamples
);
}
static
av_cold
void
uninit
(
AVFilterContext
*
ctx
)
{
PanContext
*
pan
=
ctx
->
priv
;
swr_free
(
&
pan
->
swr
);
}
AVFilter
avfilter_af_pan
=
{
.
name
=
"pan"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Remix channels with coefficients (panning)."
),
.
priv_size
=
sizeof
(
PanContext
),
.
init
=
init
,
.
uninit
=
uninit
,
.
query_formats
=
query_formats
,
.
inputs
=
(
const
AVFilterPad
[])
{
...
...
libavfilter/version.h
View file @
6728dd37
...
...
@@ -30,7 +30,7 @@
#define LIBAVFILTER_VERSION_MAJOR 2
#define LIBAVFILTER_VERSION_MINOR 59
#define LIBAVFILTER_VERSION_MICRO 10
1
#define LIBAVFILTER_VERSION_MICRO 10
2
#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