[FFmpeg-devel] [ffmpeg-devel] [PATCH 3/4] lavfi: add audio convert filter
Stefano Sabatini
stefano.sabatini-lala at poste.it
Wed Jul 27 15:49:05 CEST 2011
On date Wednesday 2011-07-27 01:05:19 +0300, Mina Nagy Zaki encoded:
> Add aconvert filter to perform sample format and channel layout conversion.
>
> Based on code by Stefano Sabatini and "S.N. Hemanth Meenakshisundaram"
> smeenaks at ucsd.edu.
> ---
> libavfilter/Makefile | 1 +
> libavfilter/af_aconvert.c | 430 ++++++++++++++++++++++++++++++++++++
> libavfilter/af_aconvert_rematrix.c | 185 ++++++++++++++++
> libavfilter/allfilters.c | 1 +
Missing docs (can be added later when we approach to the final
revision).
> 4 files changed, 617 insertions(+), 0 deletions(-)
> create mode 100644 libavfilter/af_aconvert.c
> create mode 100644 libavfilter/af_aconvert_rematrix.c
>
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 83b906d..0e6051b 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -18,6 +18,7 @@ OBJS = allfilters.o \
>
> OBJS-$(CONFIG_AVCODEC) += avcodec.o
>
> +OBJS-$(CONFIG_ACONVERT_FILTER) += af_aconvert.o
> OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o
> OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o
Missing dependency on libavcodec.
> diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c
> new file mode 100644
> index 0000000..0f8ba33
> --- /dev/null
> +++ b/libavfilter/af_aconvert.c
> @@ -0,0 +1,430 @@
> +/*
> + * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks at ucsd.edu>
> + * Copyright (c) 2011 Stefano Sabatini
> + * Copyright (c) 2011 Mina Nagy Zaki
> + *
> + * 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
> + * sample format and channel layout conversion audio filter
> + * based on code in libavcodec/resample.c by Fabrice Bellard and
> + * libavcodec/audioconvert.c by Michael Niedermayer
> + */
> +
> +#include "avfilter.h"
> +#include "libavcodec/audioconvert.h"
> +
> +#define SFMT_t uint8_t
FMT_TYPE (or SFMT_TYPE) looks more readable to my eyes
> +#define REMATRIX(FUNC) FUNC ## _u8
For clarity:
#define REMATRIX_FUNC_NAME(PREFIX) PREFIX ## _u8
> +#include "af_aconvert_rematrix.c"
> +
> +#define SFMT_t int16_t
> +#define REMATRIX(FUNC) FUNC ## _s16
> +#include "af_aconvert_rematrix.c"
> +
> +#define SFMT_t int32_t
> +#define REMATRIX(FUNC) FUNC ## _s32
> +#include "af_aconvert_rematrix.c"
> +
> +#define FLOATING
> +
> +#define SFMT_t float
> +#define REMATRIX(FUNC) FUNC ## _flt
> +#include "af_aconvert_rematrix.c"
> +
> +#define SFMT_t double
> +#define REMATRIX(FUNC) FUNC ## _dbl
> +#include "af_aconvert_rematrix.c"
> +
> +typedef struct {
> + int nb_samples; ///< current size of buffers
confusing... nb != size
> + enum AVSampleFormat out_sample_fmt; ///< output sample format
> + int64_t out_chlayout; ///< output channel layout
> +
> + int out_strides[8],
> + in_strides [8];
> +
> + AVFilterBufferRef *mix_samplesref; ///< rematrixed buffer
> + AVFilterBufferRef *out_samplesref; ///< output buffer after required conversions
> + uint8_t *packed_data[8]; ///< pointers for packing conversion
> + uint8_t **in_data, **out_data; ///< input/output for av_audio_convert
> +
> + AVAudioConvert *audioconvert_ctx; ///< context for conversion to output sample format
> +
> + void (*convert_chlayout) ();
> +} AConvertContext;
> +
> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> +{
> + AConvertContext *aconvert = ctx->priv;
> + char sample_fmt_str[8] = "", chlayout_str[32] = "";
32 is not enough for the layout
> +
> + if (args)
> + sscanf(args, "%8[^:]:%32s", sample_fmt_str, chlayout_str);
> +
> + aconvert->out_sample_fmt =
> + *sample_fmt_str ? av_get_sample_fmt(sample_fmt_str) : AV_SAMPLE_FMT_NONE;
> +
> + if (*sample_fmt_str && aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE) {
> + /* -1 is a valid value for out_sample_fmt and indicates no change
> + * in sample format. */
Nit: s/-1/AV_SAMPLE_FMT_NONE/
> + char *tail;
> + aconvert->out_sample_fmt = strtol(sample_fmt_str, &tail, 10);
> + if (*tail || (aconvert->out_sample_fmt >= AV_SAMPLE_FMT_NB &&
> + aconvert->out_sample_fmt != -1)) {
> + av_log(ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n",
> + sample_fmt_str);
> + return AVERROR(EINVAL);
> + }
> + }
> +
> + aconvert->out_chlayout = *chlayout_str ?
> + av_get_channel_layout(chlayout_str) : -1;
> +
> + if (*chlayout_str && aconvert->out_chlayout < AV_CH_LAYOUT_STEREO) {
> + /* -1 is a valid value for out_chlayout and indicates no change
> + * in channel layout. */
> + char *tail;
> + aconvert->out_chlayout = strtol(chlayout_str, &tail, 10);
> + if (*tail || (aconvert->out_chlayout < AV_CH_LAYOUT_STEREO &&
> + aconvert->out_chlayout != -1)) {
> + av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s\n",
> + chlayout_str);
> + return AVERROR(EINVAL);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static av_cold void uninit(AVFilterContext *ctx)
> +{
> + AConvertContext *aconvert = ctx->priv;
> + avfilter_unref_buffer(aconvert->mix_samplesref);
> + avfilter_unref_buffer(aconvert->out_samplesref);
aconvert->X_samplesref = NULL may be safer.
> + if (aconvert->audioconvert_ctx)
> + av_audio_convert_free(aconvert->audioconvert_ctx);
I never remember if we memset the priv context to 0 on uninit, if this
is the case no need to set it manually.
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> + AVFilterFormats *formats = NULL;
> + AConvertContext *aconvert = ctx->priv;
> +
> + avfilter_formats_ref(avfilter_all_packing_formats(),
> + &ctx->outputs[0]->in_packing);
> + avfilter_formats_ref(avfilter_all_packing_formats(),
> + &ctx->inputs[0]->out_packing);
> +
> + avfilter_formats_ref(avfilter_all_formats(AVMEDIA_TYPE_AUDIO),
> + &ctx->inputs[0]->out_formats);
> + if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
> + avfilter_add_format(&formats, aconvert->out_sample_fmt);
> + avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats);
> + } else
> + avfilter_formats_ref(avfilter_all_formats(AVMEDIA_TYPE_AUDIO),
> + &ctx->outputs[0]->in_formats);
> +
> + avfilter_formats_ref(avfilter_all_channel_layouts(),
> + &ctx->inputs[0]->out_chlayouts);
> + if (aconvert->out_chlayout != -1) {
> + formats = NULL;
> + avfilter_add_format(&formats, aconvert->out_chlayout);
> + avfilter_formats_ref(formats, &ctx->outputs[0]->in_chlayouts);
> + } else
> + avfilter_formats_ref(avfilter_all_channel_layouts(),
> + &ctx->outputs[0]->in_chlayouts);
> +
> + return 0;
> +}
> +
> +#define CHOOSE_FUNC_SFMT(FUNC) \
I suggest the name:
SET_CONVERT_CHLAYOUT(PREFIX)
> + switch (inlink->format) { \
> + case AV_SAMPLE_FMT_U8: \
> + aconvert->convert_chlayout = FUNC ## _u8; break; \
> + case AV_SAMPLE_FMT_S16: \
> + aconvert->convert_chlayout = FUNC ## _s16; break; \
> + case AV_SAMPLE_FMT_S32: \
> + aconvert->convert_chlayout = FUNC ## _s32; break; \
> + case AV_SAMPLE_FMT_FLT: \
> + aconvert->convert_chlayout = FUNC ## _flt; break; \
> + case AV_SAMPLE_FMT_DBL: \
> + aconvert->convert_chlayout = FUNC ## _dbl; break; \
> + }
> +
> +#define CHOOSE_FUNC(OUT, FUNC) \
> + if (aconvert->out_chlayout == OUT) { \
> + if (inlink->planar) \
> + CHOOSE_FUNC_SFMT(FUNC ## _planar) \
> + else \
> + CHOOSE_FUNC_SFMT(FUNC ## _packed) \
> + }
> +
> +#define CHOOSE_FUNC2(IN, OUT, FUNC) \
> + if (inlink->channel_layout == IN && \
> + aconvert->out_chlayout == OUT) { \
> + if (inlink->planar) \
> + CHOOSE_FUNC_SFMT(FUNC ## _planar) \
> + else \
> + CHOOSE_FUNC_SFMT(FUNC ## _packed) \
> + }
> +
> +static int config_output(AVFilterLink *outlink)
> +{
> + AVFilterLink *inlink = outlink->src->inputs[0];
> + AConvertContext *aconvert = outlink->src->priv;
> + char buf1[32], buf2[32];
Is 32 enough?
> + /* if not specified in args, use the format and layout of the output */
> + if (aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE)
> + aconvert->out_sample_fmt = outlink->format;
> + if (aconvert->out_chlayout == -1)
> + aconvert->out_chlayout = outlink->channel_layout;
> +
> + av_get_channel_layout_string(buf1, sizeof(buf1),
> + -1, inlink ->channel_layout);
> + av_get_channel_layout_string(buf2, sizeof(buf2),
> + -1, outlink->channel_layout);
> + av_log(outlink->src, AV_LOG_INFO, "fmt:%s cl:%s planar:%i -> fmt:%s cl:%s planar:%i\n",
> + av_get_sample_fmt_name(inlink ->format), buf1, inlink->planar,
> + av_get_sample_fmt_name(outlink->format), buf2, outlink->planar);
> +
> + /* handle stereo_to_mono and mono_to_stereo separately because there are
> + * no planar versions */
> + if (!inlink->planar &&
> + inlink->channel_layout == AV_CH_LAYOUT_STEREO &&
> + aconvert->out_chlayout == AV_CH_LAYOUT_MONO) {
> + CHOOSE_FUNC_SFMT(stereo_to_mono_packed);
> + }
> + else
> + if (!outlink->planar &&
> + inlink->channel_layout == AV_CH_LAYOUT_MONO &&
> + aconvert->out_chlayout == AV_CH_LAYOUT_STEREO) {
> + CHOOSE_FUNC_SFMT(mono_to_stereo_packed);
> + }
> +
> + if (!aconvert->convert_chlayout &&
> + inlink->channel_layout != outlink->channel_layout) {
> + CHOOSE_FUNC2(AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_5POINT1, ac3_5p1_mux)
> + else CHOOSE_FUNC2(AV_CH_LAYOUT_5POINT1, AV_CH_LAYOUT_STEREO, surround_to_stereo)
> + else CHOOSE_FUNC( AV_CH_LAYOUT_MONO, mono_downmix)
> + }
> +
> + /* If there's no channel conversion function and output is stereo,
> + * we can do generic stereo downmixing:
> + * if there's a format conversion then stereo downmixing is implicitly
> + * done by av_audio_convert.
> + * if there's no format conversion then packed stereo downmixing is
> + * explicitly done by av_audio_convert, while planar is done in
> + * filter_samples
> + */
> + if (!aconvert->convert_chlayout &&
> + outlink->channel_layout != inlink->channel_layout &&
> + outlink->channel_layout != AV_CH_LAYOUT_STEREO) {
> + av_log(outlink->src, AV_LOG_ERROR,
> + "Unsupported channel layout conversion requested!\n");
> + return AVERROR(EINVAL);
> + }
This is a bit messy, but nothing we can do about it. Anyway I'd like
to test this conversion code with the audio lavfi script, once it is
ready, before to commit this.
> +
> + return 0;
> +}
> +
> +static void init_buffers(AVFilterLink *inlink, int nb_samples)
> +{
> + AConvertContext *aconvert = inlink->dst->priv;
> + AVFilterLink * const outlink = inlink->dst->outputs[0];
> + int i, packed_stride = 0;
> + int in_channels =
> + av_get_channel_layout_nb_channels(inlink->channel_layout),
> + out_channels =
> + av_get_channel_layout_nb_channels(outlink->channel_layout);
> + const short
> + stereo_downmix = inlink->channel_layout != outlink->channel_layout &&
> + !aconvert->convert_chlayout,
> + format_conv = inlink->format != outlink->format,
> + packing_conv = inlink->planar != outlink->planar &&
> + in_channels != 1 &&
> + out_channels != 1;
> +
> + aconvert->nb_samples = nb_samples;
> + uninit(inlink->dst);
> +
> + // rematrixing
> + if (aconvert->convert_chlayout) {
> + aconvert->mix_samplesref =
> + avfilter_get_audio_buffer(outlink,
> + AV_PERM_WRITE | AV_PERM_REUSE2,
> + inlink->format,
> + nb_samples,
> + outlink->channel_layout,
> + inlink->planar);
> + in_channels = out_channels;
> + }
> +
> + /* If there's any conversion left to do, we need a buffer */
> + if (format_conv || packing_conv || stereo_downmix) {
> + aconvert->out_samplesref = avfilter_get_audio_buffer(outlink,
> + AV_PERM_WRITE | AV_PERM_REUSE2,
> + outlink->format,
> + nb_samples,
> + outlink->channel_layout,
> + outlink->planar);
> + }
> +
> + /* if there's a format/mode conversion or packed stereo downmixing,
> + * we need an audio_convert context
> + */
> + if (format_conv || packing_conv || (stereo_downmix && !outlink->planar)) {
> + aconvert->in_strides[0] = av_get_bytes_per_sample(inlink->format);
> + aconvert->out_strides[0] = av_get_bytes_per_sample(outlink->format);
> +
> + aconvert->out_data = aconvert->out_samplesref->data;
> + if (aconvert->mix_samplesref)
> + aconvert->in_data = aconvert->mix_samplesref->data;
> +
> + if (packing_conv) {
> + if (outlink->planar) {
> + if (aconvert->mix_samplesref)
> + aconvert->packed_data[0] =
> + aconvert->mix_samplesref->data[0];
> + aconvert->in_data = aconvert->packed_data;
> + packed_stride = aconvert->in_strides[0];
> + aconvert->in_strides[0] *= in_channels;
> + } else {
> + aconvert->packed_data[0] = aconvert->out_samplesref->data[0];
> + aconvert->out_data = aconvert->packed_data;
> + packed_stride = aconvert->out_strides[0];
> + aconvert->out_strides[0] *= out_channels;
> + }
> + } else if (!outlink->planar) {
> + out_channels = 1;
> + }
> +
> + for (i = 1; i < out_channels; i++) {
> + aconvert->packed_data[i] = aconvert->packed_data[i-1] +
> + packed_stride;
> + aconvert->in_strides[i] = aconvert->in_strides[0];
> + aconvert->out_strides[i] = aconvert->out_strides[0];
> + }
> +
> + aconvert->audioconvert_ctx =
> + av_audio_convert_alloc(outlink->format, out_channels,
> + inlink->format, out_channels, NULL, 0);
Add a check here, just to be sure (or an av_assert if you're lazy).
> + }
> +
> +}
> +
> +static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
> +{
> + AConvertContext *aconvert = inlink->dst->priv;
> + AVFilterBufferRef *curbuf = insamplesref;
> + AVFilterLink * const outlink = inlink->dst->outputs[0];
> + int nb_channels = av_get_channel_layout_nb_channels(
> + curbuf->audio->channel_layout);
> +
> + if (!aconvert->nb_samples ||
> + (curbuf->audio->nb_samples > aconvert->nb_samples))
> + init_buffers(inlink, curbuf->audio->nb_samples);
> +
> + if (aconvert->mix_samplesref) {
> + if (inlink->planar && nb_channels != 1)
> + aconvert->convert_chlayout(aconvert->mix_samplesref->data,
> + curbuf->data,
> + curbuf->audio->nb_samples,
> + nb_channels);
> + else
> + aconvert->convert_chlayout(aconvert->mix_samplesref->data[0],
> + curbuf->data[0],
> + curbuf->audio->nb_samples,
> + nb_channels);
> +
> + aconvert->mix_samplesref->audio->nb_samples =
> + curbuf->audio->nb_samples;
> + curbuf = aconvert->mix_samplesref;
> +
> + }
> +
> + if (aconvert->audioconvert_ctx) {
> + if (!aconvert->mix_samplesref) {
> + if (aconvert->in_data == aconvert->packed_data) {
> + int i, packed_stride = av_get_bytes_per_sample(inlink->format);
> + aconvert->packed_data[0] = curbuf->data[0];
> + for (i = 1; i < nb_channels; i++)
> + aconvert->packed_data[i] =
> + aconvert->packed_data[i-1] + packed_stride;
> + } else {
> + aconvert->in_data = curbuf->data;
> + }
> + }
> +
> + if (inlink->planar == outlink->planar && !outlink->planar)
> + nb_channels = av_get_channel_layout_nb_channels(
> + curbuf->audio->channel_layout);
> + else
> + nb_channels = 1;
> +
> + av_audio_convert(aconvert->audioconvert_ctx,
> + (void * const *) aconvert->out_data,
> + aconvert->out_strides,
> + (const void * const *) aconvert->in_data,
> + aconvert->in_strides,
> + curbuf->audio->nb_samples * nb_channels);
> +
> + aconvert->out_samplesref->audio->nb_samples =
> + curbuf->audio->nb_samples;
> + curbuf = aconvert->out_samplesref;
> + }
> +
> + /* Handle generic planar stereo downmixing */
> + if (!aconvert->convert_chlayout && !aconvert->audioconvert_ctx &&
> + outlink->channel_layout == AV_CH_LAYOUT_STEREO) {
> + int size =
> + av_get_bytes_per_sample(inlink->format) * curbuf->audio->nb_samples;
> + if (nb_channels == 1) curbuf->data[1] = curbuf->data[0];
> + memcpy(aconvert->out_samplesref->data[0],curbuf->data[0], size);
> + memcpy(aconvert->out_samplesref->data[1], curbuf->data[1], size);
> + aconvert->out_samplesref->audio->nb_samples =
> + curbuf->audio->nb_samples;
> + curbuf = aconvert->out_samplesref;
> + }
> +
> + avfilter_filter_samples(inlink->dst->outputs[0],
> + avfilter_ref_buffer(curbuf, ~0));
> + avfilter_unref_buffer(insamplesref);
> +}
> +
> +AVFilter avfilter_af_aconvert = {
> + .name = "aconvert",
> + .description = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout."),
> + .priv_size = sizeof(AConvertContext),
> + .init = init,
> + .uninit = uninit,
> + .query_formats = query_formats,
> +
> + .inputs = (AVFilterPad[]) {{ .name = "default",
> + .type = AVMEDIA_TYPE_AUDIO,
> + .filter_samples = filter_samples,
> + .min_perms = AV_PERM_READ, },
> + { .name = NULL}},
> + .outputs = (AVFilterPad[]) {{ .name = "default",
> + .type = AVMEDIA_TYPE_AUDIO,
> + .config_props = config_output, },
> + { .name = NULL}},
> +};
> diff --git a/libavfilter/af_aconvert_rematrix.c b/libavfilter/af_aconvert_rematrix.c
> new file mode 100644
> index 0000000..3e538e7
> --- /dev/null
> +++ b/libavfilter/af_aconvert_rematrix.c
> @@ -0,0 +1,185 @@
> +/*
> + * Copyright (c) 2011 Mina Nagy Zaki
> + *
> + * 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
> + * audio rematrixing functions
> + */
> +
> +#if defined(FLOATING)
> +# define DIV2 /2
> +#else
> +# define DIV2 >>1
> +#endif
> +
> +#define REMATRIX_FUNC_PACKED(FUNC) static void REMATRIX(FUNC) \
> + (SFMT_t *out, SFMT_t *in, int nb_samples, int in_channels)
I suggest (SIG -> signature):
#define REMATRIX_FUNC_PACKED_SIG(PREFIX) \
static void REMATRIX_FUNC_NAME(PREFIX) (FMT_TYPE *out, FMT_TYPE *in, int nb_samples, int in_channels)
> +#define REMATRIX_FUNC_PLANAR(FUNC) static void REMATRIX(FUNC) \
> + (SFMT_t *outp[], SFMT_t *inp[], int nb_samples, int in_channels)
> +
> +REMATRIX_FUNC_PACKED(stereo_to_mono_packed)
> +{
> + while (nb_samples >= 4) {
> + out[0] = (in[0] + in[1]) DIV2;
> + out[1] = (in[2] + in[3]) DIV2;
> + out[2] = (in[4] + in[5]) DIV2;
> + out[3] = (in[6] + in[7]) DIV2;
> + out += 4;
> + in += 8;
> + nb_samples -= 4;
> + }
> + while (nb_samples--) {
> + out[0] = (in[0] + in[1]) DIV2;
> + out++;
> + in += 2;
> + }
> +}
> +
> +REMATRIX_FUNC_PACKED(mono_to_stereo_packed)
> +{
> + while (nb_samples >= 4) {
> + out[0] = out[1] = in[0];
> + out[2] = out[3] = in[1];
> + out[4] = out[5] = in[2];
> + out[6] = out[7] = in[3];
> + out += 8;
> + in += 4;
> + nb_samples -= 4;
> + }
> + while (nb_samples--) {
> + out[0] = out[1] = in[0];
> + out += 2;
> + in += 1;
> + }
> +}
why the nb_samples >= 4 special casing?
> +
> +/**
> + * This is for when we have more than 2 input channels, need to downmix to mono
> + * and do not have a conversion formula available. We just use first two input
> + * channels - left and right. This is a placeholder until more conversion
> + * functions are written.
> + */
> +REMATRIX_FUNC_PACKED(mono_downmix_packed)
> +{
> + while (nb_samples--) {
> + out[0] = (in[0] + in[1]) DIV2;
> + in += in_channels;
> + out++;
> + }
> +}
> +
> +REMATRIX_FUNC_PLANAR(mono_downmix_planar)
> +{
> + SFMT_t *in[2], *out = outp[0];
> + in[0] = inp[0];
> + in[1] = inp[1];
> +
> + while (nb_samples >= 4) {
> + out[0] = (in[0][0] + in[1][0]) DIV2;
> + out[1] = (in[0][1] + in[1][1]) DIV2;
> + out[2] = (in[0][2] + in[1][2]) DIV2;
> + out[3] = (in[0][3] + in[1][3]) DIV2;
> + out += 4;
> + in[0] += 4;
> + in[1] += 4;
> + nb_samples -= 4;
> + }
> + while (nb_samples--) {
> + out[0] = (in[0][0] + in[1][0]) DIV2;
> + out++;
> + in[0]++;
> + in[1]++;
> + }
> +
> +}
> +
> +/* Stereo to 5.1 output */
> +REMATRIX_FUNC_PACKED(ac3_5p1_mux_packed)
the function name is obfuscated, what about stereo_to_5p1_packed?
> +{
> + while (nb_samples--) {
> + out[0] = in[0]; /* left */
> + out[1] = in[1]; /* right */
> + out[2] = (in[0] + in[1]) DIV2; /* center */
> + out[3] = 0; /* low freq */
> + out[4] = 0; /* FIXME: left surround: -3dB or -6dB or -9dB of stereo left */
> + out[5] = 0; /* FIXME: right surroud: -3dB or -6dB or -9dB of stereo right */
> + in += 2;
> + out += 6;
> + }
> +}
> +
> +REMATRIX_FUNC_PLANAR(ac3_5p1_mux_planar)
> +{
> + SFMT_t *in[2], *out[6];
> + in[0] = inp[0]; in[1] = inp[1];
> + out[0] = outp[0]; out[1] = outp[1];
> + out[2] = outp[2]; out[3] = outp[3];
> + out[4] = outp[4]; out[5] = outp[5];
> +
> + while (nb_samples--) {
> + *out[0]++ = *in[0]; /* left */
> + *out[1]++ = *in[1]; /* right */
> + *out[2]++ = (*in[0] + *in[1]) DIV2; /* center */
> + *out[3]++ = 0; /* low freq */
> + *out[4]++ = 0; /* FIXME: left surround: -3dB or -6dB or -9dB of stereo left */
> + *out[5]++ = 0; /* FIXME: right surroud: -3dB or -6dB or -9dB of stereo right */
> + in[0]++; in[1]++;
> + }
> +}
> +
> +
> +/*
> +5.1 to stereo input: [fl, fr, c, lfe, rl, rr]
> +- Left = front_left + rear_gain * rear_left + center_gain * center
> +- Right = front_right + rear_gain * rear_right + center_gain * center
> +Where rear_gain is usually around 0.5-1.0 and
> + center_gain is almost always 0.7 (-3 dB)
> +*/
> +REMATRIX_FUNC_PACKED(surround_to_stereo_packed)
again, maybe 5p1_to_stereo_packed for readability
> +{
> + while (nb_samples--) {
> + *out++ = in[0] + (0.5 * in[4]) + (0.7 * in[2]); //FIXME CLIPPING!
> + *out++ = in[1] + (0.5 * in[5]) + (0.7 * in[2]); //FIXME CLIPPING!
> +
> + in += 6;
> + }
> +}
> +
> +REMATRIX_FUNC_PLANAR(surround_to_stereo_planar)
> +{
> + SFMT_t *in[6], *out[2];
> + out[0] = outp[0];
> + out[1] = outp[1];
> + in[0] = inp[0]; in[1] = inp[1];
> + in[2] = inp[2]; in[3] = inp[3];
> + in[4] = inp[4]; in[5] = inp[5];
> +
> + while (nb_samples--) {
> + *out[0]++ = *in[0] + (0.5 * *in[4]) + (0.7 * *in[2]); //FIXME CLIPPING!
> + *out[1]++ = *in[1] + (0.5 * *in[5]) + (0.7 * *in[2]); //FIXME CLIPPING!
> +
> + in[0]++; in[1]++; in[2]++; in[3]++; in[4]++; in[5]++;
> + }
> +}
More information about the ffmpeg-devel
mailing list