libavresample: Remove deprecated library

Deprecated in c29038f304.
The resample filter based upon this library has been removed as well.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
Andreas Rheinhardt 2021-04-14 04:33:24 +02:00 committed by James Almer
parent d40bb518b5
commit 420cedd497
59 changed files with 5 additions and 10167 deletions

View File

@ -23,7 +23,6 @@ FFLIBS-$(CONFIG_AVDEVICE) += avdevice
FFLIBS-$(CONFIG_AVFILTER) += avfilter
FFLIBS-$(CONFIG_AVFORMAT) += avformat
FFLIBS-$(CONFIG_AVCODEC) += avcodec
FFLIBS-$(CONFIG_AVRESAMPLE) += avresample
FFLIBS-$(CONFIG_POSTPROC) += postproc
FFLIBS-$(CONFIG_SWRESAMPLE) += swresample
FFLIBS-$(CONFIG_SWSCALE) += swscale

16
configure vendored
View File

@ -132,7 +132,6 @@ Component options:
--disable-swscale disable libswscale build
--disable-postproc disable libpostproc build
--disable-avfilter disable libavfilter build
--enable-avresample enable libavresample build (deprecated) [no]
--disable-pthreads disable pthreads [autodetect]
--disable-w32threads disable Win32 threads [autodetect]
--disable-os2threads disable OS/2 threads [autodetect]
@ -1901,7 +1900,6 @@ LIBRARY_LIST="
avformat
avcodec
swresample
avresample
avutil
"
@ -3609,7 +3607,6 @@ program_opencl_filter_deps="opencl"
pullup_filter_deps="gpl"
removelogo_filter_deps="avcodec avformat swscale"
repeatfields_filter_deps="gpl"
resample_filter_deps="avresample"
roberts_opencl_filter_deps="opencl"
rubberband_filter_deps="librubberband"
sab_filter_deps="gpl swscale"
@ -3711,8 +3708,6 @@ avfilter_deps="avutil"
avfilter_suggest="libm"
avformat_deps="avcodec avutil"
avformat_suggest="libm network zlib"
avresample_deps="avutil"
avresample_suggest="libm"
avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt"
postproc_deps="avutil gpl"
postproc_suggest="libm"
@ -3795,7 +3790,7 @@ intrinsics="none"
enable $PROGRAM_LIST
enable $DOCUMENT_LIST
enable $EXAMPLE_LIST
enable $(filter_out avresample $LIBRARY_LIST)
enable $LIBRARY_LIST
enable stripping
enable asm
@ -6845,7 +6840,7 @@ EOF
# add some linker flags
check_ldflags -Wl,--warn-common
check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample
check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil
enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir
test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic
@ -6860,8 +6855,7 @@ enabled neon_clobber_test &&
-Wl,--wrap,avcodec_receive_packet \
-Wl,--wrap,avcodec_send_frame \
-Wl,--wrap,avcodec_receive_frame \
-Wl,--wrap,swr_convert \
-Wl,--wrap,avresample_convert ||
-Wl,--wrap,swr_convert ||
disable neon_clobber_test
enabled xmm_clobber_test &&
@ -6873,7 +6867,6 @@ enabled xmm_clobber_test &&
-Wl,--wrap,avcodec_send_frame \
-Wl,--wrap,avcodec_receive_frame \
-Wl,--wrap,swr_convert \
-Wl,--wrap,avresample_convert \
-Wl,--wrap,sws_scale ||
disable xmm_clobber_test
@ -7098,7 +7091,6 @@ check_deps $CONFIG_LIST \
$ALL_COMPONENTS \
enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86"
enabled avresample && warn "Building with deprecated library libavresample"
case $target_os in
haiku)
@ -7214,7 +7206,6 @@ enabled movie_filter && prepend avfilter_deps "avformat avcodec"
enabled pan_filter && prepend avfilter_deps "swresample"
enabled pp_filter && prepend avfilter_deps "postproc"
enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale"
enabled resample_filter && prepend avfilter_deps "avresample"
enabled sab_filter && prepend avfilter_deps "swscale"
enabled scale_filter && prepend avfilter_deps "swscale"
enabled scale2ref_filter && prepend avfilter_deps "swscale"
@ -7707,7 +7698,6 @@ extralibs_avcodec="$avcodec_extralibs"
extralibs_avformat="$avformat_extralibs"
extralibs_avdevice="$avdevice_extralibs"
extralibs_avfilter="$avfilter_extralibs"
extralibs_avresample="$avresample_extralibs"
extralibs_postproc="$postproc_extralibs"
extralibs_swscale="$swscale_extralibs"
extralibs_swresample="$swresample_extralibs"

View File

@ -6,7 +6,6 @@ libavcodec: 2017-10-21
libavdevice: 2017-10-21
libavfilter: 2017-10-21
libavformat: 2017-10-21
libavresample: 2017-10-21
libpostproc: 2017-10-21
libswresample: 2017-10-21
libswscale: 2017-10-21

View File

@ -26,7 +26,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_LINK)/

View File

@ -34,7 +34,6 @@
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libavresample/avresample.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libpostproc/postprocess.h"
@ -545,9 +544,6 @@ int opt_default(void *optctx, const char *opt, const char *arg)
char opt_stripped[128];
const char *p;
const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class();
#if CONFIG_AVRESAMPLE
const AVClass *rc = avresample_get_class();
#endif
#if CONFIG_SWSCALE
const AVClass *sc = sws_get_class();
#endif
@ -617,13 +613,6 @@ int opt_default(void *optctx, const char *opt, const char *arg)
consumed = 1;
}
#endif
#if CONFIG_AVRESAMPLE
if ((o=opt_find(&rc, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
av_dict_set(&resample_opts, opt, arg, FLAGS);
consumed = 1;
}
#endif
if (consumed)
return 0;
@ -1134,7 +1123,6 @@ static void print_all_libs_info(int flags, int level)
PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);
PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
PRINT_LIB_INFO(swscale, SWSCALE, flags, level);
PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);
PRINT_LIB_INFO(postproc, POSTPROC, flags, level);

View File

@ -26,8 +26,6 @@
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavresample/avresample.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"

View File

@ -135,7 +135,6 @@ OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o
OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o
OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
OBJS-$(CONFIG_RUBBERBAND_FILTER) += af_rubberband.o
OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER) += af_sidechaincompress.o
OBJS-$(CONFIG_SIDECHAINGATE_FILTER) += af_agate.o

View File

@ -1,369 +0,0 @@
/*
* 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
*/
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavresample/avresample.h"
#include "audio.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
typedef struct ResampleContext {
const AVClass *class;
AVAudioResampleContext *avr;
AVDictionary *options;
int resampling;
int64_t next_pts;
int64_t next_in_pts;
/* set by filter_frame() to signal an output frame to request_frame() */
int got_output;
} ResampleContext;
static av_cold int init(AVFilterContext *ctx, AVDictionary **opts)
{
ResampleContext *s = ctx->priv;
const AVClass *avr_class = avresample_get_class();
AVDictionaryEntry *e = NULL;
while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
if (av_opt_find(&avr_class, e->key, NULL, 0,
AV_OPT_SEARCH_FAKE_OBJ | AV_OPT_SEARCH_CHILDREN))
av_dict_set(&s->options, e->key, e->value, 0);
}
e = NULL;
while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX)))
av_dict_set(opts, e->key, NULL, 0);
/* do not allow the user to override basic format options */
av_dict_set(&s->options, "in_channel_layout", NULL, 0);
av_dict_set(&s->options, "out_channel_layout", NULL, 0);
av_dict_set(&s->options, "in_sample_fmt", NULL, 0);
av_dict_set(&s->options, "out_sample_fmt", NULL, 0);
av_dict_set(&s->options, "in_sample_rate", NULL, 0);
av_dict_set(&s->options, "out_sample_rate", NULL, 0);
return 0;
}
static av_cold void uninit(AVFilterContext *ctx)
{
ResampleContext *s = ctx->priv;
if (s->avr) {
avresample_close(s->avr);
avresample_free(&s->avr);
}
av_dict_free(&s->options);
}
static int query_formats(AVFilterContext *ctx)
{
AVFilterLink *inlink = ctx->inputs[0];
AVFilterLink *outlink = ctx->outputs[0];
AVFilterFormats *in_formats, *out_formats, *in_samplerates, *out_samplerates;
AVFilterChannelLayouts *in_layouts, *out_layouts;
int ret;
if (!(in_formats = ff_all_formats (AVMEDIA_TYPE_AUDIO)) ||
!(out_formats = ff_all_formats (AVMEDIA_TYPE_AUDIO)) ||
!(in_samplerates = ff_all_samplerates ( )) ||
!(out_samplerates = ff_all_samplerates ( )) ||
!(in_layouts = ff_all_channel_layouts ( )) ||
!(out_layouts = ff_all_channel_layouts ( )))
return AVERROR(ENOMEM);
if ((ret = ff_formats_ref (in_formats, &inlink->outcfg.formats )) < 0 ||
(ret = ff_formats_ref (out_formats, &outlink->incfg.formats )) < 0 ||
(ret = ff_formats_ref (in_samplerates, &inlink->outcfg.samplerates )) < 0 ||
(ret = ff_formats_ref (out_samplerates, &outlink->incfg.samplerates )) < 0 ||
(ret = ff_channel_layouts_ref (in_layouts, &inlink->outcfg.channel_layouts)) < 0 ||
(ret = ff_channel_layouts_ref (out_layouts, &outlink->incfg.channel_layouts)) < 0)
return ret;
return 0;
}
static int config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
AVFilterLink *inlink = ctx->inputs[0];
ResampleContext *s = ctx->priv;
char buf1[64], buf2[64];
int ret;
int64_t resampling_forced;
if (s->avr) {
avresample_close(s->avr);
avresample_free(&s->avr);
}
if (inlink->channel_layout == outlink->channel_layout &&
inlink->sample_rate == outlink->sample_rate &&
(inlink->format == outlink->format ||
(av_get_channel_layout_nb_channels(inlink->channel_layout) == 1 &&
av_get_channel_layout_nb_channels(outlink->channel_layout) == 1 &&
av_get_planar_sample_fmt(inlink->format) ==
av_get_planar_sample_fmt(outlink->format))))
return 0;
if (!(s->avr = avresample_alloc_context()))
return AVERROR(ENOMEM);
if (s->options) {
int ret;
AVDictionaryEntry *e = NULL;
while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX)))
av_log(ctx, AV_LOG_VERBOSE, "lavr option: %s=%s\n", e->key, e->value);
ret = av_opt_set_dict(s->avr, &s->options);
if (ret < 0)
return ret;
}
av_opt_set_int(s->avr, "in_channel_layout", inlink ->channel_layout, 0);
av_opt_set_int(s->avr, "out_channel_layout", outlink->channel_layout, 0);
av_opt_set_int(s->avr, "in_sample_fmt", inlink ->format, 0);
av_opt_set_int(s->avr, "out_sample_fmt", outlink->format, 0);
av_opt_set_int(s->avr, "in_sample_rate", inlink ->sample_rate, 0);
av_opt_set_int(s->avr, "out_sample_rate", outlink->sample_rate, 0);
if ((ret = avresample_open(s->avr)) < 0)
return ret;
av_opt_get_int(s->avr, "force_resampling", 0, &resampling_forced);
s->resampling = resampling_forced || (inlink->sample_rate != outlink->sample_rate);
if (s->resampling) {
outlink->time_base = (AVRational){ 1, outlink->sample_rate };
s->next_pts = AV_NOPTS_VALUE;
s->next_in_pts = AV_NOPTS_VALUE;
} else
outlink->time_base = inlink->time_base;
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(ctx, AV_LOG_VERBOSE,
"fmt:%s srate:%d cl:%s -> fmt:%s srate:%d cl:%s\n",
av_get_sample_fmt_name(inlink ->format), inlink ->sample_rate, buf1,
av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf2);
return 0;
}
static int request_frame(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
ResampleContext *s = ctx->priv;
int ret = 0;
s->got_output = 0;
while (ret >= 0 && !s->got_output)
ret = ff_request_frame(ctx->inputs[0]);
/* flush the lavr delay buffer */
if (ret == AVERROR_EOF && s->avr) {
AVFrame *frame;
int nb_samples = avresample_get_out_samples(s->avr, 0);
if (!nb_samples)
return ret;
frame = ff_get_audio_buffer(outlink, nb_samples);
if (!frame)
return AVERROR(ENOMEM);
ret = avresample_convert(s->avr, frame->extended_data,
frame->linesize[0], nb_samples,
NULL, 0, 0);
if (ret <= 0) {
av_frame_free(&frame);
return (ret == 0) ? AVERROR_EOF : ret;
}
frame->nb_samples = ret;
frame->pts = s->next_pts;
return ff_filter_frame(outlink, frame);
}
return ret;
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
AVFilterContext *ctx = inlink->dst;
ResampleContext *s = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
int ret;
if (s->avr) {
AVFrame *out;
int delay, nb_samples;
/* maximum possible samples lavr can output */
delay = avresample_get_delay(s->avr);
nb_samples = avresample_get_out_samples(s->avr, in->nb_samples);
out = ff_get_audio_buffer(outlink, nb_samples);
if (!out) {
ret = AVERROR(ENOMEM);
goto fail;
}
ret = avresample_convert(s->avr, out->extended_data, out->linesize[0],
nb_samples, in->extended_data, in->linesize[0],
in->nb_samples);
if (ret <= 0) {
av_frame_free(&out);
if (ret < 0)
goto fail;
}
av_assert0(!avresample_available(s->avr));
if (s->resampling && s->next_pts == AV_NOPTS_VALUE) {
if (in->pts == AV_NOPTS_VALUE) {
av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, "
"assuming 0.\n");
s->next_pts = 0;
} else
s->next_pts = av_rescale_q(in->pts, inlink->time_base,
outlink->time_base);
}
if (ret > 0) {
out->nb_samples = ret;
ret = av_frame_copy_props(out, in);
if (ret < 0) {
av_frame_free(&out);
goto fail;
}
if (s->resampling) {
out->sample_rate = outlink->sample_rate;
/* Only convert in->pts if there is a discontinuous jump.
This ensures that out->pts tracks the number of samples actually
output by the resampler in the absence of such a jump.
Otherwise, the rounding in av_rescale_q() and av_rescale()
causes off-by-1 errors. */
if (in->pts != AV_NOPTS_VALUE && in->pts != s->next_in_pts) {
out->pts = av_rescale_q(in->pts, inlink->time_base,
outlink->time_base) -
av_rescale(delay, outlink->sample_rate,
inlink->sample_rate);
} else
out->pts = s->next_pts;
s->next_pts = out->pts + out->nb_samples;
s->next_in_pts = in->pts + in->nb_samples;
} else
out->pts = in->pts;
ret = ff_filter_frame(outlink, out);
s->got_output = 1;
}
fail:
av_frame_free(&in);
} else {
in->format = outlink->format;
ret = ff_filter_frame(outlink, in);
s->got_output = 1;
}
return ret;
}
#if FF_API_CHILD_CLASS_NEXT
static const AVClass *resample_child_class_next(const AVClass *prev)
{
return prev ? NULL : avresample_get_class();
}
#endif
static const AVClass *resample_child_class_iterate(void **iter)
{
const AVClass *c = *iter ? NULL : avresample_get_class();
*iter = (void*)(uintptr_t)c;
return c;
}
static void *resample_child_next(void *obj, void *prev)
{
ResampleContext *s = obj;
return prev ? NULL : s->avr;
}
static const AVClass resample_class = {
.class_name = "resample",
.item_name = av_default_item_name,
.version = LIBAVUTIL_VERSION_INT,
#if FF_API_CHILD_CLASS_NEXT
.child_class_next = resample_child_class_next,
#endif
.child_class_iterate = resample_child_class_iterate,
.child_next = resample_child_next,
};
static const AVFilterPad avfilter_af_resample_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
},
{ NULL }
};
static const AVFilterPad avfilter_af_resample_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.config_props = config_output,
.request_frame = request_frame
},
{ NULL }
};
AVFilter ff_af_resample = {
.name = "resample",
.description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."),
.priv_size = sizeof(ResampleContext),
.priv_class = &resample_class,
.init_dict = init,
.uninit = uninit,
.query_formats = query_formats,
.inputs = avfilter_af_resample_inputs,
.outputs = avfilter_af_resample_outputs,
};

View File

@ -129,7 +129,6 @@ extern AVFilter ff_af_lv2;
extern AVFilter ff_af_mcompand;
extern AVFilter ff_af_pan;
extern AVFilter ff_af_replaygain;
extern AVFilter ff_af_resample;
extern AVFilter ff_af_rubberband;
extern AVFilter ff_af_sidechaincompress;
extern AVFilter ff_af_sidechaingate;

View File

@ -1,19 +0,0 @@
NAME = avresample
DESC = Libav audio resampling library
HEADERS = avresample.h \
version.h \
OBJS = audio_convert.o \
audio_data.o \
audio_mix.o \
audio_mix_matrix.o \
dither.o \
options.o \
resample.o \
utils.o \
# Windows resource file
SLIBOBJS-$(HAVE_GNU_WINDRES) += avresampleres.o
TESTPROGS = avresample

View File

@ -1,7 +0,0 @@
OBJS += aarch64/audio_convert_init.o \
aarch64/resample_init.o \
OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o
NEON-OBJS += aarch64/audio_convert_neon.o \
aarch64/resample_neon.o \

View File

@ -1,28 +0,0 @@
/*
* 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
*/
#ifndef AVRESAMPLE_AARCH64_ASM_OFFSETS_H
#define AVRESAMPLE_AARCH64_ASM_OFFSETS_H
/* struct ResampleContext */
#define FILTER_BANK 0x10
#define FILTER_LENGTH 0x18
#define PHASE_SHIFT 0x34
#define PHASE_MASK (PHASE_SHIFT + 0x04) // loaded as pair
#endif /* AVRESAMPLE_AARCH64_ASM_OFFSETS_H */

View File

@ -1,49 +0,0 @@
/*
* 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
*/
#include <stdint.h>
#include "config.h"
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/aarch64/cpu.h"
#include "libavutil/samplefmt.h"
#include "libavresample/audio_convert.h"
void ff_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
void ff_conv_fltp_to_s16_neon(int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src,
int len, int channels);
av_cold void ff_audio_convert_init_aarch64(AudioConvert *ac)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT,
0, 16, 8, "NEON",
ff_conv_flt_to_s16_neon);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
2, 16, 8, "NEON",
ff_conv_fltp_to_s16_2ch_neon);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
0, 16, 8, "NEON",
ff_conv_fltp_to_s16_neon);
}
}

View File

@ -1,363 +0,0 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
* 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
*/
#include "config.h"
#include "libavutil/aarch64/asm.S"
function ff_conv_flt_to_s16_neon, export=1
subs x2, x2, #8
ld1 {v0.4s}, [x1], #16
fcvtzs v4.4s, v0.4s, #31
ld1 {v1.4s}, [x1], #16
fcvtzs v5.4s, v1.4s, #31
b.eq 3f
ands x12, x2, #~15
b.eq 2f
1: subs x12, x12, #16
sqrshrn v4.4h, v4.4s, #16
ld1 {v2.4s}, [x1], #16
fcvtzs v6.4s, v2.4s, #31
sqrshrn2 v4.8h, v5.4s, #16
ld1 {v3.4s}, [x1], #16
fcvtzs v7.4s, v3.4s, #31
sqrshrn v6.4h, v6.4s, #16
st1 {v4.8h}, [x0], #16
sqrshrn2 v6.8h, v7.4s, #16
ld1 {v0.4s}, [x1], #16
fcvtzs v4.4s, v0.4s, #31
ld1 {v1.4s}, [x1], #16
fcvtzs v5.4s, v1.4s, #31
st1 {v6.8h}, [x0], #16
b.ne 1b
ands x2, x2, #15
b.eq 3f
2: ld1 {v2.4s}, [x1], #16
sqrshrn v4.4h, v4.4s, #16
fcvtzs v6.4s, v2.4s, #31
ld1 {v3.4s}, [x1], #16
sqrshrn2 v4.8h, v5.4s, #16
fcvtzs v7.4s, v3.4s, #31
sqrshrn v6.4h, v6.4s, #16
st1 {v4.8h}, [x0], #16
sqrshrn2 v6.8h, v7.4s, #16
st1 {v6.8h}, [x0]
ret
3: sqrshrn v4.4h, v4.4s, #16
sqrshrn2 v4.8h, v5.4s, #16
st1 {v4.8h}, [x0]
ret
endfunc
function ff_conv_fltp_to_s16_2ch_neon, export=1
ldp x4, x5, [x1]
subs x2, x2, #8
ld1 {v0.4s}, [x4], #16
fcvtzs v4.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v5.4s, v1.4s, #31
ld1 {v2.4s}, [x5], #16
fcvtzs v6.4s, v2.4s, #31
ld1 {v3.4s}, [x5], #16
fcvtzs v7.4s, v3.4s, #31
b.eq 3f
ands x12, x2, #~15
b.eq 2f
1: subs x12, x12, #16
ld1 {v16.4s}, [x4], #16
fcvtzs v20.4s, v16.4s, #31
sri v6.4s, v4.4s, #16
ld1 {v17.4s}, [x4], #16
fcvtzs v21.4s, v17.4s, #31
ld1 {v18.4s}, [x5], #16
fcvtzs v22.4s, v18.4s, #31
ld1 {v19.4s}, [x5], #16
sri v7.4s, v5.4s, #16
st1 {v6.4s}, [x0], #16
fcvtzs v23.4s, v19.4s, #31
st1 {v7.4s}, [x0], #16
sri v22.4s, v20.4s, #16
ld1 {v0.4s}, [x4], #16
sri v23.4s, v21.4s, #16
st1 {v22.4s}, [x0], #16
fcvtzs v4.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v5.4s, v1.4s, #31
ld1 {v2.4s}, [x5], #16
fcvtzs v6.4s, v2.4s, #31
ld1 {v3.4s}, [x5], #16
fcvtzs v7.4s, v3.4s, #31
st1 {v23.4s}, [x0], #16
b.ne 1b
ands x2, x2, #15
b.eq 3f
2: sri v6.4s, v4.4s, #16
ld1 {v0.4s}, [x4], #16
fcvtzs v0.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v1.4s, v1.4s, #31
ld1 {v2.4s}, [x5], #16
fcvtzs v2.4s, v2.4s, #31
sri v7.4s, v5.4s, #16
ld1 {v3.4s}, [x5], #16
fcvtzs v3.4s, v3.4s, #31
sri v2.4s, v0.4s, #16
st1 {v6.4s,v7.4s}, [x0], #32
sri v3.4s, v1.4s, #16
st1 {v2.4s,v3.4s}, [x0], #32
ret
3: sri v6.4s, v4.4s, #16
sri v7.4s, v5.4s, #16
st1 {v6.4s,v7.4s}, [x0]
ret
endfunc
function ff_conv_fltp_to_s16_neon, export=1
cmp w3, #2
b.eq X(ff_conv_fltp_to_s16_2ch_neon)
b.gt 1f
ldr x1, [x1]
b X(ff_conv_flt_to_s16_neon)
1:
cmp w3, #4
lsl x12, x3, #1
b.lt 4f
5: // 4 channels
ldp x4, x5, [x1], #16
ldp x6, x7, [x1], #16
mov w9, w2
mov x8, x0
ld1 {v4.4s}, [x4], #16
fcvtzs v4.4s, v4.4s, #31
ld1 {v5.4s}, [x5], #16
fcvtzs v5.4s, v5.4s, #31
ld1 {v6.4s}, [x6], #16
fcvtzs v6.4s, v6.4s, #31
ld1 {v7.4s}, [x7], #16
fcvtzs v7.4s, v7.4s, #31
6:
subs w9, w9, #8
ld1 {v0.4s}, [x4], #16
fcvtzs v0.4s, v0.4s, #31
sri v5.4s, v4.4s, #16
ld1 {v1.4s}, [x5], #16
fcvtzs v1.4s, v1.4s, #31
sri v7.4s, v6.4s, #16
ld1 {v2.4s}, [x6], #16
fcvtzs v2.4s, v2.4s, #31
zip1 v16.4s, v5.4s, v7.4s
ld1 {v3.4s}, [x7], #16
fcvtzs v3.4s, v3.4s, #31
zip2 v17.4s, v5.4s, v7.4s
st1 {v16.d}[0], [x8], x12
sri v1.4s, v0.4s, #16
st1 {v16.d}[1], [x8], x12
sri v3.4s, v2.4s, #16
st1 {v17.d}[0], [x8], x12
zip1 v18.4s, v1.4s, v3.4s
st1 {v17.d}[1], [x8], x12
zip2 v19.4s, v1.4s, v3.4s
b.eq 7f
ld1 {v4.4s}, [x4], #16
fcvtzs v4.4s, v4.4s, #31
st1 {v18.d}[0], [x8], x12
ld1 {v5.4s}, [x5], #16
fcvtzs v5.4s, v5.4s, #31
st1 {v18.d}[1], [x8], x12
ld1 {v6.4s}, [x6], #16
fcvtzs v6.4s, v6.4s, #31
st1 {v19.d}[0], [x8], x12
ld1 {v7.4s}, [x7], #16
fcvtzs v7.4s, v7.4s, #31
st1 {v19.d}[1], [x8], x12
b 6b
7:
st1 {v18.d}[0], [x8], x12
st1 {v18.d}[1], [x8], x12
st1 {v19.d}[0], [x8], x12
st1 {v19.d}[1], [x8], x12
subs w3, w3, #4
b.eq end
cmp w3, #4
add x0, x0, #8
b.ge 5b
4: // 2 channels
cmp w3, #2
b.lt 4f
ldp x4, x5, [x1], #16
mov w9, w2
mov x8, x0
tst w9, #8
ld1 {v4.4s}, [x4], #16
fcvtzs v4.4s, v4.4s, #31
ld1 {v5.4s}, [x5], #16
fcvtzs v5.4s, v5.4s, #31
ld1 {v6.4s}, [x4], #16
fcvtzs v6.4s, v6.4s, #31
ld1 {v7.4s}, [x5], #16
fcvtzs v7.4s, v7.4s, #31
b.eq 6f
subs w9, w9, #8
b.eq 7f
sri v5.4s, v4.4s, #16
ld1 {v4.4s}, [x4], #16
fcvtzs v4.4s, v4.4s, #31
st1 {v5.s}[0], [x8], x12
sri v7.4s, v6.4s, #16
st1 {v5.s}[1], [x8], x12
ld1 {v6.4s}, [x4], #16
fcvtzs v6.4s, v6.4s, #31
st1 {v5.s}[2], [x8], x12
st1 {v5.s}[3], [x8], x12
st1 {v7.s}[0], [x8], x12
st1 {v7.s}[1], [x8], x12
ld1 {v5.4s}, [x5], #16
fcvtzs v5.4s, v5.4s, #31
st1 {v7.s}[2], [x8], x12
st1 {v7.s}[3], [x8], x12
ld1 {v7.4s}, [x5], #16
fcvtzs v7.4s, v7.4s, #31
6:
subs w9, w9, #16
ld1 {v0.4s}, [x4], #16
sri v5.4s, v4.4s, #16
fcvtzs v0.4s, v0.4s, #31
ld1 {v1.4s}, [x5], #16
sri v7.4s, v6.4s, #16
st1 {v5.s}[0], [x8], x12
st1 {v5.s}[1], [x8], x12
fcvtzs v1.4s, v1.4s, #31
st1 {v5.s}[2], [x8], x12
st1 {v5.s}[3], [x8], x12
ld1 {v2.4s}, [x4], #16
st1 {v7.s}[0], [x8], x12
fcvtzs v2.4s, v2.4s, #31
st1 {v7.s}[1], [x8], x12
ld1 {v3.4s}, [x5], #16
st1 {v7.s}[2], [x8], x12
fcvtzs v3.4s, v3.4s, #31
st1 {v7.s}[3], [x8], x12
sri v1.4s, v0.4s, #16
sri v3.4s, v2.4s, #16
b.eq 6f
ld1 {v4.4s}, [x4], #16
st1 {v1.s}[0], [x8], x12
fcvtzs v4.4s, v4.4s, #31
st1 {v1.s}[1], [x8], x12
ld1 {v5.4s}, [x5], #16
st1 {v1.s}[2], [x8], x12
fcvtzs v5.4s, v5.4s, #31
st1 {v1.s}[3], [x8], x12
ld1 {v6.4s}, [x4], #16
st1 {v3.s}[0], [x8], x12
fcvtzs v6.4s, v6.4s, #31
st1 {v3.s}[1], [x8], x12
ld1 {v7.4s}, [x5], #16
st1 {v3.s}[2], [x8], x12
fcvtzs v7.4s, v7.4s, #31
st1 {v3.s}[3], [x8], x12
b.gt 6b
6:
st1 {v1.s}[0], [x8], x12
st1 {v1.s}[1], [x8], x12
st1 {v1.s}[2], [x8], x12
st1 {v1.s}[3], [x8], x12
st1 {v3.s}[0], [x8], x12
st1 {v3.s}[1], [x8], x12
st1 {v3.s}[2], [x8], x12
st1 {v3.s}[3], [x8], x12
b 8f
7:
sri v5.4s, v4.4s, #16
sri v7.4s, v6.4s, #16
st1 {v5.s}[0], [x8], x12
st1 {v5.s}[1], [x8], x12
st1 {v5.s}[2], [x8], x12
st1 {v5.s}[3], [x8], x12
st1 {v7.s}[0], [x8], x12
st1 {v7.s}[1], [x8], x12
st1 {v7.s}[2], [x8], x12
st1 {v7.s}[3], [x8], x12
8:
subs w3, w3, #2
add x0, x0, #4
b.eq end
4: // 1 channel
ldr x4, [x1]
tst w2, #8
mov w9, w2
mov x5, x0
ld1 {v0.4s}, [x4], #16
fcvtzs v0.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v1.4s, v1.4s, #31
b.ne 8f
6:
subs w9, w9, #16
ld1 {v2.4s}, [x4], #16
fcvtzs v2.4s, v2.4s, #31
ld1 {v3.4s}, [x4], #16
fcvtzs v3.4s, v3.4s, #31
st1 {v0.h}[1], [x5], x12
st1 {v0.h}[3], [x5], x12
st1 {v0.h}[5], [x5], x12
st1 {v0.h}[7], [x5], x12
st1 {v1.h}[1], [x5], x12
st1 {v1.h}[3], [x5], x12
st1 {v1.h}[5], [x5], x12
st1 {v1.h}[7], [x5], x12
b.eq 7f
ld1 {v0.4s}, [x4], #16
fcvtzs v0.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v1.4s, v1.4s, #31
7:
st1 {v2.h}[1], [x5], x12
st1 {v2.h}[3], [x5], x12
st1 {v2.h}[5], [x5], x12
st1 {v2.h}[7], [x5], x12
st1 {v3.h}[1], [x5], x12
st1 {v3.h}[3], [x5], x12
st1 {v3.h}[5], [x5], x12
st1 {v3.h}[7], [x5], x12
b.gt 6b
ret
8:
subs w9, w9, #8
st1 {v0.h}[1], [x5], x12
st1 {v0.h}[3], [x5], x12
st1 {v0.h}[5], [x5], x12
st1 {v0.h}[7], [x5], x12
st1 {v1.h}[1], [x5], x12
st1 {v1.h}[3], [x5], x12
st1 {v1.h}[5], [x5], x12
st1 {v1.h}[7], [x5], x12
b.eq end
ld1 {v0.4s}, [x4], #16
fcvtzs v0.4s, v0.4s, #31
ld1 {v1.4s}, [x4], #16
fcvtzs v1.4s, v1.4s, #31
b 6b
end:
ret
endfunc

View File

@ -1,31 +0,0 @@
/*
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
* 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
*/
#include "libavresample/avresample.h"
#include "libavutil/aarch64/neontest.h"
wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output,
int out_plane_size, int out_samples, uint8_t **input,
int in_plane_size, int in_samples))
{
testneonclobbers(avresample_convert, avr, output, out_plane_size,
out_samples, input, in_plane_size, in_samples);
}

View File

@ -1,71 +0,0 @@
/*
* 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
*/
#include <stdint.h>
#include "config.h"
#include "libavutil/cpu.h"
#include "libavutil/aarch64/cpu.h"
#include "libavutil/internal.h"
#include "libavutil/samplefmt.h"
#include "libavresample/resample.h"
#include "asm-offsets.h"
AV_CHECK_OFFSET(struct ResampleContext, filter_bank, FILTER_BANK);
AV_CHECK_OFFSET(struct ResampleContext, filter_length, FILTER_LENGTH);
AV_CHECK_OFFSET(struct ResampleContext, phase_shift, PHASE_SHIFT);
AV_CHECK_OFFSET(struct ResampleContext, phase_mask, PHASE_MASK);
void ff_resample_one_dbl_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_one_flt_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_one_s16_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_one_s32_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
av_cold void ff_audio_resample_init_aarch64(ResampleContext *c,
enum AVSampleFormat sample_fmt)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
if (!c->linear) {
switch (sample_fmt) {
case AV_SAMPLE_FMT_DBLP:
c->resample_one = ff_resample_one_dbl_neon;
break;
case AV_SAMPLE_FMT_FLTP:
c->resample_one = ff_resample_one_flt_neon;
break;
case AV_SAMPLE_FMT_S16P:
c->resample_one = ff_resample_one_s16_neon;
break;
case AV_SAMPLE_FMT_S32P:
c->resample_one = ff_resample_one_s32_neon;
break;
}
}
}
}

View File

@ -1,233 +0,0 @@
/*
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
* 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
*/
#include "libavutil/aarch64/asm.S"
#include "asm-offsets.h"
.macro resample_one fmt, es=2
.ifnc \fmt, dbl
.macro M_MUL2 x:vararg
.endm
.macro M_MLA2 x:vararg
.endm
.endif
function ff_resample_one_\fmt\()_neon, export=1
sxtw x2, w2
ldr x9, [x0, #FILTER_BANK]
ldr w6, [x0, #FILTER_LENGTH]
ldp w7, w8, [x0, #PHASE_SHIFT] // and phase_mask
lsr x10, x4, x7 // sample_index
and x4, x4, x8
lsl x11, x6, #\es // filter_length * elem_size
add x3, x3, x10, lsl #\es // src[sample_index]
madd x9, x11, x4, x9 // filter
cmp w6, #16
b.lt 5f
8: // remaining filter_length at least 16
subs w6, w6, #16
LOAD8 v4, v5, v6, v7, x3
LOAD8 v16, v17, v18, v19, x9
M_MUL v0, v4, v16, v1
M_MUL2 v1, v6, v18
7:
LOAD8 v20, v21, v22, v23, x3
M_MLA v0, v5, v17, v1
M_MLA2 v1, v7, v19
LOAD8 v24, v25, v26, v27, x9
M_MLA v0, v20, v24, v1
M_MLA2 v1, v22, v26
b.eq 6f
cmp w6, #16
M_MLA v0, v21, v25, v1
M_MLA2 v1, v23, v27
b.lt 4f
subs w6, w6, #16
LOAD8 v4, v5, v6, v7, x3
LOAD8 v16, v17, v18, v19, x9
M_MLA v0, v4, v16, v1
M_MLA2 v1, v6, v18
b 7b
6:
M_MLA v0, v21, v25, v1
M_MLA2 v1, v23, v27
STORE_ONE 0, x1, x2, v1
ret
5:
movi v0.16b, #0
movi v1.16b, #0
4: // remaining filter_length 1-15
cmp w6, #4
b.lt 2f
subs w6, w6, #4
LOAD4 v4, v5, x3
LOAD4 v6, v7, x9
M_MLA v0, v4, v6, v1
M_MLA2 v1, v5, v7
b.eq 0f
b 4b
2: // remaining filter_length 1-3
cmp w6, #2
b.lt 1f
LOAD2 2, x3
LOAD2 3, x9
subs w6, w6, #2
M_MLA v0, v2, v3
b.eq 0f
1: // remaining filter_length 1
LOAD1 6, x3
LOAD1 7, x9
M_MLA v0, v6, v7
0:
STORE_ONE 0, x1, x2, v1
ret
endfunc
.purgem LOAD1
.purgem LOAD2
.purgem LOAD4
.purgem LOAD8
.purgem M_MLA
.purgem M_MLA2
.purgem M_MUL
.purgem M_MUL2
.purgem STORE_ONE
.endm
.macro LOAD1 d1, addr
ldr d\d1, [\addr], #8
.endm
.macro LOAD2 d1, addr
ld1 {v\d1\().2d}, [\addr], #16
.endm
.macro LOAD4 d1, d2, addr
ld1 {\d1\().2d,\d2\().2d}, [\addr], #32
.endm
.macro LOAD8 d1, d2, d3, d4, addr
ld1 {\d1\().2d,\d2\().2d,\d3\().2d,\d4\().2d}, [\addr], #64
.endm
.macro M_MLA d, r0, r1, d2:vararg
fmla \d\().2d, \r0\().2d, \r1\().2d
.endm
.macro M_MLA2 second:vararg
M_MLA \second
.endm
.macro M_MUL d, r0, r1, d2:vararg
fmul \d\().2d, \r0\().2d, \r1\().2d
.endm
.macro M_MUL2 second:vararg
M_MUL \second
.endm
.macro STORE_ONE rn, addr, idx, d2
fadd v\rn\().2d, v\rn\().2d, \d2\().2d
faddp d\rn\(), v\rn\().2d
str d\rn\(), [\addr, \idx, lsl #3]
.endm
resample_one dbl, 3
.macro LOAD1 d1, addr
ldr s\d1, [\addr], #4
.endm
.macro LOAD2 d1, addr
ld1 {v\d1\().2s}, [\addr], #8
.endm
.macro LOAD4 d1, d2, addr
ld1 {\d1\().4s}, [\addr], #16
.endm
.macro LOAD8 d1, d2, d3, d4, addr
ld1 {\d1\().4s,\d2\().4s}, [\addr], #32
.endm
.macro M_MLA d, r0, r1, d2:vararg
fmla \d\().4s, \r0\().4s, \r1\().4s
.endm
.macro M_MUL d, r0, r1, d2:vararg
fmul \d\().4s, \r0\().4s, \r1\().4s
.endm
.macro STORE_ONE rn, addr, idx, d2
faddp v\rn\().4s, v\rn\().4s, v\rn\().4s
faddp s\rn\(), v\rn\().2s
str s\rn\(), [\addr, \idx, lsl #2]
.endm
resample_one flt
.macro LOAD1 d1, addr
ldr h\d1, [\addr], #2
.endm
.macro LOAD2 d1, addr
ldr s\d1, [\addr], #4
.endm
.macro LOAD4 d1, d2, addr
ld1 {\d1\().4h}, [\addr], #8
.endm
.macro LOAD8 d1, d2, d3, d4, addr
ld1 {\d1\().4h,\d2\().4h}, [\addr], #16
.endm
.macro M_MLA d, r0, r1, d2:vararg
smlal \d\().4s, \r0\().4h, \r1\().4h
.endm
.macro M_MUL d, r0, r1, d2:vararg
smull \d\().4s, \r0\().4h, \r1\().4h
.endm
.macro STORE_ONE rn, addr, idx, d2
addp v\rn\().4s, v\rn\().4s, v\rn\().4s
addp v\rn\().4s, v\rn\().4s, v\rn\().4s
sqrshrn v\rn\().4h, v\rn\().4s, #15
str h\rn\(), [\addr, \idx, lsl #1]
.endm
resample_one s16, 1
.macro LOAD1 d1, addr
ldr s\d1, [\addr], #4
.endm
.macro LOAD2 d1, addr
ld1 {v\d1\().2s}, [\addr], #8
.endm
.macro LOAD4 d1, d2, addr
ld1 {\d1\().4s}, [\addr], #16
.endm
.macro LOAD8 d1, d2, d3, d4, addr
ld1 {\d1\().4s,\d2\().4s}, [\addr], #32
.endm
.macro M_MLA d1, r0, r1, d2:vararg
smlal \d1\().2d, \r0\().2s, \r1\().2s
.ifnb \d2
smlal2 \d2\().2d, \r0\().4s, \r1\().4s
.endif
.endm
.macro M_MUL d1, r0, r1, d2:vararg
smull \d1\().2d, \r0\().2s, \r1\().2s
.ifnb \d2
smull2 \d2\().2d, \r0\().4s, \r1\().4s
.endif
.endm
.macro STORE_ONE rn, addr, idx, d2
add v\rn\().2d, v\rn\().2d, \d2\().2d
addp d\rn\(), v\rn\().2d
sqrshrn v\rn\().2s, v\rn\().2d, #30
str s\rn\(), [\addr, \idx, lsl #2]
.endm
resample_one s32

View File

@ -1,7 +0,0 @@
OBJS += arm/audio_convert_init.o \
arm/resample_init.o
OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o
NEON-OBJS += arm/audio_convert_neon.o \
arm/resample_neon.o

View File

@ -1,29 +0,0 @@
/*
* 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
*/
#ifndef AVRESAMPLE_ARM_ASM_OFFSETS_H
#define AVRESAMPLE_ARM_ASM_OFFSETS_H
/* struct ResampleContext */
#define FILTER_BANK 0x08
#define FILTER_LENGTH 0x0c
#define SRC_INCR 0x20
#define PHASE_SHIFT 0x28
#define PHASE_MASK (PHASE_SHIFT + 0x04)
#endif /* AVRESAMPLE_ARM_ASM_OFFSETS_H */

View File

@ -1,49 +0,0 @@
/*
* 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
*/
#include <stdint.h>
#include "config.h"
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/arm/cpu.h"
#include "libavutil/samplefmt.h"
#include "libavresample/audio_convert.h"
void ff_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
void ff_conv_fltp_to_s16_neon(int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src,
int len, int channels);
av_cold void ff_audio_convert_init_arm(AudioConvert *ac)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT,
0, 16, 8, "NEON",
ff_conv_flt_to_s16_neon);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
0, 16, 8, "NEON",
ff_conv_fltp_to_s16_neon);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
2, 16, 8, "NEON",
ff_conv_fltp_to_s16_2ch_neon);
}
}

View File

@ -1,363 +0,0 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
* 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
*/
#include "config.h"
#include "libavutil/arm/asm.S"
function ff_conv_flt_to_s16_neon, export=1
subs r2, r2, #8
vld1.32 {q0}, [r1,:128]!
vcvt.s32.f32 q8, q0, #31
vld1.32 {q1}, [r1,:128]!
vcvt.s32.f32 q9, q1, #31
beq 3f
bics r12, r2, #15
beq 2f
1: subs r12, r12, #16
vqrshrn.s32 d4, q8, #16
vld1.32 {q0}, [r1,:128]!
vcvt.s32.f32 q0, q0, #31
vqrshrn.s32 d5, q9, #16
vld1.32 {q1}, [r1,:128]!
vcvt.s32.f32 q1, q1, #31
vqrshrn.s32 d6, q0, #16
vst1.16 {q2}, [r0,:128]!
vqrshrn.s32 d7, q1, #16
vld1.32 {q8}, [r1,:128]!
vcvt.s32.f32 q8, q8, #31
vld1.32 {q9}, [r1,:128]!
vcvt.s32.f32 q9, q9, #31
vst1.16 {q3}, [r0,:128]!
bne 1b
ands r2, r2, #15
beq 3f
2: vld1.32 {q0}, [r1,:128]!
vqrshrn.s32 d4, q8, #16
vcvt.s32.f32 q0, q0, #31
vld1.32 {q1}, [r1,:128]!
vqrshrn.s32 d5, q9, #16
vcvt.s32.f32 q1, q1, #31
vqrshrn.s32 d6, q0, #16
vst1.16 {q2}, [r0,:128]!
vqrshrn.s32 d7, q1, #16
vst1.16 {q3}, [r0,:128]!
bx lr
3: vqrshrn.s32 d4, q8, #16
vqrshrn.s32 d5, q9, #16
vst1.16 {q2}, [r0,:128]!
bx lr
endfunc
function ff_conv_fltp_to_s16_2ch_neon, export=1
ldm r1, {r1, r3}
subs r2, r2, #8
vld1.32 {q0}, [r1,:128]!
vcvt.s32.f32 q8, q0, #31
vld1.32 {q1}, [r1,:128]!
vcvt.s32.f32 q9, q1, #31
vld1.32 {q10}, [r3,:128]!
vcvt.s32.f32 q10, q10, #31
vld1.32 {q11}, [r3,:128]!
vcvt.s32.f32 q11, q11, #31
beq 3f
bics r12, r2, #15
beq 2f
1: subs r12, r12, #16
vld1.32 {q0}, [r1,:128]!
vcvt.s32.f32 q0, q0, #31
vsri.32 q10, q8, #16
vld1.32 {q1}, [r1,:128]!
vcvt.s32.f32 q1, q1, #31
vld1.32 {q12}, [r3,:128]!
vcvt.s32.f32 q12, q12, #31
vld1.32 {q13}, [r3,:128]!
vsri.32 q11, q9, #16
vst1.16 {q10}, [r0,:128]!
vcvt.s32.f32 q13, q13, #31
vst1.16 {q11}, [r0,:128]!
vsri.32 q12, q0, #16
vld1.32 {q8}, [r1,:128]!
vsri.32 q13, q1, #16
vst1.16 {q12}, [r0,:128]!
vcvt.s32.f32 q8, q8, #31
vld1.32 {q9}, [r1,:128]!
vcvt.s32.f32 q9, q9, #31
vld1.32 {q10}, [r3,:128]!
vcvt.s32.f32 q10, q10, #31
vld1.32 {q11}, [r3,:128]!
vcvt.s32.f32 q11, q11, #31
vst1.16 {q13}, [r0,:128]!
bne 1b
ands r2, r2, #15
beq 3f
2: vsri.32 q10, q8, #16
vld1.32 {q0}, [r1,:128]!
vcvt.s32.f32 q0, q0, #31
vld1.32 {q1}, [r1,:128]!
vcvt.s32.f32 q1, q1, #31
vld1.32 {q12}, [r3,:128]!
vcvt.s32.f32 q12, q12, #31
vsri.32 q11, q9, #16
vld1.32 {q13}, [r3,:128]!
vcvt.s32.f32 q13, q13, #31
vst1.16 {q10}, [r0,:128]!
vsri.32 q12, q0, #16
vst1.16 {q11}, [r0,:128]!
vsri.32 q13, q1, #16
vst1.16 {q12-q13},[r0,:128]!
bx lr
3: vsri.32 q10, q8, #16
vsri.32 q11, q9, #16
vst1.16 {q10-q11},[r0,:128]!
bx lr
endfunc
function ff_conv_fltp_to_s16_neon, export=1
cmp r3, #2
itt lt
ldrlt r1, [r1]
blt X(ff_conv_flt_to_s16_neon)
beq X(ff_conv_fltp_to_s16_2ch_neon)
push {r4-r8, lr}
cmp r3, #4
lsl r12, r3, #1
blt 4f
@ 4 channels
5: ldm r1!, {r4-r7}
mov lr, r2
mov r8, r0
vld1.32 {q8}, [r4,:128]!
vcvt.s32.f32 q8, q8, #31
vld1.32 {q9}, [r5,:128]!
vcvt.s32.f32 q9, q9, #31
vld1.32 {q10}, [r6,:128]!
vcvt.s32.f32 q10, q10, #31
vld1.32 {q11}, [r7,:128]!
vcvt.s32.f32 q11, q11, #31
6: subs lr, lr, #8
vld1.32 {q0}, [r4,:128]!
vcvt.s32.f32 q0, q0, #31
vsri.32 q9, q8, #16
vld1.32 {q1}, [r5,:128]!
vcvt.s32.f32 q1, q1, #31
vsri.32 q11, q10, #16
vld1.32 {q2}, [r6,:128]!
vcvt.s32.f32 q2, q2, #31
vzip.32 d18, d22
vld1.32 {q3}, [r7,:128]!
vcvt.s32.f32 q3, q3, #31
vzip.32 d19, d23
vst1.16 {d18}, [r8], r12
vsri.32 q1, q0, #16
vst1.16 {d22}, [r8], r12
vsri.32 q3, q2, #16
vst1.16 {d19}, [r8], r12
vzip.32 d2, d6
vst1.16 {d23}, [r8], r12
vzip.32 d3, d7
beq 7f
vld1.32 {q8}, [r4,:128]!
vcvt.s32.f32 q8, q8, #31
vst1.16 {d2}, [r8], r12
vld1.32 {q9}, [r5,:128]!
vcvt.s32.f32 q9, q9, #31
vst1.16 {d6}, [r8], r12
vld1.32 {q10}, [r6,:128]!
vcvt.s32.f32 q10, q10, #31
vst1.16 {d3}, [r8], r12
vld1.32 {q11}, [r7,:128]!
vcvt.s32.f32 q11, q11, #31
vst1.16 {d7}, [r8], r12
b 6b
7: vst1.16 {d2}, [r8], r12
vst1.16 {d6}, [r8], r12
vst1.16 {d3}, [r8], r12
vst1.16 {d7}, [r8], r12
subs r3, r3, #4
it eq
popeq {r4-r8, pc}
cmp r3, #4
add r0, r0, #8
bge 5b
@ 2 channels
4: cmp r3, #2
blt 4f
ldm r1!, {r4-r5}
mov lr, r2
mov r8, r0
tst lr, #8
vld1.32 {q8}, [r4,:128]!
vcvt.s32.f32 q8, q8, #31
vld1.32 {q9}, [r5,:128]!
vcvt.s32.f32 q9, q9, #31
vld1.32 {q10}, [r4,:128]!
vcvt.s32.f32 q10, q10, #31
vld1.32 {q11}, [r5,:128]!
vcvt.s32.f32 q11, q11, #31
beq 6f
subs lr, lr, #8
beq 7f
vsri.32 d18, d16, #16
vsri.32 d19, d17, #16
vld1.32 {q8}, [r4,:128]!
vcvt.s32.f32 q8, q8, #31
vst1.32 {d18[0]}, [r8], r12
vsri.32 d22, d20, #16
vst1.32 {d18[1]}, [r8], r12
vsri.32 d23, d21, #16
vst1.32 {d19[0]}, [r8], r12
vst1.32 {d19[1]}, [r8], r12
vld1.32 {q9}, [r5,:128]!
vcvt.s32.f32 q9, q9, #31
vst1.32 {d22[0]}, [r8], r12
vst1.32 {d22[1]}, [r8], r12
vld1.32 {q10}, [r4,:128]!
vcvt.s32.f32 q10, q10, #31
vst1.32 {d23[0]}, [r8], r12
vst1.32 {d23[1]}, [r8], r12
vld1.32 {q11}, [r5,:128]!
vcvt.s32.f32 q11, q11, #31
6: subs lr, lr, #16
vld1.32 {q0}, [r4,:128]!
vcvt.s32.f32 q0, q0, #31
vsri.32 d18, d16, #16
vld1.32 {q1}, [r5,:128]!
vcvt.s32.f32 q1, q1, #31
vsri.32 d19, d17, #16
vld1.32 {q2}, [r4,:128]!
vcvt.s32.f32 q2, q2, #31
vld1.32 {q3}, [r5,:128]!
vcvt.s32.f32 q3, q3, #31
vst1.32 {d18[0]}, [r8], r12
vsri.32 d22, d20, #16
vst1.32 {d18[1]}, [r8], r12
vsri.32 d23, d21, #16
vst1.32 {d19[0]}, [r8], r12
vsri.32 d2, d0, #16
vst1.32 {d19[1]}, [r8], r12
vsri.32 d3, d1, #16
vst1.32 {d22[0]}, [r8], r12
vsri.32 d6, d4, #16
vst1.32 {d22[1]}, [r8], r12
vsri.32 d7, d5, #16
vst1.32 {d23[0]}, [r8], r12
vst1.32 {d23[1]}, [r8], r12
beq 6f
vld1.32 {q8}, [r4,:128]!
vcvt.s32.f32 q8, q8, #31
vst1.32 {d2[0]}, [r8], r12
vst1.32 {d2[1]}, [r8], r12
vld1.32 {q9}, [r5,:128]!
vcvt.s32.f32 q9, q9, #31
vst1.32 {d3[0]}, [r8], r12
vst1.32 {d3[1]}, [r8], r12
vld1.32 {q10}, [r4,:128]!
vcvt.s32.f32 q10, q10, #31
vst1.32 {d6[0]}, [r8], r12
vst1.32 {d6[1]}, [r8], r12
vld1.32 {q11}, [r5,:128]!
vcvt.s32.f32 q11, q11, #31
vst1.32 {d7[0]}, [r8], r12
vst1.32 {d7[1]}, [r8], r12
bgt 6b
6: vst1.32 {d2[0]}, [r8], r12
vst1.32 {d2[1]}, [r8], r12
vst1.32 {d3[0]}, [r8], r12
vst1.32 {d3[1]}, [r8], r12
vst1.32 {d6[0]}, [r8], r12
vst1.32 {d6[1]}, [r8], r12
vst1.32 {d7[0]}, [r8], r12
vst1.32 {d7[1]}, [r8], r12
b 8f
7: vsri.32 d18, d16, #16
vsri.32 d19, d17, #16
vst1.32 {d18[0]}, [r8], r12
vsri.32 d22, d20, #16
vst1.32 {d18[1]}, [r8], r12
vsri.32 d23, d21, #16
vst1.32 {d19[0]}, [r8], r12
vst1.32 {d19[1]}, [r8], r12
vst1.32 {d22[0]}, [r8], r12
vst1.32 {d22[1]}, [r8], r12
vst1.32 {d23[0]}, [r8], r12
vst1.32 {d23[1]}, [r8], r12
8: subs r3, r3, #2
add r0, r0, #4
it eq
popeq {r4-r8, pc}
@ 1 channel
4: ldr r4, [r1]
tst r2, #8
mov lr, r2
mov r5, r0
vld1.32 {q0}, [r4,:128]!
vcvt.s32.f32 q0, q0, #31
vld1.32 {q1}, [r4,:128]!
vcvt.s32.f32 q1, q1, #31
bne 8f
6: subs lr, lr, #16
vld1.32 {q2}, [r4,:128]!
vcvt.s32.f32 q2, q2, #31
vld1.32 {q3}, [r4,:128]!
vcvt.s32.f32 q3, q3, #31
vst1.16 {d0[1]}, [r5,:16], r12
vst1.16 {d0[3]}, [r5,:16], r12
vst1.16 {d1[1]}, [r5,:16], r12
vst1.16 {d1[3]}, [r5,:16], r12
vst1.16 {d2[1]}, [r5,:16], r12
vst1.16 {d2[3]}, [r5,:16], r12
vst1.16 {d3[1]}, [r5,:16], r12
vst1.16 {d3[3]}, [r5,:16], r12
beq 7f
vld1.32 {q0}, [r4,:128]!
vcvt.s32.f32 q0, q0, #31
vld1.32 {q1}, [r4,:128]!
vcvt.s32.f32 q1, q1, #31
7: vst1.16 {d4[1]}, [r5,:16], r12
vst1.16 {d4[3]}, [r5,:16], r12
vst1.16 {d5[1]}, [r5,:16], r12
vst1.16 {d5[3]}, [r5,:16], r12
vst1.16 {d6[1]}, [r5,:16], r12
vst1.16 {d6[3]}, [r5,:16], r12
vst1.16 {d7[1]}, [r5,:16], r12
vst1.16 {d7[3]}, [r5,:16], r12
bgt 6b
pop {r4-r8, pc}
8: subs lr, lr, #8
vst1.16 {d0[1]}, [r5,:16], r12
vst1.16 {d0[3]}, [r5,:16], r12
vst1.16 {d1[1]}, [r5,:16], r12
vst1.16 {d1[3]}, [r5,:16], r12
vst1.16 {d2[1]}, [r5,:16], r12
vst1.16 {d2[3]}, [r5,:16], r12
vst1.16 {d3[1]}, [r5,:16], r12
vst1.16 {d3[3]}, [r5,:16], r12
it eq
popeq {r4-r8, pc}
vld1.32 {q0}, [r4,:128]!
vcvt.s32.f32 q0, q0, #31
vld1.32 {q1}, [r4,:128]!
vcvt.s32.f32 q1, q1, #31
b 6b
endfunc

View File

@ -1,31 +0,0 @@
/*
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
* 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
*/
#include "libavresample/avresample.h"
#include "libavutil/arm/neontest.h"
wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output,
int out_plane_size, int out_samples, uint8_t **input,
int in_plane_size, int in_samples))
{
testneonclobbers(avresample_convert, avr, output, out_plane_size,
out_samples, input, in_plane_size, in_samples);
}

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* 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
*/
#include "config.h"
#include "libavutil/cpu.h"
#include "libavutil/arm/cpu.h"
#include "libavutil/internal.h"
#include "libavutil/samplefmt.h"
#include "libavresample/resample.h"
#include "asm-offsets.h"
AV_CHECK_OFFSET(struct ResampleContext, filter_bank, FILTER_BANK);
AV_CHECK_OFFSET(struct ResampleContext, filter_length, FILTER_LENGTH);
AV_CHECK_OFFSET(struct ResampleContext, src_incr, SRC_INCR);
AV_CHECK_OFFSET(struct ResampleContext, phase_shift, PHASE_SHIFT);
AV_CHECK_OFFSET(struct ResampleContext, phase_mask, PHASE_MASK);
void ff_resample_one_flt_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_one_s16_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_one_s32_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void ff_resample_linear_flt_neon(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
av_cold void ff_audio_resample_init_arm(ResampleContext *c,
enum AVSampleFormat sample_fmt)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
switch (sample_fmt) {
case AV_SAMPLE_FMT_FLTP:
if (c->linear)
c->resample_one = ff_resample_linear_flt_neon;
else
c->resample_one = ff_resample_one_flt_neon;
break;
case AV_SAMPLE_FMT_S16P:
if (!c->linear)
c->resample_one = ff_resample_one_s16_neon;
break;
case AV_SAMPLE_FMT_S32P:
if (!c->linear)
c->resample_one = ff_resample_one_s32_neon;
break;
}
}
}

View File

@ -1,358 +0,0 @@
/*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* 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
*/
#include "libavutil/arm/asm.S"
#include "asm-offsets.h"
.macro resample_one fmt, es=2
function ff_resample_one_\fmt\()_neon, export=1
push {r4, r5}
add r1, r1, r2, lsl #\es
ldr r2, [r0, #PHASE_SHIFT+4] /* phase_mask */
ldr ip, [sp, #8] /* index */
ldr r5, [r0, #FILTER_LENGTH]
and r2, ip, r2 /* (index & phase_mask) */
ldr r4, [r0, #PHASE_SHIFT]
lsr r4, ip, r4 /* compute sample_index */
mul r2, r2, r5
ldr ip, [r0, #FILTER_BANK]
add r3, r3, r4, lsl #\es /* &src[sample_index] */
cmp r5, #8
add r0, ip, r2, lsl #\es /* filter = &filter_bank[...] */
blt 5f
8:
subs r5, r5, #8
LOAD4
MUL4
7:
LOAD4
beq 6f
cmp r5, #8
MLA4
blt 4f
subs r5, r5, #8
LOAD4
MLA4
b 7b
6:
MLA4
STORE
pop {r4, r5}
bx lr
5:
INIT4
4: /* remaining filter_length 1 to 7 */
cmp r5, #4
blt 2f
subs r5, r5, #4
LOAD4
MLA4
beq 0f
2: /* remaining filter_length 1 to 3 */
cmp r5, #2
blt 1f
subs r5, r5, #2
LOAD2
MLA2
beq 0f
1: /* remaining filter_length 1 */
LOAD1
MLA1
0:
STORE
pop {r4, r5}
bx lr
endfunc
.purgem LOAD1
.purgem LOAD2
.purgem LOAD4
.purgem MLA1
.purgem MLA2
.purgem MLA4
.purgem MUL4
.purgem INIT4
.purgem STORE
.endm
/* float32 */
.macro LOAD1
veor.32 d0, d0
vld1.32 {d0[0]}, [r0]! /* load filter */
vld1.32 {d4[0]}, [r3]! /* load src */
.endm
.macro LOAD2
vld1.32 {d0}, [r0]! /* load filter */
vld1.32 {d4}, [r3]! /* load src */
.endm
.macro LOAD4
vld1.32 {d0,d1}, [r0]! /* load filter */
vld1.32 {d4,d5}, [r3]! /* load src */
.endm
.macro MLA1
vmla.f32 d16, d0, d4[0]
.endm
.macro MLA2
vmla.f32 d16, d0, d4
.endm
.macro MLA4
vmla.f32 d16, d0, d4
vmla.f32 d17, d1, d5
.endm
.macro MUL4
vmul.f32 d16, d0, d4
vmul.f32 d17, d1, d5
.endm
.macro INIT4
veor.f32 q8, q8
.endm
.macro STORE
vpadd.f32 d16, d16, d17
vpadd.f32 d16, d16, d16
vst1.32 d16[0], [r1]
.endm
resample_one flt, 2
/* s32 */
.macro LOAD1
veor.32 d0, d0
vld1.32 {d0[0]}, [r0]! /* load filter */
vld1.32 {d4[0]}, [r3]! /* load src */
.endm
.macro LOAD2
vld1.32 {d0}, [r0]! /* load filter */
vld1.32 {d4}, [r3]! /* load src */
.endm
.macro LOAD4
vld1.32 {d0,d1}, [r0]! /* load filter */
vld1.32 {d4,d5}, [r3]! /* load src */
.endm
.macro MLA1
vmlal.s32 q8, d0, d4[0]
.endm
.macro MLA2
vmlal.s32 q8, d0, d4
.endm
.macro MLA4
vmlal.s32 q8, d0, d4
vmlal.s32 q9, d1, d5
.endm
.macro MUL4
vmull.s32 q8, d0, d4
vmull.s32 q9, d1, d5
.endm
.macro INIT4
veor.s64 q8, q8
veor.s64 q9, q9
.endm
.macro STORE
vadd.s64 q8, q8, q9
vadd.s64 d16, d16, d17
vqrshrn.s64 d16, q8, #30
vst1.32 d16[0], [r1]
.endm
resample_one s32, 2
/* s16 */
.macro LOAD1
veor.16 d0, d0
vld1.16 {d0[0]}, [r0]! /* load filter */
vld1.16 {d4[0]}, [r3]! /* load src */
.endm
.macro LOAD2
veor.16 d0, d0
vld1.32 {d0[0]}, [r0]! /* load filter */
veor.16 d4, d4
vld1.32 {d4[0]}, [r3]! /* load src */
.endm
.macro LOAD4
vld1.16 {d0}, [r0]! /* load filter */
vld1.16 {d4}, [r3]! /* load src */
.endm
.macro MLA1
vmlal.s16 q8, d0, d4[0]
.endm
.macro MLA2
vmlal.s16 q8, d0, d4
.endm
.macro MLA4
vmlal.s16 q8, d0, d4
.endm
.macro MUL4
vmull.s16 q8, d0, d4
.endm
.macro INIT4
veor.s32 q8, q8
.endm
.macro STORE
vpadd.s32 d16, d16, d17
vpadd.s32 d16, d16, d16
vqrshrn.s32 d16, q8, #15
vst1.16 d16[0], [r1]
.endm
resample_one s16, 1
.macro resample_linear fmt, es=2
function ff_resample_linear_\fmt\()_neon, export=1
push {r4, r5}
add r1, r1, r2, lsl #\es
ldr r2, [r0, #PHASE_SHIFT+4] /* phase_mask */
ldr ip, [sp, #8] /* index */
ldr r5, [r0, #FILTER_LENGTH]
and r2, ip, r2 /* (index & phase_mask) */
ldr r4, [r0, #PHASE_SHIFT]
lsr r4, ip, r4 /* compute sample_index */
mul r2, r2, r5
ldr ip, [r0, #FILTER_BANK]
add r3, r3, r4, lsl #\es /* &src[sample_index] */
cmp r5, #8
ldr r4, [r0, #SRC_INCR]
add r0, ip, r2, lsl #\es /* filter = &filter_bank[...] */
add r2, r0, r5, lsl #\es /* filter[... + c->filter_length] */
blt 5f
8:
subs r5, r5, #8
LOAD4
MUL4
7:
LOAD4
beq 6f
cmp r5, #8
MLA4
blt 4f
subs r5, r5, #8
LOAD4
MLA4
b 7b
6:
MLA4
STORE
pop {r4, r5}
bx lr
5:
INIT4
4: /* remaining filter_length 1 to 7 */
cmp r5, #4
blt 2f
subs r5, r5, #4
LOAD4
MLA4
beq 0f
2: /* remaining filter_length 1 to 3 */
cmp r5, #2
blt 1f
subs r5, r5, #2
LOAD2
MLA2
beq 0f
1: /* remaining filter_length 1 */
LOAD1
MLA1
0:
STORE
pop {r4, r5}
bx lr
endfunc
.purgem LOAD1
.purgem LOAD2
.purgem LOAD4
.purgem MLA1
.purgem MLA2
.purgem MLA4
.purgem MUL4
.purgem INIT4
.purgem STORE
.endm
/* float32 linear */
.macro LOAD1
veor.32 d0, d0
veor.32 d2, d2
vld1.32 {d0[0]}, [r0]! /* load filter */
vld1.32 {d2[0]}, [r2]! /* load filter */
vld1.32 {d4[0]}, [r3]! /* load src */
.endm
.macro LOAD2
vld1.32 {d0}, [r0]! /* load filter */
vld1.32 {d2}, [r2]! /* load filter */
vld1.32 {d4}, [r3]! /* load src */
.endm
.macro LOAD4
vld1.32 {d0,d1}, [r0]! /* load filter */
vld1.32 {d2,d3}, [r2]! /* load filter */
vld1.32 {d4,d5}, [r3]! /* load src */
.endm
.macro MLA1
vmla.f32 d18, d0, d4[0]
vmla.f32 d16, d2, d4[0]
.endm
.macro MLA2
vmla.f32 d18, d0, d4
vmla.f32 d16, d2, d4
.endm
.macro MLA4
vmla.f32 q9, q0, q2
vmla.f32 q8, q1, q2
.endm
.macro MUL4
vmul.f32 q9, q0, q2
vmul.f32 q8, q1, q2
.endm
.macro INIT4
veor.f32 q9, q9
veor.f32 q8, q8
.endm
.macro STORE
vldr s0, [sp, #12] /* frac */
vmov s1, r4
vcvt.f32.s32 d0, d0
vsub.f32 q8, q8, q9 /* v2 - val */
vpadd.f32 d18, d18, d19
vpadd.f32 d16, d16, d17
vpadd.f32 d2, d18, d18
vpadd.f32 d1, d16, d16
vmul.f32 s2, s2, s0 /* (v2 - val) * frac */
vdiv.f32 s2, s2, s1 /* / c->src_incr */
vadd.f32 s4, s4, s2
vstr s4, [r1]
.endm
resample_linear flt, 2

View File

@ -1,416 +0,0 @@
/*
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include "config.h"
#include "libavutil/common.h"
#include "libavutil/libm.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
#include "libavutil/samplefmt.h"
#include "audio_convert.h"
#include "audio_data.h"
#include "dither.h"
enum ConvFuncType {
CONV_FUNC_TYPE_FLAT,
CONV_FUNC_TYPE_INTERLEAVE,
CONV_FUNC_TYPE_DEINTERLEAVE,
};
typedef void (conv_func_flat)(uint8_t *out, const uint8_t *in, int len);
typedef void (conv_func_interleave)(uint8_t *out, uint8_t *const *in,
int len, int channels);
typedef void (conv_func_deinterleave)(uint8_t **out, const uint8_t *in, int len,
int channels);
struct AudioConvert {
AVAudioResampleContext *avr;
DitherContext *dc;
enum AVSampleFormat in_fmt;
enum AVSampleFormat out_fmt;
int apply_map;
int channels;
int planes;
int ptr_align;
int samples_align;
int has_optimized_func;
const char *func_descr;
const char *func_descr_generic;
enum ConvFuncType func_type;
conv_func_flat *conv_flat;
conv_func_flat *conv_flat_generic;
conv_func_interleave *conv_interleave;
conv_func_interleave *conv_interleave_generic;
conv_func_deinterleave *conv_deinterleave;
conv_func_deinterleave *conv_deinterleave_generic;
};
void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt, int channels,
int ptr_align, int samples_align,
const char *descr, void *conv)
{
int found = 0;
switch (ac->func_type) {
case CONV_FUNC_TYPE_FLAT:
if (av_get_packed_sample_fmt(ac->in_fmt) == in_fmt &&
av_get_packed_sample_fmt(ac->out_fmt) == out_fmt) {
ac->conv_flat = conv;
ac->func_descr = descr;
ac->ptr_align = ptr_align;
ac->samples_align = samples_align;
if (ptr_align == 1 && samples_align == 1) {
ac->conv_flat_generic = conv;
ac->func_descr_generic = descr;
} else {
ac->has_optimized_func = 1;
}
found = 1;
}
break;
case CONV_FUNC_TYPE_INTERLEAVE:
if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt &&
(!channels || ac->channels == channels)) {
ac->conv_interleave = conv;
ac->func_descr = descr;
ac->ptr_align = ptr_align;
ac->samples_align = samples_align;
if (ptr_align == 1 && samples_align == 1) {
ac->conv_interleave_generic = conv;
ac->func_descr_generic = descr;
} else {
ac->has_optimized_func = 1;
}
found = 1;
}
break;
case CONV_FUNC_TYPE_DEINTERLEAVE:
if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt &&
(!channels || ac->channels == channels)) {
ac->conv_deinterleave = conv;
ac->func_descr = descr;
ac->ptr_align = ptr_align;
ac->samples_align = samples_align;
if (ptr_align == 1 && samples_align == 1) {
ac->conv_deinterleave_generic = conv;
ac->func_descr_generic = descr;
} else {
ac->has_optimized_func = 1;
}
found = 1;
}
break;
}
if (found) {
av_log(ac->avr, AV_LOG_DEBUG, "audio_convert: found function: %-4s "
"to %-4s (%s)\n", av_get_sample_fmt_name(ac->in_fmt),
av_get_sample_fmt_name(ac->out_fmt), descr);
}
}
#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt
#define CONV_LOOP(otype, expr) \
do { \
*(otype *)po = expr; \
pi += is; \
po += os; \
} while (po < end); \
#define CONV_FUNC_FLAT(ofmt, otype, ifmt, itype, expr) \
static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t *in, \
int len) \
{ \
int is = sizeof(itype); \
int os = sizeof(otype); \
const uint8_t *pi = in; \
uint8_t *po = out; \
uint8_t *end = out + os * len; \
CONV_LOOP(otype, expr) \
}
#define CONV_FUNC_INTERLEAVE(ofmt, otype, ifmt, itype, expr) \
static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t **in, \
int len, int channels) \
{ \
int ch; \
int out_bps = sizeof(otype); \
int is = sizeof(itype); \
int os = channels * out_bps; \
for (ch = 0; ch < channels; ch++) { \
const uint8_t *pi = in[ch]; \
uint8_t *po = out + ch * out_bps; \
uint8_t *end = po + os * len; \
CONV_LOOP(otype, expr) \
} \
}
#define CONV_FUNC_DEINTERLEAVE(ofmt, otype, ifmt, itype, expr) \
static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t **out, const uint8_t *in, \
int len, int channels) \
{ \
int ch; \
int in_bps = sizeof(itype); \
int is = channels * in_bps; \
int os = sizeof(otype); \
for (ch = 0; ch < channels; ch++) { \
const uint8_t *pi = in + ch * in_bps; \
uint8_t *po = out[ch]; \
uint8_t *end = po + os * len; \
CONV_LOOP(otype, expr) \
} \
}
#define CONV_FUNC_GROUP(ofmt, otype, ifmt, itype, expr) \
CONV_FUNC_FLAT( ofmt, otype, ifmt, itype, expr) \
CONV_FUNC_INTERLEAVE( ofmt, otype, ifmt ## P, itype, expr) \
CONV_FUNC_DEINTERLEAVE(ofmt ## P, otype, ifmt, itype, expr)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_U8, uint8_t, *(const uint8_t *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 8)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 24)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0f / (1 << 7)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0 / (1 << 7)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t, (*(const int16_t *)pi >> 8) + 0x80)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi << 16)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0f / (1 << 15)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0 / (1 << 15)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t, (*(const int32_t *)pi >> 24) + 0x80)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi >> 16)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0f / (1U << 31)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0 / (1U << 31)))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8( lrintf(*(const float *)pi * (1 << 7)) + 0x80))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16( lrintf(*(const float *)pi * (1 << 15))))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *)pi * (1U << 31))))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_FLT, float, *(const float *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_FLT, float, *(const float *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8( lrint(*(const double *)pi * (1 << 7)) + 0x80))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16( lrint(*(const double *)pi * (1 << 15))))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *)pi * (1U << 31))))
CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_DBL, double, *(const double *)pi)
CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_DBL, double, *(const double *)pi)
#define SET_CONV_FUNC_GROUP(ofmt, ifmt) \
ff_audio_convert_set_func(ac, ofmt, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt)); \
ff_audio_convert_set_func(ac, ofmt ## P, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt ## P, ifmt)); \
ff_audio_convert_set_func(ac, ofmt, ifmt ## P, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt ## P));
static void set_generic_function(AudioConvert *ac)
{
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL)
SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL)
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);
av_freep(ac);
}
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate,
int apply_map)
{
AudioConvert *ac;
int in_planar, out_planar;
ac = av_mallocz(sizeof(*ac));
if (!ac)
return NULL;
ac->avr = avr;
ac->out_fmt = out_fmt;
ac->in_fmt = in_fmt;
ac->channels = channels;
ac->apply_map = apply_map;
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,
apply_map);
if (!ac->dc) {
av_free(ac);
return NULL;
}
return ac;
}
in_planar = ff_sample_fmt_is_planar(in_fmt, channels);
out_planar = ff_sample_fmt_is_planar(out_fmt, channels);
if (in_planar == out_planar) {
ac->func_type = CONV_FUNC_TYPE_FLAT;
ac->planes = in_planar ? ac->channels : 1;
} else if (in_planar)
ac->func_type = CONV_FUNC_TYPE_INTERLEAVE;
else
ac->func_type = CONV_FUNC_TYPE_DEINTERLEAVE;
set_generic_function(ac);
if (ARCH_AARCH64)
ff_audio_convert_init_aarch64(ac);
if (ARCH_ARM)
ff_audio_convert_init_arm(ac);
if (ARCH_X86)
ff_audio_convert_init_x86(ac);
return ac;
}
int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in)
{
int use_generic = 1;
int len = in->nb_samples;
int p;
if (ac->dc) {
/* dithered conversion */
av_log(ac->avr, AV_LOG_TRACE, "%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) {
int ptr_align = FFMIN(in->ptr_align, out->ptr_align);
int samples_align = FFMIN(in->samples_align, out->samples_align);
int aligned_len = FFALIGN(len, ac->samples_align);
if (!(ptr_align % ac->ptr_align) && samples_align >= aligned_len) {
len = aligned_len;
use_generic = 0;
}
}
av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\n", len,
av_get_sample_fmt_name(ac->in_fmt),
av_get_sample_fmt_name(ac->out_fmt),
use_generic ? ac->func_descr_generic : ac->func_descr);
if (ac->apply_map) {
ChannelMapInfo *map = &ac->avr->ch_map_info;
if (!ff_sample_fmt_is_planar(ac->out_fmt, ac->channels)) {
av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n");
return AVERROR(EINVAL);
}
if (map->do_remap) {
if (ff_sample_fmt_is_planar(ac->in_fmt, ac->channels)) {
conv_func_flat *convert = use_generic ? ac->conv_flat_generic :
ac->conv_flat;
for (p = 0; p < ac->planes; p++)
if (map->channel_map[p] >= 0)
convert(out->data[p], in->data[map->channel_map[p]], len);
} else {
uint8_t *data[AVRESAMPLE_MAX_CHANNELS];
conv_func_deinterleave *convert = use_generic ?
ac->conv_deinterleave_generic :
ac->conv_deinterleave;
for (p = 0; p < ac->channels; p++)
data[map->input_map[p]] = out->data[p];
convert(data, in->data[0], len, ac->channels);
}
}
if (map->do_copy || map->do_zero) {
for (p = 0; p < ac->planes; p++) {
if (map->channel_copy[p])
memcpy(out->data[p], out->data[map->channel_copy[p]],
len * out->stride);
else if (map->channel_zero[p])
av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt);
}
}
} else {
switch (ac->func_type) {
case CONV_FUNC_TYPE_FLAT: {
if (!in->is_planar)
len *= in->channels;
if (use_generic) {
for (p = 0; p < ac->planes; p++)
ac->conv_flat_generic(out->data[p], in->data[p], len);
} else {
for (p = 0; p < ac->planes; p++)
ac->conv_flat(out->data[p], in->data[p], len);
}
break;
}
case CONV_FUNC_TYPE_INTERLEAVE:
if (use_generic)
ac->conv_interleave_generic(out->data[0], in->data, len,
ac->channels);
else
ac->conv_interleave(out->data[0], in->data, len, ac->channels);
break;
case CONV_FUNC_TYPE_DEINTERLEAVE:
if (use_generic)
ac->conv_deinterleave_generic(out->data, in->data[0], len,
ac->channels);
else
ac->conv_deinterleave(out->data, in->data[0], len,
ac->channels);
break;
}
}
out->nb_samples = in->nb_samples;
return 0;
}

View File

@ -1,103 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_AUDIO_CONVERT_H
#define AVRESAMPLE_AUDIO_CONVERT_H
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
/**
* Set conversion function if the parameters match.
*
* This compares the parameters of the conversion function to the parameters
* in the AudioConvert context. If the parameters do not match, no changes are
* made to the active functions. If the parameters do match and the alignment
* is not constrained, the function is set as the generic conversion function.
* If the parameters match and the alignment is constrained, the function is
* set as the optimized conversion function.
*
* @param ac AudioConvert context
* @param out_fmt output sample format
* @param in_fmt input sample format
* @param channels number of channels, or 0 for any number of channels
* @param ptr_align buffer pointer alignment, in bytes
* @param samples_align buffer size alignment, in samples
* @param descr function type description (e.g. "C" or "SSE")
* @param conv conversion function pointer
*/
void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt, int channels,
int ptr_align, int samples_align,
const char *descr, void *conv);
/**
* 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
* @param sample_rate sample rate (used for dithering)
* @param apply_map apply channel map during conversion
* @return newly-allocated AudioConvert context
*/
AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate,
int apply_map);
/**
* 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.
*
* For each call, the alignment of the input and output AudioData buffers are
* examined to determine whether to use the generic or optimized conversion
* function (when available).
*
* The number of samples to convert is determined by in->nb_samples. The output
* buffer must be large enough to handle this many samples. out->nb_samples is
* set by this function before a successful return.
*
* @param ac AudioConvert context
* @param out output audio data
* @param in input audio data
* @return 0 on success, negative AVERROR code on failure
*/
int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in);
/* arch-specific initialization functions */
void ff_audio_convert_init_aarch64(AudioConvert *ac);
void ff_audio_convert_init_arm(AudioConvert *ac);
void ff_audio_convert_init_x86(AudioConvert *ac);
#endif /* AVRESAMPLE_AUDIO_CONVERT_H */

View File

@ -1,381 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include <string.h>
#include "libavutil/mem.h"
#include "audio_data.h"
static const AVClass audio_data_class = {
.class_name = "AudioData",
.item_name = av_default_item_name,
.version = LIBAVUTIL_VERSION_INT,
};
/*
* Calculate alignment for data pointers.
*/
static void calc_ptr_alignment(AudioData *a)
{
int p;
int min_align = 128;
for (p = 0; p < a->planes; p++) {
int cur_align = 128;
while ((intptr_t)a->data[p] % cur_align)
cur_align >>= 1;
if (cur_align < min_align)
min_align = cur_align;
}
a->ptr_align = min_align;
}
int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels)
{
if (channels == 1)
return 1;
else
return av_sample_fmt_is_planar(sample_fmt);
}
int ff_audio_data_set_channels(AudioData *a, int channels)
{
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
channels > a->allocated_channels)
return AVERROR(EINVAL);
a->channels = channels;
a->planes = a->is_planar ? channels : 1;
calc_ptr_alignment(a);
return 0;
}
int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size,
int channels, int nb_samples,
enum AVSampleFormat sample_fmt, int read_only,
const char *name)
{
int p;
memset(a, 0, sizeof(*a));
a->class = &audio_data_class;
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
return AVERROR(EINVAL);
}
a->sample_size = av_get_bytes_per_sample(sample_fmt);
if (!a->sample_size) {
av_log(a, AV_LOG_ERROR, "invalid sample format\n");
return AVERROR(EINVAL);
}
a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
a->planes = a->is_planar ? channels : 1;
a->stride = a->sample_size * (a->is_planar ? 1 : channels);
for (p = 0; p < (a->is_planar ? channels : 1); p++) {
if (!src[p]) {
av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
return AVERROR(EINVAL);
}
a->data[p] = src[p];
}
a->allocated_samples = nb_samples * !read_only;
a->nb_samples = nb_samples;
a->sample_fmt = sample_fmt;
a->channels = channels;
a->allocated_channels = channels;
a->read_only = read_only;
a->allow_realloc = 0;
a->name = name ? name : "{no name}";
calc_ptr_alignment(a);
a->samples_align = plane_size / a->stride;
return 0;
}
AudioData *ff_audio_data_alloc(int channels, int nb_samples,
enum AVSampleFormat sample_fmt, const char *name)
{
AudioData *a;
int ret;
if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
return NULL;
a = av_mallocz(sizeof(*a));
if (!a)
return NULL;
a->sample_size = av_get_bytes_per_sample(sample_fmt);
if (!a->sample_size) {
av_free(a);
return NULL;
}
a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
a->planes = a->is_planar ? channels : 1;
a->stride = a->sample_size * (a->is_planar ? 1 : channels);
a->class = &audio_data_class;
a->sample_fmt = sample_fmt;
a->channels = channels;
a->allocated_channels = channels;
a->read_only = 0;
a->allow_realloc = 1;
a->name = name ? name : "{no name}";
if (nb_samples > 0) {
ret = ff_audio_data_realloc(a, nb_samples);
if (ret < 0) {
av_free(a);
return NULL;
}
return a;
} else {
calc_ptr_alignment(a);
return a;
}
}
int ff_audio_data_realloc(AudioData *a, int nb_samples)
{
int ret, new_buf_size, plane_size, p;
/* check if buffer is already large enough */
if (a->allocated_samples >= nb_samples)
return 0;
/* validate that the output is not read-only and realloc is allowed */
if (a->read_only || !a->allow_realloc)
return AVERROR(EINVAL);
new_buf_size = av_samples_get_buffer_size(&plane_size,
a->allocated_channels, nb_samples,
a->sample_fmt, 0);
if (new_buf_size < 0)
return new_buf_size;
/* if there is already data in the buffer and the sample format is planar,
allocate a new buffer and copy the data, otherwise just realloc the
internal buffer and set new data pointers */
if (a->nb_samples > 0 && a->is_planar) {
uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
nb_samples, a->sample_fmt, 0);
if (ret < 0)
return ret;
for (p = 0; p < a->planes; p++)
memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
av_freep(&a->buffer);
memcpy(a->data, new_data, sizeof(new_data));
a->buffer = a->data[0];
} else {
av_freep(&a->buffer);
a->buffer = av_malloc(new_buf_size);
if (!a->buffer)
return AVERROR(ENOMEM);
ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
a->allocated_channels, nb_samples,
a->sample_fmt, 0);
if (ret < 0)
return ret;
}
a->buffer_size = new_buf_size;
a->allocated_samples = nb_samples;
calc_ptr_alignment(a);
a->samples_align = plane_size / a->stride;
return 0;
}
void ff_audio_data_free(AudioData **a)
{
if (!*a)
return;
av_free((*a)->buffer);
av_freep(a);
}
int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
{
int ret, p;
/* validate input/output compatibility */
if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
return AVERROR(EINVAL);
if (map && !src->is_planar) {
av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
return AVERROR(EINVAL);
}
/* if the input is empty, just empty the output */
if (!src->nb_samples) {
dst->nb_samples = 0;
return 0;
}
/* reallocate output if necessary */
ret = ff_audio_data_realloc(dst, src->nb_samples);
if (ret < 0)
return ret;
/* copy data */
if (map) {
if (map->do_remap) {
for (p = 0; p < src->planes; p++) {
if (map->channel_map[p] >= 0)
memcpy(dst->data[p], src->data[map->channel_map[p]],
src->nb_samples * src->stride);
}
}
if (map->do_copy || map->do_zero) {
for (p = 0; p < src->planes; p++) {
if (map->channel_copy[p])
memcpy(dst->data[p], dst->data[map->channel_copy[p]],
src->nb_samples * src->stride);
else if (map->channel_zero[p])
av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
1, dst->sample_fmt);
}
}
} else {
for (p = 0; p < src->planes; p++)
memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
}
dst->nb_samples = src->nb_samples;
return 0;
}
int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
int src_offset, int nb_samples)
{
int ret, p, dst_offset2, dst_move_size;
/* validate input/output compatibility */
if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
return AVERROR(EINVAL);
}
/* validate offsets are within the buffer bounds */
if (dst_offset < 0 || dst_offset > dst->nb_samples ||
src_offset < 0 || src_offset > src->nb_samples) {
av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
src_offset, dst_offset);
return AVERROR(EINVAL);
}
/* check offsets and sizes to see if we can just do nothing and return */
if (nb_samples > src->nb_samples - src_offset)
nb_samples = src->nb_samples - src_offset;
if (nb_samples <= 0)
return 0;
/* validate that the output is not read-only */
if (dst->read_only) {
av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
return AVERROR(EINVAL);
}
/* reallocate output if necessary */
ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
if (ret < 0) {
av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
return ret;
}
dst_offset2 = dst_offset + nb_samples;
dst_move_size = dst->nb_samples - dst_offset;
for (p = 0; p < src->planes; p++) {
if (dst_move_size > 0) {
memmove(dst->data[p] + dst_offset2 * dst->stride,
dst->data[p] + dst_offset * dst->stride,
dst_move_size * dst->stride);
}
memcpy(dst->data[p] + dst_offset * dst->stride,
src->data[p] + src_offset * src->stride,
nb_samples * src->stride);
}
dst->nb_samples += nb_samples;
return 0;
}
void ff_audio_data_drain(AudioData *a, int nb_samples)
{
if (a->nb_samples <= nb_samples) {
/* drain the whole buffer */
a->nb_samples = 0;
} else {
int p;
int move_offset = a->stride * nb_samples;
int move_size = a->stride * (a->nb_samples - nb_samples);
for (p = 0; p < a->planes; p++)
memmove(a->data[p], a->data[p] + move_offset, move_size);
a->nb_samples -= nb_samples;
}
}
int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
int nb_samples)
{
uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
int offset_size, p;
if (offset >= a->nb_samples)
return 0;
offset_size = offset * a->stride;
for (p = 0; p < a->planes; p++)
offset_data[p] = a->data[p] + offset_size;
return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
}
int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
{
int ret;
if (a->read_only)
return AVERROR(EINVAL);
ret = ff_audio_data_realloc(a, nb_samples);
if (ret < 0)
return ret;
ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
if (ret >= 0)
a->nb_samples = ret;
return ret;
}

View File

@ -1,178 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_AUDIO_DATA_H
#define AVRESAMPLE_AUDIO_DATA_H
#include <stdint.h>
#include "libavutil/audio_fifo.h"
#include "libavutil/log.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels);
/**
* Audio buffer used for intermediate storage between conversion phases.
*/
struct AudioData {
const AVClass *class; /**< AVClass for logging */
uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */
uint8_t *buffer; /**< data buffer */
unsigned int buffer_size; /**< allocated buffer size */
int allocated_samples; /**< number of samples the buffer can hold */
int nb_samples; /**< current number of samples */
enum AVSampleFormat sample_fmt; /**< sample format */
int channels; /**< channel count */
int allocated_channels; /**< allocated channel count */
int is_planar; /**< sample format is planar */
int planes; /**< number of data planes */
int sample_size; /**< bytes per sample */
int stride; /**< sample byte offset within a plane */
int read_only; /**< data is read-only */
int allow_realloc; /**< realloc is allowed */
int ptr_align; /**< minimum data pointer alignment */
int samples_align; /**< allocated samples alignment */
const char *name; /**< name for debug logging */
};
int ff_audio_data_set_channels(AudioData *a, int channels);
/**
* Initialize AudioData using a given source.
*
* This does not allocate an internal buffer. It only sets the data pointers
* and audio parameters.
*
* @param a AudioData struct
* @param src source data pointers
* @param plane_size plane size, in bytes.
* This can be 0 if unknown, but that will lead to
* optimized functions not being used in many cases,
* which could slow down some conversions.
* @param channels channel count
* @param nb_samples number of samples in the source data
* @param sample_fmt sample format
* @param read_only indicates if buffer is read only or read/write
* @param name name for debug logging (can be NULL)
* @return 0 on success, negative AVERROR value on error
*/
int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size,
int channels, int nb_samples,
enum AVSampleFormat sample_fmt, int read_only,
const char *name);
/**
* Allocate AudioData.
*
* This allocates an internal buffer and sets audio parameters.
*
* @param channels channel count
* @param nb_samples number of samples to allocate space for
* @param sample_fmt sample format
* @param name name for debug logging (can be NULL)
* @return newly allocated AudioData struct, or NULL on error
*/
AudioData *ff_audio_data_alloc(int channels, int nb_samples,
enum AVSampleFormat sample_fmt,
const char *name);
/**
* Reallocate AudioData.
*
* The AudioData must have been previously allocated with ff_audio_data_alloc().
*
* @param a AudioData struct
* @param nb_samples number of samples to allocate space for
* @return 0 on success, negative AVERROR value on error
*/
int ff_audio_data_realloc(AudioData *a, int nb_samples);
/**
* Free AudioData.
*
* The AudioData must have been previously allocated with ff_audio_data_alloc().
*
* @param a AudioData struct
*/
void ff_audio_data_free(AudioData **a);
/**
* Copy data from one AudioData to another.
*
* @param out output AudioData
* @param in input AudioData
* @param map channel map, NULL if not remapping
* @return 0 on success, negative AVERROR value on error
*/
int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map);
/**
* Append data from one AudioData to the end of another.
*
* @param dst destination AudioData
* @param dst_offset offset, in samples, to start writing, relative to the
* start of dst
* @param src source AudioData
* @param src_offset offset, in samples, to start copying, relative to the
* start of the src
* @param nb_samples number of samples to copy
* @return 0 on success, negative AVERROR value on error
*/
int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
int src_offset, int nb_samples);
/**
* Drain samples from the start of the AudioData.
*
* Remaining samples are shifted to the start of the AudioData.
*
* @param a AudioData struct
* @param nb_samples number of samples to drain
*/
void ff_audio_data_drain(AudioData *a, int nb_samples);
/**
* Add samples in AudioData to an AVAudioFifo.
*
* @param af Audio FIFO Buffer
* @param a AudioData struct
* @param offset number of samples to skip from the start of the data
* @param nb_samples number of samples to add to the FIFO
* @return number of samples actually added to the FIFO, or
* negative AVERROR code on error
*/
int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
int nb_samples);
/**
* Read samples from an AVAudioFifo to AudioData.
*
* @param af Audio FIFO Buffer
* @param a AudioData struct
* @param nb_samples number of samples to read from the FIFO
* @return number of samples actually read from the FIFO, or
* negative AVERROR code on error
*/
int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples);
#endif /* AVRESAMPLE_AUDIO_DATA_H */

View File

@ -1,742 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include "libavutil/common.h"
#include "libavutil/libm.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
#include "audio_mix.h"
static const char * const coeff_type_names[] = { "q8", "q15", "flt" };
struct AudioMix {
AVAudioResampleContext *avr;
enum AVSampleFormat fmt;
enum AVMixCoeffType coeff_type;
uint64_t in_layout;
uint64_t out_layout;
int in_channels;
int out_channels;
int ptr_align;
int samples_align;
int has_optimized_func;
const char *func_descr;
const char *func_descr_generic;
mix_func *mix;
mix_func *mix_generic;
int in_matrix_channels;
int out_matrix_channels;
int output_zero[AVRESAMPLE_MAX_CHANNELS];
int input_skip[AVRESAMPLE_MAX_CHANNELS];
int output_skip[AVRESAMPLE_MAX_CHANNELS];
int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS];
int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS];
float *matrix_flt[AVRESAMPLE_MAX_CHANNELS];
void **matrix;
};
void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
enum AVMixCoeffType coeff_type, int in_channels,
int out_channels, int ptr_align, int samples_align,
const char *descr, void *mix_func)
{
if (fmt == am->fmt && coeff_type == am->coeff_type &&
( in_channels == am->in_matrix_channels || in_channels == 0) &&
(out_channels == am->out_matrix_channels || out_channels == 0)) {
char chan_str[16];
am->mix = mix_func;
am->func_descr = descr;
am->ptr_align = ptr_align;
am->samples_align = samples_align;
if (ptr_align == 1 && samples_align == 1) {
am->mix_generic = mix_func;
am->func_descr_generic = descr;
} else {
am->has_optimized_func = 1;
}
if (in_channels) {
if (out_channels)
snprintf(chan_str, sizeof(chan_str), "[%d to %d] ",
in_channels, out_channels);
else
snprintf(chan_str, sizeof(chan_str), "[%d to any] ",
in_channels);
} else if (out_channels) {
snprintf(chan_str, sizeof(chan_str), "[any to %d] ",
out_channels);
} else {
snprintf(chan_str, sizeof(chan_str), "[any to any] ");
}
av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] "
"[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt),
coeff_type_names[coeff_type], chan_str, descr);
}
}
#define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c
#define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr) \
static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix, \
int len, int out_ch, int in_ch) \
{ \
int i, in, out; \
stype temp[AVRESAMPLE_MAX_CHANNELS]; \
for (i = 0; i < len; i++) { \
for (out = 0; out < out_ch; out++) { \
sumtype sum = 0; \
for (in = 0; in < in_ch; in++) \
sum += samples[in][i] * matrix[out][in]; \
temp[out] = expr; \
} \
for (out = 0; out < out_ch; out++) \
samples[out][i] = temp[out]; \
} \
}
MIX_FUNC_GENERIC(FLTP, FLT, float, float, float, sum)
MIX_FUNC_GENERIC(S16P, FLT, int16_t, float, float, av_clip_int16(lrintf(sum)))
MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15))
MIX_FUNC_GENERIC(S16P, Q8, int16_t, int16_t, int32_t, av_clip_int16(sum >> 8))
/* TODO: templatize the channel-specific C functions */
static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len,
int out_ch, int in_ch)
{
float *src0 = samples[0];
float *src1 = samples[1];
float *dst = src0;
float m0 = matrix[0][0];
float m1 = matrix[0][1];
while (len > 4) {
*dst++ = *src0++ * m0 + *src1++ * m1;
*dst++ = *src0++ * m0 + *src1++ * m1;
*dst++ = *src0++ * m0 + *src1++ * m1;
*dst++ = *src0++ * m0 + *src1++ * m1;
len -= 4;
}
while (len > 0) {
*dst++ = *src0++ * m0 + *src1++ * m1;
len--;
}
}
static void mix_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len,
int out_ch, int in_ch)
{
int16_t *src0 = samples[0];
int16_t *src1 = samples[1];
int16_t *dst = src0;
float m0 = matrix[0][0];
float m1 = matrix[0][1];
while (len > 4) {
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
len -= 4;
}
while (len > 0) {
*dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1));
len--;
}
}
static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len,
int out_ch, int in_ch)
{
int16_t *src0 = samples[0];
int16_t *src1 = samples[1];
int16_t *dst = src0;
int16_t m0 = matrix[0][0];
int16_t m1 = matrix[0][1];
while (len > 4) {
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
len -= 4;
}
while (len > 0) {
*dst++ = (*src0++ * m0 + *src1++ * m1) >> 8;
len--;
}
}
static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len,
int out_ch, int in_ch)
{
float v;
float *dst0 = samples[0];
float *dst1 = samples[1];
float *src = dst0;
float m0 = matrix[0][0];
float m1 = matrix[1][0];
while (len > 4) {
v = *src++;
*dst0++ = v * m0;
*dst1++ = v * m1;
v = *src++;
*dst0++ = v * m0;
*dst1++ = v * m1;
v = *src++;
*dst0++ = v * m0;
*dst1++ = v * m1;
v = *src++;
*dst0++ = v * m0;
*dst1++ = v * m1;
len -= 4;
}
while (len > 0) {
v = *src++;
*dst0++ = v * m0;
*dst1++ = v * m1;
len--;
}
}
static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len,
int out_ch, int in_ch)
{
float v0, v1;
float *src0 = samples[0];
float *src1 = samples[1];
float *src2 = samples[2];
float *src3 = samples[3];
float *src4 = samples[4];
float *src5 = samples[5];
float *dst0 = src0;
float *dst1 = src1;
float *m0 = matrix[0];
float *m1 = matrix[1];
while (len > 0) {
v0 = *src0++;
v1 = *src1++;
*dst0++ = v0 * m0[0] +
v1 * m0[1] +
*src2 * m0[2] +
*src3 * m0[3] +
*src4 * m0[4] +
*src5 * m0[5];
*dst1++ = v0 * m1[0] +
v1 * m1[1] +
*src2++ * m1[2] +
*src3++ * m1[3] +
*src4++ * m1[4] +
*src5++ * m1[5];
len--;
}
}
static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len,
int out_ch, int in_ch)
{
float v0, v1;
float *dst0 = samples[0];
float *dst1 = samples[1];
float *dst2 = samples[2];
float *dst3 = samples[3];
float *dst4 = samples[4];
float *dst5 = samples[5];
float *src0 = dst0;
float *src1 = dst1;
while (len > 0) {
v0 = *src0++;
v1 = *src1++;
*dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1];
*dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1];
*dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1];
*dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1];
*dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1];
*dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1];
len--;
}
}
static av_cold int mix_function_init(AudioMix *am)
{
am->func_descr = am->func_descr_generic = "n/a";
am->mix = am->mix_generic = NULL;
/* no need to set a mix function when we're skipping mixing */
if (!am->in_matrix_channels || !am->out_matrix_channels)
return 0;
/* any-to-any C versions */
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT));
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT));
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15,
0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15));
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8));
/* channel-specific C versions */
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_c);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c);
if (ARCH_X86)
ff_audio_mix_init_x86(am);
if (!am->mix) {
av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] "
"[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt),
coeff_type_names[am->coeff_type], am->in_channels,
am->out_channels);
return AVERROR_PATCHWELCOME;
}
return 0;
}
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
{
AudioMix *am;
int ret;
am = av_mallocz(sizeof(*am));
if (!am)
return NULL;
am->avr = avr;
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
"mixing: %s\n",
av_get_sample_fmt_name(avr->internal_sample_fmt));
goto error;
}
am->fmt = avr->internal_sample_fmt;
am->coeff_type = avr->mix_coeff_type;
am->in_layout = avr->in_channel_layout;
am->out_layout = avr->out_channel_layout;
am->in_channels = avr->in_channels;
am->out_channels = avr->out_channels;
/* build matrix if the user did not already set one */
if (avr->mix_matrix) {
ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
if (ret < 0)
goto error;
av_freep(&avr->mix_matrix);
} else {
double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
sizeof(*matrix_dbl));
if (!matrix_dbl)
goto error;
ret = avresample_build_matrix(avr->in_channel_layout,
avr->out_channel_layout,
avr->center_mix_level,
avr->surround_mix_level,
avr->lfe_mix_level,
avr->normalize_mix_level,
matrix_dbl,
avr->in_channels,
avr->matrix_encoding);
if (ret < 0) {
av_free(matrix_dbl);
goto error;
}
ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
if (ret < 0) {
av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n");
av_free(matrix_dbl);
goto error;
}
av_free(matrix_dbl);
}
return am;
error:
av_free(am);
return NULL;
}
void ff_audio_mix_free(AudioMix **am_p)
{
AudioMix *am;
if (!*am_p)
return;
am = *am_p;
if (am->matrix) {
av_free(am->matrix[0]);
am->matrix = NULL;
}
memset(am->matrix_q8, 0, sizeof(am->matrix_q8 ));
memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
av_freep(am_p);
}
int ff_audio_mix(AudioMix *am, AudioData *src)
{
int use_generic = 1;
int len = src->nb_samples;
int i, j;
/* determine whether to use the optimized function based on pointer and
samples alignment in both the input and output */
if (am->has_optimized_func) {
int aligned_len = FFALIGN(len, am->samples_align);
if (!(src->ptr_align % am->ptr_align) &&
src->samples_align >= aligned_len) {
len = aligned_len;
use_generic = 0;
}
}
av_log(am->avr, AV_LOG_TRACE, "audio_mix: %d samples - %d to %d channels (%s)\n",
src->nb_samples, am->in_channels, am->out_channels,
use_generic ? am->func_descr_generic : am->func_descr);
if (am->in_matrix_channels && am->out_matrix_channels) {
uint8_t **data;
uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL };
if (am->out_matrix_channels < am->out_channels ||
am->in_matrix_channels < am->in_channels) {
for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) {
if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i])
continue;
data0[j++] = src->data[i];
}
data = data0;
} else {
data = src->data;
}
if (use_generic)
am->mix_generic(data, am->matrix, len, am->out_matrix_channels,
am->in_matrix_channels);
else
am->mix(data, am->matrix, len, am->out_matrix_channels,
am->in_matrix_channels);
}
if (am->out_matrix_channels < am->out_channels) {
for (i = 0; i < am->out_channels; i++)
if (am->output_zero[i])
av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt);
}
ff_audio_data_set_channels(src, am->out_channels);
return 0;
}
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
{
int i, o, i0, o0;
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
return AVERROR(EINVAL);
}
#define GET_MATRIX_CONVERT(suffix, scale) \
if (!am->matrix_ ## suffix[0]) { \
av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n"); \
return AVERROR(EINVAL); \
} \
for (o = 0, o0 = 0; o < am->out_channels; o++) { \
for (i = 0, i0 = 0; i < am->in_channels; i++) { \
if (am->input_skip[i] || am->output_zero[o]) \
matrix[o * stride + i] = 0.0; \
else \
matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] * \
(scale); \
if (!am->input_skip[i]) \
i0++; \
} \
if (!am->output_zero[o]) \
o0++; \
}
switch (am->coeff_type) {
case AV_MIX_COEFF_TYPE_Q8:
GET_MATRIX_CONVERT(q8, 1.0 / 256.0);
break;
case AV_MIX_COEFF_TYPE_Q15:
GET_MATRIX_CONVERT(q15, 1.0 / 32768.0);
break;
case AV_MIX_COEFF_TYPE_FLT:
GET_MATRIX_CONVERT(flt, 1.0);
break;
default:
av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
return AVERROR(EINVAL);
}
return 0;
}
static void reduce_matrix(AudioMix *am, const double *matrix, int stride)
{
int i, o;
memset(am->output_zero, 0, sizeof(am->output_zero));
memset(am->input_skip, 0, sizeof(am->input_skip));
memset(am->output_skip, 0, sizeof(am->output_skip));
/* exclude output channels if they can be zeroed instead of mixed */
for (o = 0; o < am->out_channels; o++) {
int zero = 1;
/* check if the output is always silent */
for (i = 0; i < am->in_channels; i++) {
if (matrix[o * stride + i] != 0.0) {
zero = 0;
break;
}
}
/* check if the corresponding input channel makes a contribution to
any output channel */
if (o < am->in_channels) {
for (i = 0; i < am->out_channels; i++) {
if (matrix[i * stride + o] != 0.0) {
zero = 0;
break;
}
}
}
if (zero) {
am->output_zero[o] = 1;
am->out_matrix_channels--;
if (o < am->in_channels)
am->in_matrix_channels--;
}
}
if (am->out_matrix_channels == 0 || am->in_matrix_channels == 0) {
am->out_matrix_channels = 0;
am->in_matrix_channels = 0;
return;
}
/* skip input channels that contribute fully only to the corresponding
output channel */
for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) {
int skip = 1;
for (o = 0; o < am->out_channels; o++) {
int i0;
if ((o != i && matrix[o * stride + i] != 0.0) ||
(o == i && matrix[o * stride + i] != 1.0)) {
skip = 0;
break;
}
/* if the input contributes fully to the output, also check that no
other inputs contribute to this output */
if (o == i) {
for (i0 = 0; i0 < am->in_channels; i0++) {
if (i0 != i && matrix[o * stride + i0] != 0.0) {
skip = 0;
break;
}
}
}
}
if (skip) {
am->input_skip[i] = 1;
am->in_matrix_channels--;
}
}
/* skip input channels that do not contribute to any output channel */
for (; i < am->in_channels; i++) {
int contrib = 0;
for (o = 0; o < am->out_channels; o++) {
if (matrix[o * stride + i] != 0.0) {
contrib = 1;
break;
}
}
if (!contrib) {
am->input_skip[i] = 1;
am->in_matrix_channels--;
}
}
if (am->in_matrix_channels == 0) {
am->out_matrix_channels = 0;
return;
}
/* skip output channels that only get full contribution from the
corresponding input channel */
for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) {
int skip = 1;
int o0;
for (i = 0; i < am->in_channels; i++) {
if ((o != i && matrix[o * stride + i] != 0.0) ||
(o == i && matrix[o * stride + i] != 1.0)) {
skip = 0;
break;
}
}
/* check if the corresponding input channel makes a contribution to
any other output channel */
i = o;
for (o0 = 0; o0 < am->out_channels; o0++) {
if (o0 != i && matrix[o0 * stride + i] != 0.0) {
skip = 0;
break;
}
}
if (skip) {
am->output_skip[o] = 1;
am->out_matrix_channels--;
}
}
if (am->out_matrix_channels == 0) {
am->in_matrix_channels = 0;
return;
}
}
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
{
int i, o, i0, o0, ret;
char in_layout_name[128];
char out_layout_name[128];
if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n");
return AVERROR(EINVAL);
}
if (am->matrix) {
av_free(am->matrix[0]);
am->matrix = NULL;
}
am->in_matrix_channels = am->in_channels;
am->out_matrix_channels = am->out_channels;
reduce_matrix(am, matrix, stride);
#define CONVERT_MATRIX(type, expr) \
am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \
am->in_matrix_channels * \
sizeof(*am->matrix_## type[0])); \
if (!am->matrix_## type[0]) \
return AVERROR(ENOMEM); \
for (o = 0, o0 = 0; o < am->out_channels; o++) { \
if (am->output_zero[o] || am->output_skip[o]) \
continue; \
if (o0 > 0) \
am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \
am->in_matrix_channels; \
for (i = 0, i0 = 0; i < am->in_channels; i++) { \
double v; \
if (am->input_skip[i] || am->output_zero[i]) \
continue; \
v = matrix[o * stride + i]; \
am->matrix_## type[o0][i0] = expr; \
i0++; \
} \
o0++; \
} \
am->matrix = (void **)am->matrix_## type;
if (am->in_matrix_channels && am->out_matrix_channels) {
switch (am->coeff_type) {
case AV_MIX_COEFF_TYPE_Q8:
CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
break;
case AV_MIX_COEFF_TYPE_Q15:
CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
break;
case AV_MIX_COEFF_TYPE_FLT:
CONVERT_MATRIX(flt, v)
break;
default:
av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
return AVERROR(EINVAL);
}
}
ret = mix_function_init(am);
if (ret < 0)
return ret;
av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
am->in_channels, am->in_layout);
av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name),
am->out_channels, am->out_layout);
av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n",
in_layout_name, out_layout_name);
av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n",
am->in_matrix_channels, am->out_matrix_channels);
for (o = 0; o < am->out_channels; o++) {
for (i = 0; i < am->in_channels; i++) {
if (am->output_zero[o])
av_log(am->avr, AV_LOG_DEBUG, " (ZERO)");
else if (am->input_skip[i] || am->output_zero[i] || am->output_skip[o])
av_log(am->avr, AV_LOG_DEBUG, " (SKIP)");
else
av_log(am->avr, AV_LOG_DEBUG, " %0.3f ",
matrix[o * am->in_channels + i]);
}
av_log(am->avr, AV_LOG_DEBUG, "\n");
}
return 0;
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_AUDIO_MIX_H
#define AVRESAMPLE_AUDIO_MIX_H
#include <stdint.h>
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch,
int in_ch);
/**
* Set mixing function if the parameters match.
*
* This compares the parameters of the mixing function to the parameters in the
* AudioMix context. If the parameters do not match, no changes are made to the
* active functions. If the parameters do match and the alignment is not
* constrained, the function is set as the generic mixing function. If the
* parameters match and the alignment is constrained, the function is set as
* the optimized mixing function.
*
* @param am AudioMix context
* @param fmt input/output sample format
* @param coeff_type mixing coefficient type
* @param in_channels number of input channels, or 0 for any number of channels
* @param out_channels number of output channels, or 0 for any number of channels
* @param ptr_align buffer pointer alignment, in bytes
* @param samples_align buffer size alignment, in samples
* @param descr function type description (e.g. "C" or "SSE")
* @param mix_func mixing function pointer
*/
void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
enum AVMixCoeffType coeff_type, int in_channels,
int out_channels, int ptr_align, int samples_align,
const char *descr, void *mix_func);
/**
* Allocate and initialize an AudioMix context.
*
* The parameters in the AVAudioResampleContext are used to initialize the
* AudioMix context.
*
* @param avr AVAudioResampleContext
* @return newly-allocated AudioMix context.
*/
AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr);
/**
* Free an AudioMix context.
*/
void ff_audio_mix_free(AudioMix **am);
/**
* Apply channel mixing to audio data using the current mixing matrix.
*/
int ff_audio_mix(AudioMix *am, AudioData *src);
/**
* Get the current mixing matrix.
*/
int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride);
/**
* Set the current mixing matrix.
*/
int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride);
/* arch-specific initialization functions */
void ff_audio_mix_init_x86(AudioMix *am);
#endif /* AVRESAMPLE_AUDIO_MIX_H */

View File

@ -1,294 +0,0 @@
/*
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include "libavutil/common.h"
#include "libavutil/libm.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
#include "audio_mix.h"
/* channel positions */
#define FRONT_LEFT 0
#define FRONT_RIGHT 1
#define FRONT_CENTER 2
#define LOW_FREQUENCY 3
#define BACK_LEFT 4
#define BACK_RIGHT 5
#define FRONT_LEFT_OF_CENTER 6
#define FRONT_RIGHT_OF_CENTER 7
#define BACK_CENTER 8
#define SIDE_LEFT 9
#define SIDE_RIGHT 10
#define TOP_CENTER 11
#define TOP_FRONT_LEFT 12
#define TOP_FRONT_CENTER 13
#define TOP_FRONT_RIGHT 14
#define TOP_BACK_LEFT 15
#define TOP_BACK_CENTER 16
#define TOP_BACK_RIGHT 17
#define STEREO_LEFT 29
#define STEREO_RIGHT 30
#define WIDE_LEFT 31
#define WIDE_RIGHT 32
#define SURROUND_DIRECT_LEFT 33
#define SURROUND_DIRECT_RIGHT 34
#define LOW_FREQUENCY_2 35
#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
static av_always_inline int even(uint64_t layout)
{
return (!layout || !!(layout & (layout - 1)));
}
static int sane_layout(uint64_t layout)
{
/* check that there is at least 1 front speaker */
if (!(layout & AV_CH_LAYOUT_SURROUND))
return 0;
/* check for left/right symmetry */
if (!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)) ||
!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)) ||
!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)) ||
!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)) ||
!even(layout & (AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT)) ||
!even(layout & (AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT)) ||
!even(layout & (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT)) ||
!even(layout & (AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT)) ||
!even(layout & (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT)))
return 0;
return 1;
}
int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
double center_mix_level, double surround_mix_level,
double lfe_mix_level, int normalize,
double *matrix_out, int stride,
enum AVMatrixEncoding matrix_encoding)
{
int i, j, out_i, out_j;
double matrix[64][64] = {{0}};
int64_t unaccounted;
double maxcoef = 0;
int in_channels, out_channels;
if ((out_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX) {
out_layout = AV_CH_LAYOUT_STEREO;
}
unaccounted = in_layout & ~out_layout;
in_channels = av_get_channel_layout_nb_channels( in_layout);
out_channels = av_get_channel_layout_nb_channels(out_layout);
memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out));
/* check if layouts are supported */
if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS)
return AVERROR(EINVAL);
if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS)
return AVERROR(EINVAL);
/* check if layouts are unbalanced or abnormal */
if (!sane_layout(in_layout) || !sane_layout(out_layout))
return AVERROR_PATCHWELCOME;
/* route matching input/output channels */
for (i = 0; i < 64; i++) {
if (in_layout & out_layout & (1ULL << i))
matrix[i][i] = 1.0;
}
/* mix front center to front left/right */
if (unaccounted & AV_CH_FRONT_CENTER) {
if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) {
if ((in_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) {
matrix[FRONT_LEFT ][FRONT_CENTER] += center_mix_level;
matrix[FRONT_RIGHT][FRONT_CENTER] += center_mix_level;
} else {
matrix[FRONT_LEFT ][FRONT_CENTER] += M_SQRT1_2;
matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2;
}
} else
return AVERROR_PATCHWELCOME;
}
/* mix front left/right to center */
if (unaccounted & AV_CH_LAYOUT_STEREO) {
if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2;
matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2;
/* mix left/right/center to center */
if (in_layout & AV_CH_FRONT_CENTER)
matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2;
} else
return AVERROR_PATCHWELCOME;
}
/* mix back center to back, side, or front */
if (unaccounted & AV_CH_BACK_CENTER) {
if (out_layout & AV_CH_BACK_LEFT) {
matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2;
matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2;
} else if (out_layout & AV_CH_SIDE_LEFT) {
matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2;
matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2;
} else if (out_layout & AV_CH_FRONT_LEFT) {
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
} else {
matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level;
matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level;
}
} else {
matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
}
} else if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2;
} else
return AVERROR_PATCHWELCOME;
}
/* mix back left/right to back center, side, or front */
if (unaccounted & AV_CH_BACK_LEFT) {
if (out_layout & AV_CH_BACK_CENTER) {
matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2;
matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2;
} else if (out_layout & AV_CH_SIDE_LEFT) {
/* if side channels do not exist in the input, just copy back
channels to side channels, otherwise mix back into side */
if (in_layout & AV_CH_SIDE_LEFT) {
matrix[SIDE_LEFT ][BACK_LEFT ] += M_SQRT1_2;
matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2;
} else {
matrix[SIDE_LEFT ][BACK_LEFT ] += 1.0;
matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0;
}
} else if (out_layout & AV_CH_FRONT_LEFT) {
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2;
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2;
matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2;
} else {
matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level;
matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level;
}
} else if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2;
} else
return AVERROR_PATCHWELCOME;
}
/* mix side left/right into back or front */
if (unaccounted & AV_CH_SIDE_LEFT) {
if (out_layout & AV_CH_BACK_LEFT) {
/* if back channels do not exist in the input, just copy side
channels to back channels, otherwise mix side into back */
if (in_layout & AV_CH_BACK_LEFT) {
matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2;
matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
} else {
matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0;
matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
}
} else if (out_layout & AV_CH_BACK_CENTER) {
matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2;
matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2;
} else if (out_layout & AV_CH_FRONT_LEFT) {
if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2;
} else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2;
matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2;
} else {
matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level;
matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level;
}
} else if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2;
matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2;
} else
return AVERROR_PATCHWELCOME;
}
/* mix left-of-center/right-of-center into front left/right or center */
if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) {
if (out_layout & AV_CH_FRONT_LEFT) {
matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0;
matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0;
} else if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2;
matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2;
} else
return AVERROR_PATCHWELCOME;
}
/* mix LFE into front left/right or center */
if (unaccounted & AV_CH_LOW_FREQUENCY) {
if (out_layout & AV_CH_FRONT_CENTER) {
matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level;
} else if (out_layout & AV_CH_FRONT_LEFT) {
matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2;
} else
return AVERROR_PATCHWELCOME;
}
/* transfer internal matrix to output matrix and calculate maximum
per-channel coefficient sum */
for (out_i = i = 0; out_i < out_channels && i < 64; i++) {
double sum = 0;
for (out_j = j = 0; out_j < in_channels && j < 64; j++) {
matrix_out[out_i * stride + out_j] = matrix[i][j];
sum += fabs(matrix[i][j]);
if (in_layout & (1ULL << j))
out_j++;
}
maxcoef = FFMAX(maxcoef, sum);
if (out_layout & (1ULL << i))
out_i++;
}
/* normalize */
if (normalize && maxcoef > 1.0) {
for (i = 0; i < out_channels; i++)
for (j = 0; j < in_channels; j++)
matrix_out[i * stride + j] /= maxcoef;
}
return 0;
}

View File

@ -1,595 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_AVRESAMPLE_H
#define AVRESAMPLE_AVRESAMPLE_H
/**
* @file
* @ingroup lavr
* external API header
*/
/**
* @defgroup lavr libavresample
* @{
*
* Libavresample (lavr) is a library that handles audio resampling, sample
* format conversion and mixing.
*
* Interaction with lavr is done through AVAudioResampleContext, which is
* allocated with avresample_alloc_context(). It is opaque, so all parameters
* must be set with the @ref avoptions API.
*
* For example the following code will setup conversion from planar float sample
* format to interleaved signed 16-bit integer, downsampling from 48kHz to
* 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing
* matrix):
* @code
* AVAudioResampleContext *avr = avresample_alloc_context();
* av_opt_set_int(avr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0);
* av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
* av_opt_set_int(avr, "in_sample_rate", 48000, 0);
* av_opt_set_int(avr, "out_sample_rate", 44100, 0);
* av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
* av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
* @endcode
*
* Once the context is initialized, it must be opened with avresample_open(). If
* you need to change the conversion parameters, you must close the context with
* avresample_close(), change the parameters as described above, then reopen it
* again.
*
* The conversion itself is done by repeatedly calling avresample_convert().
* Note that the samples may get buffered in two places in lavr. The first one
* is the output FIFO, where the samples end up if the output buffer is not
* large enough. The data stored in there may be retrieved at any time with
* avresample_read(). The second place is the resampling delay buffer,
* applicable only when resampling is done. The samples in it require more input
* before they can be processed. Their current amount is returned by
* avresample_get_delay(). At the end of conversion the resampling buffer can be
* flushed by calling avresample_convert() with NULL input.
*
* The following code demonstrates the conversion loop assuming the parameters
* from above and caller-defined functions get_input() and handle_output():
* @code
* uint8_t **input;
* int in_linesize, in_samples;
*
* while (get_input(&input, &in_linesize, &in_samples)) {
* uint8_t *output
* int out_linesize;
* int out_samples = avresample_get_out_samples(avr, in_samples);
*
* av_samples_alloc(&output, &out_linesize, 2, out_samples,
* AV_SAMPLE_FMT_S16, 0);
* out_samples = avresample_convert(avr, &output, out_linesize, out_samples,
* input, in_linesize, in_samples);
* handle_output(output, out_linesize, out_samples);
* av_freep(&output);
* }
* @endcode
*
* When the conversion is finished and the FIFOs are flushed if required, the
* conversion context and everything associated with it must be freed with
* avresample_free().
*/
#include "libavutil/avutil.h"
#include "libavutil/channel_layout.h"
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
#include "libavresample/version.h"
#define AVRESAMPLE_MAX_CHANNELS 32
typedef struct AVAudioResampleContext AVAudioResampleContext;
/**
* @deprecated use libswresample
*
* Mixing Coefficient Types */
enum attribute_deprecated AVMixCoeffType {
AV_MIX_COEFF_TYPE_Q8, /** 16-bit 8.8 fixed-point */
AV_MIX_COEFF_TYPE_Q15, /** 32-bit 17.15 fixed-point */
AV_MIX_COEFF_TYPE_FLT, /** floating-point */
AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */
};
/**
* @deprecated use libswresample
*
* Resampling Filter Types */
enum attribute_deprecated AVResampleFilterType {
AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */
AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */
AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */
};
/**
* @deprecated use libswresample
*/
enum attribute_deprecated 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. */
};
/**
*
* @deprecated use libswresample
*
* Return the LIBAVRESAMPLE_VERSION_INT constant.
*/
attribute_deprecated
unsigned avresample_version(void);
/**
*
* @deprecated use libswresample
*
* Return the libavresample build-time configuration.
* @return configure string
*/
attribute_deprecated
const char *avresample_configuration(void);
/**
*
* @deprecated use libswresample
*
* Return the libavresample license.
*/
attribute_deprecated
const char *avresample_license(void);
/**
*
* @deprecated use libswresample
*
* Get the AVClass for AVAudioResampleContext.
*
* Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options
* without allocating a context.
*
* @see av_opt_find().
*
* @return AVClass for AVAudioResampleContext
*/
attribute_deprecated
const AVClass *avresample_get_class(void);
/**
*
* @deprecated use libswresample
*
* Allocate AVAudioResampleContext and set options.
*
* @return allocated audio resample context, or NULL on failure
*/
attribute_deprecated
AVAudioResampleContext *avresample_alloc_context(void);
/**
*
* @deprecated use libswresample
*
* Initialize AVAudioResampleContext.
* @note The context must be configured using the AVOption API.
* @note The fields "in_channel_layout", "out_channel_layout",
* "in_sample_rate", "out_sample_rate", "in_sample_fmt",
* "out_sample_fmt" must be set.
*
* @see av_opt_set_int()
* @see av_opt_set_dict()
* @see av_get_default_channel_layout()
*
* @param avr audio resample context
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_open(AVAudioResampleContext *avr);
/**
*
* @deprecated use libswresample
*
* Check whether an AVAudioResampleContext is open or closed.
*
* @param avr AVAudioResampleContext to check
* @return 1 if avr is open, 0 if avr is closed.
*/
attribute_deprecated
int avresample_is_open(AVAudioResampleContext *avr);
/**
*
* @deprecated use libswresample
*
* Close AVAudioResampleContext.
*
* This closes the context, but it does not change the parameters. The context
* can be reopened with avresample_open(). It does, however, clear the output
* FIFO and any remaining leftover samples in the resampling delay buffer. If
* there was a custom matrix being used, that is also cleared.
*
* @see avresample_convert()
* @see avresample_set_matrix()
*
* @param avr audio resample context
*/
attribute_deprecated
void avresample_close(AVAudioResampleContext *avr);
/**
*
* @deprecated use libswresample
*
* Free AVAudioResampleContext and associated AVOption values.
*
* This also calls avresample_close() before freeing.
*
* @param avr audio resample context
*/
attribute_deprecated
void avresample_free(AVAudioResampleContext **avr);
/**
*
* @deprecated use libswresample
*
* Generate a channel mixing matrix.
*
* This function is the one used internally by libavresample for building the
* default mixing matrix. It is made public just as a utility function for
* building custom matrices.
*
* @param in_layout input channel layout
* @param out_layout output channel layout
* @param center_mix_level mix level for the center channel
* @param surround_mix_level mix level for the surround channel(s)
* @param lfe_mix_level mix level for the low-frequency effects channel
* @param normalize if 1, coefficients will be normalized to prevent
* overflow. if 0, coefficients will not be
* normalized.
* @param[out] matrix mixing coefficients; matrix[i + stride * o] is
* the weight of input channel i in output channel o.
* @param stride distance between adjacent input channels in the
* matrix array
* @param matrix_encoding matrixed stereo downmix mode (e.g. dplii)
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
double center_mix_level, double surround_mix_level,
double lfe_mix_level, int normalize, double *matrix,
int stride, enum AVMatrixEncoding matrix_encoding);
/**
*
* @deprecated use libswresample
*
* Get the current channel mixing matrix.
*
* If no custom matrix has been previously set or the AVAudioResampleContext is
* not open, an error is returned.
*
* @param avr audio resample context
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
* input channel i in output channel o.
* @param stride distance between adjacent input channels in the matrix array
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
int stride);
/**
*
* @deprecated use libswresample
*
* Set channel mixing matrix.
*
* Allows for setting a custom mixing matrix, overriding the default matrix
* generated internally during avresample_open(). This function can be called
* anytime on an allocated context, either before or after calling
* avresample_open(), as long as the channel layouts have been set.
* avresample_convert() always uses the current matrix.
* Calling avresample_close() on the context will clear the current matrix.
*
* @see avresample_close()
*
* @param avr audio resample context
* @param matrix mixing coefficients; matrix[i + stride * o] is the weight of
* input channel i in output channel o.
* @param stride distance between adjacent input channels in the matrix array
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
int stride);
/**
*
* @deprecated use libswresample
*
* Set a customized input channel mapping.
*
* This function can only be called when the allocated context is not open.
* Also, the input channel layout must have already been set.
*
* Calling avresample_close() on the context will clear the channel mapping.
*
* The map for each input channel specifies the channel index in the source to
* use for that particular channel, or -1 to mute the channel. Source channels
* can be duplicated by using the same index for multiple input channels.
*
* Examples:
*
* Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to FFmpeg order (L,R,C,LFE,Ls,Rs):
* { 1, 2, 0, 5, 3, 4 }
*
* Muting the 3rd channel in 4-channel input:
* { 0, 1, -1, 3 }
*
* Duplicating the left channel of stereo input:
* { 0, 0 }
*
* @param avr audio resample context
* @param channel_map customized input channel mapping
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_set_channel_mapping(AVAudioResampleContext *avr,
const int *channel_map);
/**
*
* @deprecated use libswresample
*
* Set compensation for resampling.
*
* This can be called anytime after avresample_open(). If resampling is not
* automatically enabled because of a sample rate conversion, the
* "force_resampling" option must have been set to 1 when opening the context
* in order to use resampling compensation.
*
* @param avr audio resample context
* @param sample_delta compensation delta, in samples
* @param compensation_distance compensation distance, in samples
* @return 0 on success, negative AVERROR code on failure
*/
attribute_deprecated
int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta,
int compensation_distance);
/**
*
* @deprecated use libswresample
*
* Provide the upper bound on the number of samples the configured
* conversion would output.
*
* @param avr audio resample context
* @param in_nb_samples number of input samples
*
* @return number of samples or AVERROR(EINVAL) if the value
* would exceed INT_MAX
*/
attribute_deprecated
int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples);
/**
*
* @deprecated use libswresample
*
* Convert input samples and write them to the output FIFO.
*
* The upper bound on the number of output samples can be obtained through
* avresample_get_out_samples().
*
* The output data can be NULL or have fewer allocated samples than required.
* In this case, any remaining samples not written to the output will be added
* to an internal FIFO buffer, to be returned at the next call to this function
* or to avresample_read().
*
* If converting sample rate, there may be data remaining in the internal
* resampling delay buffer. avresample_get_delay() tells the number of remaining
* samples. To get this data as output, call avresample_convert() with NULL
* input.
*
* At the end of the conversion process, there may be data remaining in the
* internal FIFO buffer. avresample_available() tells the number of remaining
* samples. To get this data as output, either call avresample_convert() with
* NULL input or call avresample_read().
*
* @see avresample_get_out_samples()
* @see avresample_read()
* @see avresample_get_delay()
*
* @param avr audio resample context
* @param output output data pointers
* @param out_plane_size output plane size, in bytes.
* This can be 0 if unknown, but that will lead to
* optimized functions not being used directly on the
* output, which could slow down some conversions.
* @param out_samples maximum number of samples that the output buffer can hold
* @param input input data pointers
* @param in_plane_size input plane size, in bytes
* This can be 0 if unknown, but that will lead to
* optimized functions not being used directly on the
* input, which could slow down some conversions.
* @param in_samples number of input samples to convert
* @return number of samples written to the output buffer,
* not including converted samples added to the internal
* output FIFO
*/
attribute_deprecated
int avresample_convert(AVAudioResampleContext *avr, uint8_t **output,
int out_plane_size, int out_samples,
uint8_t * const *input, int in_plane_size,
int in_samples);
/**
*
* @deprecated use libswresample
*
* Return the number of samples currently in the resampling delay buffer.
*
* When resampling, there may be a delay between the input and output. Any
* unconverted samples in each call are stored internally in a delay buffer.
* This function allows the user to determine the current number of samples in
* the delay buffer, which can be useful for synchronization.
*
* @see avresample_convert()
*
* @param avr audio resample context
* @return number of samples currently in the resampling delay buffer
*/
attribute_deprecated
int avresample_get_delay(AVAudioResampleContext *avr);
/**
*
* @deprecated use libswresample
*
* Return the number of available samples in the output FIFO.
*
* During conversion, if the user does not specify an output buffer or
* specifies an output buffer that is smaller than what is needed, remaining
* samples that are not written to the output are stored to an internal FIFO
* buffer. The samples in the FIFO can be read with avresample_read() or
* avresample_convert().
*
* @see avresample_read()
* @see avresample_convert()
*
* @param avr audio resample context
* @return number of samples available for reading
*/
attribute_deprecated
int avresample_available(AVAudioResampleContext *avr);
/**
*
* @deprecated use libswresample
*
* Read samples from the output FIFO.
*
* During conversion, if the user does not specify an output buffer or
* specifies an output buffer that is smaller than what is needed, remaining
* samples that are not written to the output are stored to an internal FIFO
* buffer. This function can be used to read samples from that internal FIFO.
*
* @see avresample_available()
* @see avresample_convert()
*
* @param avr audio resample context
* @param output output data pointers. May be NULL, in which case
* nb_samples of data is discarded from output FIFO.
* @param nb_samples number of samples to read from the FIFO
* @return the number of samples written to output
*/
attribute_deprecated
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples);
/**
*
* @deprecated use libswresample
*
* Convert the samples in the input AVFrame and write them to the output AVFrame.
*
* Input and output AVFrames must have channel_layout, sample_rate and format set.
*
* The upper bound on the number of output samples is obtained through
* avresample_get_out_samples().
*
* If the output AVFrame does not have the data pointers allocated the nb_samples
* field will be set using avresample_get_out_samples() and av_frame_get_buffer()
* is called to allocate the frame.
*
* The output AVFrame can be NULL or have fewer allocated samples than required.
* In this case, any remaining samples not written to the output will be added
* to an internal FIFO buffer, to be returned at the next call to this function
* or to avresample_convert() or to avresample_read().
*
* If converting sample rate, there may be data remaining in the internal
* resampling delay buffer. avresample_get_delay() tells the number of
* remaining samples. To get this data as output, call this function or
* avresample_convert() with NULL input.
*
* At the end of the conversion process, there may be data remaining in the
* internal FIFO buffer. avresample_available() tells the number of remaining
* samples. To get this data as output, either call this function or
* avresample_convert() with NULL input or call avresample_read().
*
* If the AVAudioResampleContext configuration does not match the output and
* input AVFrame settings the conversion does not take place and depending on
* which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED
* or AVERROR_OUTPUT_CHANGED|AVERROR_INPUT_CHANGED is returned.
*
* @see avresample_get_out_samples()
* @see avresample_available()
* @see avresample_convert()
* @see avresample_read()
* @see avresample_get_delay()
*
* @param avr audio resample context
* @param output output AVFrame
* @param input input AVFrame
* @return 0 on success, AVERROR on failure or nonmatching
* configuration.
*/
attribute_deprecated
int avresample_convert_frame(AVAudioResampleContext *avr,
AVFrame *output, AVFrame *input);
/**
*
* @deprecated use libswresample
*
* Configure or reconfigure the AVAudioResampleContext using the information
* provided by the AVFrames.
*
* The original resampling context is reset even on failure.
* The function calls avresample_close() internally if the context is open.
*
* @see avresample_open();
* @see avresample_close();
*
* @param avr audio resample context
* @param out output AVFrame
* @param in input AVFrame
* @return 0 on success, AVERROR on failure.
*/
attribute_deprecated
int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in);
/**
* @}
*/
#endif /* AVRESAMPLE_AVRESAMPLE_H */

View File

@ -1,55 +0,0 @@
/*
* Windows resource file for libavresample
*
* Copyright (C) 2012 James Almer
* Copyright (C) 2013 Tiancheng "Timothy" Gu
*
* 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
*/
#include <windows.h>
#include "libavresample/version.h"
#include "libavutil/ffversion.h"
#include "config.h"
1 VERSIONINFO
FILEVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0
PRODUCTVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "CompanyName", "FFmpeg Project"
VALUE "FileDescription", "Libav audio resampling library"
VALUE "FileVersion", AV_STRINGIFY(LIBAVRESAMPLE_VERSION)
VALUE "InternalName", "libavresample"
VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
VALUE "OriginalFilename", "avresample" BUILDSUF "-" AV_STRINGIFY(LIBAVRESAMPLE_VERSION_MAJOR) SLIBSUF
VALUE "ProductName", "FFmpeg"
VALUE "ProductVersion", FFMPEG_VERSION
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409, 0x04B0
}
}

View File

@ -1,440 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* Triangular with Noise Shaping is based on opusfile.
* Copyright (c) 1994-2012 by the Xiph.Org Foundation and contributors
*
* 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
* Dithered Audio Sample Quantization
*
* Converts from dbl, flt, or s32 to s16 using dithering.
*/
#include <math.h>
#include <stdint.h>
#include "libavutil/attributes.h"
#include "libavutil/common.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;
unsigned int seed;
AVLFG lfg;
float *noise_buf;
int noise_buf_size;
int noise_buf_ptr;
float dither_a[4];
float dither_b[4];
} DitherState;
struct DitherContext {
DitherDSPContext ddsp;
enum AVResampleDitherMethod method;
int apply_map;
ChannelMapInfo *ch_map_info;
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
int channels;
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)
void (*quantize)(int16_t *dst, const float *src, float *dither, int len);
int samples_align;
};
/* mute threshold, in seconds */
#define MUTE_THRESHOLD_SEC 0.000333
/* scale factor for 16-bit output.
The signal is attenuated slightly to avoid clipping */
#define S16_SCALE 32753.0f
/* scale to convert lfg from INT_MIN/INT_MAX to -0.5/0.5 */
#define LFG_SCALE (1.0f / (2.0f * INT32_MAX))
/* 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
};
static void dither_int_to_float_rectangular_c(float *dst, int *src, int len)
{
int i;
for (i = 0; i < len; i++)
dst[i] = src[i] * LFG_SCALE;
}
static void dither_int_to_float_triangular_c(float *dst, int *src0, int len)
{
int i;
int *src1 = src0 + len;
for (i = 0; i < len; i++) {
float r = src0[i] * LFG_SCALE;
r += src1[i] * LFG_SCALE;
dst[i] = r;
}
}
static void quantize_c(int16_t *dst, const float *src, float *dither, int len)
{
int i;
for (i = 0; i < len; i++)
dst[i] = av_clip_int16(lrintf(src[i] * S16_SCALE + dither[i]));
}
#define SQRT_1_6 0.40824829046386301723f
static void dither_highpass_filter(float *src, int len)
{
int i;
/* filter is from libswresample in FFmpeg */
for (i = 0; i < len - 2; i++)
src[i] = (-src[i] + 2 * src[i + 1] - src[i + 2]) * SQRT_1_6;
}
static int generate_dither_noise(DitherContext *c, DitherState *state,
int min_samples)
{
int i;
int nb_samples = FFALIGN(min_samples, 16) + 16;
int buf_samples = nb_samples *
(c->method == AV_RESAMPLE_DITHER_RECTANGULAR ? 1 : 2);
unsigned int *noise_buf_ui;
av_freep(&state->noise_buf);
state->noise_buf_size = state->noise_buf_ptr = 0;
state->noise_buf = av_malloc(buf_samples * sizeof(*state->noise_buf));
if (!state->noise_buf)
return AVERROR(ENOMEM);
state->noise_buf_size = FFALIGN(min_samples, 16);
noise_buf_ui = (unsigned int *)state->noise_buf;
av_lfg_init(&state->lfg, state->seed);
for (i = 0; i < buf_samples; i++)
noise_buf_ui[i] = av_lfg_get(&state->lfg);
c->ddsp.dither_int_to_float(state->noise_buf, noise_buf_ui, nb_samples);
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_HP)
dither_highpass_filter(state->noise_buf, nb_samples);
return 0;
}
static void quantize_triangular_ns(DitherContext *c, DitherState *state,
int16_t *dst, const float *src,
int nb_samples)
{
int i, j;
float *dither = &state->noise_buf[state->noise_buf_ptr];
if (state->mute > c->mute_reset_threshold)
memset(state->dither_a, 0, sizeof(state->dither_a));
for (i = 0; i < nb_samples; i++) {
float err = 0;
float sample = src[i] * S16_SCALE;
for (j = 0; j < 4; j++) {
err += c->ns_coef_b[j] * state->dither_b[j] -
c->ns_coef_a[j] * state->dither_a[j];
}
for (j = 3; j > 0; j--) {
state->dither_a[j] = state->dither_a[j - 1];
state->dither_b[j] = state->dither_b[j - 1];
}
state->dither_a[0] = err;
sample -= err;
if (state->mute > c->mute_dither_threshold) {
dst[i] = av_clip_int16(lrintf(sample));
state->dither_b[0] = 0;
} else {
dst[i] = av_clip_int16(lrintf(sample + dither[i]));
state->dither_b[0] = av_clipf(dst[i] - sample, -1.5f, 1.5f);
}
state->mute++;
if (src[i])
state->mute = 0;
}
}
static int convert_samples(DitherContext *c, int16_t **dst, float * const *src,
int channels, int nb_samples)
{
int ch, ret;
int aligned_samples = FFALIGN(nb_samples, 16);
for (ch = 0; ch < channels; ch++) {
DitherState *state = &c->state[ch];
if (state->noise_buf_size < aligned_samples) {
ret = generate_dither_noise(c, state, nb_samples);
if (ret < 0)
return ret;
} else if (state->noise_buf_size - state->noise_buf_ptr < aligned_samples) {
state->noise_buf_ptr = 0;
}
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) {
quantize_triangular_ns(c, state, dst[ch], src[ch], nb_samples);
} else {
c->quantize(dst[ch], src[ch],
&state->noise_buf[state->noise_buf_ptr],
FFALIGN(nb_samples, c->samples_align));
}
state->noise_buf_ptr += aligned_samples;
}
return 0;
}
int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src)
{
int ret;
AudioData *flt_data;
/* output directly to dst if it is planar */
if (dst->sample_fmt == AV_SAMPLE_FMT_S16P)
c->s16_data = dst;
else {
/* make sure s16_data is large enough for the output */
ret = ff_audio_data_realloc(c->s16_data, src->nb_samples);
if (ret < 0)
return ret;
}
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
/* make sure flt_data is large enough for the input */
ret = ff_audio_data_realloc(c->flt_data, src->nb_samples);
if (ret < 0)
return ret;
flt_data = c->flt_data;
}
if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) {
/* convert input samples to fltp and scale to s16 range */
ret = ff_audio_convert(c->ac_in, flt_data, src);
if (ret < 0)
return ret;
} else if (c->apply_map) {
ret = ff_audio_data_copy(flt_data, src, c->ch_map_info);
if (ret < 0)
return ret;
} else {
flt_data = src;
}
/* check alignment and padding constraints */
if (c->method != AV_RESAMPLE_DITHER_TRIANGULAR_NS) {
int ptr_align = FFMIN(flt_data->ptr_align, c->s16_data->ptr_align);
int samples_align = FFMIN(flt_data->samples_align, c->s16_data->samples_align);
int aligned_len = FFALIGN(src->nb_samples, c->ddsp.samples_align);
if (!(ptr_align % c->ddsp.ptr_align) && samples_align >= aligned_len) {
c->quantize = c->ddsp.quantize;
c->samples_align = c->ddsp.samples_align;
} else {
c->quantize = quantize_c;
c->samples_align = 1;
}
}
ret = convert_samples(c, (int16_t **)c->s16_data->data,
(float * const *)flt_data->data, src->channels,
src->nb_samples);
if (ret < 0)
return ret;
c->s16_data->nb_samples = src->nb_samples;
/* interleave output to dst if needed */
if (dst->sample_fmt == AV_SAMPLE_FMT_S16) {
ret = ff_audio_convert(c->ac_out, dst, c->s16_data);
if (ret < 0)
return ret;
} else
c->s16_data = NULL;
return 0;
}
void ff_dither_free(DitherContext **cp)
{
DitherContext *c = *cp;
int ch;
if (!c)
return;
ff_audio_data_free(&c->flt_data);
ff_audio_data_free(&c->s16_data);
ff_audio_convert_free(&c->ac_in);
ff_audio_convert_free(&c->ac_out);
for (ch = 0; ch < c->channels; ch++)
av_free(c->state[ch].noise_buf);
av_free(c->state);
av_freep(cp);
}
static av_cold void dither_init(DitherDSPContext *ddsp,
enum AVResampleDitherMethod method)
{
ddsp->quantize = quantize_c;
ddsp->ptr_align = 1;
ddsp->samples_align = 1;
if (method == AV_RESAMPLE_DITHER_RECTANGULAR)
ddsp->dither_int_to_float = dither_int_to_float_rectangular_c;
else
ddsp->dither_int_to_float = dither_int_to_float_triangular_c;
if (ARCH_X86)
ff_dither_init_x86(ddsp, method);
}
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate, int apply_map)
{
AVLFG seed_gen;
DitherContext *c;
int ch;
if (av_get_packed_sample_fmt(out_fmt) != AV_SAMPLE_FMT_S16 ||
av_get_bytes_per_sample(in_fmt) <= 2) {
av_log(avr, AV_LOG_ERROR, "dithering %s to %s is not supported\n",
av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt));
return NULL;
}
c = av_mallocz(sizeof(*c));
if (!c)
return NULL;
c->apply_map = apply_map;
if (apply_map)
c->ch_map_info = &avr->ch_map_info;
if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS &&
sample_rate != 48000 && sample_rate != 44100) {
av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz "
"for triangular_ns dither. using triangular_hp instead.\n");
avr->dither_method = AV_RESAMPLE_DITHER_TRIANGULAR_HP;
}
c->method = avr->dither_method;
dither_init(&c->ddsp, c->method);
if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) {
if (sample_rate == 48000) {
c->ns_coef_b = ns_48_coef_b;
c->ns_coef_a = ns_48_coef_a;
} else {
c->ns_coef_b = ns_44_coef_b;
c->ns_coef_a = ns_44_coef_a;
}
}
/* Either s16 or s16p output format is allowed, but s16p is used
internally, so we need to use a temp buffer and interleave if the output
format is s16 */
if (out_fmt != AV_SAMPLE_FMT_S16P) {
c->s16_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_S16P,
"dither s16 buffer");
if (!c->s16_data)
goto fail;
c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P,
channels, sample_rate, 0);
if (!c->ac_out)
goto fail;
}
if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) {
c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP,
"dither flt buffer");
if (!c->flt_data)
goto fail;
}
if (in_fmt != AV_SAMPLE_FMT_FLTP) {
c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt,
channels, sample_rate, c->apply_map);
if (!c->ac_in)
goto fail;
}
c->state = av_mallocz(channels * sizeof(*c->state));
if (!c->state)
goto fail;
c->channels = channels;
/* calculate thresholds for turning off dithering during periods of
silence to avoid replacing digital silence with quiet dither noise */
c->mute_dither_threshold = lrintf(sample_rate * MUTE_THRESHOLD_SEC);
c->mute_reset_threshold = c->mute_dither_threshold * 4;
/* initialize dither states */
av_lfg_init(&seed_gen, 0xC0FFEE);
for (ch = 0; ch < channels; ch++) {
DitherState *state = &c->state[ch];
state->mute = c->mute_reset_threshold + 1;
state->seed = av_lfg_get(&seed_gen);
generate_dither_noise(c, state, FFMAX(32768, sample_rate / 2));
}
return c;
fail:
ff_dither_free(&c);
return NULL;
}

View File

@ -1,93 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_DITHER_H
#define AVRESAMPLE_DITHER_H
#include "avresample.h"
#include "audio_data.h"
typedef struct DitherContext DitherContext;
typedef struct DitherDSPContext {
/**
* Convert samples from flt to s16 with added dither noise.
*
* @param dst destination float array, range -0.5 to 0.5
* @param src source int array, range INT_MIN to INT_MAX.
* @param dither float dither noise array
* @param len number of samples
*/
void (*quantize)(int16_t *dst, const float *src, float *dither, int len);
int ptr_align; ///< src and dst constraints for quantize()
int samples_align; ///< len constraints for quantize()
/**
* Convert dither noise from int to float with triangular distribution.
*
* @param dst destination float array, range -0.5 to 0.5
* constraints: 32-byte aligned
* @param src0 source int array, range INT_MIN to INT_MAX.
* the array size is len * 2
* constraints: 32-byte aligned
* @param len number of output noise samples
* constraints: multiple of 16
*/
void (*dither_int_to_float)(float *dst, int *src0, int len);
} DitherDSPContext;
/**
* Allocate and initialize a DitherContext.
*
* The parameters in the AVAudioResampleContext are used to initialize the
* DitherContext.
*
* @param avr AVAudioResampleContext
* @return newly-allocated DitherContext
*/
DitherContext *ff_dither_alloc(AVAudioResampleContext *avr,
enum AVSampleFormat out_fmt,
enum AVSampleFormat in_fmt,
int channels, int sample_rate, int apply_map);
/**
* Free a DitherContext.
*
* @param c DitherContext
*/
void ff_dither_free(DitherContext **c);
/**
* Convert audio sample format with dithering.
*
* @param c DitherContext
* @param dst destination audio data
* @param src source audio data
* @return 0 if ok, negative AVERROR code on failure
*/
int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src);
/* arch-specific initialization functions */
void ff_dither_init_x86(DitherDSPContext *ddsp,
enum AVResampleDitherMethod method);
#endif /* AVRESAMPLE_DITHER_H */

View File

@ -1,116 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#ifndef AVRESAMPLE_INTERNAL_H
#define AVRESAMPLE_INTERNAL_H
#include "libavutil/audio_fifo.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
#include "avresample.h"
typedef struct AudioData AudioData;
typedef struct AudioConvert AudioConvert;
typedef struct AudioMix AudioMix;
typedef struct ResampleContext ResampleContext;
enum RemapPoint {
REMAP_NONE,
REMAP_IN_COPY,
REMAP_IN_CONVERT,
REMAP_OUT_COPY,
REMAP_OUT_CONVERT,
};
typedef struct ChannelMapInfo {
int channel_map[AVRESAMPLE_MAX_CHANNELS]; /**< source index of each output channel, -1 if not remapped */
int do_remap; /**< remap needed */
int channel_copy[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to copy from */
int do_copy; /**< copy needed */
int channel_zero[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to zero */
int do_zero; /**< zeroing needed */
int input_map[AVRESAMPLE_MAX_CHANNELS]; /**< dest index of each input channel */
} ChannelMapInfo;
struct AVAudioResampleContext {
const AVClass *av_class; /**< AVClass for logging and AVOptions */
uint64_t in_channel_layout; /**< input channel layout */
enum AVSampleFormat in_sample_fmt; /**< input sample format */
int in_sample_rate; /**< input sample rate */
uint64_t out_channel_layout; /**< output channel layout */
enum AVSampleFormat out_sample_fmt; /**< output sample format */
int out_sample_rate; /**< output sample rate */
enum AVSampleFormat internal_sample_fmt; /**< internal sample format */
enum AVMixCoeffType mix_coeff_type; /**< mixing coefficient type */
double center_mix_level; /**< center mix level */
double surround_mix_level; /**< surround mix level */
double lfe_mix_level; /**< lfe mix level */
int normalize_mix_level; /**< enable mix level normalization */
int force_resampling; /**< force resampling */
int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */
double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */
enum AVResampleFilterType filter_type; /**< resampling filter type */
int kaiser_beta; /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
enum AVResampleDitherMethod dither_method; /**< dither method */
int in_channels; /**< number of input channels */
int out_channels; /**< number of output channels */
int resample_channels; /**< number of channels used for resampling */
int downmix_needed; /**< downmixing is needed */
int upmix_needed; /**< upmixing is needed */
int mixing_needed; /**< either upmixing or downmixing is needed */
int resample_needed; /**< resampling is needed */
int in_convert_needed; /**< input sample format conversion is needed */
int out_convert_needed; /**< output sample format conversion is needed */
int in_copy_needed; /**< input data copy is needed */
AudioData *in_buffer; /**< buffer for converted input */
AudioData *resample_out_buffer; /**< buffer for output from resampler */
AudioData *out_buffer; /**< buffer for converted output */
AVAudioFifo *out_fifo; /**< FIFO for output samples */
AudioConvert *ac_in; /**< input sample format conversion context */
AudioConvert *ac_out; /**< output sample format conversion context */
ResampleContext *resample; /**< resampling context */
AudioMix *am; /**< channel mixing context */
enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */
/**
* mix matrix
* only used if avresample_set_matrix() is called before avresample_open()
*/
double *mix_matrix;
int use_channel_map;
enum RemapPoint remap_point;
ChannelMapInfo ch_map_info;
};
void ff_audio_resample_init_aarch64(ResampleContext *c,
enum AVSampleFormat sample_fmt);
void ff_audio_resample_init_arm(ResampleContext *c,
enum AVSampleFormat sample_fmt);
#endif /* AVRESAMPLE_INTERNAL_H */

View File

@ -1,6 +0,0 @@
LIBAVRESAMPLE_MAJOR {
global:
av*;
local:
*;
};

View File

@ -1,113 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include "libavutil/mathematics.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_mix.h"
/**
* @file
* Options definition for AVAudioResampleContext.
*/
#define OFFSET(x) offsetof(AVAudioResampleContext, x)
#define PARAM AV_OPT_FLAG_AUDIO_PARAM
static const AVOption avresample_options[] = {
{ "in_channel_layout", "Input Channel Layout", OFFSET(in_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM },
{ "in_sample_fmt", "Input Sample Format", OFFSET(in_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM },
{ "in_sample_rate", "Input Sample Rate", OFFSET(in_sample_rate), AV_OPT_TYPE_INT, { .i64 = 48000 }, 1, INT_MAX, PARAM },
{ "out_channel_layout", "Output Channel Layout", OFFSET(out_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM },
{ "out_sample_fmt", "Output Sample Format", OFFSET(out_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM },
{ "out_sample_rate", "Output Sample Rate", OFFSET(out_sample_rate), AV_OPT_TYPE_INT, { .i64 = 48000 }, 1, INT_MAX, PARAM },
{ "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM, "internal_sample_fmt" },
{"u8" , "8-bit unsigned integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"s16", "16-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"s32", "32-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"flt", "32-bit float", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLT }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"dbl", "64-bit double", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBL }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"u8p" , "8-bit unsigned integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"s16p", "16-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"s32p", "32-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"fltp", "32-bit float planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLTP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{"dblp", "64-bit double planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBLP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"},
{ "mix_coeff_type", "Mixing Coefficient Type", OFFSET(mix_coeff_type), AV_OPT_TYPE_INT, { .i64 = AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q8, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" },
{ "q8", "16-bit 8.8 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q8 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" },
{ "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" },
{ "flt", "Floating-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_FLT }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" },
{ "center_mix_level", "Center Mix Level", OFFSET(center_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM },
{ "surround_mix_level", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM },
{ "lfe_mix_level", "LFE Mix Level", OFFSET(lfe_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, -32.0, 32.0, PARAM },
{ "normalize_mix_level", "Normalize Mix Level", OFFSET(normalize_mix_level), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, PARAM },
{ "force_resampling", "Force Resampling", OFFSET(force_resampling), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM },
{ "filter_size", "Resampling Filter Size", OFFSET(filter_size), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 32, /* ??? */ PARAM },
{ "phase_shift", "Resampling Phase Shift", OFFSET(phase_shift), AV_OPT_TYPE_INT, { .i64 = 10 }, 0, 30, /* ??? */ PARAM },
{ "linear_interp", "Use Linear Interpolation", OFFSET(linear_interp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM },
{ "cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM },
/* duplicate option in order to work with avconv */
{ "resample_cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM },
{ "matrix_encoding", "Matrixed Stereo Encoding", OFFSET(matrix_encoding), AV_OPT_TYPE_INT, {.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" },
{ "none", "None", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
{ "dolby", "Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
{ "dplii", "Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
{ "filter_type", "Filter Type", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, AV_RESAMPLE_FILTER_TYPE_CUBIC, AV_RESAMPLE_FILTER_TYPE_KAISER, PARAM, "filter_type" },
{ "cubic", "Cubic", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" },
{ "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" },
{ "kaiser", "Kaiser Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" },
{ "kaiser_beta", "Kaiser Window Beta", OFFSET(kaiser_beta), AV_OPT_TYPE_INT, { .i64 = 9 }, 2, 16, PARAM },
{ "dither_method", "Dither Method", OFFSET(dither_method), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_DITHER_NONE }, 0, AV_RESAMPLE_DITHER_NB-1, PARAM, "dither_method"},
{"none", "No Dithering", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_NONE }, INT_MIN, INT_MAX, PARAM, "dither_method"},
{"rectangular", "Rectangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_RECTANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"},
{"triangular", "Triangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"},
{"triangular_hp", "Triangular Dither With High Pass", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_HP }, INT_MIN, INT_MAX, PARAM, "dither_method"},
{"triangular_ns", "Triangular Dither With Noise Shaping", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_NS }, INT_MIN, INT_MAX, PARAM, "dither_method"},
{ NULL },
};
static const AVClass av_resample_context_class = {
.class_name = "AVAudioResampleContext",
.item_name = av_default_item_name,
.option = avresample_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVAudioResampleContext *avresample_alloc_context(void)
{
AVAudioResampleContext *avr;
avr = av_mallocz(sizeof(*avr));
if (!avr)
return NULL;
avr->av_class = &av_resample_context_class;
av_opt_set_defaults(avr);
return avr;
}
const AVClass *avresample_get_class(void)
{
return &av_resample_context_class;
}

View File

@ -1,446 +0,0 @@
/*
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include "libavutil/common.h"
#include "libavutil/libm.h"
#include "libavutil/log.h"
#include "internal.h"
#include "resample.h"
#include "audio_data.h"
/* double template */
#define CONFIG_RESAMPLE_DBL
#include "resample_template.c"
#undef CONFIG_RESAMPLE_DBL
/* float template */
#define CONFIG_RESAMPLE_FLT
#include "resample_template.c"
#undef CONFIG_RESAMPLE_FLT
/* s32 template */
#define CONFIG_RESAMPLE_S32
#include "resample_template.c"
#undef CONFIG_RESAMPLE_S32
/* s16 template */
#include "resample_template.c"
/* 0th order modified Bessel function of the first kind. */
static double bessel(double x)
{
double v = 1;
double lastv = 0;
double t = 1;
int i;
x = x * x / 4;
for (i = 1; v != lastv; i++) {
lastv = v;
t *= x / (i * i);
v += t;
}
return v;
}
/* Build a polyphase filterbank. */
static int build_filter(ResampleContext *c, double factor)
{
int ph, i;
double x, y, w;
double *tab;
int tap_count = c->filter_length;
int phase_count = 1 << c->phase_shift;
const int center = (tap_count - 1) / 2;
tab = av_malloc(tap_count * sizeof(*tab));
if (!tab)
return AVERROR(ENOMEM);
for (ph = 0; ph < phase_count; ph++) {
double norm = 0;
for (i = 0; i < tap_count; i++) {
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
if (x == 0) y = 1.0;
else y = sin(x) / x;
switch (c->filter_type) {
case AV_RESAMPLE_FILTER_TYPE_CUBIC: {
const float d = -0.5; //first order derivative = -0.5
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
if (x < 1.0) y = 1 - 3 * x*x + 2 * x*x*x + d * ( -x*x + x*x*x);
else y = d * (-4 + 8 * x - 5 * x*x + x*x*x);
break;
}
case AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL:
w = 2.0 * x / (factor * tap_count) + M_PI;
y *= 0.3635819 - 0.4891775 * cos( w) +
0.1365995 * cos(2 * w) -
0.0106411 * cos(3 * w);
break;
case AV_RESAMPLE_FILTER_TYPE_KAISER:
w = 2.0 * x / (factor * tap_count * M_PI);
y *= bessel(c->kaiser_beta * sqrt(FFMAX(1 - w * w, 0)));
break;
}
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
for (i = 0; i < tap_count; i++)
tab[i] = tab[i] / norm;
c->set_filter(c->filter_bank, tab, ph, tap_count);
}
av_free(tab);
return 0;
}
ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr)
{
ResampleContext *c;
int out_rate = avr->out_sample_rate;
int in_rate = avr->in_sample_rate;
double factor = FFMIN(out_rate * avr->cutoff / in_rate, 1.0);
int phase_count = 1 << avr->phase_shift;
int felem_size;
if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
avr->internal_sample_fmt != AV_SAMPLE_FMT_S32P &&
avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP &&
avr->internal_sample_fmt != AV_SAMPLE_FMT_DBLP) {
av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
"resampling: %s\n",
av_get_sample_fmt_name(avr->internal_sample_fmt));
return NULL;
}
c = av_mallocz(sizeof(*c));
if (!c)
return NULL;
c->avr = avr;
c->phase_shift = avr->phase_shift;
c->phase_mask = phase_count - 1;
c->linear = avr->linear_interp;
c->filter_length = FFMAX((int)ceil(avr->filter_size / factor), 1);
c->filter_type = avr->filter_type;
c->kaiser_beta = avr->kaiser_beta;
switch (avr->internal_sample_fmt) {
case AV_SAMPLE_FMT_DBLP:
c->resample_one = c->linear ? resample_linear_dbl : resample_one_dbl;
c->resample_nearest = resample_nearest_dbl;
c->set_filter = set_filter_dbl;
break;
case AV_SAMPLE_FMT_FLTP:
c->resample_one = c->linear ? resample_linear_flt : resample_one_flt;
c->resample_nearest = resample_nearest_flt;
c->set_filter = set_filter_flt;
break;
case AV_SAMPLE_FMT_S32P:
c->resample_one = c->linear ? resample_linear_s32 : resample_one_s32;
c->resample_nearest = resample_nearest_s32;
c->set_filter = set_filter_s32;
break;
case AV_SAMPLE_FMT_S16P:
c->resample_one = c->linear ? resample_linear_s16 : resample_one_s16;
c->resample_nearest = resample_nearest_s16;
c->set_filter = set_filter_s16;
break;
}
if (ARCH_AARCH64)
ff_audio_resample_init_aarch64(c, avr->internal_sample_fmt);
if (ARCH_ARM)
ff_audio_resample_init_arm(c, avr->internal_sample_fmt);
felem_size = av_get_bytes_per_sample(avr->internal_sample_fmt);
c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * felem_size);
if (!c->filter_bank)
goto error;
if (build_filter(c, factor) < 0)
goto error;
memcpy(&c->filter_bank[(c->filter_length * phase_count + 1) * felem_size],
c->filter_bank, (c->filter_length - 1) * felem_size);
memcpy(&c->filter_bank[c->filter_length * phase_count * felem_size],
&c->filter_bank[(c->filter_length - 1) * felem_size], felem_size);
c->compensation_distance = 0;
if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate,
in_rate * (int64_t)phase_count, INT32_MAX / 2))
goto error;
c->ideal_dst_incr = c->dst_incr;
c->padding_size = (c->filter_length - 1) / 2;
c->initial_padding_filled = 0;
c->index = 0;
c->frac = 0;
/* allocate internal buffer */
c->buffer = ff_audio_data_alloc(avr->resample_channels, c->padding_size,
avr->internal_sample_fmt,
"resample buffer");
if (!c->buffer)
goto error;
c->buffer->nb_samples = c->padding_size;
c->initial_padding_samples = c->padding_size;
av_log(avr, AV_LOG_DEBUG, "resample: %s from %d Hz to %d Hz\n",
av_get_sample_fmt_name(avr->internal_sample_fmt),
avr->in_sample_rate, avr->out_sample_rate);
return c;
error:
ff_audio_data_free(&c->buffer);
av_free(c->filter_bank);
av_free(c);
return NULL;
}
void ff_audio_resample_free(ResampleContext **c)
{
if (!*c)
return;
ff_audio_data_free(&(*c)->buffer);
av_free((*c)->filter_bank);
av_freep(c);
}
int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta,
int compensation_distance)
{
ResampleContext *c;
if (compensation_distance < 0)
return AVERROR(EINVAL);
if (!compensation_distance && sample_delta)
return AVERROR(EINVAL);
if (!avr->resample_needed) {
av_log(avr, AV_LOG_ERROR, "Unable to set resampling compensation\n");
return AVERROR(EINVAL);
}
c = avr->resample;
c->compensation_distance = compensation_distance;
if (compensation_distance) {
c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr *
(int64_t)sample_delta / compensation_distance;
} else {
c->dst_incr = c->ideal_dst_incr;
}
return 0;
}
static int resample(ResampleContext *c, void *dst, const void *src,
int *consumed, int src_size, int dst_size, int update_ctx,
int nearest_neighbour)
{
int dst_index;
unsigned int index = c->index;
int frac = c->frac;
int dst_incr_frac = c->dst_incr % c->src_incr;
int dst_incr = c->dst_incr / c->src_incr;
int compensation_distance = c->compensation_distance;
if (!dst != !src)
return AVERROR(EINVAL);
if (nearest_neighbour) {
uint64_t index2 = ((uint64_t)index) << 32;
int64_t incr = (1LL << 32) * c->dst_incr / c->src_incr;
dst_size = FFMIN(dst_size,
(src_size-1-index) * (int64_t)c->src_incr /
c->dst_incr);
if (dst) {
for(dst_index = 0; dst_index < dst_size; dst_index++) {
c->resample_nearest(dst, dst_index, src, index2 >> 32);
index2 += incr;
}
} else {
dst_index = dst_size;
}
index += dst_index * dst_incr;
index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr;
frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr;
} else {
for (dst_index = 0; dst_index < dst_size; dst_index++) {
int sample_index = index >> c->phase_shift;
if (sample_index + c->filter_length > src_size)
break;
if (dst)
c->resample_one(c, dst, dst_index, src, index, frac);
frac += dst_incr_frac;
index += dst_incr;
if (frac >= c->src_incr) {
frac -= c->src_incr;
index++;
}
if (dst_index + 1 == compensation_distance) {
compensation_distance = 0;
dst_incr_frac = c->ideal_dst_incr % c->src_incr;
dst_incr = c->ideal_dst_incr / c->src_incr;
}
}
}
if (consumed)
*consumed = index >> c->phase_shift;
if (update_ctx) {
index &= c->phase_mask;
if (compensation_distance) {
compensation_distance -= dst_index;
if (compensation_distance <= 0)
return AVERROR_BUG;
}
c->frac = frac;
c->index = index;
c->dst_incr = dst_incr_frac + c->src_incr*dst_incr;
c->compensation_distance = compensation_distance;
}
return dst_index;
}
int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src)
{
int ch, in_samples, in_leftover, consumed = 0, out_samples = 0;
int ret = AVERROR(EINVAL);
int nearest_neighbour = (c->compensation_distance == 0 &&
c->filter_length == 1 &&
c->phase_shift == 0);
in_samples = src ? src->nb_samples : 0;
in_leftover = c->buffer->nb_samples;
/* add input samples to the internal buffer */
if (src) {
ret = ff_audio_data_combine(c->buffer, in_leftover, src, 0, in_samples);
if (ret < 0)
return ret;
} else if (in_leftover <= c->final_padding_samples) {
/* no remaining samples to flush */
return 0;
}
if (!c->initial_padding_filled) {
int bps = av_get_bytes_per_sample(c->avr->internal_sample_fmt);
int i;
if (src && c->buffer->nb_samples < 2 * c->padding_size)
return 0;
for (i = 0; i < c->padding_size; i++)
for (ch = 0; ch < c->buffer->channels; ch++) {
if (c->buffer->nb_samples > 2 * c->padding_size - i) {
memcpy(c->buffer->data[ch] + bps * i,
c->buffer->data[ch] + bps * (2 * c->padding_size - i), bps);
} else {
memset(c->buffer->data[ch] + bps * i, 0, bps);
}
}
c->initial_padding_filled = 1;
}
if (!src && !c->final_padding_filled) {
int bps = av_get_bytes_per_sample(c->avr->internal_sample_fmt);
int i;
ret = ff_audio_data_realloc(c->buffer,
FFMAX(in_samples, in_leftover) +
c->padding_size);
if (ret < 0) {
av_log(c->avr, AV_LOG_ERROR, "Error reallocating resampling buffer\n");
return AVERROR(ENOMEM);
}
for (i = 0; i < c->padding_size; i++)
for (ch = 0; ch < c->buffer->channels; ch++) {
if (in_leftover > i) {
memcpy(c->buffer->data[ch] + bps * (in_leftover + i),
c->buffer->data[ch] + bps * (in_leftover - i - 1),
bps);
} else {
memset(c->buffer->data[ch] + bps * (in_leftover + i),
0, bps);
}
}
c->buffer->nb_samples += c->padding_size;
c->final_padding_samples = c->padding_size;
c->final_padding_filled = 1;
}
/* calculate output size and reallocate output buffer if needed */
/* TODO: try to calculate this without the dummy resample() run */
if (!dst->read_only && dst->allow_realloc) {
out_samples = resample(c, NULL, NULL, NULL, c->buffer->nb_samples,
INT_MAX, 0, nearest_neighbour);
ret = ff_audio_data_realloc(dst, out_samples);
if (ret < 0) {
av_log(c->avr, AV_LOG_ERROR, "error reallocating output\n");
return ret;
}
}
/* resample each channel plane */
for (ch = 0; ch < c->buffer->channels; ch++) {
out_samples = resample(c, (void *)dst->data[ch],
(const void *)c->buffer->data[ch], &consumed,
c->buffer->nb_samples, dst->allocated_samples,
ch + 1 == c->buffer->channels, nearest_neighbour);
}
if (out_samples < 0) {
av_log(c->avr, AV_LOG_ERROR, "error during resampling\n");
return out_samples;
}
/* drain consumed samples from the internal buffer */
ff_audio_data_drain(c->buffer, consumed);
c->initial_padding_samples = FFMAX(c->initial_padding_samples - consumed, 0);
av_log(c->avr, AV_LOG_TRACE, "resampled %d in + %d leftover to %d out + %d leftover\n",
in_samples, in_leftover, out_samples, c->buffer->nb_samples);
dst->nb_samples = out_samples;
return 0;
}
int avresample_get_delay(AVAudioResampleContext *avr)
{
ResampleContext *c = avr->resample;
if (!avr->resample_needed || !avr->resample)
return 0;
return FFMAX(c->buffer->nb_samples - c->padding_size, 0);
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* 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
*/
#ifndef AVRESAMPLE_RESAMPLE_H
#define AVRESAMPLE_RESAMPLE_H
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
struct ResampleContext {
AVAudioResampleContext *avr;
AudioData *buffer;
uint8_t *filter_bank;
int filter_length;
int ideal_dst_incr;
int dst_incr;
unsigned int index;
int frac;
int src_incr;
int compensation_distance;
int phase_shift;
int phase_mask;
int linear;
enum AVResampleFilterType filter_type;
int kaiser_beta;
void (*set_filter)(void *filter, double *tab, int phase, int tap_count);
void (*resample_one)(struct ResampleContext *c, void *dst0,
int dst_index, const void *src0,
unsigned int index, int frac);
void (*resample_nearest)(void *dst0, int dst_index,
const void *src0, unsigned int index);
int padding_size;
int initial_padding_filled;
int initial_padding_samples;
int final_padding_filled;
int final_padding_samples;
};
/**
* Allocate and initialize a ResampleContext.
*
* The parameters in the AVAudioResampleContext are used to initialize the
* ResampleContext.
*
* @param avr AVAudioResampleContext
* @return newly-allocated ResampleContext
*/
ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr);
/**
* Free a ResampleContext.
*
* @param c ResampleContext
*/
void ff_audio_resample_free(ResampleContext **c);
/**
* Resample audio data.
*
* Changes the sample rate.
*
* @par
* All samples in the source data may not be consumed depending on the
* resampling parameters and the size of the output buffer. The unconsumed
* samples are automatically added to the start of the source in the next call.
* If the destination data can be reallocated, that may be done in this function
* in order to fit all available output. If it cannot be reallocated, fewer
* input samples will be consumed in order to have the output fit in the
* destination data buffers.
*
* @param c ResampleContext
* @param dst destination audio data
* @param src source audio data
* @return 0 on success, negative AVERROR code on failure
*/
int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src);
#endif /* AVRESAMPLE_RESAMPLE_H */

View File

@ -1,118 +0,0 @@
/*
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* 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
*/
#include <math.h>
#include <stdint.h>
#include "libavutil/common.h"
#include "internal.h"
#if defined(CONFIG_RESAMPLE_DBL)
#define SET_TYPE(func) func ## _dbl
#define FELEM double
#define FELEM2 double
#define FELEML double
#define OUT(d, v) d = v
#define DBL_TO_FELEM(d, v) d = v
#elif defined(CONFIG_RESAMPLE_FLT)
#define SET_TYPE(func) func ## _flt
#define FELEM float
#define FELEM2 float
#define FELEML float
#define OUT(d, v) d = v
#define DBL_TO_FELEM(d, v) d = v
#elif defined(CONFIG_RESAMPLE_S32)
#define SET_TYPE(func) func ## _s32
#define FELEM int32_t
#define FELEM2 int64_t
#define FELEML int64_t
#define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30)
#define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 30)));
#else
#define SET_TYPE(func) func ## _s16
#define FELEM int16_t
#define FELEM2 int32_t
#define FELEML int64_t
#define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15)
#define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << 15)))
#endif
static void SET_TYPE(resample_nearest)(void *dst0, int dst_index, const void *src0, unsigned int index)
{
FELEM *dst = dst0;
const FELEM *src = src0;
dst[dst_index] = src[index];
}
static void SET_TYPE(resample_linear)(ResampleContext *c, void *dst0, int dst_index,
const void *src0, unsigned int index, int frac)
{
FELEM *dst = dst0;
const FELEM *src = src0;
int i;
unsigned int sample_index = index >> c->phase_shift;
FELEM2 val = 0;
FELEM *filter = ((FELEM *)c->filter_bank) +
c->filter_length * (index & c->phase_mask);
FELEM2 v2 = 0;
for (i = 0; i < c->filter_length; i++) {
val += src[sample_index + i] * (FELEM2)filter[i];
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length];
}
val += (v2 - val) * (FELEML)frac / c->src_incr;
OUT(dst[dst_index], val);
}
static void SET_TYPE(resample_one)(ResampleContext *c,
void *dst0, int dst_index, const void *src0,
unsigned int index, int frac)
{
FELEM *dst = dst0;
const FELEM *src = src0;
int i;
unsigned int sample_index = index >> c->phase_shift;
FELEM2 val = 0;
FELEM *filter = ((FELEM *)c->filter_bank) +
c->filter_length * (index & c->phase_mask);
for (i = 0; i < c->filter_length; i++)
val += src[sample_index + i] * (FELEM2)filter[i];
OUT(dst[dst_index], val);
}
static void SET_TYPE(set_filter)(void *filter0, double *tab, int phase,
int tap_count)
{
int i;
FELEM *filter = ((FELEM *)filter0) + phase * tap_count;
for (i = 0; i < tap_count; i++) {
DBL_TO_FELEM(filter[i], tab[i]);
}
}
#undef SET_TYPE
#undef FELEM
#undef FELEM2
#undef FELEML
#undef OUT
#undef DBL_TO_FELEM

View File

@ -1 +0,0 @@
/avresample

View File

@ -1,342 +0,0 @@
/*
* Copyright (c) 2002 Fabrice Bellard
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include <stdint.h>
#include <stdio.h>
#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include "libavutil/lfg.h"
#include "libavutil/libm.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
#include "libavresample/avresample.h"
static double dbl_rand(AVLFG *lfg)
{
return 2.0 * (av_lfg_get(lfg) / (double)UINT_MAX) - 1.0;
}
#define PUT_FUNC(name, fmt, type, expr) \
static void put_sample_ ## name(void **data, enum AVSampleFormat sample_fmt,\
int channels, int sample, int ch, \
double v_dbl) \
{ \
type v = expr; \
type **out = (type **)data; \
if (av_sample_fmt_is_planar(sample_fmt)) \
out[ch][sample] = v; \
else \
out[0][sample * channels + ch] = v; \
}
PUT_FUNC(u8, AV_SAMPLE_FMT_U8, uint8_t, av_clip_uint8 ( lrint(v_dbl * (1 << 7)) + 128))
PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1 << 15))))
PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31))))
PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float, v_dbl)
PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double, v_dbl)
static void put_sample(void **data, enum AVSampleFormat sample_fmt,
int channels, int sample, int ch, double v_dbl)
{
switch (av_get_packed_sample_fmt(sample_fmt)) {
case AV_SAMPLE_FMT_U8:
put_sample_u8(data, sample_fmt, channels, sample, ch, v_dbl);
break;
case AV_SAMPLE_FMT_S16:
put_sample_s16(data, sample_fmt, channels, sample, ch, v_dbl);
break;
case AV_SAMPLE_FMT_S32:
put_sample_s32(data, sample_fmt, channels, sample, ch, v_dbl);
break;
case AV_SAMPLE_FMT_FLT:
put_sample_flt(data, sample_fmt, channels, sample, ch, v_dbl);
break;
case AV_SAMPLE_FMT_DBL:
put_sample_dbl(data, sample_fmt, channels, sample, ch, v_dbl);
break;
}
}
static void audiogen(AVLFG *rnd, void **data, enum AVSampleFormat sample_fmt,
int channels, int sample_rate, int nb_samples)
{
int i, ch, k;
double v, f, a, ampa;
double tabf1[AVRESAMPLE_MAX_CHANNELS];
double tabf2[AVRESAMPLE_MAX_CHANNELS];
double taba[AVRESAMPLE_MAX_CHANNELS];
#define PUT_SAMPLE put_sample(data, sample_fmt, channels, k, ch, v);
k = 0;
/* 1 second of single freq sine at 1000 Hz */
a = 0;
for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
v = sin(a) * 0.30;
for (ch = 0; ch < channels; ch++)
PUT_SAMPLE
a += M_PI * 1000.0 * 2.0 / sample_rate;
}
/* 1 second of varying frequency between 100 and 10000 Hz */
a = 0;
for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
v = sin(a) * 0.30;
for (ch = 0; ch < channels; ch++)
PUT_SAMPLE
f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate);
a += M_PI * f * 2.0 / sample_rate;
}
/* 0.5 second of low amplitude white noise */
for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) {
v = dbl_rand(rnd) * 0.30;
for (ch = 0; ch < channels; ch++)
PUT_SAMPLE
}
/* 0.5 second of high amplitude white noise */
for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) {
v = dbl_rand(rnd);
for (ch = 0; ch < channels; ch++)
PUT_SAMPLE
}
/* 1 second of unrelated ramps for each channel */
for (ch = 0; ch < channels; ch++) {
taba[ch] = 0;
tabf1[ch] = 100 + av_lfg_get(rnd) % 5000;
tabf2[ch] = 100 + av_lfg_get(rnd) % 5000;
}
for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
for (ch = 0; ch < channels; ch++) {
v = sin(taba[ch]) * 0.30;
PUT_SAMPLE
f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate);
taba[ch] += M_PI * f * 2.0 / sample_rate;
}
}
/* 2 seconds of 500 Hz with varying volume */
a = 0;
ampa = 0;
for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) {
for (ch = 0; ch < channels; ch++) {
double amp = (1.0 + sin(ampa)) * 0.15;
if (ch & 1)
amp = 0.30 - amp;
v = sin(a) * amp;
PUT_SAMPLE
a += M_PI * 500.0 * 2.0 / sample_rate;
ampa += M_PI * 2.0 / sample_rate;
}
}
}
/* formats, rates, and layouts are ordered for priority in testing.
e.g. 'avresample-test 4 2 2' will test all input/output combinations of
S16/FLTP/S16P/FLT, 48000/44100, and stereo/mono */
static const enum AVSampleFormat formats[] = {
AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_S32P,
AV_SAMPLE_FMT_S32,
AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_U8,
AV_SAMPLE_FMT_DBLP,
AV_SAMPLE_FMT_DBL,
};
static const int rates[] = {
48000,
44100,
16000
};
static const uint64_t layouts[] = {
AV_CH_LAYOUT_STEREO,
AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_5POINT1,
AV_CH_LAYOUT_7POINT1,
};
int main(int argc, char **argv)
{
AVAudioResampleContext *s;
AVLFG rnd;
int ret = 0;
uint8_t *in_buf = NULL;
uint8_t *out_buf = NULL;
unsigned int in_buf_size;
unsigned int out_buf_size;
uint8_t *in_data[AVRESAMPLE_MAX_CHANNELS] = { 0 };
uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 };
int in_linesize;
int out_linesize;
uint64_t in_ch_layout;
int in_channels;
enum AVSampleFormat in_fmt;
int in_rate;
uint64_t out_ch_layout;
int out_channels;
enum AVSampleFormat out_fmt;
int out_rate;
int num_formats, num_rates, num_layouts;
int i, j, k, l, m, n;
num_formats = 2;
num_rates = 2;
num_layouts = 2;
if (argc > 1) {
if (!av_strncasecmp(argv[1], "-h", 3)) {
av_log(NULL, AV_LOG_INFO, "Usage: avresample-test [<num formats> "
"[<num sample rates> [<num channel layouts>]]]\n"
"Default is 2 2 2\n");
return 0;
}
num_formats = strtol(argv[1], NULL, 0);
num_formats = av_clip(num_formats, 1, FF_ARRAY_ELEMS(formats));
}
if (argc > 2) {
num_rates = strtol(argv[2], NULL, 0);
num_rates = av_clip(num_rates, 1, FF_ARRAY_ELEMS(rates));
}
if (argc > 3) {
num_layouts = strtol(argv[3], NULL, 0);
num_layouts = av_clip(num_layouts, 1, FF_ARRAY_ELEMS(layouts));
}
av_log_set_level(AV_LOG_DEBUG);
av_lfg_init(&rnd, 0xC0FFEE);
in_buf_size = av_samples_get_buffer_size(&in_linesize, 8, 48000 * 6,
AV_SAMPLE_FMT_DBLP, 0);
out_buf_size = in_buf_size;
in_buf = av_malloc(in_buf_size);
if (!in_buf)
goto end;
out_buf = av_malloc(out_buf_size);
if (!out_buf)
goto end;
s = avresample_alloc_context();
if (!s) {
av_log(NULL, AV_LOG_ERROR, "Error allocating AVAudioResampleContext\n");
ret = 1;
goto end;
}
for (i = 0; i < num_formats; i++) {
in_fmt = formats[i];
for (k = 0; k < num_layouts; k++) {
in_ch_layout = layouts[k];
in_channels = av_get_channel_layout_nb_channels(in_ch_layout);
for (m = 0; m < num_rates; m++) {
in_rate = rates[m];
ret = av_samples_fill_arrays(in_data, &in_linesize, in_buf,
in_channels, in_rate * 6,
in_fmt, 0);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "failed in_data fill arrays\n");
goto end;
}
audiogen(&rnd, (void **)in_data, in_fmt, in_channels, in_rate, in_rate * 6);
for (j = 0; j < num_formats; j++) {
out_fmt = formats[j];
for (l = 0; l < num_layouts; l++) {
out_ch_layout = layouts[l];
out_channels = av_get_channel_layout_nb_channels(out_ch_layout);
for (n = 0; n < num_rates; n++) {
out_rate = rates[n];
av_log(NULL, AV_LOG_INFO, "%s to %s, %d to %d channels, %d Hz to %d Hz\n",
av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt),
in_channels, out_channels, in_rate, out_rate);
ret = av_samples_fill_arrays(out_data, &out_linesize,
out_buf, out_channels,
out_rate * 6, out_fmt, 0);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "failed out_data fill arrays\n");
goto end;
}
av_opt_set_int(s, "in_channel_layout", in_ch_layout, 0);
av_opt_set_int(s, "in_sample_fmt", in_fmt, 0);
av_opt_set_int(s, "in_sample_rate", in_rate, 0);
av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0);
av_opt_set_int(s, "out_sample_fmt", out_fmt, 0);
av_opt_set_int(s, "out_sample_rate", out_rate, 0);
av_opt_set_int(s, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
ret = avresample_open(s);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Error opening context\n");
goto end;
}
ret = avresample_convert(s, out_data, out_linesize, out_rate * 6,
in_data, in_linesize, in_rate * 6);
if (ret < 0) {
char errbuf[256];
av_strerror(ret, errbuf, sizeof(errbuf));
av_log(NULL, AV_LOG_ERROR, "%s\n", errbuf);
goto end;
}
av_log(NULL, AV_LOG_INFO, "Converted %d samples to %d samples\n",
in_rate * 6, ret);
if (avresample_get_delay(s) > 0)
av_log(NULL, AV_LOG_INFO, "%d delay samples not converted\n",
avresample_get_delay(s));
if (avresample_available(s) > 0)
av_log(NULL, AV_LOG_INFO, "%d samples available for output\n",
avresample_available(s));
av_log(NULL, AV_LOG_INFO, "\n");
avresample_close(s);
}
}
}
}
}
}
ret = 0;
end:
av_freep(&in_buf);
av_freep(&out_buf);
avresample_free(&s);
return ret;
}

View File

@ -1,793 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include "libavutil/common.h"
#include "libavutil/dict.h"
// #include "libavutil/error.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "avresample.h"
#include "internal.h"
#include "audio_data.h"
#include "audio_convert.h"
#include "audio_mix.h"
#include "resample.h"
int avresample_open(AVAudioResampleContext *avr)
{
int ret;
if (avresample_is_open(avr)) {
av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n");
return AVERROR(EINVAL);
}
/* set channel mixing parameters */
avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n",
avr->in_channel_layout);
return AVERROR(EINVAL);
}
avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n",
avr->out_channel_layout);
return AVERROR(EINVAL);
}
avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels);
avr->downmix_needed = avr->in_channels > avr->out_channels;
avr->upmix_needed = avr->out_channels > avr->in_channels ||
(!avr->downmix_needed && (avr->mix_matrix ||
avr->in_channel_layout != avr->out_channel_layout));
avr->mixing_needed = avr->downmix_needed || avr->upmix_needed;
/* set resampling parameters */
avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate ||
avr->force_resampling;
/* select internal sample format if not specified by the user */
if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE &&
(avr->mixing_needed || avr->resample_needed)) {
enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt),
av_get_bytes_per_sample(out_fmt));
if (max_bps <= 2) {
avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P;
} else if (avr->mixing_needed) {
avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP;
} else {
if (max_bps <= 4) {
if (in_fmt == AV_SAMPLE_FMT_S32P ||
out_fmt == AV_SAMPLE_FMT_S32P) {
if (in_fmt == AV_SAMPLE_FMT_FLTP ||
out_fmt == AV_SAMPLE_FMT_FLTP) {
/* if one is s32 and the other is flt, use dbl */
avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP;
} else {
/* if one is s32 and the other is s32, s16, or u8, use s32 */
avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P;
}
} else {
/* if one is flt and the other is flt, s16 or u8, use flt */
avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP;
}
} else {
/* if either is dbl, use dbl */
avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP;
}
}
av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n",
av_get_sample_fmt_name(avr->internal_sample_fmt));
}
/* we may need to add an extra conversion in order to remap channels if
the output format is not planar */
if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed &&
!ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels)) {
avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
}
/* set sample format conversion parameters */
if (avr->resample_needed || avr->mixing_needed)
avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt;
else
avr->in_convert_needed = avr->use_channel_map &&
!ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels);
if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed)
avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
else
avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed ||
(avr->use_channel_map && avr->resample_needed));
if (avr->use_channel_map) {
if (avr->in_copy_needed) {
avr->remap_point = REMAP_IN_COPY;
av_log(avr, AV_LOG_TRACE, "remap channels during in_copy\n");
} else if (avr->in_convert_needed) {
avr->remap_point = REMAP_IN_CONVERT;
av_log(avr, AV_LOG_TRACE, "remap channels during in_convert\n");
} else if (avr->out_convert_needed) {
avr->remap_point = REMAP_OUT_CONVERT;
av_log(avr, AV_LOG_TRACE, "remap channels during out_convert\n");
} else {
avr->remap_point = REMAP_OUT_COPY;
av_log(avr, AV_LOG_TRACE, "remap channels during out_copy\n");
}
#ifdef DEBUG
{
int ch;
av_log(avr, AV_LOG_TRACE, "output map: ");
if (avr->ch_map_info.do_remap)
for (ch = 0; ch < avr->in_channels; ch++)
av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_map[ch]);
else
av_log(avr, AV_LOG_TRACE, "n/a");
av_log(avr, AV_LOG_TRACE, "\n");
av_log(avr, AV_LOG_TRACE, "copy map: ");
if (avr->ch_map_info.do_copy)
for (ch = 0; ch < avr->in_channels; ch++)
av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_copy[ch]);
else
av_log(avr, AV_LOG_TRACE, "n/a");
av_log(avr, AV_LOG_TRACE, "\n");
av_log(avr, AV_LOG_TRACE, "zero map: ");
if (avr->ch_map_info.do_zero)
for (ch = 0; ch < avr->in_channels; ch++)
av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_zero[ch]);
else
av_log(avr, AV_LOG_TRACE, "n/a");
av_log(avr, AV_LOG_TRACE, "\n");
av_log(avr, AV_LOG_TRACE, "input map: ");
for (ch = 0; ch < avr->in_channels; ch++)
av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.input_map[ch]);
av_log(avr, AV_LOG_TRACE, "\n");
}
#endif
} else
avr->remap_point = REMAP_NONE;
/* allocate buffers */
if (avr->in_copy_needed || avr->in_convert_needed) {
avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
0, avr->internal_sample_fmt,
"in_buffer");
if (!avr->in_buffer) {
ret = AVERROR(EINVAL);
goto error;
}
}
if (avr->resample_needed) {
avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels,
1024, avr->internal_sample_fmt,
"resample_out_buffer");
if (!avr->resample_out_buffer) {
ret = AVERROR(EINVAL);
goto error;
}
}
if (avr->out_convert_needed) {
avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0,
avr->out_sample_fmt, "out_buffer");
if (!avr->out_buffer) {
ret = AVERROR(EINVAL);
goto error;
}
}
avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels,
1024);
if (!avr->out_fifo) {
ret = AVERROR(ENOMEM);
goto error;
}
/* setup contexts */
if (avr->in_convert_needed) {
avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
avr->in_sample_fmt, avr->in_channels,
avr->in_sample_rate,
avr->remap_point == REMAP_IN_CONVERT);
if (!avr->ac_in) {
ret = AVERROR(ENOMEM);
goto error;
}
}
if (avr->out_convert_needed) {
enum AVSampleFormat src_fmt;
if (avr->in_convert_needed)
src_fmt = avr->internal_sample_fmt;
else
src_fmt = avr->in_sample_fmt;
avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
avr->out_channels,
avr->out_sample_rate,
avr->remap_point == REMAP_OUT_CONVERT);
if (!avr->ac_out) {
ret = AVERROR(ENOMEM);
goto error;
}
}
if (avr->resample_needed) {
avr->resample = ff_audio_resample_init(avr);
if (!avr->resample) {
ret = AVERROR(ENOMEM);
goto error;
}
}
if (avr->mixing_needed) {
avr->am = ff_audio_mix_alloc(avr);
if (!avr->am) {
ret = AVERROR(ENOMEM);
goto error;
}
}
return 0;
error:
avresample_close(avr);
return ret;
}
int avresample_is_open(AVAudioResampleContext *avr)
{
return !!avr->out_fifo;
}
void avresample_close(AVAudioResampleContext *avr)
{
ff_audio_data_free(&avr->in_buffer);
ff_audio_data_free(&avr->resample_out_buffer);
ff_audio_data_free(&avr->out_buffer);
av_audio_fifo_free(avr->out_fifo);
avr->out_fifo = NULL;
ff_audio_convert_free(&avr->ac_in);
ff_audio_convert_free(&avr->ac_out);
ff_audio_resample_free(&avr->resample);
ff_audio_mix_free(&avr->am);
av_freep(&avr->mix_matrix);
avr->use_channel_map = 0;
}
void avresample_free(AVAudioResampleContext **avr)
{
if (!*avr)
return;
avresample_close(*avr);
av_opt_free(*avr);
av_freep(avr);
}
static int handle_buffered_output(AVAudioResampleContext *avr,
AudioData *output, AudioData *converted)
{
int ret;
if (!output || av_audio_fifo_size(avr->out_fifo) > 0 ||
(converted && output->allocated_samples < converted->nb_samples)) {
if (converted) {
/* if there are any samples in the output FIFO or if the
user-supplied output buffer is not large enough for all samples,
we add to the output FIFO */
av_log(avr, AV_LOG_TRACE, "[FIFO] add %s to out_fifo\n", converted->name);
ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0,
converted->nb_samples);
if (ret < 0)
return ret;
}
/* if the user specified an output buffer, read samples from the output
FIFO to the user output */
if (output && output->allocated_samples > 0) {
av_log(avr, AV_LOG_TRACE, "[FIFO] read from out_fifo to output\n");
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return ff_audio_data_read_from_fifo(avr->out_fifo, output,
output->allocated_samples);
}
} else if (converted) {
/* copy directly to output if it is large enough or there is not any
data in the output FIFO */
av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", converted->name);
output->nb_samples = 0;
ret = ff_audio_data_copy(output, converted,
avr->remap_point == REMAP_OUT_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return output->nb_samples;
}
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return 0;
}
int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
uint8_t **output, int out_plane_size,
int out_samples,
uint8_t * const *input,
int in_plane_size, int in_samples)
{
AudioData input_buffer;
AudioData output_buffer;
AudioData *current_buffer;
int ret, direct_output;
/* reset internal buffers */
if (avr->in_buffer) {
avr->in_buffer->nb_samples = 0;
ff_audio_data_set_channels(avr->in_buffer,
avr->in_buffer->allocated_channels);
}
if (avr->resample_out_buffer) {
avr->resample_out_buffer->nb_samples = 0;
ff_audio_data_set_channels(avr->resample_out_buffer,
avr->resample_out_buffer->allocated_channels);
}
if (avr->out_buffer) {
avr->out_buffer->nb_samples = 0;
ff_audio_data_set_channels(avr->out_buffer,
avr->out_buffer->allocated_channels);
}
av_log(avr, AV_LOG_TRACE, "[start conversion]\n");
/* initialize output_buffer with output data */
direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0;
if (output) {
ret = ff_audio_data_init(&output_buffer, output, out_plane_size,
avr->out_channels, out_samples,
avr->out_sample_fmt, 0, "output");
if (ret < 0)
return ret;
output_buffer.nb_samples = 0;
}
if (input) {
/* initialize input_buffer with input data */
ret = ff_audio_data_init(&input_buffer, input, in_plane_size,
avr->in_channels, in_samples,
avr->in_sample_fmt, 1, "input");
if (ret < 0)
return ret;
current_buffer = &input_buffer;
if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed &&
!avr->out_convert_needed && direct_output && out_samples >= in_samples) {
/* in some rare cases we can copy input to output and upmix
directly in the output buffer */
av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", current_buffer->name);
ret = ff_audio_data_copy(&output_buffer, current_buffer,
avr->remap_point == REMAP_OUT_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
current_buffer = &output_buffer;
} else if (avr->remap_point == REMAP_OUT_COPY &&
(!direct_output || out_samples < in_samples)) {
/* if remapping channels during output copy, we may need to
* use an intermediate buffer in order to remap before adding
* samples to the output fifo */
av_log(avr, AV_LOG_TRACE, "[copy] %s to out_buffer\n", current_buffer->name);
ret = ff_audio_data_copy(avr->out_buffer, current_buffer,
&avr->ch_map_info);
if (ret < 0)
return ret;
current_buffer = avr->out_buffer;
} else if (avr->in_copy_needed || avr->in_convert_needed) {
/* if needed, copy or convert input to in_buffer, and downmix if
applicable */
if (avr->in_convert_needed) {
ret = ff_audio_data_realloc(avr->in_buffer,
current_buffer->nb_samples);
if (ret < 0)
return ret;
av_log(avr, AV_LOG_TRACE, "[convert] %s to in_buffer\n", current_buffer->name);
ret = ff_audio_convert(avr->ac_in, avr->in_buffer,
current_buffer);
if (ret < 0)
return ret;
} else {
av_log(avr, AV_LOG_TRACE, "[copy] %s to in_buffer\n", current_buffer->name);
ret = ff_audio_data_copy(avr->in_buffer, current_buffer,
avr->remap_point == REMAP_IN_COPY ?
&avr->ch_map_info : NULL);
if (ret < 0)
return ret;
}
ff_audio_data_set_channels(avr->in_buffer, avr->in_channels);
if (avr->downmix_needed) {
av_log(avr, AV_LOG_TRACE, "[downmix] in_buffer\n");
ret = ff_audio_mix(avr->am, avr->in_buffer);
if (ret < 0)
return ret;
}
current_buffer = avr->in_buffer;
}
} else {
/* flush resampling buffer and/or output FIFO if input is NULL */
if (!avr->resample_needed)
return handle_buffered_output(avr, output ? &output_buffer : NULL,
NULL);
current_buffer = NULL;
}
if (avr->resample_needed) {
AudioData *resample_out;
if (!avr->out_convert_needed && direct_output && out_samples > 0)
resample_out = &output_buffer;
else
resample_out = avr->resample_out_buffer;
av_log(avr, AV_LOG_TRACE, "[resample] %s to %s\n",
current_buffer ? current_buffer->name : "null",
resample_out->name);
ret = ff_audio_resample(avr->resample, resample_out,
current_buffer);
if (ret < 0)
return ret;
/* if resampling did not produce any samples, just return 0 */
if (resample_out->nb_samples == 0) {
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return 0;
}
current_buffer = resample_out;
}
if (avr->upmix_needed) {
av_log(avr, AV_LOG_TRACE, "[upmix] %s\n", current_buffer->name);
ret = ff_audio_mix(avr->am, current_buffer);
if (ret < 0)
return ret;
}
/* if we resampled or upmixed directly to output, return here */
if (current_buffer == &output_buffer) {
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return current_buffer->nb_samples;
}
if (avr->out_convert_needed) {
if (direct_output && out_samples >= current_buffer->nb_samples) {
/* convert directly to output */
av_log(avr, AV_LOG_TRACE, "[convert] %s to output\n", current_buffer->name);
ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer);
if (ret < 0)
return ret;
av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
return output_buffer.nb_samples;
} else {
ret = ff_audio_data_realloc(avr->out_buffer,
current_buffer->nb_samples);
if (ret < 0)
return ret;
av_log(avr, AV_LOG_TRACE, "[convert] %s to out_buffer\n", current_buffer->name);
ret = ff_audio_convert(avr->ac_out, avr->out_buffer,
current_buffer);
if (ret < 0)
return ret;
current_buffer = avr->out_buffer;
}
}
return handle_buffered_output(avr, output ? &output_buffer : NULL,
current_buffer);
}
int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in)
{
if (avresample_is_open(avr)) {
avresample_close(avr);
}
if (in) {
avr->in_channel_layout = in->channel_layout;
avr->in_sample_rate = in->sample_rate;
avr->in_sample_fmt = in->format;
}
if (out) {
avr->out_channel_layout = out->channel_layout;
avr->out_sample_rate = out->sample_rate;
avr->out_sample_fmt = out->format;
}
return 0;
}
static int config_changed(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret = 0;
if (in) {
if (avr->in_channel_layout != in->channel_layout ||
avr->in_sample_rate != in->sample_rate ||
avr->in_sample_fmt != in->format) {
ret |= AVERROR_INPUT_CHANGED;
}
}
if (out) {
if (avr->out_channel_layout != out->channel_layout ||
avr->out_sample_rate != out->sample_rate ||
avr->out_sample_fmt != out->format) {
ret |= AVERROR_OUTPUT_CHANGED;
}
}
return ret;
}
static inline int convert_frame(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret;
uint8_t **out_data = NULL, **in_data = NULL;
int out_linesize = 0, in_linesize = 0;
int out_nb_samples = 0, in_nb_samples = 0;
if (out) {
out_data = out->extended_data;
out_linesize = out->linesize[0];
out_nb_samples = out->nb_samples;
}
if (in) {
in_data = in->extended_data;
in_linesize = in->linesize[0];
in_nb_samples = in->nb_samples;
}
ret = avresample_convert(avr, out_data, out_linesize,
out_nb_samples,
in_data, in_linesize,
in_nb_samples);
if (ret < 0) {
if (out)
out->nb_samples = 0;
return ret;
}
if (out)
out->nb_samples = ret;
return 0;
}
static inline int available_samples(AVFrame *out)
{
int samples;
int bytes_per_sample = av_get_bytes_per_sample(out->format);
if (!bytes_per_sample)
return AVERROR(EINVAL);
samples = out->linesize[0] / bytes_per_sample;
if (av_sample_fmt_is_planar(out->format)) {
return samples;
} else {
int channels = av_get_channel_layout_nb_channels(out->channel_layout);
return samples / channels;
}
}
int avresample_convert_frame(AVAudioResampleContext *avr,
AVFrame *out, AVFrame *in)
{
int ret, setup = 0;
if (!avresample_is_open(avr)) {
if ((ret = avresample_config(avr, out, in)) < 0)
return ret;
if ((ret = avresample_open(avr)) < 0)
return ret;
setup = 1;
} else {
// return as is or reconfigure for input changes?
if ((ret = config_changed(avr, out, in)))
return ret;
}
if (out) {
if (!out->linesize[0]) {
out->nb_samples = avresample_get_out_samples(avr, in->nb_samples);
if ((ret = av_frame_get_buffer(out, 0)) < 0) {
if (setup)
avresample_close(avr);
return ret;
}
} else {
if (!out->nb_samples)
out->nb_samples = available_samples(out);
}
}
return convert_frame(avr, out, in);
}
int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
int stride)
{
int in_channels, out_channels, i, o;
if (avr->am)
return ff_audio_mix_get_matrix(avr->am, matrix, stride);
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
return AVERROR(EINVAL);
}
if (!avr->mix_matrix) {
av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
return AVERROR(EINVAL);
}
for (o = 0; o < out_channels; o++)
for (i = 0; i < in_channels; i++)
matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
return 0;
}
int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
int stride)
{
int in_channels, out_channels, i, o;
if (avr->am)
return ff_audio_mix_set_matrix(avr->am, matrix, stride);
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS ||
out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
return AVERROR(EINVAL);
}
if (avr->mix_matrix)
av_freep(&avr->mix_matrix);
avr->mix_matrix = av_malloc(in_channels * out_channels *
sizeof(*avr->mix_matrix));
if (!avr->mix_matrix)
return AVERROR(ENOMEM);
for (o = 0; o < out_channels; o++)
for (i = 0; i < in_channels; i++)
avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
return 0;
}
int avresample_set_channel_mapping(AVAudioResampleContext *avr,
const int *channel_map)
{
ChannelMapInfo *info = &avr->ch_map_info;
int in_channels, ch, i;
in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) {
av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
return AVERROR(EINVAL);
}
memset(info, 0, sizeof(*info));
memset(info->input_map, -1, sizeof(info->input_map));
for (ch = 0; ch < in_channels; ch++) {
if (channel_map[ch] >= in_channels) {
av_log(avr, AV_LOG_ERROR, "Invalid channel map\n");
return AVERROR(EINVAL);
}
if (channel_map[ch] < 0) {
info->channel_zero[ch] = 1;
info->channel_map[ch] = -1;
info->do_zero = 1;
} else if (info->input_map[channel_map[ch]] >= 0) {
info->channel_copy[ch] = info->input_map[channel_map[ch]];
info->channel_map[ch] = -1;
info->do_copy = 1;
} else {
info->channel_map[ch] = channel_map[ch];
info->input_map[channel_map[ch]] = ch;
info->do_remap = 1;
}
}
/* Fill-in unmapped input channels with unmapped output channels.
This is used when remapping during conversion from interleaved to
planar format. */
for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) {
while (ch < in_channels && info->input_map[ch] >= 0)
ch++;
while (i < in_channels && info->channel_map[i] >= 0)
i++;
if (ch >= in_channels || i >= in_channels)
break;
info->input_map[ch] = i;
}
avr->use_channel_map = 1;
return 0;
}
int avresample_available(AVAudioResampleContext *avr)
{
return av_audio_fifo_size(avr->out_fifo);
}
int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples)
{
int64_t samples = avresample_get_delay(avr) + (int64_t)in_nb_samples;
if (avr->resample_needed) {
samples = av_rescale_rnd(samples,
avr->out_sample_rate,
avr->in_sample_rate,
AV_ROUND_UP);
}
samples += avresample_available(avr);
if (samples > INT_MAX)
return AVERROR(EINVAL);
return samples;
}
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples)
{
if (!output)
return av_audio_fifo_drain(avr->out_fifo, nb_samples);
return av_audio_fifo_read(avr->out_fifo, (void**)output, nb_samples);
}
unsigned avresample_version(void)
{
return LIBAVRESAMPLE_VERSION_INT;
}
const char *avresample_license(void)
{
#define LICENSE_PREFIX "libavresample license: "
return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
}
const char *avresample_configuration(void)
{
return FFMPEG_CONFIGURATION;
}

View File

@ -1,50 +0,0 @@
/*
* 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
*/
#ifndef AVRESAMPLE_VERSION_H
#define AVRESAMPLE_VERSION_H
/**
* @file
* @ingroup lavr
* Libavresample version macros.
*/
#include "libavutil/version.h"
#define LIBAVRESAMPLE_VERSION_MAJOR 4
#define LIBAVRESAMPLE_VERSION_MINOR 0
#define LIBAVRESAMPLE_VERSION_MICRO 0
#define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \
LIBAVRESAMPLE_VERSION_MINOR, \
LIBAVRESAMPLE_VERSION_MICRO)
#define LIBAVRESAMPLE_VERSION AV_VERSION(LIBAVRESAMPLE_VERSION_MAJOR, \
LIBAVRESAMPLE_VERSION_MINOR, \
LIBAVRESAMPLE_VERSION_MICRO)
#define LIBAVRESAMPLE_BUILD LIBAVRESAMPLE_VERSION_INT
#define LIBAVRESAMPLE_IDENT "Lavr" AV_STRINGIFY(LIBAVRESAMPLE_VERSION)
/**
* FF_API_* defines may be placed below to indicate public API that will be
* dropped at a future version bump. The defines themselves are not part of
* the public API and may change, break or disappear at any time.
*/
#endif /* AVRESAMPLE_VERSION_H */

View File

@ -1,9 +0,0 @@
OBJS += x86/audio_convert_init.o \
x86/audio_mix_init.o \
x86/dither_init.o \
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
X86ASM-OBJS += x86/audio_convert.o \
x86/audio_mix.o \
x86/dither.o \

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include "config.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
#include "libavresample/audio_convert.h"
/* flat conversions */
void ff_conv_s16_to_s32_sse2(int16_t *dst, const int32_t *src, int len);
void ff_conv_s16_to_flt_sse2(float *dst, const int16_t *src, int len);
void ff_conv_s16_to_flt_sse4(float *dst, const int16_t *src, int len);
void ff_conv_s32_to_s16_mmx (int16_t *dst, const int32_t *src, int len);
void ff_conv_s32_to_s16_sse2(int16_t *dst, const int32_t *src, int len);
void ff_conv_s32_to_flt_sse2(float *dst, const int32_t *src, int len);
void ff_conv_s32_to_flt_avx (float *dst, const int32_t *src, int len);
void ff_conv_flt_to_s16_sse2(int16_t *dst, const float *src, int len);
void ff_conv_flt_to_s32_sse2(int32_t *dst, const float *src, int len);
void ff_conv_flt_to_s32_avx (int32_t *dst, const float *src, int len);
/* interleave conversions */
void ff_conv_s16p_to_s16_2ch_sse2(int16_t *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_s16_2ch_avx (int16_t *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_s16_6ch_sse2(int16_t *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_s16_6ch_sse2slow(int16_t *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_s16_6ch_avx (int16_t *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_flt_2ch_sse2(float *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_flt_2ch_avx (float *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_flt_6ch_sse2 (float *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_flt_6ch_ssse3(float *dst, int16_t *const *src,
int len, int channels);
void ff_conv_s16p_to_flt_6ch_avx (float *dst, int16_t *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_2ch_sse2 (int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_2ch_ssse3(int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_6ch_sse (int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_6ch_sse2(int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_s16_6ch_avx (int16_t *dst, float *const *src,
int len, int channels);
void ff_conv_fltp_to_flt_2ch_sse(float *dst, float *const *src, int len,
int channels);
void ff_conv_fltp_to_flt_2ch_avx(float *dst, float *const *src, int len,
int channels);
void ff_conv_fltp_to_flt_6ch_mmx (float *dst, float *const *src, int len,
int channels);
void ff_conv_fltp_to_flt_6ch_sse4(float *dst, float *const *src, int len,
int channels);
void ff_conv_fltp_to_flt_6ch_avx (float *dst, float *const *src, int len,
int channels);
/* deinterleave conversions */
void ff_conv_s16_to_s16p_2ch_sse2(int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_s16p_2ch_ssse3(int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_s16p_2ch_avx (int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_s16p_6ch_sse2 (int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_s16p_6ch_ssse3(int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_s16p_6ch_avx (int16_t *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_2ch_sse2(float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_2ch_avx (float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_6ch_sse2 (float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_6ch_ssse3(float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_6ch_sse4 (float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_s16_to_fltp_6ch_avx (float *const *dst, int16_t *src,
int len, int channels);
void ff_conv_flt_to_s16p_2ch_sse2(int16_t *const *dst, float *src,
int len, int channels);
void ff_conv_flt_to_s16p_2ch_avx (int16_t *const *dst, float *src,
int len, int channels);
void ff_conv_flt_to_s16p_6ch_sse2 (int16_t *const *dst, float *src,
int len, int channels);
void ff_conv_flt_to_s16p_6ch_ssse3(int16_t *const *dst, float *src,
int len, int channels);
void ff_conv_flt_to_s16p_6ch_avx (int16_t *const *dst, float *src,
int len, int channels);
void ff_conv_flt_to_fltp_2ch_sse(float *const *dst, float *src, int len,
int channels);
void ff_conv_flt_to_fltp_2ch_avx(float *const *dst, float *src, int len,
int channels);
void ff_conv_flt_to_fltp_6ch_sse2(float *const *dst, float *src, int len,
int channels);
void ff_conv_flt_to_fltp_6ch_avx (float *const *dst, float *src, int len,
int channels);
av_cold void ff_audio_convert_init_x86(AudioConvert *ac)
{
int cpu_flags = av_get_cpu_flags();
if (EXTERNAL_MMX(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
0, 1, 8, "MMX", ff_conv_s32_to_s16_mmx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
6, 1, 4, "MMX", ff_conv_fltp_to_flt_6ch_mmx);
}
if (EXTERNAL_SSE(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
6, 1, 2, "SSE", ff_conv_fltp_to_s16_6ch_sse);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
2, 16, 8, "SSE", ff_conv_fltp_to_flt_2ch_sse);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT,
2, 16, 4, "SSE", ff_conv_flt_to_fltp_2ch_sse);
}
if (EXTERNAL_SSE2(cpu_flags)) {
if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
0, 16, 16, "SSE2", ff_conv_s32_to_s16_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
6, 16, 8, "SSE2", ff_conv_s16p_to_s16_6ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
6, 16, 4, "SSE2", ff_conv_fltp_to_s16_6ch_sse2);
} else {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
6, 1, 4, "SSE2SLOW", ff_conv_s16p_to_s16_6ch_sse2slow);
}
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16,
0, 16, 8, "SSE2", ff_conv_s16_to_s32_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16,
0, 16, 8, "SSE2", ff_conv_s16_to_flt_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32,
0, 16, 8, "SSE2", ff_conv_s32_to_flt_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT,
0, 16, 16, "SSE2", ff_conv_flt_to_s16_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT,
0, 16, 16, "SSE2", ff_conv_flt_to_s32_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
2, 16, 16, "SSE2", ff_conv_s16p_to_s16_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P,
2, 16, 8, "SSE2", ff_conv_s16p_to_flt_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P,
6, 16, 4, "SSE2", ff_conv_s16p_to_flt_6ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
2, 16, 4, "SSE2", ff_conv_fltp_to_s16_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
2, 16, 8, "SSE2", ff_conv_s16_to_s16p_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
6, 16, 4, "SSE2", ff_conv_s16_to_s16p_6ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16,
2, 16, 8, "SSE2", ff_conv_s16_to_fltp_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16,
6, 16, 4, "SSE2", ff_conv_s16_to_fltp_6ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT,
2, 16, 8, "SSE2", ff_conv_flt_to_s16p_2ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT,
6, 16, 4, "SSE2", ff_conv_flt_to_s16p_6ch_sse2);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT,
6, 16, 4, "SSE2", ff_conv_flt_to_fltp_6ch_sse2);
}
if (EXTERNAL_SSSE3(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P,
6, 16, 4, "SSSE3", ff_conv_s16p_to_flt_6ch_ssse3);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
2, 16, 4, "SSSE3", ff_conv_fltp_to_s16_2ch_ssse3);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
2, 16, 8, "SSSE3", ff_conv_s16_to_s16p_2ch_ssse3);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
6, 16, 4, "SSSE3", ff_conv_s16_to_s16p_6ch_ssse3);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16,
6, 16, 4, "SSSE3", ff_conv_s16_to_fltp_6ch_ssse3);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT,
6, 16, 4, "SSSE3", ff_conv_flt_to_s16p_6ch_ssse3);
}
if (EXTERNAL_SSE4(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16,
0, 16, 8, "SSE4", ff_conv_s16_to_flt_sse4);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
6, 16, 4, "SSE4", ff_conv_fltp_to_flt_6ch_sse4);
}
if (EXTERNAL_AVX_FAST(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32,
0, 32, 16, "AVX", ff_conv_s32_to_flt_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT,
0, 32, 32, "AVX", ff_conv_flt_to_s32_avx);
}
if (EXTERNAL_AVX(cpu_flags)) {
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
2, 16, 16, "AVX", ff_conv_s16p_to_s16_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
6, 16, 8, "AVX", ff_conv_s16p_to_s16_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P,
2, 16, 8, "AVX", ff_conv_s16p_to_flt_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P,
6, 16, 4, "AVX", ff_conv_s16p_to_flt_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP,
6, 16, 4, "AVX", ff_conv_fltp_to_s16_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
6, 16, 4, "AVX", ff_conv_fltp_to_flt_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
2, 16, 8, "AVX", ff_conv_s16_to_s16p_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16,
6, 16, 4, "AVX", ff_conv_s16_to_s16p_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16,
2, 16, 8, "AVX", ff_conv_s16_to_fltp_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16,
6, 16, 4, "AVX", ff_conv_s16_to_fltp_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT,
2, 16, 8, "AVX", ff_conv_flt_to_s16p_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT,
6, 16, 4, "AVX", ff_conv_flt_to_s16p_6ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT,
2, 16, 4, "AVX", ff_conv_flt_to_fltp_2ch_avx);
ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT,
6, 16, 4, "AVX", ff_conv_flt_to_fltp_6ch_avx);
}
}

View File

@ -1,511 +0,0 @@
;******************************************************************************
;* x86 optimized channel mixing
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
;* 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
;******************************************************************************
%include "libavutil/x86/x86util.asm"
%include "util.asm"
SECTION .text
;-----------------------------------------------------------------------------
; void ff_mix_2_to_1_fltp_flt(float **src, float **matrix, int len,
; int out_ch, int in_ch);
;-----------------------------------------------------------------------------
%macro MIX_2_TO_1_FLTP_FLT 0
cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1
mov src1q, [srcq+gprsize]
mov srcq, [srcq ]
sub src1q, srcq
mov matrixq, [matrixq ]
VBROADCASTSS m4, [matrixq ]
VBROADCASTSS m5, [matrixq+4]
ALIGN 16
.loop:
mulps m0, m4, [srcq ]
mulps m1, m5, [srcq+src1q ]
mulps m2, m4, [srcq+ mmsize]
mulps m3, m5, [srcq+src1q+mmsize]
addps m0, m0, m1
addps m2, m2, m3
mova [srcq ], m0
mova [srcq+mmsize], m2
add srcq, mmsize*2
sub lend, mmsize*2/4
jg .loop
REP_RET
%endmacro
INIT_XMM sse
MIX_2_TO_1_FLTP_FLT
%if HAVE_AVX_EXTERNAL
INIT_YMM avx
MIX_2_TO_1_FLTP_FLT
%endif
;-----------------------------------------------------------------------------
; void ff_mix_2_to_1_s16p_flt(int16_t **src, float **matrix, int len,
; int out_ch, int in_ch);
;-----------------------------------------------------------------------------
%macro MIX_2_TO_1_S16P_FLT 0
cglobal mix_2_to_1_s16p_flt, 3,4,6, src, matrix, len, src1
mov src1q, [srcq+gprsize]
mov srcq, [srcq]
sub src1q, srcq
mov matrixq, [matrixq ]
VBROADCASTSS m4, [matrixq ]
VBROADCASTSS m5, [matrixq+4]
ALIGN 16
.loop:
mova m0, [srcq ]
mova m2, [srcq+src1q]
S16_TO_S32_SX 0, 1
S16_TO_S32_SX 2, 3
cvtdq2ps m0, m0
cvtdq2ps m1, m1
cvtdq2ps m2, m2
cvtdq2ps m3, m3
mulps m0, m4
mulps m1, m4
mulps m2, m5
mulps m3, m5
addps m0, m2
addps m1, m3
cvtps2dq m0, m0
cvtps2dq m1, m1
packssdw m0, m1
mova [srcq], m0
add srcq, mmsize
sub lend, mmsize/2
jg .loop
REP_RET
%endmacro
INIT_XMM sse2
MIX_2_TO_1_S16P_FLT
INIT_XMM sse4
MIX_2_TO_1_S16P_FLT
;-----------------------------------------------------------------------------
; void ff_mix_2_to_1_s16p_q8(int16_t **src, int16_t **matrix, int len,
; int out_ch, int in_ch);
;-----------------------------------------------------------------------------
INIT_XMM sse2
cglobal mix_2_to_1_s16p_q8, 3,4,6, src, matrix, len, src1
mov src1q, [srcq+gprsize]
mov srcq, [srcq]
sub src1q, srcq
mov matrixq, [matrixq]
movd m4, [matrixq]
movd m5, [matrixq]
SPLATW m4, m4, 0
SPLATW m5, m5, 1
pxor m0, m0
punpcklwd m4, m0
punpcklwd m5, m0
ALIGN 16
.loop:
mova m0, [srcq ]
mova m2, [srcq+src1q]
punpckhwd m1, m0, m0
punpcklwd m0, m0
punpckhwd m3, m2, m2
punpcklwd m2, m2
pmaddwd m0, m4
pmaddwd m1, m4
pmaddwd m2, m5
pmaddwd m3, m5
paddd m0, m2
paddd m1, m3
psrad m0, 8
psrad m1, 8
packssdw m0, m1
mova [srcq], m0
add srcq, mmsize
sub lend, mmsize/2
jg .loop
REP_RET
;-----------------------------------------------------------------------------
; void ff_mix_1_to_2_fltp_flt(float **src, float **matrix, int len,
; int out_ch, int in_ch);
;-----------------------------------------------------------------------------
%macro MIX_1_TO_2_FLTP_FLT 0
cglobal mix_1_to_2_fltp_flt, 3,5,4, src0, matrix0, len, src1, matrix1
mov src1q, [src0q+gprsize]
mov src0q, [src0q]
sub src1q, src0q
mov matrix1q, [matrix0q+gprsize]
mov matrix0q, [matrix0q]
VBROADCASTSS m2, [matrix0q]
VBROADCASTSS m3, [matrix1q]
ALIGN 16
.loop:
mova m0, [src0q]
mulps m1, m0, m3
mulps m0, m0, m2
mova [src0q ], m0
mova [src0q+src1q], m1
add src0q, mmsize
sub lend, mmsize/4
jg .loop
REP_RET
%endmacro
INIT_XMM sse
MIX_1_TO_2_FLTP_FLT
%if HAVE_AVX_EXTERNAL
INIT_YMM avx
MIX_1_TO_2_FLTP_FLT
%endif
;-----------------------------------------------------------------------------
; void ff_mix_1_to_2_s16p_flt(int16_t **src, float **matrix, int len,
; int out_ch, int in_ch);
;-----------------------------------------------------------------------------
%macro MIX_1_TO_2_S16P_FLT 0
cglobal mix_1_to_2_s16p_flt, 3,5,6, src0, matrix0, len, src1, matrix1
mov src1q, [src0q+gprsize]
mov src0q, [src0q]
sub src1q, src0q
mov matrix1q, [matrix0q+gprsize]
mov matrix0q, [matrix0q]
VBROADCASTSS m4, [matrix0q]
VBROADCASTSS m5, [matrix1q]
ALIGN 16
.loop:
mova m0, [src0q]
S16_TO_S32_SX 0, 2
cvtdq2ps m0, m0
cvtdq2ps m2, m2
mulps m1, m0, m5
mulps m0, m0, m4
mulps m3, m2, m5
mulps m2, m2, m4
cvtps2dq m0, m0
cvtps2dq m1, m1
cvtps2dq m2, m2
cvtps2dq m3, m3
packssdw m0, m2
packssdw m1, m3
mova [src0q ], m0
mova [src0q+src1q], m1
add src0q, mmsize
sub lend, mmsize/2
jg .loop
REP_RET
%endmacro
INIT_XMM sse2
MIX_1_TO_2_S16P_FLT
INIT_XMM sse4
MIX_1_TO_2_S16P_FLT
%if HAVE_AVX_EXTERNAL
INIT_XMM avx
MIX_1_TO_2_S16P_FLT
%endif
;-----------------------------------------------------------------------------
; void ff_mix_3_8_to_1_2_fltp/s16p_flt(float/int16_t **src, float **matrix,
; int len, int out_ch, int in_ch);
;-----------------------------------------------------------------------------
%macro MIX_3_8_TO_1_2_FLT 3 ; %1 = in channels, %2 = out channels, %3 = s16p or fltp
; define some names to make the code clearer
%assign in_channels %1
%assign out_channels %2
%assign stereo out_channels - 1
%ifidn %3, s16p
%assign is_s16 1
%else
%assign is_s16 0
%endif
; determine how many matrix elements must go on the stack vs. mmregs
%assign matrix_elements in_channels * out_channels
%if is_s16
%if stereo
%assign needed_mmregs 7
%else
%assign needed_mmregs 5
%endif
%else
%if stereo
%assign needed_mmregs 4
%else
%assign needed_mmregs 3
%endif
%endif
%assign matrix_elements_mm num_mmregs - needed_mmregs
%if matrix_elements < matrix_elements_mm
%assign matrix_elements_mm matrix_elements
%endif
%if matrix_elements_mm < matrix_elements
%assign matrix_elements_stack matrix_elements - matrix_elements_mm
%else
%assign matrix_elements_stack 0
%endif
%assign matrix_stack_size matrix_elements_stack * mmsize
%assign needed_stack_size -1 * matrix_stack_size
%if ARCH_X86_32 && in_channels >= 7
%assign needed_stack_size needed_stack_size - 16
%endif
cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, needed_stack_size, src0, src1, len, src2, src3, src4, src5, src6, src7
; define src pointers on stack if needed
%if matrix_elements_stack > 0 && ARCH_X86_32 && in_channels >= 7
%define src5m [rsp+matrix_stack_size+0]
%define src6m [rsp+matrix_stack_size+4]
%define src7m [rsp+matrix_stack_size+8]
%endif
; load matrix pointers
%define matrix0q r1q
%define matrix1q r3q
%if stereo
mov matrix1q, [matrix0q+gprsize]
%endif
mov matrix0q, [matrix0q]
; define matrix coeff names
%assign %%i 0
%assign %%j needed_mmregs
%rep in_channels
%if %%i >= matrix_elements_mm
CAT_XDEFINE mx_stack_0_, %%i, 1
CAT_XDEFINE mx_0_, %%i, [rsp+(%%i-matrix_elements_mm)*mmsize]
%else
CAT_XDEFINE mx_stack_0_, %%i, 0
CAT_XDEFINE mx_0_, %%i, m %+ %%j
%assign %%j %%j+1
%endif
%assign %%i %%i+1
%endrep
%if stereo
%assign %%i 0
%rep in_channels
%if in_channels + %%i >= matrix_elements_mm
CAT_XDEFINE mx_stack_1_, %%i, 1
CAT_XDEFINE mx_1_, %%i, [rsp+(in_channels+%%i-matrix_elements_mm)*mmsize]
%else
CAT_XDEFINE mx_stack_1_, %%i, 0
CAT_XDEFINE mx_1_, %%i, m %+ %%j
%assign %%j %%j+1
%endif
%assign %%i %%i+1
%endrep
%endif
; load/splat matrix coeffs
%assign %%i 0
%rep in_channels
%if mx_stack_0_ %+ %%i
VBROADCASTSS m0, [matrix0q+4*%%i]
mova mx_0_ %+ %%i, m0
%else
VBROADCASTSS mx_0_ %+ %%i, [matrix0q+4*%%i]
%endif
%if stereo
%if mx_stack_1_ %+ %%i
VBROADCASTSS m0, [matrix1q+4*%%i]
mova mx_1_ %+ %%i, m0
%else
VBROADCASTSS mx_1_ %+ %%i, [matrix1q+4*%%i]
%endif
%endif
%assign %%i %%i+1
%endrep
; load channel pointers to registers as offsets from the first channel pointer
%if ARCH_X86_64
movsxd lenq, r2d
%endif
shl lenq, 2-is_s16
%assign %%i 1
%rep (in_channels - 1)
%if ARCH_X86_32 && in_channels >= 7 && %%i >= 5
mov src5q, [src0q+%%i*gprsize]
add src5q, lenq
mov src %+ %%i %+ m, src5q
%else
mov src %+ %%i %+ q, [src0q+%%i*gprsize]
add src %+ %%i %+ q, lenq
%endif
%assign %%i %%i+1
%endrep
mov src0q, [src0q]
add src0q, lenq
neg lenq
.loop:
; for x86-32 with 7-8 channels we do not have enough gp registers for all src
; pointers, so we have to load some of them from the stack each time
%define copy_src_from_stack ARCH_X86_32 && in_channels >= 7 && %%i >= 5
%if is_s16
; mix with s16p input
mova m0, [src0q+lenq]
S16_TO_S32_SX 0, 1
cvtdq2ps m0, m0
cvtdq2ps m1, m1
%if stereo
mulps m2, m0, mx_1_0
mulps m3, m1, mx_1_0
%endif
mulps m0, m0, mx_0_0
mulps m1, m1, mx_0_0
%assign %%i 1
%rep (in_channels - 1)
%if copy_src_from_stack
%define src_ptr src5q
%else
%define src_ptr src %+ %%i %+ q
%endif
%if stereo
%if copy_src_from_stack
mov src_ptr, src %+ %%i %+ m
%endif
mova m4, [src_ptr+lenq]
S16_TO_S32_SX 4, 5
cvtdq2ps m4, m4
cvtdq2ps m5, m5
FMULADD_PS m2, m4, mx_1_ %+ %%i, m2, m6
FMULADD_PS m3, m5, mx_1_ %+ %%i, m3, m6
FMULADD_PS m0, m4, mx_0_ %+ %%i, m0, m4
FMULADD_PS m1, m5, mx_0_ %+ %%i, m1, m5
%else
%if copy_src_from_stack
mov src_ptr, src %+ %%i %+ m
%endif
mova m2, [src_ptr+lenq]
S16_TO_S32_SX 2, 3
cvtdq2ps m2, m2
cvtdq2ps m3, m3
FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m4
FMULADD_PS m1, m3, mx_0_ %+ %%i, m1, m4
%endif
%assign %%i %%i+1
%endrep
%if stereo
cvtps2dq m2, m2
cvtps2dq m3, m3
packssdw m2, m3
mova [src1q+lenq], m2
%endif
cvtps2dq m0, m0
cvtps2dq m1, m1
packssdw m0, m1
mova [src0q+lenq], m0
%else
; mix with fltp input
%if stereo || mx_stack_0_0
mova m0, [src0q+lenq]
%endif
%if stereo
mulps m1, m0, mx_1_0
%endif
%if stereo || mx_stack_0_0
mulps m0, m0, mx_0_0
%else
mulps m0, mx_0_0, [src0q+lenq]
%endif
%assign %%i 1
%rep (in_channels - 1)
%if copy_src_from_stack
%define src_ptr src5q
mov src_ptr, src %+ %%i %+ m
%else
%define src_ptr src %+ %%i %+ q
%endif
; avoid extra load for mono if matrix is in a mm register
%if stereo || mx_stack_0_ %+ %%i
mova m2, [src_ptr+lenq]
%endif
%if stereo
FMULADD_PS m1, m2, mx_1_ %+ %%i, m1, m3
%endif
%if stereo || mx_stack_0_ %+ %%i
FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m2
%else
FMULADD_PS m0, mx_0_ %+ %%i, [src_ptr+lenq], m0, m1
%endif
%assign %%i %%i+1
%endrep
mova [src0q+lenq], m0
%if stereo
mova [src1q+lenq], m1
%endif
%endif
add lenq, mmsize
jl .loop
; zero ymm high halves
%if mmsize == 32
vzeroupper
%endif
RET
%endmacro
%macro MIX_3_8_TO_1_2_FLT_FUNCS 0
%assign %%i 3
%rep 6
INIT_XMM sse
MIX_3_8_TO_1_2_FLT %%i, 1, fltp
MIX_3_8_TO_1_2_FLT %%i, 2, fltp
INIT_XMM sse2
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
INIT_XMM sse4
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
; do not use ymm AVX or FMA4 in x86-32 for 6 or more channels due to stack alignment issues
%if HAVE_AVX_EXTERNAL
%if ARCH_X86_64 || %%i < 6
INIT_YMM avx
%else
INIT_XMM avx
%endif
MIX_3_8_TO_1_2_FLT %%i, 1, fltp
MIX_3_8_TO_1_2_FLT %%i, 2, fltp
INIT_XMM avx
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
%endif
%if HAVE_FMA4_EXTERNAL
%if ARCH_X86_64 || %%i < 6
INIT_YMM fma4
%else
INIT_XMM fma4
%endif
MIX_3_8_TO_1_2_FLT %%i, 1, fltp
MIX_3_8_TO_1_2_FLT %%i, 2, fltp
INIT_XMM fma4
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
%endif
%assign %%i %%i+1
%endrep
%endmacro
MIX_3_8_TO_1_2_FLT_FUNCS

View File

@ -1,215 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include "config.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
#include "libavresample/audio_mix.h"
void ff_mix_2_to_1_fltp_flt_sse(float **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_2_to_1_fltp_flt_avx(float **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_2_to_1_s16p_flt_sse2(int16_t **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_2_to_1_s16p_flt_sse4(int16_t **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_2_to_1_s16p_q8_sse2(int16_t **src, int16_t **matrix,
int len, int out_ch, int in_ch);
void ff_mix_1_to_2_fltp_flt_sse(float **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_1_to_2_fltp_flt_avx(float **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_1_to_2_s16p_flt_sse2(int16_t **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_1_to_2_s16p_flt_sse4(int16_t **src, float **matrix, int len,
int out_ch, int in_ch);
void ff_mix_1_to_2_s16p_flt_avx (int16_t **src, float **matrix, int len,
int out_ch, int in_ch);
#define DEFINE_MIX_3_8_TO_1_2(chan) \
void ff_mix_ ## chan ## _to_1_fltp_flt_sse(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_fltp_flt_sse(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_s16p_flt_sse2(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_s16p_flt_sse2(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_s16p_flt_sse4(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_s16p_flt_sse4(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_fltp_flt_avx(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_fltp_flt_avx(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_s16p_flt_avx(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_s16p_flt_avx(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_fltp_flt_fma4(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_fltp_flt_fma4(float **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
\
void ff_mix_ ## chan ## _to_1_s16p_flt_fma4(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch); \
void ff_mix_ ## chan ## _to_2_s16p_flt_fma4(int16_t **src, \
float **matrix, int len, \
int out_ch, int in_ch);
DEFINE_MIX_3_8_TO_1_2(3)
DEFINE_MIX_3_8_TO_1_2(4)
DEFINE_MIX_3_8_TO_1_2(5)
DEFINE_MIX_3_8_TO_1_2(6)
DEFINE_MIX_3_8_TO_1_2(7)
DEFINE_MIX_3_8_TO_1_2(8)
#define SET_MIX_3_8_TO_1_2(chan) \
if (EXTERNAL_SSE(cpu_flags)) { \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, 16, 4, "SSE", \
ff_mix_ ## chan ## _to_1_fltp_flt_sse); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, 16, 4, "SSE", \
ff_mix_## chan ##_to_2_fltp_flt_sse); \
} \
if (EXTERNAL_SSE2(cpu_flags)) { \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, 16, 8, "SSE2", \
ff_mix_ ## chan ## _to_1_s16p_flt_sse2); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, 16, 8, "SSE2", \
ff_mix_ ## chan ## _to_2_s16p_flt_sse2); \
} \
if (EXTERNAL_SSE4(cpu_flags)) { \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, 16, 8, "SSE4", \
ff_mix_ ## chan ## _to_1_s16p_flt_sse4); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, 16, 8, "SSE4", \
ff_mix_ ## chan ## _to_2_s16p_flt_sse4); \
} \
if (EXTERNAL_AVX(cpu_flags)) { \
int ptr_align = 32; \
int smp_align = 8; \
if (ARCH_X86_32 || chan >= 6) { \
ptr_align = 16; \
smp_align = 4; \
} \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, ptr_align, smp_align, "AVX", \
ff_mix_ ## chan ## _to_1_fltp_flt_avx); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, ptr_align, smp_align, "AVX", \
ff_mix_ ## chan ## _to_2_fltp_flt_avx); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, 16, 8, "AVX", \
ff_mix_ ## chan ## _to_1_s16p_flt_avx); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, 16, 8, "AVX", \
ff_mix_ ## chan ## _to_2_s16p_flt_avx); \
} \
if (EXTERNAL_FMA4(cpu_flags)) { \
int ptr_align = 32; \
int smp_align = 8; \
if (ARCH_X86_32 || chan >= 6) { \
ptr_align = 16; \
smp_align = 4; \
} \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, ptr_align, smp_align, "FMA4", \
ff_mix_ ## chan ## _to_1_fltp_flt_fma4); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, ptr_align, smp_align, "FMA4", \
ff_mix_ ## chan ## _to_2_fltp_flt_fma4); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 1, 16, 8, "FMA4", \
ff_mix_ ## chan ## _to_1_s16p_flt_fma4); \
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\
chan, 2, 16, 8, "FMA4", \
ff_mix_ ## chan ## _to_2_s16p_flt_fma4); \
}
av_cold void ff_audio_mix_init_x86(AudioMix *am)
{
int cpu_flags = av_get_cpu_flags();
if (EXTERNAL_SSE(cpu_flags)) {
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
2, 1, 16, 8, "SSE", ff_mix_2_to_1_fltp_flt_sse);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
1, 2, 16, 4, "SSE", ff_mix_1_to_2_fltp_flt_sse);
}
if (EXTERNAL_SSE2(cpu_flags)) {
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_flt_sse2);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8,
2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_q8_sse2);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
1, 2, 16, 8, "SSE2", ff_mix_1_to_2_s16p_flt_sse2);
}
if (EXTERNAL_SSE4(cpu_flags)) {
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
2, 1, 16, 8, "SSE4", ff_mix_2_to_1_s16p_flt_sse4);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
1, 2, 16, 8, "SSE4", ff_mix_1_to_2_s16p_flt_sse4);
}
if (EXTERNAL_AVX_FAST(cpu_flags)) {
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
2, 1, 32, 16, "AVX", ff_mix_2_to_1_fltp_flt_avx);
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,
1, 2, 32, 8, "AVX", ff_mix_1_to_2_fltp_flt_avx);
}
if (EXTERNAL_AVX(cpu_flags)) {
ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,
1, 2, 16, 8, "AVX", ff_mix_1_to_2_s16p_flt_avx);
}
SET_MIX_3_8_TO_1_2(3)
SET_MIX_3_8_TO_1_2(4)
SET_MIX_3_8_TO_1_2(5)
SET_MIX_3_8_TO_1_2(6)
SET_MIX_3_8_TO_1_2(7)
SET_MIX_3_8_TO_1_2(8)
}

View File

@ -1,117 +0,0 @@
;******************************************************************************
;* x86 optimized dithering format conversion
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
;* 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
;******************************************************************************
%include "libavutil/x86/x86util.asm"
SECTION_RODATA 32
; 1.0f / (2.0f * INT32_MAX)
pf_dither_scale: times 8 dd 2.32830643762e-10
pf_s16_scale: times 4 dd 32753.0
SECTION .text
;------------------------------------------------------------------------------
; void ff_quantize(int16_t *dst, float *src, float *dither, int len);
;------------------------------------------------------------------------------
INIT_XMM sse2
cglobal quantize, 4,4,3, dst, src, dither, len
lea lenq, [2*lend]
add dstq, lenq
lea srcq, [srcq+2*lenq]
lea ditherq, [ditherq+2*lenq]
neg lenq
mova m2, [pf_s16_scale]
.loop:
mulps m0, m2, [srcq+2*lenq]
mulps m1, m2, [srcq+2*lenq+mmsize]
addps m0, [ditherq+2*lenq]
addps m1, [ditherq+2*lenq+mmsize]
cvtps2dq m0, m0
cvtps2dq m1, m1
packssdw m0, m1
mova [dstq+lenq], m0
add lenq, mmsize
jl .loop
REP_RET
;------------------------------------------------------------------------------
; void ff_dither_int_to_float_rectangular(float *dst, int *src, int len)
;------------------------------------------------------------------------------
%macro DITHER_INT_TO_FLOAT_RECTANGULAR 0
cglobal dither_int_to_float_rectangular, 3,3,3, dst, src, len
lea lenq, [4*lend]
add srcq, lenq
add dstq, lenq
neg lenq
mova m0, [pf_dither_scale]
.loop:
cvtdq2ps m1, [srcq+lenq]
cvtdq2ps m2, [srcq+lenq+mmsize]
mulps m1, m1, m0
mulps m2, m2, m0
mova [dstq+lenq], m1
mova [dstq+lenq+mmsize], m2
add lenq, 2*mmsize
jl .loop
REP_RET
%endmacro
INIT_XMM sse2
DITHER_INT_TO_FLOAT_RECTANGULAR
INIT_YMM avx
DITHER_INT_TO_FLOAT_RECTANGULAR
;------------------------------------------------------------------------------
; void ff_dither_int_to_float_triangular(float *dst, int *src0, int len)
;------------------------------------------------------------------------------
%macro DITHER_INT_TO_FLOAT_TRIANGULAR 0
cglobal dither_int_to_float_triangular, 3,4,5, dst, src0, len, src1
lea lenq, [4*lend]
lea src1q, [src0q+2*lenq]
add src0q, lenq
add dstq, lenq
neg lenq
mova m0, [pf_dither_scale]
.loop:
cvtdq2ps m1, [src0q+lenq]
cvtdq2ps m2, [src0q+lenq+mmsize]
cvtdq2ps m3, [src1q+lenq]
cvtdq2ps m4, [src1q+lenq+mmsize]
addps m1, m1, m3
addps m2, m2, m4
mulps m1, m1, m0
mulps m2, m2, m0
mova [dstq+lenq], m1
mova [dstq+lenq+mmsize], m2
add lenq, 2*mmsize
jl .loop
REP_RET
%endmacro
INIT_XMM sse2
DITHER_INT_TO_FLOAT_TRIANGULAR
INIT_YMM avx
DITHER_INT_TO_FLOAT_TRIANGULAR

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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
*/
#include "config.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
#include "libavresample/dither.h"
void ff_quantize_sse2(int16_t *dst, const float *src, float *dither, int len);
void ff_dither_int_to_float_rectangular_sse2(float *dst, int *src, int len);
void ff_dither_int_to_float_rectangular_avx(float *dst, int *src, int len);
void ff_dither_int_to_float_triangular_sse2(float *dst, int *src0, int len);
void ff_dither_int_to_float_triangular_avx(float *dst, int *src0, int len);
av_cold void ff_dither_init_x86(DitherDSPContext *ddsp,
enum AVResampleDitherMethod method)
{
int cpu_flags = av_get_cpu_flags();
if (EXTERNAL_SSE2(cpu_flags)) {
ddsp->quantize = ff_quantize_sse2;
ddsp->ptr_align = 16;
ddsp->samples_align = 8;
}
if (method == AV_RESAMPLE_DITHER_RECTANGULAR) {
if (EXTERNAL_SSE2(cpu_flags)) {
ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_sse2;
}
if (EXTERNAL_AVX_FAST(cpu_flags)) {
ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_avx;
}
} else {
if (EXTERNAL_SSE2(cpu_flags)) {
ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_sse2;
}
if (EXTERNAL_AVX_FAST(cpu_flags)) {
ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_avx;
}
}
}

View File

@ -1,41 +0,0 @@
;******************************************************************************
;* x86 utility macros for libavresample
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
;* 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
;******************************************************************************
%macro S16_TO_S32_SX 2 ; src/low dst, high dst
%if cpuflag(sse4)
pmovsxwd m%2, m%1
psrldq m%1, 8
pmovsxwd m%1, m%1
SWAP %1, %2
%else
mova m%2, m%1
punpckhwd m%2, m%2
punpcklwd m%1, m%1
psrad m%2, 16
psrad m%1, 16
%endif
%endmacro
%macro DEINT2_PS 3 ; src0/even dst, src1/odd dst, temp
shufps m%3, m%1, m%2, q3131
shufps m%1, m%2, q2020
SWAP %2,%3
%endmacro

View File

@ -1,31 +0,0 @@
/*
* check XMM registers for clobbers on Win64
* Copyright (c) 2013 Martin Storsjo
*
* 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
*/
#include "libavresample/avresample.h"
#include "libavutil/x86/w64xmmtest.h"
wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output,
int out_plane_size, int out_samples, uint8_t **input,
int in_plane_size, int in_samples))
{
testxmmclobbers(avresample_convert, avr, output, out_plane_size,
out_samples, input, in_plane_size, in_samples);
}

View File

@ -157,7 +157,6 @@ include $(SRC_PATH)/tests/fate/indeo.mak
include $(SRC_PATH)/tests/fate/libavcodec.mak
include $(SRC_PATH)/tests/fate/libavdevice.mak
include $(SRC_PATH)/tests/fate/libavformat.mak
include $(SRC_PATH)/tests/fate/libavresample.mak
include $(SRC_PATH)/tests/fate/libavutil.mak
include $(SRC_PATH)/tests/fate/libswresample.mak
include $(SRC_PATH)/tests/fate/libswscale.mak

View File

@ -48,7 +48,6 @@ configure()(
--samples="${samples}" \
--enable-gpl \
--enable-memory-poisoning \
--enable-avresample \
${ignore_tests:+--ignore-tests="$ignore_tests"} \
${arch:+--arch=$arch} \
${cpu:+--cpu="$cpu"} \

View File

@ -1,68 +0,0 @@
CROSS_TEST = $(foreach I,$(1), \
$(foreach J,$(1), \
$(if $(filter-out $(I),$(J)), \
$(eval $(call $(2),$(I),$(J),$(3),$(4),$(5))), \
)))
MIX_CHANNELS = 1 2 3 4 5 6 7 8
define MIX
FATE_LAVR_MIX += fate-lavr-mix-$(3)-$(1)-$(2)
fate-lavr-mix-$(3)-$(1)-$(2): tests/data/asynth-44100-$(1).wav
fate-lavr-mix-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-$(1).wav -ac $(2) -mix_coeff_type $(3) -internal_sample_fmt $(4) -f s16le -af atrim=end_sample=1024 -
fate-lavr-mix-$(3)-$(1)-$(2): CMP = oneoff
fate-lavr-mix-$(3)-$(1)-$(2): REF = $(SAMPLES)/lavr/lavr-mix-$(3)-$(1)-$(2)
endef
$(call CROSS_TEST,$(MIX_CHANNELS),MIX,q8,s16p)
$(call CROSS_TEST,$(MIX_CHANNELS),MIX,q15,s16p)
$(call CROSS_TEST,$(MIX_CHANNELS),MIX,flt,fltp)
# test output zeroing with skipped corresponding input
FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, CHANNELMAP RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-lavr-mix-output-zero
fate-lavr-mix-output-zero: tests/data/filtergraphs/lavr_mix_output_zero tests/data/asynth-44100-4.wav
fate-lavr-mix-output-zero: CMP = oneoff
fate-lavr-mix-output-zero: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-4.wav -filter_script $(TARGET_PATH)/tests/data/filtergraphs/lavr_mix_output_zero -f s16le -
fate-lavr-mix-output-zero: REF = $(SAMPLES)/lavr/lavr-mix-output-zero
FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_MIX)
fate-lavr-mix: $(FATE_LAVR_MIX-yes)
#FATE_LAVR += $(FATE_LAVR_MIX-yes)
SAMPLERATES = 2626 8000 44100 48000 96000
define RESAMPLE
FATE_LAVR_RESAMPLE += fate-lavr-resample-$(3)-$(1)-$(2)
fate-lavr-resample-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
fate-lavr-resample-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -ar $(2) -internal_sample_fmt $(3) -f $(4) -af atrim=end_sample=10240 -
fate-lavr-resample-$(3)-$(1)-$(2): CMP = oneoff
fate-lavr-resample-$(3)-$(1)-$(2): CMP_UNIT = $(5)
fate-lavr-resample-$(3)-$(1)-$(2): FUZZ = 6
fate-lavr-resample-$(3)-$(1)-$(2): REF = $(SAMPLES)/lavr/lavr-resample-$(3)-$(1)-$(2)-v3
endef
$(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,s16p,s16le,s16)
$(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,s32p,s32le,s16)
$(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,fltp,f32le,f32)
$(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,dblp,f64le,f64)
FATE_LAVR_RESAMPLE += fate-lavr-resample-linear
fate-lavr-resample-linear: tests/data/asynth-44100-1.wav
fate-lavr-resample-linear: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -ar 48000 -filter_size 32 -linear_interp 1 -f s16le -af atrim=end_sample=10240 -
fate-lavr-resample-linear: CMP = oneoff
fate-lavr-resample-linear: CMP_UNIT = s16
fate-lavr-resample-linear: REF = $(SAMPLES)/lavr/lavr-resample-linear
FATE_LAVR_RESAMPLE += fate-lavr-resample-nearest
fate-lavr-resample-nearest: tests/data/asynth-48000-1.wav
fate-lavr-resample-nearest: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-48000-1.wav -ar 44100 -filter_size 0 -phase_shift 0 -f s16le -af atrim=end_sample=10240 -
fate-lavr-resample-nearest: CMP = oneoff
fate-lavr-resample-nearest: CMP_UNIT = s16
fate-lavr-resample-nearest: REF = $(SAMPLES)/lavr/lavr-resample-nearest
FATE_LAVR_RESAMPLE-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_RESAMPLE)
fate-lavr-resample: $(FATE_LAVR_RESAMPLE-yes)
#FATE_LAVR += $(FATE_LAVR_RESAMPLE-yes)
FATE_SAMPLES_AVCONV += $(FATE_LAVR)
fate-lavr: $(FATE_LAVR)

View File

@ -43,7 +43,6 @@ EOF
# gen-rc libavdevice "FFmpeg device handling library"
# gen-rc libavfilter "FFmpeg audio/video filtering library"
# gen-rc libpostproc "FFmpeg postprocessing library"
# gen-rc libavresample "Libav audio resampling library"
# gen-rc libswscale "FFmpeg image rescaling library"
# gen-rc libswresample "FFmpeg audio resampling library"

View File

@ -30,7 +30,7 @@
* build the fuzz target.
Choose the value of FFMPEG_CODEC (e.g. AV_CODEC_ID_DVD_SUBTITLE) and
choose one of FUZZ_FFMPEG_VIDEO, FUZZ_FFMPEG_AUDIO, FUZZ_FFMPEG_SUBTITLE.
clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread
clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread
* create a corpus directory and put some samples there (empty dir is ok too):
mkdir CORPUS && cp some-files CORPUS