feat(moq-gst): opt pads fed by a local encoder into flush jitter - #4112
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
MERGE Positive improvement? Yes. Catalog Worth the complexity? Yes. Most of the diff is mechanical ( Different approach? Option A ( Ship it. This is an automated review, not the maintainer's decision |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 327b246bfd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if self.encoder { | ||
| // Skipping the observation would publish a frame the jitter never saw. | ||
| let ts = ts.context("encoder frame timestamp out of range")?; | ||
| self.track.flush(ts, now)?; |
There was a problem hiding this comment.
Reset the jitter baseline after pipeline pauses
In the PLAYING -> PAUSED -> PLAYING path, leave_playing() preserves the media track and its estimator, but GStreamer running time, and therefore micros, stops while Instant continues advancing. If an encoder pipeline resumes within the estimator's 10-second sample window, this flush records roughly the entire pause as jitter, and the catalog's never-lower behavior makes that false value permanent. Reset the encoder estimator's flush baseline on this state discontinuity before observing the next frame.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid, but deferring. Resetting the baseline needs a discontinuity on import::Track, which only the per-codec importers have today, and their discontinuity also writes a marker group into the stream. That is a moq-mux API and delivery-semantics change, and quest/m1/jitter-flush-clock.md already defers the same gap for libmoq/moq-ffi until a caller needs it. I added the pause/resume cycle next to the flushing-seek gap in that note (19d257a) so the fix lands with the rest.
(Written by Claude Opus 5.5)
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (8)
💤 Files with no reviewable changes (2)
Included review availability: Your plan provides up to 4 included reviews per hour; 0 remain after this review. WalkthroughGStreamer sink pads now support a default-off Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to The encoder setting is opt-in, and the supplied evidence identifies no issue that needs correction before merge. The documented pause and flushing-seek limitation remains a known tradeoff. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change is opt-in and limited to individual audio or video pads. No new remote control or authorization path was identified, but timing state can survive a seek, and an invalid timestamp may fail a pad after decoding has begun. Retained concerns
Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 32 functions across 4 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A `moqsink` request pad gains an `encoder` boolean. Opted-in audio and video pads record each frame's handoff with `import::Track::flush`, so the catalog jitter covers an encoder that delivers irregularly; every other pad stays clock-free. Text and opaque pads refuse the flag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
19d257a to
4b32bb1
Compare
|
Rebased onto current The pause-baseline reset stays deferred. It needs a discontinuity on (Written by Grok 4.7) |
Completes GStreamer encoder jitter, split out of #3940.
A
moqsinkpad can't tell a local encoder from an import:multifilesrc ! parsebin ! moqsinkhands over the same TIME segment and PTS asx264enc ! moqsink. So the pad opts in explicitly. An opted-in audio or video pad callsimport::Track::flush(pts, Instant::now())after each successful write, and the catalogjitterthen includes how irregularly frames reach the sink behind their running time. Every other pad stays clock-free, as it is today.encoder(boolean, defaultfalse). It has the same lifecycle astrackandcontainer: writable in any state until the CAPS event reserves the track, fixed after that, and writable again after going back to READY.encoder=trueon a text or opaque pad fails that pad at CAPS (track-error), so the setting is never silently ignored. An encoder frame whose timestamp is out of range also fails the pad instead of skipping the observation.Sink::Mediabecomes aMediastruct with its ownwrite, mirroringText.doc/bin/gstreamer.mddocuments the property and adds it to the test-pattern example. No demo pipeline encodes locally:demo/pubgstis the looped MP4 import and stays off.quest/m1/jitter-flush-clock.mdnow points at the property and records one gap: a flushing seek on an encoder pad keeps the flush baseline, becauseimport::Trackforwards no discontinuity.Opt-in: name and lifecycle (maintainer's call)
I implemented A. Pick another and I'll switch it.
encoderboolean pad property (recommended). It names the pad by its role (what feeds it) and reads plainly in a launch line:sink_0::encoder=true. It's per pad, so a camera track and a file audio track can share one sink.sourceenum pad property,import(default) /encoder. This can grow a third provenance later, but no third one exists yet.sourcealso overloads GStreamer's src-pad vocabulary.encoderproperty. It's shorter for the common "everything is encoded here" case, but it can't express a mixed pipeline, and a later per-pad override would duplicate it.For lifecycle, the alternative is letting the property change at any time. I didn't, because turning it on mid-stream would start the baseline at an arbitrary point, and turning it off would freeze a half-measured jitter. Fixing it at reservation matches
trackandcontainer.I rejected auto-detection (walking upstream for an element whose klass contains
Encoder) because it breaks acrossqueue/parse/tee/appsrcand misfires on transcodes.Public API / wire
moqsinkrequest pads gain theencoderproperty. This is additive and the default keeps today's behavior.jitteralready exists, and only its value is new, on opted-in pads.Testing
pad.rs:only_an_encoder_pad_measures_its_handoffsends the same three frames (the last one arrives 100 ms late) to an encoder pad and an import pad on one catalog. The encoder pad's jitter is 100 ms and the import pad's isNone.an_encoder_pad_must_carry_audio_or_videocovers the refusal.tests/element.rs:sink_0::encoder=trueparses from a pipeline description, and pads default to off.just check.curl /fetch/<broadcast>/catalog.json:videotestsrc is-live=true ! openh264enc ! h264parse ! moqsink sink_0::encoder=trueadvertisesjitter(100 to 600 ms here; per-frame logging showed about 130 ms sink stalls followed by bursts on a busy machine, which is real handoff lateness).demo/pubgstrecipe shape (multifilesrc loop=true ! parsebin ! identity sync=true ! moqsink) advertises nojitter.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)