summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/decode/dec_audio.c53
-rw-r--r--audio/decode/dec_audio.h5
-rw-r--r--audio/filter/af.c26
-rw-r--r--audio/filter/af.h2
-rw-r--r--player/audio.c74
5 files changed, 56 insertions, 104 deletions
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;
- struct MPOpts *opts = mpctx->opts;
+ assert(mpctx->d_audio);
- assert(d_audio);
+ struct af_stream *afs = mpctx->d_audio->afilter;
+ struct MPOpts *opts = mpctx->opts;
struct mp_audio in_format;
- mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);
-
- struct mp_audio out_format;
- ao_get_format(mpctx->ao, &out_format);
+ mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format);
+ int new_srate = in_format.rate;
- 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);