diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index 4b8ae7949c..29674f3e0e 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -164,57 +164,13 @@ void audio_uninit(struct dec_audio *d_audio) { if (!d_audio) return; - if (d_audio->afilter) { - MP_VERBOSE(d_audio, "Uninit audio filters...\n"); - af_destroy(d_audio->afilter); - d_audio->afilter = NULL; - } + MP_VERBOSE(d_audio, "Uninit audio filters...\n"); + af_destroy(d_audio->afilter); uninit_decoder(d_audio); talloc_free(d_audio->decode_buffer); talloc_free(d_audio); } - -int audio_init_filters(struct dec_audio *d_audio, int in_samplerate, - int *out_samplerate, struct mp_chmap *out_channels, - int *out_format) -{ - if (!d_audio->afilter) - d_audio->afilter = af_new(d_audio->global); - struct af_stream *afs = d_audio->afilter; - - // input format: same as codec's output format: - mp_audio_buffer_get_format(d_audio->decode_buffer, &afs->input); - // Sample rate can be different when adjusting playback speed - afs->input.rate = in_samplerate; - - // output format: same as ao driver's input format (if missing, fallback to input) - afs->output.rate = *out_samplerate; - mp_audio_set_channels(&afs->output, out_channels); - mp_audio_set_format(&afs->output, *out_format); - - afs->replaygain_data = d_audio->replaygain_data; - - char *s_from = mp_audio_config_to_str(&afs->input); - char *s_to = mp_audio_config_to_str(&afs->output); - MP_VERBOSE(d_audio, "Building audio filter chain for %s -> %s...\n", s_from, s_to); - talloc_free(s_from); - talloc_free(s_to); - - // let's autoprobe it! - if (af_init(afs) != 0) { - af_destroy(afs); - d_audio->afilter = NULL; - return 0; // failed :( - } - - *out_samplerate = afs->output.rate; - *out_channels = afs->output.channels; - *out_format = afs->output.format; - - return 1; -} - /* Decode packets until we know the audio format. Then reinit the buffer. * Returns AD_OK on success, negative AD_* code otherwise. * Also returns AD_OK if already initialized (and does nothing). @@ -304,7 +260,7 @@ static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf, int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf, int minsamples) { - if (!d_audio->afilter) + if (d_audio->afilter->initialized < 1) return AD_ERR; // Indicates that a filter seems to be buffering large amounts of data @@ -354,8 +310,7 @@ void audio_reset_decoding(struct dec_audio *d_audio) { if (d_audio->ad_driver) d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL); - if (d_audio->afilter) - af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL); + af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL); d_audio->pts = MP_NOPTS_VALUE; d_audio->pts_offset = 0; if (d_audio->decode_buffer) diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index b76ff0b95c..08fa87e8a7 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -36,7 +36,6 @@ struct dec_audio { struct mp_audio_buffer *decode_buffer; struct af_stream *afilter; char *decoder_desc; - struct replaygain_data *replaygain_data; int init_retries; // set by decoder struct mp_audio decoded; // decoded audio set by last decode_packet() call @@ -65,8 +64,4 @@ int initial_audio_decode(struct dec_audio *d_audio); void audio_reset_decoding(struct dec_audio *d_audio); void audio_uninit(struct dec_audio *d_audio); -int audio_init_filters(struct dec_audio *d_audio, int in_samplerate, - int *out_samplerate, struct mp_chmap *out_channels, - int *out_format); - #endif /* MPLAYER_DEC_AUDIO_H */ diff --git a/audio/filter/af.c b/audio/filter/af.c index 72029f1013..176946b6d4 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -558,22 +558,27 @@ static int af_reinit(struct af_stream *s) MP_ERR(s, "Reinitialization did not work, " "audio filter '%s' returned error code %i\n", af->info->name, rv); - af_print_filter_chain(s, af, MSGL_ERR); - return AF_ERROR; + goto error; } } - af_print_filter_chain(s, NULL, MSGL_V); - /* Set previously unset fields in s->output to those of the filter chain * output. This is used to make the output format fixed, and even if you * insert new filters or change the input format, the output format won't * change. (Audio outputs generally can't change format at runtime.) */ af_copy_unset_fields(&s->output, &s->filter_output); - return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR; + if (af_config_equals(&s->output, &s->filter_output)) { + s->initialized = 1; + af_print_filter_chain(s, NULL, MSGL_V); + return AF_OK; + } + + goto error; negotiate_error: MP_ERR(s, "Unable to convert audio input format to output format.\n"); +error: + s->initialized = -1; af_print_filter_chain(s, af, MSGL_ERR); return AF_ERROR; } @@ -583,6 +588,7 @@ void af_uninit(struct af_stream *s) { while (s->first->next && s->first->next != s->last) af_remove(s, s->first->next); + s->initialized = 0; } struct af_stream *af_new(struct mpv_global *global) @@ -632,10 +638,6 @@ void af_destroy(struct af_stream *s) The return value is 0 if success and -1 if failure */ int af_init(struct af_stream *s) { - // Sanity check - if (!s) - return -1; - // Precaution in case caller is misbehaving mp_audio_set_null_data(&s->input); mp_audio_set_null_data(&s->output); @@ -647,6 +649,7 @@ int af_init(struct af_stream *s) for (int i = 0; list && list[i].name; i++) { if (!af_prepend(s, s->last, list[i].name, list[i].attribs)) { af_uninit(s); + s->initialized = -1; return -1; } } @@ -655,7 +658,6 @@ int af_init(struct af_stream *s) if (af_reinit(s) != AF_OK) { // Something is stuffed audio out will not work MP_ERR(s, "Could not create audio filter chain.\n"); - af_uninit(s); return -1; } return 0; @@ -668,9 +670,6 @@ int af_init(struct af_stream *s) struct af_instance *af_add(struct af_stream *s, char *name, char **args) { struct af_instance *new; - // Sanity check - if (!s || !s->first || !name) - return NULL; // Insert the filter somewhere nice if (af_is_conversion_filter(s->first->next)) new = af_append(s, s->first->next, name, args); @@ -698,6 +697,7 @@ struct af_instance *af_add(struct af_stream *s, char *name, char **args) int af_filter(struct af_stream *s, struct mp_audio *data, int flags) { struct af_instance *af = s->first; + assert(s->initialized > 0); assert(mp_audio_config_equals(af->data, data)); // Iterate through all filters while (af) { diff --git a/audio/filter/af.h b/audio/filter/af.h index bec0e823fe..579ac271ef 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -80,6 +80,8 @@ struct af_instance { // Current audio stream struct af_stream { + int initialized; // 0: no, 1: yes, -1: attempted to, but failed + // The first and last filter in the list struct af_instance *first; struct af_instance *last; diff --git a/player/audio.c b/player/audio.c index cc4496ed57..85dda4722c 100644 --- a/player/audio.c +++ b/player/audio.c @@ -45,34 +45,30 @@ static int recreate_audio_filters(struct MPContext *mpctx) { - struct dec_audio *d_audio = mpctx->d_audio; + assert(mpctx->d_audio); + + struct af_stream *afs = mpctx->d_audio->afilter; struct MPOpts *opts = mpctx->opts; - assert(d_audio); - struct mp_audio in_format; - mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format); + mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format); + int new_srate = in_format.rate; - struct mp_audio out_format; - ao_get_format(mpctx->ao, &out_format); - - int new_srate; - if (af_control_any_rev(d_audio->afilter, AF_CONTROL_SET_PLAYBACK_SPEED, - &opts->playback_speed)) - new_srate = in_format.rate; - else { + if (!af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED, + &opts->playback_speed)) + { new_srate = in_format.rate * opts->playback_speed; - if (new_srate != out_format.rate) + if (new_srate != afs->output.rate) opts->playback_speed = new_srate / (double)in_format.rate; } - if (!audio_init_filters(d_audio, new_srate, - &out_format.rate, &out_format.channels, &out_format.format)) - { + afs->input.rate = new_srate; + + if (af_init(afs) < 0) { MP_ERR(mpctx, "Couldn't find matching filter/ao format!\n"); return -1; } - mixer_reinit_audio(mpctx->mixer, mpctx->ao, mpctx->d_audio->afilter); + mixer_reinit_audio(mpctx->mixer, mpctx->ao, afs); return 0; } @@ -121,7 +117,8 @@ void reinit_audio_chain(struct MPContext *mpctx) mpctx->d_audio->global = mpctx->global; mpctx->d_audio->opts = opts; mpctx->d_audio->header = sh; - mpctx->d_audio->replaygain_data = sh->audio->replaygain_data; + mpctx->d_audio->afilter = af_new(mpctx->global); + mpctx->d_audio->afilter->replaygain_data = sh->audio->replaygain_data; mpctx->ao_buffer = mp_audio_buffer_create(NULL); if (!audio_init_best_codec(mpctx->d_audio, opts->audio_decoders)) goto init_error; @@ -152,39 +149,41 @@ void reinit_audio_chain(struct MPContext *mpctx) uninit_player(mpctx, INITIALIZED_AO); } - int ao_srate = opts->force_srate; - int ao_format = opts->audio_output_format; - struct mp_chmap ao_channels = {0}; + struct af_stream *afs = mpctx->d_audio->afilter; + if (mpctx->initialized_flags & INITIALIZED_AO) { - struct mp_audio out_format; - ao_get_format(mpctx->ao, &out_format); - ao_srate = out_format.rate; - ao_format = out_format.format; - ao_channels = out_format.channels; + ao_get_format(mpctx->ao, &afs->output); } else { + afs->output = (struct mp_audio){0}; + afs->output.rate = opts->force_srate; + mp_audio_set_format(&afs->output, opts->audio_output_format); + // automatic downmix if (!AF_FORMAT_IS_SPECIAL(in_format.format)) - ao_channels = opts->audio_output_channels; // automatic downmix + mp_audio_set_channels(&afs->output, &opts->audio_output_channels); } + // filter input format: same as codec's output format: + mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &afs->input); + // Determine what the filter chain outputs. recreate_audio_filters() also // needs this for testing whether playback speed is changed by resampling // or using a special filter. - if (!audio_init_filters(mpctx->d_audio, // preliminary init - // input: - in_format.rate, - // output: - &ao_srate, &ao_channels, &ao_format)) { + if (af_init(afs) < 0) { MP_ERR(mpctx, "Error at audio filter chain pre-init!\n"); goto init_error; } if (!(mpctx->initialized_flags & INITIALIZED_AO)) { mpctx->initialized_flags |= INITIALIZED_AO; - mp_chmap_remove_useless_channels(&ao_channels, + afs->initialized = 0; // do it again + + mp_chmap_remove_useless_channels(&afs->output.channels, &opts->audio_output_channels); + mp_audio_set_channels(&afs->output, &afs->output.channels); + mpctx->ao = ao_init_best(mpctx->global, mpctx->input, - mpctx->encode_lavc_ctx, ao_srate, ao_format, - ao_channels); + mpctx->encode_lavc_ctx, afs->output.rate, + afs->output.format, afs->output.channels); struct ao *ao = mpctx->ao; if (!ao) { MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n"); @@ -195,6 +194,7 @@ void reinit_audio_chain(struct MPContext *mpctx) ao_get_format(ao, &fmt); mp_audio_buffer_reinit(mpctx->ao_buffer, &fmt); + afs->output = fmt; mpctx->ao_decoder_fmt = talloc(NULL, struct mp_audio); *mpctx->ao_decoder_fmt = in_format; @@ -229,7 +229,7 @@ double written_audio_pts(struct MPContext *mpctx) struct mp_audio in_format; mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format); - if (!mp_audio_config_valid(&in_format) || !d_audio->afilter) + if (!mp_audio_config_valid(&in_format) || d_audio->afilter->initialized < 1) return MP_NOPTS_VALUE; // first calculate the end pts of audio that has been output by decoder @@ -365,7 +365,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) if (!d_audio) return; - if (!d_audio->afilter || !mpctx->ao) { + if (d_audio->afilter->initialized < 1 || !mpctx->ao) { // Probe the initial audio format. Returns AD_OK (and does nothing) if // the format is already known. int r = initial_audio_decode(mpctx->d_audio);