From c8775d216bac37801bbc4b8c237ac0873f195cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magn=C3=BAs=20Sm=C3=A1ri=20Sm=C3=A1rason?= Date: Tue, 14 Jul 2026 13:24:25 +0000 Subject: [PATCH] Add headless / Apple Silicon macOS rendering guide (#9) Adds guides/HeadlessRenderingMacOS.md covering headless melt on macOS: install, running with no display via the avformat consumer, -progress2 for scripts and CI, and headless title rendering. Leads with the qtext producer, which renders headless on macOS out of the box (Qt uses the cocoa platform, so the Linux DISPLAY abort that mlt#1069 addresses does not apply). Documents QT_QPA_PLATFORM=offscreen as the portable form for cross-platform scripts, and pango as the zero-GUI-dependency fallback. Linked from developers/BuildTips.md under the existing macOS subsection, mirroring the Windows guide. Version-stamped for graceful aging. Co-Authored-By: Claude Opus 4.8 (1M context) --- developers/BuildTips.md | 3 + guides/HeadlessRenderingMacOS.md | 106 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 guides/HeadlessRenderingMacOS.md diff --git a/developers/BuildTips.md b/developers/BuildTips.md index 3e768503..c905e06f 100644 --- a/developers/BuildTips.md +++ b/developers/BuildTips.md @@ -27,6 +27,9 @@ ffmpeg, SDL, etc. using [MacPorts](http://www.macports.org/). Normally, I use MLT configuration: `--enable-gpl --prefix=/opt/local` +For a modern Apple Silicon walkthrough, including running `melt` headless for +batch and CI rendering, see the [Headless Rendering on macOS]({{ "/docs/headlessmacos/" | prepend: site.baseurl }}) page. + #### Windows See the [Building on Windows]({{ "/docs/windowsbuild/" | prepend: site.baseurl }}) page. diff --git a/guides/HeadlessRenderingMacOS.md b/guides/HeadlessRenderingMacOS.md new file mode 100644 index 00000000..48d8957f --- /dev/null +++ b/guides/HeadlessRenderingMacOS.md @@ -0,0 +1,106 @@ +--- +title: Documentation +wrap_title: Headless Rendering on macOS +permalink: /docs/headlessmacos/ +--- + +*Last verified with melt 7.38.0 and FFmpeg 8.1 on Apple Silicon (macOS), July 2026.* + +This guide covers running `melt` with no graphical session on macOS: the setup and the flags that matter for unattended, batch, and CI rendering. It describes a Homebrew install on Apple Silicon, which is the setup behind an automated video pipeline the author runs daily. Dan uses MacPorts; the equivalent ports exist and the commands translate directly. + +### Install + +Homebrew ships a maintained MLT formula, so the whole toolchain is one command: + +~~~bash +brew install mlt +~~~ + +That pulls in FFmpeg, the Qt modules, and the rest of the runtime. Confirm the binary and the modules it can see: + +~~~bash +melt -version +melt -query "producers" | grep -E "avformat|pango|qtext" +~~~ + +If you build from source instead, point `configure` at the Homebrew prefix rather than hardcoding a path, so the guide keeps working when the prefix changes: + +~~~bash +./configure --enable-gpl --prefix="$(brew --prefix)" +~~~ + +### Run melt with no display + +The one thing to know: `melt` with no `-consumer` argument opens the interactive SDL preview, which needs a window and an audio device. In a headless, batch, or CI context you always name the `avformat` consumer and write to a file: + +~~~bash +melt -profile atsc_1080p_25 \ + input.mp4 \ + -consumer avformat:output.mp4 \ + vcodec=libx264 acodec=aac +~~~ + +That runs to completion and exits on its own, with no window and no display server. There is no `DISPLAY` variable to set and nothing to wrap it in. Pick the `-profile` that matches your target format; `melt -query "profiles"` lists them. + +### Progress reporting for scripts and CI + +Use `-progress2` for unattended runs. It prints one progress line per update instead of overwriting a single line, so it reads cleanly in a log file or a CI console: + +~~~bash +melt -progress2 -profile atsc_1080p_25 \ + input.mp4 \ + -consumer avformat:output.mp4 vcodec=libx264 acodec=aac +~~~ + +Each line carries the current frame and a percentage, which is straightforward to parse if you want to drive a progress bar from a wrapper script. + +### Titles and text overlays + +This is the part that takes the longest to work out, so here is what actually happens on macOS. + +**Use `qtext` (the Qt text producer). It works headless on macOS out of the box.** macOS Qt runs on the `cocoa` platform, so the `DISPLAY` / `WAYLAND_DISPLAY` abort that affects headless Linux never fires here. No environment variable is needed, and the Qt text options are richer than the alternatives: + +~~~bash +melt -profile atsc_1080p_25 \ + color:black out=125 \ + qtext:. text="Rendered headless" fgcolour=0xffffffff size=72 \ + -consumer avformat:titled.mp4 vcodec=libx264 +~~~ + +**For cross-platform scripts, set `QT_QPA_PLATFORM=offscreen`.** On headless Linux this is what lets the Qt modules run without a display server (see [mlt#1069](https://github.com/mltframework/mlt/pull/1069)). It is harmless on macOS, so putting it in a shared render script keeps the same command working on both platforms: + +~~~bash +QT_QPA_PLATFORM=offscreen melt -profile atsc_1080p_25 \ + color:black out=125 \ + qtext:. text="Portable across macOS and Linux" size=72 \ + -consumer avformat:titled.mp4 vcodec=libx264 +~~~ + +**The `pango` producer is the fallback with no Qt or window-server dependency at all.** It is the right choice in two cases: a launchd `LaunchDaemon` running with no logged-in Aqua session, and a stock Homebrew FFmpeg, which as of FFmpeg 8 no longer ships the `drawtext` filter, so the FFmpeg text path is unavailable there. `pango` needs neither: + +~~~bash +melt -profile atsc_1080p_25 \ + color:black out=125 \ + pango:. text="No Qt, no display" fgcolour=0xffffffff size=72 \ + -consumer avformat:titled.mp4 vcodec=libx264 +~~~ + +In short: `qtext` for the richest text and the default on macOS, `QT_QPA_PLATFORM=offscreen` in front of it for scripts you also run on Linux, and `pango` when there is no window server at all. + +### A complete headless job + +Putting it together, a batch job that renders a clip with a title overlay and logs progress: + +~~~bash +#!/usr/bin/env bash +set -euo pipefail + +melt -progress2 -profile atsc_1080p_25 \ + input.mp4 \ + qtext:. text="Draft" fgcolour=0xccffffff size=64 \ + -consumer avformat:output.mp4 \ + vcodec=libx264 acodec=aac \ + 2>&1 | tee render.log +~~~ + +No display, no manual cleanup, and an exit code and log you can act on from cron, launchd, or CI.