From cc17b43d8dd324fbae98407124618e746a390a76 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 3 Jun 2015 01:22:25 +0200 Subject: [PATCH] swresample: Add swr_get_out_samples() Previous version reviewed-by: Pavel Koshevoy Previous version reviewed-by: wm4 Signed-off-by: Michael Niedermayer --- doc/APIchanges | 3 +++ libswresample/resample.c | 20 +++++++++++++++++++ libswresample/swresample.c | 30 +++++++++++++++++++++++++++++ libswresample/swresample.h | 25 +++++++++++++++++++++--- libswresample/swresample_internal.h | 2 ++ libswresample/version.h | 2 +- 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index e151999286..5c36dca285 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,9 @@ libavutil: 2014-08-09 API changes, most recent first: +2015-06-04 - xxxxxxx - lswr 1.2.100 + Add swr_get_out_samples() + 2015-05-27 - xxxxxxx - lavu 54.26.100 - cpu.h Add AV_CPU_FLAG_AVXSLOW. diff --git a/libswresample/resample.c b/libswresample/resample.c index d4c7d06794..f2624b5dc7 100644 --- a/libswresample/resample.c +++ b/libswresample/resample.c @@ -345,6 +345,25 @@ static int64_t get_delay(struct SwrContext *s, int64_t base){ return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr << c->phase_shift); } +static int64_t get_out_samples(struct SwrContext *s, int in_samples) { + ResampleContext *c = s->resample; + // The + 2 are added to allow implementations to be slightly inaccuarte, they should not be needed currently + // They also make it easier to proof that changes and optimizations do not + // break the upper bound + int64_t num = s->in_buffer_count + 2LL + in_samples; + num *= 1 << c->phase_shift; + num -= c->index; + num = av_rescale_rnd(num, s->out_sample_rate, ((int64_t)s->in_sample_rate) << c->phase_shift, AV_ROUND_UP) + 2; + + if (c->compensation_distance) { + if (num > INT_MAX) + return AVERROR(EINVAL); + + num = FFMAX(num, (num * c->ideal_dst_incr - 1) / c->dst_incr + 1); + } + return num; +} + static int resample_flush(struct SwrContext *s) { AudioData *a= &s->in_buffer; int i, j, ret; @@ -414,4 +433,5 @@ struct Resampler const swri_resampler={ set_compensation, get_delay, invert_initial_buffer, + get_out_samples, }; diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 87ad7f8d78..4aa081be1b 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -673,11 +673,15 @@ int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_C const uint8_t *in_arg [SWR_CH_MAX], int in_count){ AudioData * in= &s->in; AudioData *out= &s->out; + int av_unused max_output; if (!swr_is_initialized(s)) { av_log(s, AV_LOG_ERROR, "Context has not been initialized\n"); return AVERROR(EINVAL); } +#if ASSERT_LEVEL >1 + max_output = swr_get_out_samples(s, in_count); +#endif while(s->drop_output > 0){ int ret; @@ -720,6 +724,9 @@ int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_C int ret = swr_convert_internal(s, out, out_count, in, in_count); if(ret>0 && !s->drop_output) s->outpts += ret * (int64_t)s->in_sample_rate; + + av_assert2(max_output < 0 || ret < 0 || ret <= max_output); + return ret; }else{ AudioData tmp= *in; @@ -771,6 +778,7 @@ int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_C } if(ret2>0 && !s->drop_output) s->outpts += ret2 * (int64_t)s->in_sample_rate; + av_assert2(max_output < 0 || ret2 < 0 || ret2 <= max_output); return ret2; } } @@ -822,6 +830,28 @@ int64_t swr_get_delay(struct SwrContext *s, int64_t base){ } } +int swr_get_out_samples(struct SwrContext *s, int in_samples) +{ + int64_t out_samples; + + if (in_samples < 0) + return AVERROR(EINVAL); + + if (s->resampler && s->resample) { + if (!s->resampler->get_out_samples) + return AVERROR(ENOSYS); + out_samples = s->resampler->get_out_samples(s, in_samples); + } else { + out_samples = s->in_buffer_count + in_samples; + av_assert0(s->out_sample_rate == s->in_sample_rate); + } + + if (out_samples > INT_MAX) + return AVERROR(EINVAL); + + return out_samples; +} + int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance){ int ret; diff --git a/libswresample/swresample.h b/libswresample/swresample.h index 37656a667d..e1617f472f 100644 --- a/libswresample/swresample.h +++ b/libswresample/swresample.h @@ -294,9 +294,10 @@ void swr_close(struct SwrContext *s); * in and in_count can be set to 0 to flush the last few samples out at the * end. * - * If more input is provided than output space then the input will be buffered. - * You can avoid this buffering by providing more output space than input. - * Conversion will run directly without copying whenever possible. + * If more input is provided than output space, then the input will be buffered. + * You can avoid this buffering by using swr_get_out_samples() to retrieve an + * upper bound on the required number of output samples for the given number of + * input samples. Conversion will run directly without copying whenever possible. * * @param s allocated Swr context, with parameters set * @param out output buffers, only the first one need be set in case of packed audio @@ -435,6 +436,24 @@ int swr_inject_silence(struct SwrContext *s, int count); */ int64_t swr_get_delay(struct SwrContext *s, int64_t base); +/** + * Find an upper bound on the number of samples that the next swr_convert + * call will output, if called with in_samples of input samples. This + * depends on the internal state, and anything changing the internal state + * (like further swr_convert() calls) will may change the number of samples + * swr_get_out_samples() returns for the same number of input samples. + * + * @param in_samples number of input samples. + * @note any call to swr_inject_silence(), swr_convert(), swr_next_pts() + * or swr_set_compensation() invalidates this limit + * @note it is recommended to pass the correct available buffer size + * to all functions like swr_convert() even if swr_get_out_samples() + * indicates that less would be used. + * @returns an upper bound on the number of samples that the next swr_convert + * will output or a negative value to indicate an error + */ +int swr_get_out_samples(struct SwrContext *s, int in_samples); + /** * @} * diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h index 774593938b..7595588f41 100644 --- a/libswresample/swresample_internal.h +++ b/libswresample/swresample_internal.h @@ -76,6 +76,7 @@ typedef int (* resample_flush_func)(struct SwrContext *c); typedef int (* set_compensation_func)(struct ResampleContext *c, int sample_delta, int compensation_distance); typedef int64_t (* get_delay_func)(struct SwrContext *s, int64_t base); typedef int (* invert_initial_buffer_func)(struct ResampleContext *c, AudioData *dst, const AudioData *src, int src_size, int *dst_idx, int *dst_count); +typedef int64_t (* get_out_samples_func)(struct SwrContext *s, int in_samples); struct Resampler { resample_init_func init; @@ -85,6 +86,7 @@ struct Resampler { set_compensation_func set_compensation; get_delay_func get_delay; invert_initial_buffer_func invert_initial_buffer; + get_out_samples_func get_out_samples; }; extern struct Resampler const swri_resampler; diff --git a/libswresample/version.h b/libswresample/version.h index 61c76fa2f4..94ac9c52d0 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBSWRESAMPLE_VERSION_MAJOR 1 -#define LIBSWRESAMPLE_VERSION_MINOR 1 +#define LIBSWRESAMPLE_VERSION_MINOR 2 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \