Originally published August 1, 2019 @ 9:25 pm

While ffmpeg has multithreading capability, getting the best performance on multi-core systems calls for something more than just playing with the -threads option.

I’ve seen suggestions to set the -threads option to 1.5 the number of cores, which doesn’t make any sense. The most common choice for this option is the default 0 that means letting ffmpeg figure out what to do. While the -threads argument rages on, I decided to do some basic testing

The few tests below were ran on my Dell XPS 15 (9570) with an 8th-gen Intel Core i7-8750H processor having 6 cores and 12 threads. The laptop is running Windows 10 Pro with Ubuntu 18.04 LTS installed via Microsoft store. The ffmpeg version is 4.1.3-static.

For the first test, I picked an h264-encoded GoPro video just under 300MB in size and play time of about 2m 42s. The task was to split this video into multiple files of 15-second duration each. Thus, the first file will contain frames for 0-15s, the second file – 15-30s,  and so on.

The first run is just a basic loop, running one ffmpeg instance at a time with -threads option set to 0. This here is as if you were running the commands sequentially by hand, minus any delays due to you.

i=0; j=0

time while [ ${j} -le ${f_duration} ]; do

ffmpeg -i "${f_path}" -threads 0 -ss ${j} -t 15 ${f_name}_${i}.${f_ext} 2>/dev/null 1>&2

(( i = i + 1 ))

(( j = j + 15 ))

done

 I ran this a few dozen times, and the average execution time was 5m15.136s.

Now, for the second test, I decide to micromanage ffmpeg a bit. I know I have six double-threaded cores, so, I fugured, I’ll run six ffmpegs at a time with the -threads option set to 2. This will leave ffmpeg with no opportunity to make any decisions.

i=0; j=0

while [ ${j} -le ${f_duration} ]; do

{ ffmpeg -i "${f_path}" -threads 2 -ss ${j} -t 15 ${f_name}_${i}.${f_ext} & } 2>/dev/null 1>&2

pids+=($!)

(( i = i + 1 ))

(( j = j + 15 ))

while [ $(ps -ef | grep -c "[f]fmpeg.*threads") -ge 6 ]; do 
sleep 5; done ; 
done

for pid in ${pids[*]}

do
 wait ${pid} 2>/dev/null 1>&2

done

Once again, I ran this process a couple of dozen times and the average processing time was 5m22.466s. And setting -threads to 1.5, as so many suggest, does nothing but increases execution time.

The conclusion here is obvious: ffmpeg does a decent job identifying the available CPU resources and distributing the load correspondingly. Why so many people are reporting such different results? Probably because they’re using different versions of ffmpeg on vastly different hardware. Also, they don’t really know how to analyze running processes and monitor system performance, and just run top. And even then they don’t know how to correctly interpret performance data they’re seeing.

If you really want to get a sense of how ffmpeg utilizes available system resources, I’d suggest you use htop, atop, or, better yet, install netdata.