cloudflare / cloudflare/moq-rs
moq-pub: include prft Producer Reference Time Box passthrough
- Dominant language
- Rust
- Stars
- 166
- Forks
- 59
- Avg merge
- 18h 21m
- Merged PRs (30d)
- 22
Description
For MoQT streaming, clients currently don't have something similar to HLS/DASH AvailabilityStartTime/PROGRAM-DATE-TIME for clock alignment or latency measurement. CMAF supports in-band means of signaling this type of info via prft box. One potential implementation guarded by feature flag outlined in below diff:
```
diff --git a/moq-pub/src/main.rs b/moq-pub/src/main.rs
index 17d6403..1c5c27c 100644
--- a/moq-pub/src/main.rs
+++ b/moq-pub/src/main.rs
@@ -38,6 +38,14 @@ pub struct Cli {
#[arg(long)]
pub name: String,
+ /// Forward Producer Reference Time (prft) boxes to subscribers.
+ ///
+ /// When the input fMP4 contains prft boxes (e.g. `ffmpeg -write_prft wallclock`),
+ /// attach them to the following moof object so players can map media time to the
+ /// producer's UTC wall-clock and compute live latency. Off by default.
+ #[arg(long)]
+ pub forward_prft: bool,
+
/// The TLS configuration.
#[command(flatten)]
pub tls: moq_native_ietf::tls::Args,
@@ -58,7 +66,7 @@ async fn main() -> anyhow::Result<()> {
let (writer, _, reader) =
serve::Tracks::new(TrackNamespace::from_utf8_path(&cli.name)).produce();
- let media = Media::new(writer)?;
+ let media = Media::new(writer, cli.forward_prft)?;
let tls = cli.tls.load()?;
diff --git a/moq-pub/src/media.rs b/moq-pub/src/media.rs
index 3cb0d9e..0018e97 100644
--- a/moq-pub/src/media.rs
+++ b/moq-pub/src/media.rs
@@ -28,10 +28,18 @@ pub struct Media {
// The current track name
current: Option,
+
+ // Pre-moof boxes (e.g. prft) buffered to prepend onto the next moof object,
+ // so subscribers receive the producer's UTC->media-time mapping for latency.
+ pending_pre_moof: Option,
+
+ // When true, forward prft boxes to subscribers (off by default to match
+ // stock behaviour; enable with `--forward-prft`).
+ forward_prft: bool,
}
impl Media {
- pub fn new(mut broadcast: TracksWriter) -> anyhow::Result {
+ pub fn new(mut broadcast: TracksWriter, forward_prft: bool) -> anyhow::Result {
let catalog = broadcast
.create(".catalog")
.context("broadcast closed")?
@@ -49,6 +57,8 @@ impl Media {
ftyp: None,
moov: None,
current: None,
+ pending_pre_moof: None,
+ forward_prft,
})
}
@@ -118,6 +128,18 @@ impl Media {
}
}
+ // Prepend any buffered pre-moof boxes (e.g. prft) so the published
+ // object is [prft]+moof and the subscriber keeps the UTC anchor.
+ let header_bytes = match self.pending_pre_moof.take() {
+ Some(pre) => {
+ let mut combined = BytesMut::with_capacity(pre.len() + atom.len());
+ combined.put_slice(&pre);
+ combined.put_slice(&atom);
+ combined.freeze()
+ }
+ None => atom,
+ };
+
// Get the track for this moof.
let track = self
.tracks
@@ -130,7 +152,7 @@ impl Media {
// Publish the moof header, creating a new segment if it's a keyframe.
track
- .header(atom, fragment)
+ .header(header_bytes, fragment)
.context("failed to publish moof")?;
}
mp4::BoxType::MdatBox => {
@@ -146,7 +168,12 @@ impl Media {
}
_ => {
- // Skip unknown atoms
+ // Forward Producer Reference Time boxes (prft) by attaching them to
+ // the next moof object; players use the UTC->media-time mapping they
+ // carry to compute live latency. All other unknown boxes are skipped.
+ if self.forward_prft && atom.len() >= 8 && &atom[4..8] == b"prft" {
+ self.pending_pre_moof = Some(atom);
+ }
}
}
```
Contributor guide
Research direction
Start in moq-pub/src/main.rs at the CLI definition and Media construction, then read moq-pub/src/media.rs to follow how MP4 atoms become published moof objects. Verify the feature flag is off by default, and when enabled, prft boxes from the input are attached to the following moof while other unknown boxes retain their current behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- audio-video-rtc
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100