use gstreamer::Element;
use std::sync::Arc;
use wayclip_core::{models::error::WayclipError, settings::UserSettings};
use crate::common::gst::guard::CaptureHealth;
use crate::linux::engine::gstreamer::video::encoder::VideoEncoderFactory;
use crate::linux::engine::gstreamer::video::nvidia::VideoNvidia;
use crate::linux::engine::gstreamer::video::parser::VideoParserFactory;
use crate::linux::engine::gstreamer::video::preprocessor::VideoPreprocessFactory;
use crate::linux::engine::gstreamer::{
CaptureMode, DEFAULT_GST_LEAKY_DOWNSTREAM, DEFAULT_MAX_SIZE_BUFFER, DEFAULT_MAX_SIZE_BYTES,
DEFAULT_MAX_SIZE_TIME_NS,
};
use crate::{
common::gst::{GStreamer, app::DEFAULT_APPSRC_DO_TIMESTAMP, element::GStreamerElementType},
linux::engine::pipewire::DaemonEngineConnectionData,
};
pub mod encoder;
pub mod nvidia;
pub mod parser;
pub mod preprocessor;
pub struct VideoBranchBuilder<'a> {
user_settings: &'a UserSettings,
connection_data: &'a DaemonEngineConnectionData,
mode: CaptureMode,
health: Arc<CaptureHealth>,
}
impl<'a> VideoBranchBuilder<'a> {
pub fn new(
user_settings: &'a UserSettings,
connection_data: &'a DaemonEngineConnectionData,
mode: CaptureMode,
health: Arc<CaptureHealth>,
) -> Self {
Self {
user_settings,
connection_data,
mode,
health,
}
}
pub fn build(self) -> Result<Vec<Element>, WayclipError> {
let (file_descriptor, node_id) = self.connection_data.extract_data()?;
let mode = if VideoNvidia::nvidia_cuda_enabled(&self.user_settings.recording.video.codec) {
CaptureMode::SystemMemory
} else {
self.mode
};
let pipewire_src = GStreamer::build_element(GStreamerElementType::VideoPipewireSrc {
do_timestamp: DEFAULT_APPSRC_DO_TIMESTAMP,
fd: file_descriptor,
path: node_id.into(),
keepalive_ms: 1000 / self.user_settings.recording.video.fps.0.max(1) as i32,
always_copy: mode == CaptureMode::SystemMemory,
})?;
let video_queue_1 = Self::build_queue()?;
let video_queue_2 = Self::build_queue()?;
let video_queue_3 = GStreamer::build_element(GStreamerElementType::AudioQueue)?;
let (mut elements, pre_encode_caps) = VideoPreprocessFactory::build(
pipewire_src,
video_queue_1,
self.user_settings,
self.mode,
self.health,
)?;
let encoder = VideoEncoderFactory::build_encoder(self.user_settings)?;
let (parser, parser_caps) =
VideoParserFactory::build(&self.user_settings.recording.video.codec)?;
elements.push(pre_encode_caps);
elements.push(video_queue_2);
elements.push(encoder);
elements.push(parser);
if let Some(caps) = parser_caps {
elements.push(caps);
}
elements.push(video_queue_3);
Ok(elements)
}
fn build_queue() -> Result<Element, WayclipError> {
Ok(GStreamer::build_element(
GStreamerElementType::VideoQueue {
buffers: DEFAULT_MAX_SIZE_BUFFER,
bytes: DEFAULT_MAX_SIZE_BYTES,
time: DEFAULT_MAX_SIZE_TIME_NS,
leaky: DEFAULT_GST_LEAKY_DOWNSTREAM.into(),
},
)?)
}
}