Skip to content

Commit d4932f8

Browse files
committed
Fresh cut
Signed-off-by: Michael Mattsson <[email protected]>
1 parent 4883810 commit d4932f8

File tree

4 files changed

+198
-44
lines changed

4 files changed

+198
-44
lines changed

README.md

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,51 @@ Options:
1717
--profile TEXT Profile name in --config
1818
--mbps INTEGER Throttle encoder bitrate to Mbit/s, overrides bitrate in
1919
`encoder` sections in --config. Use with caution.
20+
--baseline Apply multiviewer baseline configuration suitable for
21+
streaming.
2022
--debug Turn on very verbose logging and override --config flag.
2123
--help Show this message and exit.
2224
```
2325

2426
Example configuration file.
2527

2628
```yaml
27-
# Orei multi-viewer commands
29+
# Orei multiviewer commands
2830
# https://cdn.shopify.com/s/files/1/1988/4253/files/UHD-401MV-Updated_User_Manual.pdf?v=1672745852
2931

3032
# Magewell encoder API
3133
# https://www.magewell.com/api-docs/pro-convert-encoder-api/
3234
---
3335
config:
3436
local:
37+
# If serial_port can't be found, the .config.mv.ip_addr will be used
3538
serial_port: /dev/cu.usbserial-3
36-
# set to true to ignore encoder when local serial is connected
37-
ignore_encoder: true
38-
debug: true
39+
# Set to true to ignore encoder and encoder sections
40+
ignore_encoder: false
41+
# Do not set to true in production
42+
debug: false
3943
mv:
44+
# Set your preferences
4045
ip_addr: 192.168.37.5
46+
# run `./cli.py --baseline --config config.yaml` to apply baseline on a new
47+
# unit, like disabling HDCP, OSD, auto-switching and window borders.
48+
# vka sets the background color when applying the baseline config
49+
vka: blue # video keep active pattern, blue or black.
50+
51+
# tunables
4152
remote_timeout: 2.0 # Positive float timeout in seconds for IP-based command
4253
# If null is given, the socket is put in blocking mode
4354
command_delay: .1 # Positive float delay after sending a MV command
4455
# Tune this if timeouts are being hit on quad layouts
45-
modes:
46-
3840x2160p60: 3
47-
3840x2160p30: 5
48-
1920x1080p60: 8
49-
scenes:
50-
single: 1
51-
pip: 2 # Not tested
52-
pbp: 3 # Not tested
53-
triple: 4
54-
quad: 5
56+
57+
# All encoder sections are optional if you don't have a compatible encoder.
5558
encoder:
5659
ip_addr: 192.168.37.4
5760
user: Admin
5861
# md5 of your password (this is Admin)
5962
pass: e3afed0047b08059d0fada10f400c1e5
6063
profiles:
61-
default:
64+
main:
6265
mv:
6366
# Keyed from with config.mv.scenes
6467
scene: quad
@@ -95,14 +98,42 @@ profiles:
9598
framerate: raw
9699
# 1920x1080 etc, raw means match input
97100
resolution: 1920x1080
101+
playfield:
102+
mv:
103+
# Keyed from with config.mv.scenes
104+
scene: pip
105+
# Keyed from with config.mv.modes
106+
output: 3840x2160p60
107+
# Consume key (HDMI input) with value (viewport output)
108+
layout:
109+
HDMI-4: 1 # bottom input
110+
HDMI-2: 2 # inlay input
111+
audio: 3
112+
pip: # percentages
113+
size: 25
114+
pos-x: 2
115+
pos-y: 3
116+
encoder:
117+
# 50 - 200 "quality" slider, default is 100, ignored when --mbps is used
118+
bitrate: 200
119+
# frame rate, raw matches input, half, one-third, quarter are valid
120+
framerate: raw
121+
# 1920x1080 etc, raw means match input
122+
resolution: raw
98123
```
99124
100125
## Prequisites and Hardware SKUs
101126
102127
RigC has been developed on a Mac and will most likely just work on Mac and Linux at this time.
103128
104-
- Python scripting needs to be activated in OBS (find instructions for this elsewhere)
105-
- HDCP needs to be disabled on the multiviewer prior use with a capture card
129+
- Python scripting needs to be activated in OBS (find instructions for this elsewhere).
130+
- HDCP needs to be disabled on the multiviewer prior use with a capture card.
131+
132+
RigC now allows baseline configuration of a brand new multiviewer. It will disable HDCP and set other useful defaults.
133+
134+
```
135+
./cli.py --baseline --config config.yaml --debug
136+
```
106137

107138
### Tested (and should work) Hardware
108139

@@ -116,6 +147,13 @@ These share the same MCU on paper.
116147
- Monoprice Blackbird Pro Series 4K60 Multiviewer (not tested)
117148
- NEUVIDEO 4x1 4K60 UHD Quad/PiP/PoP Multiviewer (not tested)
118149

150+
It's recommended to make sure the latest firmware of the MCU and scaler is installed. The latest version of RigC is tested against:
151+
152+
```
153+
MCU FW version 1.00.12
154+
SCALER FW version 20240328-11
155+
```
156+
119157
#### Serial servers
120158

121159
Any serial server that expose the serial interface over Telnet (port 23) should work.
@@ -127,6 +165,8 @@ These are the ones I've gone through.
127165
- StarTech NETRS2321P
128166
- Works out of the box without any configuration except setting an IP address.
129167

168+
**Tip:** If you're looking for a quick and dirty solution to just run a few commands on the multiviewer, check out [CoolTerm](https://coolterm.macupdate.com/). It works for both local and remote serial interfaces and great for debugging.
169+
130170
#### Encoders
131171

132172
Magewell Pro Converters all have the same API. The Ultra Encode series would need work.
@@ -139,10 +179,14 @@ Magewell Pro Converters all have the same API. The Ultra Encode series would nee
139179
- Magewell Pro Convert SDI Plus
140180
- Magewell Pro Convert SDI TX
141181

182+
**Note:** RigC does NOT require an NDI encoder to operate.
183+
142184
## Marketecture
143185

144186
![](assets/README/marketecture.png)
145187

188+
Using the serial interface is optional and RigC can configure a quad or triple view as a set-it-and-forget-it on the multiviewer. The output may be captured by either an encoder remotely or HDMI locally. In such configuration, RigC does not even need to be installed into OBS and can merely be used as a multiviewer configuration tool.
189+
146190
## Demos
147191

148192
A short snippet that describes the benefit of using 4K cameras in single view modes.
@@ -203,6 +247,17 @@ Next, hit that `+` sign and find `rigc.py` in the `rigc` repository.
203247

204248
Please use [issues](/datamattsson/rigc/issues) to report potential issues and ask questions.
205249

250+
## Known Issues and Limitations
251+
252+
Major annoyances and workarounds.
253+
254+
- RigC is inserted synchronously after the scene transition and needs to return an exit code to OBS before becomes usable again. Under normal circumstances this takes less then half a second and is not noticeable by the broadcaster. You will get the spinning beach ball that will eventually freeze the program until RigC times out. Asynchronous execution is on the roadmap for RigC. See also: Next bullet.
255+
- Do NOT run RigC with `--debug` enabled in production. In certain circumstances the serial port read operation gets stuck and takes up to a minute to timeout. Since the OBS script is synchronous, the program will be impacted after a few seconds. Without `--debug`, the serial port is never read, only written to.
256+
- Do NOT run RigC with `--mbps` enabled in production. It's highly volatile and may lock up OBS if configured inappropriately.
257+
- Make sure you have the latest firmware installed for your devices. Contact the vendor to ensure your device is updated, this includes both the encoder and multiviewer.
258+
- Since RigC is inserted AFTER the scene transition the program will see some ugly switching for around half a second. To cover up this, I'm using "Image Slideshows" with an animated GIF that substitutes the scene transition as it runs immediately BEFORE the scene transition and smooths over the switching.
259+
- OBS keeps the names of profiles in the configuration pane dropdowns. If you're switching different configuration files for different purposes, make sure the profile names overlap otherwise you'll lose the dropdown selections. I learned this the hard way.
260+
206261
# Background
207262

208263
In the world of pinball streaming you are dependent of having at least three cameras capturing talent, playfield and score boards wirelessly in a very confined space. A multiviewer is a great device to ingest HDMI signals and output a "grid" of inputs to OBS. The principal caveat of using such a solution is that the input will be a quarter of the original resolution and there is some loss of quality when working with 1080p60 if scaling is involved (I.e stretching 960 to 1080 for the playfield camera). The most common adapted solution is to run one wireless HDMI transmitter/receiver pair per camera but it comes with its own set of challenges.
@@ -213,6 +268,8 @@ Running full NDI over WiFi is considered by industry professionals the dumbest i
213268

214269
A purpose built 2160p60 wireless HDMI transmitter/receiver product from Teradek cost $6,490 last time I checked. RigC is the solution until competition has caught up with Teradek to make 2160p60 wireless affordable and feasible for pinball streaming, RigC costs about a third and is way more flexible than a dedicated 2160p60 transmitter/receiver.
215270

271+
**Edit 2024-12-28**: Accsoon have released an affordable 2160p60 transmitter/receiver ([CineView Master 4K](https://accsoonusa.com/page/cineview-4k/)) that retails for around $900 with the meager bandwidth of 12Mbit/s and it's nowhere near where it needs to be for high definition tournament pinball streaming using a multiviewer.
272+
216273
# License, Contribute and Support RigC
217274

218275
RigC is available under the [MIT](LICENSE) license.

cli.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,29 @@
1414
datefmt='%a, %d %b %Y %H:%M:%S +0000')
1515

1616
class PinballRig:
17-
def __init__(self, config, mbps):
17+
def __init__(self, config, mbps, baseline):
1818
self.config = config
1919
self.mbps = mbps
20+
self.baseline = baseline
2021
self.logger = logging.getLogger(f'{__name__}')
2122
self.logger.setLevel(logging.DEBUG if self.config.get(
2223
'local').get('debug') else logging.INFO)
24+
2325
def configure(self, config, profile):
2426
try:
2527
mv = uhdmcu.FourXOneUHD(config)
26-
mv.apply(profile['mv'])
28+
if profile:
29+
mv.apply(profile.get('mv'))
30+
else:
31+
mv.baseline()
32+
return
2733
except Exception as exc:
2834
self.logger.error(f'Unable to apply MV config: "{exc}"')
2935
raise RigBroke from exc
30-
if not config['local']['ignore_encoder'] or not os.path.exists(config['local']['serial_port']):
36+
if not self.config.get('local').get('ignore_encoder') and profile.get('encoder'):
3137
try:
3238
enc = magewell.ProConvert(config, self.mbps)
33-
enc.apply(profile['encoder'])
39+
enc.apply(profile.get('encoder'))
3440
except Exception as exc:
3541
self.logger.error(f'Unable to apply Encoder config: {exc}')
3642
raise RigBroke from exc
@@ -43,9 +49,10 @@ class RigBroke(Exception):
4349
default='config.yaml', help='config.yaml formatted file')
4450
@click.option('--profile', default='default', help='Profile name in --config')
4551
@click.option('--mbps', default=0, help='Throttle encoder bitrate to Mbit/s, overrides bitrate in `encoder` sections in --config. Use with caution.')
52+
@click.option('--baseline', default=False, help='Apply multiviewer baseline configuration suitable for streaming.', is_flag=True)
4653
@click.option('--debug', default=False, help='Turn on very verbose logging and override --config flag.', is_flag=True)
4754

48-
def apply(config, profile, mbps, debug):
55+
def apply(config, profile, mbps, debug, baseline):
4956

5057
logger = logging.getLogger(f'{__name__}')
5158
if debug:
@@ -64,18 +71,26 @@ def apply(config, profile, mbps, debug):
6471
if debug:
6572
config['local']['debug'] = True
6673

67-
if config and profiles.get(profile):
68-
rig = PinballRig(config, mbps)
74+
if config and profiles.get(profile) and not baseline:
75+
rig = PinballRig(config, mbps, baseline)
6976
try:
7077
rig.configure(config, profiles.get(profile))
7178
logger.debug(f'Rig configured with profile: "{profile}"')
7279
except RigBroke:
7380
logger.error('Failed configuring the rig, check logs.')
7481
sys.exit(1)
82+
elif config and baseline:
83+
rig = PinballRig(config, mbps, baseline)
84+
try:
85+
rig.configure(config, False)
86+
logger.debug(f'Rig baseline configured.')
87+
except RigBroke:
88+
logger.error('Failed applying baseline, check logs.')
89+
sys.exit(1)
7590
else:
7691
logger.error(f'The `config` stanza or profile "{profile}" in the `profiles` \
7792
stanza invalid in --config file')
7893
sys.exit(1)
7994

8095
if __name__ == '__main__':
81-
apply(None, None, None, None)
96+
apply(None, None, None, None, None)

config.yaml-dist

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
1-
# Orei multi-viewer commands
1+
# Orei multiviewer commands
22
# https://cdn.shopify.com/s/files/1/1988/4253/files/UHD-401MV-Updated_User_Manual.pdf?v=1672745852
33

44
# Magewell encoder API
55
# https://www.magewell.com/api-docs/pro-convert-encoder-api/
66
---
77
config:
88
local:
9+
# If serial_port can't be found, the .config.mv.ip_addr will be used
910
serial_port: /dev/cu.usbserial-3
10-
# set to true to ignore encoder when local serial is connected
11-
ignore_encoder: true
12-
debug: true
11+
# Set to true to ignore encoder and encoder sections
12+
ignore_encoder: false
13+
# Do not set to true in production
14+
debug: false
1315
mv:
16+
# Set your preferences
1417
ip_addr: 192.168.37.5
18+
# run `./cli.py --baseline --config config.yaml` to apply baseline on a new
19+
# unit, like disabling HDCP, OSD, auto-switching and window borders.
20+
# vka sets the background color when applying the baseline config
21+
vka: blue # video keep active pattern, blue or black.
22+
23+
# tunables
1524
remote_timeout: 2.0 # Positive float timeout in seconds for IP-based command
1625
# If null is given, the socket is put in blocking mode
1726
command_delay: .1 # Positive float delay after sending a MV command
1827
# Tune this if timeouts are being hit on quad layouts
19-
modes:
20-
3840x2160p60: 3
21-
3840x2160p30: 5
22-
1920x1080p60: 8
23-
scenes:
24-
single: 1
25-
pip: 2 # Not tested
26-
pbp: 3 # Not tested
27-
triple: 4
28-
quad: 5
28+
29+
# All encoder sections are optional if you don't have a compatible encoder.
2930
encoder:
3031
ip_addr: 192.168.37.4
3132
user: Admin
3233
# md5 of your password (this is Admin)
3334
pass: e3afed0047b08059d0fada10f400c1e5
3435
profiles:
35-
default:
36+
main:
3637
mv:
3738
# Keyed from with config.mv.scenes
3839
scene: quad
@@ -69,3 +70,25 @@ profiles:
6970
framerate: raw
7071
# 1920x1080 etc, raw means match input
7172
resolution: 1920x1080
73+
playfield:
74+
mv:
75+
# Keyed from with config.mv.scenes
76+
scene: pip
77+
# Keyed from with config.mv.modes
78+
output: 3840x2160p60
79+
# Consume key (HDMI input) with value (viewport output)
80+
layout:
81+
HDMI-4: 1 # bottom input
82+
HDMI-2: 2 # inlay input
83+
audio: 3
84+
pip: # percentages
85+
size: 25
86+
pos-x: 2
87+
pos-y: 3
88+
encoder:
89+
# 50 - 200 "quality" slider, default is 100, ignored when --mbps is used
90+
bitrate: 200
91+
# frame rate, raw matches input, half, one-third, quarter are valid
92+
framerate: raw
93+
# 1920x1080 etc, raw means match input
94+
resolution: raw

0 commit comments

Comments
 (0)