Как я могу подогнать видео под определенный размер, но не увеличивать его с помощью FFmpeg?

13

Мне нужно подогнать видео до 640x360 (максимум, который может обрабатывать плеер моего телефона), при этом сохраняя соотношение сторон , но я также хочу, чтобы видео не изменялось, если оно меньше 640x360 (нет смысла увеличивать его в конце концов).

Есть ли способ получить это поведение с помощью командной строки ffmpeg?

sashoalm
источник
Я не думаю, что это может быть сделано исключительно в ffmpeg, но если вы хотите написать скрипт, это определенно можно сделать.
evilsoup
Я уже написал его, но я хотел очистить свой код, если он не нужен.
sashoalm
Вероятно, это возможно с масштабным фильтром, который использует такие функции, как, min(…)но, безусловно, проще с простым скриптом, который анализирует измерения. Смотрите мою команду здесь для примера того, что можно сделать: superuser.com/questions/547296/…
slhck

Ответы:

10

В новых версиях ffmpeg вы можете использовать опцию scaleфильтра force_original_aspect_ratio. Например, чтобы разместить видео в разрешении 1280 × 720 без увеличения (см. Этот пост для получения дополнительной информации):

ffmpeg -i input.mp4 -filter:v "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

Здесь scaleфильтр масштабируется до 1280 × 720, если входное видео больше этого. Если он меньше, он не будет увеличен. padФильтр необходим довести вывод видео до 1280 × 720, в случае , если его соотношение сторон или размера отличается от заданного размера.


В старых версиях ffmpeg есть несколько хакерских решений. Сначала определите ширину, высоту и соотношение сторон вашего вывода. Это спасет нас от набора текста.

width=640; height=360
aspect=$( bc <<< "scale=3; $width / $height") # <= floating point division

Теперь давайте применим супер сложную команду фильтра, которую написал Джим Уорралл :

ffmpeg -i input.mp4 -vf "scale = min(1\,gt(iw\,$width)+gt(ih\,$height)) * (gte(a\,$aspect)*$width + \
lt(a\,$aspect)*(($height*iw)/ih)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*iw : \
min(1\,gt(iw\,$width)+gt(ih\,$height)) * (lte(a\,$aspect)*$height + \
gt(a\,$aspect)*(($width*ih)/iw)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*ih" \
output.mp4

Я не буду подробно объяснять, что все это делает, но в основном вы можете кормить его любым видео, и оно будет только уменьшать, а не улучшать. Если вы готовы к этому, вы можете разделить фильтр на отдельные выражения. Можно было бы сократить это, но это также работает.

slhck
источник
1
+1, но это действительно ужасная команда: P
evilsoup
Я точно знаю? Я потратил десять минут, пытаясь разбить его на логические части, а затем вставив некоторые значения, но я сдался. Это немного старо, и, возможно, было бы возможно написать это намного более кратко чем это все же.
slhck
14

Более читаемая версия может выглядеть следующим образом:

-filter_complex "scale=iw*min(1\,min(640/iw\,360/ih)):-1"

640 / iw - коэффициент горизонтального масштабирования, а 360 / ih - коэффициент вертикального масштабирования.

Вы хотите поместить масштабированное изображение в поле вывода и сохранить соотношение сторон (хранилище). Вы делаете это, выбирая наименьший коэффициент масштабирования с минимальной функцией: min (640 / iw, 360 / ih)

Вы хотите предотвратить любое масштабирование (т.е. коэффициент масштабирования> 1,0), поэтому вы добавляете еще одну минимальную функцию: min (1, min (640 / iw, 360 / ih))

Следующим шагом является вычисление выходного разрешения путем умножения масштабного коэффициента на input-width и input-height:
output-width = iw * min (1, min (640 / iw, 360 / ih))
output-height = ih * min (1, min (640 / iw, 360 / ih))

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

immerzl
источник
А + работает из коробки. Решение выбранного ответа не сохранило соотношение сторон. Это сжало кадры.
287352
5

У меня тоже была такая же проблема, но она была решена путем подгонки видео в квадрат 640x640 (из-за вертикальных видео, сделанных на смартфонах).

Итак, используя логику immerzi и некоторые исследования, я получаю следующее:

-vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2"

последняя часть предназначена для высоты, делимой на 2, которая нужна многим кодировщикам.

Shebuka
источник