diff options
author | wm4 <wm4@nowhere> | 2017-09-21 12:48:30 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2017-09-21 12:48:30 +0200 |
commit | fdb300b983744c522f335ccf64e9788b78f86701 (patch) | |
tree | abd10d97e8c6cb30e1621db8b67d709cbfaeb705 | |
parent | 3a2d5e68acb2ac0f8b09b896907a692b1c48c6b3 (diff) |
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?)
-rw-r--r-- | audio/audio.h | 2 | ||||
-rw-r--r-- | audio/decode/dec_audio.c | 3 | ||||
-rw-r--r-- | audio/filter/af.h | 5 | ||||
-rw-r--r-- | audio/format.c | 2 | ||||
-rw-r--r-- | options/options.c | 7 | ||||
-rw-r--r-- | player/audio.c | 310 | ||||
-rw-r--r-- | player/command.c | 13 | ||||
-rw-r--r-- | player/core.h | 6 | ||||
-rw-r--r-- | player/playloop.c | 1 | ||||
-rw-r--r-- | player/video.c | 2 | ||||
-rw-r--r-- | wscript | 4 | ||||
-rw-r--r-- | wscript_build.py | 26 |
12 files changed, 273 insertions, 108 deletions
diff --git a/audio/audio.h b/audio/audio.h index a4d9134a20..f370067b78 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -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 diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index 401e26fb7b..387a479a8c 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -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. diff --git a/audio/filter/af.h b/audio/filter/af.h index bbf7b53bad..4bd8f55b96 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -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" diff --git a/audio/format.c b/audio/format.c index 9a0ebbee42..3df11ba301 100644 --- a/audio/format.c +++ b/audio/format.c @@ -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) diff --git a/options/options.c b/options/options.c index 9c435edb15..7dc3b0b160 100644 --- a/options/options.c +++ b/options/options.c @@ -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, ), 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" @@ -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, } ] diff --git a/wscript_build.py b/wscript_build.py index 0726bd5c9d..d9b56074ef 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -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" ), |