Control Surface UX: pill toggle, background rename, per-scene properties
- Sliding pill toggle (green ON / red OFF) replaces checkbox - Geometry mismatch error for custom backgrounds - Backdrop -> Background: C# rename, SQL column rename with migration - Source.IsBackground: new -> override (fixes WPF binding) - Legacy 'Backdrop' display name migrated to 'Background' - Per-scene UseDefaultBackground + CustomBackgroundPath - Asset files renamed backdrop -> background - StagedScene/LiveScene split, thumbnail strip, edit gating - TransitionService (Cut/Fade/Move) - Context menu: Capture Desktop, Refresh Desktop - Resolution badge removed, ON-AIR status light added
This commit is contained in:
@@ -8,7 +8,7 @@ namespace ytLive.Tests;
|
||||
/// <summary>
|
||||
/// The output compositor (TASK 4 ship step 1): renders a scene into the encoder's
|
||||
/// master frame, mirroring the XAML preview minus the editing chrome. The integration
|
||||
/// test composites a full scene (backdrop + round webcam + images + mirror + border)
|
||||
/// test composites a full scene (background + round webcam + images + mirror + border)
|
||||
/// and asserts per-layer probe pixels; the vertical-tier test asserts the 9:16 crop
|
||||
/// and upscale. Frames are pushed by the test — no capture managers involved.
|
||||
/// </summary>
|
||||
@@ -60,11 +60,11 @@ public class SceneCompositorTests
|
||||
[Fact]
|
||||
public void Composite_FullScene_MasterPixels()
|
||||
{
|
||||
var red = Solid(1920, 1080, 255, 0, 0); // backdrop
|
||||
var red = Solid(1920, 1080, 255, 0, 0); // background
|
||||
var green = Solid(1280, 720, 0, 255, 0); // webcam
|
||||
var split = Split(100, 100, 0, 255, 255, 255, 0, 255); // image: left cyan, right magenta
|
||||
|
||||
var backdrop = new Source { Type = SourceType.DisplayCapture, IsBackdrop = true, CaptureKey = "monitor:0" };
|
||||
var background = new Source { Type = SourceType.DisplayCapture, IsBackground = true, CaptureKey = "monitor:0" };
|
||||
var roundWebcam = new WebcamSceneConfig { X = 100, Y = 100, Width = 300, Height = 300, ClipShape = ClipShape.Round };
|
||||
var imageA = new Source { Type = SourceType.Image, X = 1200, Y = 600, Width = 200, Height = 200 };
|
||||
var imageB = new Source
|
||||
@@ -74,7 +74,7 @@ public class SceneCompositorTests
|
||||
};
|
||||
|
||||
var scene = new Scene { Name = "Live" };
|
||||
scene.Elements.Add(backdrop);
|
||||
scene.Elements.Add(background);
|
||||
scene.Elements.Add(roundWebcam);
|
||||
scene.Elements.Add(imageA);
|
||||
scene.Elements.Add(imageB);
|
||||
@@ -82,7 +82,7 @@ public class SceneCompositorTests
|
||||
VideoFrame? FrameFor(SceneElement e) => e switch
|
||||
{
|
||||
WebcamSceneConfig => green,
|
||||
Source { IsBackdrop: true } => red,
|
||||
Source { IsBackground: true } => red,
|
||||
Source { Type: SourceType.Image } => split,
|
||||
_ => null,
|
||||
};
|
||||
@@ -98,11 +98,11 @@ public class SceneCompositorTests
|
||||
Assert.Equal(1920, output.Width);
|
||||
Assert.Equal(1080, output.Height);
|
||||
|
||||
// backdrop at the frame corner
|
||||
// background at the frame corner
|
||||
AssertColor(output, 0, 0, 255, 0, 0);
|
||||
// round webcam: center is the (square-cropped) webcam feed
|
||||
AssertColor(output, 250, 250, 0, 255, 0);
|
||||
// round webcam: element-square corner is OUTSIDE the circle -> backdrop shows
|
||||
// round webcam: element-square corner is OUTSIDE the circle -> background shows
|
||||
AssertColor(output, 101, 101, 255, 0, 0);
|
||||
// imageA (unmirrored): left half cyan, right half magenta
|
||||
AssertColor(output, 1220, 700, 0, 255, 255);
|
||||
@@ -120,16 +120,16 @@ public class SceneCompositorTests
|
||||
var red = Solid(1920, 1080, 255, 0, 0);
|
||||
var green = Solid(1280, 720, 0, 255, 0);
|
||||
|
||||
var backdrop = new Source { Type = SourceType.DisplayCapture, IsBackdrop = true, CaptureKey = "monitor:0" };
|
||||
var background = new Source { Type = SourceType.DisplayCapture, IsBackground = true, CaptureKey = "monitor:0" };
|
||||
var roundWebcam = new WebcamSceneConfig { X = 656, Y = 100, Width = 300, Height = 300, ClipShape = ClipShape.Round };
|
||||
var scene = new Scene { Name = "Live" };
|
||||
scene.Elements.Add(backdrop);
|
||||
scene.Elements.Add(background);
|
||||
scene.Elements.Add(roundWebcam);
|
||||
|
||||
VideoFrame? FrameFor(SceneElement e) => e switch
|
||||
{
|
||||
WebcamSceneConfig => green,
|
||||
Source { IsBackdrop: true } => red,
|
||||
Source { IsBackground: true } => red,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
@@ -143,11 +143,11 @@ public class SceneCompositorTests
|
||||
|
||||
Assert.Equal(1080, output.Width);
|
||||
Assert.Equal(1920, output.Height);
|
||||
// top-left of the crop is pure backdrop (webcam starts at crop y=100, inset from the corner)
|
||||
// top-left of the crop is pure background (webcam starts at crop y=100, inset from the corner)
|
||||
AssertColor(output, 0, 0, 255, 0, 0);
|
||||
// the webcam center (crop 150,250) scales to output ~(267,444) and stays green
|
||||
AssertColor(output, 267, 444, 0, 255, 0);
|
||||
// far from the webcam, still backdrop
|
||||
// far from the webcam, still background
|
||||
AssertColor(output, 978, 1688, 255, 0, 0);
|
||||
}
|
||||
|
||||
@@ -155,9 +155,9 @@ public class SceneCompositorTests
|
||||
public void Composite_WithFlash_BlendsOverContent()
|
||||
{
|
||||
var red = Solid(1920, 1080, 255, 0, 0);
|
||||
var backdrop = new Source { Type = SourceType.DisplayCapture, IsBackdrop = true, CaptureKey = "monitor:0" };
|
||||
var background = new Source { Type = SourceType.DisplayCapture, IsBackground = true, CaptureKey = "monitor:0" };
|
||||
var scene = new Scene { Name = "Live" };
|
||||
scene.Elements.Add(backdrop);
|
||||
scene.Elements.Add(background);
|
||||
|
||||
// flash: a semi-transparent white pixel at the center of a master-sized frame
|
||||
var flash = new VideoFrame(1920, 1080, new byte[1920 * 1080 * 4]);
|
||||
@@ -185,9 +185,9 @@ public class SceneCompositorTests
|
||||
public void Composite_WithSocialBar_OverlaysAboveFlash_AtTopOrBottom()
|
||||
{
|
||||
var red = Solid(1920, 1080, 255, 0, 0);
|
||||
var backdrop = new Source { Type = SourceType.DisplayCapture, IsBackdrop = true, CaptureKey = "monitor:0" };
|
||||
var background = new Source { Type = SourceType.DisplayCapture, IsBackground = true, CaptureKey = "monitor:0" };
|
||||
var scene = new Scene { Name = "Live" };
|
||||
scene.Elements.Add(backdrop);
|
||||
scene.Elements.Add(background);
|
||||
|
||||
var options = new CompositorOptions
|
||||
{
|
||||
@@ -210,11 +210,11 @@ public class SceneCompositorTests
|
||||
var top = compositor.Render(scene, _ => red, flash, options, bar, 0);
|
||||
AssertColor(top, 0, 0, 0, 255, 0); // bar above flash at the top-left
|
||||
AssertColor(top, 960, 540, 255, 127, 127); // 50% white over red
|
||||
AssertColor(top, 100, 100, 255, 0, 0); // empty overlay area: backdrop
|
||||
AssertColor(top, 100, 100, 255, 0, 0); // empty overlay area: background
|
||||
|
||||
var bottom = compositor.Render(scene, _ => red, flash, options, bar, 1040);
|
||||
AssertColor(bottom, 0, 1040, 0, 255, 0); // bar drawn at the bottom edge
|
||||
AssertColor(bottom, 0, 1039, 255, 0, 0); // backdrop just above the bar
|
||||
AssertColor(bottom, 0, 1039, 255, 0, 0); // background just above the bar
|
||||
AssertColor(bottom, 960, 540, 255, 0, 0); // bar region moved away from center
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user