Преобразование видео в фиксированный размер экрана путем обрезки и изменения размера


22

Я пытался понять это сам, но множество вариантов просто сбивает меня с толку.

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

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

Последнее, что мне нужно, это 720x480 в XVid AVI с аудиодорожкой MP3.

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

Может кто-нибудь сказать мне командную строку для запуска - или, по крайней мере, получить мне / большую часть пути туда? Если это должно быть несколько командных строк (запустите X, чтобы получить разрешение, выполните этот расчет, а затем запустите Y с выводом этого вычисления), я могу написать это.


Очевидно, видеоустройство работает как с Mpeg4, так и с XVid AVI, если это проще / лучше.
Энди Джеффрис

Ответы:


19

Я не гуру ffmpeg, но это должно сработать.

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

ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width in.mp4

С относительно свежим ffmpeg вы можете изменить размер вашего видео с помощью следующих опций:

ffmpeg -i in.mp4 -vf scale=720:480 out.mp4

Вы можете установить ширину или высоту -1, чтобы разрешить ffmpegизменение размера видео с сохранением соотношения сторон. На самом деле, -2это лучший выбор, так как вычисленное значение должно быть четным. Таким образом, вы можете напечатать:

ffmpeg -i in.mp4 -vf scale=720:-2 out.mp4

Как только вы получите видео, оно может оказаться больше ожидаемого, 720x480поскольку вы позволяете ffmpegвычислить высоту, поэтому вам придется его обрезать. Это можно сделать так:

ffmpeg -i in.mp4 -filter:v "crop=in_w:480" out.mp4

Наконец, вы можете написать такой скрипт (его легко оптимизировать, но я сделал его простым для разборчивости):

#!/bin/bash

FILE="/tmp/test.mp4"
TMP="/tmp/tmp.mp4"
OUT="/tmp/out.mp4"

OUT_WIDTH=720
OUT_HEIGHT=480

# Get the size of input video:
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${FILE})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Get the difference between actual and desired size
W_DIFF=$[ ${OUT_WIDTH} - ${IN_WIDTH} ]
H_DIFF=$[ ${OUT_HEIGHT} - ${IN_HEIGHT} ]

# Let's take the shorter side, so the video will be at least as big
# as the desired size:
CROP_SIDE="n"
if [ ${W_DIFF} -lt ${H_DIFF} ] ; then
  SCALE="-2:${OUT_HEIGHT}"
  CROP_SIDE="w"
else
  SCALE="${OUT_WIDTH}:-2"
  CROP_SIDE="h"
fi

# Then perform a first resizing
ffmpeg -i ${FILE} -vf scale=${SCALE} ${TMP}

# Now get the temporary video size
eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width ${TMP})
IN_WIDTH=${streams_stream_0_width}
IN_HEIGHT=${streams_stream_0_height}

# Calculate how much we should crop
if [ "z${CROP_SIDE}" = "zh" ] ; then
  DIFF=$[ ${IN_HEIGHT} - ${OUT_HEIGHT} ]
  CROP="in_w:in_h-${DIFF}"
elif [ "z${CROP_SIDE}" = "zw" ] ; then
  DIFF=$[ ${IN_WIDTH} - ${OUT_WIDTH} ]
  CROP="in_w-${DIFF}:in_h"
fi

# Then crop...
ffmpeg -i ${TMP} -filter:v "crop=${CROP}" ${OUT}

У меня было такое странное ощущение, что он пропустит сценарий, но я пробовал его с множеством видеофайлов, и, похоже, он правильно обрезает и изменяет размер видео до абсолютно правильного размера - отлично!
Энди Джеффрис

Похоже, что с решением CROP_SIDE что-то не так.
Сутра

`# Получите коэффициент между фактическим и желаемым размером w_rate = echo "scale=3; ${in_width}/${out_width}*1000"| bc | awk '{printf "%d", $0}' h_rate = echo "scale=3; ${in_height}/${out_height}*1000"| bc | awk '{printf "%d", $0}' # Давайте возьмем более короткую сторону, чтобы видео было по меньшей мере таким же большим, # как желаемый размер, и обрежем более длинную сторону: crop_side = 'n' if [$ {w_rate} -gt $ {h_rate}]; then scale = "- 2: $ {out_height}" crop_side = 'w' else scale = "$ {out_width}: - 2" crop_side = 'h' fi `
Сутра

23
ffmpeg -i input.file -vf "scale=(iw*sar)*max(720/(iw*sar)\,480/ih):ih*max(720/(iw*sar)\,480/ih), crop=720:480" -c:v mpeg4 -vtag XVID -q:v 4 -c:a libmp3lame -q:a 4 output.avi

Замените «input.file» на имя вашего входного файла.


Это должен быть главный ответ, так как он не требует вызова ffprobe. Обратите внимание на запятую в команде. Вам нужно будет избежать обратной косой черты, если вы помещаете команду в строку C / JavaScript / PHP.
Cleong

Здорово, Брайан. Часть с видеофильтром - это то, что мне тоже нужно. (т.е. конвертировать старые 4: 3 видео в 16: 9)!
Дейв

1
гений! все сделано в одном.
Соли

2
Намного чище, чем сценарий выше. Обратите внимание, если вы не хотите XVID / MP3, вы можете просто изменить теги после второй кавычки на что-то вроде-c:a copy scaled_result.mp4
Ник

7

Если вы хотите обрезать и масштабировать за один раз, вы можете создать цепочку фильтров обрезки и масштабирования следующим образом:

ffmpeg -i SomeInput.mp4 -vf "crop=in_h*9/16:in_h,scale=-2:400" -t 4 SomeOutput.mp4

Приведенное выше сначала обрезает видео до портрета 16: 9, затем масштабируется до 400 пикселей в высоту x соответствующую (четное число) ширину.


1

Я новичок в ffmpeg, но теперь у меня есть небольшой конвертер в VB.NET, который создает необработанные фильмы различных форматов вывода для использования на небольших устройствах, которые имеют доступ к SD-карте, но не имеют достаточной мощности для декодирования сложного видео.

Из-за того, как он работает при изменении размера и обрезки, мне пришлось кодировать его вручную и создавать параметры. В основном мне нужно знать результирующие ширину и высоту.

У меня есть 2 флажка для вариантов: -

Сохранить соотношение сторон (X) Заполните все пиксели (X)

В качестве входных данных необходимы только 4 переменные (1) Ширина исходного видео, (2) Высота исходного видео, (3) Ширина устройства, (4) Высота устройства.

Хотя для VB.NET достаточно легко адаптироваться под любой язык.

    Dim crop As String = "" ' will build this in ffmpeg format for -s or scale and crop

    If cbAspectRatio.Checked = False Then
        m_dest_output_w = sz._w
        m_dest_output_h = sz._h

        ' scale to w * h - simple
        crop = " -s " & m_dest_output_w & ":" & m_dest_output_h
    Else
        Dim ratio As Double = CDbl(m_video_width) / CDbl(m_video_height) ' this is aspect ratio of original unsized video

        If cbFillPixels.Checked = False Then ' shrink to fit
            If sz._w * ratio <= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w / ratio
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h / ratio
            End If

            ' no cropping just resizing to a non-filled area that fits

            crop = " -s " & m_dest_output_w & ":" & m_dest_output_h ' no cropping needed as letterboxed

        Else ' expand / fill --- cropping needed
            If sz._w * ratio >= m_video_height Then
                m_dest_output_w = sz._w
                m_dest_output_h = sz._w * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":0:" & Math.Abs((m_dest_output_h - sz._h)) \ 2
            Else
                m_dest_output_h = sz._h
                m_dest_output_w = sz._h * ratio

                crop = ",crop=" & sz._w & ":" & sz._h & ":" & Math.Abs((m_dest_output_w - sz._w)) \ 2 & ":0"
            End If

            crop = " -vf scale=" & m_dest_output_w & ":" & m_dest_output_h & crop

            m_dest_output_w = sz._w
            m_dest_output_h = sz._h
        End If
    End If
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.