- FfmpegFrameRateParser (pure): prefers avg_frame_rate= then r_frame_rate=,
rational N/N/M, unknown/0 -> null.
- IFrameRateProbe + FfmpegFrameRateProbe: derives sibling ffprobe.exe from the
located ffmpeg dir, reuses the IDecodeProcess seam for the ffprobe subprocess
text; null if ffprobe absent.
- FfmpegLocator now also extracts ffprobe.exe (ProbeFileName) from the pinned
archive, conditional so old caches without it degrade to no pacing.
- Tests: 6 pure parser units + 1 probe integration via fake locator/process;
FfmpegLocatorTests still green. 15/15, 0 warnings.
Pacing (probe->delay) is slice 2b. Derivative reference: standard ffprobe
avg_frame_rate probing used across OBS/media tooling.
IFfmpegLocator seam that resolves ffmpeg.exe (PATH -> cache -> pinned download),
plus the licensing compliance that makes a paid GA product defensible.
NOTE FOR USERS: this change shows NO difference in the app's behavior except a
new top-bar "About" button (opens THIRD-PARTY-NOTICES.txt). It is scaffolding
for the encoder/streaming work.
- Services/Encoder/: IFfmpegLocator + FfmpegLocator. Pin is BtbN lgpl-shared
autobuild-2026-08-09-13-03 (NOT gyan.dev/GPL or static: LGPLv2.1 §6 static
relink material avoided by dynamic linking); extracts ffmpeg.exe + libav*.dll
via a staging dir so a crash never leaves a partial cache
- THIRD-PARTY-NOTICES.txt: LGPL/BSD/MIT notices + source offer, copied to the
build output, surfaced by the About button; v1 gate = bundle full license
texts (TASK 4 requirement 9)
- ai.md "Licensing - do not violate" guardrails (never GPL/nonfree/static/latest-
tag, never link FFmpeg in, never drop notices); TASKS.md + Services/index.md
updated
- Tests: FfmpegLocatorTests - hermetic decision-ladder integration test + shared-
build DLL extraction + edge cases; docs updated (78 tests passing, 0 warnings)