diff options
author | Martin Herkt <lachs0r@srsfckn.biz> | 2016-08-15 15:19:29 +0200 |
---|---|---|
committer | Martin Herkt <lachs0r@srsfckn.biz> | 2016-08-15 15:19:29 +0200 |
commit | fd1bc95b4865ff789780c2213eefbdf77f0d4d1f (patch) | |
tree | 639e098e46cf1b77ecea7df95d7b968c25e1d0c9 /audio | |
parent | 1e00bcc14c9b0d9beb8e152f958fc0db4bc6d31b (diff) | |
parent | d7a7e9a8c861c4a9881fcef5cf69c746742b8b88 (diff) | |
download | mpv-fd1bc95b4865ff789780c2213eefbdf77f0d4d1f.tar.bz2 mpv-fd1bc95b4865ff789780c2213eefbdf77f0d4d1f.tar.xz |
Merge branch 'master' into release/current
Diffstat (limited to 'audio')
-rw-r--r-- | audio/audio.c | 45 | ||||
-rw-r--r-- | audio/audio.h | 1 | ||||
-rw-r--r-- | audio/chmap.c | 38 | ||||
-rw-r--r-- | audio/chmap.h | 3 | ||||
-rw-r--r-- | audio/chmap_sel.c | 13 | ||||
-rw-r--r-- | audio/chmap_sel.h | 2 | ||||
-rw-r--r-- | audio/decode/ad_lavc.c | 4 | ||||
-rw-r--r-- | audio/filter/af.c | 260 | ||||
-rw-r--r-- | audio/filter/af.h | 5 | ||||
-rw-r--r-- | audio/filter/af_delay.c | 194 | ||||
-rw-r--r-- | audio/filter/af_format.c | 16 | ||||
-rw-r--r-- | audio/filter/af_lavcac3enc.c | 46 | ||||
-rw-r--r-- | audio/filter/af_lavrresample.c | 21 | ||||
-rw-r--r-- | audio/filter/af_volume.c | 20 | ||||
-rw-r--r-- | audio/mixer.c | 152 | ||||
-rw-r--r-- | audio/mixer.h | 43 | ||||
-rw-r--r-- | audio/out/ao.c | 36 | ||||
-rw-r--r-- | audio/out/ao.h | 12 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 77 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_exclusive.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_properties.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 2 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 2 | ||||
-rw-r--r-- | audio/out/ao_null.c | 16 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 5 | ||||
-rw-r--r-- | audio/out/ao_wasapi_utils.c | 2 | ||||
-rw-r--r-- | audio/out/internal.h | 4 | ||||
-rw-r--r-- | audio/out/pull.c | 8 | ||||
-rw-r--r-- | audio/out/push.c | 6 |
30 files changed, 362 insertions, 677 deletions
diff --git a/audio/audio.c b/audio/audio.c index 306401b5a4..502bbf2134 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -138,6 +138,9 @@ static void mp_audio_destructor(void *ptr) * available on every plane. The previous data is kept (for the smallest * common number of samples before/after resize). * + * This also makes sure the resulting buffer is writable (even in the case + * the buffer has the correct size). + * * mpa->samples is not set or used. * * This function is flexible enough to handle format and channel layout @@ -153,6 +156,12 @@ void mp_audio_realloc(struct mp_audio *mpa, int samples) int size = get_plane_size(mpa, samples); if (size < 0) abort(); // oom or invalid parameters + if (!mp_audio_is_writeable(mpa)) { + for (int n = 0; n < MP_NUM_CHANNELS; n++) { + av_buffer_unref(&mpa->allocated[n]); + mpa->planes[n] = NULL; + } + } for (int n = 0; n < mpa->num_planes; n++) { if (!mpa->allocated[n] || size != mpa->allocated[n]->size) { if (av_buffer_realloc(&mpa->allocated[n], size) < 0) @@ -171,7 +180,7 @@ void mp_audio_realloc(struct mp_audio *mpa, int samples) // If the buffer is reallocated, also preallocate. void mp_audio_realloc_min(struct mp_audio *mpa, int samples) { - if (samples > mp_audio_get_allocated_size(mpa)) { + if (samples > mp_audio_get_allocated_size(mpa) || !mp_audio_is_writeable(mpa)) { size_t alloc = ta_calc_prealloc_elems(samples); if (alloc > INT_MAX) abort(); // oom @@ -347,9 +356,9 @@ struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe) mp_chmap_from_lavc(&lavc_chmap, avframe->channel_layout); #if LIBAVUTIL_VERSION_MICRO >= 100 - // FFmpeg being special again - if (lavc_chmap.num != avframe->channels) - mp_chmap_from_channels(&lavc_chmap, avframe->channels); + // FFmpeg being stupid POS again + if (lavc_chmap.num != av_frame_get_channels(avframe)) + mp_chmap_from_channels(&lavc_chmap, av_frame_get_channels(avframe)); #endif new->rate = avframe->sample_rate; @@ -394,12 +403,9 @@ fail: return NULL; } -// Returns NULL on failure. The input is always unreffed. -struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame) +int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe) { - struct AVFrame *avframe = av_frame_alloc(); - if (!avframe) - goto fail; + av_frame_unref(avframe); avframe->nb_samples = frame->samples; avframe->format = af_to_avformat(frame->format); @@ -410,8 +416,8 @@ struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame) if (!avframe->channel_layout) goto fail; #if LIBAVUTIL_VERSION_MICRO >= 100 - // FFmpeg being a stupid POS (but I respect it) - avframe->channels = frame->channels.num; + // FFmpeg being a stupid POS again + av_frame_set_channels(avframe, frame->channels.num); #endif avframe->sample_rate = frame->rate; @@ -457,6 +463,23 @@ struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame) avframe = tmp; } + return 0; + +fail: + av_frame_unref(avframe); + return -1; +} + +// Returns NULL on failure. The input is always unreffed. +struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame) +{ + struct AVFrame *avframe = av_frame_alloc(); + if (!avframe) + goto fail; + + if (mp_audio_to_avframe(frame, avframe) < 0) + goto fail; + talloc_free(frame); return avframe; diff --git a/audio/audio.h b/audio/audio.h index e126e93b66..0f32f080b9 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -81,6 +81,7 @@ int mp_audio_make_writeable(struct mp_audio *data); struct AVFrame; struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe); struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame); +int mp_audio_to_avframe(struct mp_audio *frame, struct AVFrame *avframe); struct mp_audio_pool; struct mp_audio_pool *mp_audio_pool_create(void *ta_parent); diff --git a/audio/chmap.c b/audio/chmap.c index 1d4970da6c..bbd3a17404 100644 --- a/audio/chmap.c +++ b/audio/chmap.c @@ -230,44 +230,6 @@ void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels) } } -// Return channel index of the given speaker, or -1. -static int mp_chmap_find_speaker(const struct mp_chmap *map, int speaker) -{ - for (int n = 0; n < map->num; n++) { - if (map->speaker[n] == speaker) - return n; - } - return -1; -} - -static void mp_chmap_remove_speaker(struct mp_chmap *map, int speaker) -{ - int index = mp_chmap_find_speaker(map, speaker); - if (index >= 0) { - for (int n = index; n < map->num - 1; n++) - map->speaker[n] = map->speaker[n + 1]; - map->num--; - } -} - -// Some decoders output additional, redundant channels, which are usually -// useless and will mess up proper audio output channel handling. -// map: channel map from which the channels should be removed -// requested: if not NULL, and if it contains any of the "useless" channels, -// don't remove them (this is for convenience) -void mp_chmap_remove_useless_channels(struct mp_chmap *map, - const struct mp_chmap *requested) -{ - if (requested && - mp_chmap_find_speaker(requested, MP_SPEAKER_ID_DL) >= 0) - return; - - if (map->num > 2) { - mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DL); - mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DR); - } -} - // Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>. // Speakers not representable by ffmpeg/libav are dropped. // Warning: this ignores the order of the channels, and will return a channel diff --git a/audio/chmap.h b/audio/chmap.h index aa9b1c5a10..dff69336d6 100644 --- a/audio/chmap.h +++ b/audio/chmap.h @@ -109,9 +109,6 @@ void mp_chmap_fill_na(struct mp_chmap *map, int num); void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels); void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels); -void mp_chmap_remove_useless_channels(struct mp_chmap *map, - const struct mp_chmap *requested); - uint64_t mp_chmap_to_lavc(const struct mp_chmap *src); uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src); void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src); diff --git a/audio/chmap_sel.c b/audio/chmap_sel.c index 45b696c924..4fb7544f20 100644 --- a/audio/chmap_sel.c +++ b/audio/chmap_sel.c @@ -374,3 +374,16 @@ void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev) if (s->allow_any) mp_msg(log, lev, " - anything\n"); } + +// Select a channel map from the given list that fits best to c. Don't change +// *c if there's no match, or the list is empty. +void mp_chmap_sel_list(struct mp_chmap *c, struct mp_chmap *maps, int num_maps) +{ + // This is a separate function to keep messing with mp_chmap_sel internals + // within this source file. + struct mp_chmap_sel sel = { + .chmaps = maps, + .num_chmaps = num_maps, + }; + mp_chmap_sel_fallback(&sel, c); +} diff --git a/audio/chmap_sel.h b/audio/chmap_sel.h index 5bd8783b83..4b11557a2b 100644 --- a/audio/chmap_sel.h +++ b/audio/chmap_sel.h @@ -47,4 +47,6 @@ bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map, struct mp_log; void mp_chmal_sel_log(const struct mp_chmap_sel *s, struct mp_log *log, int lev); +void mp_chmap_sel_list(struct mp_chmap *c, struct mp_chmap *maps, int num_maps); + #endif diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 0316f6b7d1..c785c62c90 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -104,9 +104,9 @@ static int init(struct dec_audio *da, const char *decoder) lavc_context->codec_type = AVMEDIA_TYPE_AUDIO; lavc_context->codec_id = lavc_codec->id; - if (opts->downmix) { + if (opts->downmix && mpopts->audio_output_channels.num_chmaps == 1) { lavc_context->request_channel_layout = - mp_chmap_to_lavc(&mpopts->audio_output_channels); + mp_chmap_to_lavc(&mpopts->audio_output_channels.chmaps[0]); } // Always try to set - option only exists for AC3 at the moment diff --git a/audio/filter/af.c b/audio/filter/af.c index 21b0982692..a132965295 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -31,7 +31,6 @@ #include "af.h" // Static list of filters -extern const struct af_info af_info_delay; extern const struct af_info af_info_channels; extern const struct af_info af_info_format; extern const struct af_info af_info_volume; @@ -46,7 +45,6 @@ extern const struct af_info af_info_lavfi; extern const struct af_info af_info_rubberband; static const struct af_info *const filter_list[] = { - &af_info_delay, &af_info_channels, &af_info_format, &af_info_volume, @@ -256,6 +254,8 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at, mp_snprintf_cat(b, sizeof(b), "\"%s\" ", af->label); if (af->data) mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data)); + if (af->auto_inserted) + mp_snprintf_cat(b, sizeof(b), " [a]"); if (af == at) mp_snprintf_cat(b, sizeof(b), " <-"); MP_MSG(s, msg_level, "%s\n", b); @@ -266,164 +266,156 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at, MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output)); } -// in is what af can take as input - insert a conversion filter if the actual -// input format doesn't match what af expects. -// Returns: -// AF_OK: must call af_reinit() or equivalent, format matches (or is closer) -// AF_FALSE: nothing was changed, format matches -// else: error -static int af_fix_format_conversion(struct af_stream *s, - struct af_instance **p_af, - struct mp_audio in) +static void reset_formats(struct af_stream *s) { - int rv; - struct af_instance *af = *p_af; - struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (actual.format == in.format) - return AF_FALSE; - int dstfmt = in.format; - char *filter = "lavrresample"; - if (!af_lavrresample_test_conversion(actual.format, dstfmt)) - return AF_ERROR; - if (strcmp(filter, prev->info->name) == 0) { - if (prev->control(prev, AF_CONTROL_SET_FORMAT, &dstfmt) == AF_OK) { - *p_af = prev; - return AF_OK; - } - return AF_ERROR; - } - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) - return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_FORMAT, &dstfmt))) { - af_remove(s, new); - return rv; + struct mp_audio none = {0}; + for (struct af_instance *af = s->first; af; af = af->next) { + if (af != s->first && af != s->last) + mp_audio_copy_config(af->data, &none); } - *p_af = new; - return AF_OK; } -// same as af_fix_format_conversion - only wrt. channels -static int af_fix_channels(struct af_stream *s, struct af_instance **p_af, - struct mp_audio in) +static int filter_reinit(struct af_instance *af) { - int rv; - struct af_instance *af = *p_af; struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (mp_chmap_equals(&actual.channels, &in.channels)) - return AF_FALSE; - if (prev->control(prev, AF_CONTROL_SET_CHANNELS, &in.channels) == AF_OK) { - *p_af = prev; - return AF_OK; - } - char *filter = "lavrresample"; - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) + assert(prev); + + // Check if this is the first filter + struct mp_audio in = *prev->data; + // Reset just in case... + mp_audio_set_null_data(&in); + + if (!mp_audio_config_valid(&in)) return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_CHANNELS, &in.channels))) - return rv; - *p_af = new; - return AF_OK; + + af->fmt_in = in; + int rv = af->control(af, AF_CONTROL_REINIT, &in); + if (rv == AF_OK && !mp_audio_config_equals(&in, prev->data)) + rv = AF_FALSE; // conversion filter needed + if (rv == AF_FALSE) + af->fmt_in = in; + + if (rv == AF_OK) { + if (!mp_audio_config_valid(af->data)) + return AF_ERROR; + af->fmt_out = *af->data; + } + + return rv; } -static int af_fix_rate(struct af_stream *s, struct af_instance **p_af, - struct mp_audio in) +static int filter_reinit_with_conversion(struct af_stream *s, struct af_instance *af) { - int rv; - struct af_instance *af = *p_af; - struct af_instance *prev = af->prev; - struct mp_audio actual = *prev->data; - if (actual.rate == in.rate) - return AF_FALSE; - if (prev->control(prev, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate) == AF_OK) { - *p_af = prev; - return AF_OK; + int rv = filter_reinit(af); + + // Conversion filter is needed + if (rv == AF_FALSE) { + // First try if we can change the output format of the previous + // filter to the input format the current filter is expecting. + struct mp_audio in = af->fmt_in; + if (af->prev != s->first && !mp_audio_config_equals(af->prev->data, &in)) { + // This should have been successful (because it succeeded + // before), even if just reverting to the old output format. + mp_audio_copy_config(af->prev->data, &in); + rv = filter_reinit(af->prev); + if (rv != AF_OK) + return rv; + } + if (!mp_audio_config_equals(af->prev->data, &in)) { + // Retry with conversion filter added. + struct af_instance *new = + af_prepend(s, af, "lavrresample", NULL); + if (!new) + return AF_ERROR; + new->auto_inserted = true; + mp_audio_copy_config(new->data, &in); + rv = filter_reinit(new); + if (rv != AF_OK) + af_remove(s, new); + } + if (rv == AF_OK) + rv = filter_reinit(af); } - char *filter = "lavrresample"; - struct af_instance *new = af_prepend(s, af, filter, NULL); - if (new == NULL) - return AF_ERROR; - new->auto_inserted = true; - if (AF_OK != (rv = new->control(new, AF_CONTROL_SET_RESAMPLE_RATE, &in.rate))) - return rv; - *p_af = new; - return AF_OK; + + return rv; } -static void reset_formats(struct af_stream *s) +static int af_find_output_conversion(struct af_stream *s, struct mp_audio *cfg) { - for (struct af_instance *af = s->first; af; af = af->next) { - af->control(af, AF_CONTROL_SET_RESAMPLE_RATE, &(int){0}); - af->control(af, AF_CONTROL_SET_CHANNELS, &(struct mp_chmap){0}); - af->control(af, AF_CONTROL_SET_FORMAT, &(int){0}); + assert(mp_audio_config_valid(&s->output)); + assert(s->initialized > 0); + + if (mp_chmap_equals_reordered(&s->input.channels, &s->output.channels)) + return AF_ERROR; + + // Heuristic to detect point of conversion. If it looks like something + // more complicated is going on, better bail out. + // We expect that the last filter converts channels. + struct af_instance *conv = s->last->prev; + if (!conv->auto_inserted) + return AF_ERROR; + if (!(mp_chmap_equals_reordered(&conv->fmt_in.channels, &s->input.channels) && + mp_chmap_equals_reordered(&conv->fmt_out.channels, &s->output.channels))) + return AF_ERROR; + // Also, should be the only one which does auto conversion. + for (struct af_instance *af = s->first->next; af != s->last; af = af->next) + { + if (af != conv && af->auto_inserted && + !mp_chmap_equals_reordered(&af->fmt_in.channels, &af->fmt_out.channels)) + return AF_ERROR; } + // And not if it's the only filter. + if (conv->prev == s->first && conv->next == s->last) + return AF_ERROR; + + *cfg = s->output; + return AF_OK; } // Return AF_OK on success or AF_ERROR on failure. -// Warning: -// A failed af_reinit() leaves the audio chain behind in a useless, broken -// state (for example, format filters that were tentatively inserted stay -// inserted). -// In that case, you should always rebuild the filter chain, or abort. -static int af_reinit(struct af_stream *s) -{ +static int af_do_reinit(struct af_stream *s, bool second_pass) +{ + struct mp_audio convert_early = {0}; + if (second_pass) { + // If a channel conversion happens, and it is done by an auto-inserted + // filter, then insert a filter to convert it early. Otherwise, do + // nothing and return immediately. + if (af_find_output_conversion(s, &convert_early) != AF_OK) + return AF_OK; + } + remove_auto_inserted_filters(s); af_chain_forget_frames(s); reset_formats(s); s->first->fmt_in = s->first->fmt_out = s->input; + + if (mp_audio_config_valid(&convert_early)) { + struct af_instance *new = af_prepend(s, s->first, "lavrresample", NULL); + if (!new) + return AF_ERROR; + new->auto_inserted = true; + mp_audio_copy_config(new->data, &convert_early); + int rv = filter_reinit(new); + if (rv != AF_DETACH && rv != AF_OK) + return AF_ERROR; + MP_VERBOSE(s, "Moving up output conversion.\n"); + } + // Start with the second filter, as the first filter is the special input // filter which needs no initialization. struct af_instance *af = s->first->next; - // Up to 4 retries per filter (channel, rate, format conversions) - int max_retry = 4; - int retry = 0; while (af) { - if (retry >= max_retry) - goto negotiate_error; - - // Check if this is the first filter - struct mp_audio in = *af->prev->data; - // Reset just in case... - mp_audio_set_null_data(&in); - - if (!mp_audio_config_valid(&in)) - goto error; + int rv = filter_reinit_with_conversion(s, af); - af->fmt_in = in; - int rv = af->control(af, AF_CONTROL_REINIT, &in); - if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data)) - rv = AF_FALSE; // conversion filter needed switch (rv) { case AF_OK: - if (!mp_audio_config_valid(af->data)) - goto error; - af->fmt_out = *af->data; af = af->next; break; - case AF_FALSE: { // Configuration filter is needed - if (af_fix_channels(s, &af, in) == AF_OK) { - retry++; - continue; - } - if (af_fix_rate(s, &af, in) == AF_OK) { - retry++; - continue; - } - // Do this last, to prevent "format->lavrresample" being added to - // the filter chain when output formats not supported by - // af_lavrresample are in use. - if (af_fix_format_conversion(s, &af, in) == AF_OK) { - retry++; - continue; - } + case AF_FALSE: { // If the format conversion is (probably) caused by spdif, then // (as a feature) drop the filter, instead of failing hard. int fmt_in1 = af->prev->data->format; - int fmt_in2 = in.format; + int fmt_in2 = af->fmt_in.format; if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) { bool spd1 = af_fmt_is_spdif(fmt_in1); bool spd2 = af_fmt_is_spdif(fmt_in2); @@ -434,7 +426,6 @@ static int af_reinit(struct af_stream *s) struct af_instance *aft = af->prev; af_remove(s, af); af = aft->next; - retry++; continue; } } @@ -452,8 +443,6 @@ static int af_reinit(struct af_stream *s) af->info->name, rv); goto error; } - if (af && !af->auto_inserted) - retry = 0; } /* Set previously unset fields in s->output to those of the filter chain @@ -477,6 +466,19 @@ error: return AF_ERROR; } +static int af_reinit(struct af_stream *s) +{ + int r = af_do_reinit(s, false); + if (r == AF_OK && mp_audio_config_valid(&s->output)) { + r = af_do_reinit(s, true); + if (r != AF_OK) { + MP_ERR(s, "Failed second pass filter negotiation.\n"); + r = af_do_reinit(s, false); + } + } + return r; +} + // Uninit and remove all filters void af_uninit(struct af_stream *s) { diff --git a/audio/filter/af.h b/audio/filter/af.h index 9c49081f66..697024b781 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -112,9 +112,6 @@ struct af_stream { enum af_control { AF_CONTROL_REINIT = 1, AF_CONTROL_RESET, - AF_CONTROL_SET_RESAMPLE_RATE, - AF_CONTROL_SET_FORMAT, - AF_CONTROL_SET_CHANNELS, AF_CONTROL_SET_VOLUME, AF_CONTROL_GET_VOLUME, AF_CONTROL_SET_PAN_LEVEL, @@ -160,6 +157,4 @@ int af_test_output(struct af_instance *af, struct mp_audio *out); int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma); float af_softclip(float a); -bool af_lavrresample_test_conversion(int src_format, int dst_format); - #endif /* MPLAYER_AF_H */ diff --git a/audio/filter/af_delay.c b/audio/filter/af_delay.c deleted file mode 100644 index 8d1cca8a72..0000000000 --- a/audio/filter/af_delay.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This audio filter delays the output signal for the different - * channels and can be used for simple position panning. - * An extension for this filter would be a reverb. - * - * Original author: Anders - * - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> - -#include "common/common.h" -#include "af.h" - -#define L 65536 - -#define UPDATEQI(qi) qi=(qi+1)&(L-1) - -// Data for specific instances of this filter -typedef struct af_delay_s -{ - void* q[AF_NCH]; // Circular queues used for delaying audio signal - int wi[AF_NCH]; // Write index - int ri; // Read index - float d[AF_NCH]; // Delay [ms] - char *delaystr; -}af_delay_t; - -// Initialization and runtime control -static int control(struct af_instance* af, int cmd, void* arg) -{ - af_delay_t* s = af->priv; - switch(cmd){ - case AF_CONTROL_REINIT:{ - int i; - struct mp_audio *in = arg; - - if (in->bps != 1 && in->bps != 2 && in->bps != 4) { - MP_FATAL(af, "Sample format not supported\n"); - return AF_ERROR; - } - - // Free prevous delay queues - for(i=0;i<af->data->nch;i++) - free(s->q[i]); - - mp_audio_force_interleaved_format(in); - mp_audio_copy_config(af->data, in); - - // Allocate new delay queues - for(i=0;i<af->data->nch;i++){ - s->q[i] = calloc(L,af->data->bps); - if(NULL == s->q[i]) - MP_FATAL(af, "Out of memory\n"); - } - - if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0)) - return AF_ERROR; - s->ri = 0; - for(i=0;i<AF_NCH;i++){ - MP_DBG(af, "Channel %i delayed by %0.3fms\n", - i,MPCLAMP(s->d[i],0.0,1000.0)); - MP_TRACE(af, "Channel %i delayed by %i samples\n", - i,s->wi[i]); - } - return AF_OK; - } - } - return AF_UNKNOWN; -} - -// Deallocate memory -static void uninit(struct af_instance* af) -{ - int i; - - for(i=0;i<AF_NCH;i++) - free(((af_delay_t*)(af->priv))->q[i]); -} - -static int filter_frame(struct af_instance *af, struct mp_audio *c) -{ - if (!c) - return 0; - af_delay_t* s = af->priv; // Setup for this instance - int nch = c->nch; // Number of channels - int len = mp_audio_psize(c)/c->bps; // Number of sample in data chunk - int ri = 0; - int ch,i; - if (af_make_writeable(af, c) < 0) { - talloc_free(c); - return -1; - } - for(ch=0;ch<nch;ch++){ - switch(c->bps){ - case 1:{ - int8_t* a = c->planes[0]; - int8_t* q = s->q[ch]; - int wi = s->wi[ch]; - ri = s->ri; - for(i=ch;i<len;i+=nch){ - q[wi] = a[i]; - a[i] = q[ri]; - UPDATEQI(wi); - UPDATEQI(ri); - } - s->wi[ch] = wi; - break; - } - case 2:{ - int16_t* a = c->planes[0]; - int16_t* q = s->q[ch]; - int wi = s->wi[ch]; - ri = s->ri; - for(i=ch;i<len;i+=nch){ - q[wi] = a[i]; - a[i] = q[ri]; - UPDATEQI(wi); - UPDATEQI(ri); - } - s->wi[ch] = wi; - break; - } - case 4:{ - int32_t* a = c->planes[0]; - int32_t* q = s->q[ch]; - int wi = s->wi[ch]; - ri = s->ri; - for(i=ch;i<len;i+=nch){ - q[wi] = a[i]; - a[i] = q[ri]; - UPDATEQI(wi); - UPDATEQI(ri); - } |