Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ Catalog HLS field.
- [Buffered playback subscribes in ascending order](/quest/m1/buffered-ascending.md) - a buffered `<moq-watch>` asks for the oldest group first, so a voice reply's opening arrives first, and audio's head hold shrinks to the floor
- [JS reload config](/quest/m1/js-reload-config.md) - `@moq/net` reload takes Rust's `healthy` backoff and no ignored `extensions`
- [TS fidelity and recovery](/quest/m1/ts-reliability/README.md) - both modes have explicit profiles, automated validation, loss tests, and a dedicated guide
- [Encoders declare no reordering](/quest/m1/encoder-reorder.md) - moq-video encoders publish `reorder: 0`
- [JS resume reports drops](/quest/m1/resume-drops.md) - a routed JS subscriber reports its copies' dropped groups, so publishers forward SUBSCRIBE_DROP
- [Lowered resume floor](/quest/m1/resume-floor.md) - lowering a resumed reader's floor re-offers groups only a released copy cached
- [WebGPU on Safari](/quest/m1/webgpu-safari.md) - the WebGPU renderer is verified on Safari 26 for macOS and iOS
Expand Down
18 changes: 0 additions & 18 deletions quest/m1/encoder-reorder.md

This file was deleted.

22 changes: 21 additions & 1 deletion rs/moq-video/src/encode/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ pub(crate) struct Applied {
}

impl Applied {
// A confirmed preset disables frame reordering even when the bitstream omits its bound.
fn reorder(&self, parsed: Option<u8>) -> Option<u8> {
self.preset.map(|_| 0).or(parsed)
}

/// A report that `preset` took effect through `controls`.
#[cfg_attr(
not(any(feature = "openh264", feature = "nvidia", feature = "vaapi", target_os = "macos")),
Expand Down Expand Up @@ -294,6 +299,7 @@ impl Config {
// rides in an optional VUI. Fill them from the config that produced the rest.
rendition.bitrate.get_or_insert(self.resolved_bitrate().as_bps());
rendition.framerate.get_or_insert(self.framerate.as_f64());
rendition.reorder = sink.applied().reorder(rendition.reorder);
Ok((rendition, sink))
}

Expand Down Expand Up @@ -380,7 +386,6 @@ impl Encoder {

/// The latency and compression controls the backend applied for
/// [`Config::preset`], fixed for the session's lifetime.
#[cfg(test)]
pub(crate) fn applied(&self) -> Applied {
self.backend.applied()
}
Expand Down Expand Up @@ -566,6 +571,21 @@ mod tests {

use crate::{I420, Surface};

#[test]
fn reorder_is_declared_only_for_confirmed_controls() {
for preset in [Preset::LowLatency, Preset::Balanced, Preset::Quality] {
let applied = Applied {
preset: Some(preset),
..Applied::default()
};
assert_eq!(applied.reorder(None), Some(0));
assert_eq!(applied.reorder(Some(3)), Some(0));
}
let unconfirmed = Applied::default();
assert_eq!(unconfirmed.reorder(None), None);
assert_eq!(unconfirmed.reorder(Some(3)), Some(3));
}

/// A mid-gray RGBA buffer: encodable without a camera.
fn gray_rgba(width: u32, height: u32) -> Vec<u8> {
vec![0x80u8; width as usize * height as usize * 4]
Expand Down
1 change: 1 addition & 0 deletions rs/moq-video/src/encode/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,7 @@ mod tests {
// Software (openh264) so the test is deterministic and never touches a
// hardware backend.
let (name, config) = roundtrip_rendition(Codec::H264, encoder::Kind::Software).await;
assert_eq!(config.reorder, Some(0));
assert!(name.ends_with(".avc3"));
assert_eq!(config.coded_width, Some(320));
assert_eq!(config.coded_height, Some(240));
Expand Down
22 changes: 19 additions & 3 deletions rs/moq-video/src/encode/sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use std::sync::Arc;

use super::Encoded;
use super::encoder::Config;
use super::encoder::{Applied, Config};
use crate::{Error, Frame};

#[cfg(apple)]
Expand Down Expand Up @@ -75,6 +75,12 @@ impl Sink {
self.0.name()
}

/// The latency and compression controls the backend applied, like the
/// encoder's own report.
pub(crate) fn applied(&self) -> Applied {
self.0.applied()
}

/// Cut a new group at the next frame, like
/// [`Encoder::cut`](super::Encoder::cut).
///
Expand Down Expand Up @@ -152,7 +158,7 @@ mod threaded {
use tokio::sync::{mpsc, oneshot};

use super::super::Encoded;
use super::super::encoder::{Config, Encoder};
use super::super::encoder::{Applied, Config, Encoder};
use crate::worker::{Ready, Worker};
use crate::{Error, Frame};

Expand Down Expand Up @@ -198,6 +204,7 @@ mod threaded {
/// What the encode thread reports once its encoder is open.
pub struct Opened {
name: String,
applied: Applied,
}

/// Build an encoder for `config` and serve requests until the channel closes.
Expand All @@ -210,6 +217,7 @@ mod threaded {
// If the awaiting `open` was cancelled, give up before encoding.
let opened = Opened {
name: encoder.name().to_owned(),
applied: encoder.applied(),
};
if !ready.ok(opened) {
return;
Expand Down Expand Up @@ -266,6 +274,10 @@ mod threaded {
&self.0.info().name
}

pub fn applied(&self) -> Applied {
self.0.info().applied.clone()
}

pub async fn cut(&mut self) -> Result<(), Error> {
self.0.request(|resp| Request::Cut { resp }).await
}
Expand Down Expand Up @@ -300,7 +312,7 @@ mod inline {
use std::sync::Arc;

use super::super::Encoded;
use super::super::encoder::{Config, Encoder};
use super::super::encoder::{Applied, Config, Encoder};
use crate::{Error, Frame};

/// An [`Encoder`] driven inline on the calling thread (see the module docs).
Expand All @@ -320,6 +332,10 @@ mod inline {
self.0.name()
}

pub fn applied(&self) -> Applied {
self.0.applied()
}

/// Async only to match the threaded `Inner`; there's no thread to hand this
/// to, so it runs inline. The same holds for the calls below.
pub async fn cut(&mut self) -> Result<(), Error> {
Expand Down
Loading