As I mentioned previously, at Cricingif we are focusing on building a fast, efficient play by play highlights platform. One of the bottlenecks we have been facing is video compression – some of the programs we have been using for video and audio capture are very clunky, slow and CPU-intensive. After burning through a couple of laptop motherboards, I’ve decided to give FFmpeg a go.
Here are the results of my experiment with video compression using FFmpeg. For the purpose of this experiment, I used a pre-recorded video clip, but in our production environment at Cricingif we record video and audio capture through live streams. Nevertheless, the results are equally valid in that scenario as well.
I’ve taken an input video with the following specs:
For the record, the test machine is a Microsoft Surface Pro 4 with 8 gigabytes of RAM, 256gb of hard drive space and powered by the i7-6650u processor. Granted this isn’t the best machine for video encoding, but it’s my work machine and it’s what I’m experimenting on. I have run the tests on our production setups but these results are illustrative of what I achieved there.
The first step is to do a simple mp4 video encoding using the h.264 codec:
ffmpeg.exe -i "Take 4.MTS" -vcodec libx264 -acodec aac test1.mp4
Thirty-two seconds to encode a 25-second video at run-time is too much, we cannot afford to have an encoding time longer than the video itself in our real-time application. However, for now we will be streaming 640×480 video to our users due to the limited capability of Pakistan’s network and device landscape. Let’s try that:
ffmpeg.exe -i "Take 4.MTS" -vcodec libx264 -filter:v scale=640:-1 -acodec aac -pix_fmt yuv420p test3.mp4
Using this, the file size is now down to 3,504,438 bytes at 640×480. The encoding time is also now just 7.2 seconds. This works, but at 134 kbps this is more than most Wi-Fi can handle. Time to improve further.
|Playing around with the constant rate factor (default: 23) allows for lossy compression of the input stream while negligibly affecting the output. In addition, since Cricingif videos are mainly consumed on mobile, the minor loss of quality is acceptable.|
Also realized that the x.264 codec does not allow for odd values, so in case the input video dimensions are slightly off, it will throw a “width or height not divisible by 2” error. A very nice explanation is here. So I’ve updated the command:
ffmpeg.exe -i "Take 4.MTS" -vcodec libx264 -crf 29 -filter:v scale="640:trunc(ow/a/2)*2" -acodec aac -pix_fmt yuv420p test3.mp4
A 7 second encoding time is a decent trade-off. Using different options such as the superfast preset or defining fixed rates does bring down the compression time to 5 seconds or thereabouts, but the trade-off is in the increased file size. In the current state, the data transmission is about 63kbps, something reasonably achievable with only about 220MB of data consumed per hour of streaming.
One further test involved testing out at 360p resolution, which is a standard YouTube playback format. With this, a file size of just 1,222,874 bytes is achieved with an encoding time of only 6.2 seconds. At 46kbps, only 160MB of data per hour is consumed. Good enough for now.
A detailed table of results for all experiments:
|File||Resolution||Bitrate||FPS||Size (b)||Encoding Time (s)|
For more on what I’ve done, do check out my resume
Get in touch with me at: qasimzafar AT outlook DOT com