swresample: Add swr_get_out_samples()
authorMichael Niedermayer <michaelni@gmx.at>
Tue, 2 Jun 2015 23:22:25 +0000 (01:22 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 4 Jun 2015 03:37:32 +0000 (05:37 +0200)
Previous version reviewed-by: Pavel Koshevoy <pkoshevoy@gmail.com>
Previous version reviewed-by: wm4 <nfxjfg@googlemail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
doc/APIchanges
libswresample/resample.c
libswresample/swresample.c
libswresample/swresample.h
libswresample/swresample_internal.h
libswresample/version.h

index e151999..5c36dca 100644 (file)
@@ -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.
 
index d4c7d06..f2624b5 100644 (file)
@@ -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,
 };
index 87ad7f8..4aa081b 100644 (file)
@@ -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;
 
index 37656a6..e1617f4 100644 (file)
@@ -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);
+
 /**
  * @}
  *
index 7745939..7595588 100644 (file)
@@ -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;
index 61c76fa..94ac9c5 100644 (file)
@@ -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, \