Tôi không phải là bậc thầy về ffmpeg, nhưng điều này sẽ tạo nên mánh khóe.
Trước hết, bạn có thể nhận được kích thước của video đầu vào như thế này:
ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width in.mp4
Với một ffmpeg hợp lý gần đây, bạn có thể thay đổi kích thước video của mình bằng các tùy chọn sau:
ffmpeg -i in.mp4 -vf scale=720:480 out.mp4
Bạn có thể đặt chiều rộng hoặc chiều cao thành -1
để cho phép ffmpeg
thay đổi kích thước video giữ tỷ lệ khung hình. Trên thực tế, -2
là một lựa chọn tốt hơn vì giá trị tính toán nên thậm chí. Vì vậy, bạn có thể gõ:
ffmpeg -i in.mp4 -vf scale=720:-2 out.mp4
Khi bạn nhận được video, nó có thể lớn hơn mong đợi 720x480
vì bạn để ffmpeg
tính chiều cao, vì vậy bạn sẽ phải cắt nó. Điều này có thể được thực hiện như thế này:
ffmpeg -i in.mp4 -filter:v "crop=in_w:480" out.mp4
Cuối cùng, bạn có thể viết một tập lệnh như thế này (có thể dễ dàng tối ưu hóa, nhưng tôi giữ nó đơn giản cho mức độ dễ đọc):
#!/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}