scc/writer: delay colliding pop-on captions instead of dropping them - #548
scc/writer: delay colliding pop-on captions instead of dropping them#548jason-valenzuela wants to merge 1 commit into
Conversation
1113d90 to
d917292
Compare
|
@jason-valenzuela I would be tempted to wait until all chunks are collected before moving them. |
Got it! Will adjust my approach here. |
d917292 to
f9bce80
Compare
|
@palemieux Updated the approach here, let me know what you think! The chunk-moving logic is now run after the all the pop-on chunks are collected. |
palemieux
left a comment
There was a problem hiding this comment.
Is the issue happening with content that was originally authored for 608, or content that was authored in other formats?
| # pop-on captions are collected here at their natural (undelayed) positions and | ||
| # line 21 collisions are resolved in a post-pass below, once the whole list is | ||
| # known: (enm chunk, its erase chunk or None, caption begin time) | ||
| popon_captions: List = [] |
There was a problem hiding this comment.
Why create a popon_captions list when chunks could be sufficient?
There was a problem hiding this comment.
I added the intermediate list to keep each caption's (paint, erase) pair and its begin explicit for the delay pass and the warning. But I can build the paint/erase chunks straight into chunks in the loop and run the collision pass over chunks directly, pairing them there, and remove the extra list.
|
|
||
| return decoded_value | ||
|
|
||
| def _decode_min_popon_display_frames(value: str) -> int: |
There was a problem hiding this comment.
I am not sure there is every a correct value here since the duration of a caption is related to the amount of text present. I would define a simply boolean (by default true) that indicates whether overlapping captions should be dropped.
There was a problem hiding this comment.
Got it, will switch this over to a boolean config!
This issue is happening for content that was authored in other formats! I've been seeing this issue when we're doing VTT -> SCC conversions. |
f9bce80 to
9beb6f2
Compare
Problem
scc_writer.from_modelsilently drops whole pop-on captions when a caption's line-21 packets cannot be transmitted back-to-back with the previous caption's (theSkipping ISD … due to overlap in line 21 packetspath). On dense content this loses caption text with only a log warning.Fix
When a pop-on caption collides with the previous one, delay its onset to sit right after the previous caption's packets instead of dropping it, carrying the preceding erase (EDM) into the delayed chunk so no stale erase wipes it and the emitted timecodes stay monotonic and non-overlapping. The pull-back of the preceding erase is bounded to the minimum needed, so the previous caption keeps as much of its authored on-screen time as possible (and an author-written short cue is never itself penalised). A caption that still cannot achieve a minimum readable window even after delaying is dropped honestly (the existing warning) rather than emitted as a two-frame flash.
The minimum readable window is exposed as a new
SccWriterConfigurationfieldmin_popon_display_frames(default15≈ 0.5 s at 29.97 fps;0disables dropping entirely, preserving maximal text at the cost of possible flashes). The common, non-colliding path is unchanged — existing golden-SCC tests are untouched.Tests
test_dense_popon_no_line_drop— dense captions previously dropped now survive a write→read round-trip (exact SCC asserted)test_dense_popon_emitted_scc_is_ordered— emitted timecodes monotonic and non-overlappingtest_dense_popon_cascade_all_emitted_captions_displayable— every emitted caption meets the display floortest_dense_popon_authored_short_prev_not_dropped— a short authored cue no longer forces an unnecessary droptest_dense_popon_drop_only_when_infeasible— a caption is dropped only when no readable window existstest_dense_popon_erase_pullback— the bounded erase pull-back path (erase moved minimally, both captions keep a window above the floor)test_min_popon_display_frames— config parse/default/validationFull suite: 617 passed, 0 failures, 0 errors, 6 pre-existing skips.
Notes
from_modelindexeschunks[-2]under alen(chunks) > 0guard, which raisesIndexErrorwhen exactly one chunk exists — happy to file a separate issue.