[FFmpeg-trac] #4609(avformat:reopened): webp muxer silently seeks backwards when converting bigger png inputs and produce borked results when trying to write the length in the header (was: webp muxer seeks backwards)

FFmpeg trac at avcodec.org
Thu Oct 5 15:25:04 EEST 2023


#4609: webp muxer silently seeks backwards when converting bigger png inputs and
produce borked results when trying to write the length in the header
------------------------------------+------------------------------------
             Reporter:  ronag       |                    Owner:  (none)
                 Type:  defect      |                   Status:  reopened
             Priority:  normal      |                Component:  avformat
              Version:  git-master  |               Resolution:
             Keywords:  webp        |               Blocked By:
             Blocking:              |  Reproduced by developer:  0
Analyzed by developer:  0           |
------------------------------------+------------------------------------
Changes (by Jorropo):

 * cc: Jorropo (added)
 * status:  closed => reopened
 * resolution:  invalid =>
 * summary:  webp muxer seeks backwards =>
     webp muxer silently seeks backwards when converting bigger png inputs
     and produce borked results when trying to write the length in the
     header

Comment:

 Hey, I have a reproduction that fails on all versions of ffmpeg I could
 get my hand on (4.1.11, 6.0, 2023-10-5 git-master
 9078dc0c5202d54160f9a2d4c86c6f1ce756a224).
 {{{
 > curl -sssL
 https://w3s.link/ipfs/QmXgtZqEkiVuZgXSHJT3Cxmg2FDDqLwhRDRwrF3DipvKmN/t1.png
 | ffmpeg -i - -vcodec libwebp -preset default -f webp - | cat > t1.webp #
 gives broken file
 ffmpeg version n6.0 Copyright (c) 2000-2023 the FFmpeg developers
   built with gcc 13.2.1 (GCC) 20230801
   configuration: --prefix=/usr --disable-debug --disable-static --disable-
 stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto
 --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-
 ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b
 --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi
 --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libjxl
 --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb
 --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopenmpt
 --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg
 --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh
 --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab
 --enable-libvmaf --enable-libvorbis --enable-libvpl --enable-libvpx
 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb
 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec
 --enable-nvenc --enable-opencl --enable-opengl --enable-shared --enable-
 version3 --enable-vulkan
   libavutil      58.  2.100 / 58.  2.100
   libavcodec     60.  3.100 / 60.  3.100
   libavformat    60.  3.100 / 60.  3.100
   libavdevice    60.  1.100 / 60.  1.100
   libavfilter     9.  3.100 /  9.  3.100
   libswscale      7.  1.100 /  7.  1.100
   libswresample   4. 10.100 /  4. 10.100
   libpostproc    57.  1.100 / 57.  1.100
 Input #0, png_pipe, from 'fd:':
   Duration: N/A, bitrate: N/A
   Stream #0:0: Video: png, rgba(pc), 2860x1576 [SAR 5669:5669 DAR
 715:394], 25 fps, 25 tbr, 25 tbn
 Stream mapping:
   Stream #0:0 -> #0:0 (png (native) -> webp (libwebp))
 Output #0, webp, to 'pipe:':
   Metadata:
     encoder         : Lavf60.3.100
   Stream #0:0: Video: webp, bgra(pc, gbr/unknown/unknown, progressive),
 2860x1576 [SAR 1:1 DAR 715:394], q=2-31, 200 kb/s, 25 fps, 1k tbn
     Metadata:
       encoder         : Lavc60.3.100 libwebp
 [libwebp @ 0x55f4e77f54c0] Using libwebp for RGB-to-YUV conversion. You
 may want to consider passing in YUV instead for lossy encoding.
 frame=    1 fps=0.0 q=-0.0 Lsize=     163kB time=00:00:00.00 bitrate=N/A
 speed=   0x
 video:163kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
 muxing overhead: 0.002401%
 }}}
 {{{
 ffmpeg version n6.0 Copyright (c) 2000-2023 the FFmpeg developers
   built with gcc 13.2.1 (GCC) 20230801
   configuration: --prefix=/usr --disable-debug --disable-static --disable-
 stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto
 --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-
 ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b
 --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi
 --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libjxl
 --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb
 --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopenmpt
 --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg
 --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh
 --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab
 --enable-libvmaf --enable-libvorbis --enable-libvpl --enable-libvpx
 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb
 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec
 --enable-nvenc --enable-opencl --enable-opengl --enable-shared --enable-
 version3 --enable-vulkan
   libavutil      58.  2.100 / 58.  2.100
   libavcodec     60.  3.100 / 60.  3.100
   libavformat    60.  3.100 / 60.  3.100
   libavdevice    60.  1.100 / 60.  1.100
   libavfilter     9.  3.100 /  9.  3.100
   libswscale      7.  1.100 /  7.  1.100
   libswresample   4. 10.100 /  4. 10.100
   libpostproc    57.  1.100 / 57.  1.100
 Input #0, png_pipe, from 'fd:':
   Duration: N/A, bitrate: N/A
   Stream #0:0: Video: png, rgba(pc), 2530x1430 [SAR 5669:5669 DAR 23:13],
 25 fps, 25 tbr, 25 tbn
 Stream mapping:
   Stream #0:0 -> #0:0 (png (native) -> webp (libwebp))
 Output #0, webp, to 'pipe:':
   Metadata:
     encoder         : Lavf60.3.100
   Stream #0:0: Video: webp, bgra(pc, gbr/unknown/unknown, progressive),
 2530x1430 [SAR 1:1 DAR 23:13], q=2-31, 200 kb/s, 25 fps, 1k tbn
     Metadata:
       encoder         : Lavc60.3.100 libwebp
 [libwebp @ 0x555b029314c0] Using libwebp for RGB-to-YUV conversion. You
 may want to consider passing in YUV instead for lossy encoding.
 frame=    1 fps=0.0 q=-0.0 Lsize=     147kB time=00:00:00.00 bitrate=N/A
 speed=   0x
 video:147kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
 muxing overhead: 0.002663%
 }}}
 {{{
 > curl -sssL
 https://w3s.link/ipfs/QmXgtZqEkiVuZgXSHJT3Cxmg2FDDqLwhRDRwrF3DipvKmN/t3.png
 | ffmpeg -i - -vcodec libwebp -preset default -f webp - | cat > t3.webp #
 gives broken file
 ffmpeg version n6.0 Copyright (c) 2000-2023 the FFmpeg developers
   built with gcc 13.2.1 (GCC) 20230801
   configuration: --prefix=/usr --disable-debug --disable-static --disable-
 stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto
 --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-
 ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b
 --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi
 --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libjxl
 --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb
 --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopenmpt
 --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg
 --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh
 --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab
 --enable-libvmaf --enable-libvorbis --enable-libvpl --enable-libvpx
 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb
 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec
 --enable-nvenc --enable-opencl --enable-opengl --enable-shared --enable-
 version3 --enable-vulkan
   libavutil      58.  2.100 / 58.  2.100
   libavcodec     60.  3.100 / 60.  3.100
   libavformat    60.  3.100 / 60.  3.100
   libavdevice    60.  1.100 / 60.  1.100
   libavfilter     9.  3.100 /  9.  3.100
   libswscale      7.  1.100 /  7.  1.100
   libswresample   4. 10.100 /  4. 10.100
   libpostproc    57.  1.100 / 57.  1.100
 Input #0, png_pipe, from 'fd:':
   Duration: N/A, bitrate: N/A
   Stream #0:0: Video: png, rgba(pc), 1518x802 [SAR 5669:5669 DAR 759:401],
 25 fps, 25 tbr, 25 tbn
 Stream mapping:
   Stream #0:0 -> #0:0 (png (native) -> webp (libwebp))
 Output #0, webp, to 'pipe:':
   Metadata:
     encoder         : Lavf60.3.100
   Stream #0:0: Video: webp, bgra(pc, gbr/unknown/unknown, progressive),
 1518x802 [SAR 1:1 DAR 759:401], q=2-31, 200 kb/s, 25 fps, 1k tbn
     Metadata:
       encoder         : Lavc60.3.100 libwebp
 [libwebp @ 0x561307cf74c0] Using libwebp for RGB-to-YUV conversion. You
 may want to consider passing in YUV instead for lossy encoding.
 frame=    1 fps=0.0 q=-0.0 Lsize=      69kB time=00:00:00.00 bitrate=N/A
 speed=   0x
 video:69kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
 muxing overhead: 0.005682%
 }}}
 The resulting files really feels like they want to work, firefox flashes
 the correct image for a frame before switching to an error.

 This one smaller than the others works:
 {{{
 > curl -sssL
 https://w3s.link/ipfs/QmXgtZqEkiVuZgXSHJT3Cxmg2FDDqLwhRDRwrF3DipvKmN/t4.png
 | ffmpeg -i - -vcodec libwebp -preset default -f webp - | cat > t4.webp #
 works
 ffmpeg version n6.0 Copyright (c) 2000-2023 the FFmpeg developers
   built with gcc 13.2.1 (GCC) 20230801
   configuration: --prefix=/usr --disable-debug --disable-static --disable-
 stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto
 --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-
 ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b
 --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi
 --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libjxl
 --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb
 --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopenmpt
 --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg
 --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh
 --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab
 --enable-libvmaf --enable-libvorbis --enable-libvpl --enable-libvpx
 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb
 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec
 --enable-nvenc --enable-opencl --enable-opengl --enable-shared --enable-
 version3 --enable-vulkan
   libavutil      58.  2.100 / 58.  2.100
   libavcodec     60.  3.100 / 60.  3.100
   libavformat    60.  3.100 / 60.  3.100
   libavdevice    60.  1.100 / 60.  1.100
   libavfilter     9.  3.100 /  9.  3.100
   libswscale      7.  1.100 /  7.  1.100
   libswresample   4. 10.100 /  4. 10.100
   libpostproc    57.  1.100 / 57.  1.100
 Input #0, png_pipe, from 'fd:':
   Duration: N/A, bitrate: N/A
   Stream #0:0: Video: png, rgba(pc), 672x480 [SAR 5669:5669 DAR 7:5], 25
 fps, 25 tbr, 25 tbn
 Stream mapping:
   Stream #0:0 -> #0:0 (png (native) -> webp (libwebp))
 Output #0, webp, to 'pipe:':
   Metadata:
     encoder         : Lavf60.3.100
   Stream #0:0: Video: webp, bgra(pc, gbr/unknown/unknown, progressive),
 672x480 [SAR 1:1 DAR 7:5], q=2-31, 200 kb/s, 25 fps, 1k tbn
     Metadata:
       encoder         : Lavc60.3.100 libwebp
 [libwebp @ 0x55cb0b0564c0] Using libwebp for RGB-to-YUV conversion. You
 may want to consider passing in YUV instead for lossy encoding.
 frame=    1 fps=0.0 q=-0.0 Lsize=      27kB time=00:00:00.00 bitrate=N/A
 speed=   0x
 video:27kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
 muxing overhead: 0.000000%
 }}}

 Writing to a file directly instead of through a pipe correctly works,
 diffing the old and bad files the surface bug seems evident:
 {{{
 1c1
 < 00000000: 5249 4646 b48a 0200 5745 4250 5650 3820  RIFF....WEBPVP8
 ---
 > 00000000: 5249 4646 0000 0000 5745 4250 5650 3820  RIFF....WEBPVP8
 10412c10412
 < 00028ab0: 0000 0000 0000 0000 0000 0000            ............
 ---
 > 00028ab0: 0000 0000 0000 0000 0000 0000 b48a 0200  ................
 }}}
 We can see that for the bad file the length bytes of the header are blank,
 and the value that is supposed to be there is instead precariously
 appended to the end.
 This is the first time I've looked at the webp spec so take this with a
 grain of salt, but it looks like when the input file is too big, some
 internal processing switches to a streaming mode, it zerofills the length
 header and then after writing the complete webp it then tries to write the
 length to the header using seek but errors aren't properly checked and the
 seek is silently dropped leaving the length written to the tail of the
 file.
-- 
Ticket URL: <https://trac.ffmpeg.org/ticket/4609#comment:6>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list