Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
joaoantoniocardoso committed Oct 30, 2024
1 parent 3913043 commit 2bd8615
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/lib/mavlink/mavlink_camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl MavlinkCameraInner {

let mavlink_stream_type = match video_stream_uri.scheme() {
"rtsp" => mavlink::common::VideoStreamType::VIDEO_STREAM_TYPE_RTSP,
"udp" => mavlink::common::VideoStreamType::VIDEO_STREAM_TYPE_RTPUDP,
"udp" | "udp265" => mavlink::common::VideoStreamType::VIDEO_STREAM_TYPE_RTPUDP,
unsupported => {
return Err(anyhow!(
"Scheme {unsupported:#?} is not supported for a Mavlink Camera."
Expand Down
4 changes: 2 additions & 2 deletions src/lib/stream/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,9 +404,9 @@ fn validate_endpoints(video_and_stream_information: &VideoAndStreamInformation)
VideoSourceType::Redirect(_)
) {
match scheme {
"udp" | "rtsp" => return None,
"udp" | "udp265" | "rtsp" => return None,
_ => return Some(anyhow!(
"The URL's scheme for REDIRECT endpoints should be \"udp\" or \"rtsp\", but was: {scheme:?}",
"The URL's scheme for REDIRECT endpoints should be \"udp\", \"udp265\", or \"rtsp\", but was: {scheme:?}",
))
};
}
Expand Down
23 changes: 23 additions & 0 deletions src/lib/stream/pipeline/fake_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ impl FakePipeline {
rtp_tee_name = rtp_tee_name,
)
}
VideoEncodeType::H265 => {
format!(concat!(
"videotestsrc pattern={pattern} is-live=true do-timestamp=true",
" ! timeoverlay",
" ! video/x-raw,format=I420",
" ! x265enc tune=zerolatency speed-preset=ultrafast bitrate=5000",
" ! h265parse",
" ! capsfilter name={filter_name} caps=video/x-h265,profile={profile},stream-format=byte-stream,alignment=au,width={width},height={height},framerate={interval_denominator}/{interval_numerator}",
" ! tee name={video_tee_name} allow-not-linked=true",
" ! rtph265pay aggregate-mode=zero-latency config-interval=10 pt=96",
" ! tee name={rtp_tee_name} allow-not-linked=true"
),
pattern = pattern,
profile = "main",
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!(
Expand Down
4 changes: 2 additions & 2 deletions src/lib/stream/pipeline/redirect_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ impl RedirectPipeline {
sink_tee_name = sink_tee_name,
)
}
"udp" => {
"udp" | "udp265" => {
format!(
concat!(
"udpsrc address={address} port={port} close-socket=false auto-multicast=true",
"udpsrc address={address} port={port} close-socket=false auto-multicast=true do-timestamp=true",
" ! application/x-rtp",
" ! tee name={sink_tee_name} allow-not-linked=true"
),
Expand Down
22 changes: 21 additions & 1 deletion src/lib/stream/pipeline/v4l_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl V4lPipeline {
format!(
concat!(
"v4l2src device={device} do-timestamp=true",
" ! h264parse", // Here we need the parse to help the stream-format and alignment part, which is being fixed here because avc/au seems to reduce the CPU usage in the RTP payloading part.
" ! h264parse", // Here we need the parse to help the stream-format and alignment part, which is being fixated here because avc/au seems to reduce the CPU usage in the RTP payloading part.
" ! capsfilter name={filter_name} caps=video/x-h264,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",
Expand All @@ -73,6 +73,26 @@ impl V4lPipeline {
rtp_tee_name = rtp_tee_name,
)
}
VideoEncodeType::H265 => {
format!(
concat!(
"v4l2src device={device} do-timestamp=true",
" ! h265parse",
" ! capsfilter name={filter_name} caps=video/x-h265,stream-format=byte-stream,alignment=au,width={width},height={height},framerate={interval_denominator}/{interval_numerator}",
" ! tee name={video_tee_name} allow-not-linked=true",
" ! rtph265pay aggregate-mode=zero-latency config-interval=10 pt=96",
" ! tee name={rtp_tee_name} allow-not-linked=true"
),
device = device,
width = width,
height = height,
interval_denominator = interval_denominator,
interval_numerator = interval_numerator,
filter_name = filter_name,
video_tee_name = video_tee_name,
rtp_tee_name = rtp_tee_name,
)
}
VideoEncodeType::Yuyv => {
format!(
concat!(
Expand Down
13 changes: 13 additions & 0 deletions src/lib/stream/rtsp/rtsp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,19 @@ impl RTSPServer {
rtp_caps = rtp_caps,
)
}
"H265" => {
format!(
concat!(
"shmsrc socket-path={socket_path} do-timestamp=true is-live=false",
" ! queue leaky=downstream flush-on-eos=true silent=true max-size-buffers=0",
" ! capsfilter caps={rtp_caps:?}",
" ! rtph265depay",
" ! rtph265pay name=pay0 aggregate-mode=zero-latency config-interval=10 pt=96",
),
socket_path = socket_path,
rtp_caps = rtp_caps,
)
}
"RAW" => {
format!(
concat!(
Expand Down
14 changes: 14 additions & 0 deletions src/lib/stream/sink/image_sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,20 @@ impl ImageSink {
_transcoding_elements.push(filter);
_transcoding_elements.push(decoder);
}
VideoEncodeType::H265 => {
// For h265, we need to filter-out unwanted non-key frames here, before decoding it.
let filter = gst::ElementFactory::make("identity")
.property("drop-buffer-flags", gst::BufferFlags::DELTA_UNIT)
.property("sync", false)
.build()?;
let decoder = gst::ElementFactory::make("avdec_h265")
.property_from_str("lowres", "2") // (0) is 'full'; (1) is '1/2-size'; (2) is '1/4-size'
.build()?;
decoder.has_property("discard-corrupted-frames", None).then(|| decoder.set_property("discard-corrupted-frames", true));
decoder.has_property("std-compliance", None).then(|| decoder.set_property_from_str("std-compliance", "normal"));
_transcoding_elements.push(filter);
_transcoding_elements.push(decoder);
}
VideoEncodeType::Mjpg => {
let decoder = gst::ElementFactory::make("jpegdec").build()?;
decoder.has_property("discard-corrupted-frames", None).then(|| decoder.set_property("discard-corrupted-frames", true));
Expand Down
7 changes: 4 additions & 3 deletions src/lib/stream/sink/udp_sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl UdpSink {
let clients = addresses
.iter()
.filter_map(|address| {
if address.scheme() != "udp" {
if !matches!(address.scheme(), "udp" | "udp265") {
return None;
}
if let (Some(host), Some(port)) = (address.host(), address.port()) {
Expand All @@ -334,8 +334,9 @@ impl UdpSink {
.collect::<Vec<String>>()
.join(",");
let description = format!("multiudpsink sync=false clients={clients}");
let _udpsink =
gst::parse::launch(&description).context("Failed parsing pipeline description")?;
let _udpsink = gst::parse::launch(&description).context(format!(
"Failed parsing pipeline description: {description:?}"
))?;

let udpsink_sink_pad = _udpsink
.static_pad("sink")
Expand Down
6 changes: 3 additions & 3 deletions src/lib/stream/webrtc/signalling_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,9 @@ impl SignallingServer {
let (height, width, encode, interval) =
match &stream.video_and_stream.stream_information.configuration {
crate::stream::types::CaptureConfiguration::Video(configuration) => {
// Filter out non-H264 local streams
if configuration.encode != crate::video::types::VideoEncodeType::H264 {
trace!("Stream {:?} will not be listed in available streams because it's encoding isn't H264 (it's {:?} instead)", stream.video_and_stream.name, configuration.encode);
// Filter out non-H264/h265 local streams
if !matches!(configuration.encode, crate::video::types::VideoEncodeType::H264 | crate::video::types::VideoEncodeType::H265) {
trace!("Stream {:?} will not be listed in available streams because it's encoding isn't H264 or H265 (it's {:?} instead)", stream.video_and_stream.name, configuration.encode);
return None;
}
(
Expand Down
3 changes: 0 additions & 3 deletions src/lib/video/local/video_source_local_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ use tracing::*;

use lazy_static::lazy_static;

lazy_static! {
static ref H264_PROFILES: Arc<Mutex<HashMap<String, String>>> = Default::default();
}
lazy_static! {
static ref VIDEO_FORMATS: Arc<Mutex<HashMap<String, Vec<Format>>>> = Default::default();
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/video/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl VideoEncodeType {
let fourcc = fourcc.to_uppercase();
match fourcc.as_str() {
"H264" => VideoEncodeType::H264,
"H265" | "HEVC" => VideoEncodeType::H265,
"MJPG" => VideoEncodeType::Mjpg,
"YUYV" => VideoEncodeType::Yuyv,
_ => VideoEncodeType::Unknown(fourcc),
Expand Down
5 changes: 5 additions & 0 deletions src/lib/video/video_source_gst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl VideoSource for VideoSourceGst {
.collect();

let sizes: Vec<Size> = [
(160, 120),
(320, 240),
(640, 480),
(720, 480),
Expand All @@ -70,6 +71,10 @@ impl VideoSource for VideoSourceGst {
encode: VideoEncodeType::H264,
sizes: sizes.clone(),
},
Format {
encode: VideoEncodeType::H265,
sizes: sizes.clone(),
},
Format {
encode: VideoEncodeType::Yuyv,
sizes: sizes.clone(),
Expand Down

0 comments on commit 2bd8615

Please sign in to comment.