···6677The actual metadata insertion and signing done to each video segment is through
88[C2PA](https://c2pa.org/) tooling. A
99-[fork](https://github.com/streamplace/c2pa-rs) of their Rust
1010-SDK that adds support for ES256K is used, and called in Go through FFI. The code
1111-for this can be seen in `rust/iroh-streamplace/src/c2pa.rs`.
99+[fork](https://github.com/streamplace/c2pa-rs) of their Rust SDK that adds
1010+support for ES256K is used, and called in Go through FFI. The code for this can
1111+be seen in `rust/iroh-streamplace/src/c2pa.rs`.
12121313The metadata stored in the video with C2PA must be in a valid C2PA "manifest"
1414format, documented in the specification. Here is an example Streamplace
···9797 "Iptc4xmpExt": "http://iptc.org/std/Iptc4xmpExt/2008-02-29/"
9898 },
9999 "dc:creator": "did:plc:y3lae7hmqiwyq7w2v3bcb2c2",
100100- "dc:title": [
101101- "🦎🦎"
102102- ],
103103- "dc:date": [
104104- "2025-10-21T19:24:24.156Z"
105105- ],
100100+ "dc:title": ["🦎🦎"],
101101+ "dc:date": ["2025-10-21T19:24:24.156Z"],
106102 "distributionPolicy": {
107103 "deleteAfter": "2025-10-21T19:29:24.000Z"
108104 },
···157153158154The official version of c2patool can extract this manifest, but will not
159155consider it valid due to the use of ES256K. If you build c2patool from the
160160-[fork](https://github.com/streamplace/c2pa-rs) used by
161161-Streamplace, it will validate.
156156+[fork](https://github.com/streamplace/c2pa-rs) used by Streamplace, it will
157157+validate.
162158163159Note the variety of information stored in the manifest: user DID, signing key,
164160timestamp, content warnings, copyright, etc. More can be added in the future,
165161for example whether you consent to remixing.
166162167167-You can see several assertions with the name `place.stream.*`. This is
168168-where Streamplace-specific metadata is stored, and is related to the lexicon.
169169-It's the easiest place to parse out this metadata.
163163+You can see several assertions with the name `place.stream.*`. This is where
164164+Streamplace-specific metadata is stored, and is related to the lexicon. It's the
165165+easiest place to parse out this metadata.
170166171171-In addition to the primary `place.stream` assertions, we make a best-effort attempt to translate the Streamplace assertions into spec-compliant C2PA metadata assertions, which are also included in the signed manifest. This allows other C2PA-compliant software to parse out information about Streamplace segments, such as content warnings. However, not everything Streamplace does fits neatly into C2PA-compliant metadata, so the primary source of truth for metadata on a Streamplace segment remains the `place.stream` assertions.
167167+In addition to the primary `place.stream` assertions, we make a best-effort
168168+attempt to translate the Streamplace assertions into spec-compliant C2PA
169169+metadata assertions, which are also included in the signed manifest. This allows
170170+other C2PA-compliant software to parse out information about Streamplace
171171+segments, such as content warnings. However, not everything Streamplace does
172172+fits neatly into C2PA-compliant metadata, so the primary source of truth for
173173+metadata on a Streamplace segment remains the `place.stream` assertions.
172174173175## Code paths
174176
···2020 the
2121 [IPTC controlled vocabulary for content warnings](https://cv.iptc.org/newscodes/contentwarning/).
2222 Each warning provides descriptions to help creators properly categorize their
2323- content. Streamplace node operators may also configure their nodes to exclude certain types of content.
2323+ content. Streamplace node operators may also configure their nodes to exclude
2424+ certain types of content.
24252. **Content Rights** (`place.stream.metadata.contentRights`): This section
2526 captures copyright and attribution information, including the creator’s name,
2627 copyright notice, publication year, license type, and credit line. The system
···31323. **Distribution Policy** (`place.stream.metadata.distributionPolicy`): This
3233 section currently allows creators to specify a `deleteAfter` property, which
3334 is meant to indicate the time after which the user no longer wants the stream
3434- to be made available for playback. It also allows you to optionally restrict syndication of your livestream to a certain set of broadcasters.
3535+ to be made available for playback. It also allows you to optionally restrict
3636+ syndication of your livestream to a certain set of broadcasters.
35373638When a user creates or updates their metadata configuration through the
3739frontend, the record is published to their Personal Data Server (PDS) with the
···2222 and **distribution policy**. This record is also synced by nodes to their
2323 local database.
24245. **Stream Authentication**: When a user starts a stream, they include their
2525- stream key as a param in the WHIP or RTMPS request to the node. The node decodes the
2626- key, extracts the private key and DID, and verifies that the public key
2727- exists and is valid.
2525+ stream key as a param in the WHIP or RTMPS request to the node. The node
2626+ decodes the key, extracts the private key and DID, and verifies that the
2727+ public key exists and is valid.
28286. **Signer Creation**: Once authenticated, the node creates a signer instance
2929 using the user's private key.
30307. **Segmentation**: The incoming live stream is segmented into one-second MP4
3131 chunks.
32328. **Manifest Creation and Signing**: For each segment, the node creates a C2PA
3333- manifest using the user's metadata configuration. It then uses the streamer's private key to sign the manifest, and embeds the signed manifest directly into
3434- the MP4 segment.
3333+ manifest using the user's metadata configuration. It then uses the streamer's
3434+ private key to sign the manifest, and embeds the signed manifest directly
3535+ into the MP4 segment.
35369. **Signed Segments**: The output is a continuous stream of MP4 segments, each
3637 cryptographically signed and containing its own C2PA manifest.