Skip to content

esds: descriptor size varint encoded in reverse order; AudioSpecificConfig bit-extraction bugs #192

Description

@kixelated

Related to #76 — a concrete list of defects in src/moov/trak/mdia/minf/stbl/stsd/mp4a/esds.rs:

1. Descriptor size varint encoded in reverse group order.
Decode (esds.rs:51-58) reads the ISO 14496-1 base-128 length MSB-group-first (correct). Encode (esds.rs:96-104) emits the least-significant 7-bit group first with the continuation bit on it:

let mut size = tmp.len() as u32;
while size > 0 {
    let mut b = (size & 0x7F) as u8;   // low group first
    size >>= 7;
    if size > 0 { b |= 0x80; }
    b.encode(buf)?;
}

For body size 200 this writes C8 01, which decodes as size 9217 → corrupt stream. Additionally, size 0 writes no length byte at all (while size > 0 never runs), producing a tag with no length field. Currently only reachable via the public Descriptor::Unknown variant or any descriptor ≥ 128 bytes, so it's latent — but any user-constructed descriptor or payload growth hits it.

2. AudioSpecificConfig bit-extraction bugs (esds.rs:262-310).

  • :269 — extended audioObjectType: 32 + ((byte_a & 7) | (byte_b >> 5)) is missing << 3 on the first term; the two 3-bit halves are OR'd on top of each other. Any AOT ≥ 32 (USAC/xHE-AAC = 42) decodes to a wrong profile.
  • :286 — extended-profile channel config: (byte_b & 1) | (byte_c & 0xE0) should be ((byte_b & 1) << 3) | (byte_c >> 5); yields values up to 225 for a 4-bit field.
  • :279-283freq_index == 15 escape: the 24-bit explicit sample rate starts 7 bits into the byte stream but is read byte-aligned, the channel config is selected one bit off, the sample rate is then discarded, and encode can't reproduce the escape (existing TODO) — round-trip corrupts.
  • :306 — encode does self.profile << 3; for extended profiles ≥ 32 (which decode can produce) the shift silently truncates the AOT with no error.

3. EsDescriptor flags byte ignored (esds.rs:154).
streamDependenceFlag / URL_Flag / OCR_streamFlag are read and discarded (// XXX flags must be 0); when set, the following dependsOn_ES_ID / URL string / OCR_ES_ID bytes are misparsed as child descriptors.

4. Size-varint decode desync (esds.rs:52-58).
If the 4th size byte still has the continuation bit set, the loop exits silently with a truncated size instead of erroring, desyncing the parse.

Found during an extensive automated correctness review (Claude Code); verified against the current main sources.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions