Merge commit '93c04e095dc37ebdab22174e88cfa91e24940866'
[ffmpeg.git] / libswresample / audioconvert.c
index 26cf471..325bdf4 100644 (file)
 #include "audioconvert.h"
 
 
-typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end);
-
-struct AudioConvert {
-    int channels;
-    conv_func_type *conv_f;
-    const int *ch_map;
-    uint8_t silence[8]; ///< silence input sample
-};
-
 #define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt
 
 //FIXME rounding ?
@@ -86,7 +77,7 @@ CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*
 CONV_FUNC(AV_SAMPLE_FMT_FLT, float  , AV_SAMPLE_FMT_DBL, *(const double*)pi)
 CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi)
 
-#define FMT_PAIR_FUNC(out, in) [out + AV_SAMPLE_FMT_NB*in] = CONV_FUNC_NAME(out, in)
+#define FMT_PAIR_FUNC(out, in) [(out) + AV_SAMPLE_FMT_NB*(in)] = CONV_FUNC_NAME(out, in)
 
 static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = {
     FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ),
@@ -116,6 +107,19 @@ static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAM
     FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL),
 };
 
+static void cpy1(uint8_t **dst, const uint8_t **src, int len){
+    memcpy(*dst, *src, len);
+}
+static void cpy2(uint8_t **dst, const uint8_t **src, int len){
+    memcpy(*dst, *src, 2*len);
+}
+static void cpy4(uint8_t **dst, const uint8_t **src, int len){
+    memcpy(*dst, *src, 4*len);
+}
+static void cpy8(uint8_t **dst, const uint8_t **src, int len){
+    memcpy(*dst, *src, 8*len);
+}
+
 AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt,
                                        enum AVSampleFormat in_fmt,
                                        int channels, const int *ch_map,
@@ -129,11 +133,30 @@ AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt,
     ctx = av_mallocz(sizeof(*ctx));
     if (!ctx)
         return NULL;
+
+    if(channels == 1){
+         in_fmt = av_get_planar_sample_fmt( in_fmt);
+        out_fmt = av_get_planar_sample_fmt(out_fmt);
+    }
+
     ctx->channels = channels;
     ctx->conv_f   = f;
     ctx->ch_map   = ch_map;
-    if (in_fmt == AV_SAMPLE_FMT_U8)
+    if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P)
         memset(ctx->silence, 0x80, sizeof(ctx->silence));
+
+    if(out_fmt == in_fmt && !ch_map) {
+        switch(av_get_bytes_per_sample(in_fmt)){
+            case 1:ctx->simd_f = cpy1; break;
+            case 2:ctx->simd_f = cpy2; break;
+            case 4:ctx->simd_f = cpy4; break;
+            case 8:ctx->simd_f = cpy8; break;
+        }
+    }
+
+    if(HAVE_YASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);
+    if(ARCH_ARM)              swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);
+
     return ctx;
 }
 
@@ -145,21 +168,57 @@ 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;
+    unsigned misaligned = 0;
 
     av_assert0(ctx->channels == out->ch_count);
 
+    if (ctx->in_simd_align_mask) {
+        int planes = in->planar ? in->ch_count : 1;
+        unsigned m = 0;
+        for (ch = 0; ch < planes; ch++)
+            m |= (intptr_t)in->ch[ch];
+        misaligned |= m & ctx->in_simd_align_mask;
+    }
+    if (ctx->out_simd_align_mask) {
+        int planes = out->planar ? out->ch_count : 1;
+        unsigned m = 0;
+        for (ch = 0; ch < planes; ch++)
+            m |= (intptr_t)out->ch[ch];
+        misaligned |= m & ctx->out_simd_align_mask;
+    }
+
     //FIXME optimize common cases
 
+    if(ctx->simd_f && !ctx->ch_map && !misaligned){
+        off = len&~15;
+        av_assert1(off>=0);
+        av_assert1(off<=len);
+        av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]);
+        if(off>0){
+            if(out->planar == in->planar){
+                int planes = out->planar ? out->ch_count : 1;
+                for(ch=0; ch<planes; ch++){
+                    ctx->simd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count));
+                }
+            }else{
+                ctx->simd_f(out->ch, (const uint8_t **)in->ch, off);
+            }
+        }
+        if(off == len)
+            return 0;
+    }
+
     for(ch=0; ch<ctx->channels; 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;
 }