Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Automate Pre-Delivery Asset Validation on a Rented Mac

A render that looks correct on your screen can still fail broadcast QC if the codec profile, color space, frame-rate rational, or filename is off by one character. Run an automated validation script on your rented Mac right before upload and you catch those failures before the delivery portal ever sees them. The $29 virtual Intel macOS plan (2 vCPU, 8 GiB RAM, 80 GiB disk) is enough to run the script because ffprobe only reads container headers; bigger hardware only matters if the same session also transcodes or renders.

Common Delivery Failures This Catches

Broadcast and streaming platforms reject deliverables for a short list of predictable reasons:

  • Codec mismatch: sending H.264 when the spec demands ProRes 422 HQ, or submitting ProRes 4444 when only ProRes 422 is accepted.
  • Resolution or aspect ratio: 1920×1090 instead of 1920×1080, or anamorphic pixel dimensions when square pixels are required.
  • Frame-rate rational: 30/1 (true 30 fps) versus 30000/1001 (29.97). They look identical on a timeline and fail an exact-match spec check.
  • Pixel format and bit depth: yuv420p (8-bit 4:2:0) vs yuv422p10le (10-bit 4:2:2). HDR pipelines also need specific transfer-function and color-primaries metadata.
  • Naming conventions: a client spec requiring SHW_S01E03_v2.mov will bounce show_S01E03_v2.mov immediately.

Manual spot-checking one or two files misses regressions across a full batch. The script below checks every file in a folder against a machine-readable spec and fails loudly on the first problem.

Installing ffprobe on the Rented Mac

ffprobe ships with every FFmpeg build and reads structured metadata from almost any media container. The Figment macOS image is clean, so install Homebrew and the packages once per rental from the desktop terminal reached through the browser console:

# One-time setup on the rented Mac (desktop terminal, reached through the browser console)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install ffmpeg   # includes ffprobe
brew install jq       # JSON parser used by the validation script

Per the ffprobe documentation, -of json -show_entries returns only the fields you ask for, and -select_streams v:0 narrows output to the first video track:

ffprobe -v quiet -of json \
  -show_entries "stream=codec_name,width,height,r_frame_rate,pix_fmt" \
  -select_streams v:0 \
  deliverable.mov

For HDR deliverables, add color_space,color_transfer,color_primaries to -show_entries to check the EOTF and gamut tags your client requires (for example bt2020 primaries and smpte2084 transfer for HDR10).

Spot-Checking with mdls

For files that Spotlight has already indexed, mdls prints macOS metadata attributes. Content-type values use Apple's Uniform Type Identifiers:

mdls -name kMDItemPixelWidth -name kMDItemPixelHeight render_ep03.mov
mdls -name kMDItemContentType render_ep03.mov
# com.apple.quicktime-movie for .mov
# public.mpeg-4 for .mp4

mdls depends on Spotlight indexing, which may not have run on files you just copied in. Treat ffprobe as the authoritative source for per-stream checks and use mdls as a quick cross-check once the files have settled.

Building a Spec File

Encode the client's delivery requirements as a flat key=value config. The fps value must match ffprobe's r_frame_rate output exactly — it is a rational, not a decimal — and the naming_re must be a working extended regex for the real filename pattern.

# apple_tv_plus_spec.conf
# 4K ProRes 422 HQ, 23.976 fps, 10-bit 4:2:2
codec=prores
width=3840
height=2160
fps=24000/1001
pix_fmt=yuv422p10le
naming_re=^SHW_S[0-9]{2}E[0-9]{2}_v[0-9]+\.mov$

Common fps rationals: 24/1 (true 24), 24000/1001 (23.976), 30/1 (true 30), 30000/1001 (29.97), 60/1 (true 60), 60000/1001 (59.94). Run ffprobe once on a known-good render from your NLE and copy the string it prints — some tools write prores and some write prores_ks; use whichever your renders actually produce. Keep each value on a single line with no surrounding spaces; the loader below strips whitespace from every value.

The Validation Script

Save as validate_delivery.sh, chmod +x, and run it against a batch folder. It is an unexecuted example — test it on a known-good and a known-bad file before putting it in front of a deadline.

#!/usr/bin/env bash
# validate_delivery.sh — pre-delivery QC for broadcast/streaming deliverables
# Usage: ./validate_delivery.sh <spec.conf> <media_folder>
# Requires: ffprobe (brew install ffmpeg), jq (brew install jq)
set -euo pipefail

SPEC="${1:?Usage: $0 <spec.conf> <media_folder>}"
FOLDER="${2:?Usage: $0 <spec.conf> <media_folder>}"

spec_val() { grep -E "^${1}=" "$SPEC" | cut -d= -f2- | tr -d '[:space:]'; }

EXPECTED_CODEC=$(spec_val codec)
EXPECTED_WIDTH=$(spec_val width)
EXPECTED_HEIGHT=$(spec_val height)
EXPECTED_FPS=$(spec_val fps)
EXPECTED_PIX=$(spec_val pix_fmt)
NAMING_RE=$(spec_val naming_re)

PASS=0; FAIL=0; FAIL_MSGS=()

check_file() {
  local FILE="$1" BASE PROBE CODEC WIDTH HEIGHT R_FPS PIX
  BASE="$(basename "$FILE")"
  local -a ISSUES=()

  if [[ -n "$NAMING_RE" ]] && ! [[ "$BASE" =~ $NAMING_RE ]]; then
    ISSUES+=("naming: does not match /$NAMING_RE/")
  fi

  if ! PROBE=$(ffprobe -v quiet -of json \
      -show_entries "stream=codec_name,width,height,r_frame_rate,pix_fmt" \
      -select_streams v:0 "$FILE" 2>/dev/null); then
    FAIL_MSGS+=("FAIL [unreadable] $BASE")
    FAIL=$((FAIL + 1)); return 0
  fi

  CODEC=$(printf '%s' "$PROBE"  | jq -r '.streams[0].codec_name   // empty')
  WIDTH=$(printf '%s' "$PROBE"  | jq -r '.streams[0].width        // empty')
  HEIGHT=$(printf '%s' "$PROBE" | jq -r '.streams[0].height       // empty')
  R_FPS=$(printf '%s' "$PROBE"  | jq -r '.streams[0].r_frame_rate // empty')
  PIX=$(printf '%s' "$PROBE"    | jq -r '.streams[0].pix_fmt      // empty')

  [[ "$CODEC"  != "$EXPECTED_CODEC"  ]] && ISSUES+=("codec=$CODEC want=$EXPECTED_CODEC")
  [[ "$WIDTH"  != "$EXPECTED_WIDTH"  ]] && ISSUES+=("width=$WIDTH want=$EXPECTED_WIDTH")
  [[ "$HEIGHT" != "$EXPECTED_HEIGHT" ]] && ISSUES+=("height=$HEIGHT want=$EXPECTED_HEIGHT")
  [[ "$R_FPS"  != "$EXPECTED_FPS"    ]] && ISSUES+=("fps=$R_FPS want=$EXPECTED_FPS")
  [[ "$PIX"    != "$EXPECTED_PIX"    ]] && ISSUES+=("pix_fmt=$PIX want=$EXPECTED_PIX")

  if [[ ${#ISSUES[@]} -gt 0 ]]; then
    local MSG
    printf -v MSG '%s, ' "${ISSUES[@]}"
    FAIL_MSGS+=("FAIL $BASE — ${MSG%, }")
    FAIL=$((FAIL + 1))
  else
    printf 'PASS %s\n' "$BASE"
    PASS=$((PASS + 1))
  fi
}

shopt -s nullglob nocaseglob
FILES=()
for G in "$FOLDER"/*.mov "$FOLDER"/*.mp4 "$FOLDER"/*.mxf; do
  FILES+=("$G")
done

if [[ ${#FILES[@]} -eq 0 ]]; then
  printf 'No .mov/.mp4/.mxf files found in %s\n' "$FOLDER"; exit 1
fi

for f in "${FILES[@]}"; do check_file "$f"; done

printf '\n===== QC REPORT =====\nPASS: %d   FAIL: %d\n\n' "$PASS" "$FAIL"

if [[ ${#FAIL_MSGS[@]} -gt 0 ]]; then
  printf '%s\n' "${FAIL_MSGS[@]}"
  exit 1
fi
exit 0

Exit code 1 means at least one file failed, so the script slots cleanly in front of an upload step or a Shortcuts automation. Exit code 0 means every .mov, .mp4, or .mxf in the folder passed every check. set -euo pipefail ensures a broken ffprobe call or an unset variable stops the run instead of silently reporting success. If you need audio checks too, call ffprobe a second time with -select_streams a:0 and compare codec_name, sample_rate, and channels the same way.

Extending for HDR and Color Space

Add color metadata to both the spec file and the ffprobe query:

# Add to spec.conf
color_space=bt2020nc
color_transfer=smpte2084
color_primaries=bt2020

# Then add to -show_entries in check_file():
# stream=codec_name,width,height,r_frame_rate,pix_fmt,color_space,color_transfer,color_primaries
# And compare the three new variables the same way.

Container tags are not a color-accurate preview. They prove the file carries the right metadata — which is what most automated QC tools reject on — but they do not replace a calibrated hardware monitor at sign-off.

A Pre-Upload Acceptance Checklist

Run this on the rented Mac in the minute before you upload. It pairs the script with the small checks a human still needs to do:

  1. ffprobe the first and last file in the batch by hand and visually confirm the output before trusting the script on the rest.
  2. Run ./validate_delivery.sh spec.conf out/ and confirm FAIL: 0.
  3. Spot-check one file with mdls -name kMDItemContentType to confirm the UTI matches the container extension.
  4. Compare du -sh out/*.mov against the per-episode file-size cap in the client spec.
  5. Verify the delivery manifest filename list matches the folder listing: ls out/ | sort > /tmp/have.txt && diff -u manifest.txt /tmp/have.txt.
  6. Only upload after all five steps pass, and keep spec.conf and the script in the project repo so the next version uses the same rules.

Which Figment Plan to Use

The validation script reads container headers and runs shell tools — it does not decode or transcode. The $29 virtual Intel macOS plan is enough for probing a full folder of ProRes masters; ffprobe does not touch pixel data. Pick a bigger plan only if the same session also renders or transcodes:

  • Transcode a batch to the delivery codec. The physical Intel i3 Mac at $49 or an M-series Mac from $95 is the right tier. Both are currently request-based while supply is confirmed, so send the exact chip, RAM, and disk requirements with your quote.
  • Render the master itself. M-series from $95 for Apple-silicon-only tools, or the Managed Build Mac at $249/month — one M-series Mac with CI setup, backups, monitoring, and 30 minutes of monthly support — if you want Figment to run the pipeline for you. For two Macs plus two CI runners, Managed Mac Team is $999/month.

Hardware class above the $29 VM is confirmed in the configuration quote — ask for the exact chip, RAM, and disk before you commit. Access to the VM is through the browser console; the desktop terminal is where you run every command in this guide, and the plan has no GPU acceleration or audio output, so transcodes that need those belong on an i3 or M-series host.

See Mac hosting plans · Start configuring a Mac


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms