Изменение цвета FFmpeg BMP в YUV x264

Когда я кодирую определенную последовательность файлов изображений BMP в AVC/H.264, цвета смещаются. Почему это происходит?

Но если я конвертирую BMP в PNG перед запуском ffmpeg, преобразование видео выглядит правильно. Мой исходный материал находится в формате BMP, и я бы предпочел не конвертировать все вручную в PNG, чтобы выполнить обходной путь.


Для этого вопроса я взял последовательность изображений и обобщил их по основным используемым цветам:

введите описание изображения здесь

Первая попытка кодирования (чистый белый становится заметно зеленым):ffmpeg -i 000.bmp -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4

введите описание изображения здесь

Вторая попытка (еще хуже):ffmpeg -i 000.bmp -vf "colormatrix=bt601:bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 second.mp4

введите описание изображения здесь

Третья попытка (слишком яркая):ffmpeg -i 000.bmp -vf "scale=in_range=full:in_color_matrix=bt709:out_range=full:out_color_matrix=bt709" -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 third.mp4

введите описание изображения здесь

Однако использование версии того же входного изображения в формате PNG прекрасно работает:ffmpeg -i 000.png -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 fourth.mp4

введите описание изображения здесь


Я использую последнюю сборку FFmpeg для Windows x86-64 (2016-11-22 Git d316b21):

C:\Temp> ffmpeg.exe -version
ffmpeg version N-82597-gd316b21 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 5.4.0 (GCC)
configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2
    --enable-libmfx --enable-nvenc --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-libopenh264
    --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger
    --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora
    --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis
    --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264
    --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma
    --enable-decklink --enable-zlib
libavutil      55. 40.100 / 55. 40.100
libavcodec     57. 66.106 / 57. 66.106
libavformat    57. 58.100 / 57. 58.100
libavdevice    57.  2.100 / 57.  2.100
libavfilter     6. 67.100 /  6. 67.100
libswscale      4.  3.101 /  4.  3.101
libswresample   2.  4.100 /  2.  4.100
libpostproc    54.  2.100 / 54.  2.100

Перефразируя мой вопрос, как я могу преобразовать последовательность изображений BMP в видео H.264 без нежелательных сдвигов цвета?

Я уверен, поэтому, пожалуйста, подтвердите, прежде чем я рассмотрю это как ответ. Попробуйте использовать «-vcodec libx264rgb» вместо «-vcodec libx264».
Учитывая, что заголовок вопроса касается сдвига цвета при кодировании в формат YUV, как кодирование в RGB решит проблему. Проблема здесь заключается в том, чтобы правильно и полностью указать атрибуты источника, чтобы swscale мог правильно преобразовать его. Также необходимо пометить выходной поток для ленивых/неаккуратных игроков.
К ОП. как вы преобразовали BMP в PNG? И как были созданы BMP?
@Mulvya Для моего MCVE в этом вопросе я создал BMP вручную в MS Paint. Я конвертировал в PNG с помощью IrfanView. Глядя на файлы в шестнадцатеричном редакторе, BMP не имеет цветового профиля или связанных метаданных. Похоже, что в PNG по умолчанию добавлены фрагменты gAMA и фрагменты sRGB.
@RawBean Интересное предложение. Используя -vcodec libx264rgb -profile:v high444(минус -pix_fmt), я получаю видео с идеальными цветами с нулевым отклонением. Однако в нее можно играть только в MPC-HC, а не в проводнике Windows или Mozilla Firefox. Я думаю, что было бы хорошо остаться в основном профиле H.264.
@RawBean После того, как я пробовал разные вещи в течение нескольких часов, libx264rgbисправил libx264проблему для меня. Большое спасибо!!

Ответы (1)

По-видимому, FFmpeg неправильно устанавливает атрибуты входного цвета для ввода BMP (вероятно, потому, что файл не содержит этих метаданных), а декодер BMP не проверяет атрибуты, помеченные вручную. Однако мы можем заставить его использовать фильтр формата.

ffmpeg -i 000.bmp -vf format=rgb24 -pix_fmt yuv420p -vcodec libx264 -profile:v main -crf 16 first.mp4
Это работает отлично! Это дает тот же результат, что и при использовании ввода PNG. Большое спасибо! Тем не менее, это какое-то сумасшествие, потому что файлы BMP могут быть только в формате RGB24 и никак иначе...
Согласно декодеру, BMP могут иметь пиксельный формат 8-битной палитры или 5-битный RGB или 6-битный G..и т.д. (также может иметь альфа-канал). Но да, цветовое пространство RGB. Декодер изначально был выпущен в 2005 году, и его работа заключается в заполнении структуры AVFrame, передаваемой фильтрам, с соответствующими атрибутами. Поскольку BMP не сильно изменился и мало используется, с тех пор никто не удосужился модифицировать код с добавлением новых флагов.