[FFmpeg-trac] #8556(avcodec:new): PCM 24-bit integer sample format encoding introduces more quantification error

FFmpeg trac at avcodec.org
Sat Mar 7 10:19:32 EET 2020


#8556: PCM 24-bit integer sample format encoding introduces more quantification
error
-------------------------------------+-------------------------------------
             Reporter:  Prcuvu       |                     Type:  defect
               Status:  new          |                 Priority:  normal
            Component:  avcodec      |                  Version:
             Keywords:  avcodec PCM  |  unspecified
  sample rounding                    |               Blocked By:
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
 Summary of the bug:
 The 24-bit integer sample format encoding is implemented as such in
 `libavcodec/pcm.c`:
 {{{
  69 #define ENCODE(type, endian, src, dst, n, shift, offset)
 \
  70     samples_ ## type = (const type *) src;
 \
  71     for (; n > 0; n--) {
 \
  72         register type v = (*samples_ ## type++ >> shift) + offset;
 \
  73         bytestream_put_ ## endian(&dst, v);
 \
  74     }
 ...
 115     case AV_CODEC_ID_PCM_S24LE:
 116         ENCODE(int32_t, le24, samples, dst, n, 8, 0)
 117         break;
 ...
 609 PCM_CODEC  (PCM_S24LE,        AV_SAMPLE_FMT_S32, pcm_s24le,
 "PCM signed 24-bit little-endian");
 }}}
 The codec uses 32-bit signed integer internally and right-shift to 24-bit
 on encoding without checking magnitude of the least significant 8 bits.
 Ideally it should do some rounding check.

 In `libswresample/audioconvert.c`:
 {{{
  80 CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT,
 av_clipl_int32(llrintf(*(const float*)pi * (1U<<31))))
 }}}
 It is using `llrintf` which rounds to the nearest representable value by
 default.

 If I try to convert a 32-bit floating point PCM wave file to 24-bit signed
 integer sample format, the behaviour is inconsistent with that converting
 to 32-bit signed integer sample format. For the 24-bit integer case, it is
 effectively rounding down to negative infinity.

 For example, assume there is an input floating point value which is (0.75
 / 2^23^). The desired 24-bit integer value should be 1 with correct
 rounding.
 With the current implementation, it will be converted to a 32-bit integer
 value of 192 first, then right-shifted by 8 bits. The final result is 0,
 which can be seen as being rounded down.

 This issue resides in all conversions involving 24-bit integer as target
 format.

 Possible solutions include adding a new `AV_SAMPLE_FMT_S24` format in
 avutil or adding rounding check in `ENCODE` macro in `libavcodec/pcm.c`.

 How to reproduce:
 {{{
 % ffmpeg -i [f32.wav] -acodec pcm_s24le [s24.wav]
 }}}

--
Ticket URL: <https://trac.ffmpeg.org/ticket/8556>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list