summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-06-05 00:55:13 +0200
committerwm4 <wm4@nowhere>2014-06-05 01:15:14 +0200
commitdcecb9cba3ab2e9c1d082c9860aecb9e437e40f6 (patch)
treec366e02227a4814504f7911d0f6e2d48f5ec0ff4
parent4a4e464d1dadce90bc91dce5448890e987019d89 (diff)
downloadlibass-dcecb9cba3ab2e9c1d082c9860aecb9e437e40f6.tar.bz2
libass-dcecb9cba3ab2e9c1d082c9860aecb9e437e40f6.tar.xz
Add a mechanism for selective style overrides
This adds 2 new API functions: ass_set_selective_style_override() ass_set_selective_style_override_enabled() They can be used to force dialog text to use a specific ASS_Style. It uses a fuzzy heuristic for that, and the quality of results may vary. It does style overriding selectively and tries not to override things that need explicit styling. The heuristic for that isn't set in stone either, and can change with future libass versions. Closes libass#88.
-rw-r--r--libass/ass.h28
-rw-r--r--libass/ass_parse.c26
-rw-r--r--libass/ass_parse.h1
-rw-r--r--libass/ass_render.c101
-rw-r--r--libass/ass_render.h6
-rw-r--r--libass/ass_render_api.c18
-rw-r--r--libass/libass.sym2
7 files changed, 160 insertions, 22 deletions
diff --git a/libass/ass.h b/libass/ass.h
index b797a97..408bdeb 100644
--- a/libass/ass.h
+++ b/libass/ass.h
@@ -23,7 +23,7 @@
#include <stdarg.h>
#include "ass_types.h"
-#define LIBASS_VERSION 0x01102001
+#define LIBASS_VERSION 0x01103000
/*
* A linked list of images produced by an ass renderer.
@@ -320,6 +320,32 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
int update);
/**
+ * \brief Set selective style override mode.
+ * If enabled, the renderer attempts to override the ASS script's styling of
+ * normal subtitles, without affecting explicitly positioned text. If an event
+ * looks like a normal subtitle, parts of the font style are copied from the
+ * user style set with ass_set_selective_style_override().
+ * Warning: the heuristic used for deciding when to override the style is rather
+ * rough, and enabling this option can lead to incorrectly rendered
+ * subtitles. Since the ASS format doesn't have any support for
+ * allowing end-users to customize subtitle styling, this feature can
+ * only be implemented on "best effort" basis, and has to rely on
+ * heuristics that can easily break.
+ * \param priv renderer handle
+ * \param enable enable selective styling if the value is not 0
+ */
+void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int enable);
+
+/**
+ * \brief Set style for selective style override.
+ * See ass_set_selective_style_override_enabled().
+ * \param style style settings to use if override is enabled. Applications
+ * should initialize it with {0} before setting fields. Strings will be copied
+ * by the function.
+ */
+void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style);
+
+/**
* \brief Update/build font cache. This needs to be called if it was
* disabled when ass_set_fonts was set.
*
diff --git a/libass/ass_parse.c b/libass/ass_parse.c
index d6b2627..d0d1972 100644
--- a/libass/ass_parse.c
+++ b/libass/ass_parse.c
@@ -1025,3 +1025,29 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str)
*str = p;
return chr;
}
+
+// Return 1 if the event contains tags that will put the renderer into the
+// EVENT_POSITIONED state. Return 0 otherwise.
+int event_is_positioned(char *str)
+{
+ // look for \pos and \move tags inside {...}
+ // mirrors get_next_char, but is faster and doesn't change any global state
+ while (*str) {
+ if (str[0] == '\\' && str[1] != '\0') {
+ str += 2;
+ } else if (str[0] == '{') {
+ str++;
+ while (*str && *str != '}') {
+ if (*str == '\\') {
+ char *p = str + 1;
+ if (mystrcmp(&p, "pos") || mystrcmp(&p, "move"))
+ return 1;
+ }
+ str++;
+ }
+ } else {
+ str++;
+ }
+ }
+ return 0;
+}
diff --git a/libass/ass_parse.h b/libass/ass_parse.h
index 88fcda8..85f3d53 100644
--- a/libass/ass_parse.h
+++ b/libass/ass_parse.h
@@ -35,6 +35,7 @@ void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
void process_karaoke_effects(ASS_Renderer *render_priv);
unsigned get_next_char(ASS_Renderer *render_priv, char **str);
char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr);
+int event_is_positioned(char *str);
extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
extern uint32_t mult_alpha(uint32_t a, uint32_t b);
diff --git a/libass/ass_render.c b/libass/ass_render.c
index 0cc1848..625a77d 100644
--- a/libass/ass_render.c
+++ b/libass/ass_render.c
@@ -208,6 +208,8 @@ void ass_renderer_done(ASS_Renderer *render_priv)
free(render_priv->settings.default_font);
free(render_priv->settings.default_family);
+ free(render_priv->user_override_style.FontName);
+
free_list_clear(render_priv);
free(render_priv);
}
@@ -763,14 +765,89 @@ static void compute_string_bbox(TextInfo *text, DBBox *bbox)
bbox->xMin = bbox->xMax = bbox->yMin = bbox->yMax = 0.;
}
+static ASS_Style *handle_selective_style_overrides(ASS_Renderer *render_priv,
+ ASS_Style *rstyle)
+{
+ // The script style is the one the event was declared with.
+ // The rstyle is either NULL, or the style used with a \r tag.
+ ASS_Style *script = render_priv->track->styles +
+ render_priv->state.event->Style;
+ ASS_Style *new = &render_priv->state.override_style_temp_storage;
+ int override = !event_is_positioned(render_priv->state.event->Text);
+ double scale;
+
+ if (!rstyle)
+ rstyle = script;
+
+ render_priv->state.style = script;
+
+ if (!override || !render_priv->settings.selective_style_overrides)
+ return rstyle;
+
+ // Create a new style that contains a mix of the original style and
+ // user_style (the user's override style). Copy only fields from the
+ // script's style that are deemed necessary.
+ *new = render_priv->user_override_style;
+
+ new->StrikeOut = rstyle->StrikeOut;
+ new->Underline = rstyle->Underline;
+ new->Angle = rstyle->Angle;
+
+ new->MarginL = script->MarginL;
+ new->MarginR = script->MarginR;
+ new->MarginV = script->MarginV;
+ new->Alignment = script->Alignment;
+ new->Encoding = script->Encoding;
+ new->treat_fontname_as_pattern = script->treat_fontname_as_pattern;
+
+ // The user style is supposed to be independent of the script resolution.
+ // Treat the user style's values as if they were specified for a script with
+ // PlayResY=288, and rescale the values to the current script.
+ scale = render_priv->track->PlayResY / 288.0;
+ new->FontSize *= scale;
+ new->Spacing *= scale;
+ new->Outline *= scale;
+ new->Shadow *= scale;
+
+ render_priv->state.style = new;
+
+ return new;
+}
+
+static void init_font_scale(ASS_Renderer *render_priv)
+{
+ ASS_Settings *settings_priv = &render_priv->settings;
+
+ render_priv->font_scale = ((double) render_priv->orig_height) /
+ render_priv->track->PlayResY;
+ if (settings_priv->storage_height)
+ render_priv->blur_scale = ((double) render_priv->orig_height) /
+ settings_priv->storage_height;
+ else
+ render_priv->blur_scale = 1.;
+ if (render_priv->track->ScaledBorderAndShadow)
+ render_priv->border_scale =
+ ((double) render_priv->orig_height) /
+ render_priv->track->PlayResY;
+ else
+ render_priv->border_scale = render_priv->blur_scale;
+ if (!settings_priv->storage_height)
+ render_priv->blur_scale = render_priv->border_scale;
+
+ render_priv->font_scale *= settings_priv->font_size_coeff;
+ render_priv->border_scale *= settings_priv->font_size_coeff;
+ render_priv->blur_scale *= settings_priv->font_size_coeff;
+}
+
/**
* \brief partially reset render_context to style values
* Works like {\r}: resets some style overrides
*/
void reset_render_context(ASS_Renderer *render_priv, ASS_Style *style)
{
- if (!style)
- style = render_priv->state.style;
+ style = handle_selective_style_overrides(render_priv, style);
+
+ init_font_scale(render_priv);
render_priv->state.c[0] = style->PrimaryColour;
render_priv->state.c[1] = style->SecondaryColour;
@@ -814,11 +891,10 @@ static void
init_render_context(ASS_Renderer *render_priv, ASS_Event *event)
{
render_priv->state.event = event;
- render_priv->state.style = render_priv->track->styles + event->Style;
render_priv->state.parsed_tags = 0;
render_priv->state.has_clips = 0;
- reset_render_context(render_priv, render_priv->state.style);
+ reset_render_context(render_priv, NULL);
render_priv->state.wrap_style = render_priv->track->WrapStyle;
render_priv->state.evt_type = EVENT_NORMAL;
@@ -2636,23 +2712,6 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track,
ass_lazy_track_init(render_priv->library, render_priv->track);
- render_priv->font_scale = settings_priv->font_size_coeff *
- render_priv->orig_height / render_priv->track->PlayResY;
- if (settings_priv->storage_height)
- render_priv->blur_scale = ((double) render_priv->orig_height) /
- settings_priv->storage_height;
- else
- render_priv->blur_scale = 1.;
- if (render_priv->track->ScaledBorderAndShadow)
- render_priv->border_scale =
- ((double) render_priv->orig_height) /
- render_priv->track->PlayResY;
- else
- render_priv->border_scale = render_priv->blur_scale;
- if (!settings_priv->storage_height)
- render_priv->blur_scale = render_priv->border_scale;
- render_priv->border_scale *= settings_priv->font_size_coeff;
-
ass_shaper_set_kerning(render_priv->shaper, track->Kerning);
ass_shaper_set_language(render_priv->shaper, track->Language);
ass_shaper_set_level(render_priv->shaper, render_priv->settings.shaper);
diff --git a/libass/ass_render.h b/libass/ass_render.h
index 8e15ad5..e1b42b2 100644
--- a/libass/ass_render.h
+++ b/libass/ass_render.h
@@ -85,6 +85,7 @@ typedef struct {
double par; // user defined pixel aspect ratio (0 = unset)
ASS_Hinting hinting;
ASS_ShapingLevel shaper;
+ int selective_style_overrides;
char *default_font;
char *default_family;
@@ -294,6 +295,9 @@ typedef struct {
int treat_family_as_pattern;
int wrap_style;
int font_encoding;
+
+ // used to store RenderContext.style when doing selective style overrides
+ ASS_Style override_style_temp_storage;
} RenderContext;
typedef struct {
@@ -360,6 +364,8 @@ struct ass_renderer {
FreeList *free_head;
FreeList *free_tail;
+
+ ASS_Style user_override_style;
};
typedef struct render_priv {
diff --git a/libass/ass_render_api.c b/libass/ass_render_api.c
index b06fc80..072b693 100644
--- a/libass/ass_render_api.c
+++ b/libass/ass_render_api.c
@@ -151,6 +151,24 @@ void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
default_font, fc, config, update);
}
+void ass_set_selective_style_override_enabled(ASS_Renderer *priv, int enable)
+{
+ enable = !!enable;
+ if (priv->settings.selective_style_overrides != enable) {
+ priv->settings.selective_style_overrides = enable;
+ ass_reconfigure(priv);
+ }
+}
+
+void ass_set_selective_style_override(ASS_Renderer *priv, ASS_Style *style)
+{
+ ASS_Style *user_style = &priv->user_override_style;
+ free(user_style->FontName);
+ *user_style = *style;
+ user_style->FontName = strdup(user_style->FontName);
+ user_style->Name = "OverrideStyle"; // name insignificant
+}
+
int ass_fonts_update(ASS_Renderer *render_priv)
{
return fontconfig_update(render_priv->fontconfig_priv);
diff --git a/libass/libass.sym b/libass/libass.sym
index d0cc155..89e212c 100644
--- a/libass/libass.sym
+++ b/libass/libass.sym
@@ -39,3 +39,5 @@ ass_flush_events
ass_set_shaper
ass_set_line_position
ass_set_pixel_aspect
+ass_set_selective_style_override_enabled
+ass_set_selective_style_override