Skip to content

Commit 1d06df6

Browse files
authored
Merge pull request #70 from gomadoufu/feat-#69
2 parents 69c1ba9 + 0b0c15e commit 1d06df6

File tree

9 files changed

+246
-172
lines changed

9 files changed

+246
-172
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "gomast"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

README.md

+18-40
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,27 @@
33
Thin wrapper for GStreamer, for development and testing on RaspberryPi.
44

55
```sh
6-
# use default options (test video, vga, 30fps, h264)
7-
$ gomast example.com 5000
8-
Running: gst-launch-1.0 videotestsrc ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! x264enc ! rtph264pay ! udpsink host=example.com port=5000
6+
# input: testpattern, YUY2
7+
# output: 640x480, vp8, example.com:5004
8+
$ gomast input test yuy2 output 640 480 vp8 example.com 5004
9+
Running: gst-launch-1.0 videotestsrc ! video/x-raw,format=YUY2,width=640,height=480 ! videoconvert ! vp8enc ! rtpvp8pay ! udpsink host=example.com port=5004
910
Setting pipeline to PAUSED ...
1011
Pipeline is PREROLLING ...
11-
...
12-
13-
# use custom options (mipi video, hd, 60fps, vp8)
14-
$ gomast myserver.com 7000 -i mipi -f 60 -t vp8 -r hd
15-
Running: gst-launch-1.0 libcamerasrc ! video/x-raw,width=1280,height=720,framerate=60/1 ! videoconvert ! vp8enc ! rtpvp8pay ! udpsink host=myserver.com port=7000
16-
Setting pipeline to PAUSED ...
17-
Pipeline is PREROLLING ...
18-
...
19-
20-
# use hardware encoder
21-
$ gomast myserver.com 7000 -9 usb --hardware
22-
Running: gst-launch-1.0 -v v4l2src ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! v4l2h264enc ! 'video/x-h264,level=(string)4' ! rtph264pay ! udpsink host=myserver.com port=7000
23-
Setting pipeline to PAUSED ...
24-
Pipeline is PREROLLING ...
25-
...
26-
12+
Redistribute latency...
13+
Pipeline is PREROLLED ...
14+
Setting pipeline to PLAYING ...
15+
Redistribute latency...
16+
New clock: GstSystemClock
17+
0:00:06.3 / 99:99:99.
18+
19+
# input: usb camera, YUY2
20+
# output: 1280x720, h264, example.com:7001, hardware encode
2721
# dry-run mode
28-
$ gomast myserver.com 7000 --dry-run
29-
gst-launch-1.0 videotestsrc ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! x264enc ! rtph264pay ! udpsink host=myserver.com port=7000
22+
$ gomast input usb yuy2 output 1280 720 h264 example.com 7001 --hardware --dry-run
23+
gst-launch-1.0 -v v4l2src ! video/x-raw,format=YUY2,width=1280,height=720 ! videoconvert ! v4l2h264enc ! 'video/x-h264,level=(string)4' ! rtph264pay ! udpsink host=example.com port=7001
3024

3125
# show available devices
32-
$ gomast --show | grep h264
26+
$ gomast show | grep h264
3327
applemedia: vtenc_h264: H.264 encoder
3428
applemedia: vtenc_h264_hw: H.264 (HW only) encoder
3529
codectimestamper: h264timestamper: H.264 timestamper
@@ -58,28 +52,12 @@ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreame
5852

5953
## Download
6054

61-
RaspberryPiOS(armv7-unknown-linux-musl), Linux(unknown-linux-musl), and MacOS(apple-darwin)
55+
RaspberryPiOS(armv7-unknown-linux-musl), Linux(unknown-linux-musl), and MacOS(apple-darwin)
6256
binaries are available from [Release](http://github.com/gomadoufu/gomastreamer/releases) page.
6357

6458
## Usage
6559

66-
Format: `gomast [OPTIONS] [HOST] [PORT]`.
67-
68-
You can specify the following options:
69-
70-
-i, --input : Source of video [default: test] [possible values: test, mipi, usb]
71-
72-
-r, --resolution : Resolution of video [default: vga] [possible values: vga, sd, hd]
73-
74-
-f, --framerate : Framerate of video [default: 30]
75-
76-
-t, --type : Format of video [default: h264] [possible values: vp8, h264]
77-
78-
--hardware : Use hardware encode
79-
80-
--dry-run : Dry-run mode, just print command
81-
82-
--show : Show information of devices
60+
`gomast input <INPUT_TYPE> <FORMAT> output <WIDTH> <HEIGHT> <ENCODER> <HOST> <PORT> [options]`
8361

8462
The HOST and PORT arguments correspond to the host and port arguments of the GStreamer `udpsink` element. There are required arguments.
8563

src/executor/build.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use crate::parser::{
2+
destruct::Elements,
3+
parse::{InputType, OutputFormat},
4+
};
5+
6+
use std::{collections::HashMap, vec};
7+
8+
#[derive(Debug)]
9+
pub struct Builder {
10+
arguments: Elements,
11+
arg_map: HashMap<String, String>,
12+
}
13+
14+
impl Builder {
15+
pub fn new(arguments: Elements) -> Builder {
16+
let arg_map = map_args()
17+
.iter()
18+
.map(|(k, v)| (k.to_string(), v.to_string()))
19+
.collect();
20+
Builder { arguments, arg_map }
21+
}
22+
pub fn build(&self) -> Vec<String> {
23+
let mut result = vec![];
24+
result.push(self.match_input_type());
25+
result.push("!".to_string());
26+
// カメラから、指定された解像度の映像を取得しておく。後で変換しない。
27+
result.push(format!(
28+
"{},{},{}",
29+
self.arguments.iformat,
30+
format_args!("width={}", self.arguments.iwidth),
31+
format_args!("height={}", self.arguments.iheight),
32+
));
33+
result.push("!".to_string());
34+
result.push("videoconvert".to_string());
35+
result.push("!".to_string());
36+
result.push(self.match_oformat());
37+
result.push("!".to_string());
38+
result.push(self.match_rtp());
39+
result.push("!".to_string());
40+
result.push("udpsink".to_string());
41+
result.push(format!("host={}", self.arguments.ohost));
42+
result.push(format!("port={}", self.arguments.oport));
43+
44+
result
45+
}
46+
47+
fn match_input_type(&self) -> String {
48+
match self.arguments.itype {
49+
InputType::Test => self.arg_map.get("test").unwrap().to_string(),
50+
InputType::Mipi => self.arg_map.get("mipi").unwrap().to_string(),
51+
InputType::Usb => self.arg_map.get("usb").unwrap().to_string(),
52+
}
53+
}
54+
55+
fn match_oformat(&self) -> String {
56+
match &self.arguments.oformat {
57+
OutputFormat::H264 if self.arguments.hardware => {
58+
self.arg_map.get("h264hard").unwrap().to_string()
59+
}
60+
OutputFormat::H264 => self.arg_map.get("h264soft").unwrap().to_string(),
61+
OutputFormat::Vp8 if self.arguments.hardware => {
62+
self.arg_map.get("vp8hard").unwrap().to_string()
63+
}
64+
OutputFormat::Vp8 => self.arg_map.get("vp8soft").unwrap().to_string(),
65+
}
66+
}
67+
68+
fn match_rtp(&self) -> String {
69+
match self.arguments.oformat {
70+
OutputFormat::H264 => self.arg_map.get("h264rtp").unwrap().to_string(),
71+
OutputFormat::Vp8 => self.arg_map.get("vp8rtp").unwrap().to_string(),
72+
}
73+
}
74+
}
75+
76+
fn map_args() -> Vec<(&'static str, &'static str)> {
77+
let result = vec![
78+
("test", "videotestsrc"),
79+
("mipi", "libcamerasrc"),
80+
("usb", "-v v4l2src"),
81+
("h264soft", "x264enc"),
82+
("h264hard", "v4l2h264enc ! 'video/x-h264,level=(string)4'"),
83+
("vp8soft", "vp8enc"),
84+
("vp8hard", "omxvp8enc"),
85+
("vp8rtp", "rtpvp8pay"),
86+
("h264rtp", "rtph264pay"),
87+
];
88+
result
89+
}

src/executor/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
pub mod build;
12
pub mod exec;

src/main.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
mod executor;
22
mod parser;
3-
use crate::executor::exec::Exec;
4-
use crate::parser::{convert::ArgConverter, parse::Cli};
3+
use crate::{
4+
executor::{build::Builder, exec::Exec},
5+
parser::{destruct::Elements, parse::Cli},
6+
};
57
use clap::Parser;
68

79
fn main() {
810
let cli = Cli::parse();
9-
let is_dry_run = cli.dry_run;
10-
if cli.show {
11+
let destructed = Elements::destruct(cli);
12+
let dry_run = destructed.dry_run;
13+
if destructed.show {
1114
let gst_plugins = Exec::new("gst-inspect-1.0".to_string(), vec![]);
1215
let v4l2_ctl = Exec::new("v4l2-ctl --list-devices".to_string(), vec![]);
13-
if is_dry_run {
16+
if dry_run {
1417
println!("gst-inspect-1.0 \n v4l2_ctl --list-devices");
1518
return;
1619
}
@@ -20,9 +23,9 @@ fn main() {
2023
gst_plugins.exec();
2124
return;
2225
}
23-
let converter = ArgConverter::new();
24-
let result = converter.convert(cli);
25-
if is_dry_run {
26+
let builder = Builder::new(destructed);
27+
let result = builder.build();
28+
if dry_run {
2629
println!("gst-launch-1.0 {}", result.join(" "));
2730
return;
2831
}

src/parser/convert.rs

-97
This file was deleted.

src/parser/destruct.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use super::parse::{Cli, Command, InputFormat, InputType, OutputCommands, OutputFormat};
2+
3+
#[derive(Debug)]
4+
pub struct Elements {
5+
pub itype: InputType,
6+
pub iformat: InputFormat,
7+
pub iwidth: i32,
8+
pub iheight: i32,
9+
pub oformat: OutputFormat,
10+
pub ohost: String,
11+
pub oport: i32,
12+
pub hardware: bool,
13+
pub dry_run: bool,
14+
pub show: bool,
15+
}
16+
17+
impl Elements {
18+
pub fn destruct(cli: Cli) -> Elements {
19+
match cli.input {
20+
Command::Show => Elements {
21+
itype: InputType::Test,
22+
iformat: InputFormat::Yuy2,
23+
iwidth: 0,
24+
iheight: 0,
25+
oformat: OutputFormat::H264,
26+
ohost: "".to_string(),
27+
oport: 0,
28+
hardware: false,
29+
dry_run: false,
30+
show: true,
31+
},
32+
Command::Input(input) => {
33+
let itype = input.input_type;
34+
let iformat = input.format;
35+
match input.output {
36+
OutputCommands::Output(output) => {
37+
let iwidth = output.width;
38+
let iheight = output.height;
39+
let oformat = output.format;
40+
let ohost = output.host;
41+
let oport = output.port;
42+
let hardware = output.hardware_encode;
43+
let dry_run = output.dry_run;
44+
let show = false;
45+
Elements {
46+
itype,
47+
iformat,
48+
iwidth,
49+
iheight,
50+
oformat,
51+
ohost,
52+
oport,
53+
hardware,
54+
dry_run,
55+
show,
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
}

src/parser/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
pub mod convert;
1+
pub mod destruct;
22
pub mod parse;

0 commit comments

Comments
 (0)