Convert a video to a fixed screen size by cropping and resizing
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
Replace "input.file" with the name of your input file.
I'm no ffmpeg guru, but this should do the trick.
First of all, you can get the size of input video like this:
ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width in.mp4
With a reasonably recent ffmpeg, you can resize your video with these options:
ffmpeg -i in.mp4 -vf scale=720:480 out.mp4
You can set the width or height to -1
in order to let ffmpeg
resize the video keeping the aspect ratio. Actually, -2
is a better choice since the computed value should even. So you could type:
ffmpeg -i in.mp4 -vf scale=720:-2 out.mp4
Once you get the video, it may be bigger than the expected 720x480
since you let ffmpeg
compute the height, so you'll have to crop it. This can be done like this:
ffmpeg -i in.mp4 -filter:v "crop=in_w:480" out.mp4
Finally, you could write a script like this (can easily be optimized, but I kept it simple for legibility):
#!/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}
If you want to crop and scale in one go, you can make a crop-then-scale filterchain like so:
ffmpeg -i SomeInput.mp4 -vf "crop=in_h*9/16:in_h,scale=-2:400" -t 4 SomeOutput.mp4
The above first crops a video to 16:9 portrait, then scales to 400px high x the appropriate (even number) width.