diff --git a/src/lib/video/mod.rs b/src/lib/video/mod.rs index 5bc44562..4dee6af1 100644 --- a/src/lib/video/mod.rs +++ b/src/lib/video/mod.rs @@ -6,4 +6,5 @@ pub mod xml; pub mod video_source_gst; pub mod video_source_local; +pub mod video_source_onvif; pub mod video_source_redirect; diff --git a/src/lib/video/types.rs b/src/lib/video/types.rs index 72ac7ce8..b31f4050 100644 --- a/src/lib/video/types.rs +++ b/src/lib/video/types.rs @@ -6,6 +6,7 @@ use super::{ video_source::{VideoSource, VideoSourceFormats}, video_source_gst::VideoSourceGst, video_source_local::VideoSourceLocal, + video_source_onvif::VideoSourceOnvif, video_source_redirect::VideoSourceRedirect, }; @@ -13,6 +14,7 @@ use super::{ pub enum VideoSourceType { Gst(VideoSourceGst), Local(VideoSourceLocal), + Onvif(VideoSourceOnvif), Redirect(VideoSourceRedirect), } @@ -60,6 +62,7 @@ impl VideoSourceType { match self { VideoSourceType::Local(local) => local, VideoSourceType::Gst(gst) => gst, + VideoSourceType::Onvif(onvif) => onvif, VideoSourceType::Redirect(redirect) => redirect, } } diff --git a/src/lib/video/video_source.rs b/src/lib/video/video_source.rs index 993b802b..da459b94 100644 --- a/src/lib/video/video_source.rs +++ b/src/lib/video/video_source.rs @@ -4,7 +4,7 @@ use crate::controls::types::{Control, ControlType}; use super::{ types::*, video_source_gst::VideoSourceGst, video_source_local::VideoSourceLocal, - video_source_redirect::VideoSourceRedirect, + video_source_onvif::VideoSourceOnvif, video_source_redirect::VideoSourceRedirect, }; pub trait VideoSource { @@ -31,6 +31,7 @@ pub async fn cameras_available() -> Vec { [ &VideoSourceLocal::cameras_available().await[..], &VideoSourceGst::cameras_available().await[..], + &VideoSourceOnvif::cameras_available().await[..], &VideoSourceRedirect::cameras_available().await[..], ] .concat() diff --git a/src/lib/video/video_source_onvif.rs b/src/lib/video/video_source_onvif.rs new file mode 100644 index 00000000..527f83ff --- /dev/null +++ b/src/lib/video/video_source_onvif.rs @@ -0,0 +1,89 @@ +use paperclip::actix::Apiv2Schema; +use serde::{Deserialize, Serialize}; + +use crate::controls::{onvif::manager::Manager as OnvifManager, types::Control}; + +use super::{ + types::*, + video_source::{VideoSource, VideoSourceAvailable, VideoSourceFormats}, +}; + +#[derive(Apiv2Schema, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum VideoSourceOnvifType { + Onvif(String), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct VideoSourceOnvif { + pub name: String, + pub source: VideoSourceOnvifType, +} + +impl VideoSourceFormats for VideoSourceOnvif { + async fn formats(&self) -> Vec { + let VideoSourceOnvifType::Onvif(stream_uri) = &self.source; + OnvifManager::get_formats(stream_uri) + .await + .unwrap_or_default() + } +} + +impl VideoSource for VideoSourceOnvif { + fn name(&self) -> &String { + &self.name + } + + fn source_string(&self) -> &str { + match &self.source { + VideoSourceOnvifType::Onvif(url) => url.as_str(), + } + } + + fn set_control_by_name(&self, _control_name: &str, _value: i64) -> std::io::Result<()> { + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Onvif source doesn't have controls.", + )) + } + + fn set_control_by_id(&self, _control_id: u64, _value: i64) -> std::io::Result<()> { + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Onvif source doesn't have controls.", + )) + } + + fn control_value_by_name(&self, _control_name: &str) -> std::io::Result { + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Onvif source doesn't have controls.", + )) + } + + fn control_value_by_id(&self, _control_id: u64) -> std::io::Result { + Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Onvif source doesn't have controls.", + )) + } + + fn controls(&self) -> Vec { + vec![] + } + + fn is_valid(&self) -> bool { + match &self.source { + VideoSourceOnvifType::Onvif(_) => true, + } + } + + fn is_shareable(&self) -> bool { + true + } +} + +impl VideoSourceAvailable for VideoSourceOnvif { + async fn cameras_available() -> Vec { + OnvifManager::streams_available().await.clone() + } +}