Summary
Add support for embedding C2PA manifests in OGG containers (Vorbis and Opus), implementing C2PA Technical Specification v2.3 Section A.3.5.
This section was added to the spec in December 2025 but has no implementation in c2pa-rs or any other C2PA SDK. This would be the first reference implementation.
Approach
Per the spec, the manifest store is placed in a dedicated OGG logical bitstream whose first packet begins with the 5-byte identifier \x00c2pa. Hash binding follows Section 18.7.3.7, treating each logical bitstream as a "box" named Stream-{serial} (decimal).
Implementation details
- New file:
sdk/src/asset_handlers/ogg_io.rs (~1400 lines including tests)
- No new crate dependencies -- OGG page parsing/writing implemented inline (the format is a simple 27-byte header + segment table + body)
- Traits implemented:
CAIReader, CAIWriter, AssetIO, AssetPatch, AssetBoxHash
- Supported types:
ogg, audio/ogg, opus, audio/opus
- 29 unit tests + 2 integration tests (
test_streams_ogg, test_streams_opus)
- Tested end-to-end with
c2patool on real 9MB+ audio files -- validation_state: Valid
Key design decisions
- OGG page CRC-32 uses the spec polynomial
0x04c11db7 (direct/non-reflected) with a precomputed lookup table
- Write ordering follows RFC 3533: all BOS pages grouped before any data pages
- For large manifests (>65KB), C2PA pages are split across the BOS group and data section; BoxMap handles non-contiguous ranges
RemoteRefEmbed is not implemented -- the C2PA spec does not define XMP embedding for OGG
- Both Vorbis and Opus are supported via the same handler since the embedding mechanism operates at the OGG container level
References
We have a PR ready if this is something the project is interested in.
Summary
Add support for embedding C2PA manifests in OGG containers (Vorbis and Opus), implementing C2PA Technical Specification v2.3 Section A.3.5.
This section was added to the spec in December 2025 but has no implementation in c2pa-rs or any other C2PA SDK. This would be the first reference implementation.
Approach
Per the spec, the manifest store is placed in a dedicated OGG logical bitstream whose first packet begins with the 5-byte identifier
\x00c2pa. Hash binding follows Section 18.7.3.7, treating each logical bitstream as a "box" namedStream-{serial}(decimal).Implementation details
sdk/src/asset_handlers/ogg_io.rs(~1400 lines including tests)CAIReader,CAIWriter,AssetIO,AssetPatch,AssetBoxHashogg,audio/ogg,opus,audio/opustest_streams_ogg,test_streams_opus)c2patoolon real 9MB+ audio files --validation_state: ValidKey design decisions
0x04c11db7(direct/non-reflected) with a precomputed lookup tableRemoteRefEmbedis not implemented -- the C2PA spec does not define XMP embedding for OGGReferences
We have a PR ready if this is something the project is interested in.