‹ Geoff Ruddock

Bulk compress videos to H.265 (x265) with ffmpeg

Apr 21, 2020

Despite being a relatively modern phone, my OnePlus 6T records video using the H.264 codec rather than the newer H.265 HEVC codec. A minute of 1080p video takes up ~150MB of storage, and double that for 60fps mode or 4K. Even though the phone has a decent amount of storage (64GB) it quickly fills up if you record a lot of video.

The storage savings from HEVC are pretty astounding. It typically requires 50% less bitrate (and hence storage space) to achieve the same level of quality as H.264.1 There are some third-party apps such as UltraCorder which support H.265, but I’d prefer to stick with the stock camera app. I frequently use the handy “double tap power button” shortcut to quickly launch my camera app, so it is important that the app which launches is able to handle both photos and videos. This rules out using a specialty video app which supports H.265 encoding.

Converting a single video

It’s pretty easy to compress these videos using the ffmpeg command line tool with something like the command below.

ffmpeg -i input.mp4 -vcodec libx265 -crf 28 output.mp4

I tried a few different quality settings before settling on the default -crf 28 . With this level, I cannot visually tell the difference in quality between compressed and uncompressed videos.

Converting videos in bulk

So ffmpeg is great, but I wanted to batch process all of my phone videos, with the following goals in mind:

  • Recursively search sub-directories, since I typically organize my photos and videos into a folder hierarchy.
  • Only compress videos which are not already compressed (by using ffprobe to detect if encoding is hevc)
  • Preserve the metadata (creation time, modification time) from the original video, so that chronological sort continues to work properly.

So I wrote a small python CLI tool which achieves the above goals.

The script

Put the script somewhere convenient (such as your home folder), cd to your content directory, then call the script from the terminal using python ~/compress_videos.py --recursive --file-ext=mp4 .

☠  Use at your own risk – I accept no responsibility for any data loss or mistakes caused by this script. It is a prudent idea to test it first and visually inspect the output. You should do so for each different input file you are converting. I ran into difficulty with a couple .MTS video files which were interlaced, and so required different settings to convert properly.

Further reading

CRF Guide (Constant Rate Factor in x264, x265 and libvpx) – A good overview of the difference between constant and variable bitrate encoding, and suggestions for sensible defaults for each.

  1. A Large-Scale Comparison of x264, x265, and libvpx — a Sneak Peek (Netflix Tech Blog) ↩︎