Перетворіть відео у фіксований розмір екрана, обрізаючи та змінюючи розмір


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', якщо [$ {w_rate} -gt $ {h_rate}]; тоді масштаб = "- 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-карти, але не мають достатньої потужності для декодування складного відео.

Через те, як він працює при зміні розміру та обрізанні, мені довелося кодувати його вручну та створювати параметри. В основному мені потрібно знати отриману ширину і висоту.

У мене є два прапорці для варіантів: -

Зберегти співвідношення аспектів (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.