[FFmpeg-devel] [RFC] libavfilter audio API and related issues

Stefano Sabatini stefano.sabatini-lala
Sat Jun 26 02:10:39 CEST 2010


On date Friday 2010-06-25 03:52:45 -0700, S.N. Hemanth Meenakshisundaram encoded:
> Hi All,
> 
> I moved to Git and this is a first git test patch.
> 
> The changes in this patch are:
> 
> 1. Fixes to audio filter framework code based on comments from last patch.
> 
> 2. SampleFormat and ChannelLayout definitions moved to libavutil/audiofmt.h
> 
> 3. Some channel layout and sample format utility functions copied to
> libavutil/audiodesc.h and audiodesc.c. Copies of these functions
> (with different names) still exist in libavcodec/utils.c and
> libavcodec/audioconvert.c, I haven't yet removed them to prevent
> breakage of existing code.
> 
> 4. Libavfilter audio changes now dependent only on lavu and not on lavc.
> 
> 5. Incomplete version of af_resample.c which does sample format
> conversion and will also do channel layout conversion.
> 
> Before that, I have a few questions on how to proceed:
> 
> 1. lavc has a resample.c for the above operations (in conjunction
> with audioconvert.c) and also a resample2.c which does sample rate
> conversion. Is it ok to name this filter af_resample or should I
> name this one af_reformat and reserve the af_resample name for the
> sample rate conversion filter?
> 
> 2. The current resample.c only accepts two channel input data - why?
> Depending on the file and codec, isn't it possible for input data to
> be more than two channels? Can I attempt adding multichannel input
> support or is there a reason it is not supported?
> 
> 3. The current output sample format is always forced to S16. The
> channel layout conversion filters after this all assume that the
> individual samples are shorts. This needs to be fixed right? For
> example, I was thinking of changing stereo_to_mono function so it
> accepts an extra stride parameter and uses that to do its job
> irrespective of whether inputs are shorts (S16) or otherwise. Is
> this ok?
> 
> I still need to fix nits etc in af_resample. Will do those when
> finishing the channel layout conversion.
> 
> Regards,
> Hemanth
> 
> 

> diff --git a/ffplay.c b/ffplay.c
> index 1a41e47..92a0f2a 100644
> --- a/ffplay.c
> +++ b/ffplay.c
> @@ -1789,7 +1789,7 @@ static int input_audio_init(AVFilterContext *ctx, const char *args, void *opaque
>  {
>      AudioFilterPriv *priv = ctx->priv;
>  
> -    if(!opaque) return -1;
> +    if (!opaque) return AVERROR(EINVAL);

Please try to split the patch, so that we can start to commit them to
SVN, with git that should be fairly easy.

>  
>      priv->is = opaque;
>  
> @@ -1804,24 +1804,24 @@ static int input_request_samples(AVFilterLink *link)
>  {
>      AudioFilterPriv *priv = link->src->priv;
>      AVFilterSamplesRef *samplesref;
> -    AVCodecContext *c;
> +    AVCodecContext *avctx;

Renames are fine but again keep them in separate patches.

>      double pts = 0;
>      int buf_size = 0;
>  
>      buf_size = audio_decode_frame(priv->is, &pts);
> -    c = priv->is->audio_st->codec;
> +    avctx = priv->is->audio_st->codec;
>      if (buf_size <= 0)
>          return -1;
>  
>      /* FIXME Currently audio streams seem to have no info on planar/packed.
> -     * Assuming packed here and passing 0 as last attribute to get_audio_buffer.
> +     * Assuming packed here and passing 0 as last attribute to get_samples_ref.
>       */
> -    samplesref = avfilter_get_audio_buffer(link, AV_PERM_WRITE, buf_size,
> -                                           c->channel_layout, c->sample_fmt, 0);
> +    samplesref = avfilter_get_samples_ref(link, AV_PERM_WRITE, buf_size,
> +                                           avctx->channel_layout, avctx->sample_fmt, 0);
>      memcpy(samplesref->data[0], priv->is->audio_buf, buf_size);
>  
>      samplesref->pts         = (int64_t) pts;
> -    samplesref->sample_rate = (int64_t) c->sample_rate;
> +    samplesref->sample_rate = (int64_t) avctx->sample_rate;
>      avfilter_filter_samples(link, samplesref);
>  
>      return 0;
> @@ -1878,9 +1878,9 @@ static int get_filtered_audio_samples(AVFilterContext *ctx, VideoState *is, doub
>  {
>      AVFilterSamplesRef *samplesref;
>  
> -    if(avfilter_request_samples(ctx->inputs[0]))
> +    if (avfilter_request_samples(ctx->inputs[0]))
>          return -1;
> -    if(!(samplesref = ctx->inputs[0]->cur_samples))
> +    if (!(samplesref = ctx->inputs[0]->cur_samples))
>          return -1;
>      ctx->inputs[0]->cur_samples = NULL;
>  
> @@ -2406,14 +2406,14 @@ static int stream_component_open(VideoState *is, int stream_index)
>  
>  #if CONFIG_AVFILTER
>      is->agraph = av_mallocz(sizeof(AVFilterGraph));
> -    if(!(afilt_src = avfilter_open(&input_audio_filter,  "asrc")))   goto the_end;
> -    if(!(afilt_out = avfilter_open(&output_audio_filter, "aout")))   goto the_end;
> +    if (!(afilt_src = avfilter_open(&input_audio_filter,  "asrc")))   goto the_end;
> +    if (!(afilt_out = avfilter_open(&output_audio_filter, "aout")))   goto the_end;
>  
> -    if(avfilter_init_filter(afilt_src, NULL, is))             goto the_end;
> -    if(avfilter_init_filter(afilt_out, NULL, NULL))           goto the_end;
> +    if (avfilter_init_filter(afilt_src, NULL, is))             goto the_end;
> +    if (avfilter_init_filter(afilt_out, NULL, NULL))           goto the_end;
>  
>  
> -    if(afilters) {
> +    if (afilters) {
>          AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
>          AVFilterInOut *inputs  = av_malloc(sizeof(AVFilterInOut));
>  
> @@ -2431,14 +2431,14 @@ static int stream_component_open(VideoState *is, int stream_index)
>              goto the_end;
>          av_freep(&afilters);
>      } else {
> -        if(avfilter_link(afilt_src, 0, afilt_out, 0) < 0)          goto the_end;
> +        if (avfilter_link(afilt_src, 0, afilt_out, 0) < 0)          goto the_end;
>      }
>      avfilter_graph_add_filter(is->agraph, afilt_src);
>      avfilter_graph_add_filter(is->agraph, afilt_out);
>  
> -    if(avfilter_graph_check_validity(is->agraph, NULL))           goto the_end;
> -    if(avfilter_graph_config_formats(is->agraph, NULL))           goto the_end;
> -    if(avfilter_graph_config_links(is->agraph, NULL))             goto the_end;
> +    if (avfilter_graph_check_validity(is->agraph, NULL))           goto the_end;
> +    if (avfilter_graph_config_formats(is->agraph, NULL))           goto the_end;
> +    if (avfilter_graph_config_links(is->agraph, NULL))             goto the_end;
>  
>      is->out_audio_filter = afilt_out;
>  #endif
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index a878319..75bd976 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -368,64 +368,6 @@ enum CodecID {
>  #define CODEC_TYPE_NB         AVMEDIA_TYPE_NB
>  #endif
>  
> -/**
> - * all in native-endian format
> - */
> -enum SampleFormat {
> -    SAMPLE_FMT_NONE = -1,
> -    SAMPLE_FMT_U8,              ///< unsigned 8 bits
> -    SAMPLE_FMT_S16,             ///< signed 16 bits
> -    SAMPLE_FMT_S32,             ///< signed 32 bits
> -    SAMPLE_FMT_FLT,             ///< float
> -    SAMPLE_FMT_DBL,             ///< double
> -    SAMPLE_FMT_NB               ///< Number of sample formats. DO NOT USE if dynamically linking to libavcodec
> -};
> -
> -/* Audio channel masks */
> -#define CH_FRONT_LEFT             0x00000001
> -#define CH_FRONT_RIGHT            0x00000002
> -#define CH_FRONT_CENTER           0x00000004
> -#define CH_LOW_FREQUENCY          0x00000008
> -#define CH_BACK_LEFT              0x00000010
> -#define CH_BACK_RIGHT             0x00000020
> -#define CH_FRONT_LEFT_OF_CENTER   0x00000040
> -#define CH_FRONT_RIGHT_OF_CENTER  0x00000080
> -#define CH_BACK_CENTER            0x00000100
> -#define CH_SIDE_LEFT              0x00000200
> -#define CH_SIDE_RIGHT             0x00000400
> -#define CH_TOP_CENTER             0x00000800
> -#define CH_TOP_FRONT_LEFT         0x00001000
> -#define CH_TOP_FRONT_CENTER       0x00002000
> -#define CH_TOP_FRONT_RIGHT        0x00004000
> -#define CH_TOP_BACK_LEFT          0x00008000
> -#define CH_TOP_BACK_CENTER        0x00010000
> -#define CH_TOP_BACK_RIGHT         0x00020000
> -#define CH_STEREO_LEFT            0x20000000  ///< Stereo downmix.
> -#define CH_STEREO_RIGHT           0x40000000  ///< See CH_STEREO_LEFT.
> -
> -/** Channel mask value used for AVCodecContext.request_channel_layout
> -    to indicate that the user requests the channel order of the decoder output
> -    to be the native codec channel order. */
> -#define CH_LAYOUT_NATIVE          0x8000000000000000LL
> -
> -/* Audio channel convenience macros */
> -#define CH_LAYOUT_MONO              (CH_FRONT_CENTER)
> -#define CH_LAYOUT_STEREO            (CH_FRONT_LEFT|CH_FRONT_RIGHT)
> -#define CH_LAYOUT_2_1               (CH_LAYOUT_STEREO|CH_BACK_CENTER)
> -#define CH_LAYOUT_SURROUND          (CH_LAYOUT_STEREO|CH_FRONT_CENTER)
> -#define CH_LAYOUT_4POINT0           (CH_LAYOUT_SURROUND|CH_BACK_CENTER)
> -#define CH_LAYOUT_2_2               (CH_LAYOUT_STEREO|CH_SIDE_LEFT|CH_SIDE_RIGHT)
> -#define CH_LAYOUT_QUAD              (CH_LAYOUT_STEREO|CH_BACK_LEFT|CH_BACK_RIGHT)
> -#define CH_LAYOUT_5POINT0           (CH_LAYOUT_SURROUND|CH_SIDE_LEFT|CH_SIDE_RIGHT)
> -#define CH_LAYOUT_5POINT1           (CH_LAYOUT_5POINT0|CH_LOW_FREQUENCY)
> -#define CH_LAYOUT_5POINT0_BACK      (CH_LAYOUT_SURROUND|CH_BACK_LEFT|CH_BACK_RIGHT)
> -#define CH_LAYOUT_5POINT1_BACK      (CH_LAYOUT_5POINT0_BACK|CH_LOW_FREQUENCY)
> -#define CH_LAYOUT_7POINT0           (CH_LAYOUT_5POINT0|CH_BACK_LEFT|CH_BACK_RIGHT)
> -#define CH_LAYOUT_7POINT1           (CH_LAYOUT_5POINT1|CH_BACK_LEFT|CH_BACK_RIGHT)
> -#define CH_LAYOUT_7POINT1_WIDE      (CH_LAYOUT_5POINT1_BACK|\
> -                                          CH_FRONT_LEFT_OF_CENTER|CH_FRONT_RIGHT_OF_CENTER)
> -#define CH_LAYOUT_STEREO_DOWNMIX    (CH_STEREO_LEFT|CH_STEREO_RIGHT)
> -
>  /* in bytes */
>  #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
>  
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index d5983c8..7b26435 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -15,6 +15,8 @@ OBJS = allfilters.o                                                     \
>         graphparser.o                                                    \
>         parseutils.o                                                     \
>  
> +OBJS-$(CONFIG_RESAMPLE_FILTER)               += af_resample.o
> +
>  OBJS-$(CONFIG_ASPECT_FILTER)                 += vf_aspect.o
>  OBJS-$(CONFIG_CROP_FILTER)                   += vf_crop.o
>  OBJS-$(CONFIG_DRAWBOX_FILTER)                += vf_drawbox.o
> diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c
> new file mode 100644
> index 0000000..7016a56
> --- /dev/null
> +++ b/libavfilter/af_resample.c
> @@ -0,0 +1,351 @@
> +/*
> + * copyright (c) 2007 Bobby Bingham

Put your name here (or both if you believe).

> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg 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.
> + *
> + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * resample audio filter
> + */
> +
> +#include "avfilter.h"
> +#include "libavutil/avutil.h"
> +#include "libavutil/audiodesc.h"
> +
> +typedef struct {
> +
> +    short reconfig_channel_layout;     ///< set when channel layout of incoming buffer changes
> +    short reconfig_sample_fmt;         ///< set when sample format of incoming buffer changes
> +
> +    enum SampleFormat in_sample_fmt;   ///< default incoming sample format expected
> +    enum SampleFormat out_sample_fmt;  ///< output sample format
> +    int64_t in_channel_layout;         ///< default incoming channel layout expected
> +    int64_t out_channel_layout;        ///< output channel layout
> +    
> +     AVFilterSamplesRef *temp_samples; ///< Stores temporary audio data between sample format and channel layout conversions
> +
> +} ResampleContext;
> +
> +static void stereo_to_mono(short *output, short *input, int samples_nb)
> +{
> +    short *p, *q;
> +    int n = samples_nb;
> +
> +    p = input;
> +    q = output;

nit: use input and output, so you can avoid two temporary variables
and get more meaningful names at the same time.

> +    while (n >= 4) {
> +        q[0] = (p[0] + p[1]) >> 1;
> +        q[1] = (p[2] + p[3]) >> 1;
> +        q[2] = (p[4] + p[5]) >> 1;
> +        q[3] = (p[6] + p[7]) >> 1;
> +        q += 4;
> +        p += 8;
> +        n -= 4;
> +    }
> +    while (n > 0) {
> +        q[0] = (p[0] + p[1]) >> 1;
> +        q++;
> +        p += 2;
> +        n--;
> +    }
> +}
> +
> +static void mono_to_stereo(short *output, short *input, int samples_nb)
> +{
> +    short *p, *q;
> +    int n = samples_nb;
> +    int v;
> +
> +    p = input;
> +    q = output;
> +    while (n >= 4) {
> +        v = p[0]; q[0] = v; q[1] = v;
> +        v = p[1]; q[2] = v; q[3] = v;
> +        v = p[2]; q[4] = v; q[5] = v;
> +        v = p[3]; q[6] = v; q[7] = v;
> +        q += 8;
> +        p += 4;
> +        n -= 4;
> +    }
> +    while (n > 0) {
> +        v = p[0]; q[0] = v; q[1] = v;
> +        q += 2;
> +        p += 1;
> +        n--;
> +    }
> +}
> +
> +/* FIXME: should use more abstract 'N' channels system */

Maybe, I'm fine with keeping a low-abstraction system for now if
implementing a more abstract one requires much time.

> +static void stereo_split(short *output1, short *output2, short *input, int n)

 n -> samples_nb seems a better name

> +{
> +    int i;
> +
> +    for(i=0;i<n;i++) {
> +        *output1++ = *input++;
> +        *output2++ = *input++;
> +    }
> +}
> +
> +static void stereo_mux(short *output, short *input1, short *input2, int n)

Maybe stereo_join()

> +{
> +    int i;
> +
> +    for(i=0;i<n;i++) {
> +        *output++ = *input1++;
> +        *output++ = *input2++;
> +    }
> +}
> +
> +static void ac3_5p1_mux(short *output, short *input1, short *input2, int n)
> +{
> +    int i;
> +    short l,r;
> +
> +    for(i=0;i<n;i++) {
> +      l=*input1++;
> +      r=*input2++;
> +      *output++ = l;           /* left */
> +      *output++ = (l/2)+(r/2); /* center */
> +      *output++ = r;           /* right */
> +      *output++ = 0;           /* left surround */
> +      *output++ = 0;           /* right surroud */
> +      *output++ = 0;           /* low freq */
> +    }
> +}
> +
> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> +{
> +    ResampleContext *resample = ctx->priv;
> +
> +    if (args){
> +        sscanf(args, "%d:%ld", &resample->out_sample_fmt, &resample->out_channel_layout);
> +    }
> +
> +    /**
> +     * sanity check params
> +     * SAMPLE_FMT_NONE is a valid value for out_sample_fmt and indicates no change in sample format
> +     * -1 is a valid value for out_channel_layout and indicates no change in channel layout
> +     */
> +    if (resample->out_sample_fmt >= SAMPLE_FMT_NB || resample->out_sample_fmt < SAMPLE_FMT_NONE) {

> +        av_log(ctx, AV_LOG_ERROR, "Invalid output sample format.\n");

print the name of the output format

> +        return AVERROR(EINVAL);
> +    }
> +    if ((resample->out_channel_layout > CH_LAYOUT_STEREO_DOWNMIX ||
> +         resample->out_channel_layout < CH_LAYOUT_MONO) && (resample->out_channel_layout != -1)) {
> +        av_log(ctx, AV_LOG_ERROR, "Invalid output sample format.\n");

ditto

> +        return AVERROR(EINVAL);
> +    }
> +
> +    return 0;
> +}
> +
> +static av_cold void uninit(AVFilterContext *ctx)
> +{
> +    ResampleContext *resample = ctx->priv;
> +    avfilter_unref_samples(resample->temp_samples);
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> +    AVFilterFormats *formats;
> +    enum SampleFormat sample_fmt;
> +    int ret;
> +
> +    if (ctx->inputs[0]) {
> +        formats = NULL;
> +        for (sample_fmt = 0; sample_fmt < SAMPLE_FMT_NB; sample_fmt++)
> +            if ((ret = avfilter_add_sampleformat(&formats, sample_fmt)) < 0) {
> +                avfilter_formats_unref(&formats);
> +                return ret;
> +            }
> +        avfilter_formats_ref(formats, &ctx->inputs[0]->out_formats);
> +    }
> +    if (ctx->outputs[0]) {
> +        formats = NULL;
> +        for (sample_fmt = 0; sample_fmt < SAMPLE_FMT_NB; sample_fmt++)
> +            if ((ret = avfilter_add_colorspace(&formats, sample_fmt)) < 0) {
> +                avfilter_formats_unref(&formats);
> +                return ret;
> +            }
> +        avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats);
> +    }
> +
> +    return 0;
> +}
> +
> +static void convert_channel_layout(AVFilterLink *link, AVFilterSamplesRef *insamples)
> +{
> +    ResampleContext *resample = link->dst->priv;
> +
> +    if (resample->reconfig_channel_layout) {
> +    /* Initialize input/output strides, intermediate buffers etc. */
> +    }
> +
> +    /* TODO: Convert to required channel layout using functions above and populate output audio buffer */
> +}
> +
> +static void convert_sample_format(AVFilterLink *link, AVFilterSamplesRef *insamples)
> +{
> +    ResampleContext *resample = link->dst->priv;
> +    AVFilterSamplesRef *out = resample->temp_samples;
> +
> +    int ch = 0;
> +    const int out_channels = av_channel_layout_num_channels(insamples->channel_layout);
> +    const int instride     = av_get_bits_per_sample_fmt(insamples->sample_fmt);
> +    const int outstride    = av_get_bits_per_sample_fmt(resample->out_sample_fmt);
> +
> +    const int fmt_pair = insamples->sample_fmt*SAMPLE_FMT_NB*resample->out_sample_fmt;
> +
> +    if (resample->reconfig_sample_fmt || !out || !out->size) {
> +
> +        int size = out_channels*outstride*insamples->samples_nb;
> +
> +        avfilter_unref_samples(resample->temp_samples);
> +        out = avfilter_get_samples_ref(link, AV_PERM_WRITE, size,
> +                                   insamples->channel_layout, resample->out_sample_fmt, 0);
> +
> +    }
> +
> +    /* Timestamp and sample rate can change even while sample format/channel layout remain the same */
> +    out->pts          = insamples->pts;
> +    out->sample_rate  = insamples->sample_rate;
> +
> +/* FIXME: Assuming packed samples here */
> +    for (ch = 0; ch < out_channels; ch++) {
> +        const uint8_t *pi=  insamples->data[ch];
> +        uint8_t *po = out->data[ch];
> +        const unsigned int len = out->samples_nb*out->channel_layout;
> +        uint8_t *end = po + outstride*len;
> +        if(!out->data[ch])
> +            continue;
> +
> +#define CONV(ofmt, otype, ifmt, expr)\
> +if (fmt_pair == ofmt + SAMPLE_FMT_NB*ifmt) {\
> +    do{\
> +        *(otype*)po = expr; pi += instride; po += outstride;\
> +    }while(po < end);\
> +}
> +
> +        CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_U8 ,  *(const uint8_t*)pi)
> +        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8)
> +        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24)
> +        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
> +        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
> +        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80)
> +        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_S16,  *(const int16_t*)pi)
> +        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_S16,  *(const int16_t*)pi<<16)
> +        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_S16,  *(const int16_t*)pi*(1.0 / (1<<15)))
> +        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_S16,  *(const int16_t*)pi*(1.0 / (1<<15)))
> +        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80)
> +        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_S32,  *(const int32_t*)pi>>16)
> +        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_S32,  *(const int32_t*)pi)
> +        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
> +        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
> +        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_FLT, av_clip_uint8(  lrintf(*(const float*)pi * (1<<7)) + 0x80))
> +        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_FLT, av_clip_int16(  lrintf(*(const float*)pi * (1<<15))))
> +        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31))))
> +        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_FLT, *(const float*)pi)
> +        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_FLT, *(const float*)pi)
> +        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_DBL, av_clip_uint8(  lrint(*(const double*)pi * (1<<7)) + 0x80))
> +        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_DBL, av_clip_int16(  lrint(*(const double*)pi * (1<<15))))
> +        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31))))
> +        else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_DBL, *(const double*)pi)
> +        else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_DBL, *(const double*)pi)
> +    }
> +    return;
> +}
> +
> +static int config_props(AVFilterLink *outlink)
> +{
> +    AVFilterContext *ctx = outlink->src;
> +    AVFilterLink *inlink = outlink->src->inputs[0];
> +    ResampleContext *resample = ctx->priv;
> +
> +    if (resample->out_channel_layout == -1)
> +        resample->out_channel_layout = inlink->channel_layout;
> +
> +    if (resample->out_sample_fmt == -1)
> +        resample->out_sample_fmt = inlink->aformat;
> +
> +    /* Call the channel layout conversion routine to prepare for default conversion. */
> +
> +    resample->reconfig_channel_layout = 1;
> +    convert_channel_layout(outlink, NULL);
> +    
> +    return 0;
> +}
> +
> +static void filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref)
> +{
> +    ResampleContext *resample = link->dst->priv;
> +    AVFilterLink *outlink = link->dst->outputs[0];
> +    AVFilterSamplesRef *outsamples;

I prefer outsampleref (and maybe _in_samplesref)

> +    int size = 0;
> +
> +#define CALC_BUFFER_SIZE(nsamp, ch, samples) {\
> +    int n_chan = av_channel_layout_num_channels(ch);\
> +    int n_stride = av_get_bits_per_sample_format(samples);\
> +    size = nsamp*n_chan*n_stride;\
> +}
> +    CALC_BUFFER_SIZE(samplesref->samples_nb, outlink->channel_layout, outlink->aformat);
> +    outsamples = avfilter_get_samples_ref(outlink, AV_PERM_WRITE, size,
> +                                          outlink->channel_layout, outlink->aformat, 0);
> +
> +    outsamples->pts         = samplesref->pts;
> +    outsamples->planar      = samplesref->planar;
> +    outsamples->sample_rate = samplesref->sample_rate;
> +
> +    outlink->out_samples    = outsamples;
> +
> +   /**
> +    * If input data of this buffer differs from the earlier buffer/s, set flag
> +    * to reconfigure the channel and sample format conversions.
> +    */
> +
> +   resample->reconfig_sample_fmt = (samplesref->sample_fmt != resample->out_sample_fmt);
> +   resample->reconfig_channel_layout = (samplesref->channel_layout != resample->out_channel_layout);
> +
> +   /* Convert to desired output sample format first and then to desired channel layout */
> +
> +   convert_sample_format(link, samplesref);
> +   convert_channel_layout(link, resample->temp_samples);
> +
> +   avfilter_filter_samples(outlink, avfilter_ref_samples(samplesref, ~0));
> +}
> +
> +AVFilter avfilter_af_resample = {
> +    .name        = "resample",

> +    .description = "Reformat the input audio to sample_fmt:channel_layout.",

NULL_IF_CONFIG_SMALL

[...]

Regards.
-- 
FFmpeg = Faithless and Fancy Minimal Purposeless Easy God



More information about the ffmpeg-devel mailing list