ndi: Re-organize code a bit and don't make internal modules public

This commit is contained in:
Sebastian Dröge 2022-10-12 21:57:34 +03:00
parent 0a2e6e47c9
commit 53b02a82ae
4 changed files with 56 additions and 48 deletions

View file

@ -1,24 +1,22 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
#[allow(dead_code)]
mod ndi;
#[allow(dead_code)]
mod ndisys;
mod device_provider; mod device_provider;
pub mod ndi;
#[cfg(feature = "sink")] #[cfg(feature = "sink")]
mod ndisink; mod ndisink;
#[cfg(feature = "sink")] #[cfg(feature = "sink")]
mod ndisinkcombiner; mod ndisinkcombiner;
#[cfg(feature = "sink")] #[cfg(feature = "sink")]
pub mod ndisinkmeta; mod ndisinkmeta;
mod ndisrc; mod ndisrc;
mod ndisrcdemux; mod ndisrcdemux;
pub mod ndisrcmeta; mod ndisrcmeta;
pub mod ndisys;
pub mod receiver;
use crate::ndi::*;
use crate::ndisys::*;
use crate::receiver::*;
use std::time;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -82,8 +80,10 @@ pub enum RecvColorFormat {
CompressedV5WithAudio = 13, CompressedV5WithAudio = 13,
} }
impl From<RecvColorFormat> for NDIlib_recv_color_format_e { impl From<RecvColorFormat> for crate::ndisys::NDIlib_recv_color_format_e {
fn from(v: RecvColorFormat) -> Self { fn from(v: RecvColorFormat) -> Self {
use crate::ndisys::*;
match v { match v {
RecvColorFormat::BgrxBgra => NDIlib_recv_color_format_BGRX_BGRA, RecvColorFormat::BgrxBgra => NDIlib_recv_color_format_BGRX_BGRA,
RecvColorFormat::UyvyBgra => NDIlib_recv_color_format_UYVY_BGRA, RecvColorFormat::UyvyBgra => NDIlib_recv_color_format_UYVY_BGRA,

View file

@ -13,14 +13,11 @@ use std::u32;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::ndisys; use crate::ndisys;
use crate::ndisrcmeta;
use crate::Buffer;
use crate::Receiver;
use crate::ReceiverControlHandle;
use crate::ReceiverItem;
use crate::RecvColorFormat; use crate::RecvColorFormat;
use crate::TimestampMode; use crate::TimestampMode;
use super::receiver::{self, Buffer, Receiver, ReceiverControlHandle, ReceiverItem};
use crate::ndisrcmeta;
use crate::DEFAULT_RECEIVER_NDI_NAME; use crate::DEFAULT_RECEIVER_NDI_NAME;
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
@ -61,9 +58,9 @@ impl Default for Settings {
} }
struct State { struct State {
video_info: Option<crate::VideoInfo>, video_info: Option<receiver::VideoInfo>,
video_caps: Option<gst::Caps>, video_caps: Option<gst::Caps>,
audio_info: Option<crate::AudioInfo>, audio_info: Option<receiver::AudioInfo>,
audio_caps: Option<gst::Caps>, audio_caps: Option<gst::Caps>,
current_latency: Option<gst::ClockTime>, current_latency: Option<gst::ClockTime>,
receiver: Option<Receiver>, receiver: Option<Receiver>,

View file

@ -3,6 +3,7 @@
use glib::prelude::*; use glib::prelude::*;
mod imp; mod imp;
mod receiver;
glib::wrapper! { glib::wrapper! {
pub struct NdiSrc(ObjectSubclass<imp::NdiSrc>) @extends gst_base::BaseSrc, gst::Element, gst::Object; pub struct NdiSrc(ObjectSubclass<imp::NdiSrc>) @extends gst_base::BaseSrc, gst::Element, gst::Object;

View file

@ -11,10 +11,16 @@ use std::cmp;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Condvar, Mutex, Weak}; use std::sync::{Arc, Condvar, Mutex, Weak};
use std::thread; use std::thread;
use std::time;
use atomic_refcell::AtomicRefCell; use atomic_refcell::AtomicRefCell;
use super::*; use once_cell::sync::Lazy;
use crate::ndi::*;
use crate::ndisys;
use crate::ndisys::*;
use crate::TimestampMode;
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new( gst::DebugCategory::new(
@ -29,14 +35,15 @@ pub struct Receiver(Arc<ReceiverInner>);
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum AudioInfo { pub enum AudioInfo {
AudioInfo(gst_audio::AudioInfo), Audio(gst_audio::AudioInfo),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
OpusInfo { #[allow(dead_code)]
Opus {
sample_rate: i32, sample_rate: i32,
no_channels: i32, no_channels: i32,
}, },
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
AacInfo { Aac {
sample_rate: i32, sample_rate: i32,
no_channels: i32, no_channels: i32,
codec_data: [u8; 2], codec_data: [u8; 2],
@ -46,9 +53,9 @@ pub enum AudioInfo {
impl AudioInfo { impl AudioInfo {
pub fn to_caps(&self) -> Result<gst::Caps, glib::BoolError> { pub fn to_caps(&self) -> Result<gst::Caps, glib::BoolError> {
match self { match self {
AudioInfo::AudioInfo(ref info) => info.to_caps(), AudioInfo::Audio(ref info) => info.to_caps(),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
AudioInfo::OpusInfo { AudioInfo::Opus {
sample_rate, sample_rate,
no_channels, no_channels,
} => Ok(gst::Caps::builder("audio/x-opus") } => Ok(gst::Caps::builder("audio/x-opus")
@ -57,7 +64,7 @@ impl AudioInfo {
.field("channel-mapping-family", 0i32) .field("channel-mapping-family", 0i32)
.build()), .build()),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
AudioInfo::AacInfo { AudioInfo::Aac {
sample_rate, sample_rate,
no_channels, no_channels,
codec_data, codec_data,
@ -74,7 +81,7 @@ impl AudioInfo {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum VideoInfo { pub enum VideoInfo {
VideoInfo(gst_video::VideoInfo), Video(gst_video::VideoInfo),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
SpeedHQInfo { SpeedHQInfo {
variant: String, variant: String,
@ -87,7 +94,7 @@ pub enum VideoInfo {
interlace_mode: gst_video::VideoInterlaceMode, interlace_mode: gst_video::VideoInterlaceMode,
}, },
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
H264Info { H264 {
xres: i32, xres: i32,
yres: i32, yres: i32,
fps_n: i32, fps_n: i32,
@ -97,7 +104,7 @@ pub enum VideoInfo {
interlace_mode: gst_video::VideoInterlaceMode, interlace_mode: gst_video::VideoInterlaceMode,
}, },
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
H265Info { H265 {
xres: i32, xres: i32,
yres: i32, yres: i32,
fps_n: i32, fps_n: i32,
@ -111,7 +118,7 @@ pub enum VideoInfo {
impl VideoInfo { impl VideoInfo {
pub fn to_caps(&self) -> Result<gst::Caps, glib::BoolError> { pub fn to_caps(&self) -> Result<gst::Caps, glib::BoolError> {
match self { match self {
VideoInfo::VideoInfo(ref info) => info.to_caps(), VideoInfo::Video(ref info) => info.to_caps(),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
VideoInfo::SpeedHQInfo { VideoInfo::SpeedHQInfo {
ref variant, ref variant,
@ -131,7 +138,7 @@ impl VideoInfo {
.field("variant", variant) .field("variant", variant)
.build()), .build()),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
VideoInfo::H264Info { VideoInfo::H264 {
xres, xres,
yres, yres,
fps_n, fps_n,
@ -150,7 +157,7 @@ impl VideoInfo {
.field("alignment", "au") .field("alignment", "au")
.build()), .build()),
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
VideoInfo::H265Info { VideoInfo::H265 {
xres, xres,
yres, yres,
fps_n, fps_n,
@ -639,17 +646,20 @@ impl Receiver {
} }
} }
#[allow(dead_code)]
pub fn set_flushing(&self, flushing: bool) { pub fn set_flushing(&self, flushing: bool) {
let mut queue = (self.0.queue.0).0.lock().unwrap(); let mut queue = (self.0.queue.0).0.lock().unwrap();
queue.flushing = flushing; queue.flushing = flushing;
(self.0.queue.0).1.notify_all(); (self.0.queue.0).1.notify_all();
} }
#[allow(dead_code)]
pub fn set_playing(&self, playing: bool) { pub fn set_playing(&self, playing: bool) {
let mut queue = (self.0.queue.0).0.lock().unwrap(); let mut queue = (self.0.queue.0).0.lock().unwrap();
queue.playing = playing; queue.playing = playing;
} }
#[allow(dead_code)]
pub fn shutdown(&self) { pub fn shutdown(&self) {
let mut queue = (self.0.queue.0).0.lock().unwrap(); let mut queue = (self.0.queue.0).0.lock().unwrap();
queue.shutdown = true; queue.shutdown = true;
@ -1111,7 +1121,7 @@ impl Receiver {
builder = builder.field_order(gst_video::VideoFieldOrder::TopFieldFirst); builder = builder.field_order(gst_video::VideoFieldOrder::TopFieldFirst);
} }
return Ok(VideoInfo::VideoInfo(builder.build().map_err(|_| { return Ok(VideoInfo::Video(builder.build().map_err(|_| {
gst::element_error!( gst::element_error!(
element, element,
gst::StreamError::Format, gst::StreamError::Format,
@ -1139,7 +1149,7 @@ impl Receiver {
builder = builder.field_order(gst_video::VideoFieldOrder::TopFieldFirst); builder = builder.field_order(gst_video::VideoFieldOrder::TopFieldFirst);
} }
return Ok(VideoInfo::VideoInfo(builder.build().map_err(|_| { return Ok(VideoInfo::Video(builder.build().map_err(|_| {
gst::element_error!( gst::element_error!(
element, element,
gst::StreamError::Format, gst::StreamError::Format,
@ -1222,7 +1232,7 @@ impl Receiver {
return Err(gst::FlowError::Error); return Err(gst::FlowError::Error);
} }
return Ok(VideoInfo::H264Info { return Ok(VideoInfo::H264 {
xres: video_frame.xres(), xres: video_frame.xres(),
yres: video_frame.yres(), yres: video_frame.yres(),
fps_n: video_frame.frame_rate().0, fps_n: video_frame.frame_rate().0,
@ -1260,7 +1270,7 @@ impl Receiver {
return Err(gst::FlowError::Error); return Err(gst::FlowError::Error);
} }
return Ok(VideoInfo::H265Info { return Ok(VideoInfo::H265 {
xres: video_frame.xres(), xres: video_frame.xres(),
yres: video_frame.yres(), yres: video_frame.yres(),
fps_n: video_frame.frame_rate().0, fps_n: video_frame.frame_rate().0,
@ -1295,14 +1305,14 @@ impl Receiver {
gst::ReferenceTimestampMeta::add( gst::ReferenceTimestampMeta::add(
buffer, buffer,
&*TIMECODE_CAPS, &*crate::TIMECODE_CAPS,
gst::ClockTime::from_nseconds(video_frame.timecode() as u64 * 100), gst::ClockTime::from_nseconds(video_frame.timecode() as u64 * 100),
gst::ClockTime::NONE, gst::ClockTime::NONE,
); );
if video_frame.timestamp() != ndisys::NDIlib_recv_timestamp_undefined { if video_frame.timestamp() != ndisys::NDIlib_recv_timestamp_undefined {
gst::ReferenceTimestampMeta::add( gst::ReferenceTimestampMeta::add(
buffer, buffer,
&*TIMESTAMP_CAPS, &*crate::TIMESTAMP_CAPS,
gst::ClockTime::from_nseconds(video_frame.timestamp() as u64 * 100), gst::ClockTime::from_nseconds(video_frame.timestamp() as u64 * 100),
gst::ClockTime::NONE, gst::ClockTime::NONE,
); );
@ -1355,7 +1365,7 @@ impl Receiver {
video_frame: &VideoFrame, video_frame: &VideoFrame,
) -> Result<gst::Buffer, gst::FlowError> { ) -> Result<gst::Buffer, gst::FlowError> {
match info { match info {
VideoInfo::VideoInfo(ref info) => { VideoInfo::Video(ref info) => {
let src = video_frame.data().ok_or(gst::FlowError::Error)?; let src = video_frame.data().ok_or(gst::FlowError::Error)?;
let buffer = gst::Buffer::with_size(info.size()).unwrap(); let buffer = gst::Buffer::with_size(info.size()).unwrap();
@ -1495,7 +1505,7 @@ impl Receiver {
Ok(gst::Buffer::from_mut_slice(Vec::from(data))) Ok(gst::Buffer::from_mut_slice(Vec::from(data)))
} }
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
VideoInfo::H264Info { .. } | VideoInfo::H265Info { .. } => { VideoInfo::H264 { .. } | VideoInfo::H265 { .. } => {
let compressed_packet = video_frame.compressed_packet().ok_or_else(|| { let compressed_packet = video_frame.compressed_packet().ok_or_else(|| {
error!( error!(
CAT, CAT,
@ -1599,7 +1609,7 @@ impl Receiver {
gst::FlowError::NotNegotiated gst::FlowError::NotNegotiated
})?; })?;
return Ok(AudioInfo::AudioInfo(info)); return Ok(AudioInfo::Audio(info));
} }
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
@ -1622,7 +1632,7 @@ impl Receiver {
return Err(gst::FlowError::Error); return Err(gst::FlowError::Error);
} }
return Ok(AudioInfo::AacInfo { return Ok(AudioInfo::Aac {
sample_rate: audio_frame.sample_rate(), sample_rate: audio_frame.sample_rate(),
no_channels: audio_frame.no_channels(), no_channels: audio_frame.no_channels(),
codec_data: compressed_packet codec_data: compressed_packet
@ -1653,7 +1663,7 @@ impl Receiver {
audio_frame: &AudioFrame, audio_frame: &AudioFrame,
) -> Result<gst::Buffer, gst::FlowError> { ) -> Result<gst::Buffer, gst::FlowError> {
match info { match info {
AudioInfo::AudioInfo(ref info) => { AudioInfo::Audio(ref info) => {
let src = audio_frame.data().ok_or(gst::FlowError::Error)?; let src = audio_frame.data().ok_or(gst::FlowError::Error)?;
let buff_size = (audio_frame.no_samples() as u32 * info.bpf()) as usize; let buff_size = (audio_frame.no_samples() as u32 * info.bpf()) as usize;
@ -1666,14 +1676,14 @@ impl Receiver {
gst::ReferenceTimestampMeta::add( gst::ReferenceTimestampMeta::add(
buffer, buffer,
&*TIMECODE_CAPS, &*crate::TIMECODE_CAPS,
gst::ClockTime::from_nseconds(audio_frame.timecode() as u64 * 100), gst::ClockTime::from_nseconds(audio_frame.timecode() as u64 * 100),
gst::ClockTime::NONE, gst::ClockTime::NONE,
); );
if audio_frame.timestamp() != ndisys::NDIlib_recv_timestamp_undefined { if audio_frame.timestamp() != ndisys::NDIlib_recv_timestamp_undefined {
gst::ReferenceTimestampMeta::add( gst::ReferenceTimestampMeta::add(
buffer, buffer,
&*TIMESTAMP_CAPS, &*crate::TIMESTAMP_CAPS,
gst::ClockTime::from_nseconds(audio_frame.timestamp() as u64 * 100), gst::ClockTime::from_nseconds(audio_frame.timestamp() as u64 * 100),
gst::ClockTime::NONE, gst::ClockTime::NONE,
); );
@ -1709,7 +1719,7 @@ impl Receiver {
Ok(buffer) Ok(buffer)
} }
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
AudioInfo::OpusInfo { .. } => { AudioInfo::Opus { .. } => {
let data = audio_frame.data().ok_or_else(|| { let data = audio_frame.data().ok_or_else(|| {
error!(CAT, obj: element, "Audio packet has no data"); error!(CAT, obj: element, "Audio packet has no data");
gst::element_error!( gst::element_error!(
@ -1724,7 +1734,7 @@ impl Receiver {
Ok(gst::Buffer::from_mut_slice(Vec::from(data))) Ok(gst::Buffer::from_mut_slice(Vec::from(data)))
} }
#[cfg(feature = "advanced-sdk")] #[cfg(feature = "advanced-sdk")]
AudioInfo::AacInfo { .. } => { AudioInfo::Aac { .. } => {
let compressed_packet = audio_frame.compressed_packet().ok_or_else(|| { let compressed_packet = audio_frame.compressed_packet().ok_or_else(|| {
error!( error!(
CAT, CAT,