Opened 9 years ago

Closed 9 years ago

#4287 closed defect (invalid)

lossless libx264rgb data corruption

Reported by: Peter Cordes Owned by:
Priority: normal Component: avcodec
Version: git-master Keywords: libx264
Cc: Michael Niedermayer Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

ffmpeg -c:v libx264rgb -qp 0 (lossless RGB mode) corrupts some inputs.

After disproving a couple theories while writing this bug report, I now believe that corruption depends on the input codec. It seems it can happen with any x264 settings (although in my testcase it's only visually obvious with subme>=3).

With ffmpeg reading from an RGB-utvideo.mkv, I always get bit-exact (framemd5-checked) correct output with ultrafast and veryslow. Reading from a directory of png files, I always get corrupted output. (decodes fine, but decode output != input for at least some frames).

I forget if I tested with a source produced by muxing the PNGs into an mkv. (-codec copy).

Since it depends on what input source I use, I'm now almost certain this is an ffmpeg bug, and not a libx264 bug. The x264 stand-alone cli output decodes to bit-exact correct values. (Tested using AviSynth+ (http://avs-plus.net/) to read directly from the same directory of PNGs, in a 64bit-windows build of x264.)

How to reproduce:

I'm using an 8-bit color-depth build of libx264.

It's reproducible with the first 16 frames of the Sintel trailer (1080p PNGs). With subme >= 3, there are some thin blocks of solid-blue color in all 3 of the first non-black frames. Even worse artifacts (like a block of all-white in the lower letterbox bar) appear around the middle of the video, and persist until the next black frame.
https://media.xiph.org/sintel/sintel_trailer-1080-png.tar.gz from
https://media.xiph.org/. The first 16 frames only take 308kiB (since many of them are black, starting to fade in at frame 14), so downloading just the first 1MB of the tar.gz should be enough, if they're in order within the archive.

Get at least the first 16 frames of the Sintel trailer, as PNGs in a directory called 1080/. My testcase uses the first 25 frames, because I wanted more than 3 non-black frames while I was trying to see what affected the corruption.

# if you want to copy/paste this, then
alias ffmpeg='ffmpeg -d'  # daemon mode, doesn't read stdin.  -stdin doesn't work
# or paste into a file and source it.

ffmpeg -framerate 24 -i 1080/sintel_trailer_2k_%04d.png -c:v utvideo sintel.utvideo.mkv

mkdir "gtest-$HOSTNAME"  # gtest = glitch test
ffmpeg -i sintel.utvideo.mkv -pix_fmt rgb24 -frames 25 -f framemd5 "gtest-$HOSTNAME/framemd5.rgb24.25.utvideo"

ffmpeg -framerate 24 -i 1080/sintel_trailer_2k_%04d.png -pix_fmt rgb24 -frames 25 -f framemd5 "gtest-$HOSTNAME/framemd5.rgb24.25.png-src"


# PNG input
for opt in subme={0..3}; do
   fr=25 crf=0 pr=ultrafast; s="gtest-$HOSTNAME/ffmpeg$fr.from-png.$pr.$opt";
   FFREPORT=file="'$s.log'" ffmpeg -sws_flags +print_info -framerate 24 -i 1080/sintel_trailer_2k_%04d.png -c:v libx264rgb -crf $crf -preset $pr -frames $fr -x264-params "$opt" "$s.mkv";
   ffmpeg -i "$s.mkv" -pix_fmt rgb24 -f framemd5 "${s/ffmpeg/framemd5.rgb24.}";
done

# UTVideo input
for opt in subme={0..3}; do
   fr=25 crf=0 pr=ultrafast; s="gtest-$HOSTNAME/ffmpeg$fr.from-utvideo.$pr.$opt";
   FFREPORT=file="'$s.log'" ffmpeg -sws_flags +print_info -i sintel.utvideo.mkv -c:v libx264rgb -crf $crf -preset $pr -frames $fr -x264-params "$opt" "$s.mkv";
   ffmpeg -i "$s.mkv" -pix_fmt rgb24 -f framemd5 "${s/ffmpeg/framemd5.rgb24.}";
done


md5sum gtest-$HOSTNAME/framemd5.rgb24.25.* |sort
#output:
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.from-utvideo.ultrafast.subme=0
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.from-utvideo.ultrafast.subme=1
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.from-utvideo.ultrafast.subme=2
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.from-utvideo.ultrafast.subme=3
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.png-src
69700f8152bf3b899f8120e4c4b80567  gtest-tesla/framemd5.rgb24.25.utvideo
6f5e1f1e0646951984deef28c77dccee  gtest-tesla/framemd5.rgb24.25.from-png.ultrafast.subme=3
789ec2dbc2c59f41f123310a757e08a1  gtest-tesla/framemd5.rgb24.25.from-png.ultrafast.subme=0
789ec2dbc2c59f41f123310a757e08a1  gtest-tesla/framemd5.rgb24.25.from-png.ultrafast.subme=1
789ec2dbc2c59f41f123310a757e08a1  gtest-tesla/framemd5.rgb24.25.from-png.ultrafast.subme=2


# simplified commandline:
ffmpeg -framerate 24 -i 1080/sintel_trailer_2k_%04d.png -c:v libx264rgb -qp 0 -frames 16 "sintel.16frames.medium.lossless.mkv"

ffmpeg version N-68120-gfdcb518 (on ubuntu, with some local patches) or zeranoe 64bit:
ffmpeg version N-69278-gf5b3257 Copyright (c) 2000-2015 the FFmpeg developers
  built on Jan 26 2015 22:13:17 with gcc 4.9.2 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --enable-decklink --enable-zlib

...
[libx264rgb @ 0000000002c84820] using mv_range_thread = 88
[libx264rgb @ 0000000002c84820] using SAR=1/1
[libx264rgb @ 0000000002c84820] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264rgb @ 0000000002c84820] profile High 4:4:4 Predictive, level 5.1, 4:4:4 8-bit
[libx264rgb @ 0000000002c84820] 264 - core 144 r2525 40bb568

ffplay is probably the best choice for watching the output of a 16frame video, because ffplay doesn't exit or anything at the end. It appears to be using the wrong colorspace on windows (black shows as dark gray), but that's different bug I guess.

Tested and reproduced on Ubuntu 14.04 (gcc 4.8.2) (on a Conroe E6600 CPU, dual core SSSE3), and with cross-compiled ffmpeg for Windows using https://github.com/rdp/ffmpeg-windows-build-helpers, and with zeranoe 32 and 64bit static builds (on a Sandybridge CPU, i5 quad core, SSE4.2 and AVX).

Note that the -pix_fmt rgb24 is needed with -f framemd5, because the png decoder outputs rgb24, but ffh264 outputs planar gbrp. Same data, different layout, different md5sum. Or use -pix_fmt gbrp to favor ffh264's default layout, but be consistent.

I also noticed that RGB h.264 output from ffmpeg is identified by ffmpeg -i as "gbrp(tv, gbr/unknown/unknown)". I haven't found a way to use -colorspace or -color_range jpeg to affect it. RGB output from the x264 cli shows up as gbrp(pc, ...), and mediainfo flags it as "full range". For a while I suspected the bug was that ffmpeg was telling x264 the input wasn't full range, when it actually was. But since I get perfect results with utvideo input, even though the files say tv range, that can't be it.

The AviSynth script I used for testing on Windows was just:
ImageSource("1080/sintel_trailer_2k_%04d.png", 1, 1253, 24)

I checked the framemd5 output for a complete encode of the Sintel trailer, and it's correct for ultrafast and veryslow, reading from utvideo. Different x264 settings have different md5s when reading from png, but surprisingly, the results are the same between my Linux dual core Conroe and my Windows quad core Sandybridge. (i.e. bit-identical corruption.) I also get identical results every time; this doesn't seem to depend on freak timing of threads.

Using utvideo as the input, the framemd5 matches for the full 1253 frames, not just the first 25.

Change History (7)

comment:1 by Elon Musk, 9 years ago

I tried with single png image and I do not see any artifacts.

comment:2 by Peter Cordes, 9 years ago

Neither do I, with just a single PNG as input. If I said "always corrupts", I meant when varying anything except the 16 frames of the Sintel trailer I was feeding it. I haven't tested other inputs, to see if maybe full-range RGB is the problem, or anything specific to the Sintel trailer is the problem.

I do still see corruption with only 2 frames of input.

mkdir -p "gtest-$HOSTNAME";
for opt in subme={0,3}; do
  sframe=13 fr=2 crf=0 pr=ultrafast;
  s="gtest-$HOSTNAME/ffmpeg.frame$sframe+$fr.from-png.$pr.$opt";
  FFREPORT=file="'$s.log'" ffmpeg -sws_flags +print_info  -framerate 24 -start_number $sframe -i 1080/sintel_trailer_2k_00%d.png -c:v libx264rgb -crf $crf -preset $pr -frames $fr -x264-params "$opt" "$s.mkv";
  ffmpeg -i "$s.mkv" -pix_fmt rgb24 -f framemd5 "${s/ffmpeg/framemd5.rgb24}"; done

md5sum gtest-tesla/framemd5.rgb24.* | sort
40dcf9e04347a6558866d3e126e5bb3a  gtest-tesla/framemd5.rgb24.frame13+2.from-png.ultrafast.subme=0
40dcf9e04347a6558866d3e126e5bb3a  gtest-tesla/framemd5.rgb24.threads1.frame13+2.from-png.ultrafast.subme=0
d813854b43e44ec7efaf5bb44d5b99e1  gtest-tesla/framemd5.rgb24.frame13+2.from-png.ultrafast.subme=3
d813854b43e44ec7efaf5bb44d5b99e1  gtest-tesla/framemd5.rgb24.threads1.frame13+2.from-png.ultrafast.subme=3

-threads 1 had no effect, not even combined with x264-params threads=1:$opts. (-threads doesn't get passed on to libx264, which still autodetects and uses multiple threads.)

The framemd5 of the corrupted frame (the 2nd one, which is also the first non-black frame), is the same as when running ffmpeg starting from frame #1. So whatever the problem is, it gets the same wrong answer with many or just one black frame before 0014.png (frame 13 of the video, counting from zero).

comment:3 by Michael Niedermayer, 9 years ago

Summary: lossless libx264rgb data corruption with image2 inputlossless libx264rgb data corruption

the same happens with rawvideo input, so its not a input issue also ive confirmed that the data passed into x264 does not contain these artifacts. It almost looks like a x264 issue but then i cant reproduce it with x264 command line

comment:4 by Michael Niedermayer, 9 years ago

Cc: Michael Niedermayer added

comment:5 by Carl Eugen Hoyos, 9 years ago

Keywords: libx264 added; libx264rgb x264 corruption lossless image2 removed

It seems to me that this commit did not fix the issue:
http://git.videolan.org/?p=x264.git;a=commitdiff;h=0fc5acc6
Workaround is to use -pix_fmt bgr24 (please confirm).

comment:6 by Carl Eugen Hoyos, 9 years ago

Afaict, another workaround is to use -vf format=bgr24,format=rgb24

comment:7 by Michael Niedermayer, 9 years ago

Resolution: invalid
Status: newclosed

Ive commited a workaround for this, seems a call to x264_encoder_reconfig() is related to this
but i dont see any evidence that this is a ffmpeg bug

Note: See TracTickets for help on using tickets.