From d2e7467eb203d3a34bc1111564c7058b5e9c6b12 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 10 Nov 2013 23:11:40 +0100 Subject: audio/filter: prepare filter chain for non-interleaved audio Based on earlier work by Stefano Pigozzi. There are 2 changes: 1. Instead of mp_audio.audio, mp_audio.planes[0] must be used. 2. mp_audio.len used to contain the size of the audio in bytes. Now mp_audio.samples must be used. (Where 1 sample is the smallest unit of audio that covers all channels.) Also, some filters need changes to reject non-interleaved formats properly. Nothing uses the non-interleaved features yet, but this is needed so that things don't just break when doing so. --- audio/audio.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 137 insertions(+), 11 deletions(-) (limited to 'audio/audio.c') diff --git a/audio/audio.c b/audio/audio.c index 9d41928436..ace455f123 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -17,42 +17,58 @@ #include +#include "mpvcore/mp_common.h" #include "mpvcore/mp_talloc.h" #include "audio.h" +static void update_redundant_info(struct mp_audio *mpa) +{ + assert(mp_chmap_is_empty(&mpa->channels) || + mp_chmap_is_valid(&mpa->channels)); + mpa->nch = mpa->channels.num; + mpa->bps = af_fmt2bits(mpa->format) / 8; + if (af_fmt_is_planar(mpa->format)) { + mpa->spf = 1; + mpa->num_planes = mpa->nch; + mpa->sstride = mpa->bps; + } else { + mpa->spf = mpa->nch; + mpa->num_planes = 1; + mpa->sstride = mpa->bps * mpa->nch; + } +} + void mp_audio_set_format(struct mp_audio *mpa, int format) { mpa->format = format; - mpa->bps = af_fmt2bits(format) / 8; + update_redundant_info(mpa); } void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels) { - struct mp_chmap map; - mp_chmap_from_channels(&map, num_channels); - mp_audio_set_channels(mpa, &map); + mp_chmap_from_channels(&mpa->channels, num_channels); + update_redundant_info(mpa); } // Use old MPlayer/ALSA channel layout. void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels) { - struct mp_chmap map; - mp_chmap_from_channels_alsa(&map, num_channels); - mp_audio_set_channels(mpa, &map); + mp_chmap_from_channels_alsa(&mpa->channels, num_channels); + update_redundant_info(mpa); } void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap) { - assert(mp_chmap_is_empty(chmap) || mp_chmap_is_valid(chmap)); mpa->channels = *chmap; - mpa->nch = mpa->channels.num; + update_redundant_info(mpa); } void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src) { - mp_audio_set_format(dst, src->format); - mp_audio_set_channels(dst, &src->channels); + dst->format = src->format; + dst->channels = src->channels; dst->rate = src->rate; + update_redundant_info(dst); } bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b) @@ -74,3 +90,113 @@ char *mp_audio_config_to_str(struct mp_audio *mpa) { return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format); } + +void mp_audio_force_interleaved_format(struct mp_audio *mpa) +{ + if (af_fmt_is_planar(mpa->format)) + mp_audio_set_format(mpa, af_fmt_from_planar(mpa->format)); +} + +// Return used size of a plane. (The size is the same for all planes.) +int mp_audio_psize(struct mp_audio *mpa) +{ + return mpa->samples * mpa->sstride; +} + +void mp_audio_set_null_data(struct mp_audio *mpa) +{ + for (int n = 0; n < MP_NUM_CHANNELS; n++) + mpa->planes[n] = NULL; + mpa->samples = 0; +} + +/* Reallocate the data stored in mpa->planes[n] so that enough samples are + * available on every plane. The previous data is kept (for the smallest + * common number of samples before/after resize). + * + * mpa->samples is not set or used. + * + * This function is flexible enough to handle format and channel layout + * changes. In these cases, all planes are reallocated as needed. Unused + * planes are freed. + * + * mp_audio_realloc(mpa, 0) will still yield non-NULL for mpa->data[n]. + * + * Allocated data is implicitly freed on talloc_free(mpa). + */ +void mp_audio_realloc(struct mp_audio *mpa, int samples) +{ + assert(samples >= 0); + int size = MPMAX(samples * mpa->sstride, 1); + for (int n = 0; n < mpa->num_planes; n++) { + mpa->planes[n] = talloc_realloc_size(mpa, mpa->planes[n], size); + } + for (int n = mpa->num_planes; n < MP_NUM_CHANNELS; n++) { + talloc_free(mpa->planes[n]); + mpa->planes[n] = NULL; + } +} + +// Like mp_audio_realloc(), but only reallocate if the audio grows in size. +void mp_audio_realloc_min(struct mp_audio *mpa, int samples) +{ + if (samples > mp_audio_get_allocated_size(mpa)) + mp_audio_realloc(mpa, samples); +} + +/* Get the size allocated for the data, in number of samples. If the allocated + * size isn't on sample boundaries (e.g. after format changes), the returned + * sample number is a rounded down value. + * + * Note that this only works in situations where mp_audio_realloc() also works! + */ +int mp_audio_get_allocated_size(struct mp_audio *mpa) +{ + int size = 0; + for (int n = 0; n < mpa->num_planes; n++) { + int s = talloc_get_size(mpa->planes[n]) / mpa->sstride; + size = n == 0 ? s : MPMIN(size, s); + } + return size; +} + +// Clear the samples [start, start + length) with silence. +void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length) +{ + assert(start >= 0 && length >= 0 && start + length <= mpa->samples); + int offset = start * mpa->sstride; + int size = length * mpa->sstride; + for (int n = 0; n < mpa->num_planes; n++) { + if (n > 0 && mpa->planes[n] == mpa->planes[0]) + continue; // silly optimization for special cases + af_fill_silence((char *)mpa->planes[n] + offset, size, mpa->format); + } +} + +// All integer parameters are in samples. +// dst and src can overlap. +void mp_audio_copy(struct mp_audio *dst, int dst_offset, + struct mp_audio *src, int src_offset, int length) +{ + assert(mp_audio_config_equals(dst, src)); + assert(length >= 0); + assert(dst_offset >= 0 && dst_offset + length <= dst->samples); + assert(src_offset >= 0 && src_offset + length <= src->samples); + + for (int n = 0; n < dst->num_planes; n++) { + memmove((char *)dst->planes[n] + dst_offset * dst->sstride, + (char *)src->planes[n] + src_offset * src->sstride, + length * dst->sstride); + } +} + +// Set data to the audio after the given number of samples (i.e. slice it). +void mp_audio_skip_samples(struct mp_audio *data, int samples) +{ + assert(samples >= 0 && samples <= data->samples); + + for (int n = 0; n < data->num_planes; n++) + data->planes[n] = (uint8_t *)data->planes[n] + samples * data->sstride; + + data->samples -= samples; +} -- cgit v1.2.3