Skip to content

Use typed ordered::Consumer for video/audio in moq-ffi#1163

Open
Qizot wants to merge 1 commit intomoq-dev:mainfrom
Qizot:moq-ffi-ordered-consumer
Open

Use typed ordered::Consumer for video/audio in moq-ffi#1163
Qizot wants to merge 1 commit intomoq-dev:mainfrom
Qizot:moq-ffi-ordered-consumer

Conversation

@Qizot
Copy link
Contributor

@Qizot Qizot commented Mar 25, 2026

Replace the generic subscribe_media with typed subscribe_video and subscribe_audio methods that accept catalog config and use moq_mux::ordered::Consumer<T> directly. Also fix CMAF PTS calculation to use DTS + CTS offset for correct timestamp decoding.

Replace the generic `subscribe_media` with typed `subscribe_video` and
`subscribe_audio` methods that accept catalog config and use
`moq_mux::ordered::Consumer<T>` directly. Also fix CMAF PTS calculation
to use DTS + CTS offset for correct timestamp decoding.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 25, 2026

Walkthrough

The pull request refactors the media consumer API to differentiate between video and audio streams. The subscribe_media method is replaced with separate subscribe_video and subscribe_audio methods that accept media-specific configuration. Supporting changes include adding Clone derives to FFI-exposed types (MoqDimensions, Container, MoqVideo, MoqAudio), implementing conversion traits from these FFI types to internal catalog configuration types, and updating the internal media consumer to use a tagged enum for handling video or audio streams. Additionally, CMAF container timestamp computation is updated to include composition timestamp offset in addition to decode timestamp.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: replacing generic subscribe_media with typed ordered::Consumer variants for video and audio in moq-ffi.
Description check ✅ Passed The description is related to the changeset, covering the core changes: replacing subscribe_media with subscribe_video/subscribe_audio, accepting catalog config, and fixing CMAF PTS calculation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
rs/moq-mux/src/cmaf/container.rs (1)

45-46: Add a direct regression test for non-zero CTS offsets.

This is the right fix, but none of the shown tests exercise a CMAF sample where cts != 0, so a future regression back to raw DTS handling would slip through. A focused decode test here with a positive CTS offset would make this change much safer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rs/moq-mux/src/cmaf/container.rs` around lines 45 - 46, Add a regression test
that constructs/decodes a CMAF sample with a non-zero CTS offset and asserts the
resulting Timestamp equals DTS + CTS (not raw DTS); specifically exercise the
pts calculation that uses "let pts = dts as i64 + entry.cts.unwrap_or(0) as i64"
and the call to Timestamp::from_scale so future changes don't regress to using
raw dts. Create a focused unit test that sets entry.cts to a positive value,
runs the same decode/path used by the existing CMAF tests, and assert the
produced timestamp (or sample PTS) equals the expected scaled value computed
from dts + cts. Ensure the test fails if code ignores entry.cts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rs/moq-ffi/src/media.rs`:
- Around line 33-51: The current TryFrom implementations for MoqVideo ->
hang::catalog::VideoConfig (and the analogous MoqAudio ->
hang::catalog::AudioConfig) drop timing metadata by hardcoding jitter: None and
optimize_for_latency: None; update the FFI types MoqVideo and MoqAudio to
include jitter and optimize_for_latency fields, ensure convert_catalog()
populates those fields from the importer, and change the TryFrom implementations
to map MoqVideo.jitter -> hang::catalog::VideoConfig.jitter and
MoqVideo.optimize_for_latency -> optimize_for_latency (and the analogous
MoqAudio mappings) instead of setting them to None so the rebuilt configs
preserve computed jitter/latency preferences when fed into
moq_mux::ordered::Consumer.

---

Nitpick comments:
In `@rs/moq-mux/src/cmaf/container.rs`:
- Around line 45-46: Add a regression test that constructs/decodes a CMAF sample
with a non-zero CTS offset and asserts the resulting Timestamp equals DTS + CTS
(not raw DTS); specifically exercise the pts calculation that uses "let pts =
dts as i64 + entry.cts.unwrap_or(0) as i64" and the call to
Timestamp::from_scale so future changes don't regress to using raw dts. Create a
focused unit test that sets entry.cts to a positive value, runs the same
decode/path used by the existing CMAF tests, and assert the produced timestamp
(or sample PTS) equals the expected scaled value computed from dts + cts. Ensure
the test fails if code ignores entry.cts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c675377-0946-40e0-8b60-b5bc0dbdd9de

📥 Commits

Reviewing files that changed from the base of the PR and between 4ddd4b0 and 751f0a6.

📒 Files selected for processing (4)
  • rs/moq-ffi/src/consumer.rs
  • rs/moq-ffi/src/media.rs
  • rs/moq-ffi/src/test.rs
  • rs/moq-mux/src/cmaf/container.rs

Comment on lines +33 to +51
impl TryFrom<MoqVideo> for hang::catalog::VideoConfig {
type Error = crate::error::MoqError;

fn try_from(v: MoqVideo) -> Result<Self, Self::Error> {
Ok(Self {
codec: v.codec.parse().map_err(|e: hang::Error| crate::error::MoqError::Codec(e.to_string()))?,
description: v.description.map(bytes::Bytes::from),
coded_width: v.coded.as_ref().map(|d| d.width),
coded_height: v.coded.as_ref().map(|d| d.height),
display_ratio_width: v.display_ratio.as_ref().map(|d| d.width),
display_ratio_height: v.display_ratio.as_ref().map(|d| d.height),
bitrate: v.bitrate,
framerate: v.framerate,
optimize_for_latency: None,
container: v.container.into(),
jitter: None,
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- New FFI TryFrom impls ---\n'
sed -n '33,67p' rs/moq-ffi/src/media.rs

printf '\n--- FFI catalog export path ---\n'
sed -n '107,165p' rs/moq-ffi/src/media.rs

printf '\n--- VideoConfig semantics ---\n'
sed -n '130,150p' rs/hang/src/catalog/video/mod.rs

printf '\n--- AudioConfig semantics ---\n'
sed -n '88,100p' rs/hang/src/catalog/audio/mod.rs

printf '\n--- fMP4 importer computing jitter ---\n'
sed -n '639,667p' rs/moq-mux/src/import/fmp4.rs

Repository: moq-dev/moq

Length of output: 5101


Expose and preserve jitter and optimize_for_latency in FFI conversions.

The TryFrom<MoqVideo> and TryFrom<MoqAudio> implementations lose timing metadata by hardcoding jitter: None and optimize_for_latency: None. This is problematic because:

  1. The internal catalog types (hang::catalog::VideoConfig / AudioConfig) explicitly document these fields and their semantics (e.g., jitter defaults to None means "flush immediately", but can be set to frame duration, b-frame budget, or segment duration).
  2. The fMP4 importer actively computes and updates jitter based on fragment boundaries and frame rates.
  3. Your PR now feeds these rebuilt configs directly into moq_mux::ordered::Consumer, so the loss changes playback/buffering behavior for tracks with computed jitter or latency preferences.

The FFI types MoqVideo and MoqAudio must expose these fields. Then populate them in convert_catalog() and carry them through the TryFrom implementations instead of hardcoding None.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rs/moq-ffi/src/media.rs` around lines 33 - 51, The current TryFrom
implementations for MoqVideo -> hang::catalog::VideoConfig (and the analogous
MoqAudio -> hang::catalog::AudioConfig) drop timing metadata by hardcoding
jitter: None and optimize_for_latency: None; update the FFI types MoqVideo and
MoqAudio to include jitter and optimize_for_latency fields, ensure
convert_catalog() populates those fields from the importer, and change the
TryFrom implementations to map MoqVideo.jitter ->
hang::catalog::VideoConfig.jitter and MoqVideo.optimize_for_latency ->
optimize_for_latency (and the analogous MoqAudio mappings) instead of setting
them to None so the rebuilt configs preserve computed jitter/latency preferences
when fed into moq_mux::ordered::Consumer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant