On 04/16/2014 03:00 AM, Luca Barbato wrote:
> ---
>  libavresample/avresample.h |  54 +++++++++++++++++++++
>  libavresample/utils.c      | 118 
> +++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/error.h          |   2 +
>  3 files changed, 174 insertions(+)
> 
> diff --git a/libavresample/avresample.h b/libavresample/avresample.h
> index 3358628..702a767 100644
> --- a/libavresample/avresample.h
> +++ b/libavresample/avresample.h
> @@ -96,6 +96,7 @@
>  #include "libavutil/avutil.h"
>  #include "libavutil/channel_layout.h"
>  #include "libavutil/dict.h"
> +#include "libavutil/frame.h"
>  #include "libavutil/log.h"
>  
>  #include "libavresample/version.h"
> @@ -410,6 +411,59 @@ int avresample_available(AVAudioResampleContext *avr);
>   */
>  int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int 
> nb_samples);
>  
> +
> +
> +/**
> + * Convert the samples in the input AVFrame and write them to the output 
> AVFrame.
> + *
> + * Input and output AVFrames must have channel_layout, sample_rate and 
> format set.
> + *
> + * The upper bound on the number of output samples is given by
> + * avresample_available() + (avresample_get_delay() + number of input 
> samples) *
> + * output sample rate / input sample rate.
> + *
> + * If the output AVFrame does not have the data pointers allocated a the 
> nb_samples
> + * will be set as described above and av_frame_get_buffer() will be called.

This needs to be clearer. In your code, when the function returns,
out->nb_samples is actually be the number of output samples, not the
upper bound as described here. Maybe just say that av_frame_get_buffer()
will be called to allocate any required buffers for the output frame
without going into the upper bound stuff.

> + *
> + * The output AVFrame can be NULL or have fewer allocated samples than 
> required.
> + *
> + * In this case, any remaining samples not written to the output will be 
> added
> + * to an internal FIFO buffer, to be returned at the next call to this 
> function
> + * or to avresample_convert() or to avresample_read().
> + *
> + * If converting sample rate, there may be data remaining in the internal
> + * resampling delay buffer. avresample_get_delay() tells the number of 
> remaining
> + * samples. To get this data as output, call this function or 
> avresample_convert()
> + * with NULL input.
> + *
> + * At the end of the conversion process, there may be data remaining in the
> + * internal FIFO buffer. avresample_available() tells the number of remaining
> + * samples. To get this data as output, either call this function or 
> avresample_convert()
> + * with NULL input or call avresample_read().
> + *
> + * If the AVAudioResampleContext configuration does not match the output and 
> input AVFrame
> + * settings the conversion does not take place and depending on which 
> AVFrame is not
> + * matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED or
> + * AVERROR_OUTPUT_CHANGED|AVERROR_INPUT_CHANGED is returned.

Now I'm wondering if these should be positive values instead of
AVERRORs. It has to be checked for anyway, and checking for positive
values vs. negative values seems like it would make for simpler
user-side code.

> + *
> + * @see avresample_available()
> + * @see avresample_convert()
> + * @see avresample_read()
> + * @see avresample_get_delay()
> + *
> + * @param avr             audio resample context
> + * @param output          output AVFrame
> + * @param input           input AVFrame
> + * @return                number of samples written to the output buffer,
> + *                        not including converted samples added to the 
> internal
> + *                        output FIFO or an AVERROR.

Instead of returning the number of samples written, how about just
returning 0 or AVERROR and setting output->nb_samples.

> + */
> +int avresample_convert_frame(AVAudioResampleContext *avr,
> +                             AVFrame *output, AVFrame *input);
> +
> +int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in,
> +                      AVDictionary **opts);

Doxy please. :)

> +
>  /**
>   * @}
>   */
> diff --git a/libavresample/utils.c b/libavresample/utils.c
> index 35bee42..37d9a63 100644
> --- a/libavresample/utils.c
> +++ b/libavresample/utils.c
> @@ -21,6 +21,7 @@
>  #include "libavutil/common.h"
>  #include "libavutil/dict.h"
>  #include "libavutil/error.h"
> +#include "libavutil/frame.h"
>  #include "libavutil/log.h"
>  #include "libavutil/mem.h"
>  #include "libavutil/opt.h"
> @@ -506,6 +507,123 @@ int attribute_align_arg 
> avresample_convert(AVAudioResampleContext *avr,
>                                    current_buffer);
>  }
>  
> +int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in,
> +                      AVDictionary **opts)
> +{
> +    int ret;
> +
> +    if (avresample_is_open(avr)) {
> +        avresample_close(avr);
> +    }
> +
> +    if (!out || !in)
> +        return AVERROR(EINVAL);
> +
> +    avr->in_channel_layout  = in->channel_layout;
> +    avr->out_channel_layout = out->channel_layout;
> +    avr->in_sample_rate     = in->sample_rate;
> +    avr->out_sample_rate    = out->sample_rate;
> +    avr->in_sample_fmt      = in->format;
> +    avr->out_sample_fmt     = out->format;
> +
> +    if ((ret = av_opt_set_dict(avr, opts)) < 0)
> +        return ret;
> +
> +    return avresample_open(avr);
> +}

I was thinking more along the lines of avresample_open2() to replace
avresample_open(), where 'out' and 'in' are optional if the format
options have already been set as is required in the current API.

> +
> +static int config_changed(AVAudioResampleContext *avr,
> +                          AVFrame *out, AVFrame *in)
> +{
> +    int ret = 0;
> +
> +    if (in) {
> +        if (avr->in_channel_layout != in->channel_layout ||
> +            avr->in_sample_rate    != in->sample_rate ||
> +            avr->in_sample_fmt     != in->format) {
> +            ret |= AVERROR_INPUT_CHANGED;
> +        }
> +    }
> +
> +    if (out) {
> +        if (avr->out_channel_layout != out->channel_layout ||
> +            avr->out_sample_rate    != out->sample_rate ||
> +            avr->out_sample_fmt     != out->format) {
> +            ret |= AVERROR_OUTPUT_CHANGED;
> +        }
> +    }
> +
> +    return ret;
> +}
> +
> +static inline int convert_frame(AVAudioResampleContext *avr,
> +                                AVFrame *out, AVFrame *in)
> +{
> +    int ret;
> +    uint8_t **out_data = NULL, **in_data = NULL;
> +    int out_linesize = 0, in_linesize = 0;
> +    int out_nb_samples = 0, in_nb_samples = 0;
> +
> +    if (out) {
> +        out_data       = out->extended_data;
> +        out_linesize   = out->linesize[0];
> +        out_nb_samples = out->nb_samples;
> +    }
> +
> +    if (in) {
> +        in_data       = in->extended_data;
> +        in_linesize   = in->linesize[0];
> +        in_nb_samples = in->nb_samples;
> +    }
> +
> +    ret = avresample_convert(avr, out_data, out_linesize,
> +                             out_nb_samples,
> +                             in_data, in_linesize,
> +                             in_nb_samples);
> +
> +    if (ret > 0) {
> +        out->nb_samples = ret;
> +        return 0;
> +    }
> +
> +    return ret;
> +}
> +
> +static inline int output_frame_samples(AVAudioResampleContext *avr,
> +                                       AVFrame *out, AVFrame *in)
> +{
> +    return avresample_available(avr) +
> +           (avresample_get_delay(avr) + in->nb_samples) *
> +           out->sample_rate / in->sample_rate;
> +}
> +
> +int avresample_convert_frame(AVAudioResampleContext *avr,
> +                             AVFrame *out, AVFrame *in)
> +{
> +    int ret;
> +
> +    if (!avresample_is_open(avr)) {
> +        if ((ret = avresample_config(avr, out, in, NULL)) < 0)
> +            return ret;
> +        if ((ret = avresample_open(avr)) < 0)
> +            return ret;

open twice?

> +    } else {
> +        // return as is or reconfigure for input changes?
> +        if ((ret = config_changed(avr, out, in)))
> +            return ret;
> +    }
> +
> +    if (out && !out->linesize[0]) {
> +        out->nb_samples = output_frame_samples(avr, out, in);
> +        if ((ret = av_frame_get_buffer(out, 0)) < 0) {
> +            avresample_close(avr);

why close on get_buffer() failure? maybe keep track if it was opened in
this function and only close it in that case.

> +            return ret;
> +        }
> +    }
> +
> +    return convert_frame(avr, out, in);
> +}
> +
>  int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
>                            int stride)
>  {
> diff --git a/libavutil/error.h b/libavutil/error.h
> index 268a032..0a95d2e 100644
> --- a/libavutil/error.h
> +++ b/libavutil/error.h
> @@ -60,6 +60,8 @@
>  #define AVERROR_BUG                (-0x5fb8aabe) ///< Bug detected, please 
> report the issue
>  #define AVERROR_UNKNOWN            (-0x31b4b1ab) ///< Unknown error, 
> typically from an external library
>  #define AVERROR_EXPERIMENTAL       (-0x2bb2afa8) ///< Requested feature is 
> flagged experimental. Set strict_std_compliance if you really want to use it.
> +#define AVERROR_INPUT_CHANGED      (-0x636e6701) ///< Input changed between 
> calls. Reconfiguration is required.
> +#define AVERROR_OUTPUT_CHANGED     (-0x636e6702) ///< Output changed between 
> calls. Reconfiguration is required.
>  
>  /**
>   * Put a description of the AVERROR code errnum in errbuf.

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to