Как избежать мерцания краев объектов при кодировании записи экрана в mp4 с использованием x264 и ffmpeg?

Цель

Я создаю короткие уроки, записывая свой экран (720p30fps). Контент представляет собой просто запись использования некоторого программного обеспечения для настольных компьютеров - например, перемещение мыши и открытие диалогов, набор текста, рисование фигур и т. д. Никаких высокоскоростных действий, как в игре, никаких живых кадров, никакой говорящей головы или чего-то подобного. После базового редактирования исходной записи экрана я хочу закодировать видео в форматы webm и mp4 с точно таким же разрешением и частотой кадров, которые я записал, и я хочу, чтобы качество воспроизведения было как можно ближе к исходному качеству записи. Таким образом, после окончательного кодирования не должно быть видимых артефактов сжатия.

По поводу исходной записи: Разрешение 1280x720 пикселей. Частота кадров составляет 30 кадров в секунду. Программное обеспечение для записи — Simple Screen Recorder. Кодирование — H.264 с коэффициентом постоянной скорости 10 (достаточно близко к без потерь) в контейнере Matroska. При воспроизведении оригинала артефактов нет вообще.

Затем я добавляю несколько очень простых эффектов, таких как плавное затухание и наложение текста, к исходному MKV с помощью блендера. Затем визуализируйте в последовательность изображений (формат PNG). Я использую высококачественный экспорт изображений из Blender, и снова на выходных изображениях нет признаков артефактов сжатия.

Эта проблема

Проблема возникает после того, как я кодирую последовательность изображений в видео mp4, используя кодировщик x264 с ffmpeg. Иногда некоторые части некоторых жестких краев/очертаний формы мерцают. Это не движущиеся объекты. Они неподвижны на заднем плане по сравнению с тем, где движется мышь. Кажется случайным. Например, у меня могут быть два желтых прямоугольника рядом, каждый с черным контуром, и только верхняя часть одного из контуров прямоугольника мерцает в течение нескольких кадров, а затем останавливается. Это немного отвлекает и уродливо для того, что должно быть действительно чистым/простым кодированием, основанным на записи экрана.

Я обычно вижу это для горизонтальных темных линий / резких краев. Иногда я видел подобное для вертикальных краев.

Я еще не заметил этой проблемы с выходными файлами webm, созданными ffmpeg, только с файлами mp4, закодированными x264. Команда ffmpeg, которую я использую, выглядит так:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -pix_fmt yuv420p -movflags +faststart -crf 22 -r 30 -g 300 -y myvideo.mp4

Для webm я использую ту же базовую команду и то же значение crf, но, очевидно, другой кодировщик (libvpx-vp9). Файл webm составляет около 9+ МБ для 2 минут отснятого материала. Размер mp4 составляет около 3,5 МБ. Как правило, качество между ними невозможно различить, только в те моменты, когда в mp4 мерцают некоторые сегменты жесткой линии.

Я примерно проиллюстрировал проблему ниже, используя ASCII-графику, где я пытаюсь показать один прямоугольник на четырех кадрах. Сначала это нормально, затем для некоторых кадров часть контура прямоугольника рисуется с некоторой дополнительной толщиной в некоторых частях, заставляя его немного мерцать или покачиваться. Потом снова становится идеально.

-----------------
|               |
-----------------


------=====------
|               |
-----------------


______=====______
|               |
-----------------


-----------------
|               |
-----------------

Примеры

Сравните следующие изображения. Обратите внимание, что на втором изображении два нижних прямоугольника имеют дополнительную серую линию над или под частью их черной границы. Я захватил эти изображения, когда VLC воспроизводил мой mp4, закодированный x264, на 100% (без масштаба). Это не очень драматичный пример, но, надеюсь, этого достаточно, чтобы показать, что происходит. Поскольку лишние линии появляются и исчезают, создается эффект мерцания.

Ноты:

  1. Запись была сделана с помощью Simple Screen Recorder на экране с разрешением 1280x720 с максимальным использованием LibreOffice Draw. Вы не можете видеть артефакты ни в исходной записи, ни в последовательности изображений PNG, которую я экспортировал из Blender.
  2. Команда, которую я использовал для создания видео mp4, была:ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

снимок экрана, когда при воспроизведении mp4 в VLC не отображаются артефакты

снимок экрана, когда появляются артефакты при воспроизведении того же mp4 в VLC

(Легче заметить артефакты, если вы переключаетесь между двумя изображениями в исходном размере)

Вопросов

Как называется такой артефакт сжатия?

Какой флаг я могу передать ffmpeg, чтобы попытаться подавить его?

Что я пробовал до сих пор

Много экспериментов с CRF и значениями скорости. Для CRF я снизил до 18, и это, кажется, немного уменьшает мерцание, но не устраняет его. Но этот коэффициент скорости кажется слишком низким, чтобы получить приличное кодирование контента, такого простого, как запись экрана с низким уровнем активности в 720p.

Я также пробовал вручную устанавливать b-кадры и эталонные кадры на значения от 1 до 16, варьировал размер гопов от 30 до 300 и пробовал разные значения для параметра -me_method. И я попробовал пару настроек деинтерлейса с помощью опции yadif, но я совершенно уверен, что это не имеет отношения к этой проблеме, и кажется, что это только ухудшает качество выходного видео. В итоге команды ffmpeg выглядят примерно так:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -coder ac -pix_fmt yuv420p -movflags +faststart -crf 22 -bf 16 -b_strategy 2 -refs 16 -direct-pred spatial -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

Но до сих пор заметное влияние оказывало только изменение значения CRF. Я не хочу опускаться намного ниже, потому что это слишком сильно увеличит размер видео.

Обновление: результаты испытаний

Я использовал приведенный выше пример с LibreOffice Draw и экраном 1280x720p для записи клипа продолжительностью около 47 секунд в файл MKV, закодированный H.264. Я импортировал это в Blender и сразу же экспортировал обратно в виде последовательности изображений PNG — без каких-либо эффектов или правок. Затем я пропустил последовательность изображений через ffmpeg с кодировщиком x264, чтобы создать видеофайл mp4.

Я начал изменять исходную команду ffmpeg по одному параметру за раз, чтобы увидеть разницу. В основном я сосредоточился на значении CRF, потому что это был единственный способ увидеть уменьшение артефактов сжатия. Даже с CRF, установленным на 10, я все еще мог видеть странное мерцание/полосатость по краям в нескольких местах. В конце концов я снизил значение до 5 и вообще не заметил никаких артефактов. Идеальное значение, возможно, где-то между 5 и 10 для этого контента.

Это оставило меня с видео, которое слишком велико для того, чем оно является. Повозившись со значениями B-кадра и эталонного кадра, чтобы добиться незначительного уменьшения размера файла, я, наконец, вернулся к изменению значения gop, и это оказало относительно большое влияние. Установка gop на 300 вместо 30 практически вдвое уменьшила размер файла. Итак, моя последняя команда ffmpeg была такой:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4

(Обновление: я изначально опубликовал указанную выше команду как -crf 10... теперь исправлен на -crf 5)

Основные параметры, которые я отбросил, были:

  • -pix_fmt yuv420p(это может ухудшить качество)
  • -coder ac(Я не видел никакого положительного эффекта с этим или без него)
  • -b_strategy 2(это на самом деле немного увеличило размер файла в некоторых случаях)
  • -direct-pred spatial(абсолютно не влияет на качество/размер выходного файла, который я мог наблюдать)

Если бы я доставлял выходной файл на YouTube, я бы подумал о том, чтобы вернуть -pix_fmt yuv420pи -coder acи -flags cgopтолько потому, что они рекомендуют их.

Эти параметры привели к незначительному улучшению/уменьшению размера файла (в долях 1 МБ):

  • -bf 16
  • -refs 16
  • -me_method umh -me_range 16

Вы можете увидеть изменение размера файла на экране ниже, где я назвал каждый выходной файл в соответствии с параметрами ffmpeg, которые я изменил. Все, что не содержит crf05 в имени, свидетельствует о проблеме артефактов.

Выходные файлы, созданные с использованием различных параметров ffmpeg и x264.

Для сравнения, я выполнил аналогичную команду для создания файла webm, но с гораздо худшим/более высоким значением CRF. При значении CRF 22 результирующий файл mp4 имел размер 1,4 МБ без каких-либо заметных артефактов сжатия. Я использовал команду ffmpeg:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libvpx-vp9 -b:v 0 -tile-columns 2 -crf 22 -r 30 -g 300 -y myvideo.webm

Обновление: больше результатов испытаний

Следуя предложениям stib и Mulvya, я попробовал параметры и -tuneи изменил значение от 5 до 10. Я сделал то же самое для своих собственных экспериментов с параметрами и . Выходной mp4, основанный на моем входном mkv-видео, имел видимые мерцающие артефакты сжатия в одном и том же месте, пока я не уменьшил crf до 6 при использовании и до 5 с параметрами или при использовании-trelliscrf-me_method-bf-trellis-bf -refs-tune. Вот снимки экрана, показывающие последние артефакты, которые я пытаюсь устранить, используя более высокие значения crf. Первый экран — входное mkv-видео, второй — образец закодированного видео в формате mp4, созданный с использованием параметра -trellis 0. Артефакты видны на верхней границе одного из прямоугольников. (На черном фоне также есть толстая серая полоса — это не артефакт сжатия, я думаю, что это диалог в процессе исчезновения после нажатия кнопки «Отмена» в моей записи демо / семпла.)

часть кадра в оригинальном mkv видо без артефактов сжатия

почти та же часть закодированного видео в формате mp4 с артефактами сжатия

Вот команды и результирующие размеры файлов

-настроить анимацию:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -tune animation -r 30 -g 300 -y myvideo.mp4
Размер: 2 757 370
Видимые артефакты: Нет

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -tune animation -r 30 -g 300 -y myvideo.mp4
Размер: 2 593 711
Видимые артефакты: Да

-решетка 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Размер: 2 214 534 байт
Видимые артефакты: Нет

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts trellis=0 -r 30 -g 300 -y myvideo.mp4
Размер: 2 074 544 байта.
Видимые артефакты: есть (правда, мизерное количество — буквально несколько пикселей за доли секунды)

-fast_skip 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Размер: 2 012 596 байт
Видимые артефакты: Нет

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Размер: 1 883 919 байт
Видимые артефакты: Да (очень маленький/небольшой объем)

-psy 0 -fast_pskip 0:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 7 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Размер: 1 886 919 байт
Видимые артефакты: Нет

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 8 -pix_fmt yuv420p -x264opts psy=0:fast_pskip=0 -r 30 -g 300 -y myvideo.mp4
Размер: 1 764 771 байт
Видимые артефакты: Да

-bf -ссылки:

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Размер: 2 257 420 байт
Видимые артефакты: Нет

ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 6 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4
Размер: 2 106 439 байт
Видимые артефакты: Да (хотя и мизерное количество)

-deblock:
ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4
Размер: 982 549 байт
Видимые артефакты: Нет

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -bf 16 -refs 16 -me_method umh -me_range 64 -r 30 -g 300 -y myvideo.mp4
Размер: 961 460 байт
Видимые артефакты: Нет

Заключение

Либо кодировщик vp9 намного лучше справляется с таким видеоконтентом, либо есть какой-то параметр x264, о котором я не знаю, который улучшит ситуацию. Есть ли у кого-нибудь идеи по поводу варианта, который я могу дать ffmpeg, чтобы получить лучший результат с x264/mp4? (И я не пытаюсь развязать какую-то войну кодеков — мне нужно публиковаться в обоих форматах!)

Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат .

Ответы (2)

Параметр, который, по-видимому, оказывает наибольшее влияние на удаление этого артефакта (для типа контента в исходном сообщении), допуская при этом более высокие значения CRF, — это deblock. Использование -deblock -3,-3допустимого значения CRF 14 с полным устранением артефактов. Использование значений CRF 15 и 16 повторно вводит артефакт, хотя и в крошечных количествах и не очень заметно, если только вы не ищете его специально. Также значения деблокировки -3-1 и -3-0 работали достаточно хорошо, но не устраняли артефакт полностью на CRF 14.

Последняя команда была:

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 14 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0:deblock=-3,-3 -r 30 -g 300 -y myvideo.mp4

Чтобы выжать еще несколько килобайт сжатия, вы можете прочитать параметры bf refs me_method umhи me_range. Но я обнаружил, что мне нужен me_rangeнабор на 64. Меньшие значения снова вызовут артефакт сжатия.

Примечание. У меня был некоторый успех с изменением aq-modeи aq-strength, но это было не так хорошо, как деблокировка для удаления артефактов.

Добавил результаты использования этого подхода в исходный пост, для сравнения с другими методами.
Спасибо за работу над этим. Я думаю, что проблема в том, что кодировщик не может решить, что делать с черным, и из-за случайности в соответствии с необходимостью кодировщика он оказывается случайным в этой области. Я думаю, что может быть полезно очистить OP сейчас, чтобы другим не пришлось пробираться через него, это может помочь получить некоторый ответ. Я был там. Чтобы задать хороший вопрос, требуется много сдержанности. не легко с чем-то таким сложным. Может быть, даже объединить ответы, если они связаны? просто мысль.

Изменяйте значение CRF до тех пор, пока вы не увидите артефакты сжатия. При необходимости сделайте смехотворно низким, например, CRF = 5.

Увеличьте значение GOP, чтобы компенсировать больший размер выходного файла. Например, для видео с частотой 30 кадров в секунду попробуйте gop=300.

Ваша команда ffmpeg может выглядеть так:ffmpeg -speed 1 -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -crf 5 -bf 16 -refs 16 -r 30 -g 300 -me_method umh -me_range 16 -y myvideo.mp4

Редактировать: (используя правильный параметр скорости для x264, добавляя pix_fmt и другие параметры x264)

ffmpeg -framerate 30 -f image2 -i frames/%04d.png -c:v libx264 -movflags +faststart -preset veryslow -crf 5 -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0 -bf 16 -refs 16 -me_method umh -me_range 16 -r 30 -g 300 -y myvideo.mp4

Я в основном отказываюсь от решения этой проблемы любым разумным способом. Это плохо информированный и, вероятно, плохой ответ на мой собственный вопрос. Надеюсь, кто-то более знающий может ответить с более разумными параметрами ffmpeg/x264 для такого рода контента, а не просто изменять значение CRF до чего-то экстремального.
Я уже несколько месяцев использую подход, похожий на мой, и он работает хорошо. Обычно мне не нужно значение CRF ниже 5... но 7 обычно является разумной отправной точкой. Также в более поздних версиях ffmpeg мне пришлось перейти с -speed 1 на -preset veryslow. (Кажется, -speed на самом деле для libvpx, а не libx264). Также я использую эти опции сейчас: -pix_fmt yuv420p -x264opts fast_pskip=0:psy=0Ответ обновлен соответствующим образом.