Skip to content

Commit 7c5b272

Browse files
committed
feat: multiview border support
1 parent 938fdcf commit 7c5b272

9 files changed

+264
-10
lines changed

LibAtem.MockTests/DeviceTestCases.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal static class DeviceTestCases
2323
public static readonly ProtocolVersion Version = ProtocolVersion.V8_1_1;
2424
public static readonly string MiniExtremeIso = "mini-extreme-iso-v8.6.1";
2525
public static readonly string Mini = "mini-v8.3";
26-
public static readonly string Constellation = "constellation-v8.2.3";
26+
public static readonly string Constellation = "constellation-8k-v9.4";
2727
public static readonly string Constellation2MEHD = "constellation-2me-hd-v8.7";
2828
public static readonly string TwoME = "2me-v8.3";
2929
public static readonly string TwoME4K = "";
@@ -50,6 +50,7 @@ internal static class DeviceTestCases
5050
public static readonly string[] MultiviewToggleSafeArea = { TwoME4K, FourME4K, Constellation };
5151
public static readonly string[] MultiviewVuMeters = { TwoME4K, FourME4K, Constellation };
5252
public static readonly string[] MultiviewLabelSample = { TwoME4K, TwoME, Constellation, MiniExtremeIso, Mini };
53+
public static readonly string[] MultiviewBorders = { Constellation };
5354

5455
public static readonly string[] CameraControl = {TwoME, Constellation};
5556
public static readonly string[] SerialPort = { TwoME, Constellation };

LibAtem.MockTests/LibAtem.MockTests.csproj

+6
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@
9898
<None Update="TestFiles\Handshake\constellation-2me-hd-v8.7.data">
9999
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
100100
</None>
101+
<None Update="TestFiles\Handshake\constellation-4me-4k-v9.4.data">
102+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
103+
</None>
104+
<None Update="TestFiles\Handshake\constellation-8k-v9.4.data">
105+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
106+
</None>
101107
<None Update="TestFiles\Handshake\constellation-v8.0.2.data">
102108
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
103109
</None>

LibAtem.MockTests/SdkState/MultiViewerStateBuilder.cs

+19
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ public static void Build(IBMDSwitcher switcher, AtemState state)
4444
info.CanChangeLayout = canChangeLayout != 0;
4545
props.CanAdjustVuMeterOpacity(out int canChangeVuOpacity);
4646
info.CanChangeVuMeterOpacity = canChangeVuOpacity != 0;
47+
48+
props.CanChangeOverlayProperties(out int canChangeOverlayProperties);
49+
info.SupportsOverlayProperties = canChangeOverlayProperties != 0;
50+
51+
if (info.SupportsOverlayProperties)
52+
{
53+
props.GetBorderColor(out double red, out double green, out double blue, out double alpha);
54+
state.BorderColor = new MultiViewerState.BorderColorState() { Red = red, Green = green, Blue = blue, Alpha = alpha };
55+
}
4756
#endif
4857

4958
props.GetLayout(out _BMDSwitcherMultiViewLayout layout);
@@ -83,6 +92,16 @@ public static void Build(IBMDSwitcher switcher, AtemState state)
8392
st.VuMeterEnabled = vuEnabled != 0;
8493
}
8594

95+
if (info.SupportsOverlayProperties)
96+
{
97+
// props.CurrentInputSupportsLabelOverlay((uint)window, out int windowSupportsLabel);
98+
// st.SupportsLabelVisible = windowSupportsLabel != 0;
99+
props.GetLabelVisible((uint)window, out int labelVisible);
100+
st.LabelVisible = labelVisible != 0;
101+
props.GetBorderVisible((uint)window, out int borderVisible);
102+
st.BorderVisible = borderVisible != 0;
103+
}
104+
86105
return st;
87106
}).ToList();
88107

LibAtem.MockTests/SdkState/SdkStateBuilder.cs

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public static AtemState Build(IBMDSwitcher switcher, AtemStateBuilderSettings up
9898
supportsMultiviewer = false;
9999
}
100100
}
101+
multiviewModes.Sort();
101102

102103
var downConvertModes = new List<VideoMode>();
103104
if (supportsDownConvert)
@@ -116,6 +117,7 @@ public static AtemState Build(IBMDSwitcher switcher, AtemStateBuilderSettings up
116117
supportsDownConvert = false;
117118
}
118119
}
120+
downConvertModes.Sort();
119121

120122
modes.Add(new VideoModeInfo
121123
{

LibAtem.MockTests/TestFiles/Handshake/constellation-8k-v9.4.data

+108
Large diffs are not rendered by default.

LibAtem.MockTests/TestHandshakeState.cs

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ private void RunTest(string caseId)
123123

124124
using var server = new AtemMockServer("127.0.0.1", commandData, DeviceTestCases.Version);
125125
var stateSettings = new AtemStateBuilderSettings();
126+
stateSettings.IgnoreUnknownCameraControlProperties = true;
126127
using var helper = new AtemSdkClientWrapper("127.0.0.1", stateSettings, 1);
127128

128129
var libAtemState = AtemTestHelper.SanitiseStateIncompabalities(DeviceTestCases.Version,

LibAtem.MockTests/TestMultiview.cs

+124-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using BMDSwitcherAPI;
66
using LibAtem.Commands;
77
using LibAtem.Commands.Settings.Multiview;
8+
using LibAtem.Commands.SuperSource;
89
using LibAtem.Common;
910
using LibAtem.MockTests.SdkState;
1011
using LibAtem.MockTests.Util;
@@ -67,7 +68,7 @@ public void TestLayout()
6768
stateBefore.Settings.MultiViewers[(int)mv.Item1].Properties.Layout = newValue;
6869
helper.SendAndWaitForChange(stateBefore, () =>
6970
{
70-
mv.Item2.SetLayout((_BMDSwitcherMultiViewLayout) newValue);
71+
mv.Item2.SetLayout((_BMDSwitcherMultiViewLayout)newValue);
7172
});
7273
}
7374
}
@@ -86,7 +87,7 @@ public void TestSwapProgramPreview()
8687
Assert.Equal(1, supportsSwap);
8788

8889
AtemState stateBefore = helper.Helper.BuildLibState();
89-
MultiViewerState mvState = stateBefore.Settings.MultiViewers[(int) mv.Item1];
90+
MultiViewerState mvState = stateBefore.Settings.MultiViewers[(int)mv.Item1];
9091

9192
for (int i = 0; i < 5; i++)
9293
{
@@ -123,7 +124,7 @@ public void TestToggleSafeAreaEnabled()
123124
mv.Item2.SupportsQuadrantLayout(out int supportsQuadrant);
124125

125126
int[] windows = supportsQuadrant == 0
126-
? new[] {0, 1}
127+
? new[] { 0, 1 }
127128
: Randomiser.SelectionOfGroup(Enumerable.Range(0, 16).ToList()).ToArray();
128129

129130
foreach (int window in windows)
@@ -132,10 +133,10 @@ public void TestToggleSafeAreaEnabled()
132133
for (int i = 0; i < 5; i++)
133134
{
134135
bool newValue = i % 2 == 0;
135-
stateBefore.Settings.MultiViewers[(int) mv.Item1].Windows[window].SafeAreaEnabled = newValue;
136+
stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window].SafeAreaEnabled = newValue;
136137

137138
helper.SendAndWaitForChange(stateBefore,
138-
() => { mv.Item2.SetSafeAreaEnabled((uint) window, newValue ? 1 : 0); });
139+
() => { mv.Item2.SetSafeAreaEnabled((uint)window, newValue ? 1 : 0); });
139140
}
140141
}
141142
}
@@ -206,7 +207,7 @@ public void TestVuMeterOpacity()
206207
for (int i = 0; i < 5; i++)
207208
{
208209
double newValue = Randomiser.Range(0, 100);
209-
stateBefore.Settings.MultiViewers[(int) mv.Item1].VuMeterOpacity = newValue;
210+
stateBefore.Settings.MultiViewers[(int)mv.Item1].VuMeterOpacity = newValue;
210211

211212
helper.SendAndWaitForChange(stateBefore,
212213
() => { mv.Item2.SetVuMeterOpacity(newValue / 100); });
@@ -264,7 +265,7 @@ public void TestWindowSupportsVuMeterEnabled()
264265
foreach (int window in windows)
265266
{
266267
AtemState stateBefore = helper.Helper.BuildLibState();
267-
MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int) mv.Item1].Windows[window];
268+
MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window];
268269

269270
MultiviewWindowInputGetCommand cmd = cmds.Single(c => c.WindowIndex == window && c.MultiviewIndex == mv.Item1);
270271

@@ -368,7 +369,7 @@ public void TestSource()
368369

369370
helper.SendAndWaitForChange(stateBefore, () =>
370371
{
371-
mv.Item2.SetWindowInput((uint) window, (long) src);
372+
mv.Item2.SetWindowInput((uint)window, (long)src);
372373
});
373374
}
374375
}
@@ -388,5 +389,120 @@ private static IEnumerable<ICommand> SourceCommandHandler(Lazy<ImmutableList<ICo
388389
}
389390
}
390391

392+
[Fact]
393+
public void TestWindowLabelVisible()
394+
{
395+
var handler = CommandGenerator.CreateAutoCommandHandler<MultiviewWindowOverlaySetCommand, MultiviewWindowOverlayGetCommand>("LabelVisible", true);
396+
397+
AtemMockServerWrapper.Each(_output, _pool, handler, DeviceTestCases.MultiviewBorders, helper =>
398+
{
399+
foreach (Tuple<uint, IBMDSwitcherMultiView> mv in GetMultiviewers(helper))
400+
{
401+
// TODO: re-enable this
402+
// mv.Item2.CanChangeOverlayProperties(out int supported);
403+
// Assert.Equal(1, supported);
404+
405+
int[] windows = Randomiser
406+
.SelectionOfGroup(Enumerable.Range(0, 16).ToList()).ToArray();
407+
408+
foreach (int window in windows)
409+
{
410+
AtemState stateBefore = helper.Helper.BuildLibState();
411+
MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window];
412+
413+
for (int i = 0; i < 5; i++)
414+
{
415+
bool newValue = i % 2 == 0;
416+
windowState.LabelVisible = newValue;
417+
418+
helper.SendAndWaitForChange(stateBefore, () =>
419+
{
420+
mv.Item2.SetLabelVisible((uint)window, newValue ? 1 : 0);
421+
});
422+
}
423+
}
424+
}
425+
});
426+
}
427+
428+
[Fact]
429+
public void TestWindowBorderVisible()
430+
{
431+
var handler = CommandGenerator.CreateAutoCommandHandler<MultiviewWindowOverlaySetCommand, MultiviewWindowOverlayGetCommand>("BorderVisible", true);
432+
433+
AtemMockServerWrapper.Each(_output, _pool, handler, DeviceTestCases.MultiviewBorders, helper =>
434+
{
435+
foreach (Tuple<uint, IBMDSwitcherMultiView> mv in GetMultiviewers(helper))
436+
{
437+
// TODO: re-enable this
438+
// mv.Item2.CanChangeOverlayProperties(out int supported);
439+
// Assert.Equal(1, supported);
440+
441+
int[] windows = Randomiser
442+
.SelectionOfGroup(Enumerable.Range(0, 16).ToList()).ToArray();
443+
444+
foreach (int window in windows)
445+
{
446+
AtemState stateBefore = helper.Helper.BuildLibState();
447+
MultiViewerState.WindowState windowState = stateBefore.Settings.MultiViewers[(int)mv.Item1].Windows[window];
448+
449+
for (int i = 0; i < 5; i++)
450+
{
451+
bool newValue = i % 2 == 0;
452+
windowState.BorderVisible = newValue;
453+
454+
helper.SendAndWaitForChange(stateBefore, () =>
455+
{
456+
mv.Item2.SetBorderVisible((uint)window, newValue ? 1 : 0);
457+
});
458+
}
459+
}
460+
}
461+
});
462+
}
463+
464+
[Fact]
465+
public void TestBorderColor()
466+
{
467+
var expectedCmd = new MultiviewBorderColorGetCommand();
468+
var handler = CommandGenerator.EchoCommand(expectedCmd);
469+
470+
AtemMockServerWrapper.Each(_output, _pool, handler, DeviceTestCases.MultiviewBorders, helper =>
471+
{
472+
foreach (Tuple<uint, IBMDSwitcherMultiView> mv in GetMultiviewers(helper))
473+
{
474+
// TODO: re-enable this
475+
// mv.Item2.CanChangeOverlayProperties(out int supported);
476+
// Assert.Equal(1, supported);
477+
478+
479+
AtemState stateBefore = helper.Helper.BuildLibState();
480+
MultiViewerState mvState = stateBefore.Settings.MultiViewers[(int)mv.Item1];
481+
482+
for (int i = 0; i < 5; i++)
483+
{
484+
expectedCmd.MultiviewIndex = mv.Item1;
485+
expectedCmd.Red = Randomiser.Range(0, 1, 100);
486+
expectedCmd.Green = Randomiser.Range(0, 1, 100);
487+
expectedCmd.Blue = Randomiser.Range(0, 1, 100);
488+
expectedCmd.Alpha = Randomiser.Range(0, 1, 100);
489+
490+
mvState.BorderColor = new MultiViewerState.BorderColorState
491+
{
492+
Red = expectedCmd.Red,
493+
Green = expectedCmd.Green,
494+
Blue = expectedCmd.Blue,
495+
Alpha = expectedCmd.Alpha
496+
};
497+
498+
helper.SendAndWaitForChange(stateBefore, () =>
499+
{
500+
mv.Item2.SetBorderColor(expectedCmd.Red, expectedCmd.Green, expectedCmd.Blue, expectedCmd.Alpha);
501+
});
502+
503+
}
504+
}
505+
});
506+
}
391507
}
392508
}

LibAtem.MockTests/Util/AtemServerClientPool.cs

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public AtemServerClientPool()
138138
{
139139
_pool = new Dictionary<string, AtemMockServerPoolItem>();
140140
StateSettings = new AtemStateBuilderSettings();
141+
StateSettings.IgnoreUnknownCameraControlProperties = true;
141142
}
142143

143144
public AtemMockServerPoolItem GetCase(string caseId)

0 commit comments

Comments
 (0)