[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