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.)
This commit is contained in:
wm4 2013-07-22 14:43:58 +02:00
parent 221ef23d0d
commit 3b8dfddb4c
14 changed files with 210 additions and 280 deletions

View File

@ -186,6 +186,8 @@ input.conf and Slave Commands
+--------------------------------+----------------------------------------+
| ``show_chapters`` | ``show_text ${chapter-list}`` |
+--------------------------------+----------------------------------------+
| ``af_switch``, ``af_add``, ... | ``af [set|add|...]`` |
+--------------------------------+----------------------------------------+
Other
~~~~~

View File

@ -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
----------------------

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
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;
}
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;
}
// 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++;
}
}

View File

@ -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;
};
@ -138,13 +135,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
@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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 } },

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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),

View File

@ -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;