[FFmpeg-devel] [PATCH] swresample: Add swr_get_out_samples()

wm4 nfxjfg at googlemail.com
Thu Jun 4 10:48:01 CEST 2015


On Thu, 4 Jun 2015 04:37:31 +0200
Michael Niedermayer <michaelni at gmx.at> wrote:

> On Wed, Jun 03, 2015 at 11:11:23AM +0200, wm4 wrote:
> > On Wed,  3 Jun 2015 01:22:49 +0200
> > Michael Niedermayer <michaelni at gmx.at> wrote:
> > 
> > > Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> > > ---
> > >  libswresample/resample.c            |   17 +++++++++++++++++
> > >  libswresample/swresample.c          |   30
> > > ++++++++++++++++++++++++++++++ libswresample/swresample.h
> > > |   14 ++++++++++++++ libswresample/swresample_internal.h |    2 ++
> > >  libswresample/version.h             |    2 +-
> > >  5 files changed, 64 insertions(+), 1 deletion(-)
> > > 
> > 
> > Well, it's interesting to see that the implementation is much more
> > complicated than what's suggested in the public API doxygen, or what
> > af_aresample.c does.
> 
> i dont know, it doesnt look much more complex to me, its handling
> compensation_distance, and does a bit of error checking
> 
> 
> > 
> > > diff --git a/libswresample/resample.c b/libswresample/resample.c
> > > index d4c7d06..c61bcb0 100644
> > > --- a/libswresample/resample.c
> > > +++ b/libswresample/resample.c
> > > @@ -345,6 +345,22 @@ 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;
> > > +    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); +
> > > +    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 + 2;
> > 
> > What's the are the two "+2" for (here and at initialization of num)?
> > Maybe there should be a comment explaining them.
> 
> comment added

The comment you added to the final version had 2 typos.

> 
> > 
> > > +}
> > > +
> > >  static int resample_flush(struct SwrContext *s) {
> > >      AudioData *a= &s->in_buffer;
> > >      int i, j, ret;
> > > @@ -414,4 +430,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 3d3ab83..a5f5930 100644
> > > --- a/libswresample/swresample.c
> > > +++ b/libswresample/swresample.c
> > > @@ -672,11 +672,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;
> > > @@ -719,6 +723,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;
> > > @@ -770,6 +777,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;
> > >      }
> > >  }
> > > @@ -821,6 +829,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);
> > 
> > When does this happen? Unless it's only before the context is
> > "opened", I'd say this is unacceptable. It should at least attempt to
> > return an upper bound. How else would the API user be able to tell how
> > much data to read?
> > 
> > (Unless you require the API user to do repeated resample calls with no
> > input to drain the remaining internal buffers?)
> 
> ENOSYS happens if you select the soxr resampler, ive not yet looked
> into if this is possible to know this based on API without depending
> on soxr internals.
> 
> either its possible to do then it should get implemented
> or its not in which case its just not possible if the user selects
> soxr
> 

This is a bit of a problem. Since soxr can be enabled via the generic
AVOptions, a user could easily break the API. Which is not good. (I
already had this issue with libswresample/soxr in a different case. I
didn't even know about it, until a user tried to use it.)


More information about the ffmpeg-devel mailing list