6.18.0 - a codec routing default that stops handing files to the path that refuses them
One routing change, plus the FFmpegBuild bump that surfaced it. Drop-in from 6.17.1, no API change.
Two allowlists that were never complementary
The dispatch switch in AetherEngine.load named its software codecs (AV1 without hardware, VP9, VP8, MPEG-4 Part 2, MPEG-2, VC-1) and sent everything else to the native path. That reads like a conservative default, and it was not one, because the native path is an allowlist of its own: HLSVideoEngine accepts HEVC, H.264 and hardware-decodable AV1, and throws unsupportedCodec on anything else.
So the two lists did not cover each other, they left a hole. A codec nobody had enumerated was not routed to a fallback, it was routed to the one path that refuses it by contract, and it never reached libavcodec, which decodes it.
What surfaced it
FFmpegBuild#1 added the QuickTime RLE decoder, the lossless codec that screen-capture and animation .mov exports use. With the decoder compiled in, the file still failed the load, because it never got that far. Measured on a real qtrle mov (640x480 rgb24 + pcm_s16le) through aetherctl play:
[Demuxer] stream[0] type=video codec=qtrle 640x480
[AetherEngine] dispatch: codec=55 → native
LOAD FAILED: HLSVideoEngine: unsupported codec id 55 (only HEVC and H.264 supported)
The demuxer was never the problem. ProRes, MJPEG, Theora, Cinepak and rawvideo share the shape.
The change
VideoRoutingPolicy.requiresSoftwarePath now defaults to software, and only the codecs the native path actually carries stay native. Same fixture, same command:
[AetherEngine] dispatch: codec=55 → software
[SWDecoder] Opened: 640x480, codec=qtrle, threads=1, 8-bit
[SWHost] first video frame enqueued: pixfmt=0x34323076 size=640x480 pts=0.000s
t=08 state=ended cur=7.82 dur=8.0
RGB24 converts to NV12 through the existing swscale path with no special case, since sws_getCachedContext reads the source format off the frame.
AV_CODEC_ID_NONE stays native explicitly. An audio-only source probes as NONE, and letting the new default catch it would have moved music playback onto the software host, which is not the path it is verified on.
Whether an exotic codec then plays is a question for the FFmpeg build rather than for routing: with no decoder compiled in it now fails at SoftwareVideoDecoder with Unsupported video codec (id: N), which is at least the honest error and names the codec.
Dependencies
FFmpegBuild 2.4.1: adds the qtrle decoder, 40 decoders total, demuxer / filter / parser lists unchanged. Consumers pinning .upToNextMinor(from: "2.4.0") pick it up without a manifest change.
Consumers
Any host that dispatches by codec id ahead of the engine should check its own list against this. Sodalite's Jellyfin device profile, for one, advertised a VideoCodec list mirroring the old dispatch table; the right mirror is now what the bundled FFmpeg build carries a decoder for.
Suite green at 1686 tests in 246 suites. Thanks to @dalsoop, whose PR is what exposed the routing hole.