Skip to content

Commit 8927cee

Browse files
chore(release): prep 4.6.0 - in-band CEA-608 closed captions (#77)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XZTEfmztPE8hAdjHdBr9BH
1 parent 089c6e0 commit 8927cee

2 files changed

Lines changed: 8 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ the public-API contract.
1010

1111
## [Unreleased]
1212

13+
## [4.6.0] — 2026-06-27
14+
1315
### Added
1416

15-
- **In-band CEA-608 closed captions from a demuxable caption track, rendered through the host overlay (#77).** A source whose only caption track is an embedded CEA-608 stream (`eia_608`, e.g. a QuickTime/MP4 `c608` track) previously could not render: FFmpegBuild ships no `ccaption` decoder, so the side-demuxer `EmbeddedSubtitleDecoder` open failed and the track sat active-but-blank (`subActive=true / subCues=0`). The engine now reads that caption track's `cc_data` off the segment producer's existing source connection — a read-only observer keeps the `eia_608` stream in the demuxer's keep-set, hands each of its packets to an external `ClosedCaptionTap`, then drops it (never muxed → the loopback-HLS segment output is byte-identical to the no-CC path). An in-house CEA-608 decoder (pop-on / roll-up / paint-on, PAC row addressing, mid-row codes, and the basic / special / extended West-European character sets; odd-parity validation, doubled-control suppression and the character / PAC tables validated against FFmpeg's `ccaption_dec.c`) turns the bytes into cues published on the same `subtitleCues` host-overlay path as every other side-decoded subtitle codec. Because the tap owns the cue buffer and rides the producer (re-threaded onto every restart via `makeProducer`), captions appear instantly on enable — no second demuxer, no extra connection — and survive seek / reload / wedge. The native `mov_text` rendition (#55) is untouched: CC is excluded from that path (it can't become `tx3g`) and rendered through the overlay like the bitmap subtitle codecs, so — as with those — it is host-overlay only (no PiP / AirPlay CC). First cut: 608 field-1 / channel CC1; CEA-708 (DTVCC) and field 2 are follow-ons. Thanks to DrHurt for the externalise-subtitles steer.
17+
- **In-band CEA-608 closed captions from a demuxable caption track, rendered through the host overlay (#77).** A source whose only caption track is an embedded CEA-608 stream (`eia_608`, e.g. a QuickTime/MP4 `c608` track) previously could not render: FFmpegBuild ships no `ccaption` decoder, so the side-demuxer `EmbeddedSubtitleDecoder` open failed and the track sat active-but-blank (`subActive=true / subCues=0`). The engine now reads that caption track's `cc_data` off the segment producer's existing source connection: a read-only observer keeps the `eia_608` stream in the demuxer's keep-set, hands each of its packets to an external `ClosedCaptionTap`, then drops it (never muxed → the loopback-HLS segment output is byte-identical to the no-CC path). An in-house CEA-608 decoder (pop-on / roll-up / paint-on, PAC row addressing, mid-row codes, and the basic / special / extended West-European character sets; odd-parity validation, doubled-control suppression and the character / PAC tables validated against FFmpeg's `ccaption_dec.c`) turns the bytes into cues published on the same `subtitleCues` host-overlay path as every other side-decoded subtitle codec. Because the tap owns the cue buffer and rides the producer (re-threaded onto every restart via `makeProducer`), captions appear instantly on enable (no second demuxer, no extra connection) and survive seek / reload / wedge. The native `mov_text` rendition (#55) is untouched: CC is excluded from that path (it can't become `tx3g`) and rendered through the overlay like the bitmap subtitle codecs, so (as with those) it is host-overlay only (no PiP / AirPlay CC). First cut: 608 field-1 / channel CC1; CEA-708 (DTVCC) and field 2 are follow-ons. Thanks to DrHurt for the externalise-subtitles steer.
18+
19+
([release notes](https://github.com/superuser404notfound/AetherEngine/releases/tag/4.6.0))
1620

1721
## [4.5.7] — 2026-06-27
1822

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Subtitle cues land in raw source PTS; render the overlay against `player.sourceT
152152
Install via Swift Package Manager:
153153

154154
```swift
155-
.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "4.5.7")
155+
.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "4.6.0")
156156
```
157157

158158
Two complementary samples ship in `Examples/`:
@@ -275,10 +275,10 @@ Browse all of this as a searchable site at **[aetherengine.superuser404.de](http
275275
AetherEngine uses [Semantic Versioning](https://semver.org). The public API surface — every `public` declaration in `Sources/AetherEngine/` — is the stability contract. **Major** removes / renames public symbols or breaks adopters; **Minor** adds public API or codec / format support; **Patch** fixes bugs with no public API change. `internal` types are not part of the contract.
276276

277277
```swift
278-
.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "4.5.7")
278+
.package(url: "https://github.com/superuser404notfound/AetherEngine", from: "4.6.0")
279279
```
280280

281-
Pin to `.upToNextMinor(from: "4.5.7")` for stricter teams that prefer to opt into minor bumps explicitly.
281+
Pin to `.upToNextMinor(from: "4.6.0")` for stricter teams that prefer to opt into minor bumps explicitly.
282282

283283
## Requirements
284284

0 commit comments

Comments
 (0)