summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-09-21 12:48:30 +0200
committerwm4 <wm4@nowhere>2017-09-21 12:48:30 +0200
commitfdb300b983744c522f335ccf64e9788b78f86701 (patch)
treeabd10d97e8c6cb30e1621db8b67d709cbfaeb705 /player
parent3a2d5e68acb2ac0f8b09b896907a692b1c48c6b3 (diff)
downloadmpv-fdb300b983744c522f335ccf64e9788b78f86701.tar.bz2
mpv-fdb300b983744c522f335ccf64e9788b78f86701.tar.xz
audio: make libaf derived code optional
This code could not be relicensed. The intention was to write new filter code (which could handle both audio and video), but that's a bit of work. Write some code that can do audio conversion (resampling, downmixing, etc.) without the old audio filter chain code in order to speed up the LGPL relicensing. If you build with --disable-libaf, nothing in audio/filter/* is compiled in. It breaks a few features, such as --volume, --af, pitch correction on speed changes, replaygain. Most likely this adds some bugs, even if --disable-libaf is not used. (How the fuck does EOF notification work again anyway?)
Diffstat (limited to 'player')
-rw-r--r--player/audio.c310
-rw-r--r--player/command.c13
-rw-r--r--player/core.h6
-rw-r--r--player/playloop.c1
-rw-r--r--player/video.c2
5 files changed, 241 insertions, 91 deletions
diff --git a/player/audio.c b/player/audio.c
index 2a4c90dcc6..a26a7d1ff5 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -33,10 +33,10 @@
#include "common/common.h"
#include "osdep/timer.h"
-#include "audio/audio.h"
#include "audio/audio_buffer.h"
+#include "audio/aconverter.h"
+#include "audio/format.h"
#include "audio/decode/dec_audio.h"
-#include "audio/filter/af.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "video/decode/dec_video.h"
@@ -54,6 +54,11 @@ enum {
AD_STARVE = -6,
};
+#if HAVE_LIBAF
+
+#include "audio/audio.h"
+#include "audio/filter/af.h"
+
// Use pitch correction only for speed adjustments by the user, not minor sync
// correction ones.
static int get_speed_method(struct MPContext *mpctx)
@@ -180,7 +185,6 @@ void audio_update_volume(struct MPContext *mpctx)
if (opts->softvol_mute == 1)
gain = 0.0;
-#if HAVE_GPL
if (!af_control_any_rev(ao_c->af, AF_CONTROL_SET_VOLUME, &gain)) {
if (gain == 1.0)
return;
@@ -190,7 +194,6 @@ void audio_update_volume(struct MPContext *mpctx)
&& af_control_any_rev(ao_c->af, AF_CONTROL_SET_VOLUME, &gain)))
MP_ERR(mpctx, "No volume control available.\n");
}
-#endif
}
/* NOTE: Currently the balance code is seriously buggy: it always changes
@@ -238,7 +241,6 @@ static int recreate_audio_filters(struct MPContext *mpctx)
{
assert(mpctx->ao_chain);
-#if HAVE_GPL
struct af_stream *afs = mpctx->ao_chain->af;
if (afs->initialized < 1 && af_init(afs) < 0)
goto fail;
@@ -246,7 +248,6 @@ static int recreate_audio_filters(struct MPContext *mpctx)
recreate_speed_filters(mpctx);
if (afs->initialized < 1 && af_init(afs) < 0)
goto fail;
-#endif
if (mpctx->opts->softvol == SOFTVOL_NO)
MP_ERR(mpctx, "--softvol=no is not supported anymore.\n");
@@ -284,26 +285,40 @@ int reinit_audio_filters(struct MPContext *mpctx)
return 1;
}
+#else /* HAVE_LIBAV */
+
+void audio_update_volume(struct MPContext *mpctx) {}
+void audio_update_balance(struct MPContext *mpctx) {}
+int reinit_audio_filters(struct MPContext *mpctx) { return 0; }
+
+#endif /* else HAVE_LIBAF */
+
// Call this if opts->playback_speed or mpctx->speed_factor_* change.
void update_playback_speed(struct MPContext *mpctx)
{
mpctx->audio_speed = mpctx->opts->playback_speed * mpctx->speed_factor_a;
mpctx->video_speed = mpctx->opts->playback_speed * mpctx->speed_factor_v;
+#if HAVE_LIBAF
if (!mpctx->ao_chain || mpctx->ao_chain->af->initialized < 1)
return;
if (!update_speed_filters(mpctx))
recreate_audio_filters(mpctx);
+#endif
}
static void ao_chain_reset_state(struct ao_chain *ao_c)
{
ao_c->pts = MP_NOPTS_VALUE;
ao_c->pts_reset = false;
- talloc_free(ao_c->input_frame);
- ao_c->input_frame = NULL;
+ TA_FREEP(&ao_c->input_frame);
+ TA_FREEP(&ao_c->output_frame);
+#if HAVE_LIBAF
af_seek_reset(ao_c->af);
+#endif
+ if (ao_c->conv)
+ mp_aconverter_flush(ao_c->conv);
mp_audio_buffer_clear(ao_c->ao_buffer);
if (ao_c->audio_src)
@@ -350,9 +365,13 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
if (ao_c->filter_src)
lavfi_set_connected(ao_c->filter_src, false);
+#if HAVE_LIBAF
af_destroy(ao_c->af);
+#endif
+ talloc_free(ao_c->conv);
talloc_free(ao_c->input_frame);
talloc_free(ao_c->input_format);
+ talloc_free(ao_c->filter_input_format);
talloc_free(ao_c->ao_buffer);
talloc_free(ao_c);
}
@@ -369,16 +388,17 @@ void uninit_audio_chain(struct MPContext *mpctx)
}
}
-static void get_ao_format(struct ao *ao, struct mp_audio *aformat)
+static char *audio_config_to_str_buf(char *buf, size_t buf_sz, int rate,
+ int format, struct mp_chmap channels)
{
- int samplerate;
- int format;
- struct mp_chmap channels;
- ao_get_format(ao, &samplerate, &format, &channels);
- *aformat = (struct mp_audio){0};
- mp_audio_set_format(aformat, format);
- mp_audio_set_channels(aformat, &channels);
- aformat->rate = samplerate;
+ char ch[128];
+ mp_chmap_to_str_buf(ch, sizeof(ch), &channels);
+ char *hr_ch = mp_chmap_to_str_hr(&channels);
+ if (strcmp(hr_ch, ch) != 0)
+ mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch);
+ snprintf(buf, buf_sz, "%dHz %s %dch %s", rate,
+ ch, channels.num, af_fmt_to_str(format));
+ return buf;
}
static void reinit_audio_filters_and_output(struct MPContext *mpctx)
@@ -387,7 +407,6 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
struct ao_chain *ao_c = mpctx->ao_chain;
assert(ao_c);
struct track *track = ao_c->track;
- struct af_stream *afs = ao_c->af;
if (!mp_aframe_config_is_valid(ao_c->input_format)) {
// We don't know the audio format yet - so configure it later as we're
@@ -403,24 +422,33 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
uninit_audio_out(mpctx);
}
+ TA_FREEP(&ao_c->output_frame);
+
+ int out_rate = 0;
+ int out_format = 0;
+ struct mp_chmap out_channels = {0};
+ if (mpctx->ao) {
+ ao_get_format(mpctx->ao, &out_rate, &out_format, &out_channels);
+ } else if (af_fmt_is_pcm(mp_aframe_get_format(ao_c->input_format))) {
+ out_rate = opts->force_srate;
+ out_format = opts->audio_output_format;
+ if (opts->audio_output_channels.num_chmaps == 1)
+ out_channels = opts->audio_output_channels.chmaps[0];
+ }
+
+#if HAVE_LIBAF
+ struct af_stream *afs = ao_c->af;
+
struct mp_audio in_format;
mp_audio_config_from_aframe(&in_format, ao_c->input_format);
if (mpctx->ao && mp_audio_config_equals(&in_format, &afs->input))
return;
afs->output = (struct mp_audio){0};
- if (mpctx->ao) {
- get_ao_format(mpctx->ao, &afs->output);
- } else if (af_fmt_is_pcm(mp_aframe_get_format(ao_c->input_format))) {
- afs->output.rate = opts->force_srate;
- mp_audio_set_format(&afs->output, opts->audio_output_format);
- if (opts->audio_output_channels.num_chmaps == 1) {
- mp_audio_set_channels(&afs->output,
- &opts->audio_output_channels.chmaps[0]);
- }
- }
+ afs->output.rate = out_rate;
+ mp_audio_set_format(&afs->output, out_format);
+ mp_audio_set_channels(&afs->output, &out_channels);
-#if HAVE_GPL
// filter input format: same as codec's output format:
afs->input = in_format;
@@ -432,9 +460,27 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
goto init_error;
}
+ out_rate = afs->output.rate;
+ out_format = afs->output.format;
+ out_channels = afs->output.channels;
+#else
+ if (mpctx->ao && ao_c->filter_input_format &&
+ mp_aframe_config_equals(ao_c->filter_input_format, ao_c->input_format))
+ return;
+
+ TA_FREEP(&ao_c->filter_input_format);
+
+ if (!out_rate)
+ out_rate = mp_aframe_get_rate(ao_c->input_format);
+ if (!out_format)
+ out_format = mp_aframe_get_format(ao_c->input_format);
+ if (!out_channels.num)
+ mp_aframe_get_chmap(ao_c->input_format, &out_channels);
+#endif
+
if (!mpctx->ao) {
int ao_flags = 0;
- bool spdif_fallback = af_fmt_is_spdif(afs->output.format) &&
+ bool spdif_fallback = af_fmt_is_spdif(out_format) &&
ao_c->spdif_passthrough;
if (opts->ao_null_fallback && !spdif_fallback)
@@ -446,30 +492,32 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
if (opts->audio_exclusive)
ao_flags |= AO_INIT_EXCLUSIVE;
- if (af_fmt_is_pcm(afs->output.format)) {
+ if (af_fmt_is_pcm(out_format)) {
if (!opts->audio_output_channels.set ||
opts->audio_output_channels.auto_safe)
ao_flags |= AO_INIT_SAFE_MULTICHANNEL_ONLY;
- mp_chmap_sel_list(&afs->output.channels,
+ mp_chmap_sel_list(&out_channels,
opts->audio_output_channels.chmaps,
opts->audio_output_channels.num_chmaps);
}
- mp_audio_set_channels(&afs->output, &afs->output.channels);
-
mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb,
- mpctx, mpctx->encode_lavc_ctx, afs->output.rate,
- afs->output.format, afs->output.channels);
+ mpctx, mpctx->encode_lavc_ctx, out_rate,
+ out_format, out_channels);
ao_c->ao = mpctx->ao;
- struct mp_audio fmt = {0};
+ int ao_rate = 0;
+ int ao_format = 0;
+ struct mp_chmap ao_channels = {0};
if (mpctx->ao)
- get_ao_format(mpctx->ao, &fmt);
+ ao_get_format(mpctx->ao, &ao_rate, &ao_format, &ao_channels);
// Verify passthrough format was not changed.
- if (mpctx->ao && af_fmt_is_spdif(afs->output.format)) {
- if (!mp_audio_config_equals(&afs->output, &fmt)) {
+ if (mpctx->ao && af_fmt_is_spdif(out_format)) {
+ if (out_rate != ao_rate || out_format != ao_format ||
+ !mp_chmap_equals(&out_channels, &ao_channels))
+ {
MP_ERR(mpctx, "Passthrough format unsupported.\n");
ao_uninit(mpctx->ao);
mpctx->ao = NULL;
@@ -497,17 +545,36 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
goto init_error;
}
- mp_audio_buffer_reinit_fmt(ao_c->ao_buffer, fmt.format, &fmt.channels,
- fmt.rate);
- afs->output = fmt;
+ mp_audio_buffer_reinit_fmt(ao_c->ao_buffer, ao_format, &ao_channels,
+ ao_rate);
+
+#if HAVE_LIBAF
+ afs->output = (struct mp_audio){0};
+ afs->output.rate = ao_rate;
+ mp_audio_set_format(&afs->output, ao_format);
+ mp_audio_set_channels(&afs->output, &ao_channels);
if (!mp_audio_config_equals(&afs->output, &afs->filter_output))
afs->initialized = 0;
+#else
+ int in_rate = mp_aframe_get_rate(ao_c->input_format);
+ int in_format = mp_aframe_get_format(ao_c->input_format);
+ struct mp_chmap in_chmap = {0};
+ mp_aframe_get_chmap(ao_c->input_format, &in_chmap);
+ if (!mp_aconverter_reconfig(ao_c->conv, in_rate, in_format, in_chmap,
+ ao_rate, ao_format, ao_channels))
+ {
+ MP_ERR(mpctx, "Cannot convert audio data for output.\n");
+ goto init_error;
+ }
+ ao_c->filter_input_format = mp_aframe_new_ref(ao_c->input_format);
+#endif
- mpctx->ao_decoder_fmt = mp_aframe_create();
- mp_aframe_config_copy(mpctx->ao_decoder_fmt, ao_c->input_format);
+ mpctx->ao_decoder_fmt = mp_aframe_new_ref(ao_c->input_format);
+ char tmp[80];
MP_INFO(mpctx, "AO: [%s] %s\n", ao_get_name(mpctx->ao),
- mp_audio_config_to_str(&fmt));
+ audio_config_to_str_buf(tmp, sizeof(tmp), ao_rate, ao_format,
+ ao_channels));
MP_VERBOSE(mpctx, "AO: Description: %s\n", ao_get_description(mpctx->ao));
update_window_title(mpctx, true);
@@ -515,6 +582,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
opts->audio_wait_open > 0 ? mp_time_sec() + opts->audio_wait_open : 0;
}
+#if HAVE_LIBAF
if (recreate_audio_filters(mpctx) < 0)
goto init_error;
#endif
@@ -584,9 +652,13 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
struct ao_chain *ao_c = talloc_zero(NULL, struct ao_chain);
mpctx->ao_chain = ao_c;
ao_c->log = mpctx->log;
+#if HAVE_LIBAF
ao_c->af = af_new(mpctx->global);
if (track && track->stream)
ao_c->af->replaygain_data = track->stream->codec->replaygain_data;
+#else
+ ao_c->conv = mp_aconverter_create(mpctx->global, mpctx->log, NULL);
+#endif
ao_c->spdif_passthrough = true;
ao_c->pts = MP_NOPTS_VALUE;
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
@@ -628,16 +700,26 @@ double written_audio_pts(struct MPContext *mpctx)
if (!ao_c)
return MP_NOPTS_VALUE;
- if (ao_c->af->initialized < 1)
- return MP_NOPTS_VALUE;
-
// first calculate the end pts of audio that has been output by decoder
double a_pts = ao_c->pts;
if (a_pts == MP_NOPTS_VALUE)
return MP_NOPTS_VALUE;
// Data buffered in audio filters, measured in seconds of "missing" output
- double buffered_output = af_calc_delay(ao_c->af);
+ double buffered_output = 0;
+
+#if HAVE_LIBAF
+ if (ao_c->af->initialized < 1)
+ return MP_NOPTS_VALUE;
+
+ buffered_output += af_calc_delay(ao_c->af);
+#endif
+
+ if (ao_c->conv)
+ buffered_output += mp_aconverter_get_latency(ao_c->conv);
+
+ if (ao_c->output_frame)
+ buffered_output += mp_aframe_duration(ao_c->output_frame);
// Data that was ready for ao but was buffered because ao didn't fully
// accept everything to internal buffers yet
@@ -720,9 +802,12 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
if (mpctx->audio_status != STATUS_SYNCING)
return true;
- struct mp_audio out_format = {0};
- get_ao_format(mpctx->ao, &out_format);
- double play_samplerate = out_format.rate / mpctx->audio_speed;
+ int ao_rate;
+ int ao_format;
+ struct mp_chmap ao_channels;
+ ao_get_format(mpctx->ao, &ao_rate, &ao_format, &ao_channels);
+
+ double play_samplerate = ao_rate / mpctx->audio_speed;
if (!opts->initial_audio_sync) {
mpctx->audio_status = STATUS_FILLING;
@@ -784,25 +869,27 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
}
mpctx->audio_allow_second_chance_seek = false;
- int align = af_format_sample_alignment(out_format.format);
+ int align = af_format_sample_alignment(ao_format);
*skip = (int)(-ptsdiff * play_samplerate) / align * align;
return true;
}
-static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
+static bool copy_output(struct MPContext *mpctx, struct ao_chain *ao_c,
int minsamples, double endpts, bool eof, bool *seteof)
{
- struct af_stream *afs = mpctx->ao_chain->af;
+ struct mp_audio_buffer *outbuf = ao_c->ao_buffer;
- while (mp_audio_buffer_samples(outbuf) < minsamples) {
- if (af_output_frame(afs, eof) < 0)
- return true; // error, stop doing stuff
+ int ao_rate;
+ int ao_format;
+ struct mp_chmap ao_channels;
+ ao_get_format(ao_c->ao, &ao_rate, &ao_format, &ao_channels);
+ while (mp_audio_buffer_samples(outbuf) < minsamples) {
int cursamples = mp_audio_buffer_samples(outbuf);
int maxsamples = INT_MAX;
if (endpts != MP_NOPTS_VALUE) {
- double rate = afs->output.rate / mpctx->audio_speed;
+ double rate = ao_rate / mpctx->audio_speed;
double curpts = written_audio_pts(mpctx);
if (curpts != MP_NOPTS_VALUE) {
double remaining =
@@ -811,24 +898,43 @@ static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
}
}
- struct mp_audio *mpa = af_read_output_frame(afs);
- if (!mpa)
+ if (!ao_c->output_frame || !mp_aframe_get_size(ao_c->output_frame)) {
+ TA_FREEP(&ao_c->output_frame);
+#if HAVE_LIBAF
+ struct af_stream *afs = mpctx->ao_chain->af;
+ if (af_output_frame(afs, eof) < 0)
+ return true; // error, stop doing stuff
+ struct mp_audio *mpa = af_read_output_frame(afs);
+ ao_c->output_frame = mp_audio_to_aframe(mpa);
+ talloc_free(mpa);
+#else
+ if (eof)
+ mp_aconverter_write_input(ao_c->conv, NULL);
+ mp_aconverter_set_speed(ao_c->conv, mpctx->audio_speed);
+ bool got_eof;
+ ao_c->output_frame = mp_aconverter_read_output(ao_c->conv, &got_eof);
+#endif
+ }
+
+ if (!ao_c->output_frame)
return false; // out of data
- if (cursamples + mpa->samples > maxsamples) {
+ if (cursamples + mp_aframe_get_size(ao_c->output_frame) > maxsamples) {
if (cursamples < maxsamples) {
- struct mp_audio pre = *mpa;
- mp_audio_buffer_append(outbuf, mpa->planes,
+ uint8_t **data = mp_aframe_get_data_ro(ao_c->output_frame);
+ mp_audio_buffer_append(outbuf, (void **)data,
+ maxsamples - cursamples);
+ mp_aframe_skip_samples(ao_c->output_frame,
maxsamples - cursamples);
- mp_audio_skip_samples(mpa, pre.samples);
}
- af_unread_output_frame(afs, mpa);
*seteof = true;
return true;
}
- mp_audio_buffer_append(outbuf, mpa->planes, mpa->samples);
- talloc_free(mpa);
+ uint8_t **data = mp_aframe_get_data_ro(ao_c->output_frame);
+ mp_audio_buffer_append(outbuf, (void **)data,
+ mp_aframe_get_size(ao_c->output_frame));
+ TA_FREEP(&ao_c->output_frame);
}
return true;
}
@@ -869,9 +975,14 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
int minsamples)
{
struct ao_chain *ao_c = mpctx->ao_chain;
+#if HAVE_LIBAF
struct af_stream *afs = ao_c->af;
if (afs->initialized < 1)
return AD_ERR;
+#else
+ if (!ao_c->filter_input_format)
+ return AD_ERR;
+#endif
MP_STATS(ao_c, "start audio");
@@ -882,7 +993,7 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
while (1) {
res = 0;
- if (copy_output(mpctx, outbuf, minsamples, endpts, false, &eof))
+ if (copy_output(mpctx, ao_c, minsamples, endpts, false, &eof))
break;
res = decode_new_frame(ao_c);
@@ -892,41 +1003,58 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
break;
if (res < 0) {
// drain filters first (especially for true EOF case)
- copy_output(mpctx, outbuf, minsamples, endpts, true, &eof);
+ copy_output(mpctx, ao_c, minsamples, endpts, true, &eof);
break;
}
// On format change, make sure to drain the filter chain.
+#if HAVE_LIBAF
struct mp_audio in_format;
mp_audio_config_from_aframe(&in_format, ao_c->input_format);
if (!mp_audio_config_equals(&afs->input, &in_format)) {
- copy_output(mpctx, outbuf, minsamples, endpts, true, &eof);
+ copy_output(mpctx, ao_c, minsamples, endpts, true, &eof);
+ res = AD_NEW_FMT;
+ break;
+ }
+#else
+ if (!mp_aframe_config_equals(ao_c->filter_input_format,
+ ao_c->input_format))
+ {
+ copy_output(mpctx, ao_c, minsamples, endpts, true, &eof);
res = AD_NEW_FMT;
break;
}
+#endif
- struct mp_audio *mpa = mp_audio_from_aframe(ao_c->input_frame);
- talloc_free(ao_c->input_frame);
- ao_c->input_frame = NULL;
- if (!mpa)
- abort();
- if (mpa->pts == MP_NOPTS_VALUE) {
+ double pts = mp_aframe_get_pts(ao_c->input_frame);
+ if (pts == MP_NOPTS_VALUE) {
ao_c->pts = MP_NOPTS_VALUE;
} else {
// Attempt to detect jumps in PTS. Even for the lowest sample rates
// and with worst container rounded timestamp, this should be a
// margin more than enough.
- double desync = mpa->pts - ao_c->pts;
+ double desync = pts - ao_c->pts;
if (ao_c->pts != MP_NOPTS_VALUE && fabs(desync) > 0.1) {
MP_WARN(ao_c, "Invalid audio PTS: %f -> %f\n",
- ao_c->pts, mpa->pts);
+ ao_c->pts, pts);
if (desync >= 5)
ao_c->pts_reset = true;
}
- ao_c->pts = mpa->pts + mpa->samples / (double)mpa->rate;
+ ao_c->pts = mp_aframe_end_pts(ao_c->input_frame);
}
+
+#if HAVE_LIBAF
+ struct mp_audio *mpa = mp_audio_from_aframe(ao_c->input_frame);
+ talloc_free(ao_c->input_frame);
+ ao_c->input_frame = NULL;
+ if (!mpa)
+ abort();
if (af_filter_frame(afs, mpa) < 0)
return AD_ERR;
+#else
+ if (mp_aconverter_write_input(ao_c->conv, ao_c->input_frame))
+ ao_c->input_frame = NULL;
+#endif
}
if (res == 0 && mp_audio_buffer_samples(outbuf) < minsamples && eof)
@@ -957,7 +1085,10 @@ void reload_audio_output(struct MPContext *mpctx)
ao_c->spdif_passthrough = true;
ao_c->spdif_failed = false;
d_audio->try_spdif = true;
+#if HAVE_LIBAF
ao_c->af->initialized = 0;
+#endif
+ TA_FREEP(&ao_c->filter_input_format);
if (!audio_init_best_codec(d_audio)) {
MP_ERR(mpctx, "Error reinitializing audio.\n");
error_on_track(mpctx, ao_c->track);
@@ -982,7 +1113,12 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
if (!ao_c)
return;
- if (ao_c->af->initialized < 1 || !mpctx->ao) {
+ bool is_initialized = !!ao_c->filter_input_format;
+#if HAVE_LIBAF
+ is_initialized = ao_c->af->initialized == 1;
+#endif
+
+ if (!is_initialized || !mpctx->ao) {
// Probe the initial audio format. Returns AD_OK (and does nothing) if
// the format is already known.
int r = AD_NO_PROGRESS;
@@ -1012,10 +1148,12 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
return;
}
- struct mp_audio out_format = {0};
- get_ao_format(mpctx->ao, &out_format);
- double play_samplerate = out_format.rate / mpctx->audio_speed;
- int align = af_format_sample_alignment(out_format.format);
+ int ao_rate;
+ int ao_format;
+ struct mp_chmap ao_channels;
+ ao_get_format(mpctx->ao, &ao_rate, &ao_format, &ao_channels);
+ double play_samplerate = ao_rate / mpctx->audio_speed;
+ int align = af_format_sample_alignment(ao_format);
// If audio is infinitely fast, somehow try keeping approximate A/V sync.
if (mpctx->audio_status == STATUS_PLAYING && ao_untimed(mpctx->ao) &&
diff --git a/player/command.c b/player/command.c
index 1147eab14e..1cf8dc2438 100644
--- a/player/command.c
+++ b/player/command.c
@@ -57,8 +57,8 @@
#include "video/out/vo.h"
#include "video/csputils.h"
#include "audio/aframe.h"
+#include "audio/format.h"
#include "audio/out/ao.h"
-#include "audio/filter/af.h"
#include "video/decode/dec_video.h"
#include "audio/decode/dec_audio.h"
#include "video/out/bitmap_packer.h"
@@ -71,6 +71,10 @@
#include "core.h"
+#if HAVE_LIBAF
+#include "audio/filter/af.h"
+#endif
+
#ifdef _WIN32
#include <windows.h>
#endif
@@ -1455,10 +1459,12 @@ static int mp_property_filter_metadata(void *ctx, struct m_property *prop,
struct vf_chain *vf = mpctx->vo_chain->vf;
res = vf_control_by_label(vf, VFCTRL_GET_METADATA, &metadata, key);
} else if (strcmp(type, "af") == 0) {
+#if HAVE_LIBAF
if (!(mpctx->ao_chain && mpctx->ao_chain->af))
return M_PROPERTY_UNAVAILABLE;
struct af_stream *af = mpctx->ao_chain->af;
res = af_control_by_label(af, AF_CONTROL_GET_METADATA, &metadata, key);
+#endif
}
switch (res) {
case CONTROL_UNKNOWN:
@@ -1785,8 +1791,7 @@ static int mp_property_mixer_active(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
- struct ao_chain *ao_c = mpctx->ao_chain;
- return m_property_flag_ro(action, arg, ao_c && ao_c->af->initialized > 0);
+ return m_property_flag_ro(action, arg, !!mpctx->ao);
}
/// Volume (RW)
@@ -5491,11 +5496,13 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
return vf_send_command(mpctx->vo_chain->vf, cmd->args[0].v.s,
cmd->args[1].v.s, cmd->args[2].v.s);
+#if HAVE_LIBAF
case MP_CMD_AF_COMMAND:
if (!mpctx->ao_chain)
return -1;
return af_send_command(mpctx->ao_chain->af, cmd->args[0].v.s,
cmd->args[1].v.s, cmd->args[2].v.s);
+#endif
case MP_CMD_SCRIPT_BINDING: {
mpv_event_client_message event = {0};
diff --git a/player/core.h b/player/core.h
index 1c1924aee2..c3ceefd17d 100644
--- a/player/core.h
+++ b/player/core.h
@@ -200,6 +200,7 @@ struct ao_chain {
bool pts_reset;
struct af_stream *af;
+ struct mp_aconverter *conv; // if af unavailable
struct ao *ao;
struct mp_audio_buffer *ao_buffer;
double ao_resume_time;
@@ -207,9 +208,14 @@ struct ao_chain {
// 1-element input frame queue.
struct mp_aframe *input_frame;
+ // 1-element output frame queue.
+ struct mp_aframe *output_frame;
+
// Last known input_mpi format (so af can be reinitialized any time).
struct mp_aframe *input_format;
+ struct mp_aframe *filter_input_format;
+
struct track *track;
struct lavfi_pad *filter_src;
struct dec_audio *audio_src;
diff --git a/player/playloop.c b/player/playloop.c
index c908b1a6e2..3dc185dd55 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -39,7 +39,6 @@
#include "osdep/timer.h"
#include "audio/decode/dec_audio.h"
-#include "audio/filter/af.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "stream/stream.h"
diff --git a/player/video.c b/player/video.c
index e1034c46f0..03331c7828 100644
--- a/player/video.c
+++ b/player/video.c
@@ -34,6 +34,7 @@
#include "osdep/timer.h"
#include "audio/out/ao.h"
+#include "audio/format.h"
#include "demux/demux.h"
#include "stream/stream.h"
#include "sub/osd.h"
@@ -42,7 +43,6 @@
#include "video/decode/dec_video.h"
#include "video/decode/vd.h"
#include "video/out/vo.h"
-#include "audio/filter/af.h"
#include "audio/decode/dec_audio.h"
#include "core.h"