Using FFmpeg to Create HEVC Videos That Work on Apple Devices

The HEVC (H.265) video codec will produce smaller file sizes at the same level of video quality. FFmpeg can create those files, however, a certain tag is needed for the files to be recognized by Apple software.

HEVC (High Efficiency Video Coding), also known as H.265, is a video compression standard that, compared to it predecessor H.264, offers from 25 % to 50 % better data compression at the same level of video quality. Apple’s operating systems natively support HEVC since iOS 11 and macOS High Serria. FFmpeg can create those files, however, a certain tag is needed for the files to be recognized by Apple software.

TL;DR

Use the -tag:v hvc1 parameter in your FFmpeg command make your HEVC file work on Apple devices.

Full example:

ffmpeg -i input.avi -c:v libx265 -crf 28 -c:a aac -b:a 128k -tag:v hvc1 output.mp4

My Usecase: Old DV Material in iCloud Photos

I have hours of home video material lying around on my file server, recorded with an ancient Hi8 camcorder back in the 90s. I had digitalized those tapes in 2008 using a more modern Hi8 camcorder with digital output, resulting in DV-encoded AVI files. In this format, 60 minutes need around 13 GB, which is fine for high-quality long-term archival, but not for quick access from everywhere. Since my goal is to import those videos into iCloud Photos, I needed to find a suitable format to transcode to.

Using FFmpeg to Convert to HEVC

FFmpeg is the utility when it comes to converting video or audio files. However, when simply using the HEVC encoding command suggested in the FFmpeg H.265 Encoding Guide, you will notice that the resulting video file won’t have a thumbnail icon in Finder and won’t play in QuickTime Player or on any iDevice (it will play in VLC though).

To make it Apple-friendly, we’ll need to add an “hvc1” tag. We can do this with the following command (assuming your original file is called input.avi):

ffmpeg -i input.avi -c:v libx265 -crf 28 -c:a aac -b:a 128k -tag:v hvc1 output.mp4

Note: I’m using FFmpeg Version 4.1.1 here. If you’re on an older version, this might not work. You can check your FFmpeg version by running ffmpeg without any parameters.

The CRF Value

The number after -crf defines the video quality of the resulting file. In the example above, I have used the default CRF value of 28 (for H.264, the default was 23 which, according to FFmpeg’s encoding guide, should be visually equivalent).

I suggest you play with this value until you find the best compromise between file size and video quality. The scale goes from 0 (lossless) to 51 (worst quality). I ended up using 22 which, at the cost of a larger file, provides better quality than the default. To determine this value, I encoded a short video clip with different CRF values (e.g. 0 for reference, 20, 22, 25, 31), took screenshots, and compared the stills to the reference until I found the difference to be small enough. I found my sweet spot at 22 where the difference to 20 was so minor that I didn’t find it worth wasting space for only subtle quality improvement. You’re mileage my vary.

Tagging Existing HEVC Files

If you have already converted a bunch of files to HEVC, but forgot to add the tag, don’t worry—you can add the tag after the fact without re-encoding the files:

ffmpeg -i input.mp4 -vcodec copy -acodec copy -tag:v hvc1 output.mp4

The -vcodec copy and -acodec copy arguments will instruct FFmpeg to copy the source streams and not to re-encode them.

Batch-Convert a Folder

To make this even more useful, you can use the following command that recursively walks over a folder structure to convert all *.avi to HEVC. It will start in the current directory, leaving the original files untouched.

find . -name *.avi -exec sh -c \
    'ffmpeg -i "$1" -c:v libx265 -crf 28 -c:a aac -b:a 128k -tag:v hvc1 "${1%.avi}.mp4"' _ {} \;

Further Reading