Skip to content

Commit 571df99

Browse files
committed
Merge branch 'release/0.2.0'
2 parents 0f8d1cd + 31b4e6d commit 571df99

7 files changed

Lines changed: 171 additions & 45 deletions

File tree

Cargo.lock

Lines changed: 46 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rusty-engine"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "Rust reimagining of potential-engine"
55
readme = "README.md"
66
license = "MIT"
@@ -13,6 +13,8 @@ travis-ci = { repository = "opensight-cv/rusty-engine" }
1313
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1414

1515
[dependencies]
16+
serde = { version = "1.0", features = ["derive"] }
17+
serde_json = "1.0.44"
1618
structopt = "0.3.7"
1719
glib = "0.9.0"
1820
gstreamer = "0.15.0"

src/main.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use gstreamer_rtsp_server::{
99
};
1010
use structopt::StructOpt;
1111

12-
use pipe_builder::{Encoder, Input, VideoSize};
12+
use pipe_builder::{Encoder, Input, Pipe, VideoSize};
1313

1414
#[derive(Debug, StructOpt)]
1515
#[structopt(
@@ -34,9 +34,10 @@ struct Opt {
3434
long,
3535
help = "Input mode to use",
3636
required_unless = "list",
37+
required_unless = "pipes-as-json",
3738
possible_values(&["v4l2", "shmem", "rpi"])
3839
)]
39-
input: Input,
40+
input: Option<Input>, // this looks stupid, but some library freaks out without it. we get the desired effect at run anyway
4041
#[structopt(
4142
short,
4243
long,
@@ -54,6 +55,8 @@ struct Opt {
5455
default_value_if("input", Some("rpi"), "camera")
5556
)]
5657
encoder: Encoder,
58+
#[structopt(long, help = "Pipelines to run as JSON.")]
59+
pipes_as_json: Option<String>,
5760
#[structopt(long, help = "List all input modes and exit.", group = "list")]
5861
list_in: bool,
5962
#[structopt(long, help = "List all encoders and exit.", group = "list")]
@@ -79,30 +82,46 @@ fn main() {
7982
}
8083
return;
8184
}
82-
// try to set up video size
83-
let size = VideoSize::new(opt.width, opt.height, opt.framerate);
84-
let device = opt.device.unwrap_or("".to_string());
85-
let mut input = opt.input;
86-
input = match input {
87-
Input::Video4Linux(_) => Input::Video4Linux(device),
88-
Input::SharedMemory(_) => Input::SharedMemory(device),
89-
_ => input,
90-
};
91-
let encoder = opt.encoder;
92-
let pipe = pipe_builder::create_pipe(input, encoder, size);
93-
println!("Pipeline constructed: {}", pipe);
85+
// set up basic Gst stuff
9486
gstreamer::init().expect("GStreamer could not init!");
9587
let loop_ = MainLoop::new(Option::None, false);
9688
let server = RTSPServer::new();
9789
server.set_service(&opt.net_opt.get_port().to_string());
98-
let factory = RTSPMediaFactory::new();
99-
factory.set_launch(&pipe);
100-
factory.set_shared(true);
10190
let mounts = server
10291
.get_mount_points()
10392
.expect("Failed to get mount points");
104-
// set up mounts
105-
mounts.add_factory(opt.net_opt.get_url(), &factory);
93+
if opt.pipes_as_json.is_some() {
94+
let config = opt.pipes_as_json.unwrap();
95+
let pipes: Vec<Pipe> = serde_json::from_str(&config).expect("JSON could not parse!");
96+
println!("{:#?}", pipes);
97+
for pipe in pipes.iter() {
98+
let factory = RTSPMediaFactory::new();
99+
let pipe_str = pipe_builder::create_pipe(pipe);
100+
println!("Pipeline constructed: {}", pipe_str);
101+
factory.set_launch(&pipe_str);
102+
factory.set_shared(true);
103+
mounts.add_factory(pipe.url(), &factory);
104+
}
105+
} else {
106+
// try to set up video size
107+
let size = VideoSize::new(opt.width, opt.height, opt.framerate);
108+
let device = opt.device.unwrap_or("".to_string());
109+
let mut input = opt.input.unwrap();
110+
input = match input {
111+
Input::Video4Linux(_) => Input::Video4Linux(device),
112+
Input::SharedMemory(_) => Input::SharedMemory(device),
113+
_ => input,
114+
};
115+
let encoder = opt.encoder;
116+
let pipe = Pipe::new(input, encoder, size, String::from(opt.net_opt.get_url()));
117+
let pipe_str = pipe_builder::create_pipe(&pipe);
118+
println!("Pipeline constructed: {}", pipe_str);
119+
let factory = RTSPMediaFactory::new();
120+
factory.set_launch(&pipe_str);
121+
factory.set_shared(true);
122+
// set up mounts
123+
mounts.add_factory(pipe.url(), &factory);
124+
}
106125
server.attach(Option::None);
107126
println!("Starting loop...");
108127
loop_.run();

src/pipe_builder/encoder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use serde::Deserialize;
12
use std::{convert, fmt, str::FromStr};
23

3-
#[derive(Debug, PartialEq, Eq)]
4+
#[derive(Debug, PartialEq, Eq, Deserialize)]
45
pub enum Encoder {
56
Software,
67
OpenMAX,

src/pipe_builder/input.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use serde::Deserialize;
12
use std::{convert, fmt, str::FromStr};
23

3-
#[derive(Debug, PartialEq)]
4+
#[derive(Debug, PartialEq, Deserialize)]
45
pub enum Input {
56
Video4Linux(String),
67
SharedMemory(String),

src/pipe_builder/mod.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
mod encoder;
22
mod input;
3-
pub use self::{encoder::Encoder, input::Input};
3+
mod pipe;
4+
pub use self::{encoder::Encoder, input::Input, pipe::Pipe};
45

6+
use serde::Deserialize;
7+
8+
#[derive(Debug, Deserialize)]
59
pub struct VideoSize {
610
width: u32,
711
height: u32,
@@ -18,32 +22,34 @@ impl VideoSize {
1822
}
1923
}
2024

21-
pub fn create_pipe(inp: Input, enc: Encoder, dim: VideoSize) -> String {
22-
if inp == Input::Raspberry && enc != Encoder::Camera {
25+
pub fn create_pipe(pipe: &Pipe) -> String {
26+
if *pipe.input() == Input::Raspberry && *pipe.encoder() != Encoder::Camera {
2327
println!("using a raspberry pi camera with any encoder besides the one provided by the driver is a Bad Idea");
2428
}
25-
let inp_str = match inp {
29+
let inp_str = match pipe.input() {
2630
Input::Video4Linux(device) => format!("v4l2src device={}", device),
2731
Input::Raspberry => String::from("rpicamsrc"),
2832
Input::SharedMemory(socket) => format!(
2933
"shmsrc socket-path={} ! capsfilter caps=video/x-raw,format=I420",
3034
socket
3135
),
3236
};
33-
let enc_str = match enc {
37+
let enc_str = match pipe.encoder() {
3438
Encoder::Software => format!(
35-
"video/x-raw,width={w},height={h},framerate={f}/1 ! videoconvert ! x264enc",
36-
w = dim.width,
37-
h = dim.height,
38-
f = dim.framerate
39+
"video/x-raw,width={w},height={h},framerate={f}/1 ! videoconvert ! x264enc tune=zerolatency",
40+
w = pipe.size().width,
41+
h = pipe.size().height,
42+
f = pipe.size().framerate
3943
),
4044
Encoder::Camera => format!(
4145
"video/x-h264,width={w},height={h},framerate={f}/1",
42-
w = dim.width,
43-
h = dim.height,
44-
f = dim.framerate
46+
w = pipe.size().width,
47+
h = pipe.size().height,
48+
f = pipe.size().framerate
4549
),
46-
Encoder::OpenMAX => format!("videoconvert ! video/x-raw,format=I420,width={w},height={h},framerate={f}/1 ! omxh264enc ! video/x-h264", w = dim.width, h = dim.height, f = dim.framerate)
50+
Encoder::OpenMAX => format!(
51+
"video/x-raw,width={w},height={h},framerate={f}/1 ! videoconvert ! video/x-raw,format=I420 ! omxh264enc ! video/x-h264,profile=baseline",
52+
w = pipe.size().width, h = pipe.size().height, f = pipe.size().framerate)
4753
};
4854
vec![inp_str, enc_str, String::from("rtph264pay name=pay0")].join(" ! ")
4955
}
@@ -60,26 +66,37 @@ mod tests {
6066
fn test_raspberry_pipe() {
6167
assert_eq!(
6268
"rpicamsrc ! video/x-h264,width=320,height=240,framerate=30/1 ! rtph264pay name=pay0",
63-
create_pipe(Input::Raspberry, Encoder::Camera, test_size())
69+
create_pipe(&Pipe::new(
70+
Input::Raspberry,
71+
Encoder::Camera,
72+
test_size(),
73+
String::new()
74+
))
6475
);
6576
}
6677

6778
#[test]
6879
fn test_v4l2_pipes() {
6980
assert_eq!(
70-
"v4l2src device=/dev/video0 ! video/x-raw,width=320,height=240,framerate=30/1 ! videoconvert ! x264enc ! rtph264pay name=pay0",
81+
"v4l2src device=/dev/video0 ! video/x-raw,width=320,height=240,framerate=30/1 ! videoconvert ! x264enc tune=zerolatency ! rtph264pay name=pay0",
7182
create_pipe(
72-
Input::Video4Linux("/dev/video0".to_string()),
73-
Encoder::Software,
74-
test_size(),
83+
&Pipe::new(
84+
Input::Video4Linux("/dev/video0".to_string()),
85+
Encoder::Software,
86+
test_size(),
87+
String::new()
88+
)
7589
)
7690
);
7791
assert_eq!(
78-
"v4l2src device=/dev/video0 ! videoconvert ! video/x-raw,format=I420,width=320,height=240,framerate=30/1 ! omxh264enc ! video/x-h264 ! rtph264pay name=pay0",
92+
"v4l2src device=/dev/video0 ! video/x-raw,width=320,height=240,framerate=30/1 ! videoconvert ! video/x-raw,format=I420 ! omxh264enc ! video/x-h264,profile=baseline ! rtph264pay name=pay0",
7993
create_pipe(
80-
Input::Video4Linux("/dev/video0".to_string()),
81-
Encoder::OpenMAX,
82-
test_size(),
94+
&Pipe::new(
95+
Input::Video4Linux("/dev/video0".to_string()),
96+
Encoder::OpenMAX,
97+
test_size(),
98+
String::new()
99+
)
83100
)
84101
);
85102
}

src/pipe_builder/pipe.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use serde::Deserialize;
2+
3+
#[derive(Debug, Deserialize)]
4+
pub struct Pipe {
5+
input: super::Input,
6+
encoder: super::Encoder,
7+
size: super::VideoSize,
8+
url: String,
9+
}
10+
11+
impl Pipe {
12+
pub fn new(
13+
input: super::Input,
14+
encoder: super::Encoder,
15+
size: super::VideoSize,
16+
url: String,
17+
) -> Pipe {
18+
Pipe {
19+
input,
20+
encoder,
21+
size,
22+
url,
23+
}
24+
}
25+
26+
pub fn input(&self) -> &super::Input {
27+
&self.input
28+
}
29+
30+
pub fn encoder(&self) -> &super::Encoder {
31+
&self.encoder
32+
}
33+
34+
pub fn size(&self) -> &super::VideoSize {
35+
&self.size
36+
}
37+
38+
pub fn url(&self) -> &String {
39+
&self.url
40+
}
41+
}

0 commit comments

Comments
 (0)