2.7 KiB
DeckLink Output Node — Architecture Plan
What you'll build
shared/DeckLinkSender.hpp— analogous toDeckLinkReceiver.hppnodes/decklinkout/main.cpp+CMakeLists.txt
The key difference: scheduled playback
DeckLink output uses a pull model — the card calls you when it needs frames, rather than you reading when a frame arrives.
Steps:
EnableVideoOutput(mode, bmdVideoOutputFlagDefault)EnableAudioOutput(48kHz, int32, channels, bmdAudioOutputStreamContinuous)- Allocate a pool of ~3
IDeckLinkMutableVideoFrameobjects viaCreateVideoFrame - Pre-fill and
ScheduleVideoFramethose 3 frames to prime the pipeline StartScheduledPlayback(0, fps_num, 1.0)- The card fires
ScheduledFrameCompletedcallback when a frame has been displayed — fill it with the next grain and re-schedule it
Audio is pushed separately:
ScheduleAudioSamples(buf, count, stream_time, timescale, &written) — no callback,
just keep it full.
DeckLinkSender.hpp public API
Use a condition variable the same way as the receiver, but inverted — the callback signals that a frame slot is free:
DeckLinkSender:
start_output(device_index, width, height, fps_num, fps_den, channels)
submit_frame(const uint8_t* src, uint32_t stride) // blocks until a slot is free
submit_audio(const float* planar, int samples) // non-blocking push
Implementation steps
-
nodes/decklinkout/CMakeLists.txt— copy fromdecklinkin, rename target todmf-node-decklinkout -
shared/DeckLinkSender.hppenumerate_devices()— identical to receiverstart_output():EnableVideoOutput→EnableAudioOutput→ allocate 3 frames → pre-fill with black →StartScheduledPlaybackOutputCallback(nested private class) implementingIDeckLinkVideoOutputCallback::ScheduledFrameCompleted— pushes freed frame back to a queue, signals a CVsubmit_frame(): waits for a free frame from the queue,memcpysrc → frame, callScheduleVideoFramesubmit_audio(): convert float32 planar → int32 interleaved (reverse of receiver), then callScheduleAudioSamples
-
nodes/decklinkout/main.cpp— create MXL flow readers, detect format, create sender, loop reading grains and callingsubmit_frame/submit_audio
Gotcha: stream time
The stream_time passed to ScheduleVideoFrame must be monotonically increasing in
units of fps_num (the timescale passed to StartScheduledPlayback).
Easiest approach: keep a counter and pass frame_count * fps_den as the stream time.
ScheduleVideoFrame(frame, frame_count * fps_den, fps_den, fps_num);
frame_count++;