From 1b2160ba4fcfaeee8a478b84d0155e796f133061 Mon Sep 17 00:00:00 2001 From: DmitriyLugovoy Date: Fri, 22 Mar 2024 21:51:55 +0200 Subject: [PATCH] add convertation from YUYV to h264, now QGroundControl can see our stream, fix ssl in Dockerfile, update docker/build_and_run.sh now container can see all our cameras --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- Cross.toml | 3 +++ docker/Dockerfile | 10 +++++----- docker/build_and_run.sh | 7 ++++++- src/mavlink/mavlink_camera.rs | 8 +++++--- src/stream/pipeline/v4l_pipeline.rs | 8 +++++--- src/stream/sink/image_sink.rs | 14 +++++++++++++- 8 files changed, 40 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eb62c011..90e7e454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2395,9 +2395,9 @@ dependencies = [ [[package]] name = "mavlink" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25c0885d2ff5393752980be397e3f6ce3ca97c92445c62263a9127061bcfaf42" +checksum = "17a33c99ebbba3b0b2a3d47dd05b42339602a4d0c0a877ed0e95ef57e6b80529" dependencies = [ "bitflags 1.3.2", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index 14972451..fec9fa08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ ts-rs = "7.1" cached = { version = "0.48", features = ["serde", "serde_json", "async_tokio_rt_multi_thread"] } ## Mavlink -mavlink = { version = "0.10.6", features = ["default", "emit-extensions"] } +mavlink = { version = "0.10.7", features = ["default", "emit-extensions"] } ## WebRTC async-tungstenite = { version = "0.25", features = ["tokio-runtime", "tokio-native-tls"] } diff --git a/Cross.toml b/Cross.toml index df1c80f0..303cdda0 100644 --- a/Cross.toml +++ b/Cross.toml @@ -6,3 +6,6 @@ image = "joaoantoniocardoso/cross-rs:armv7-unknown-linux-gnueabihf-bullseye-slim [target.aarch64-unknown-linux-gnu] image = "joaoantoniocardoso/cross-rs:aarch64-unknown-linux-gnu-bullseye-slim-with-gstreamer" + +[target.aarch64-buildroot-linux-gnu] +image = "joaoantoniocardoso/companion-base:update-gstreamer" diff --git a/docker/Dockerfile b/docker/Dockerfile index 109fc825..2d9cd774 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -from ubuntu:22.04 +FROM ubuntu:22.04 RUN apt update -y && \ apt install -y --no-install-recommends \ @@ -15,10 +15,10 @@ RUN apt update -y && \ # We need libssl.so.1.1 # Note: if the link breaks, find it here: http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/?C=M;O=D -RUN wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.21_amd64.deb && \ - dpkg -i libssl1.1_1.1.1f-1ubuntu2.21_amd64.deb ; \ - rm -rf libssl1.1_1.1.1f-1ubuntu2.21_amd64.deb +RUN wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.22_amd64.deb && \ + dpkg -i libssl1.1_1.1.1f-1ubuntu2.22_amd64.deb ; \ + rm -rf libssl1.1_1.1.1f-1ubuntu2.22_amd64.deb COPY ./target/x86_64-unknown-linux-gnu/release/mavlink-camera-manager / -ENTRYPOINT ./mavlink-camera-manager --mavlink=tcpout:192.168.2.2:5777 --verbose --reset +ENTRYPOINT ./mavlink-camera-manager --mavlink=tcpout:0.0.0.0:5777 --verbose --reset diff --git a/docker/build_and_run.sh b/docker/build_and_run.sh index 82c63773..4f91c27d 100755 --- a/docker/build_and_run.sh +++ b/docker/build_and_run.sh @@ -9,4 +9,9 @@ cross build --release --target=x86_64-unknown-linux-gnu docker build -t $USER/mavlink-camera-manager:$(git rev-parse HEAD) -f ./docker/Dockerfile . # Run -docker run -it --net=host $USER/mavlink-camera-manager:$(git rev-parse HEAD) +docker run -it --rm --network host\ + --privileged\ + -v /dev:/dev\ + -v /sys/devices:/sys/devices\ + -v ./logs:/logs\ + $USER/mavlink-camera-manager:$(git rev-parse HEAD)\ diff --git a/src/mavlink/mavlink_camera.rs b/src/mavlink/mavlink_camera.rs index 58427ff3..e411583f 100644 --- a/src/mavlink/mavlink_camera.rs +++ b/src/mavlink/mavlink_camera.rs @@ -138,9 +138,8 @@ impl MavlinkCameraInner { let component_id = camera.component.component_id; let system_id = camera.component.system_id; - let mut period = tokio::time::interval(tokio::time::Duration::from_secs(1)); loop { - period.tick().await; + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; let header = mavlink::MavHeader { system_id, @@ -277,7 +276,10 @@ impl MavlinkCameraInner { focal_length: 0.0, sensor_size_h: 0.0, sensor_size_v: 0.0, - flags: mavlink::common::CameraCapFlags::CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM, + flags: mavlink::common::CameraCapFlags::CAMERA_CAP_FLAGS_HAS_VIDEO_STREAM | + mavlink::common::CameraCapFlags::CAMERA_CAP_FLAGS_CAN_CAPTURE_IMAGE_IN_VIDEO_MODE | + mavlink::common::CameraCapFlags::CAMERA_CAP_FLAGS_HAS_BASIC_ZOOM | + mavlink::common::CameraCapFlags::CAMERA_CAP_FLAGS_HAS_BASIC_FOCUS, resolution_h: camera.component.resolution_h, resolution_v: camera.component.resolution_v, cam_definition_version: 0, diff --git a/src/stream/pipeline/v4l_pipeline.rs b/src/stream/pipeline/v4l_pipeline.rs index 68b52c59..b4e44a78 100644 --- a/src/stream/pipeline/v4l_pipeline.rs +++ b/src/stream/pipeline/v4l_pipeline.rs @@ -78,9 +78,11 @@ impl V4lPipeline { concat!( "v4l2src device={device} do-timestamp=true", " ! videoconvert", - " ! capsfilter name={filter_name} caps=video/x-raw,format=I420,width={width},height={height},framerate={interval_denominator}/{interval_numerator}", + " ! x264enc", + " ! h264parse", + " ! 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", - " ! rtpvrawpay pt=96", + " ! rtph264pay aggregate-mode=zero-latency config-interval=10 pt=96", " ! tee name={rtp_tee_name} allow-not-linked=true" ), device = device, @@ -120,7 +122,7 @@ impl V4lPipeline { } }; - debug!("pipeline_description: {description:#?}"); + debug!("pipeline_description: {description:?}"); let pipeline = gst::parse::launch(&description)?; diff --git a/src/stream/sink/image_sink.rs b/src/stream/sink/image_sink.rs index 1265af2e..79cf3222 100644 --- a/src/stream/sink/image_sink.rs +++ b/src/stream/sink/image_sink.rs @@ -352,7 +352,19 @@ impl ImageSink { decoder.has_property("discard-corrupted-frames", None).then(|| decoder.set_property("discard-corrupted-frames", true)); _transcoding_elements.push(decoder); } - VideoEncodeType::Yuyv => {} + VideoEncodeType::Yuyv => { + // For h264, 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_h264") + .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)); + _transcoding_elements.push(filter); + _transcoding_elements.push(decoder); + } _ => return Err(anyhow!("Unsupported video encoding for ImageSink: {encoding:?}. The supported are: H264, MJPG and YUYV")), };