From bbb46f3ec7128d8a624f2aa5b4f99ec44c0b9567 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sat, 12 Nov 2011 15:43:43 -0500 Subject: libavutil: add utility functions to simplify allocation of audio buffers. Based on code by Stefano Sabatini. --- libavutil/avutil.h | 2 +- libavutil/samplefmt.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/samplefmt.h | 53 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) (limited to 'libavutil') diff --git a/libavutil/avutil.h b/libavutil/avutil.h index 0c256ca765..a93a0799a7 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -153,7 +153,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 51 -#define LIBAVUTIL_VERSION_MINOR 17 +#define LIBAVUTIL_VERSION_MINOR 18 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ diff --git a/libavutil/samplefmt.c b/libavutil/samplefmt.c index 6fc3b7e467..f38d05e426 100644 --- a/libavutil/samplefmt.c +++ b/libavutil/samplefmt.c @@ -92,3 +92,68 @@ int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) return 0; return sample_fmt_info[sample_fmt].planar; } + +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int line_size; + int sample_size = av_get_bytes_per_sample(sample_fmt); + int planar = av_sample_fmt_is_planar(sample_fmt); + + /* validate parameter ranges */ + if (!sample_size || nb_samples <= 0 || nb_channels <= 0) + return AVERROR(EINVAL); + + /* check for integer overflow */ + if (nb_channels > INT_MAX / align || + (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) + return AVERROR(EINVAL); + + line_size = planar ? FFALIGN(nb_samples * sample_size, align) : + FFALIGN(nb_samples * sample_size * nb_channels, align); + if (linesize) + *linesize = line_size; + + return planar ? line_size * nb_channels : line_size; +} + +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + uint8_t *buf, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int ch, planar, buf_size; + + planar = av_sample_fmt_is_planar(sample_fmt); + buf_size = av_samples_get_buffer_size(linesize, nb_channels, nb_samples, + sample_fmt, align); + if (buf_size < 0) + return buf_size; + + audio_data[0] = buf; + for (ch = 1; planar && ch < nb_channels; ch++) + audio_data[ch] = audio_data[ch-1] + *linesize; + + return 0; +} + +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align) +{ + uint8_t *buf; + int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, + sample_fmt, align); + if (size < 0) + return size; + + buf = av_mallocz(size); + if (!buf) + return AVERROR(ENOMEM); + + size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, + nb_samples, sample_fmt, align); + if (size < 0) { + av_free(buf); + return size; + } + return 0; +} diff --git a/libavutil/samplefmt.h b/libavutil/samplefmt.h index ce7ffc737b..b6715561d4 100644 --- a/libavutil/samplefmt.h +++ b/libavutil/samplefmt.h @@ -92,4 +92,57 @@ int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); */ int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Fill channel data pointers and linesize for samples with sample + * format sample_fmt. + * + * The pointers array is filled with the pointers to the samples data: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The linesize array is filled with the aligned size of each channel's data + * buffer for planar layout, or the aligned size of the buffer for all channels + * for packed layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (1 = no alignment required) + * @return 0 on success or a negative error code on failure + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s) + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (1 = no alignment required) + * @return 0 on success or a negative error code on failure + * @see av_samples_fill_arrays() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + #endif /* AVUTIL_SAMPLEFMT_H */ -- cgit v1.2.3