1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-24 00:23:27 +00:00

audio: refactor some aspects of filter chain setup

There's no real reason why audio_init_filter() should exist. Just use
af_init or af_reinit directly. (We lose a useless message; the same
information is printed in a quite close place with more details.)

Requires less code, and the way the filter chain is marked as having
failed to initialize allows just switching off audio instead of
crashing if trying to insert a volume filter in mixer.c fails, and
recreating the old filter chain fails too.
This commit is contained in:
wm4 2014-10-02 01:47:27 +02:00
parent 2e16dfbf93
commit 7dd3822d09
5 changed files with 56 additions and 104 deletions

View File

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

View File

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

View File

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

View File

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

View File

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