FFMPEG (libx264) «высота не делится на 2»

188

Я пытаюсь кодировать .mp4 видео из набора кадров, используя FFMPEG с использованием кодека libx264.

Это команда, которую я запускаю:

/usr/local/bin/ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4

Иногда я получаю следующую ошибку:

[libx264 @ 0xa3b85a0] height not divisible by 2 (520x369)

После небольшого поиска кажется, что проблема связана с алгоритмом масштабирования и может быть исправлена ​​добавлением аргумента -vf.

Однако в моем случае я не хочу делать масштабирование. В идеале я хочу сохранить размеры точно такими же, как у рам. Любой совет? Есть ли какое-то соотношение сторон, которое обеспечивает h264?

Энди Хин
источник
@AleksandrDubinsky Но ответ LordNeckbeard не сохраняет исходную ширину и высоту. Здесь нам нужно вручную указать ширину или высоту ... и если мы используем -vf scale = -2: ih или -vf scale = iw: -2, это не будет работать, если высота и ширина неравны .. Пожалуйста, объясните, как этот ответ является более оптимальным? .. спасибо
вармашривастава
1
@varmashrivastava Что ж, SO работает так, что, возможно, изначально был один вопрос, а затем Google отправляет кучу людей с другим вопросом, которые затем захватывают страницу. Это то, что есть, старайтесь не бороться с этим. Правильный ответ на оригинальный вопрос - -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"это даже не один из ответов. Правильный ответ на все остальные вопросы - лорд Нэкборд.
Александр Дубинский
@varmashrivastava Я пошел вперед и исправил первый ответ. Надеюсь, модов это не испортит.
Александр Дубинский
@AleksandrDubinsky спасибо .. и пользователь может использовать "scale="вместо"pad=" если он / она не хочет иметь цветные пиксели заполнения?
Вармашривастава

Ответы:

269

Ответ на оригинальный вопрос, который не хочет масштабировать видео:

-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Команда:

ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

По сути, .h264 нужны четные размеры, поэтому этот фильтр будет:

  1. Разделите оригинальную высоту и ширину на 2
  2. Округлите его до ближайшего пикселя
  3. Умножьте это на 2 снова, таким образом делая это четное число
  4. Добавить черные отступы до этого числа

Вы можете изменить цвет заполнения, добавив параметр фильтра :color=white. Смотрите документацию колодки .

Энди Хин
источник
3
Это не ошибка. Неважно, что вы не выполняете масштабирование, поскольку выходные данные будут наследовать размер кадра входных данных.
Llogan
5
Для записи, я просто делал что-то, где я создал видео из изображения, и он использовал yuvj444p в качестве формата пикселей; это не заботилось о размере видео. Затем мне нужно было преобразовать его в yuv420p, а затем он позаботился о размере видео. Я посмотрел yuv420p в Википедии, я думаю, что это многопиксельный цветовой формат, для которого нужно, чтобы изображение было определенного размера. Не уверен, почему это так важно.
lahwran
7
Возможно, вам лучше использовать блокнот, а не масштаб, чтобы добавить черную строку / столбец. Масштабирование изображения на один пиксель приведет к его размытию.
Гленн Мейнард
5
@NickeManarin, этот фильтр должен работать , чтобы добавить 1 пиксель белого дополнения к вертикальному размеру, с видео , расположенное вверху слева: -vf pad="width=iw:height=ih+1:x=0:y=0:color=white". Документация панели ffmpeg находится здесь: ffmpeg.org/ffmpeg-filters.html#pad-1 .
Марк Берри
4
Вот решение , которое только добавляет пиксель дополнения к размерам, четные: -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2".
17
250

Просто используйте -2

Из документации фильтра весов :

Если одно из значений -n с n > 1, масштабом фильтр также будет использовать значение , которое поддерживает соотношение сторон входного изображения, вычисленное с другим указанного размером. После этого он, однако, удостоверится, что рассчитанный размер делится на, nи при необходимости скорректирует значение.

Примеры

Установите ширину в 1280, и высота будет автоматически рассчитана для сохранения соотношения сторон, а высота будет делиться на 2:

-vf scale=1280:-2

То же, что и выше, но с объявленной высотой; оставляя ширину, которая будет обработана фильтром:

-vf scale=-2:720

"делится на 2"

В соответствии с требованиями x264, «делимые на 2 для ширины и высоты» необходимы для выходов с субдискретизацией цветности YUV 4: 2: 0. 4: 2: 2 потребуется «делится на 2 по ширине», а 4: 4: 4 не имеет этих ограничений. Однако большинство игроков, не основанных на FFmpeg, могут правильно декодировать только 4: 2: 0, поэтому вы часто видитеffmpeg команды с -pix_fmt yuv420pопцией при выводе видео H.264.

Предостережение

К сожалению, вы не можете использовать -2как ширину, так и высоту, но если вы уже указали одно измерение, то использовать -2это простое решение.

llogan
источник
14
Я думаю, что tihis должен быть помечен как правильный ответ, потому что никаких «уловок» не было. Желаете поднять голос более одного раза
LucaM
1
Почему -vf scale=-2:-2не работает? В моем случае я хочу максимально сохранить исходный размер файла. То, что сработало для меня, было -vf scale=-2:ih. Но это не работает, если оба ч / б неравномерны.
Паскаль
2
@tuner Результирующее значение -2зависит от объявленного значения другого измерения.
Llogan
3
в моем случае это дало мне следующую ошибку: Size values less than -1 are not acceptable.но ответ от @Zbyszek работал отлично.
Жюльен
64

Если вы хотите установить некоторую ширину вывода и иметь вывод с тем же соотношением, что и оригинал

scale=720:-1 

и не упасть с этой проблемой, то вы можете использовать

scale="720:trunc(ow/a/2)*2"

(Только для людей, ищущих, как сделать это с масштабированием)

Zbyszek
источник
16
И для фиксированной высоты этоscale="trunc(oh*a/2)*2:720"
Том
20

Проблема с scale решениями здесь заключается в том, что они искажают исходное изображение / видео, что почти никогда не соответствует желаемому.

Вместо этого я обнаружил, что лучшим решением является добавление 1-пиксельной панели к нечетному размеру. (По умолчанию накладка черного цвета, и ее трудно заметить.)

Проблема с другим pad решениями заключается в том, что они не обобщаются на произвольные измерения, потому что они всегда дополняют друг .

Это решение добавляет 1-пиксельный планшет к высоте и / или ширине, если они нечетные:

-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"

Это идеально, потому что он всегда делает правильные вещи, даже если нет необходимости в заполнении.

danneu
источник
Масштабные решения изменяют количество пикселей максимум на 1. Это вряд ли искажает картину. Если вы беспокоитесь о скорости фильтрации, используйте scale=iw+mod(iw,2):ih+mod(ih,2):flags=neighbor. Это может только увеличить каждое измерение на 1, если это необходимо, и будет дублировать последнюю строку / столбец.
Gyan
@Gyan Это было слишком долго , так как у меня была проблема , что это решается (мой ответ был вырезан из комментария я сделал давно), но я помню , что масштабирование с помощью одного пикселя было ввести заметные визуальные артефакты при определенных условиях, поэтому я удосужился в первую очередь. Я точно не помню, может быть, непропорциональное количество размытия от одного пиксельного изменения? Может быть, только на некоторых форматах VID / изображений? Все, что я могу сказать, - это то, что я обработал тысячи видео с этим исправлением, и это было благоприятное преобразование.
Даннеу
19

Вероятно, это связано с тем фактом, что видео H264 обычно преобразуется из пространства RGB в пространство YUV как 4: 2: 0 до применения сжатия (хотя само преобразование формата является алгоритмом сжатия с потерями, что приводит к экономии пространства на 50%).

YUV-420 начинается с изображения RGB (красный, зеленый, синий) и преобразует его в YUV (в основном один канал интенсивности и два канала «оттенка»). Затем каналы оттенков подвергаются дополнительной выборке путем создания одного образца оттенка на каждые 2X2 квадрата этого оттенка.

Если у вас есть нечетное количество пикселей RGB по горизонтали или вертикали, у вас будут неполные данные для последнего столбца или строки пикселей в пространстве оттенков субдискретизации кадра YUV.

Adisak
источник
2
Еще один интересный факт ... когда вы декодируете с помощью Microsoft Media Foundation, вам нужно использовать кратные 16 для H264. Таким образом, видео 1080P фактически декодируется в буфер с высотой 1088 (хотя вы игнорируете последние 8 строк).
Адисак
2

У лорда Некберда правильный ответ, очень быстрый

-vf scale=1280:-2

Для Android, не забудьте добавить

"-preset ultrafast" and|or "-threads n"
fallouter
источник
Вам не нужно объявлять темы: это решается автоматически. Я полагаю, что медлительность Andriod при кодировании в H.264 вызвана людьми, использующими популярный «WritingMinds / ffmpeg-android», который использует --disable-asmв своем сценарии сборки x264 . Это приводит к ненужной и значительной медлительности (вы можете проверить журнал ffmpeg, и если он показывает using cpu capabilties: none!, это плохо). Я не уверен, почему они добавили это, но я не разработчик Android.
Llogan
1

Вы также можете использовать bitandфункцию вместоtrunc :

бит и (х, 65534)

будет делать так же как trunc(x/2)*2и более прозрачно на мой взгляд.
(Рассмотрим 65534 магическое число здесь;))


Моя задача состояла в том, чтобы автоматически масштабировать множество видеофайлов до половины разрешения .

scale=-2,ih/2привести к слегка размытым изображениям

причина:

  • входные видео имели их формата изображения (DAR) набор
  • scale масштабирует реальные размеры кадра
  • во время предварительного просмотра размеры нового видео должны быть скорректированы с использованием DAR, что в случае видео с довольно низким разрешением (360x288, DAR 16: 9) может привести к размытию

решение:

-vf "scale='bitand(oh*dar, 65534)':'bitand(ih/2, 65534)', setsar=1"

объяснение:

  • output_height = input_height / 2
  • output_width = output_height * original_display_aspect_ratio
  • как output_width и output_height теперь округлены до ближайшего меньшего числа делится на 2
  • setsar=1означает, что output_dimensions теперь являются окончательными, коррекция соотношения сторон не должна применяться

Кто-то может найти это полезным.

endigo
источник