Skip to content

implement 3GPP narrowband codec sample entry (samr)#135

Merged
bradh merged 1 commit intokixelated:mainfrom
bradh:samr
Feb 19, 2026
Merged

implement 3GPP narrowband codec sample entry (samr)#135
bradh merged 1 commit intokixelated:mainfrom
bradh:samr

Conversation

@bradh
Copy link
Copy Markdown
Collaborator

@bradh bradh commented Jan 31, 2026

See 3GPP TS 26.244 or ETSI TS 126 244

Resolves #134

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 31, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Two new AMR atom kinds were added: Samr and Damr to the Any enum. A new amr module with submodules amrsampleentry, damr, and samr was added and re-exported. New public types: AmrSampleEntry (with Encode/Decode), Damr (Atom), and Samr (Atom, containing AmrSampleEntry and Damr). The Codec enum gained Samr(Samr) and corresponding encode/decode handling.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title "implement 3GPP narrowband codec sample entry (samr)" directly describes the main change - adding support for the samr (Narrowband AMR) sample entry codec, which is the primary objective of this PR.
Description check ✅ Passed The description references the 3GPP TS 26.244 specification and resolves issue #134, which aligns with the changeset adding samr codec support with proper specification compliance.
Linked Issues check ✅ Passed The PR fully implements samr support as specified in issue #134 [#134]. New files define Samr struct with AmrSampleEntry and Damr fields, Atom trait implementations for encoding/decoding per ETSI TS 126 244, and integration into the Codec enum, meeting all stated requirements.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing samr support: new amr module with submodules (samr.rs, damr.rs, amrsampleentry.rs), Codec enum extension, and encode/decode implementations. No unrelated changes detected.

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

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
Copy Markdown

@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: 3

🤖 Fix all issues with AI agents
In `@src/moov/trak/mdia/minf/stbl/stsd/amr/amrsampleentry.rs`:
- Around line 11-22: The encode implementation in AmrSampleEntry writes a 32-bit
value (16u32) causing a 30-byte output while decode expects two 16-bit fields
(total 28 bytes); replace the 16u32.encode(buf)? with two u16 writes matching
decode (e.g., 0u16.encode(buf)? followed by 16u16.encode(buf)?), update the
trailing comments to reflect Reserved_2 for each u16, and keep the rest of
AmrSampleEntry::encode unchanged so the encoded byte count matches the decoder.

In `@src/moov/trak/mdia/minf/stbl/stsd/amr/samr.rs`:
- Line 41: Update the stale comment in samr.rs that reads "Streaminfo metadata
block only" to accurately describe the AMR test data used here (e.g., mention
that this is AMR sample/frames or AMR-specific stream header/test vector), so
replace the FLAC-specific text with a concise AMR-specific description near the
top of the AMR test block in samr.rs.
- Line 19: The match arm using Any::Damr(atom) incorrectly calls atom.into() to
produce an Option; change the arm to wrap the extracted value with Some(atom)
and assign it to damr (i.e., use Some(atom) instead of atom.into()), updating
the match in the code handling Any::Damr and ensuring damr has type Option<...>
as intended.
🧹 Nitpick comments (1)
src/moov/trak/mdia/minf/stbl/stsd/amr/samr.rs (1)

49-71: Consider adding a round-trip test.

The current test only validates decoding. Adding an encode test or a decode→encode→decode round-trip test would help catch serialization mismatches (like the encode bug in AmrSampleEntry).

💡 Example round-trip test
#[test]
fn test_samr_roundtrip() {
    let original = Samr {
        amrsampleentry: AmrSampleEntry {
            data_reference_index: 1,
            timescale: 8000,
        },
        damr: Damr {
            vendor: b"erat".into(),
            decoder_version: 0,
            mode_set: 128,
            mode_change_period: 0,
            frames_per_sample: 1,
        },
    };

    let mut buf = Vec::new();
    original.encode(&mut buf).expect("failed to encode");

    let decoded = Samr::decode(&mut std::io::Cursor::new(&buf))
        .expect("failed to decode");

    assert_eq!(original, decoded);
}

Copy link
Copy Markdown

@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)
src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs (1)

1-39: No inline unit tests for Damr.

The damr.rs module has no #[cfg(test)] block. While samr.rs exercises Damr indirectly in its decode test, a standalone round-trip test in this module (encode → decode → assert field equality) would directly guard Damr's correctness in isolation.

As per coding guidelines, write unit tests inline within modules using #[cfg(test)].

🧪 Suggested inline test
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_damr_roundtrip() {
+        let damr = Damr {
+            vendor: FourCC::new(b"FFMP"),
+            decoder_version: 0,
+            mode_set: 0x81FF,
+            mode_change_period: 1,
+            frames_per_sample: 1,
+        };
+
+        let mut buf = Vec::new();
+        damr.encode(&mut buf).unwrap();
+        let decoded = Damr::decode(&mut buf.as_slice()).unwrap();
+        assert_eq!(damr, decoded);
+    }
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs` around lines 1 - 39, Add an
inline unit test under a #[cfg(test)] mod that constructs a Damr instance,
round-trips it through the Atom impl by calling Damr::encode_body (or the public
encode helper) into a buffer and then decoding it back via Damr::decode_body (or
the public decode helper), and assert that all fields (vendor, decoder_version,
mode_set, mode_change_period, frames_per_sample) match the original; name the
test something like round_trip_damr and place it in the same file near the Damr
definition so it exercises the Atom::encode_body and Atom::decode_body
implementations directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/moov/trak/mdia/minf/stbl/stsd/mod.rs`:
- Around line 121-126: The file contains unresolved merge conflict markers
around the Codec enum and another later block; remove the conflict markers
(<<<<<<<, =======, >>>>>>>) and restore both enum variants so Codec includes
both Wvtt(Wvtt) and Samr(Samr), and likewise ensure any match arms referencing
Self::Wvtt(atom) remain valid; repeat the same resolution for the other conflict
(lines referencing the same areas around 159-163) so no variants are dropped and
the code compiles cleanly.

---

Nitpick comments:
In `@src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs`:
- Around line 1-39: Add an inline unit test under a #[cfg(test)] mod that
constructs a Damr instance, round-trips it through the Atom impl by calling
Damr::encode_body (or the public encode helper) into a buffer and then decoding
it back via Damr::decode_body (or the public decode helper), and assert that all
fields (vendor, decoder_version, mode_set, mode_change_period,
frames_per_sample) match the original; name the test something like
round_trip_damr and place it in the same file near the Damr definition so it
exercises the Atom::encode_body and Atom::decode_body implementations directly.

@bradh
Copy link
Copy Markdown
Collaborator Author

bradh commented Feb 18, 2026

@coderabbitai: full review please

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 18, 2026

@bradh: I'll perform a full review of the PR, examining all the changes for the samr implementation.

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
src/moov/trak/mdia/minf/stbl/stsd/mod.rs (1)

121-123: Optional: Add a descriptive comment for the Samr variant.

Every other Codec variant is accompanied by a brief comment identifying the codec and spec reference. Samr(Samr) is the sole exception.

✏️ Suggested addition
     // WebVTT, ISO/IEC 14496-30
     Wvtt(Wvtt),
-    Samr(Samr),
+    // 3GPP Narrowband AMR (3GPP TS 26.244)
+    Samr(Samr),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/moov/trak/mdia/minf/stbl/stsd/mod.rs` around lines 121 - 123, Add a brief
descriptive comment for the Samr variant in the Codec enum (next to Samr(Samr))
similar to other variants (e.g., Wvtt), identifying it as the Microsoft SAMR
audio codec and optionally citing the relevant spec or RFC; update the comment
style to match surrounding comments so it is consistent with the other Codec
variant annotations.
src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs (1)

13-39: Add dedicated unit tests for Damr.

Per coding guidelines, unit tests should be written inline within modules using #[cfg(test)]. damr.rs has no tests of its own; coverage exists only transitively through samr.rs. An isolated test makes future regressions easier to diagnose.

✅ Suggested test block
#[cfg(test)]
mod tests {
    use super::*;
    use crate::coding::Decode;

    // AMRSpecificBox body (no outer header): vendor="erat", version=0, mode_set=0x0080, period=0, fps=1
    const ENCODED_DAMR_BODY: &[u8] = &[
        0x65, 0x72, 0x61, 0x74, // vendor = "erat"
        0x00,                   // decoder_version = 0
        0x00, 0x80,             // mode_set = 128
        0x00,                   // mode_change_period = 0
        0x01,                   // frames_per_sample = 1
    ];

    #[test]
    fn test_damr_decode() {
        let buf = &mut std::io::Cursor::new(ENCODED_DAMR_BODY);
        let damr = Damr::decode_body(buf).expect("failed to decode damr body");
        assert_eq!(damr.vendor, b"erat".into());
        assert_eq!(damr.decoder_version, 0);
        assert_eq!(damr.mode_set, 128);
        assert_eq!(damr.mode_change_period, 0);
        assert_eq!(damr.frames_per_sample, 1);
    }

    #[test]
    fn test_damr_encode() {
        let damr = Damr {
            vendor: b"erat".into(),
            decoder_version: 0,
            mode_set: 128,
            mode_change_period: 0,
            frames_per_sample: 1,
        };
        let mut buf = Vec::new();
        damr.encode_body(&mut buf).unwrap();
        assert_eq!(buf.as_slice(), ENCODED_DAMR_BODY);
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs` around lines 13 - 39, Add an
inline unit-test module under #[cfg(test)] in damr.rs that exercises
Damr::decode_body and Damr::encode_body: create a constant byte slice
representing the AMRSpecificBox body (vendor "erat", decoder_version=0,
mode_set=0x0080, mode_change_period=0, frames_per_sample=1), write a test that
decodes that slice via Damr::decode_body and asserts each field (vendor,
decoder_version, mode_set, mode_change_period, frames_per_sample), and a test
that constructs the same Damr struct, calls encode_body into a Vec, and asserts
the produced bytes equal the constant; import crate::coding::Decode where needed
and keep the tests inside mod tests with #[cfg(test)] so they run only in test
builds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/moov/trak/mdia/minf/stbl/stsd/amr/amrsampleentry.rs`:
- Around line 16-18: Replace the misleading "Reserved" comments with the correct
ISO 14496-12 field names: the two u16 values should be labeled channelcount (2)
and samplesize (16) instead of Reserved_2/Reserved_2, and the 4-byte block
before samplerate should be split/labeled as pre_defined + reserved (not a
single Reserved_4). Update the comments (and, if present, any helper constants
or variables used in amrsampleentry.rs) to reflect channelcount, samplesize, and
pre_defined/reserved so the encoded fields match the AudioSampleEntry spec.

---

Nitpick comments:
In `@src/moov/trak/mdia/minf/stbl/stsd/amr/damr.rs`:
- Around line 13-39: Add an inline unit-test module under #[cfg(test)] in
damr.rs that exercises Damr::decode_body and Damr::encode_body: create a
constant byte slice representing the AMRSpecificBox body (vendor "erat",
decoder_version=0, mode_set=0x0080, mode_change_period=0, frames_per_sample=1),
write a test that decodes that slice via Damr::decode_body and asserts each
field (vendor, decoder_version, mode_set, mode_change_period,
frames_per_sample), and a test that constructs the same Damr struct, calls
encode_body into a Vec, and asserts the produced bytes equal the constant;
import crate::coding::Decode where needed and keep the tests inside mod tests
with #[cfg(test)] so they run only in test builds.

In `@src/moov/trak/mdia/minf/stbl/stsd/mod.rs`:
- Around line 121-123: Add a brief descriptive comment for the Samr variant in
the Codec enum (next to Samr(Samr)) similar to other variants (e.g., Wvtt),
identifying it as the Microsoft SAMR audio codec and optionally citing the
relevant spec or RFC; update the comment style to match surrounding comments so
it is consistent with the other Codec variant annotations.

See 3GPP TS 26.244 or ETSI TS 126 244
@bradh
Copy link
Copy Markdown
Collaborator Author

bradh commented Feb 19, 2026

@coderabbitai: can you provide objective evidence (e.g. a specification reference) that the samr codec type derives from AudioSampleEntry?

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🌐 Web query:

3GPP TS 26.244 samr AudioSampleEntry section 6.5 6.7 structure

💡 Result:

In 3GPP TS 26.244, the AMR AudioSampleEntry for narrowband AMR uses sample entry type 'samr' (wideband uses 'sawb') and is defined in §6.5 as: [1]

AMRSampleEntry ::= BoxHeader                          // size, type='samr' or 'sawb'
                  Reserved_6                          // uint8[6] = 0
                  Data-reference-index                // uint16
                  Reserved_8                          // uint32[2] = 0
                  Reserved_2                          // uint16 = 2
                  Reserved_2                          // uint16 = 16
                  Reserved_4                          // uint32 = 0
                  TimeScale                           // uint16 (copied from mdhd timescale)
                  Reserved_2                          // uint16 = 0
                  AMRSpecificBox                      // always present for AMR/AMR-WB

The decoder-specific box referenced above is defined in §6.7 as AMRSpecificBox with box type 'damr', containing AMRDecSpecStruc: [1]

AMRSpecificBox ::= BoxHeader                          // size, type='damr'
                   DecSpecificInfo                    // AMRDecSpecStruc

AMRDecSpecStruc ::=
  vendor             // uint32 (4CC, informative)
  decoder_version    // uint8
  mode_set           // uint16 (bitmask of active AMR/AMR-WB modes)
  mode_change_period // uint8
  frames_per_sample  // uint8 (1..15)

Notes from §6.7: mode_set bit positions correspond to the AMR/AMR-WB FT mode numbers; frames_per_sample is how many 20 ms AMR frames are packed into one sample. [1]


@bradh: Based on 3GPP TS 26.244 Section 6.5, the samr codec does NOT derive from the standard AudioSampleEntry. Instead, it uses a custom structure called AMRSampleEntry.

Here's the specification structure from §6.5:

AMRSampleEntry ::= BoxHeader                          // size, type='samr' or 'sawb'
                  Reserved_6                          // uint8[6] = 0
                  Data-reference-index                // uint16
                  Reserved_8                          // uint32[2] = 0
                  Reserved_2                          // uint16 = 2
                  Reserved_2                          // uint16 = 16
                  Reserved_4                          // uint32 = 0
                  TimeScale                           // uint16 (copied from mdhd timescale)
                  Reserved_2                          // uint16 = 0
                  AMRSpecificBox                      // always present for AMR/AMR-WB

The key fields are:

  • Data-reference-index (uint16)
  • TimeScale (uint16)
  • AMRSpecificBox (damr box, defined in §6.7)

This custom structure explains why your implementation uses AmrSampleEntry with specific reserved byte handling in the Encode/Decode implementations, rather than inheriting from a standard AudioSampleEntry. The PR correctly follows the 3GPP specification.

@bradh bradh merged commit afe8572 into kixelated:main Feb 19, 2026
1 check passed
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/moov/trak/mdia/minf/stbl/stsd/amr/samr.rs (1)

5-8: Prefer amr_sample_entry over amrsampleentry for idiomatic field naming.

The field name amrsampleentry is a concatenation of three words without underscores. Rust convention uses underscores to separate words in compound identifiers (amr_sample_entry). Since this is a public field on a new type, renaming before merge is cheap and avoids a future breaking change.

♻️ Proposed rename
 pub struct Samr {
-    pub amrsampleentry: AmrSampleEntry,
+    pub amr_sample_entry: AmrSampleEntry,
     pub damr: Damr,
 }

The same rename would need to propagate to the decode_body constructor and encode_body:

     Ok(Self {
-        amrsampleentry,
+        amr_sample_entry: amrsampleentry,
         damr: damr.ok_or(Error::MissingBox(Damr::KIND))?,
     })
-    self.amrsampleentry.encode(buf)?;
+    self.amr_sample_entry.encode(buf)?;

And the two test structs (lines 57 and 75).

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

In `@src/moov/trak/mdia/minf/stbl/stsd/amr/samr.rs` around lines 5 - 8, The public
field name in struct Samr is non-idiomatic: rename the field amrsampleentry to
amr_sample_entry in the Samr struct, and propagate that change to all uses —
update the constructor in decode_body, the encoder in encode_body, and the two
test structs referenced (replace amrsampleentry -> amr_sample_entry) so
references compile; ensure any pattern matches, struct construction, and field
accesses use the new amr_sample_entry identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/moov/trak/mdia/minf/stbl/stsd/amr/samr.rs`:
- Around line 5-8: The public field name in struct Samr is non-idiomatic: rename
the field amrsampleentry to amr_sample_entry in the Samr struct, and propagate
that change to all uses — update the constructor in decode_body, the encoder in
encode_body, and the two test structs referenced (replace amrsampleentry ->
amr_sample_entry) so references compile; ensure any pattern matches, struct
construction, and field accesses use the new amr_sample_entry identifier.

@bradh bradh deleted the samr branch February 19, 2026 00:15
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.

missing box - samr

1 participant