summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-07-22 14:43:58 +0200
committerwm4 <wm4@nowhere>2013-07-22 15:11:03 +0200
commit3b8dfddb4cb6e9431da659b10c5b31a9f17c81b5 (patch)
treeb087f6551fa96a6fbe0f1f2b7f0f951f331eb552 /audio
parent221ef23d0d4454af974b08e68fad6b898d1d8e12 (diff)
downloadmpv-3b8dfddb4cb6e9431da659b10c5b31a9f17c81b5.tar.bz2
mpv-3b8dfddb4cb6e9431da659b10c5b31a9f17c81b5.tar.xz
audio/filter: use new option API
Make the VF/VO/AO option parser available to audio filters. No audio filter uses this yet, but it's still a quite intrusive change. In particular, the commands for manipulating filters at runtime completely change. We delete the old code, and use the same infrastructure as for video filters. (This forces complete reinitialization of the filter chain, which hopefully isn't a problem for any use cases. The old code forced reinitialization too, but it could potentially allow a filter to cache things; e.g. consider loaded ladspa plugins and such.)
Diffstat (limited to 'audio')
-rw-r--r--audio/decode/dec_audio.c17
-rw-r--r--audio/decode/dec_audio.h2
-rw-r--r--audio/filter/af.c195
-rw-r--r--audio/filter/af.h44
-rw-r--r--audio/mixer.c4
5 files changed, 99 insertions, 163 deletions
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 48a3512ee6..a73027e224 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -54,8 +54,6 @@ static const struct ad_functions * const ad_drivers[] = {
NULL
};
-struct af_cfg af_cfg = {0}; // Configuration for audio filters
-
static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder)
{
assert(!sh_audio->initialized);
@@ -180,7 +178,6 @@ void uninit_audio(sh_audio_t *sh_audio)
{
if (sh_audio->afilter) {
mp_msg(MSGT_DECAUDIO, MSGL_V, "Uninit audio filters...\n");
- af_uninit(sh_audio->afilter);
af_destroy(sh_audio->afilter);
sh_audio->afilter = NULL;
}
@@ -199,9 +196,10 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format)
{
+ if (!sh_audio->afilter)
+ sh_audio->afilter = af_new(sh_audio->opts);
struct af_stream *afs = sh_audio->afilter;
- if (!afs)
- afs = af_new(sh_audio->opts);
+
// input format: same as codec's output format:
afs->input.rate = in_samplerate;
mp_audio_set_channels(&afs->input, &sh_audio->channels);
@@ -212,9 +210,6 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
mp_audio_set_channels(&afs->output, out_channels);
mp_audio_set_format(&afs->output, *out_format);
- // filter config:
- memcpy(&afs->cfg, &af_cfg, sizeof(struct af_cfg));
-
char *s_from = mp_audio_config_to_str(&afs->input);
char *s_to = mp_audio_config_to_str(&afs->output);
mp_tmsg(MSGT_DECAUDIO, MSGL_V,
@@ -223,9 +218,9 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
talloc_free(s_to);
// let's autoprobe it!
- if (0 != af_init(afs)) {
- sh_audio->afilter = NULL;
+ if (af_init(afs) != 0) {
af_destroy(afs);
+ sh_audio->afilter = NULL;
return 0; // failed :(
}
@@ -233,8 +228,6 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
*out_channels = afs->output.channels;
*out_format = afs->output.format;
- // ok!
- sh_audio->afilter = (void *) afs;
return 1;
}
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 7a044e2040..b46f4282fb 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -37,6 +37,4 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format);
-extern struct af_cfg af_cfg;
-
#endif /* MPLAYER_DEC_AUDIO_H */
diff --git a/audio/filter/af.c b/audio/filter/af.c
index 7e2bdb8c18..26ca78c24f 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -22,6 +22,9 @@
#include <string.h>
#include <assert.h>
+#include "core/m_option.h"
+#include "core/m_config.h"
+
#include "af.h"
// Static list of filters
@@ -87,6 +90,27 @@ static struct af_info* filter_list[] = {
NULL
};
+static bool get_desc(struct m_obj_desc *dst, int index)
+{
+ if (index >= MP_ARRAY_SIZE(filter_list) - 1)
+ return false;
+ const struct af_info *af = filter_list[index];
+ *dst = (struct m_obj_desc) {
+ .name = af->name,
+ .description = af->info,
+ .priv_size = af->priv_size,
+ .priv_defaults = af->priv_defaults,
+ .options = af->options,
+ .p = af,
+ };
+ return true;
+}
+
+const struct m_obj_list af_obj_list = {
+ .get_desc = get_desc,
+ .description = "audio filters",
+};
+
static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
{
return a->format == b->format
@@ -139,90 +163,58 @@ static struct mp_audio *dummy_play(struct af_instance* af, struct mp_audio* data
return data;
}
-/* Find a filter in the static list of filters using it's name. This
- function is used internally */
-static struct af_info *af_find(char *name)
-{
- int i = 0;
- while (filter_list[i]) {
- if (!strcmp(filter_list[i]->name, name))
- return filter_list[i];
- i++;
- }
- mp_msg(MSGT_AFILTER, MSGL_ERR, "Couldn't find audio filter '%s'\n", name);
- return NULL;
-}
-
-/* Find filter in the dynamic filter list using it's name This
- function is used for finding already initialized filters */
-struct af_instance *af_get(struct af_stream *s, char *name)
-{
- struct af_instance *af = s->first;
- // Find the filter
- while (af != NULL) {
- if (!strcmp(af->info->name, name))
- return af;
- af = af->next;
- }
- return NULL;
-}
-
/* Function for creating a new filter of type name.The name may
contain the commandline parameters for the filter */
-static struct af_instance *af_create(struct af_stream *s,
- const char *name_with_cmd)
+static struct af_instance *af_create(struct af_stream *s, char *name,
+ char **args)
{
- char *name = strdup(name_with_cmd);
- char *cmdline = name;
-
- // Allocate space for the new filter and reset all pointers
- struct af_instance *new = malloc(sizeof(struct af_instance));
- if (!name || !new) {
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Could not allocate memory\n");
- goto err_out;
- }
- memset(new, 0, sizeof(struct af_instance));
-
- // Check for commandline parameters
- char *skip = strstr(cmdline, "=");
- if (skip) {
- *skip = '\0'; // for name
- cmdline = skip + 1;
- } else {
- cmdline = NULL;
+ struct m_obj_desc desc;
+ if (!m_obj_list_find(&desc, &af_obj_list, bstr0(name))) {
+ mp_tmsg(MSGT_VFILTER, MSGL_ERR,
+ "Couldn't find audio filter '%s'.\n", name);
+ return NULL;
}
-
- // Find filter from name
- if (NULL == (new->info = af_find(name)))
- goto err_out;
-
+ const struct af_info *info = desc.p;
/* Make sure that the filter is not already in the list if it is
non-reentrant */
- if (new->info->flags & AF_FLAGS_NOT_REENTRANT) {
- if (af_get(s, name)) {
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one "
- "instance of the filter '%s' in each stream\n", name);
- goto err_out;
+ if (info->flags & AF_FLAGS_NOT_REENTRANT) {
+ for (struct af_instance *cur = s->first; cur; cur = cur->next) {
+ if (cur->info == info) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one "
+ "instance of the filter '%s' in each stream\n", name);
+ return NULL;
+ }
}
}
mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n", name);
+ struct af_instance *af = talloc_zero(NULL, struct af_instance);
+ *af = (struct af_instance) {
+ .info = info,
+ .mul = 1,
+ };
+ struct m_config *config = m_config_from_obj_desc(af, &desc);
+ if (m_config_initialize_obj(config, &desc, &af->priv, &args) < 0)
+ goto error;
+
// Initialize the new filter
- if (AF_OK == new->info->open(new)) {
- if (cmdline) {
- if (AF_ERROR >= new->control(new, AF_CONTROL_COMMAND_LINE, cmdline))
- goto err_out;
- }
- free(name);
- return new;
+ if (af->info->open(af) != AF_OK)
+ goto error;
+ if (args && af->control) {
+ // Single option string for old filters
+ char *s = (char *)args; // m_config_initialize_obj did this
+ assert(!af->priv);
+ if (af->control(af, AF_CONTROL_COMMAND_LINE, s) <= AF_ERROR)
+ goto error;
}
-err_out:
- free(new);
+ return af;
+
+error:
mp_msg(MSGT_AFILTER, MSGL_ERR,
"[libaf] Couldn't create or open audio filter '%s'\n", name);
- free(name);
+ talloc_free(af);
return NULL;
}
@@ -231,14 +223,14 @@ err_out:
value is the new filter */
static struct af_instance *af_prepend(struct af_stream *s,
struct af_instance *af,
- const char *name)
+ char *name, char **args)
{
if (!af)
af = s->last;
if (af == s->first)
af = s->first->next;
// Create the new filter and make sure it is OK
- struct af_instance *new = af_create(s, name);
+ struct af_instance *new = af_create(s, name, args);
if (!new)
return NULL;
// Update pointers
@@ -254,14 +246,14 @@ static struct af_instance *af_prepend(struct af_stream *s,
value is the new filter */
static struct af_instance *af_append(struct af_stream *s,
struct af_instance *af,
- const char *name)
+ char *name, char **args)
{
if (!af)
af = s->first;
if (af == s->last)
af = s->last->prev;
// Create the new filter and make sure it is OK
- struct af_instance *new = af_create(s, name);
+ struct af_instance *new = af_create(s, name, args);
if (!new)
return NULL;
// Update pointers
@@ -273,7 +265,7 @@ static struct af_instance *af_append(struct af_stream *s,
}
// Uninit and remove the filter "af"
-void af_remove(struct af_stream *s, struct af_instance *af)
+static void af_remove(struct af_stream *s, struct af_instance *af)
{
if (!af)
return;
@@ -293,7 +285,7 @@ void af_remove(struct af_stream *s, struct af_instance *af)
af->next->prev = af->prev;
af->uninit(af);
- free(af);
+ talloc_free(af);
}
static void remove_auto_inserted_filters(struct af_stream *s)
@@ -341,12 +333,12 @@ static int af_count_filters(struct af_stream *s)
return count;
}
-static const char *af_find_conversion_filter(int srcfmt, int dstfmt)
+static char *af_find_conversion_filter(int srcfmt, int dstfmt)
{
for (int n = 0; filter_list[n]; n++) {
struct af_info *af = filter_list[n];
if (af->test_conversion && af->test_conversion(srcfmt, dstfmt))
- return af->name;
+ return (char *)af->name;
}
return NULL;
}
@@ -376,10 +368,10 @@ static int af_fix_format_conversion(struct af_stream *s,
*p_af = prev;
return AF_OK;
}
- const char *filter = af_find_conversion_filter(actual.format, in.format);
+ char *filter = af_find_conversion_filter(actual.format, in.format);
if (!filter)
return AF_ERROR;
- struct af_instance *new = af_prepend(s, af, filter);
+ struct af_instance *new = af_prepend(s, af, filter, NULL);
if (new == NULL)
return AF_ERROR;
new->auto_inserted = true;
@@ -403,8 +395,8 @@ static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
*p_af = prev;
return AF_OK;
}
- const char *filter = "lavrresample";
- struct af_instance *new = af_prepend(s, af, filter);
+ char *filter = "lavrresample";
+ struct af_instance *new = af_prepend(s, af, filter, NULL);
if (new == NULL)
return AF_ERROR;
new->auto_inserted = true;
@@ -427,8 +419,8 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
*p_af = prev;
return AF_OK;
}
- const char *filter = "lavrresample";
- struct af_instance *new = af_prepend(s, af, filter);
+ char *filter = "lavrresample";
+ struct af_instance *new = af_prepend(s, af, filter, NULL);
if (new == NULL)
return AF_ERROR;
new->auto_inserted = true;
@@ -438,6 +430,7 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
return AF_OK;
}
+// Return AF_OK on success or AF_ERROR on failure.
// Warning:
// A failed af_reinit() leaves the audio chain behind in a useless, broken
// state (for example, format filters that were tentatively inserted stay
@@ -445,7 +438,7 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
// In that case, you should always rebuild the filter chain, or abort.
// Also, note that for complete reinit, fixup_output_format() may have to be
// called after this function.
-int af_reinit(struct af_stream *s)
+static int af_reinit(struct af_stream *s)
{
// Start with the second filter, as the first filter is the special input
// filter which needs no initialization.
@@ -543,6 +536,7 @@ struct af_stream *af_new(struct MPOpts *opts)
};
s->first->next = s->last;
s->last->prev = s->first;
+ s->opts = opts;
return s;
}
@@ -578,8 +572,6 @@ static int fixup_output_format(struct af_stream *s)
The return value is 0 if success and -1 if failure */
int af_init(struct af_stream *s)
{
- int i = 0;
-
// Sanity check
if (!s)
return -1;
@@ -591,11 +583,10 @@ int af_init(struct af_stream *s)
// Check if this is the first call
if (s->first->next == s->last) {
// Add all filters in the list (if there are any)
- if (s->cfg.list) {
- while (s->cfg.list[i]) {
- if (!af_prepend(s, s->last, s->cfg.list[i++]))
- return -1;
- }
+ struct m_obj_settings *list = s->opts->af_settings;
+ for (int i = 0; list && list[i].name; i++) {
+ if (!af_prepend(s, s->last, list[i].name, list[i].attribs))
+ return -1;
}
}
@@ -621,7 +612,7 @@ int af_init(struct af_stream *s)
to the stream s. The filter will be inserted somewhere nice in the
list of filters. The return value is a pointer to the new filter,
If the filter couldn't be added the return value is NULL. */
-struct af_instance *af_add(struct af_stream *s, char *name)
+struct af_instance *af_add(struct af_stream *s, char *name, char **args)
{
struct af_instance *new;
// Sanity check
@@ -629,9 +620,9 @@ struct af_instance *af_add(struct af_stream *s, char *name)
return NULL;
// Insert the filter somewhere nice
if (af_is_conversion_filter(s->first->next))
- new = af_append(s, s->first->next, name);
+ new = af_append(s, s->first->next, name, args);
else
- new = af_prepend(s, s->first->next, name);
+ new = af_prepend(s, s->first->next, name, args);
if (!new)
return NULL;
@@ -729,21 +720,3 @@ struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg)
}
return NULL;
}
-
-void af_help(void)
-{
- int i = 0;
- mp_msg(MSGT_AFILTER, MSGL_INFO, "Available audio filters:\n");
- while (filter_list[i]) {
- if (filter_list[i]->comment && filter_list[i]->comment[0]) {
- mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s (%s)\n",
- filter_list[i]->name, filter_list[i]->info,
- filter_list[i]->comment);
- } else {
- mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s\n",
- filter_list[i]->name,
- filter_list[i]->info);
- }
- i++;
- }
-}
diff --git a/audio/filter/af.h b/audio/filter/af.h
index 4ccc70792f..df4e03b49a 100644
--- a/audio/filter/af.h
+++ b/audio/filter/af.h
@@ -50,15 +50,19 @@ struct af_info {
const int flags;
int (*open)(struct af_instance *vf);
bool (*test_conversion)(int src_format, int dst_format);
+ int priv_size;
+ const void *priv_defaults;
+ const struct m_option *options;
};
// Linked list of audio filters
struct af_instance {
- struct af_info *info;
+ const struct af_info *info;
int (*control)(struct af_instance *af, int cmd, void *arg);
void (*uninit)(struct af_instance *af);
struct mp_audio * (*play)(struct af_instance *af, struct mp_audio *data);
- void *setup; // setup data for this specific instance and filter
+ void *setup; // old field for priv structs
+ void *priv;
struct mp_audio *data; // configuration for outgoing data stream
struct af_instance *next;
struct af_instance *prev;
@@ -69,12 +73,6 @@ struct af_instance {
bool auto_inserted; // inserted by af.c, such as conversion filters
};
-// Configuration switches
-struct af_cfg {
- char **list; /* list of names of filters that are added to filter
- list during first initialization of stream */
-};
-
// Current audio stream
struct af_stream {
// The first and last filter in the list
@@ -86,8 +84,7 @@ struct af_stream {
struct mp_audio input;
struct mp_audio output;
struct mp_audio filter_output;
- // Configuration for this stream
- struct af_cfg cfg;
+
struct MPOpts *opts;
};
@@ -139,13 +136,6 @@ int af_init(struct af_stream *s);
void af_uninit(struct af_stream *s);
/**
- * \brief Reinit the filter list from the given filter on downwards
- * See af.c.
- * \return AF_OK on success or AF_ERROR on failure
- */
-int af_reinit(struct af_stream *s);
-
-/**
* \brief This function adds the filter "name" to the stream s.
* \param name name of filter to add
* \return pointer to the new filter, NULL if insert failed
@@ -154,22 +144,7 @@ int af_reinit(struct af_stream *s);
* list of filters (i.e. at the beginning unless the
* first filter is the format filter (why??).
*/
-struct af_instance *af_add(struct af_stream *s, char *name);
-
-/**
- * \brief Uninit and remove the filter "af"
- * \param af filter to remove
- */
-void af_remove(struct af_stream *s, struct af_instance *af);
-
-/**
- * \brief find filter in chain by name
- * \param name name of the filter to find
- * \return first filter with right name or NULL if not found
- *
- * This function is used for finding already initialized filters
- */
-struct af_instance *af_get(struct af_stream *s, char *name);
+struct af_instance *af_add(struct af_stream *s, char *name, char **args);
/**
* \brief filter data chunk through the filters in the list
@@ -282,9 +257,6 @@ float af_softclip(float a);
/** \} */ // end of af_filter group, but more functions of this group below
-/** Print a list of all available audio filters */
-void af_help(void);
-
/** Memory reallocation macro: if a local buffer is used (i.e. if the
filter doesn't operate on the incoming buffer this macro must be
called to ensure the buffer is big enough.
diff --git a/audio/mixer.c b/audio/mixer.c
index 0f1a7871d6..7ccfaa4639 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -113,7 +113,7 @@ static void setvolume_internal(mixer_t *mixer, float l, float r)
{
mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN,
"[Mixer] No hardware mixing, inserting volume filter.\n");
- if (!(af_add(mixer->afilter, "volume")
+ if (!(af_add(mixer->afilter, "volume", NULL)
&& af_control_any_rev(mixer->afilter,
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
db_vals)))
@@ -220,7 +220,7 @@ void mixer_setbalance(mixer_t *mixer, float val)
if (val == 0 || mixer->ao->channels.num < 2)
return;
- if (!(af_pan_balance = af_add(mixer->afilter, "pan"))) {
+ if (!(af_pan_balance = af_add(mixer->afilter, "pan", NULL))) {
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
"[Mixer] No balance control available.\n");
return;