summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOneric <oneric@oneric.stub>2022-09-14 15:23:52 +0200
committerOneric <oneric@oneric.stub>2022-10-14 20:21:09 +0200
commit82c654056acfc240ef1400c2bdc67489be0d98fd (patch)
tree06d5fb4ed7a2896cb9e6762c5b7782b95bcead09
parent371aa684cf8027e1f25d1a3341d0b3d374509408 (diff)
downloadlibass-82c654056acfc240ef1400c2bdc67489be0d98fd.tar.bz2
libass-82c654056acfc240ef1400c2bdc67489be0d98fd.tar.xz
Implement v4++'s \kt tag
\kt allows to set the karaoke timing offset to a value other than the sum of preceeding karaoke durations. Notably this means multiple karaoke sequences of one Event can be ative at the same time. Like in VSFilter, \kt is available regardless of the format version. Using \kt after a karaoke tag in the same override sequence always makes the preceeding karaoke act as if already completed. Using \kt within a run resets timing for the next karaoke run. Addresses part of https://github.com/libass/libass/issues/461. Further support for v4++ requires at least an ABI break.
-rw-r--r--libass/ass_parse.c21
-rw-r--r--libass/ass_render.c3
-rw-r--r--libass/ass_render.h2
3 files changed, 25 insertions, 1 deletions
diff --git a/libass/ass_parse.c b/libass/ass_parse.c
index f43831e..a7437c6 100644
--- a/libass/ass_parse.c
+++ b/libass/ass_parse.c
@@ -790,6 +790,14 @@ char *parse_tags(ASS_Renderer *render_priv, char *p, char *end, double pwr,
val = render_priv->state.style->Italic;
render_priv->state.italic = val;
update_font(render_priv);
+ } else if (tag("kt")) {
+ // v4++
+ double val = 0;
+ if (nargs)
+ val = argtod(*args) * 10;
+ render_priv->state.effect_skip_timing = dtoi32(val);
+ render_priv->state.effect_timing = 0;
+ render_priv->state.reset_effect = true;
} else if (tag("kf") || tag("K")) {
double val = 100;
if (nargs)
@@ -975,9 +983,16 @@ void process_karaoke_effects(ASS_Renderer *render_priv)
int32_t timing = 0, skip_timing = 0;
Effect effect_type = EF_NONE;
GlyphInfo *last_boundary = NULL;
+ bool has_reset = false;
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) {
+
+ if (render_priv->text_info.glyphs[i].reset_effect) {
+ has_reset = true;
+ skip_timing = 0;
+ }
+
// 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,
@@ -997,10 +1012,14 @@ void process_karaoke_effects(ASS_Renderer *render_priv)
if (effect_type == EF_NONE)
continue;
+ if (start->reset_effect)
+ timing = 0;
+
long long tm_start = timing + start->effect_skip_timing;
long long tm_end = tm_start + start->effect_timing;
- timing = tm_end + skip_timing;
+ timing = !has_reset * tm_end + skip_timing;
skip_timing = 0;
+ has_reset = false;
if (effect_type != EF_KARAOKE_KF)
tm_end = tm_start;
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 7e452df..4f3f20d 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -1099,6 +1099,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
render_priv->state.effect_type = EF_NONE;
render_priv->state.effect_timing = 0;
render_priv->state.effect_skip_timing = 0;
+ render_priv->state.reset_effect = false;
apply_transition_effects(render_priv, event);
render_priv->state.explicit = render_priv->state.evt_type != EVENT_NORMAL ||
@@ -2113,6 +2114,7 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event)
info->effect_type = render_priv->state.effect_type;
info->effect_timing = render_priv->state.effect_timing;
info->effect_skip_timing = render_priv->state.effect_skip_timing;
+ info->reset_effect = render_priv->state.reset_effect;
// VSFilter compatibility: font glyphs use PlayResY scaling in both dimensions
info->font_size =
fabs(render_priv->state.font_size * render_priv->screen_scale_y);
@@ -2153,6 +2155,7 @@ static bool parse_events(ASS_Renderer *render_priv, ASS_Event *event)
render_priv->state.effect_type = EF_NONE;
render_priv->state.effect_timing = 0;
render_priv->state.effect_skip_timing = 0;
+ render_priv->state.reset_effect = false;
}
return true;
diff --git a/libass/ass_render.h b/libass/ass_render.h
index e86219f..e9fe6dc 100644
--- a/libass/ass_render.h
+++ b/libass/ass_render.h
@@ -151,6 +151,7 @@ typedef struct glyph_info {
// after process_karaoke_effects: distance in subpixels from the karaoke origin.
// part of the glyph to the left of it is displayed in a different color.
int32_t effect_skip_timing; // delay after the end of last karaoke word
+ bool reset_effect;
int asc, desc; // font max ascender and descender
int be; // blur edges
double blur; // gaussian blur
@@ -254,6 +255,7 @@ typedef struct {
Effect effect_type;
int32_t effect_timing;
int32_t effect_skip_timing;
+ bool reset_effect;
enum {
SCROLL_LR, // left-to-right