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