Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
joaoantoniocardoso committed Jun 13, 2024
1 parent 1c80552 commit 2a78a1c
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 8 deletions.
28 changes: 24 additions & 4 deletions src/stream/pipeline/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod fake_pipeline;
pub mod qr_pipeline;
pub mod redirect_pipeline;
pub mod runner;
pub mod v4l_pipeline;
Expand All @@ -24,6 +25,7 @@ use crate::{
};

use fake_pipeline::FakePipeline;
use qr_pipeline::QrPipeline;
use redirect_pipeline::RedirectPipeline;
use runner::PipelineRunner;
use v4l_pipeline::V4lPipeline;
Expand All @@ -38,14 +40,20 @@ pub trait PipelineGstreamerInterface {
pub enum Pipeline {
V4l(V4lPipeline),
Fake(FakePipeline),
QR(QrPipeline),
Redirect(RedirectPipeline),
}

fn example() {
Pipeline::try_new(video_and_stream_information, pipeline_id)
}

impl Pipeline {
pub fn inner_state_mut(&mut self) -> &mut PipelineState {
match self {
Pipeline::V4l(pipeline) => &mut pipeline.state,
Pipeline::Fake(pipeline) => &mut pipeline.state,
Pipeline::QR(pipeline) => &mut pipeline.state,
Pipeline::Redirect(pipeline) => &mut pipeline.state,
}
}
Expand All @@ -54,6 +62,7 @@ impl Pipeline {
match self {
Pipeline::V4l(pipeline) => &pipeline.state,
Pipeline::Fake(pipeline) => &pipeline.state,
Pipeline::QR(pipeline) => &pipeline.state,
Pipeline::Redirect(pipeline) => &pipeline.state,
}
}
Expand All @@ -63,11 +72,22 @@ impl Pipeline {
video_and_stream_information: &VideoAndStreamInformation,
pipeline_id: &uuid::Uuid,
) -> Result<Self> {
let pipeline_state = PipelineState::try_new(video_and_stream_information, pipeline_id)?;
let pipeline_state: PipelineState =
PipelineState::try_new(video_and_stream_information, pipeline_id)?;
Ok(match &video_and_stream_information.video_source {
VideoSourceType::Gst(_) => Pipeline::Fake(FakePipeline {
state: pipeline_state,
}),
VideoSourceType::Gst(video_source_gst) => match video_source_gst.source {
crate::video::video_source_gst::VideoSourceGstType::Local(_) => todo!(),
crate::video::video_source_gst::VideoSourceGstType::Fake(_) => {
Pipeline::Fake(FakePipeline {
state: pipeline_state,
})
}
crate::video::video_source_gst::VideoSourceGstType::QR(_) => {
Pipeline::QR(QrPipeline {
state: pipeline_state,
})
}
},
VideoSourceType::Local(_) => Pipeline::V4l(V4lPipeline {
state: pipeline_state,
}),
Expand Down
162 changes: 162 additions & 0 deletions src/stream/pipeline/qr_pipeline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use crate::{
stream::types::CaptureConfiguration,
video::{
types::{VideoEncodeType, VideoSourceType},
video_source_gst::VideoSourceGstType,
},
video_stream::types::VideoAndStreamInformation,
};

use super::{
PipelineGstreamerInterface, PipelineState, PIPELINE_FILTER_NAME, PIPELINE_RTP_TEE_NAME,
PIPELINE_VIDEO_TEE_NAME,
};

use anyhow::{anyhow, Result};

use tracing::*;

use gst::prelude::*;

#[derive(Debug)]
pub struct QrPipeline {
pub state: PipelineState,
}

impl QrPipeline {
#[instrument(level = "debug")]
pub fn try_new(
pipeline_id: &uuid::Uuid,
video_and_stream_information: &VideoAndStreamInformation,
) -> Result<gst::Pipeline> {
let configuration = match &video_and_stream_information
.stream_information
.configuration
{
CaptureConfiguration::Video(configuration) => configuration,
unsupported => {
return Err(anyhow!("{unsupported:?} is not supported as Fake Pipeline"))
}
};

let video_source = match &video_and_stream_information.video_source {
VideoSourceType::Gst(source) => source,
unsupported => {
return Err(anyhow!(
"SourceType {unsupported:?} is not supported as Fake Pipeline"
))
}
};

let pattern = match &video_source.source {
VideoSourceGstType::Fake(pattern) => pattern,
unsupported => {
return Err(anyhow!(
"SourceType {unsupported:?} is not supported as Fake Pipeline"
))
}
};

let filter_name = format!("{PIPELINE_FILTER_NAME}-{pipeline_id}");
let video_tee_name = format!("{PIPELINE_VIDEO_TEE_NAME}-{pipeline_id}");
let rtp_tee_name = format!("{PIPELINE_RTP_TEE_NAME}-{pipeline_id}");

// Fakes (videotestsrc) are only "video/x-raw" or "video/x-bayer",
// and to be able to encode it, we need to define an available
// format for both its src the next element's sink pad.
// We are choosing "UYVY" because it is compatible with the
// application-rtp template capabilities.
// For more information: https://gstreamer.freedesktop.org/documentation/additional/design/mediatype-video-raw.html?gi-language=c#formats
let description = match &configuration.encode {
VideoEncodeType::H264 => {
format!(concat!(
"videotestsrc pattern={pattern} is-live=true do-timestamp=true",
" ! timeoverlay",
" ! video/x-raw,format=I420",
" ! x264enc tune=zerolatency speed-preset=ultrafast bitrate=5000",
" ! h264parse",
" ! capsfilter name={filter_name} caps=video/x-h264,profile={profile},stream-format=avc,alignment=au,width={width},height={height},framerate={interval_denominator}/{interval_numerator}",
" ! tee name={video_tee_name} allow-not-linked=true",
" ! rtph264pay aggregate-mode=zero-latency config-interval=10 pt=96",
" ! tee name={rtp_tee_name} allow-not-linked=true"
),
pattern = pattern,
profile = "constrained-baseline",
width = configuration.width,
height = configuration.height,
interval_denominator = configuration.frame_interval.denominator,
interval_numerator = configuration.frame_interval.numerator,
filter_name = filter_name,
video_tee_name = video_tee_name,
rtp_tee_name = rtp_tee_name,
)
}
VideoEncodeType::Yuyv => {
format!(
concat!(
// Because application-rtp templates doesn't accept "YUY2", we
// need to transcode it. We are arbitrarily chosing the closest
// format available ("UYVY").
"videotestsrc pattern={pattern} is-live=true do-timestamp=true",
" ! timeoverlay",
" ! video/x-raw,format=I420",
" ! capsfilter name={filter_name} caps=video/x-raw,format=I420,width={width},height={height},framerate={interval_denominator}/{interval_numerator}",
" ! tee name={video_tee_name} allow-not-linked=true",
" ! rtpvrawpay pt=96",
" ! tee name={rtp_tee_name} allow-not-linked=true",
),
pattern = pattern,
width = configuration.width,
height = configuration.height,
interval_denominator = configuration.frame_interval.denominator,
interval_numerator = configuration.frame_interval.numerator,
filter_name = filter_name,
video_tee_name = video_tee_name,
rtp_tee_name = rtp_tee_name,
)
}
VideoEncodeType::Mjpg => {
format!(
concat!(
"videotestsrc pattern={pattern} is-live=true do-timestamp=true",
" ! timeoverlay",
" ! video/x-raw,format=I420",
" ! jpegenc quality=85 idct-method=1",
" ! capsfilter name={filter_name} caps=image/jpeg,width={width},height={height},framerate={interval_denominator}/{interval_numerator}",
" ! tee name={video_tee_name} allow-not-linked=true",
" ! rtpjpegpay pt=96",
" ! tee name={rtp_tee_name} allow-not-linked=true",
),
pattern = pattern,
width = configuration.width,
height = configuration.height,
interval_denominator = configuration.frame_interval.denominator,
interval_numerator = configuration.frame_interval.numerator,
filter_name = filter_name,
video_tee_name = video_tee_name,
rtp_tee_name = rtp_tee_name,
)
}
unsupported => {
return Err(anyhow!(
"Encode {unsupported:?} is not supported for Test Pipeline"
))
}
};

let pipeline = gst::parse::launch(&description)?;

let pipeline = pipeline
.downcast::<gst::Pipeline>()
.expect("Couldn't downcast pipeline");

Ok(pipeline)
}
}

impl PipelineGstreamerInterface for QrPipeline {
#[instrument(level = "trace")]
fn is_running(&self) -> bool {
self.state.pipeline_runner.is_running()
}
}
18 changes: 14 additions & 4 deletions src/video/video_source_gst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub enum VideoSourceGstType {
// TODO: local should have a pipeline also
Local(VideoSourceLocal),
Fake(String),
QR(String),
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
Expand All @@ -27,6 +28,7 @@ impl VideoSource for VideoSourceGst {
match &self.source {
VideoSourceGstType::Local(local) => local.source_string(),
VideoSourceGstType::Fake(string) => string,
VideoSourceGstType::QR(_) => todo!(),
}
}

Expand Down Expand Up @@ -75,6 +77,7 @@ impl VideoSource for VideoSourceGst {
},
]
}
VideoSourceGstType::QR(_) => todo!(),
}
}

Expand Down Expand Up @@ -120,6 +123,7 @@ impl VideoSource for VideoSourceGst {
| "snow" | "solid" | "spokes" | "white" | "zone" => true,
_ => false,
},
VideoSourceGstType::QR(_) => todo!(),
}
}

Expand All @@ -130,9 +134,15 @@ impl VideoSource for VideoSourceGst {

impl VideoSourceAvailable for VideoSourceGst {
fn cameras_available() -> Vec<VideoSourceType> {
vec![VideoSourceType::Gst(VideoSourceGst {
name: "Fake source".into(),
source: VideoSourceGstType::Fake("ball".into()),
})]
vec![
VideoSourceType::Gst(VideoSourceGst {
name: "Fake source".into(),
source: VideoSourceGstType::Fake("ball".into()),
}),
// VideoSourceType::Gst(VideoSourceGst {
// name: "QR".into(),
// source: VideoSourceGstType::QR("potato".into()),
// }),
]
}
}

0 comments on commit 2a78a1c

Please sign in to comment.