通过裁剪和调整大小将视频转换为固定的屏幕尺寸


22

我试图自己解决这个问题,但是无数的选择让我感到困惑。

我想理想地使用ffmpegmencoder(或其他,但我知道我正在使用的那两个)将任何传入的视频转换为固定的屏幕尺寸。

如果视频太宽或太短,请对视频进行中心裁剪。如果大小不正确,请调整大小以使其恰好是固定的屏幕大小。

我需要的最后一件事是XVid AVI中的720x480,带有MP3音轨。

我找到了很多页面,这些页面显示了如何调整为最大分辨率,但是我需要视频精确地达到该分辨率(裁剪掉多余的部分,没有黑条)。

谁能告诉我要运行的命令行-或至少让我了解其中的大部分/大部分方式?如果需要多个命令行(运行X以获取分辨率,请执行此计算,然后使用该计算的输出运行Y),我可以编写脚本。


显然,视频设备可以与Mpeg4以及XVid AVI一起使用,如果更容易/更好。
安迪·杰弗里斯

Answers:


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决策有误。
Sutra

`#获取实际尺寸和所需尺寸之间的比率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}]; 然后规模= “ - 2:$ {out_height}” crop_side = 'W'否则规模= “$ {out_width}: - 2” crop_side = 'H'科幻`

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
Nick

7

如果您想一次性裁剪和缩放,则可以制作一个裁剪然后缩放的过滤链,如下所示:

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

上面的代码首先将视频裁剪为16:9的人像,然后缩放为400px高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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.