mirror of
https://code.videolan.org/videolan/vlc
synced 2024-10-03 01:31:53 +02:00
aout: aout_FiltersNew() can now remap channels
Add the possibility to pass an array of chan orders to the aout_FiltersNew function.
This commit is contained in:
parent
b8b7eb6d6b
commit
beb248a3f2
@ -23,6 +23,8 @@
|
|||||||
#ifndef VLC_AOUT_H
|
#ifndef VLC_AOUT_H
|
||||||
#define VLC_AOUT_H 1
|
#define VLC_AOUT_H 1
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \defgroup audio_output Audio output
|
* \defgroup audio_output Audio output
|
||||||
* \ingroup output
|
* \ingroup output
|
||||||
@ -175,6 +177,35 @@ struct audio_output
|
|||||||
} event;
|
} event;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
AOUT_CHANIDX_DISABLE = -1,
|
||||||
|
AOUT_CHANIDX_LEFT,
|
||||||
|
AOUT_CHANIDX_RIGHT,
|
||||||
|
AOUT_CHANIDX_MIDDLELEFT,
|
||||||
|
AOUT_CHANIDX_MIDDLERIGHT,
|
||||||
|
AOUT_CHANIDX_REARLEFT,
|
||||||
|
AOUT_CHANIDX_REARRIGHT,
|
||||||
|
AOUT_CHANIDX_REARCENTER,
|
||||||
|
AOUT_CHANIDX_CENTER,
|
||||||
|
AOUT_CHANIDX_LFE,
|
||||||
|
AOUT_CHANIDX_MAX
|
||||||
|
} vlc_chan_order_idx_t;
|
||||||
|
|
||||||
|
static_assert(AOUT_CHANIDX_MAX == AOUT_CHAN_MAX, "channel count mismatch");
|
||||||
|
|
||||||
|
#define AOUT_CHAN_REMAP_INIT { \
|
||||||
|
AOUT_CHANIDX_LEFT, \
|
||||||
|
AOUT_CHANIDX_RIGHT, \
|
||||||
|
AOUT_CHANIDX_MIDDLELEFT, \
|
||||||
|
AOUT_CHANIDX_MIDDLERIGHT, \
|
||||||
|
AOUT_CHANIDX_REARLEFT, \
|
||||||
|
AOUT_CHANIDX_REARRIGHT, \
|
||||||
|
AOUT_CHANIDX_REARCENTER, \
|
||||||
|
AOUT_CHANIDX_CENTER, \
|
||||||
|
AOUT_CHANIDX_LFE, \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It describes the audio channel order VLC expect.
|
* It describes the audio channel order VLC expect.
|
||||||
*/
|
*/
|
||||||
@ -323,9 +354,10 @@ typedef struct aout_request_vout aout_request_vout_t;
|
|||||||
VLC_API aout_filters_t *aout_FiltersNew(vlc_object_t *,
|
VLC_API aout_filters_t *aout_FiltersNew(vlc_object_t *,
|
||||||
const audio_sample_format_t *,
|
const audio_sample_format_t *,
|
||||||
const audio_sample_format_t *,
|
const audio_sample_format_t *,
|
||||||
const aout_request_vout_t *) VLC_USED;
|
const aout_request_vout_t *,
|
||||||
#define aout_FiltersNew(o,inf,outf,rv) \
|
const int *remap) VLC_USED;
|
||||||
aout_FiltersNew(VLC_OBJECT(o),inf,outf,rv)
|
#define aout_FiltersNew(o,inf,outf,rv,remap) \
|
||||||
|
aout_FiltersNew(VLC_OBJECT(o),inf,outf,rv,remap)
|
||||||
VLC_API void aout_FiltersDelete(vlc_object_t *, aout_filters_t *);
|
VLC_API void aout_FiltersDelete(vlc_object_t *, aout_filters_t *);
|
||||||
#define aout_FiltersDelete(o,f) \
|
#define aout_FiltersDelete(o,f) \
|
||||||
aout_FiltersDelete(VLC_OBJECT(o),f)
|
aout_FiltersDelete(VLC_OBJECT(o),f)
|
||||||
|
@ -71,7 +71,7 @@ static int transcode_audio_initialize_filters( sout_stream_t *p_stream, sout_str
|
|||||||
if( p_sys->psz_af )
|
if( p_sys->psz_af )
|
||||||
var_SetString( p_stream, "audio-filter", p_sys->psz_af );
|
var_SetString( p_stream, "audio-filter", p_sys->psz_af );
|
||||||
id->p_af_chain = aout_FiltersNew( p_stream, fmt_last,
|
id->p_af_chain = aout_FiltersNew( p_stream, fmt_last,
|
||||||
&id->p_encoder->fmt_in.audio, NULL );
|
&id->p_encoder->fmt_in.audio, NULL, NULL );
|
||||||
var_Destroy( p_stream, "audio-filter" );
|
var_Destroy( p_stream, "audio-filter" );
|
||||||
var_Destroy( p_stream, "audio-time-stretch" );
|
var_Destroy( p_stream, "audio-time-stretch" );
|
||||||
if( id->p_af_chain == NULL )
|
if( id->p_af_chain == NULL )
|
||||||
|
@ -95,7 +95,7 @@ int aout_DecNew( audio_output_t *p_aout,
|
|||||||
|
|
||||||
/* Create the audio filtering "input" pipeline */
|
/* Create the audio filtering "input" pipeline */
|
||||||
owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
|
owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
|
||||||
&owner->request_vout);
|
&owner->request_vout, NULL);
|
||||||
if (owner->filters == NULL)
|
if (owner->filters == NULL)
|
||||||
{
|
{
|
||||||
aout_OutputDelete (p_aout);
|
aout_OutputDelete (p_aout);
|
||||||
@ -166,7 +166,7 @@ static int aout_CheckReady (audio_output_t *aout)
|
|||||||
{
|
{
|
||||||
owner->filters = aout_FiltersNew (aout, &owner->input_format,
|
owner->filters = aout_FiltersNew (aout, &owner->input_format,
|
||||||
&owner->mixer_format,
|
&owner->mixer_format,
|
||||||
&owner->request_vout);
|
&owner->request_vout, NULL);
|
||||||
if (owner->filters == NULL)
|
if (owner->filters == NULL)
|
||||||
{
|
{
|
||||||
aout_OutputDelete (aout);
|
aout_OutputDelete (aout);
|
||||||
|
@ -46,13 +46,14 @@ static filter_t *CreateFilter (vlc_object_t *obj, const char *type,
|
|||||||
const char *name, filter_owner_sys_t *owner,
|
const char *name, filter_owner_sys_t *owner,
|
||||||
const audio_sample_format_t *infmt,
|
const audio_sample_format_t *infmt,
|
||||||
const audio_sample_format_t *outfmt,
|
const audio_sample_format_t *outfmt,
|
||||||
bool const_fmt)
|
config_chain_t *cfg, bool const_fmt)
|
||||||
{
|
{
|
||||||
filter_t *filter = vlc_custom_create (obj, sizeof (*filter), type);
|
filter_t *filter = vlc_custom_create (obj, sizeof (*filter), type);
|
||||||
if (unlikely(filter == NULL))
|
if (unlikely(filter == NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
filter->owner.sys = owner;
|
filter->owner.sys = owner;
|
||||||
|
filter->p_cfg = cfg;
|
||||||
filter->fmt_in.audio = *infmt;
|
filter->fmt_in.audio = *infmt;
|
||||||
filter->fmt_in.i_codec = infmt->i_format;
|
filter->fmt_in.i_codec = infmt->i_format;
|
||||||
filter->fmt_out.audio = *outfmt;
|
filter->fmt_out.audio = *outfmt;
|
||||||
@ -92,7 +93,8 @@ static filter_t *FindConverter (vlc_object_t *obj,
|
|||||||
const audio_sample_format_t *infmt,
|
const audio_sample_format_t *infmt,
|
||||||
const audio_sample_format_t *outfmt)
|
const audio_sample_format_t *outfmt)
|
||||||
{
|
{
|
||||||
return CreateFilter (obj, "audio converter", NULL, NULL, infmt, outfmt, true);
|
return CreateFilter (obj, "audio converter", NULL, NULL, infmt, outfmt,
|
||||||
|
NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static filter_t *FindResampler (vlc_object_t *obj,
|
static filter_t *FindResampler (vlc_object_t *obj,
|
||||||
@ -100,7 +102,7 @@ static filter_t *FindResampler (vlc_object_t *obj,
|
|||||||
const audio_sample_format_t *outfmt)
|
const audio_sample_format_t *outfmt)
|
||||||
{
|
{
|
||||||
return CreateFilter (obj, "audio resampler", "$audio-resampler", NULL,
|
return CreateFilter (obj, "audio resampler", "$audio-resampler", NULL,
|
||||||
infmt, outfmt, true);
|
infmt, outfmt, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -373,7 +375,8 @@ vout_thread_t *aout_filter_RequestVout (filter_t *filter, vout_thread_t *vout,
|
|||||||
static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
||||||
aout_filters_t *restrict filters, const void *owner,
|
aout_filters_t *restrict filters, const void *owner,
|
||||||
audio_sample_format_t *restrict infmt,
|
audio_sample_format_t *restrict infmt,
|
||||||
const audio_sample_format_t *restrict outfmt)
|
const audio_sample_format_t *restrict outfmt,
|
||||||
|
config_chain_t *cfg)
|
||||||
{
|
{
|
||||||
const unsigned max = sizeof (filters->tab) / sizeof (filters->tab[0]);
|
const unsigned max = sizeof (filters->tab) / sizeof (filters->tab[0]);
|
||||||
if (filters->count >= max)
|
if (filters->count >= max)
|
||||||
@ -383,7 +386,7 @@ static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
filter_t *filter = CreateFilter (obj, type, name,
|
filter_t *filter = CreateFilter (obj, type, name,
|
||||||
(void *)owner, infmt, outfmt, false);
|
(void *)owner, infmt, outfmt, cfg, false);
|
||||||
if (filter == NULL)
|
if (filter == NULL)
|
||||||
{
|
{
|
||||||
msg_Err (obj, "cannot add user %s \"%s\" (skipped)", type, name);
|
msg_Err (obj, "cannot add user %s \"%s\" (skipped)", type, name);
|
||||||
@ -407,6 +410,52 @@ static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int AppendRemapFilter(vlc_object_t *obj, aout_filters_t *restrict filters,
|
||||||
|
audio_sample_format_t *restrict infmt,
|
||||||
|
const audio_sample_format_t *restrict outfmt,
|
||||||
|
const int *wg4_remap)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
config_chain_t *cfg;
|
||||||
|
|
||||||
|
/* The remap audio filter use a different order than wg4 */
|
||||||
|
static const uint8_t wg4_to_remap[] = { 0, 2, 6, 7, 3, 5, 4, 1, 8 };
|
||||||
|
int remap[AOUT_CHAN_MAX];
|
||||||
|
bool needed = false;
|
||||||
|
for (int i = 0; i < AOUT_CHAN_MAX; ++i)
|
||||||
|
{
|
||||||
|
if (wg4_remap[i] != i)
|
||||||
|
needed = true;
|
||||||
|
remap[i] = wg4_remap[i] >= 0 ? wg4_to_remap[wg4_remap[i]] : -1;
|
||||||
|
}
|
||||||
|
if (!needed)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char *str;
|
||||||
|
int ret = asprintf(&str, "remap{channel-left=%d,channel-right=%d,"
|
||||||
|
"channel-middleleft=%d,channel-middleright=%d,"
|
||||||
|
"channel-rearleft=%d,channel-rearright=%d,"
|
||||||
|
"channel-rearcenter=%d,channel-center=%d,"
|
||||||
|
"channel-lfe=%d,normalize=false}",
|
||||||
|
remap[0], remap[1], remap[2], remap[3], remap[4],
|
||||||
|
remap[5], remap[6], remap[7], remap[8]);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
free(config_ChainCreate(&name, &cfg, str));
|
||||||
|
if (name != NULL && cfg != NULL)
|
||||||
|
ret = AppendFilter(obj, "audio filter", name, filters,
|
||||||
|
NULL, infmt, outfmt, cfg);
|
||||||
|
else
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
free(str);
|
||||||
|
free(name);
|
||||||
|
if (cfg)
|
||||||
|
config_ChainDestroy(cfg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#undef aout_FiltersNew
|
#undef aout_FiltersNew
|
||||||
/**
|
/**
|
||||||
* Sets a chain of audio filters up.
|
* Sets a chain of audio filters up.
|
||||||
@ -414,6 +463,9 @@ static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
|||||||
* \param infmt chain input format [IN]
|
* \param infmt chain input format [IN]
|
||||||
* \param outfmt chain output format [IN]
|
* \param outfmt chain output format [IN]
|
||||||
* \param request_vout visualization video output request callback
|
* \param request_vout visualization video output request callback
|
||||||
|
* \param remap a const array of size AOUT_CHAN_MAX or NULL. If not NULL, a
|
||||||
|
* remap audio filter will be inserted to remap channels according to the
|
||||||
|
* array. The array is in the WG4 order.
|
||||||
* \return a filters chain or NULL on failure
|
* \return a filters chain or NULL on failure
|
||||||
*
|
*
|
||||||
* \note
|
* \note
|
||||||
@ -425,7 +477,8 @@ static int AppendFilter(vlc_object_t *obj, const char *type, const char *name,
|
|||||||
aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
|
aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
|
||||||
const audio_sample_format_t *restrict infmt,
|
const audio_sample_format_t *restrict infmt,
|
||||||
const audio_sample_format_t *restrict outfmt,
|
const audio_sample_format_t *restrict outfmt,
|
||||||
const aout_request_vout_t *request_vout)
|
const aout_request_vout_t *request_vout,
|
||||||
|
const int *remap)
|
||||||
{
|
{
|
||||||
aout_filters_t *filters = malloc (sizeof (*filters));
|
aout_filters_t *filters = malloc (sizeof (*filters));
|
||||||
if (unlikely(filters == NULL))
|
if (unlikely(filters == NULL))
|
||||||
@ -492,10 +545,13 @@ aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
|
|||||||
if (var_InheritBool (obj, "audio-time-stretch"))
|
if (var_InheritBool (obj, "audio-time-stretch"))
|
||||||
{
|
{
|
||||||
if (AppendFilter(obj, "audio filter", "scaletempo",
|
if (AppendFilter(obj, "audio filter", "scaletempo",
|
||||||
filters, NULL, &input_format, &output_format) == 0)
|
filters, NULL, &input_format, &output_format, NULL) == 0)
|
||||||
filters->rate_filter = filters->tab[filters->count - 1];
|
filters->rate_filter = filters->tab[filters->count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remap != NULL)
|
||||||
|
AppendRemapFilter(obj, filters, &input_format, &output_format, remap);
|
||||||
|
|
||||||
/* Now add user filters */
|
/* Now add user filters */
|
||||||
char *str = var_InheritString (obj, "audio-filter");
|
char *str = var_InheritString (obj, "audio-filter");
|
||||||
if (str != NULL)
|
if (str != NULL)
|
||||||
@ -504,7 +560,7 @@ aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
|
|||||||
while ((name = strsep (&p, " :")) != NULL)
|
while ((name = strsep (&p, " :")) != NULL)
|
||||||
{
|
{
|
||||||
AppendFilter(obj, "audio filter", name, filters,
|
AppendFilter(obj, "audio filter", name, filters,
|
||||||
NULL, &input_format, &output_format);
|
NULL, &input_format, &output_format, NULL);
|
||||||
}
|
}
|
||||||
free (str);
|
free (str);
|
||||||
}
|
}
|
||||||
@ -514,7 +570,7 @@ aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
|
|||||||
char *visual = var_InheritString (obj, "audio-visual");
|
char *visual = var_InheritString (obj, "audio-visual");
|
||||||
if (visual != NULL && strcasecmp (visual, "none"))
|
if (visual != NULL && strcasecmp (visual, "none"))
|
||||||
AppendFilter(obj, "visualization", visual, filters,
|
AppendFilter(obj, "visualization", visual, filters,
|
||||||
request_vout, &input_format, &output_format);
|
request_vout, &input_format, &output_format, NULL);
|
||||||
free (visual);
|
free (visual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user