pub struct FrameSync { /* private fields */ }Expand description
Frame synchronizer for clock-corrected capture.
Converts push-based NDI streams into pull-based capture with automatic time-base correction and dynamic audio resampling.
§Ownership
FrameSync takes ownership of the Receiver (similar to how BufWriter
wraps a Write). Use receiver() to access the underlying
receiver for tally, PTZ, or status operations. Use
into_receiver() to recover the receiver when done.
§Thread Safety
FrameSync is Send + Sync like Receiver, as the underlying NDI SDK
frame-sync functions are thread-safe. However, frames returned by capture
methods borrow from the FrameSync and are not Send.
§Example
let framesync = FrameSync::new(receiver)?;
// FrameSync captures always return immediately
if let Some(video) = framesync.capture_video(ScanType::Progressive)? {
println!("Video: {}x{}", video.width(), video.height());
}
// Audio capture uses an explicit request; None means "use source value".
let audio = framesync.capture_audio(FrameSyncAudioRequest::Capture {
sample_rate: Some(NonZeroI32::new(48_000).unwrap()),
channels: Some(NonZeroI32::new(2).unwrap()),
samples: NonZeroI32::new(1_024).unwrap(),
})?;
println!("Audio: {} samples", audio.num_samples());Implementations§
Source§impl FrameSync
impl FrameSync
Sourcepub fn new(receiver: Receiver) -> Result<Self>
pub fn new(receiver: Receiver) -> Result<Self>
Create a frame synchronizer from a receiver.
Takes ownership of the receiver. Use receiver()
to access the underlying receiver for tally, PTZ, or status operations.
Use into_receiver() to recover the receiver.
§Errors
Returns an error if the NDI SDK fails to create the frame-sync instance.
§Example
let receiver = Receiver::new(&ndi, &options)?;
let framesync = FrameSync::new(receiver)?;Sourcepub fn receiver(&self) -> &Receiver
pub fn receiver(&self) -> &Receiver
Access the underlying receiver.
Use this to access receiver functionality like tally, PTZ, or status queries while the FrameSync is active.
Sourcepub fn into_receiver(self) -> Receiver
pub fn into_receiver(self) -> Receiver
Consume the FrameSync and recover the underlying Receiver.
This destroys the frame synchronizer and returns the receiver for continued use with raw capture or for creating a new FrameSync.
Sourcepub fn capture_video(
&self,
field_type: ScanType,
) -> Result<Option<FrameSyncVideoRef<'_>>>
pub fn capture_video( &self, field_type: ScanType, ) -> Result<Option<FrameSyncVideoRef<'_>>>
Capture video with time-base correction.
This function always returns immediately. It returns the best frame for the current output timing, handling clock drift and jitter automatically. The same frame may be returned multiple times when capture rate exceeds source frame rate.
§Arguments
field_type- The desired field format. UseScanType::Progressivefor most applications. For interlaced output, use the appropriate field type to maintain correct field ordering.
§Returns
Ok(Some(FrameSyncVideoRef))- A validated zero-copy reference to the captured frameOk(None)- The SDK returned the documented all-zero “no video yet” stateErr(Error::InvalidFrame(_))- The SDK returned non-empty malformed metadata
§Example
let framesync = FrameSync::new(receiver)?;
// Capture loop - call at your output frame rate
loop {
if let Some(frame) = framesync.capture_video(ScanType::Progressive)? {
// Process/display frame
println!("{}x{} @ {}/{} fps",
frame.width(), frame.height(),
frame.frame_rate_n(), frame.frame_rate_d());
} else {
// No video received yet - display placeholder
println!("Waiting for video...");
}
}Sourcepub fn capture_video_owned(
&self,
field_type: ScanType,
) -> Result<Option<VideoFrame>>
pub fn capture_video_owned( &self, field_type: ScanType, ) -> Result<Option<VideoFrame>>
Capture video and convert to an owned frame.
This is a convenience method that captures video and immediately converts
it to an owned VideoFrame that can be sent across threads.
§Arguments
field_type- The desired field format.
§Returns
Ok(Some(VideoFrame))- An owned copy of the captured frameOk(None)- No video has been received yet
§Errors
Returns an error if the SDK returns non-empty malformed frame metadata.
Sourcepub fn capture_audio(
&self,
request: FrameSyncAudioRequest,
) -> Result<FrameSyncAudioRef<'_>>
pub fn capture_audio( &self, request: FrameSyncAudioRequest, ) -> Result<FrameSyncAudioRef<'_>>
Capture audio with dynamic resampling.
This function always returns immediately. Capture requests ask the NDI SDK to resample incoming audio to match the requested sample rate, channel count, and sample count. Query requests return the current input format without requesting samples.
Call this at the rate you need audio - the SDK will adapt the incoming signal to match your output timing using dynamic audio sampling.
§Arguments
request- Explicit capture or query operation. For capture requests,Nonesample rate or channels means “use the current source value”.
§Querying Input Format
Use FrameSyncAudioRequest::QueryInput to query the current input
format without capturing samples. The returned frame contains the
input’s sample rate and channel count, or a validated empty no-source
state when no audio format has been received yet.
§Errors
Returns Error::InvalidFrame if the SDK returns malformed audio
metadata, or Error::InvalidConfiguration if the request contains a
negative NonZeroI32 value.
§Example
let framesync = FrameSync::new(receiver)?;
// Audio callback - called by sound card at its rate
let request = FrameSyncAudioRequest::Capture {
sample_rate: Some(NonZeroI32::new(48_000).unwrap()),
channels: Some(NonZeroI32::new(2).unwrap()),
samples: NonZeroI32::new(1_024).unwrap(),
};
loop {
// Request 1024 stereo samples at 48kHz
let audio = framesync.capture_audio(request)?;
// Process audio samples
let samples = audio.data();
println!("Got {} samples", samples.len());
// Check for a validated query/no-source empty state
if audio.is_empty() {
println!("No audio source yet");
}
}Sourcepub fn capture_audio_owned(
&self,
request: FrameSyncAudioRequest,
) -> Result<Option<AudioFrame>>
pub fn capture_audio_owned( &self, request: FrameSyncAudioRequest, ) -> Result<Option<AudioFrame>>
Capture audio and convert to an owned frame.
This is a convenience method that captures audio and immediately converts
it to an owned AudioFrame that can be sent across threads. Query or
no-source states that contain no sample buffer return Ok(None).
§Arguments
request- Explicit capture or query operation.
§Errors
Returns an error if the request is invalid or the SDK returns malformed audio metadata.
Sourcepub fn audio_queue_depth(&self) -> i32
pub fn audio_queue_depth(&self) -> i32
Query the current audio queue depth.
Returns the approximate number of audio samples currently buffered. This can be useful when using an inaccurate timer for audio playback.
Note: This value may change immediately after being read as new
samples are continuously received. For most applications, simply call
capture_audio at your desired rate and let the SDK handle timing.
§Example
let framesync = FrameSync::new(receiver)?;
// Check available samples before capture
let available = framesync.audio_queue_depth();
println!("Audio samples available: {}", available);Trait Implementations§
impl Send for FrameSync
§Safety
The NDI SDK documentation states that framesync operations are thread-safe. The FrameSync struct only holds an opaque pointer returned by the SDK.
impl Sync for FrameSync
§Safety
The NDI SDK guarantees that framesync capture functions are internally synchronized and can be called concurrently from multiple threads.