fix(engine): guard scaler against zero-dimension source frames
All checks were successful
CI / build-and-test (push) Successful in 31s
All checks were successful
CI / build-and-test (push) Successful in 31s
A source frame reporting width or height == 0 (a malformed/glitched NDI frame, or a sender mid-renegotiation) drove ComputeFitRect into a division by zero: srcAspect = srcW/srcH with srcH==0 yields Infinity → NaN width/height, and the Stretch path produced a degenerate copy loop. Either way a single bad frame could throw out of Scale and bubble up to the pipeline supervisor as a failure, costing a restart + reconnect. Now a zero-area source short-circuits to a black, fully-opaque frame at the target resolution — the same visual the slate path would show — so a transient bad frame is absorbed silently instead of tearing down the ISO.
This commit is contained in:
parent
e36b928c69
commit
5b3bf7d5e8
1 changed files with 17 additions and 0 deletions
|
|
@ -15,6 +15,15 @@ public sealed class ManagedNearestNeighborFrameScaler : IFrameScaler
|
|||
$"ManagedNearestNeighborFrameScaler only supports BGRA input (got {source.Format}). " +
|
||||
"v1.0 receivers request BGRA from NDI; UYVY support comes in v1.5.");
|
||||
|
||||
// Degenerate source guard: a frame reporting a zero (or negative) dimension
|
||||
// would divide-by-zero in ComputeFitRect (srcW/srcH) and produce NaN extents,
|
||||
// or drive a degenerate copy loop on the Stretch path. Rather than throw out
|
||||
// of the hot path and cost the pipeline a supervisor restart, emit a black
|
||||
// opaque frame at the target size — identical to what the no-signal slate
|
||||
// would render — so a single bad frame is absorbed without a reconnect.
|
||||
if (source.Width <= 0 || source.Height <= 0)
|
||||
return BlackFrame(targetWidth, targetHeight, timestampTicks);
|
||||
|
||||
var output = new byte[targetWidth * targetHeight * 4];
|
||||
|
||||
// Compute the destination rectangle within the target according to aspect mode.
|
||||
|
|
@ -56,6 +65,14 @@ public sealed class ManagedNearestNeighborFrameScaler : IFrameScaler
|
|||
return new ProcessedFrame(targetWidth, targetHeight, timestampTicks, output, PixelFormat.Bgra);
|
||||
}
|
||||
|
||||
/// <summary>Allocates a black, fully-opaque BGRA frame at the requested size.</summary>
|
||||
private static ProcessedFrame BlackFrame(int width, int height, long timestampTicks)
|
||||
{
|
||||
var output = new byte[width * height * 4];
|
||||
for (var i = 3; i < output.Length; i += 4) output[i] = 0xFF; // alpha; BGR stay 0
|
||||
return new ProcessedFrame(width, height, timestampTicks, output, PixelFormat.Bgra);
|
||||
}
|
||||
|
||||
private static (int X, int Y, int W, int H) ComputeFitRect(int srcW, int srcH, int dstW, int dstH, AspectMode aspect)
|
||||
{
|
||||
switch (aspect)
|
||||
|
|
|
|||
Loading…
Reference in a new issue