HLS Source Requirements
When you create a live session with sourceType: "HLS_PULL" and pictureInPicture: true, SignStream must decode your source frame-accurately in order to composite the signer onto it. Your manifest is probed at session creation and checked against the contract below, so an incompatible source fails fast with a 400 instead of producing a broken stream minutes later.
This contract applies only to picture-in-picture sessions. A signer-only HLS_PULL session (pictureInPicture absent or false) is not subject to it, and neither are RTMP_PUSH or SRT_PUSH sources.
Canonical shape
Sources matching all of the following are passed straight through to the compositor with no re-encode — the lowest-latency, highest-quality path.
| Dimension | Accepted value |
|---|---|
| Video codec | H.264 |
| Video profile | Baseline, Main, or High |
| Video level | 4.2 or lower |
| Resolution | 1920 × 1080 or lower |
| Framerate | Constant 24, 25, 30, 50, or 60 fps |
| GOP length | 6 s or shorter, keyframe-aligned to the segment boundary |
| Audio codec | AAC-LC or HE-AAC |
| Audio bitrate | 192 kbps or lower |
| Container | fMP4/CMAF (.m4s) or MPEG-TS (.ts) |
| HLS version | 3, 6, or 7 |
Both a video and an audio track are required.
Automatically normalized
These sources are accepted and re-encoded to the canonical shape for you. Expect a small additional latency and CPU cost, but no action on your side.
- H.264 with a GOP longer than 6 s (up to 12 s), or an unbounded IDR cadence
- H.264 High-10 / High-422 profile
- Variable framerate (VFR)
- Non-canonical constant framerates such as 23.976 or 29.97
- AAC at a non-canonical bitrate up to 320 kbps
- MPEG-TS with A/V-only interleaving
- Any single-dimension mismatch above where the source is otherwise within contract
Rejected at session creation
These cannot be fixed downstream, and POST /v2/live/sessions returns a 400:
- Non-H.264 video — HEVC/H.265, VP9, AV1, MPEG-2
- Encrypted or DRM-protected segments
- Resolution above 3840 × 2160 (4K itself is accepted via normalization)
- A GOP longer than 12 s, or 30 s or more without a keyframe
- Video-only or audio-only sources
- A non-HLS URL, an unreachable origin, an expired presigned URL, or a manifest that fails to parse
Error responses
Live session errors use the nested error envelope: a code you can branch on, a human-readable message, and — where the failure is dimension-specific — a details object naming the offending field.
{
"error": {
"code": "HLS_INPUT_UNREACHABLE",
"type": "VALIDATION_ERROR",
"message": "failed to reach HLS source URL",
"details": {
"url": "https://origin.example.com/live/stream.m3u8",
"reason": "connection timeout"
},
"requestId": "req_01HZ..."
}
}{
"error": {
"code": "HLS_INPUT_MALFORMED",
"type": "VALIDATION_ERROR",
"message": "HLS manifest is invalid: no segments found",
"details": {
"url": "https://origin.example.com/live/stream.m3u8"
}
}
}{
"error": {
"code": "HLS_INPUT_INCOMPATIBLE",
"type": "VALIDATION_ERROR",
"message": "H.264 profile 'high-10' is not supported",
"details": {
"video_profile": "high-10",
"expected_profiles": ["baseline", "main", "high"]
}
}
}{
"error": {
"code": "HLS_INPUT_NORMALIZE_CAPACITY",
"type": "SERVICE_UNAVAILABLE",
"message": "capacity exhausted, retry in 30s"
}
}A 503 HLS_INPUT_NORMALIZE_CAPACITY carries a Retry-After: 30 header. It is transient — retry the create call; do not change your source.
Troubleshooting
| Symptom | What to check |
|---|---|
HLS_INPUT_UNREACHABLE | The URL is reachable from the public internet, not IP-allowlisted, and any signature on it has not expired |
HLS_INPUT_MALFORMED | The manifest is a media or master playlist with at least one segment, and declares #EXT-X-VERSION |
HLS_INPUT_INCOMPATIBLE | Read details — it names the dimension that failed and the values accepted for it, then re-encode at source |
HLS_INPUT_NORMALIZE_CAPACITY | Nothing on your side — retry after 30 seconds |
Need HEVC, DRM-protected input, or another exception? Contact support@signapse.ai — some sources can be supported case by case.