feat(cc608): choose the timecc608 caption mode, defaulting to paint-on - #329
Merged
Conversation
timecc608 injected one pop-on caption per second, built and flipped inside the cue's own frames, so the caption became visible ~0.5 s into the second its clock named. go-608 v0.9.0 generates all three CTA-608 caption modes per unit, so the option now names one: <channel>-<lang>[-<mode>[-<modifier>]] with paint (the default), pop, pop-sc, roll2 and roll3. Paint-on is the default because it is self-contained by construction: each cue clears the screen and writes the caption straight onto it two characters per frame, so no cue's data leaves its own segment, every segment decodes standalone, and a client that starts, seeks or joins anywhere is correct from the first cue boundary it sees. The typing doubles as a liveness tell. Roll-up (roll2, roll3) types each line onto the base row of a window that scrolls the earlier lines up, reset at the start of every segment so the display owes nothing to the previous one; it is limited to 2 or 3 rows because the caption's own lines put its base row at row 3. Pop-on keeps both placements. With -pop each cue's EOC rides its cue's first frame and the build drains over the frames before it, so the caption is displayed over exactly the interval its text names; the cost is that a cue's build lives in the preceding segment, and a receiver joining mid-stream gets a leading EOC without it - blank on a fresh decoder, one cue of a stale caption on one that keeps 608 state, correct from the next cue on. That is a receiver-side matter: an ENM ahead of the EOC would erase the build about to be flipped. -pop-sc trades the frame accuracy back for a segment that stands alone. The scheduling is go-608's per-unit builders throughout. Their generate.Unit carries a unit's number, start time and frame count as independent facts, so a segment whose number does not match its media time - startnr_, a non-zero availabilityStartTime - still gets the right clock, and the next unit's start comes from the fragment's media duration in ticks rather than frames times frame duration, which a fractional frame rate would drift on. NumCues divides a segment down into whole periods, so a cue is never shorter than a second: a 1.92s segment gets one 1.92s cue instead of two of 0.96s. The language field is a three-letter ISO 639-2 code. It is used in one place, the SCTE 214-1 accessibility descriptor value (value="CC1=eng"), whose scheme is defined in those terms; it is not DASH's RFC 5646 @lang, which this option never sets, so en, en-US and zh-Hans would have gone straight into a non-conformant descriptor. A single-token language also makes the value's fields positional, so a mistyped mode or modifier is reported instead of being read as part of the language. The tests decode the injected cc_data back in presentation order - the order a conformant receiver reassembles it in - and assert the caption text and the frame it lands on: across two consecutive segments for the cross-segment pop-on case, for AVC and HEVC, at 30, 29.97 and 24 fps, through the low-latency chunked path, and per frame for paint-on's clear-and-type and roll-up's scroll history. Test configurations come from CreateCC608Config, so each test names its mode exactly as a request does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #326, which fixed only the pop-on flip placement. With go-608 v0.9.0 generating all three CTA-608 caption modes per unit,
timecc608can name the mode instead, and the default becomes the one whose segments are independent.The value is now
<channel>-<lang>[-<mode>[-<modifier>]]:timecc608_CC1-engtimecc608_CC1-eng-roll3roll2,roll3)timecc608_CC1-eng-poptimecc608_CC1-eng-pop-scPaint-on is the default. Each cue clears the screen and writes the caption straight onto it, so no cue's data leaves its own segment: every segment decodes standalone and a client that starts, seeks or joins anywhere is correct from the first cue boundary it sees. The typing doubles as a liveness tell.
Roll-up types each line onto the base row of a window that scrolls the earlier lines up, reset at the start of every segment. Limited to 2 or 3 rows because the caption's own lines put its base row at row 3 — a 4-row window would need a row 0.
Pop-on keeps both placements.
-popputs each EOC on its cue's first frame with the build draining over the frames before it, so the caption is displayed over exactly the interval its text names; the cost is that a cue's build lives in the preceding segment, and a receiver joining mid-stream gets a leading EOC without it — blank on a fresh decoder, one cue of a stale caption on one that keeps 608 state, correct from the next cue on. A sender cannot paper over that: an ENM ahead of the EOC would erase the build about to be flipped.-pop-sctrades the frame accuracy back for a segment that stands alone.Also in here
generate.Unitcarries a unit's number, start time and frame count as independent facts, so a segment whose number does not match its media time (startnr_, a non-zero availabilityStartTime) still gets the right clock, and the next unit's start comes from the fragment's media duration in ticks rather than frames × frame duration, which a fractional frame rate would drift on.NumCuesdivides a segment down into whole periods, so a 1.92 s segment gets one 1.92 s cue instead of two of 0.96 s. Segments of 2 s and 2.002 s are unaffected.value="CC1=eng"), whose scheme is defined in those terms — not DASH's RFC 5646@lang, which this option never sets.en,en-USandzh-Hanswere previously passed straight into a non-conformant descriptor. A single-token language also makes the fields positional, so a mistyped mode or modifier is reported instead of being read as part of the language.Verification
The tests decode the injected
cc_databack in presentation order — the order a conformant receiver reassembles it in — and assert the caption text and the frame it lands on: across two consecutive segments for the cross-segment pop-on case, for AVC and HEVC, at 30, 29.97 and 24 fps, through the low-latency chunked path, and per frame for paint-on's clear-and-type and roll-up's scroll history. Test configurations come fromCreateCC608Config, so each test names its mode exactly as a request does.go test ./...andgolangci-lint runare clean. Not yet watched in a real player.🤖 Generated with Claude Code