I'm testing out converting some videos to HEVC encoding utilizing ffmpeg and libx265 and I've discovered that the the input width must be divisible by 8 in order to successfully re-encode. I would like to determine whether a re-encode will be successful without attempting the encode and then examining the output. Ideally I'd like to do this in a bash script. My skills are somewhat limited in this regard and much of what I have come up with thus far is far less than elegant.
For example I know that I can do the math with bc as in:
echo 'scale=2;576/8' | bc
72.00
and I can obtain the width via
width=$(mediainfo $filename | grep "Width" | sed 's/[^0-9]*//g')
but the former doesn't exactly answer the question is the width divisible by 8 and the latter is ugly and uses too many pipes which research indicates is less then efficient.
I've got the ffmpeg command line for re-encoding sorted to my satisfaction using:
ffmpeg -i "$f" -c:a copy -c:v libx265 -preset "$preset" -crf 25 "$target"
and I intend to scale the video to a width divisible by 8 if it isn't already but I'm looking for better solutions than I've come up with thus far for determining if scaling is required and how to determine the closest width divisible by 8 to scale to.
The following will correct the width to a number divisible by 8 and then correctly rescale the height to a number divisible by 8 while maintaining correct aspect ratio:
As a bonus if the width is already divisible by 8 there will be no change in the output width and no error from FFmpeg.
An explanation for the scale syntax, remembering that the syntax is
-vf scale=width:height
:1. Output Width Calculation:
iw/8
: The width of the input video stream will be divided by 8. So an original width of 690 would create a number 86.25trunc
: The number 86.25 would be 'truncated' to 86*8
: 86 would be multiplied by 8 to give a final width of 688 which of course is divisible by 8!2. Output Height Calculation:
-8
: FFmpeg will calculate a height that is divisible by 8 but which also maintains the correct aspect ratio of the original fileIn a perfect world hevc encoding is run with encoding units of 8x8, 16x16, 32x32 etc and this syntax guarantees this. More details of this here...
References:
Obtaining the width is relatively simple with
mediainfo
. If you don't have it you can install it withsudo apt-get install mediainfo
width=$(mediainfo '--Inform=Video;%Width%' $filename)
Determining divisibility by 8 can be done via
A far simpler and faster approach inspired by @andrew.46 and a bit more research and testing is to let ffmpeg do the work with
ffmpeg -i $inputfilename -c:a copy -c:v libx265 -preset veryfast -x265-params crf=25 -vf scale=-8:ih $outputfilename
the
-vf scale=-8:ih
setting insures that the width is divisible by 8 (-8) and uses the input height (ih) accordingly to maintain aspect ratio.Sources:
man mediainfo
https://stackoverflow.com/questions/7376477/geting-video-information-from-mediainfo
https://superuser.com/questions/49765/how-to-make-a-statement-that-checks-if-something-is-divisible-by-something-else
How can I determine if a video can be encoded successfully with HEVC (x265) encoding
http://ffmpeg.org/ffmpeg-filters.html#scale