A video pipeline for iCloud Photos

For the most part, iCloud Photos delivers. A couple of hundred gigs of precious family memories, safely backed up, magically and (usually) instantly available on all my devices.

Then you try to play a video that isn't cached on your device… welcome to spinner town! 🐌

Unlike photos, videos in your iCloud Photos library aren't transcoded before being downloaded and viewed on your devices. Whatever file you upload is exactly what you'll be downloading later. Thanks to increasing resolutions and framerates, and despite compression advances like HEVC, the videos are getting bigger and the downloads are getting slower. Plus, iCloud storage ain't free!

I've realised that videos are only worth having in iCloud Photos if you can actually play them back. Under that logic, 4K 60fps (or whatever comes next) is usually more liability than feature.

With some trial and error, I've found that 1080p HEVC (H.265) at 30fps is a reasonable compromise between quality and file size for videos that live in my iCloud Photos library.

But I don't know at shooting time whether a clip will just be fodder for Memories or something I'll want to edit into a 4K super slow-mo masterpiece, so I still often capture bigger videos than iCloud Photos needs, especially on GoPro.

The pipeline

Here's my simple ffmpeg-based pipeline for getting videos into iCloud Photos.

Following a brew install ffmpeg, I run the following bash script on an input folder of source videos to generate lower quality (and downscaled if necessary) HEVC versions:

for f in ./input/*; do
full_filename=$(basename -- "$f")
extension="${full_filename##*.}"
filename="${full_filename%.*}"
ffmpeg -i "$f" \
-c:v libx265 \
-preset medium \
-crf 29 \
-c:a aac -b:a 192k \
-vf scale=1920:1080 \
-vtag hvc1 \
-pix_fmt yuv420p \
-r 30000/1001 \
"./output/${filename}_LOW.mov"
echo "🦖 Output ${filename}_LOW.mov"
done

Those ffmpeg options:

  • -i: the input file
  • -c:v libx265: specifies the video codec as H.265 (aka HEVC)
  • -preset medium: determines how fast the encoding process will be at the expense of detail
  • -crf 29: sets the CRF at a level that gives me a good balance between file size and quality
  • -c:a aac -b:a 192k: sets the audio codec to AAC and bitrate to 192k
  • -vf scale=1920:1080: scales resolution to 1920x1080 (you can leave this out if your source is already 1080p)
  • -vtag hvc1: I don't know what this does but the videos aren't playable on Apple devices if you don't do it
  • -pix_fmt yuv420p: something to do with colors, I can't remember why I did this
  • -r 30000/1001: set the framerate to 29.97fps

Then I import them into the Photos app, back up the high quality originals and let iCloud Photos do its thing!