diff options
Diffstat (limited to 'audio/filter/af.c')
-rw-r--r-- | audio/filter/af.c | 185 |
1 files changed, 62 insertions, 123 deletions
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 |