On Wed, Nov 28, 2012 at 03:00:10PM -0500, Justin Ruggles wrote:
> ---
>  libavresample/Makefile        |    1 +
>  libavresample/audio_convert.c |   33 ++++-
>  libavresample/audio_convert.h |   22 ++-
>  libavresample/avresample.h    |    9 +
>  libavresample/dither.c        |  392 
> +++++++++++++++++++++++++++++++++++++++++
>  libavresample/dither.h        |   60 +++++++
>  libavresample/internal.h      |    1 +
>  libavresample/options.c       |    6 +
>  libavresample/utils.c         |   10 +-
>  9 files changed, 523 insertions(+), 11 deletions(-)
>  create mode 100644 libavresample/dither.c
>  create mode 100644 libavresample/dither.h
> 
> diff --git a/libavresample/Makefile b/libavresample/Makefile
> index c0c20a9..6805280 100644
> --- a/libavresample/Makefile
> +++ b/libavresample/Makefile
> @@ -8,6 +8,7 @@ OBJS = audio_convert.o                                        
>           \
>         audio_data.o                                                     \
>         audio_mix.o                                                      \
>         audio_mix_matrix.o                                               \
> +       dither.o                                                         \
>         options.o                                                        \
>         resample.o                                                       \
>         utils.o                                                          \
> diff --git a/libavresample/audio_convert.c b/libavresample/audio_convert.c
> index dcf8a39..eb3bc1f 100644
> --- a/libavresample/audio_convert.c
> +++ b/libavresample/audio_convert.c
> @@ -29,6 +29,8 @@
>  #include "libavutil/samplefmt.h"
>  #include "audio_convert.h"
>  #include "audio_data.h"
> +#include "dither.h"
> +#include "internal.h"
>  
>  enum ConvFuncType {
>      CONV_FUNC_TYPE_FLAT,
> @@ -46,6 +48,7 @@ typedef void (conv_func_deinterleave)(uint8_t **out, const 
> uint8_t *in, int len,
>  
>  struct AudioConvert {
>      AVAudioResampleContext *avr;
> +    DitherContext *dc;
>      enum AVSampleFormat in_fmt;
>      enum AVSampleFormat out_fmt;
>      int channels;
> @@ -246,10 +249,18 @@ static void set_generic_function(AudioConvert *ac)
>      SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL)
>  }
>  
> +void ff_audio_convert_free(AudioConvert **ac)
> +{
> +    if (!*ac)
> +        return;
> +    ff_dither_free(&(*ac)->dc);

does this line do what I hope it does?

> +    av_freep(ac);
> +}
> +
>  AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
>                                       enum AVSampleFormat out_fmt,
>                                       enum AVSampleFormat in_fmt,
> -                                     int channels)
> +                                     int channels, int sample_rate)
>  {
>      AudioConvert *ac;
>      int in_planar, out_planar;
> @@ -263,6 +274,17 @@ AudioConvert 
> *ff_audio_convert_alloc(AVAudioResampleContext *avr,
>      ac->in_fmt   = in_fmt;
>      ac->channels = channels;
>  
> +    if (avr->dither_method != AV_RESAMPLE_DITHER_NONE          &&
> +        av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 &&
> +        av_get_bytes_per_sample(in_fmt) > 2) {
> +        ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, 
> sample_rate);
> +        if (!ac->dc) {
> +            av_free(ac);
> +            return NULL;
> +        }
> +        return ac;
> +    }
> +
>      in_planar  = av_sample_fmt_is_planar(in_fmt);
>      out_planar = av_sample_fmt_is_planar(out_fmt);
>  
> @@ -289,6 +311,15 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, 
> AudioData *in)
>      int use_generic = 1;
>      int len         = in->nb_samples;
>  
> +    if (ac->dc) {
> +        /* dithered conversion */
> +        av_dlog(ac->avr, "%d samples - audio_convert: %s to %s (dithered)\n",
> +                len, av_get_sample_fmt_name(ac->in_fmt),
> +                av_get_sample_fmt_name(ac->out_fmt));
> +
> +        return ff_convert_dither(ac->dc, out, in);
> +    }
> +
>      /* determine whether to use the optimized function based on pointer and
>         samples alignment in both the input and output */
>      if (ac->has_optimized_func) {
> diff --git a/libavresample/audio_convert.h b/libavresample/audio_convert.h
> index bc27223..b8808f1 100644
> --- a/libavresample/audio_convert.h
> +++ b/libavresample/audio_convert.h
> @@ -54,16 +54,26 @@ void ff_audio_convert_set_func(AudioConvert *ac, enum 
> AVSampleFormat out_fmt,
>  /**
>   * Allocate and initialize AudioConvert context for sample format conversion.
>   *
> - * @param avr      AVAudioResampleContext
> - * @param out_fmt  output sample format
> - * @param in_fmt   input sample format
> - * @param channels number of channels
> - * @return         newly-allocated AudioConvert context
> + * @param avr         AVAudioResampleContext
> + * @param out_fmt     output sample format
> + * @param in_fmt      input sample format
> + * @param channels    number of channels
> + * @param sample_rate sample rate (used for dithering)
> + * @return            newly-allocated AudioConvert context
>   */
>  AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
>                                       enum AVSampleFormat out_fmt,
>                                       enum AVSampleFormat in_fmt,
> -                                     int channels);
> +                                     int channels, int sample_rate);
> +
> +/**
> + * Free AudioConvert.
> + *
> + * The AudioConvert must have been previously allocated with 
> ff_audio_convert_alloc().
> + *
> + * @param ac  AudioConvert struct
> + */
> +void ff_audio_convert_free(AudioConvert **ac);
>  
>  /**
>   * Convert audio data from one sample format to another.
> diff --git a/libavresample/avresample.h b/libavresample/avresample.h
> index affeeeb..fc7f138 100644
> --- a/libavresample/avresample.h
> +++ b/libavresample/avresample.h
> @@ -119,6 +119,15 @@ enum AVResampleFilterType {
>      AV_RESAMPLE_FILTER_TYPE_KAISER,             /**< Kaiser Windowed Sinc */
>  };
>  
> +enum AVResampleDitherMethod {
> +    AV_RESAMPLE_DITHER_NONE,            /**< Do not use dithering */
> +    AV_RESAMPLE_DITHER_RECTANGULAR,     /**< Rectangular Dither */
> +    AV_RESAMPLE_DITHER_TRIANGULAR,      /**< Triangular Dither*/
> +    AV_RESAMPLE_DITHER_TRIANGULAR_HP,   /**< Triangular Dither with High 
> Pass */
> +    AV_RESAMPLE_DITHER_TRIANGULAR_NS,   /**< Triangular Dither with Noise 
> Shaping */
> +    AV_RESAMPLE_DITHER_NB,              /**< Number of dither types. Not 
> part of ABI. */
> +};
> +
>  /**
>   * Return the LIBAVRESAMPLE_VERSION_INT constant.
>   */
> diff --git a/libavresample/dither.c b/libavresample/dither.c
> new file mode 100644
> index 0000000..450a9b0
> --- /dev/null
> +++ b/libavresample/dither.c
> @@ -0,0 +1,392 @@
> +/*
> + * Copyright (c) 2012 Justin Ruggles <[email protected]>
> + *
> + * Triangular with Noise Shaping is based on opusfile.
> + * Copyright (c) 1994-2012 by the Xiph.Org Foundation and contributors
> + *
> + * This file is part of Libav.
> + *
> + * Libav is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * Libav is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +/**
> + * @file
> + * Dithered Audio Sample Quantization
> + *
> + * Converts from dbl, flt, or s32 to s16 using dithering.
> + */
> +
> +#include <math.h>
> +#include <stdint.h>
> +
> +#include "libavutil/common.h"
> +#include "libavutil/float_dsp.h"
> +#include "libavutil/lfg.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/samplefmt.h"
> +#include "audio_convert.h"
> +#include "dither.h"
> +#include "internal.h"
> +
> +typedef struct DitherState {
> +    int mute;
> +    AVLFG lfg;
> +    float dither_a[4];
> +    float dither_b[4];
> +} DitherState;
> +
> +struct DitherContext {
> +    AVFloatDSPContext fdsp;
> +
> +    int mute_dither_threshold;  // threshold for disabling dither
> +    int mute_reset_threshold;   // threshold for resetting noise shaping
> +    const float *ns_coef_b;     // noise shaping coeffs
> +    const float *ns_coef_a;     // noise shaping coeffs
> +
> +    DitherState *state;         // dither states for each channel
> +
> +    AudioData *flt_data;        // input data in fltp
> +    AudioData *s16_data;        // dithered output in s16p
> +    AudioConvert *ac_in;        // converter for input to fltp
> +    AudioConvert *ac_out;       // converter for s16p to s16 (if needed)
> +
> +    int16_t (*quantize)(DitherContext *c, DitherState *state, float sample);
> +};
> +
> +/* mute threshold, in seconds */
> +#define MUTE_THRESHOLD_SEC 0.000333
> +
> +/* noise shaping coefficients */
> +
> +static const float ns_48_coef_b[4] = {
> +    2.2374f, -0.7339f, -0.1251f, -0.6033f
> +};
> +
> +static const float ns_48_coef_a[4] = {
> +    0.9030f, 0.0116f, -0.5853f, -0.2571f
> +};
> +
> +static const float ns_44_coef_b[4] = {
> +    2.2061f, -0.4707f, -0.2534f, -0.6213f
> +};
> +
> +static const float ns_44_coef_a[4] = {
> +    1.0587f, 0.0676f, -0.6054f, -0.2738f
> +};

looks like it can be generated for all frequencies if you know DSP theory
(unlike me), but it's fine too

> +static inline float lfg_get_flt(AVLFG *lfg)
> +{
> +    return av_lfg_get(lfg) / (float)UINT32_MAX;
> +}

Make it generic? I think some codecs use the similar code too.


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

Reply via email to