fix(encoder): observability — silence was the bug

First real recording (2026-09-01): ffmpeg died at ~0.9s mid-session with ZERO log
lines while the pump fed a corpse for 9 more seconds. Three blind spots closed:
- OnStderrLine discarded everything non-progress: ffmpeg's actual words (startup
  config, warnings, the reason it quit) now go to AppLog prefixed 'ffmpeg:' (400-char
  cap so a \r-choked blob can't flood).
- Unexpected exit only fired ProcessFailed when code != 0 — a CLEAN exit vanished
  silently. Any exit we didn't request is now logged and fired, any code.
- ExitCode read raced StopAsync's Dispose (tonight's 'No process is associated'
  line) — guarded.
- VM output resolver logs once/5s when a webcam element resolves to a null frame
  (preview showed the cam, recording didn't — the layer skip was invisible).
FfmpegEncoderTests + FramePumpTests 21/21 against the new code, 0 warnings.
This commit is contained in:
2026-09-01 22:11:52 -07:00
parent 7f2bda8ed3
commit 8dcaee0b5b
2 changed files with 59 additions and 8 deletions
+20
View File
@@ -459,6 +459,26 @@ public partial class MainViewModel : ViewModelBase
// preview: webcam by DeviceId, live captures (the background) by CaptureKey,
// images/background by AssetId. A null frame leaves the element transparent.
private VideoFrame? ResolveOutputFrame(SceneElement element)
{
var frame = ResolveOutputFrameCore(element);
// Output-side eyes (2026-09-01): preview showed the webcam but the recording
// didn't — a null resolver frame silently DROPS the layer. Log once per 5s
// per kind so the repro run tells acquire-mismatch from compose-skip.
if (frame == null && element is WebcamSceneConfig webcam)
{
var now = DateTime.UtcNow;
if (now - _lastWebcamNullLog >= TimeSpan.FromSeconds(5))
{
_lastWebcamNullLog = now;
AppLog.Write($"Output resolver: webcam '{webcam.WebcamId}' frame is null — layer skipped in composite");
}
}
return frame;
}
private DateTime _lastWebcamNullLog = DateTime.MinValue;
private VideoFrame? ResolveOutputFrameCore(SceneElement element)
{
return element switch
{