From 2eac58eaa97ec667a2512cd27c35f006a22ec074 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 10 Jul 2016 18:39:50 +0200 Subject: audio: cleanup audio filter format negotiation The algorithm and functionality is the same, but the code becomes much simpler and easier to follow. The assumption that there is only 1 conversion filter (lavrresample) helps with the simplification, but the main change is to use the same code for format/channels/rate. Get rid of the different AF_CONTROL_SET_* controls, and change the af->data parameters directly. (af->data is badly named, but essentially is a placeholder for the output format.) Also, instead of trying to use the af_reinit() loop to init inserted conversion filters or filters with changed output formats, do it inline, and move the common code to a filter_reinit() function. This gets rid of the awful retry variable. In general, this should not change any runtime behavior. --- audio/filter/af.c | 185 ++++++++++++++--------------------------- audio/filter/af.h | 5 -- audio/filter/af_lavrresample.c | 21 ----- 3 files changed, 62 insertions(+), 149 deletions(-) (limited to 'audio') diff --git a/audio/filter/af.c b/audio/filter/af.c index 21b0982692..657340e252 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -266,101 +266,77 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at, MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output)); } -// in is what af can take as input - insert a conversion filter if the actual -// input format doesn't match what af expects. -// Returns: -// AF_OK: must call af_reinit() or equivalent, format matches (or is closer) -// AF_FALSE: nothing was changed, format matches -// else: error -static int af_fix_format_conversion(struct af_stream *s, - struct af_instance **p_af, - struct mp_audio in) -{ - int rv; - struct af_instance *af = *p_af; - struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (actual.format == in.format) - return AF_FALSE; - int dstfmt = in.format; - char *filter = "lavrresample"; - if (!af_lavrresample_test_conversion(actual.format, dstfmt)) - return AF_ERROR; - if (strcmp(filter, prev->info->name) == 0) { - if (prev->control(prev, AF_CONTROL_SET_FORMAT, &dstfmt) == AF_OK) { - *p_af = prev; - return AF_OK; - } - return AF_ERROR; - } - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) - return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_FORMAT, &dstfmt))) { - af_remove(s, new); - return rv; +static void reset_formats(struct af_stream *s) +{ + struct mp_audio none = {0}; + for (struct af_instance *af = s->first; af; af = af->next) { + if (af != s->first && af != s->last) + mp_audio_copy_config(af->data, &none); } - *p_af = new; - return AF_OK; } -// same as af_fix_format_conversion - only wrt. channels -static int af_fix_channels(struct af_stream *s, struct af_instance **p_af, - struct mp_audio in) +static int filter_reinit(struct af_instance *af) { - int rv; - struct af_instance *af = *p_af; struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (mp_chmap_equals(&actual.channels, &in.channels)) - return AF_FALSE; - if (prev->control(prev, AF_CONTROL_SET_CHANNELS, &in.channels) == AF_OK) { - *p_af = prev; - return AF_OK; - } - char *filter = "lavrresample"; - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) + assert(prev); + + // Check if this is the first filter + struct mp_audio in = *prev->data; + // Reset just in case... + mp_audio_set_null_data(&in); + + if (!mp_audio_config_valid(&in)) return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_CHANNELS, &in.channels))) - return rv; - *p_af = new; - return AF_OK; -} -static int af_fix_rate(struct af_stream *s, struct af_instance **p_af, - struct mp_audio in) -{ - int rv; - struct af_instance *af = *p_af; - struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (actual.rate == in.rate) - return AF_FALSE; - if (prev->control(prev, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate) == AF_OK) { - *p_af = prev; - return AF_OK; + af->fmt_in = in; + int rv = af->control(af, AF_CONTROL_REINIT, &in); + if (rv == AF_OK && !mp_audio_config_equals(&in, prev->data)) + rv = AF_FALSE; // conversion filter needed + if (rv == AF_FALSE) + af->fmt_in = in; + + if (rv == AF_OK) { + if (!mp_audio_config_valid(af->data)) + return AF_ERROR; + af->fmt_out = *af->data; } - char *filter = "lavrresample"; - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) - return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate))) - return rv; - *p_af = new; - return AF_OK; + + return rv; } -static void reset_formats(struct af_stream *s) +static int filter_reinit_with_conversion(struct af_stream *s, struct af_instance *af) { - for (struct af_instance *af = s->first; af; af = af->next) { - af->control(af, AF_CONTROL_SET_RESAMPLE_RATE, &(int){0}); - af->control(af, AF_CONTROL_SET_CHANNELS, &(struct mp_chmap){0}); - af->control(af, AF_CONTROL_SET_FORMAT, &(int){0}); + int rv = filter_reinit(af); + + // Conversion filter is needed + if (rv == AF_FALSE) { + // First try if we can change the output format of the previous + // filter to the input format the current filter is expecting. + struct mp_audio in = af->fmt_in; + if (af->prev != s->first && !mp_audio_config_equals(af->data, &in)) { + // This should have been successful (because it succeeded + // before), even if just reverting to the old output format. + mp_audio_copy_config(af->data, &in); + if (filter_reinit(af->prev) != AF_OK) + return AF_ERROR; + } + if (!mp_audio_config_equals(af->prev->data, &in)) { + // Retry with conversion filter added. + struct af_instance *new = + af_prepend(s, af, "lavrresample", NULL); + if (!new) + return AF_ERROR; + new->auto_inserted = true; + mp_audio_copy_config(new->data, &in); + rv = filter_reinit(new); + if (rv != AF_OK) + af_remove(s, new); + } + if (rv == AF_OK) + rv = filter_reinit(af); } + + return rv; } // Return AF_OK on success or AF_ERROR on failure. @@ -378,52 +354,18 @@ 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. struct af_instance *af = s->first->next; - // Up to 4 retries per filter (channel, rate, format conversions) - int max_retry = 4; - int retry = 0; while (af) { - if (retry >= max_retry) - goto negotiate_error; - - // Check if this is the first filter - struct mp_audio in = *af->prev->data; - // Reset just in case... - mp_audio_set_null_data(&in); - - if (!mp_audio_config_valid(&in)) - goto error; + int rv = filter_reinit_with_conversion(s, af); - af->fmt_in = in; - int rv = af->control(af, AF_CONTROL_REINIT, &in); - if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data)) - rv = AF_FALSE; // conversion filter needed switch (rv) { case AF_OK: - if (!mp_audio_config_valid(af->data)) - goto error; - af->fmt_out = *af->data; af = af->next; break; - case AF_FALSE: { // Configuration filter is needed - if (af_fix_channels(s, &af, in) == AF_OK) { - retry++; - continue; - } - if (af_fix_rate(s, &af, in) == AF_OK) { - retry++; - continue; - } - // Do this last, to prevent "format->lavrresample" being added to - // the filter chain when output formats not supported by - // af_lavrresample are in use. - if (af_fix_format_conversion(s, &af, in) == AF_OK) { - retry++; - continue; - } + case AF_FALSE: { // If the format conversion is (probably) caused by spdif, then // (as a feature) drop the filter, instead of failing hard. int fmt_in1 = af->prev->data->format; - int fmt_in2 = in.format; + int fmt_in2 = af->fmt_in.format; if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) { bool spd1 = af_fmt_is_spdif(fmt_in1); bool spd2 = af_fmt_is_spdif(fmt_in2); @@ -434,7 +376,6 @@ static int af_reinit(struct af_stream *s) struct af_instance *aft = af->prev; af_remove(s, af); af = aft->next; - retry++; continue; } } @@ -452,8 +393,6 @@ static int af_reinit(struct af_stream *s) af->info->name, rv); goto error; } - if (af && !af->auto_inserted) - retry = 0; } /* Set previously unset fields in s->output to those of the filter chain diff --git a/audio/filter/af.h b/audio/filter/af.h index 9c49081f66..697024b781 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -112,9 +112,6 @@ struct af_stream { enum af_control { AF_CONTROL_REINIT = 1, AF_CONTROL_RESET, - AF_CONTROL_SET_RESAMPLE_RATE, - AF_CONTROL_SET_FORMAT, - AF_CONTROL_SET_CHANNELS, AF_CONTROL_SET_VOLUME, AF_CONTROL_GET_VOLUME, AF_CONTROL_SET_PAN_LEVEL, @@ -160,6 +157,4 @@ int af_test_output(struct af_instance *af, struct mp_audio *out); int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma); float af_softclip(float a); -bool af_lavrresample_test_conversion(int src_format, int dst_format); - #endif /* MPLAYER_AF_H */ diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index 6fbb445563..fdef69a16b 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -173,12 +173,6 @@ static int check_output_conversion(int mp_format) return af_to_avformat(mp_format); } -bool af_lavrresample_test_conversion(int src_format, int dst_format) -{ - return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE && - check_output_conversion(dst_format) != AV_SAMPLE_FMT_NONE; -} - static struct mp_chmap fudge_pairs[][2] = { {MP_CHMAP2(BL, BR), MP_CHMAP2(SL, SR)}, {MP_CHMAP2(SL, SR), MP_CHMAP2(BL, BR)}, @@ -407,21 +401,6 @@ static int control(struct af_instance *af, int cmd, void *arg) r = configure_lavrr(af, in, out, true); return r; } - case AF_CONTROL_SET_FORMAT: { - int format = *(int *)arg; - if (format && check_output_conversion(format) == AV_SAMPLE_FMT_NONE) - return AF_FALSE; - - mp_audio_set_format(af->data, format); - return AF_OK; - } - case AF_CONTROL_SET_CHANNELS: { - mp_audio_set_channels(af->data, (struct mp_chmap *)arg); - return AF_OK; - } - case AF_CONTROL_SET_RESAMPLE_RATE: - af->data->rate = *(int *)arg; - return AF_OK; case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: { s->playback_speed = *(double *)arg; return AF_OK; -- cgit v1.2.3