SDI (Blackmagic DeckLink)
bilbycast-edge can capture and play out SDI directly on Blackmagic
DeckLink cards — video plus embedded audio, with no external SDI→IP
converter in the path. It talks to the Blackmagic SDK through a first-party C++
shim rather than FFmpeg’s decklink avdevice, because the avdevice hides
bmdFrameHasNoInputSource, which makes a pulled cable indistinguishable from a
live feed.
SDI lives behind the sdi-decklink build feature, which is off in a
plain cargo build. This page is about turning it on.
Why there is a build step at all
Section titled “Why there is a build step at all”The Blackmagic SDK is EULA-gated: you have to accept Blackmagic’s licence to download it, and it cannot be redistributed inside this project. Only the SDK headers are needed, and only while compiling.
| Needed at build time | Needed at run time | |
|---|---|---|
SDK headers (DeckLinkAPI.h, DeckLinkAPIDispatch.cpp) |
Yes | No |
libDeckLinkAPI.so (part of Desktop Video) |
No | Yes |
| A physical DeckLink card | No | Yes |
The SDK’s DeckLinkAPIDispatch.cpp loads libDeckLinkAPI.so dynamically at
runtime, so you can compile an SDI-capable binary on a machine with no card and
no driver installed. Conversely, an SDI-capable binary runs perfectly well on a
host with no card: the boot probe finds nothing, the node never advertises the
sdi-decklink capability, and the manager UI hides the SDI input and output
types for it. There is no runtime cost to carrying SDI on a non-SDI host.
Checklist A — build it yourself
Section titled “Checklist A — build it yourself”For anyone building bilbycast-edge from source on their own machine. No GitHub account, private repository, or credential is involved.
-
Download the SDK. Go to blackmagicdesign.com/support, search for “Desktop Video SDK”, choose version 16 or newer, and download it. You will need to complete Blackmagic’s registration form and accept their EULA.
-
Unzip it and locate
Linux/include. That single directory contains bothDeckLinkAPI.handDeckLinkAPIDispatch.cpp. Nothing else from the SDK is used by the build. -
Point
DECKLINK_SDK_DIRat that directory — the directory itself, not its parent:Terminal window export DECKLINK_SDK_DIR=/path/to/Blackmagic_DeckLink_SDK_16.0/Linux/include# Both of these must list. If they don't, you are one level off.ls "$DECKLINK_SDK_DIR"/DeckLinkAPI.h "$DECKLINK_SDK_DIR"/DeckLinkAPIDispatch.cpp -
Build with the feature enabled, alongside whatever else you already use:
Terminal window cargo build --release --features sdi-decklink,video-encoder-x264SDI also needs
media-codecs, which is on by default. If you disable it, both the SDI input and output refuse to start withsdi_no_media_codecs— neither can encode or decode without it. -
Install Desktop Video on the machine with the card, from the same support page. This provides the kernel driver and
libDeckLinkAPI.so. -
Check the operating system sees the card before suspecting the build:
Terminal window ls /dev/blackmagic/ -
Check the edge sees it. Start the edge, then confirm
sdi-decklinkappears in the node’s advertised capabilities and that per-port hardware status is populated. In the manager UI, the SDI input and output types become selectable for that node.
Checklist B — build it in GitHub Actions
Section titled “Checklist B — build it in GitHub Actions”For project maintainers, and for anyone running their own fork’s CI. The
release workflow already requests sdi-decklink for the two *-linux-full
artefacts (the *-rockchip row omits it deliberately) — it strips the feature
at build time when the SDK is unavailable, warns, and continues. So this is
entirely about making the headers reachable from CI. No workflow edit is
required. Once a credential does reach the run, the Verify binary step
asserts the shim symbol is linked in and fails the release if it is not, so the
feature cannot silently rot back out.
The SDK is not vendored into the public repository. It lives in a separate private repository that CI checks out.
-
Download the SDK and locate
Linux/include, exactly as in Checklist A steps 1–2. -
Create a private repository for the headers — for this project,
Bilbycast/bilbycast-decklink-sdk. Private is the point: nothing is redistributed. -
Commit only
Linux/include. NotSamples/, not the shared library, not the installer or PDFs:Terminal window mkdir bilbycast-decklink-sdk && cd bilbycast-decklink-sdkgit initcp -r /path/to/SDK/Linux/include .# Both must exist before you commit.ls include/DeckLinkAPI.h include/DeckLinkAPIDispatch.cppgit add -A && git commit -m "DeckLink SDK 16.0 headers"git tag sdk-16.0git remote add origin git@github.com:Bilbycast/bilbycast-decklink-sdk.gitgit push -u origin main --tagsCI searches for
DeckLinkAPI.hrather than assuming a fixed path, so you can keep the vendor’s directory nesting or flatten it. -
Generate a deploy key — an SSH keypair scoped to that one repository:
Terminal window ssh-keygen -t ed25519 -N "" -C "bilbycast-decklink-sdk deploy key" \-f ~/.ssh/decklink_sdk_deployThis produces
decklink_sdk_deploy(private) anddecklink_sdk_deploy.pub(public). -
Add the public half to the SDK repository: Settings → Deploy keys → Add deploy key, and paste
decklink_sdk_deploy.pub. Leave Allow write access unchecked — CI only needs to read. -
Add the private half to the edge repository: Settings → Secrets and variables → Actions → New repository secret. Name it exactly
DECKLINK_SDK_DEPLOY_KEYand paste the whole private key file, including the-----BEGIN OPENSSH PRIVATE KEY-----and-----END …-----lines. -
Verify before releasing. Push a commit and open the CI run. The
cargo check (sdi-decklink)step should run and pass. If you instead see “SDI compile gate skipped”, the secret is not visible to the run — check the name from step 6. -
Cut a release. In the release run’s build log the preflight prints
OK: DECKLINK_SDK_DEPLOY_KEY is set, and the binary verification printsOK: SDI compiled in (dl_read_frame present). The release notes switch to the SDI-present wording automatically.
To move to a newer SDK later, commit the new headers to the SDK repository. Nothing in bilbycast-edge changes.
Checklist C — allow the device nodes under systemd
Section titled “Checklist C — allow the device nodes under systemd”Only applies if you run the edge from the packaged systemd service. That unit is
hardened with DevicePolicy=closed, so device access is deny-by-default.
Skipping this produces a distinctive and confusing symptom: the node
advertises SDI but enumerates zero cards. The API probe succeeds because it
only needs libDeckLinkAPI.so, which loads fine — but every device open is
denied by the sandbox.
-
See what your card exposes:
Terminal window ls /dev/blackmagic/ -
Check the shipped unit covers them. It grants the
char-blackmagicdevice class plus/dev/blackmagic/io0throughio7. If your host shows nodes outside that set — different names, or more than eight — add matching lines to the unit:DeviceAllow=/dev/blackmagic/<node> rwPaths that don’t exist are ignored with a log warning, so extra entries are harmless.
-
Reload and restart:
Terminal window sudo systemctl daemon-reloadsudo systemctl restart bilbycast-edge -
Confirm the node’s per-port SDI hardware status is now populated.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
DECKLINK_SDK_DIR is not set at build |
Feature enabled without the headers | Checklist A step 3 |
missing …/DeckLinkAPI.h — DECKLINK_SDK_DIR does not look like the SDK's Linux/include |
Pointing at the SDK root, not Linux/include |
Point one level deeper |
Compile errors about IDeckLinkVideoBuffer / StartAccess |
SDK older than 16 | Download SDK 16 or newer |
sdi_no_media_codecs at flow start |
Built with media-codecs disabled |
Rebuild with default features |
| Node advertises SDI but lists zero devices | systemd sandbox blocking device nodes | Checklist C |
| Node does not advertise SDI at all | Desktop Video missing, or binary built without the feature | Install Desktop Video; confirm the feature was enabled |
| Released binary has no SDI | A *-rockchip artefact (never carries it), or a *-full artefact from v0.102.0 or earlier. Confirm with --print-capabilities | grep '^feature sdi-decklink' |
Upgrade to v0.103.0+ for *-full; otherwise Checklist A, or Checklist B then re-release |
| CI logs “SDI compile gate skipped” | No SDK credential visible to that run | Expected on fork PRs; otherwise recheck the secret name |
Related
Section titled “Related”- Supported Protocols — where SDI sits among the input and output types
- Codec Matrix — which encoders you can pair with SDI capture
- Install as a Linux Service — the packaged systemd unit referenced in Checklist C