diff --git a/libswresample/audioconvert.c b/libswresample/audioconvert.c index 75c1311ddb..529c911e96 100644 --- a/libswresample/audioconvert.c +++ b/libswresample/audioconvert.c @@ -125,6 +125,9 @@ AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, ctx->ch_map = ch_map; if (in_fmt == AV_SAMPLE_FMT_U8) memset(ctx->silence, 0x80, sizeof(ctx->silence)); + + if(HAVE_YASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels); + return ctx; } @@ -136,21 +139,36 @@ void swri_audio_convert_free(AudioConvert **ctx) int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) { int ch; + int off=0; + const int os= (out->planar ? 1 :out->ch_count) *out->bps; av_assert0(ctx->channels == out->ch_count); //FIXME optimize common cases + if(ctx->simd_f && !ctx->ch_map){ + int planes = out->planar ? out->ch_count : 1; + off = len/16 * 16; + av_assert1(out->planar == in->planar); + av_assert1(off>=0); + if(off>0) + for(ch=0; chsimd_f(out->ch+ch, in->ch+ch, off*os); + } + av_assert1(off<=len); + if(off == len) + return 0; + } + for(ch=0; chchannels; ch++){ const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch; const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps; - const int os= (out->planar ? 1 :out->ch_count) *out->bps; const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich]; uint8_t *po= out->ch[ch]; uint8_t *end= po + os*len; if(!po) continue; - ctx->conv_f(po, pi, is, os, end); + ctx->conv_f(po+off*os, pi+off*is, is, os, end); } return 0; } diff --git a/libswresample/audioconvert.h b/libswresample/audioconvert.h index 9f16caf6d7..9a234d4b93 100644 --- a/libswresample/audioconvert.h +++ b/libswresample/audioconvert.h @@ -35,10 +35,12 @@ typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); +typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len); typedef struct AudioConvert { int channels; conv_func_type *conv_f; + simd_func_type *simd_f; const int *ch_map; uint8_t silence[8]; ///< silence input sample }AudioConvert; diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h index 70db5ae484..293075bf5e 100644 --- a/libswresample/swresample_internal.h +++ b/libswresample/swresample_internal.h @@ -101,4 +101,8 @@ void swri_sum2(enum AVSampleFormat format, void *dst, const void *src0, const vo void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt); +void swri_audio_convert_init_x86(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); #endif diff --git a/libswresample/x86/Makefile b/libswresample/x86/Makefile new file mode 100644 index 0000000000..1ba971e02d --- /dev/null +++ b/libswresample/x86/Makefile @@ -0,0 +1,2 @@ +YASM-OBJS += x86/swresample_x86.o\ + x86/audio_convert.o\ diff --git a/libswresample/x86/audio_convert.asm b/libswresample/x86/audio_convert.asm new file mode 100644 index 0000000000..c7ce8c6c53 --- /dev/null +++ b/libswresample/x86/audio_convert.asm @@ -0,0 +1,52 @@ +;****************************************************************************** +;* Copyright (c) 2012 Michael Niedermayer +;* +;* 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/x86inc.asm" +%include "libavutil/x86/x86util.asm" + +SECTION .text + +%macro INT16_TO_INT32 0 +cglobal int16_to_int32_%1, 3, 3, 0, dst, src, len + mov srcq, [srcq] + mov dstq, [dstq] +.next + movu m4, [srcq] + pxor m0, m0 + pxor m1, m1 + punpcklwd m0, m4 + punpckhwd m1, m4 + movu [ dstq], m0 + movu [mmsize + dstq], m1 + add srcq, mmsize + add dstq, 2*mmsize + sub lenq, 2*mmsize + jg .next +%if mmsize == 8 + emms +%endif + REP_RET +%endmacro + +INIT_MMX mmx +INT16_TO_INT32 + +INIT_XMM sse +INT16_TO_INT32 diff --git a/libswresample/x86/swresample_x86.c b/libswresample/x86/swresample_x86.c new file mode 100644 index 0000000000..5c8d8290cd --- /dev/null +++ b/libswresample/x86/swresample_x86.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample 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. + * + * libswresample 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 libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libswresample/swresample_internal.h" +#include "libswresample/audioconvert.h" + +#define MULTI_CAPS_FUNC_DECL(cap) \ + void ff_int16_to_int32_ ## cap(uint8_t **dst, const uint8_t **src, int len); +MULTI_CAPS_FUNC_DECL(mmx) +MULTI_CAPS_FUNC_DECL(sse) + +void swri_audio_convert_init_x86(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels){ + int mm_flags = av_get_cpu_flags(); + + ac->simd_f= NULL; + +//FIXME add memcpy case + +#define MULTI_CAPS_FUNC(flag, cap) \ + if (mm_flags & flag) {\ + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16P)\ + ac->simd_f = ff_int16_to_int32_ ## cap;\ + } + +MULTI_CAPS_FUNC(AV_CPU_FLAG_MMX, mmx) +MULTI_CAPS_FUNC(AV_CPU_FLAG_SSE, sse) +}