1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-02 21:12:23 +00:00

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?)
This commit is contained in:
wm4 2017-09-21 12:48:30 +02:00
parent 3a2d5e68ac
commit fdb300b983
12 changed files with 273 additions and 108 deletions

View File

@ -97,4 +97,6 @@ struct mp_audio *mp_audio_pool_new_copy(struct mp_audio_pool *pool,
int mp_audio_pool_make_writeable(struct mp_audio_pool *pool,
struct mp_audio *frame);
#include "filter/af.h"
#endif

View File

@ -29,6 +29,7 @@
#include "common/msg.h"
#include "common/recorder.h"
#include "misc/bstr.h"
#include "options/options.h"
#include "stream/stream.h"
#include "demux/demux.h"
@ -39,8 +40,6 @@
#include "ad.h"
#include "audio/format.h"
#include "audio/filter/af.h"
extern const struct ad_functions ad_lavc;
// Not a real codec - specially treated.

View File

@ -22,6 +22,11 @@
#include <stdbool.h>
#include <sys/types.h>
#include "config.h"
#if !HAVE_LIBAF
#error "libaf disabled"
#endif
#include "options/options.h"
#include "audio/format.h"
#include "audio/chmap.h"

View File

@ -20,7 +20,7 @@
#include <limits.h>
#include "common/common.h"
#include "audio/filter/af.h"
#include "format.h"
// number of bytes per sample, 0 if invalid/unknown
int af_fmt_to_bytes(int format)

View File

@ -44,12 +44,15 @@
#include "video/hwdec.h"
#include "video/image_writer.h"
#include "sub/osd.h"
#include "audio/filter/af.h"
#include "audio/decode/dec_audio.h"
#include "player/core.h"
#include "player/command.h"
#include "stream/stream.h"
#if HAVE_LIBAF
#include "audio/filter/af.h"
#endif
#if HAVE_DRM
#include "video/out/drm_common.h"
#endif
@ -418,8 +421,10 @@ const m_option_t mp_opts[] = {
// ------------------------- codec/vfilter options --------------------
#if HAVE_LIBAF
OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list, ),
OPT_SETTINGSLIST("af", af_settings, 0, &af_obj_list, ),
#endif
OPT_SETTINGSLIST("vf-defaults", vf_defs, 0, &vf_obj_list, ),
OPT_SETTINGSLIST("vf", vf_settings, 0, &vf_obj_list, ),

View File

@ -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;
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) {
if (af_output_frame(afs, eof) < 0)
return true; // error, stop doing stuff
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,
}
}
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);
if (!mpa)
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) &&

View File

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

View File

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

View File

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

View File

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

View File

@ -389,6 +389,10 @@ iconv support use --disable-iconv.",
'desc': 'libarchive wrapper for reading zip files and more',
'func': check_pkg_config('libarchive >= 3.0.0'),
'default': 'disable',
}, {
'name': '--libaf',
'desc': 'internal audio filter chain',
'func': check_true,
}
]

View File

@ -152,8 +152,8 @@ def build(ctx):
sources = [
## Audio
( "audio/audio.c" ),
( "audio/aconverter.c" ),
( "audio/audio.c", "libaf" ),
( "audio/audio_buffer.c" ),
( "audio/chmap.c" ),
( "audio/chmap_sel.c" ),
@ -163,18 +163,18 @@ def build(ctx):
( "audio/decode/ad_lavc.c" ),
( "audio/decode/ad_spdif.c" ),
( "audio/decode/dec_audio.c" ),
( "audio/filter/af.c" ),
( "audio/filter/af_channels.c" ),
( "audio/filter/af_equalizer.c" ),
( "audio/filter/af_format.c" ),
( "audio/filter/af_lavcac3enc.c" ),
( "audio/filter/af_lavfi.c" ),
( "audio/filter/af_lavrresample.c" ),
( "audio/filter/af_pan.c" ),
( "audio/filter/af_rubberband.c", "rubberband" ),
( "audio/filter/af_scaletempo.c" ),
( "audio/filter/af_volume.c" ),
( "audio/filter/tools.c" ),
( "audio/filter/af.c", "libaf" ),
( "audio/filter/af_channels.c", "libaf" ),
( "audio/filter/af_equalizer.c", "libaf" ),
( "audio/filter/af_format.c", "libaf" ),
( "audio/filter/af_lavcac3enc.c", "libaf" ),
( "audio/filter/af_lavfi.c", "libaf" ),
( "audio/filter/af_lavrresample.c", "libaf" ),
( "audio/filter/af_pan.c", "libaf" ),
( "audio/filter/af_rubberband.c", "rubberband && libaf" ),
( "audio/filter/af_scaletempo.c", "libaf" ),
( "audio/filter/af_volume.c", "libaf" ),
( "audio/filter/tools.c", "libaf" ),
( "audio/out/ao.c" ),
( "audio/out/ao_alsa.c", "alsa" ),
( "audio/out/ao_audiounit.m", "audiounit" ),