summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/af.rst23
-rw-r--r--audio/filter/af_channels.c110
2 files changed, 60 insertions, 73 deletions
diff --git a/DOCS/man/en/af.rst b/DOCS/man/en/af.rst
index 34b54eb6c8..bb7f34cf62 100644
--- a/DOCS/man/en/af.rst
+++ b/DOCS/man/en/af.rst
@@ -184,7 +184,7 @@ Available filters are:
Would amplify the sound in the upper and lower frequency region
while canceling it almost completely around 1kHz.
-``channels=nch[:nr:from1:to1:from2:to2:from3:to3:...]``
+``channels=nch[:routes]``
Can be used for adding, removing, routing and copying audio channels. If
only ``<nch>`` is given, the default routing is used. It works as follows:
If the number of output channels is greater than the number of input
@@ -195,26 +195,33 @@ Available filters are:
``<nch>``
number of output channels (1-8)
- ``<nr>``
- number of routes (1-8)
- ``<from1:to1:from2:to2:from3:to3:...>``
- Pairs of numbers between 0 and 7 that define where to route each
- channel.
+ ``<routes>``
+ List of ``,`` separated routes, in the form ``from1-to1,from2-to2,...``.
+ Each pair defines where to route each channel. There can be at most
+ 8 routes. Without this argument, the default routing is used. Since
+ ``,`` is also used to separate filters, you must quote this argument
+ with ``[...]`` or similar.
.. admonition:: Examples
- ``mpv --af=channels=4:4:0:1:1:0:2:2:3:3 media.avi``
+ ``mpv --af=channels=4:[0-1,1-0,0-2,1-3] media.avi``
Would change the number of channels to 4 and set up 4 routes that
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
Observe that if media containing two channels were played back,
channels 2 and 3 would contain silence but 0 and 1 would still be
swapped.
- ``mpv --af=channels=6:4:0:0:0:1:0:2:0:3 media.avi``
+ ``mpv --af=channels=6:[0-0,0-1,0-2,0-3] media.avi``
Would change the number of channels to 6 and set up 4 routes that
copy channel 0 to channels 0 to 3. Channel 4 and 5 will contain
silence.
+ .. note::
+
+ You should probably not use this filter. If you want to change the
+ output channel layout, try the ``format`` filter, which can make mpv
+ automatically up- and downmix standard channel layouts.
+
``format=format:srate:channels:out-format:out-srate:out-channels``
Force a specific audio format/configuration without actually changing the
audio data. Keep in mind that the filter system might auto-insert actual
diff --git a/audio/filter/af_channels.c b/audio/filter/af_channels.c
index d544e4d9c0..b51e8a431e 100644
--- a/audio/filter/af_channels.c
+++ b/audio/filter/af_channels.c
@@ -35,8 +35,9 @@
typedef struct af_channels_s{
int route[AF_NCH][2];
- int nr;
+ int nch, nr;
int router;
+ char *routes;
}af_channels_t;
// Local function for copying data
@@ -138,10 +139,12 @@ static int check_routes(af_channels_t* s, int nin, int nout)
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
- af_channels_t* s = af->setup;
+ af_channels_t* s = af->priv;
switch(cmd){
case AF_CONTROL_REINIT:
+ mp_audio_set_channels_old(af->data, s->nch);
+
// Set default channel assignment
if(!s->router){
int i;
@@ -167,68 +170,19 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
af->data->rate = ((struct mp_audio*)arg)->rate;
+ mp_audio_force_interleaved_format((struct mp_audio*)arg);
mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
- mp_audio_force_interleaved_format(af->data);
- int r = af_test_output(af,(struct mp_audio*)arg);
- if (r != AF_OK)
- return r;
return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch);
- case AF_CONTROL_COMMAND_LINE:{
- int nch = 0;
- int n = 0;
- // Check number of channels and number of routing pairs
- sscanf(arg, "%i:%i%n", &nch, &s->nr, &n);
-
- // If router scan commandline for routing pairs
- if(s->nr){
- char* cp = &((char*)arg)[n];
- int ch = 0;
- // Sanity check
- if((s->nr < 1) || (s->nr > AF_NCH)){
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of routing pairs must be"
- " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
- }
- s->router = 1;
- // Scan for pairs on commandline
- while((*cp == ':') && (ch < s->nr)){
- sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
- mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Routing from channel %i to"
- " channel %i\n",s->route[ch][FR],s->route[ch][TO]);
- cp = &cp[n];
- ch++;
- }
- }
-
- struct mp_chmap chmap;
- mp_chmap_from_channels(&chmap, nch);
- if (AF_OK != af->control(af, AF_CONTROL_SET_CHANNELS, &chmap))
- return AF_ERROR;
- return AF_OK;
- }
- case AF_CONTROL_SET_CHANNELS:
- // Reinit must be called after this function has been called
-
- mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
- if(!s->router)
- mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
- " to %i\n",af->data->nch);
- return AF_OK;
}
return AF_UNKNOWN;
}
-// Deallocate memory
-static void uninit(struct af_instance* af)
-{
- free(af->setup);
-}
-
// Filter data through filter
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
{
struct mp_audio* c = data; // Current working data
struct mp_audio* l = af->data; // Local data
- af_channels_t* s = af->setup;
+ af_channels_t* s = af->priv;
int i;
mp_audio_realloc_min(af->data, data->samples);
@@ -243,7 +197,6 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->planes[0] = l->planes[0];
- c->samples = c->samples / c->nch * l->nch;
mp_audio_set_channels(c, &l->channels);
return c;
@@ -251,18 +204,45 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Allocate memory and set function pointers
static int af_open(struct af_instance* af){
- af->control=control;
- af->uninit=uninit;
- af->play=play;
- af->setup=calloc(1,sizeof(af_channels_t));
- if(af->setup == NULL)
- return AF_ERROR;
- return AF_OK;
+ af->control=control;
+ af->play=play;
+ af_channels_t *s = af->priv;
+
+ // If router scan commandline for routing pairs
+ if(s->routes && s->routes[0]){
+ char* cp = s->routes;
+ int ch = 0;
+ // Scan for pairs on commandline
+ do {
+ int n = 0;
+ if (ch >= AF_NCH) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL,
+ "[channels] Can't have more than %d routes.\n", AF_NCH);
+ return AF_ERROR;
+ }
+ sscanf(cp, "%i-%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Routing from channel %i to"
+ " channel %i\n",s->route[ch][FR],s->route[ch][TO]);
+ cp = &cp[n];
+ ch++;
+ } while(*cp == ',' && *(cp++));
+ s->nr = ch;
+ if (s->nr > 0)
+ s->router = 1;
+ }
+
+ return AF_OK;
}
-// Description of this filter
+#define OPT_BASE_STRUCT af_channels_t
struct af_info af_info_channels = {
- .info = "Insert or remove channels",
- .name = "channels",
- .open = af_open,
+ .info = "Insert or remove channels",
+ .name = "channels",
+ .open = af_open,
+ .priv_size = sizeof(af_channels_t),
+ .options = (const struct m_option[]) {
+ OPT_INTRANGE("nch", nch, 0, 1, AF_NCH, OPTDEF_INT(2)),
+ OPT_STRING("routes", routes, 0),
+ {0}
+ },
};