From b4303ad8c2142b8bdbedebb381a8ad4e6cd4feda Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Sun, 18 Oct 2020 18:08:39 +0300 Subject: Handle \k0 \ko0 \kf0 \K0 like VSFilter Don't break runs when zero-duration karaoke starts unless the karaoke *type* differs. The zero-duration karaoke block ends up glued to the previous block (if any). In case of subsequent karaoke override tags, like {\k100\k0}, the intervening tags will advance the next karaoke block's start time, but not this combined block's start or end time. Of course, runs may still be broken in the same place if there's another reason for a run break besides karaoke, so zero-duration karaoke blocks can still occur. Run breaks that have no karaoke tags at all also still produce zero-duration karaoke blocks (if there is karaoke at all). --- libass/ass_parse.c | 13 ++++++++++--- libass/ass_render.c | 7 ++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libass/ass_parse.c b/libass/ass_parse.c index 11d7f1b..5666ca6 100644 --- a/libass/ass_parse.c +++ b/libass/ass_parse.c @@ -974,13 +974,19 @@ void process_karaoke_effects(ASS_Renderer *render_priv) { long long tm_current = render_priv->time - render_priv->state.event->Start; - int timing = 0; + int timing = 0, skip_timing = 0; Effect effect_type = EF_NONE; GlyphInfo *last_boundary = NULL; for (int i = 0; i <= render_priv->text_info.length; i++) { if (i < render_priv->text_info.length && - !render_priv->text_info.glyphs[i].starts_new_run) + !render_priv->text_info.glyphs[i].starts_new_run) { + // VSFilter compatibility: if we have \k12345\k0 without a run + // break, subsequent text is still part of the same karaoke word, + // the current word's starting and ending time stay unchanged, + // but the starting time of the next karaoke word is advanced. + skip_timing += render_priv->text_info.glyphs[i].effect_skip_timing; continue; + } GlyphInfo *start = last_boundary; GlyphInfo *end = render_priv->text_info.glyphs + i; @@ -995,7 +1001,8 @@ void process_karaoke_effects(ASS_Renderer *render_priv) long long tm_start = timing + start->effect_skip_timing; long long tm_end = tm_start + start->effect_timing; - timing = tm_end; + timing = tm_end + skip_timing; + skip_timing = 0; if (effect_type != EF_KARAOKE_KF) tm_end = tm_start; diff --git a/libass/ass_render.c b/libass/ass_render.c index a324935..0ef7158 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -1855,12 +1855,15 @@ fix_glyph_scaling(ASS_Renderer *priv, GlyphInfo *glyph) // Initial run splitting based purely on the characters' styles static void split_style_runs(ASS_Renderer *render_priv) { + Effect last_effect_type = render_priv->text_info.glyphs[0].effect_type; render_priv->text_info.glyphs[0].starts_new_run = true; for (int i = 1; i < render_priv->text_info.length; i++) { GlyphInfo *info = render_priv->text_info.glyphs + i; GlyphInfo *last = render_priv->text_info.glyphs + (i - 1); + Effect effect_type = info->effect_type; info->starts_new_run = - info->effect_type != EF_NONE || + info->effect_timing || // but ignore effect_skip_timing + (effect_type != EF_NONE && effect_type != last_effect_type) || info->drawing_text || last->drawing_text || strcmp(last->font->desc.family, info->font->desc.family) || @@ -1888,6 +1891,8 @@ static void split_style_runs(ASS_Renderer *render_priv) last->italic != info->italic || last->bold != info->bold || ((last->flags ^ info->flags) & ~DECO_ROTATE); + if (effect_type != EF_NONE) + last_effect_type = effect_type; } } -- cgit v1.2.3