summaryrefslogtreecommitdiffstats
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
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.)
-rw-r--r--DOCS/man/en/changes.rst2
-rw-r--r--DOCS/man/en/input.rst22
-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
-rw-r--r--core/command.c101
-rw-r--r--core/input/input.c6
-rw-r--r--core/input/input.h6
-rw-r--r--core/mp_core.h1
-rw-r--r--core/mplayer.c85
-rw-r--r--core/options.c4
-rw-r--r--core/options.h1
14 files changed, 210 insertions, 280 deletions
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index 26c9e9d9d2..5ff532ddc9 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -186,6 +186,8 @@ input.conf and Slave Commands
+--------------------------------+----------------------------------------+
| ``show_chapters`` | ``show_text ${chapter-list}`` |
+--------------------------------+----------------------------------------+
+ | ``af_switch``, ``af_add``, ... | ``af [set|add|...]`` |
+ +--------------------------------+----------------------------------------+
Other
~~~~~
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
index fd1aad9c58..804d37d976 100644
--- a/DOCS/man/en/input.rst
+++ b/DOCS/man/en/input.rst
@@ -253,20 +253,10 @@ List of Input Commands
Input Commands that are Possibly Subject to Change
--------------------------------------------------
-``af_switch "filter1=params,filter2,..."``
- Replace the current filter chain with the given list.
+``af set|add|toggle|del|clr "filter1=params,filter2,..."``
+ Change audio filter chain. See ``vf`` command.
-``af_add "filter1=params,filter2,..."``
- Add the given list of audio filters to the audio filter chain.
-
-``af_del "filter1,filter2,..."``
- Remove the given list of audio filters.
-
-``af_clr``
- Remove all audio filters. (Conversion filters will be re-added
- automatically if needed.)
-
-``vf set|add|toggle|del "filter1=params,filter2,..."``
+``vf set|add|toggle|del|clr "filter1=params,filter2,..."``
Change video filter chain.
The first argument decides what happens:
@@ -290,6 +280,10 @@ Input Commands that are Possibly Subject to Change
indexes start from the last filter, and ``-1`` denotes the last
filter.
+ clr
+ Remove all filters. Note that like the other sub-commands, this does
+ not control automatically inserted filters.
+
You can assign labels to filter by prefixing them with ``@name:`` (where
``name`` is a user-chosen arbitrary identifier). Labels can be used to
refer to filters by name in all of the filter chain modification commands.
@@ -322,7 +316,7 @@ Undocumented commands: ``tv_start_scan``, ``tv_step_channel``, ``tv_step_norm``,
``tv_step_freq``, ``tv_set_norm``, ``dvb_set_channel``, ``radio_step_channel``,
``radio_set_channel``, ``radio_set_freq``, ``radio_step_freq`` (all of these
should be replaced by properties), ``stop`` (questionable use), ``get_property``
-(?), ``af_cmdline``, ``vo_cmdline`` (experimental).
+(?), ``vo_cmdline`` (experimental).
Input Command Prefixes
----------------------
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;
diff --git a/core/command.c b/core/command.c
index 4cf508d5e7..32479784e9 100644
--- a/core/command.c
+++ b/core/command.c
@@ -1914,43 +1914,72 @@ static const char *property_error_string(int error_value)
return "UNKNOWN";
}
-static void change_video_filters(MPContext *mpctx, const char *cmd,
- const char *arg)
+static bool reinit_filters(MPContext *mpctx, enum stream_type mediatype)
+{
+ switch (mediatype) {
+ case STREAM_VIDEO:
+ return reinit_video_filters(mpctx) >= 0;
+ case STREAM_AUDIO:
+ return reinit_audio_filters(mpctx) >= 0;
+ }
+ return false;
+}
+
+static void change_filters(MPContext *mpctx, enum stream_type mediatype,
+ const char *cmd, const char *arg)
{
struct MPOpts *opts = &mpctx->opts;
struct m_config *conf = mpctx->mconfig;
- struct m_obj_settings *old_vf_settings = NULL;
+ struct m_obj_settings *old_settings = NULL;
bool success = false;
bool need_refresh = false;
+ const char *option;
+ struct m_obj_settings **list;
+
+ switch (mediatype) {
+ case STREAM_VIDEO:
+ option = "vf";
+ list = &opts->vf_settings;
+ break;
+ case STREAM_AUDIO:
+ option = "af";
+ list = &opts->af_settings;
+ break;
+ }
// The option parser is used to modify the filter list itself.
char optname[20];
- snprintf(optname, sizeof(optname), "vf-%s", cmd);
+ snprintf(optname, sizeof(optname), "%s-%s", option, cmd);
const struct m_option *type = m_config_get_option(conf, bstr0(optname));
// Backup old settings, in case it fails
- m_option_copy(type, &old_vf_settings, &opts->vf_settings);
+ m_option_copy(type, &old_settings, list);
if (m_config_set_option0(conf, optname, arg) >= 0) {
need_refresh = true;
- success = reinit_video_filters(mpctx) >= 0;
+ success = reinit_filters(mpctx, mediatype);
}
if (!success) {
- m_option_copy(type, &opts->vf_settings, &old_vf_settings);
+ m_option_copy(type, list, &old_settings);
if (need_refresh)
- reinit_video_filters(mpctx);
+ reinit_filters(mpctx, mediatype);
}
- m_option_free(type, &old_vf_settings);
+ m_option_free(type, &old_settings);
- if (need_refresh)
+ if (need_refresh && mediatype == STREAM_VIDEO)
mp_force_video_refresh(mpctx);
}
+static void change_video_filters(MPContext *mpctx, const char *cmd,
+ const char *arg)
+{
+ change_filters(mpctx, STREAM_VIDEO, cmd, arg);
+}
+
void run_command(MPContext *mpctx, mp_cmd_t *cmd)
{
struct MPOpts *opts = &mpctx->opts;
- sh_audio_t *const sh_audio = mpctx->sh_audio;
sh_video_t *const sh_video = mpctx->sh_video;
int osd_duration = opts->osd_duration;
bool auto_osd = cmd->on_osd == MP_ON_OSD_AUTO;
@@ -2467,54 +2496,10 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
}
break;
- case MP_CMD_AF_SWITCH:
- if (sh_audio) {
- af_uninit(mpctx->mixer.afilter);
- af_init(mpctx->mixer.afilter);
- }
- /* fallthrough */
- case MP_CMD_AF_ADD:
- case MP_CMD_AF_DEL: {
- if (!sh_audio)
- break;
- char *af_args = strdup(cmd->args[0].v.s);
- bstr af_commands = bstr0(af_args);
- struct af_instance *af;
- while (af_commands.len) {
- bstr af_command;
- bstr_split_tok(af_commands, ",", &af_command, &af_commands);
- char *af_command0 = bstrdup0(NULL, af_command);
- if (cmd->id == MP_CMD_AF_DEL) {
- af = af_get(mpctx->mixer.afilter, af_command0);
- if (af != NULL)
- af_remove(mpctx->mixer.afilter, af);
- } else
- af_add(mpctx->mixer.afilter, af_command0);
- talloc_free(af_command0);
- }
- reinit_audio_chain(mpctx);
- free(af_args);
- break;
- }
- case MP_CMD_AF_CLR:
- if (!sh_audio)
- break;
- af_uninit(mpctx->mixer.afilter);
- af_init(mpctx->mixer.afilter);
- reinit_audio_chain(mpctx);
- break;
- case MP_CMD_AF_CMDLINE:
- if (sh_audio) {
- struct af_instance *af = af_get(sh_audio->afilter, cmd->args[0].v.s);
- if (!af) {
- mp_msg(MSGT_CPLAYER, MSGL_WARN,
- "Filter '%s' not found in chain.\n", cmd->args[0].v.s);
- break;
- }
- af->control(af, AF_CONTROL_COMMAND_LINE, cmd->args[1].v.s);
- af_reinit(sh_audio->afilter);
- }
+ case MP_CMD_AF:
+ change_filters(mpctx, STREAM_AUDIO, cmd->args[0].v.s, cmd->args[1].v.s);
break;
+
case MP_CMD_VF:
change_video_filters(mpctx, cmd->args[0].v.s, cmd->args[1].v.s);
break;
diff --git a/core/input/input.c b/core/input/input.c
index 66d78b48c6..467f6d6299 100644
--- a/core/input/input.c
+++ b/core/input/input.c
@@ -210,11 +210,7 @@ static const mp_cmd_t mp_cmds[] = {
}},
{ MP_CMD_DISABLE_INPUT_SECTION, "disable_section", { ARG_STRING } },
- { MP_CMD_AF_SWITCH, "af_switch", { ARG_STRING } },
- { MP_CMD_AF_ADD, "af_add", { ARG_STRING } },
- { MP_CMD_AF_DEL, "af_del", { ARG_STRING } },
- { MP_CMD_AF_CLR, "af_clr", },
- { MP_CMD_AF_CMDLINE, "af_cmdline", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_AF, "af", { ARG_STRING, ARG_STRING } },
{ MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
diff --git a/core/input/input.h b/core/input/input.h
index 1a0f2529ce..f4f5621e9f 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -77,11 +77,7 @@ enum mp_command_type {
MP_CMD_DVB_SET_CHANNEL = 5101,
/// Audio Filter commands
- MP_CMD_AF_SWITCH,
- MP_CMD_AF_ADD,
- MP_CMD_AF_DEL,
- MP_CMD_AF_CLR,
- MP_CMD_AF_CMDLINE,
+ MP_CMD_AF,
/// Video filter commands
MP_CMD_VF,
diff --git a/core/mp_core.h b/core/mp_core.h
index f7e6786b60..6bbe18c71e 100644
--- a/core/mp_core.h
+++ b/core/mp_core.h
@@ -296,6 +296,7 @@ double playing_audio_pts(struct MPContext *mpctx);
struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, int noerr);
int reinit_video_chain(struct MPContext *mpctx);
int reinit_video_filters(struct MPContext *mpctx);
+int reinit_audio_filters(struct MPContext *mpctx);
void pause_player(struct MPContext *mpctx);
void unpause_player(struct MPContext *mpctx);
void add_step_frame(struct MPContext *mpctx, int dir);
diff --git a/core/mplayer.c b/core/mplayer.c
index e54b55444f..d9c03dace5 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -1185,11 +1185,6 @@ static int build_afilter_chain(struct MPContext *mpctx)
struct ao *ao = mpctx->ao;
struct MPOpts *opts = &mpctx->opts;
int new_srate;
- int result;
- if (!sh_audio) {
- mpctx->mixer.afilter = NULL;
- return 0;
- }
if (af_control_any_rev(sh_audio->afilter,
AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET,
&opts->playback_speed))
@@ -1205,10 +1200,8 @@ static int build_afilter_chain(struct MPContext *mpctx)
opts->playback_speed = (float)new_srate / sh_audio->samplerate;
}
}
- result = init_audio_filters(sh_audio, new_srate,
- &ao->samplerate, &ao->channels, &ao->format);
- mpctx->mixer.afilter = sh_audio->afilter;
- return result;
+ return init_audio_filters(sh_audio, new_srate,
+ &ao->samplerate, &ao->channels, &ao->format);
}
@@ -1572,6 +1565,51 @@ static void update_osd_msg(struct MPContext *mpctx)
}
}
+static int recreate_audio_filters(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
+ assert(mpctx->sh_audio);
+
+ // init audio filters:
+ if (!build_afilter_chain(mpctx)) {
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR,
+ "Couldn't find matching filter/ao format!\n");
+ return -1;
+ }
+
+ mpctx->mixer.afilter = mpctx->sh_audio->afilter;
+ mpctx->mixer.volstep = opts->volstep;
+ mpctx->mixer.softvol = opts->softvol;
+ mpctx->mixer.softvol_max = opts->softvol_max;
+ mixer_reinit(&mpctx->mixer, mpctx->ao);
+ if (!(mpctx->initialized_flags & INITIALIZED_VOL)) {
+ if (opts->mixer_init_volume >= 0) {
+ mixer_setvolume(&mpctx->mixer, opts->mixer_init_volume,
+ opts->mixer_init_volume);
+ }
+ if (opts->mixer_init_mute >= 0)
+ mixer_setmute(&mpctx->mixer, opts->mixer_init_mute);
+ mpctx->initialized_flags |= INITIALIZED_VOL;
+ }
+
+ return 0;
+}
+
+int reinit_audio_filters(struct MPContext *mpctx)
+{
+ struct sh_audio *sh_audio = mpctx->sh_audio;
+ if (!sh_audio)
+ return -2;
+
+ af_uninit(mpctx->sh_audio->afilter);
+ if (af_init(mpctx->sh_audio->afilter) < 0)
+ return -1;
+ if (recreate_audio_filters(mpctx) < 0)
+ return -1;
+
+ return 0;
+}
+
void reinit_audio_chain(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
@@ -1603,7 +1641,9 @@ void reinit_audio_chain(struct MPContext *mpctx)
}
}
- // first init to detect best values
+ // Determine what the filter chain outputs. build_afilter_chain() also
+ // needs this for testing whether playback speed is changed by resampling
+ // or using a special filter.
if (!init_audio_filters(mpctx->sh_audio, // preliminary init
// input:
mpctx->sh_audio->samplerate,
@@ -1638,25 +1678,9 @@ void reinit_audio_chain(struct MPContext *mpctx)
ao->driver->info->comment);
}
- // init audio filters:
- if (!build_afilter_chain(mpctx)) {
- mp_tmsg(MSGT_CPLAYER, MSGL_ERR,
- "Couldn't find matching filter/ao format!\n");
+ if (recreate_audio_filters(mpctx) < 0)
goto init_error;
- }
- mpctx->mixer.volstep = opts->volstep;
- mpctx->mixer.softvol = opts->softvol;
- mpctx->mixer.softvol_max = opts->softvol_max;
- mixer_reinit(&mpctx->mixer, mpctx->ao);
- if (!(mpctx->initialized_flags & INITIALIZED_VOL)) {
- if (opts->mixer_init_volume >= 0) {
- mixer_setvolume(&mpctx->mixer, opts->mixer_init_volume,
- opts->mixer_init_volume);
- }
- if (opts->mixer_init_mute >= 0)
- mixer_setmute(&mpctx->mixer, opts->mixer_init_mute);
- mpctx->initialized_flags |= INITIALIZED_VOL;
- }
+
mpctx->syncing_audio = true;
return;
@@ -4512,11 +4536,6 @@ static bool handle_help_options(struct MPContext *mpctx)
talloc_free(list);
opt_exit = 1;
}
- if (af_cfg.list && strcmp(af_cfg.list[0], "help") == 0) {
- af_help();
- mp_msg(MSGT_CPLAYER, MSGL_INFO, "\n");
- opt_exit = 1;
- }
#ifdef CONFIG_X11
if (opts->vo.fstype_list && strcmp(opts->vo.fstype_list[0], "help") == 0) {
fstype_help();
diff --git a/core/options.c b/core/options.c
index cce36b90bb..03acdc570b 100644
--- a/core/options.c
+++ b/core/options.c
@@ -182,6 +182,7 @@ extern char *dvd_device, *cdrom_device;
extern double mf_fps;
extern char * mf_type;
extern const struct m_obj_list vf_obj_list;
+extern const struct m_obj_list af_obj_list;
extern const struct m_obj_list vo_obj_list;
extern const struct m_obj_list ao_obj_list;
@@ -436,8 +437,7 @@ const m_option_t mp_opts[] = {
// ------------------------- codec/vfilter options --------------------
- {"af*", &af_cfg.list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
-
+ OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list),
OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list),
OPT_STRING("ad", audio_decoders, 0),
diff --git a/core/options.h b/core/options.h
index e7f04b548c..fcb8002a42 100644
--- a/core/options.h
+++ b/core/options.h
@@ -162,6 +162,7 @@ typedef struct MPOpts {
int dtshd;
float playback_speed;
struct m_obj_settings *vf_settings;
+ struct m_obj_settings *af_settings;
float movie_aspect;
int flip;
int field_dominance;