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 не зберігає початкову ширину та висоту. Тут нам потрібно вручну вказати або ширину, або висоту. робота, якщо і висота, і ширина нерівні. Поясніть, наскільки відповідь оптимальніша? .. дякую
varmashrivastava

1
@varmashrivastava Ну, так, як це працює, це те, що спочатку можливо було одне питання, а потім Google надсилає купу людей з іншим питанням, які потім викрадають сторінку. Це те, що є, постарайтеся не боротися з цим. Правильна відповідь на початкове запитання - -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"це навіть не одна з відповідей. Правильна відповідь на питання всіх інших - це LordNeckbeard.
Олександр Дубінський

@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
Це не помилка. Не має значення, що ви не виконуєте масштабування, оскільки вихід буде успадковувати розмір кадру вхідного сигналу.
логіан

5
Для запису я просто робив щось, де я створював відео із зображення, і воно використовувало yuvj444p як формат пікселів; це не хвилювало розмір відео. Тоді мені потрібно було перетворити його на yuv420p, і тоді він піклувався про розмір відео. Я подивився на yuv420p на wikipedia, я думаю, що це кольоровий формат у багато пікселів, для якого зображення має бути певного розміру. Не впевнений, чому це має значення стиснене.
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".
danneu

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.

Caveat

На жаль, ви не можете використовувати -2як ширину, так і висоту, але якщо ви вже вказали один вимір, то використання -2- це просте рішення.


14
Я думаю, що тихі повинні бути позначені як правильна відповідь через відсутність "хитрощів". Бажано брати участь у нагоді не один раз
ЛукаМ

1
Чому -vf scale=-2:-2не працює? У моєму випадку я хочу максимально зберегти початковий розмір файлу. Що для мене працювало -vf scale=-2:ih. Але це не працює, якщо обидва ч / б нерівномірні.
Паскаль

2
@tuner Отримане значення -2залежить від оголошеного значення іншого виміру.
логіан

3
в моєму випадку це дало мені таку помилку: Size values less than -1 are not acceptable.але відповідь від @Zbyszek спрацювала чудово.
Жульєн


64

Якщо ви хочете встановити якусь вихідну ширину і мати вихід у тому ж співвідношенні, що і вихідний

scale=720:-1 

і не впасти з цією проблемою, тоді можна використовувати

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

(Просто для людей, які шукають, як це зробити за допомогою масштабування)


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"

Це ідеально, тому що він завжди робить правильно, навіть коли не потрібні прокладки.


Рішення масштабу змінюють кількість пікселів не більше ніж на 1. Це навряд чи спотворює картину. Якщо ви переживаєте за швидкість фільтрації, використовуйте scale=iw+mod(iw,2):ih+mod(ih,2):flags=neighbor. Це може збільшити кожен вимір лише на 1, якщо потрібно, і буде дублювати останній рядок / стовпець.
Gyan

@Gyan Це було занадто довго , так як у мене була проблема , що це вирішується (моя відповідь була вирізаний з коментаря я зробив давно), але я пам'ятаю , що масштабування з допомогою одного пікселя було ввести помітні візуальні артефакти при певних умовах, тому я спромігся на першому місці. Я точно не пам’ятаю, можливо, непропорційна кількість розмиття від зміни однієї пікселі? Можливо, лише на деяких форматах vid / image? Все, що я можу сказати, це те, що я обробив тисячі VID за допомогою цього виправлення, і це було сприятливою трансформацією.
danneu

19

Ймовірно, це пов'язано з тим, що відео H264 зазвичай перетворюється з RGB в простір YUV як 4: 2: 0 перед застосуванням стиснення (хоча саме перетворення формату є алгоритмом стиснення втрат, що призводить до 50% економії місця).

YUV-420 починається з RGB (червоно-зеленого синього) зображення і перетворює його в YUV (в основному один канал інтенсивності та два канали "відтінку"). Канали Hue потім підпробовуються, створюючи один зразок відтінку для кожного 2X2 квадрата цього відтінку.

Якщо у вас є непарна кількість RGB-пікселів або по горизонталі, або по вертикалі, ви будете мати неповні дані для останнього стовпчика пікселя або рядка в підпробовому просторі відтінку кадру YUV.


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

2

LordNeckbeard має правильну відповідь, дуже швидко

-vf scale=1280:-2

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

"-preset ultrafast" and|or "-threads n"

Вам не потрібно оголошувати теми: це вирішується автоматично. Я вважаю, що повільність Андріода при кодуванні до H.264 пояснюється людьми, які використовують популярний "WritingMinds / ffmpeg-android", який використовує --disable-asmу своєму сценарії збірки x264 . Це призводить до непотрібності та значної повільності (ви можете перевірити журнал ffmpeg, і якщо він показує using cpu capabilties: none!, це погано). Я не впевнений, чому вони додали це, але я не розробник Android.
llogan

1

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

bitand (x, 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"

пояснення:

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

Хтось може вважати це корисним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.