[FFmpeg-devel] [PATCH] audio conversion clipping/overflows

Ronald S. Bultje rsbultje
Mon Mar 1 15:18:58 CET 2010


Hi,

float 1.0 rounds to int INT_MIN (whatever int size). This leads to
considerable audio clipping artifacts.

Attached patch is a lame attempt of mine to fix this. It probably
makes the code slower, so sue me. :-).

Ronald
-------------- next part --------------
Index: libavcodec/audioconvert.c
===================================================================
--- libavcodec/audioconvert.c	(revision 22027)
+++ libavcodec/audioconvert.c	(working copy)
@@ -226,14 +226,20 @@
         else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_S32,  *(const int32_t*)pi)
         else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
         else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_S32,  *(const int32_t*)pi*(1.0 / (1<<31)))
-        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<7)) + 0x80)
-        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<15)))
-        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_FLT, lrintf(*(const float*)pi * (1<<31)))
+        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_FLT,
+                  av_clip_uint8(lrintf(*(const float*)pi * (1<<7)) + 0x80))
+        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_FLT,
+                  av_clip_int16(lrintf(*(const float*)pi * (1<<15))))
+        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_FLT,
+                  av_clipl_int32(llrintf(*(const float*)pi * (1<<31))))
         else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_FLT, *(const float*)pi)
         else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_FLT, *(const float*)pi)
-        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<7)) + 0x80)
-        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<15)))
-        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_DBL, lrint(*(const double*)pi * (1<<31)))
+        else CONV(SAMPLE_FMT_U8 , uint8_t, SAMPLE_FMT_DBL,
+                  av_clip_uint8(lrint(*(const double*)pi * (1<<7)) + 0x80))
+        else CONV(SAMPLE_FMT_S16, int16_t, SAMPLE_FMT_DBL,
+                  av_clip_int16(lrint(*(const double*)pi * (1<<15))))
+        else CONV(SAMPLE_FMT_S32, int32_t, SAMPLE_FMT_DBL,
+                  av_clipl_int32(llrint(*(const double*)pi * (1<<31))))
         else CONV(SAMPLE_FMT_FLT, float  , SAMPLE_FMT_DBL, *(const double*)pi)
         else CONV(SAMPLE_FMT_DBL, double , SAMPLE_FMT_DBL, *(const double*)pi)
         else return -1;
Index: libavutil/common.h
===================================================================
--- libavutil/common.h	(revision 22030)
+++ libavutil/common.h	(working copy)
@@ -222,6 +222,17 @@
 }
 
 /**
+ * Clips a signed 64-bit integer value into the -2147483648,2147483647 range.
+ * @param a value to clip
+ * @return clipped value
+ */
+static inline av_const int32_t av_clipl_int32(int64_t a)
+{
+    if ((a+2147483648) & ~2147483647) return (a>>63) ^ 2147483647;
+    else                              return a;
+}
+
+/**
  * Clips a float value into the amin-amax range.
  * @param a value to clip
  * @param amin minimum value of the clip range



More information about the ffmpeg-devel mailing list