From ea60dfe284b82fc74569bbd562e68ec48f69f154 Mon Sep 17 00:00:00 2001 From: Michael Kostylev Date: Fri, 11 May 2012 12:26:44 +0200 Subject: [PATCH 1/3] x86: vc1: drop MMX loop filter implementation, which uses MMX2 instructions. --- libavcodec/x86/vc1dsp_mmx.c | 2 -- libavcodec/x86/vc1dsp_yasm.asm | 11 ----------- 2 files changed, 13 deletions(-) diff --git a/libavcodec/x86/vc1dsp_mmx.c b/libavcodec/x86/vc1dsp_mmx.c index a525aeeeae..e1f5145735 100644 --- a/libavcodec/x86/vc1dsp_mmx.c +++ b/libavcodec/x86/vc1dsp_mmx.c @@ -701,7 +701,6 @@ static void vc1_h_loop_filter16_ ## EXT(uint8_t *src, int stride, int pq) \ } #if HAVE_YASM -LOOP_FILTER(mmx) LOOP_FILTER(mmx2) LOOP_FILTER(sse2) LOOP_FILTER(ssse3) @@ -790,7 +789,6 @@ void ff_vc1dsp_init_mmx(VC1DSPContext *dsp) #if HAVE_YASM if (mm_flags & AV_CPU_FLAG_MMX) { - ASSIGN_LF(mmx); dsp->put_no_rnd_vc1_chroma_pixels_tab[0]= ff_put_vc1_chroma_mc8_mmx_nornd; } return; diff --git a/libavcodec/x86/vc1dsp_yasm.asm b/libavcodec/x86/vc1dsp_yasm.asm index 66f61dba6a..2c5cf22a0a 100644 --- a/libavcodec/x86/vc1dsp_yasm.asm +++ b/libavcodec/x86/vc1dsp_yasm.asm @@ -227,13 +227,6 @@ section .text imul r2, 0x01010101 %endmacro -; I do not know why the sign extension is needed... -%macro PSIGNW_SRA_MMX 2 - psraw %2, 15 - PSIGNW_MMX %1, %2 -%endmacro - - %macro VC1_LF_MMX 1 INIT_MMX cglobal vc1_v_loop_filter_internal_%1 @@ -274,10 +267,6 @@ cglobal vc1_h_loop_filter8_%1, 3,5,0 RET %endmacro -%define PABSW PABSW_MMX -%define PSIGNW PSIGNW_SRA_MMX -VC1_LF_MMX mmx - %define PABSW PABSW_MMX2 VC1_LF_MMX mmx2 From d371e7b9885aabdb29c038fa723bc890276aa366 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 15:09:17 +0200 Subject: [PATCH 2/3] lavfi: add lavr-based audio resampling filter. --- configure | 1 + doc/filters.texi | 6 + libavfilter/Makefile | 2 + libavfilter/af_resample.c | 225 ++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 5 files changed, 235 insertions(+) create mode 100644 libavfilter/af_resample.c diff --git a/configure b/configure index 79b948e4f3..f6cb0e2558 100755 --- a/configure +++ b/configure @@ -1531,6 +1531,7 @@ frei0r_filter_extralibs='$ldl' frei0r_src_filter_deps="frei0r dlopen strtok_r" frei0r_src_filter_extralibs='$ldl' hqdn3d_filter_deps="gpl" +resample_filter_deps="avresample" ocv_filter_deps="libopencv" yadif_filter_deps="gpl" diff --git a/doc/filters.texi b/doc/filters.texi index dbcc86a384..8eff84a0e4 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -111,6 +111,12 @@ Below is a description of the currently available audio filters. Pass the audio source unchanged to the output. +@section resample +Convert the audio sample format, sample rate and channel layout. This filter is +not meant to be used directly, it is inserted automatically by libavfilter +whenever conversion is needed. Use the @var{aformat} filter to force a specific +conversion. + @c man end AUDIO FILTERS @chapter Audio Sources diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 49a47d3e1b..9cbb90847f 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -1,6 +1,7 @@ NAME = avfilter FFLIBS = avutil swscale FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec +FFLIBS-$(CONFIG_RESAMPLE_FILTER) += avresample HEADERS = avfilter.h \ avfiltergraph.h \ @@ -22,6 +23,7 @@ OBJS = allfilters.o \ vsrc_buffer.o \ OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o +OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c new file mode 100644 index 0000000000..f46e24b1b6 --- /dev/null +++ b/libavfilter/af_resample.c @@ -0,0 +1,225 @@ +/* + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * sample format and channel layout conversion audio filter + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" + +#include "libavresample/avresample.h" + +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ResampleContext { + AVAudioResampleContext *avr; + + int64_t next_pts; +} ResampleContext; + +static av_cold void uninit(AVFilterContext *ctx) +{ + ResampleContext *s = ctx->priv; + + if (s->avr) { + avresample_close(s->avr); + avresample_free(&s->avr); + } +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + + AVFilterFormats *in_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); + AVFilterFormats *out_formats = avfilter_all_formats(AVMEDIA_TYPE_AUDIO); + + avfilter_formats_ref(in_formats, &inlink->out_formats); + avfilter_formats_ref(out_formats, &outlink->in_formats); + + 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; + + 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) + return 0; + + if (!(s->avr = avresample_alloc_context())) + return AVERROR(ENOMEM); + + 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 both the input and output formats are s16 or u8, use s16 as + the internal sample format */ + if (av_get_bytes_per_sample(inlink->format) <= 2 && + av_get_bytes_per_sample(outlink->format) <= 2) + av_opt_set_int(s->avr, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0); + + if ((ret = avresample_open(s->avr)) < 0) + return ret; + + outlink->time_base = (AVRational){ 1, outlink->sample_rate }; + s->next_pts = AV_NOPTS_VALUE; + + 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 = avfilter_request_frame(ctx->inputs[0]); + + /* flush the lavr delay buffer */ + if (ret == AVERROR_EOF && s->avr) { + AVFilterBufferRef *buf; + int nb_samples = av_rescale_rnd(avresample_get_delay(s->avr), + outlink->sample_rate, + ctx->inputs[0]->sample_rate, + AV_ROUND_UP); + + if (!nb_samples) + return ret; + + buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); + if (!buf) + return AVERROR(ENOMEM); + + ret = avresample_convert(s->avr, (void**)buf->extended_data, + buf->linesize[0], nb_samples, + NULL, 0, 0); + if (ret <= 0) { + avfilter_unref_buffer(buf); + return (ret == 0) ? AVERROR_EOF : ret; + } + + buf->pts = s->next_pts; + ff_filter_samples(outlink, buf); + return 0; + } + return ret; +} + +static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +{ + AVFilterContext *ctx = inlink->dst; + ResampleContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + if (s->avr) { + AVFilterBufferRef *buf_out; + int delay, nb_samples, ret; + + /* maximum possible samples lavr can output */ + delay = avresample_get_delay(s->avr); + nb_samples = av_rescale_rnd(buf->audio->nb_samples + delay, + outlink->sample_rate, inlink->sample_rate, + AV_ROUND_UP); + + buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); + ret = avresample_convert(s->avr, (void**)buf_out->extended_data, + buf_out->linesize[0], nb_samples, + (void**)buf->extended_data, buf->linesize[0], + buf->audio->nb_samples); + + av_assert0(!avresample_available(s->avr)); + + if (s->next_pts == AV_NOPTS_VALUE) { + if (buf->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(buf->pts, inlink->time_base, + outlink->time_base); + } + + if (ret > 0) { + buf_out->audio->nb_samples = ret; + if (buf->pts != AV_NOPTS_VALUE) { + buf_out->pts = av_rescale_q(buf->pts, inlink->time_base, + outlink->time_base) - + av_rescale(delay, outlink->sample_rate, + inlink->sample_rate); + } else + buf_out->pts = s->next_pts; + + s->next_pts = buf_out->pts + buf_out->audio->nb_samples; + + ff_filter_samples(outlink, buf_out); + } + avfilter_unref_buffer(buf); + } else + ff_filter_samples(outlink, buf); +} + +AVFilter avfilter_af_resample = { + .name = "resample", + .description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."), + .priv_size = sizeof(ResampleContext), + + .uninit = uninit, + .query_formats = query_formats, + + .inputs = (const AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_samples = filter_samples, + .min_perms = AV_PERM_READ }, + { .name = NULL}}, + .outputs = (const AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + .request_frame = request_frame }, + { .name = NULL}}, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index f887002b66..66d890f161 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -35,6 +35,7 @@ void avfilter_register_all(void) initialized = 1; REGISTER_FILTER (ANULL, anull, af); + REGISTER_FILTER (RESAMPLE, resample, af); REGISTER_FILTER (ANULLSRC, anullsrc, asrc); From 012f04a277d21b2c5f28b3710fbe52321424946e Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 15:35:12 +0200 Subject: [PATCH 3/3] lavfi: autoinsert resample filter when necessary. --- libavfilter/avfiltergraph.c | 58 +++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 04d9027527..e576cca471 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -152,8 +152,7 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name) static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) { int i, j, ret; - int scaler_count = 0; - char inst_name[30]; + int scaler_count = 0, resampler_count = 0; /* ask all the sub-filters for their supported media formats */ for (i = 0; i < graph->filter_count; i++) { @@ -172,23 +171,50 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) if (link && link->in_formats != link->out_formats) { if (!avfilter_merge_formats(link->in_formats, link->out_formats)) { - AVFilterContext *scale; + AVFilterContext *convert; + AVFilter *filter; + AVFilterLink *inlink, *outlink; char scale_args[256]; - /* couldn't merge format lists. auto-insert scale filter */ - snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", - scaler_count++); - snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); - if ((ret = avfilter_graph_create_filter(&scale, avfilter_get_by_name("scale"), - inst_name, scale_args, NULL, graph)) < 0) - return ret; - if ((ret = avfilter_insert_filter(link, scale, 0, 0)) < 0) + char inst_name[30]; + + /* couldn't merge format lists. auto-insert conversion filter */ + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", + scaler_count++); + snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); + if ((ret = avfilter_graph_create_filter(&convert, + avfilter_get_by_name("scale"), + inst_name, scale_args, NULL, + graph)) < 0) + return ret; + break; + case AVMEDIA_TYPE_AUDIO: + if (!(filter = avfilter_get_by_name("resample"))) { + av_log(log_ctx, AV_LOG_ERROR, "'resample' filter " + "not present, cannot convert audio formats.\n"); + return AVERROR(EINVAL); + } + + snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d", + resampler_count++); + if ((ret = avfilter_graph_create_filter(&convert, + avfilter_get_by_name("resample"), + inst_name, NULL, NULL, graph)) < 0) + return ret; + break; + default: + return AVERROR(EINVAL); + } + + if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) return ret; - scale->filter->query_formats(scale); - if (((link = scale-> inputs[0]) && - !avfilter_merge_formats(link->in_formats, link->out_formats)) || - ((link = scale->outputs[0]) && - !avfilter_merge_formats(link->in_formats, link->out_formats))) { + convert->filter->query_formats(convert); + inlink = convert->inputs[0]; + outlink = convert->outputs[0]; + if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || + !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) { av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name);