Commits (1)
......@@ -234,6 +234,19 @@ dependencies = [
"thiserror",
]
[[package]]
name = "gstreamer-base-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a083493c3c340e71fa7c66eebda016e9fafc03eb1b4804cf9b2bad61994b078e"
dependencies = [
"glib-sys",
"gobject-sys",
"gstreamer-sys",
"libc",
"system-deps",
]
[[package]]
name = "gstreamer-net"
version = "0.18.0"
......@@ -259,6 +272,33 @@ dependencies = [
"system-deps",
]
[[package]]
name = "gstreamer-rtp"
version = "0.18.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f97b6af1d900db0c35811a24a2c99d04bc0249ccbad54aed773f4337a39a9e3"
dependencies = [
"bitflags",
"glib",
"gstreamer",
"gstreamer-rtp-sys",
"libc",
"once_cell",
]
[[package]]
name = "gstreamer-rtp-sys"
version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2afde26d03b4146a39d07f576082f97b3775e7884ef3ccef5c4b7c0917e17469"
dependencies = [
"glib-sys",
"gstreamer-base-sys",
"gstreamer-sys",
"libc",
"system-deps",
]
[[package]]
name = "gstreamer-rtsp"
version = "0.18.0"
......@@ -525,6 +565,7 @@ dependencies = [
"anyhow",
"futures",
"gstreamer",
"gstreamer-rtp",
"gstreamer-rtsp",
"gstreamer-rtsp-server",
"once_cell",
......
......@@ -7,11 +7,13 @@ Please read the blog post for details.
The code below needs GStreamer from the git `main` branch at the time of
writing, or version 1.22 or newer.
## Sender Clock Time Retrieval
## Rapid synchronization via RTP header extensions
This branch contains the code that retrieves the sender clock times on the
receiver and renders them over the video frames on the receiver and also
prints them on stdout.
prints them on stdout. The times are synchronized between the sender and
receiver via an RTP header extension from the very beginning instead of
relying on RTCP.
Both timestamps on the video frames should be the same: the one rendered on
the sender at the top and the one rendered on the receiver at the bottom.
......
......@@ -36,6 +36,17 @@ fn main() -> Result<(), Error> {
glib::closure!(|_playbin: &gst::Pipeline, source: &gst::Element| {
source.set_property("latency", 40u32);
source.set_property("add-reference-timestamp-meta", true);
// Don't bother updating inter-stream offsets if the difference to the previous
// configuration is less than 1ms. The synchronization will have rounding errors
// in the range of the RTP clock rate, i.e. 1/90000s and 1/48000s in this case.
source.connect_closure(
"new-manager",
false,
glib::closure!(|_rtspsrc: &gst::Element, rtpbin: &gst::Element| {
rtpbin.set_property("min-ts-offset", gst::ClockTime::from_mseconds(1));
}),
);
}),
);
......
......@@ -9,5 +9,6 @@ anyhow = "1"
futures = "0.3"
once_cell = "1"
gst = { version = "0.18", package = "gstreamer", features = ["v1_20"] }
gst-rtp = { version = "0.18", package = "gstreamer-rtp", features = ["v1_20" ] }
gst-rtsp = { version = "0.18", package = "gstreamer-rtsp", features = ["v1_20" ] }
gst-rtsp-server = { version = "0.18", package = "gstreamer-rtsp-server", features = ["v1_20"] }
......@@ -5,6 +5,7 @@
use gst::glib;
use gst::gst_error;
use gst::prelude::*;
use gst_rtp::prelude::*;
use gst_rtsp_server::prelude::*;
use anyhow::{Context, Error};
......@@ -139,6 +140,14 @@ mod media_factory {
// Configure this RTP stream to payload type 96.
video_pay.set_property("pt", 96u32);
// Add RFC6051 64-bit NTP timestamp RTP header extension.
let hdr_ext = gst_rtp::RTPHeaderExtension::create_from_uri(
"urn:ietf:params:rtp-hdrext:ntp-64",
)
.context("Creating NTP 64-bit RTP header extension")?;
hdr_ext.set_id(1);
video_pay.emit_by_name::<()>("add-extension", &[&hdr_ext]);
bin.add_many(&[&video_src, &video_overlay, &video_enc, &video_pay])
.expect("Failed to add video elements to bin");
......@@ -174,6 +183,14 @@ mod media_factory {
// Configure this RTP stream to payload type 97.
audio_pay.set_property("pt", 97u32);
// Add RFC6051 64-bit NTP timestamp RTP header extension.
let hdr_ext = gst_rtp::RTPHeaderExtension::create_from_uri(
"urn:ietf:params:rtp-hdrext:ntp-64",
)
.context("Creating NTP 64-bit RTP header extension")?;
hdr_ext.set_id(1);
audio_pay.emit_by_name::<()>("add-extension", &[&hdr_ext]);
bin.add_many(&[&audio_src, &audio_enc, &audio_pay])
.expect("Failed to add audio elements to bin");
......