MP4 H.264 vs H.265, Apple Compatibility and Storage

Date: 2022-11-19 · Word Count: 497 · Reading Time: 3 minutes

Action cameras (and many others) will encode MP4 video using H.264 or using constant rate H.265. This is somewhat space intensive though, so taking lots of video can quickly fill up your disks.

A fix for this it to re-encode as H.265 or to switch from constant bitrate to a constant rate factor (i.e. quality level). These are much more space efficient algorithms with no perceptible drop in quality. If your goal is to have the best video you can while reducing file sizes, this is a good approach. It will take some CPU time, so the working assumption here is that leaving your computer on for a few hours to compress the video won’t be a problem.

How much space savings are we talking about?

Taking GoPro video filmed at a constant bitrate of 100 Mb/s, switching to constant rate factor (CRF) of 28 reduces file sizes to about 30% of the size of the original. So a typical 4 GiB file ends up a bit over 1 GiB. In extreme examples, I’ve had a 3.7 GiB file get reduced to 50 MiB. Yes, there’s an explanation for that, I was in a pool and the whole background is an efficiently compressible flat blue.

Now, the quick way to do this is to install ffmpeg and run something like:

ffmpeg -i "${input}" -vcodec libx265 "${output}"

This is fine and dandy, you’ll be able to view your videos using VideoLAN. But, say you’re on MacOS and you want to play it natively or edit it in iMovie. Unfortunately, it won’t work. There are two ways of storing HEVC in MP4: HEC1 and HVC1.

The thing to know, is that Apple software only recognises HVC1.

So, you’ll need the following to make it work properly:

ffmpeg -i "${input}" -vcodec libx265 -tag:v hvc1 "${output}"

If you’ve already got HEC1 encoded data and want to convert it to HVC1, the way to do this is:

ffmpeg -i "${input}" -c:v copy -tag:v hvc1 -c:a copy "${output}"

You can also adjust the quality target by adjusting the Constant Rate Factor crf flag, with a lower value being a higher perceived quality target e.g.:

ffmpeg -i "${input}" -vcodec libx265 -crf 24 -tag:v hvc1 "${output}"

The default in ffmpeg is 28. This is decent for most applications, and lower than 20 is generally unnecessary. Somewhere in the 18-20 range is where there’s no perceptible difference. Even if you’re trying to optimise for upload to a video streaming service, 18 is as low as you want to go.

To give an idea of file sizes, with a 111 MiB GoPro video source, we end up with:

  • 4.6 MiB at CRF 28
  • 15 MiB at CRF 24
  • 37 MiB at CRF 20
  • 53 MiB at CRF 18

If you’d like to read a more detailed post on CRF, I recommend this CRF guide

For those contemplating WEBM (AV9), the same file ends up as 28 MiB but takes 2,385 seconds instead of 207 seconds to encode.