aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2009-07-25 07:24:39 +0300
committerGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2009-07-26 20:22:43 +0300
commit546c3fb53ce64fde5cba3e06012d244e73ae497a (patch)
tree8708989ac0b06edc091a71d73508ffc465fd669e
parent6fbcf16cfb0c6482bef87a0e8ac2162bca4cdbfd (diff)
Remove internal libass tree
Remove the libass/ directory and use the newest standalone version of the library instead.
-rw-r--r--Makefile10
-rw-r--r--ass_mp.c307
-rw-r--r--ass_mp.h82
-rw-r--r--command.c5
-rwxr-xr-xconfigure33
-rw-r--r--libass/ass.c1134
-rw-r--r--libass/ass.h229
-rw-r--r--libass/ass_bitmap.c336
-rw-r--r--libass/ass_bitmap.h53
-rw-r--r--libass/ass_cache.c385
-rw-r--r--libass/ass_cache.h98
-rw-r--r--libass/ass_cache_template.c88
-rw-r--r--libass/ass_font.c371
-rw-r--r--libass/ass_font.h60
-rw-r--r--libass/ass_fontconfig.c516
-rw-r--r--libass/ass_fontconfig.h41
-rw-r--r--libass/ass_library.c115
-rw-r--r--libass/ass_library.h41
-rw-r--r--libass/ass_mp.c279
-rw-r--r--libass/ass_mp.h60
-rw-r--r--libass/ass_render.c2616
-rw-r--r--libass/ass_types.h119
-rw-r--r--libass/ass_utils.c135
-rw-r--r--libass/ass_utils.h66
-rw-r--r--libass/mputils.h31
-rw-r--r--libmpcodecs/vf_ass.c5
-rw-r--r--libmpcodecs/vf_vo.c8
-rw-r--r--libmpdemux/demux_mkv.c3
-rw-r--r--libmpdemux/demuxer.c5
-rw-r--r--libvo/vo_gl.c3
-rw-r--r--libvo/vo_vdpau.c3
-rw-r--r--mencoder.c5
-rw-r--r--mp_msg.c15
-rw-r--r--mp_msg.h4
-rw-r--r--mpcommon.c3
-rw-r--r--mplayer.c5
36 files changed, 430 insertions, 6839 deletions
diff --git a/Makefile b/Makefile
index d750e96fd6..7bcf7481ec 100644
--- a/Makefile
+++ b/Makefile
@@ -125,15 +125,7 @@ SRCS_COMMON-$(LIBA52_INTERNAL) += liba52/crc.c \
liba52/imdct.c \
liba52/parse.c \
-SRCS_COMMON-$(LIBASS) += libass/ass.c \
- libass/ass_bitmap.c \
- libass/ass_cache.c \
- libass/ass_font.c \
- libass/ass_fontconfig.c \
- libass/ass_library.c \
- libass/ass_mp.c \
- libass/ass_render.c \
- libass/ass_utils.c \
+SRCS_COMMON-$(LIBASS) += ass_mp.c \
libmpcodecs/vf_ass.c \
SRCS_COMMON-$(LIBAVCODEC) += av_opts.c \
diff --git a/ass_mp.c b/ass_mp.c
new file mode 100644
index 0000000000..207b0454d1
--- /dev/null
+++ b/ass_mp.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with libass; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <ass/ass.h>
+#include <ass/ass_types.h>
+
+#include "mp_msg.h"
+#include "get_path.h"
+#include "ass_mp.h"
+#include "subreader.h"
+
+#ifdef CONFIG_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#endif
+
+// libass-related command line options
+ass_library_t *ass_library;
+int ass_enabled = 0;
+float ass_font_scale = 1.;
+float ass_line_spacing = 0.;
+int ass_top_margin = 0;
+int ass_bottom_margin = 0;
+#if defined(FC_VERSION) && (FC_VERSION >= 20402)
+int extract_embedded_fonts = 1;
+#else
+int extract_embedded_fonts = 0;
+#endif
+char **ass_force_style_list = NULL;
+int ass_use_margins = 0;
+char *ass_color = NULL;
+char *ass_border_color = NULL;
+char *ass_styles_file = NULL;
+int ass_hinting = ASS_HINTING_NATIVE + 4; // native hinting for unscaled osd
+
+#ifdef CONFIG_FONTCONFIG
+extern int font_fontconfig;
+#else
+static int font_fontconfig = -1;
+#endif
+extern char *font_name;
+extern char *sub_font_name;
+extern float text_font_scale_factor;
+extern int subtitle_autoscale;
+
+#ifdef CONFIG_ICONV
+extern char *sub_cp;
+#else
+static char *sub_cp = 0;
+#endif
+
+void process_force_style(ass_track_t *track);
+
+ass_track_t *ass_default_track(ass_library_t *library)
+{
+ ass_track_t *track = ass_new_track(library);
+
+ track->track_type = TRACK_TYPE_ASS;
+ track->Timer = 100.;
+ track->PlayResY = 288;
+ track->WrapStyle = 0;
+
+ if (ass_styles_file)
+ ass_read_styles(track, ass_styles_file, sub_cp);
+
+ if (track->n_styles == 0) {
+ ass_style_t *style;
+ int sid;
+ double fs;
+ uint32_t c1, c2;
+
+ sid = ass_alloc_style(track);
+ style = track->styles + sid;
+ style->Name = strdup("Default");
+ style->FontName = (font_fontconfig >= 0
+ && sub_font_name) ? strdup(sub_font_name)
+ : (font_fontconfig >= 0
+ && font_name) ? strdup(font_name) : strdup("Sans");
+ style->treat_fontname_as_pattern = 1;
+
+ fs = track->PlayResY * text_font_scale_factor / 100.;
+ // approximate autoscale coefficients
+ if (subtitle_autoscale == 2)
+ fs *= 1.3;
+ else if (subtitle_autoscale == 3)
+ fs *= 1.4;
+ style->FontSize = fs;
+
+ if (ass_color)
+ c1 = strtoll(ass_color, NULL, 16);
+ else
+ c1 = 0xFFFF0000;
+ if (ass_border_color)
+ c2 = strtoll(ass_border_color, NULL, 16);
+ else
+ c2 = 0x00000000;
+
+ style->PrimaryColour = c1;
+ style->SecondaryColour = c1;
+ style->OutlineColour = c2;
+ style->BackColour = 0x00000000;
+ style->BorderStyle = 1;
+ style->Alignment = 2;
+ style->Outline = 2;
+ style->MarginL = 10;
+ style->MarginR = 10;
+ style->MarginV = 5;
+ style->ScaleX = 1.;
+ style->ScaleY = 1.;
+ }
+
+ ass_process_force_style(track);
+ return track;
+}
+
+static int check_duplicate_plaintext_event(ass_track_t *track)
+{
+ int i;
+ ass_event_t *evt = track->events + track->n_events - 1;
+
+ for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
+ if (track->events[i].Start == evt->Start &&
+ track->events[i].Duration == evt->Duration &&
+ strcmp(track->events[i].Text, evt->Text) == 0)
+ return 1;
+ return 0;
+}
+
+/**
+ * \brief Convert subtitle to ass_event_t for the given track
+ * \param ass_track_t track
+ * \param sub subtitle to convert
+ * \return event id
+ * note: assumes that subtitle is _not_ fps-based; caller must manually correct
+ * Start and Duration in other case.
+ **/
+int ass_process_subtitle(ass_track_t *track, subtitle *sub)
+{
+ int eid;
+ ass_event_t *event;
+ int len = 0, j;
+ char *p;
+ char *end;
+
+ eid = ass_alloc_event(track);
+ event = track->events + eid;
+
+ event->Start = sub->start * 10;
+ event->Duration = (sub->end - sub->start) * 10;
+ event->Style = 0;
+
+ for (j = 0; j < sub->lines; ++j)
+ len += sub->text[j] ? strlen(sub->text[j]) : 0;
+
+ len += 2 * sub->lines; // '\N', including the one after the last line
+ len += 6; // {\anX}
+ len += 1; // '\0'
+
+ event->Text = malloc(len);
+ end = event->Text + len;
+ p = event->Text;
+
+ if (sub->alignment)
+ p += snprintf(p, end - p, "{\\an%d}", sub->alignment);
+
+ for (j = 0; j < sub->lines; ++j)
+ p += snprintf(p, end - p, "%s\\N", sub->text[j]);
+
+ if (sub->lines > 0)
+ p -= 2; // remove last "\N"
+ *p = 0;
+
+ if (check_duplicate_plaintext_event(track)) {
+ ass_free_event(track, eid);
+ track->n_events--;
+ return -1;
+ }
+
+ mp_msg(MSGT_ASS, MSGL_V,
+ "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n",
+ (int64_t) event->Start, (int64_t) event->Duration, event->Text);
+
+ return eid;
+}
+
+
+/**
+ * \brief Convert subdata to ass_track
+ * \param subdata subtitles struct from subreader
+ * \param fps video framerate
+ * \return newly allocated ass_track, filled with subtitles from subdata
+ */
+ass_track_t *ass_read_subdata(ass_library_t *library, sub_data *subdata,
+ double fps)
+{
+ ass_track_t *track;
+ int i;
+
+ track = ass_default_track(library);
+ track->name = subdata->filename ? strdup(subdata->filename) : 0;
+
+ for (i = 0; i < subdata->sub_num; ++i) {
+ int eid = ass_process_subtitle(track, subdata->subtitles + i);
+ if (eid < 0)
+ continue;
+ if (!subdata->sub_uses_time) {
+ track->events[eid].Start *= 100. / fps;
+ track->events[eid].Duration *= 100. / fps;
+ }
+ }
+ return track;
+}
+
+void ass_configure(ass_renderer_t *priv, int w, int h, int unscaled)
+{
+ int hinting;
+ ass_set_frame_size(priv, w, h);
+ ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0);
+ ass_set_use_margins(priv, ass_use_margins);
+ ass_set_font_scale(priv, ass_font_scale);
+ if (!unscaled && (ass_hinting & 4))
+ hinting = 0;
+ else
+ hinting = ass_hinting & 3;
+ ass_set_hinting(priv, hinting);
+ ass_set_line_spacing(priv, ass_line_spacing);
+}
+
+void ass_configure_fonts(ass_renderer_t *priv)
+{
+ char *dir, *path, *family;
+ dir = get_path("fonts");
+ if (font_fontconfig < 0 && sub_font_name)
+ path = strdup(sub_font_name);
+ else if (font_fontconfig < 0 && font_name)
+ path = strdup(font_name);
+ else
+ path = get_path("subfont.ttf");
+ if (font_fontconfig >= 0 && sub_font_name)
+ family = strdup(sub_font_name);
+ else if (font_fontconfig >= 0 && font_name)
+ family = strdup(font_name);
+ else
+ family = 0;
+
+ ass_set_fonts(priv, path, family, font_fontconfig + 1, NULL, 1);
+
+ free(dir);
+ free(path);
+ free(family);
+}
+
+static void message_callback(int level, const char *format, va_list va, void *ctx)
+{
+ mp_msg(MSGT_ASS, level, "[ass] ");
+ mp_msg_va(MSGT_ASS, level, format, va);
+ // libass messages lack trailing \n
+ mp_msg(MSGT_ASS, level, "\n");
+}
+
+ass_library_t *ass_init(void)
+{
+ ass_library_t *priv;
+ char *path = get_path("fonts");
+ priv = ass_library_init();
+ ass_set_message_cb(priv, message_callback, NULL);
+ ass_set_fonts_dir(priv, path);
+ ass_set_extract_fonts(priv, extract_embedded_fonts);
+ ass_set_style_overrides(priv, ass_force_style_list);
+ free(path);
+ return priv;
+}
+
+int ass_force_reload = 0; // flag set if global ass-related settings were changed
+
+ass_image_t *ass_mp_render_frame(ass_renderer_t *priv, ass_track_t *track,
+ long long now, int *detect_change)
+{
+ if (ass_force_reload) {
+ ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0);
+ ass_set_use_margins(priv, ass_use_margins);
+ ass_set_font_scale(priv, ass_font_scale);
+ ass_force_reload = 0;
+ }
+ return ass_render_frame(priv, track, now, detect_change);
+}
diff --git a/ass_mp.h b/ass_mp.h
new file mode 100644
index 0000000000..0b335b9921
--- /dev/null
+++ b/ass_mp.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with libass; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_ASS_MP_H
+#define MPLAYER_ASS_MP_H
+
+#include <stdint.h>
+
+#include "ass_mp.h"
+
+#include "subreader.h"
+
+#ifdef CONFIG_ASS
+#include <ass/ass.h>
+#include <ass/ass_types.h>
+
+extern ass_library_t *ass_library;
+extern int ass_enabled;
+extern float ass_font_scale;
+extern float ass_line_spacing;
+extern int ass_top_margin;
+extern int ass_bottom_margin;
+extern int extract_embedded_fonts;
+extern char **ass_force_style_list;
+extern int ass_use_margins;
+extern char *ass_color;
+extern char *ass_border_color;
+extern char *ass_styles_file;
+extern int ass_hinting;
+
+ass_track_t *ass_default_track(ass_library_t *library);
+int ass_process_subtitle(ass_track_t *track, subtitle *sub);
+ass_track_t *ass_read_subdata(ass_library_t *library, sub_data *subdata,
+ double fps);
+
+void ass_configure(ass_renderer_t *priv, int w, int h, int hinting);
+void ass_configure_fonts(ass_renderer_t *priv);
+ass_library_t *ass_init(void);
+
+extern int ass_force_reload;
+ass_image_t *ass_mp_render_frame(ass_renderer_t *priv, ass_track_t *track,
+ long long now, int *detect_change);
+
+#else /* CONFIG_ASS */
+
+/* Needed for EOSD code using this type to compile */
+
+typedef struct ass_image {
+ int w, h;
+ int stride;
+ unsigned char *bitmap;
+ uint32_t color;
+ int dst_x, dst_y;
+ struct ass_image *next;
+} ass_image_t;
+
+#endif
+
+typedef struct {
+ ass_image_t *imgs;
+ int changed;
+} mp_eosd_images_t;
+
+
+#endif /* MPLAYER_ASS_MP_H */
diff --git a/command.c b/command.c
index 721b145b83..bbe9300e5e 100644
--- a/command.c
+++ b/command.c
@@ -31,6 +31,7 @@
#include "vobsub.h"
#include "spudec.h"
#include "get_path.h"
+#include "ass_mp.h"
#ifdef CONFIG_TV
#include "stream/tv.h"
#endif
@@ -49,10 +50,6 @@
#ifdef CONFIG_DVDNAV
#include "stream/stream_dvdnav.h"
#endif
-#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
-#endif
#ifdef CONFIG_MENU
#include "m_struct.h"
#include "libmenu/menu.h"
diff --git a/configure b/configure
index 8027630a86..e567a8a22a 100755
--- a/configure
+++ b/configure
@@ -6092,29 +6092,16 @@ echores "$_fontconfig"
echocheck "SSA/ASS support"
-# libass depends on FreeType
-if test "$_freetype" = no ; then
- _ass=no
- _res_comment="FreeType support needed"
-fi
-
-if test "$_ass" = auto ; then
- cat > $TMPC << EOF
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#if ((FREETYPE_MAJOR < 2) || (FREETYPE_MINOR < 1) || ((FREETYPE_MINOR == 1) && (FREETYPE_PATCH < 8)))
-#error "Need FreeType 2.1.8 or newer"
-#endif
-int main(void) { return 0; }
-EOF
- _ass=no
- cc_check $($_freetypeconfig --cflags) $($_freetypeconfig --libs) && tmp_run && _ass=yes
- if test "$_ass" = no ; then
- _res_comment="FreeType >= 2.1.8 needed"
- fi
-fi
-if test "$_ass" = yes ; then
- def_ass='#define CONFIG_ASS'
+if test "$_ass" = auto -o "$_ass" = yes ; then
+ if $_pkg_config libass; then
+ _ass=yes
+ def_ass='#define CONFIG_ASS'
+ extra_ldflags="$extra_ldflags $($_pkg_config --libs libass)"
+ extra_cflags="$extra_cflags $($_pkg_config --cflags libass)"
+ else
+ _ass=no
+ def_ass='#undef CONFIG_ASS'
+ fi
else
def_ass='#undef CONFIG_ASS'
fi
diff --git a/libass/ass.c b/libass/ass.c
deleted file mode 100644
index 5e9e82c2c4..0000000000
--- a/libass/ass.c
+++ /dev/null
@@ -1,1134 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#ifdef CONFIG_ICONV
-#include <iconv.h>
-#endif
-
-#include "ass.h"
-#include "ass_utils.h"
-#include "ass_library.h"
-#include "mputils.h"
-
-typedef enum {PST_UNKNOWN = 0, PST_INFO, PST_STYLES, PST_EVENTS, PST_FONTS} parser_state_t;
-
-struct parser_priv_s {
- parser_state_t state;
- char* fontname;
- char* fontdata;
- int fontdata_size;
- int fontdata_used;
-};
-
-#define ASS_STYLES_ALLOC 20
-#define ASS_EVENTS_ALLOC 200
-
-void ass_free_track(ass_track_t* track) {
- int i;
-
- if (track->parser_priv) {
- if (track->parser_priv->fontname)
- free(track->parser_priv->fontname);
- if (track->parser_priv->fontdata)
- free(track->parser_priv->fontdata);
- free(track->parser_priv);
- }
- if (track->style_format)
- free(track->style_format);
- if (track->event_format)
- free(track->event_format);
- if (track->styles) {
- for (i = 0; i < track->n_styles; ++i)
- ass_free_style(track, i);
- free(track->styles);
- }
- if (track->events) {
- for (i = 0; i < track->n_events; ++i)
- ass_free_event(track, i);
- free(track->events);
- }
-}
-
-/// \brief Allocate a new style struct
-/// \param track track
-/// \return style id
-int ass_alloc_style(ass_track_t* track) {
- int sid;
-
- assert(track->n_styles <= track->max_styles);
-
- if (track->n_styles == track->max_styles) {
- track->max_styles += ASS_STYLES_ALLOC;
- track->styles = (ass_style_t*)realloc(track->styles, sizeof(ass_style_t)*track->max_styles);
- }
-
- sid = track->n_styles++;
- memset(track->styles + sid, 0, sizeof(ass_style_t));
- return sid;
-}
-
-/// \brief Allocate a new event struct
-/// \param track track
-/// \return event id
-int ass_alloc_event(ass_track_t* track) {
- int eid;
-
- assert(track->n_events <= track->max_events);
-
- if (track->n_events == track->max_events) {
- track->max_events += ASS_EVENTS_ALLOC;
- track->events = (ass_event_t*)realloc(track->events, sizeof(ass_event_t)*track->max_events);
- }
-
- eid = track->n_events++;
- memset(track->events + eid, 0, sizeof(ass_event_t));
- return eid;
-}
-
-void ass_free_event(ass_track_t* track, int eid) {
- ass_event_t* event = track->events + eid;
- if (event->Name)
- free(event->Name);
- if (event->Effect)
- free(event->Effect);
- if (event->Text)
- free(event->Text);
- if (event->render_priv)
- free(event->render_priv);
-}
-
-void ass_free_style(ass_track_t* track, int sid) {
- ass_style_t* style = track->styles + sid;
- if (style->Name)
- free(style->Name);
- if (style->FontName)
- free(style->FontName);
-}
-
-// ==============================================================================================
-
-static void skip_spaces(char** str) {
- char* p = *str;
- while ((*p==' ') || (*p=='\t'))
- ++p;
- *str = p;
-}
-
-static void rskip_spaces(char** str, char* limit) {
- char* p = *str;
- while ((p >= limit) && ((*p==' ') || (*p=='\t')))
- --p;
- *str = p;
-}
-
-/**
- * \brief find style by name
- * \param track track
- * \param name style name
- * \return index in track->styles
- * Returnes 0 if no styles found => expects at least 1 style.
- * Parsing code always adds "Default" style in the end.
- */
-static int lookup_style(ass_track_t* track, char* name) {
- int i;
- if (*name == '*') ++name; // FIXME: what does '*' really mean ?
- for (i = track->n_styles - 1; i >= 0; --i) {
- // FIXME: mb strcasecmp ?
- if (strcmp(track->styles[i].Name, name) == 0)
- return i;
- }
- i = track->default_style;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoStyleNamedXFoundUsingY, track, name, track->styles[i].Name);
- return i; // use the first style
-}
-
-static uint32_t string2color(char* p) {
- uint32_t tmp;
- (void)strtocolor(&p, &tmp);
- return tmp;
-}
-
-static long long string2timecode(char* p) {
- unsigned h, m, s, ms;
- long long tm;
- int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms);
- if (res < 4) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BadTimestamp);
- return 0;
- }
- tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10;
- return tm;
-}
-
-/**
- * \brief converts numpad-style align to align.
- */
-static int numpad2align(int val) {
- int res, v;
- v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment
- if (v != 0) v = 3 - v;
- res = ((val - 1) % 3) + 1; // horizontal alignment
- res += v*4;
- return res;
-}
-
-#define NEXT(str,token) \
- token = next_token(&str); \
- if (!token) break;
-
-#define ANYVAL(name,func) \
- } else if (strcasecmp(tname, #name) == 0) { \
- target->name = func(token); \
- mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
-
-#define STRVAL(name) \
- } else if (strcasecmp(tname, #name) == 0) { \
- if (target->name != NULL) free(target->name); \
- target->name = strdup(token); \
- mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
-
-#define COLORVAL(name) ANYVAL(name,string2color)
-#define INTVAL(name) ANYVAL(name,atoi)
-#define FPVAL(name) ANYVAL(name,atof)
-#define TIMEVAL(name) ANYVAL(name,string2timecode)
-#define STYLEVAL(name) \
- } else if (strcasecmp(tname, #name) == 0) { \
- target->name = lookup_style(track, token); \
- mp_msg(MSGT_ASS, MSGL_DBG2, "%s = %s\n", #name, token);
-
-#define ALIAS(alias,name) \
- if (strcasecmp(tname, #alias) == 0) {tname = #name;}
-
-static char* next_token(char** str) {
- char* p = *str;
- char* start;
- skip_spaces(&p);
- if (*p == '\0') {
- *str = p;
- return 0;
- }
- start = p; // start of the token
- for (; (*p != '\0') && (*p != ','); ++p) {}
- if (*p == '\0') {
- *str = p; // eos found, str will point to '\0' at exit
- } else {
- *p = '\0';
- *str = p + 1; // ',' found, str will point to the next char (beginning of the next token)
- }
- --p; // end of current token
- rskip_spaces(&p, start);
- if (p < start)
- p = start; // empty token
- else
- ++p; // the first space character, or '\0'
- *p = '\0';
- return start;
-}
-/**
- * \brief Parse the tail of Dialogue line
- * \param track track
- * \param event parsed data goes here
- * \param str string to parse, zero-terminated
- * \param n_ignored number of format options to skip at the beginning
-*/
-static int process_event_tail(ass_track_t* track, ass_event_t* event, char* str, int n_ignored)
-{
- char* token;
- char* tname;
- char* p = str;
- int i;
- ass_event_t* target = event;
-
- char* format = strdup(track->event_format);
- char* q = format; // format scanning pointer
-
- if (track->n_styles == 0) {
- // add "Default" style to the end
- // will be used if track does not contain a default style (or even does not contain styles at all)
- int sid = ass_alloc_style(track);
- track->styles[sid].Name = strdup("Default");
- track->styles[sid].FontName = strdup("Arial");
- }
-
- for (i = 0; i < n_ignored; ++i) {
- NEXT(q, tname);
- }
-
- while (1) {
- NEXT(q, tname);
- if (strcasecmp(tname, "Text") == 0) {
- char* last;
- event->Text = strdup(p);
- if (*event->Text != 0) {
- last = event->Text + strlen(event->Text) - 1;
- if (last >= event->Text && *last == '\r')
- *last = 0;
- }
- mp_msg(MSGT_ASS, MSGL_DBG2, "Text = %s\n", event->Text);
- event->Duration -= event->Start;
- free(format);
- return 0; // "Text" is always the last
- }
- NEXT(p, token);
-
- ALIAS(End,Duration) // temporarily store end timecode in event->Duration
- if (0) { // cool ;)
- INTVAL(Layer)
- STYLEVAL(Style)
- STRVAL(Name)
- STRVAL(Effect)
- INTVAL(MarginL)
- INTVAL(MarginR)
- INTVAL(MarginV)
- TIMEVAL(Start)
- TIMEVAL(Duration)
- }
- }
- free(format);
- return 1;
-}
-
-/**
- * \brief Parse command line style overrides (--ass-force-style option)
- * \param track track to apply overrides to
- * The format for overrides is [StyleName.]Field=Value
- */
-void process_force_style(ass_track_t* track) {
- char **fs, *eq, *dt, *style, *tname, *token;
- ass_style_t* target;
- int sid;
- char** list = track->library->style_overrides;
-
- if (!list) return;
-
- for (fs = list; *fs; ++fs) {
- eq = strrchr(*fs, '=');
- if (!eq)
- continue;
- *eq = '\0';
- token = eq + 1;
-
- if(!strcasecmp(*fs, "PlayResX"))
- track->PlayResX = atoi(token);
- else if(!strcasecmp(*fs, "PlayResY"))
- track->PlayResY = atoi(token);
- else if(!strcasecmp(*fs, "Timer"))
- track->Timer = atof(token);
- else if(!strcasecmp(*fs, "WrapStyle"))
- track->WrapStyle = atoi(token);
- else if(!strcasecmp(*fs, "ScaledBorderAndShadow"))
- track->ScaledBorderAndShadow = parse_bool(token);
-
- dt = strrchr(*fs, '.');
- if (dt) {
- *dt = '\0';
- style = *fs;
- tname = dt + 1;
- } else {
- style = NULL;
- tname = *fs;
- }
- for (sid = 0; sid < track->n_styles; ++sid) {
- if (style == NULL || strcasecmp(track->styles[sid].Name, style) == 0) {
- target = track->styles + sid;
- if (0) {
- STRVAL(FontName)
- COLORVAL(PrimaryColour)
- COLORVAL(SecondaryColour)
- COLORVAL(OutlineColour)
- COLORVAL(BackColour)
- FPVAL(FontSize)
- INTVAL(Bold)
- INTVAL(Italic)
- INTVAL(Underline)
- INTVAL(StrikeOut)
- FPVAL(Spacing)
- INTVAL(Angle)
- INTVAL(BorderStyle)
- INTVAL(Alignment)
- INTVAL(MarginL)
- INTVAL(MarginR)
- INTVAL(MarginV)
- INTVAL(Encoding)
- FPVAL(ScaleX)
- FPVAL(ScaleY)
- FPVAL(Outline)
- FPVAL(Shadow)
- }
- }
- }
- *eq = '=';
- if (dt) *dt = '.';
- }
-}
-
-/**
- * \brief Parse the Style line
- * \param track track
- * \param str string to parse, zero-terminated
- * Allocates a new style struct.
-*/
-static int process_style(ass_track_t* track, char *str)
-{
-
- char* token;
- char* tname;
- char* p = str;
- char* format;
- char* q; // format scanning pointer
- int sid;
- ass_style_t* style;
- ass_style_t* target;
-
- if (!track->style_format) {
- // no style format header
- // probably an ancient script version
- if (track->track_type == TRACK_TYPE_SSA)
- track->style_format = strdup("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
- "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline,"
- "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding");
- else
- track->style_format = strdup("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,"
- "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut,"
- "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow,"
- "Alignment, MarginL, MarginR, MarginV, Encoding");
- }
-
- q = format = strdup(track->style_format);
-
- mp_msg(MSGT_ASS, MSGL_V, "[%p] Style: %s\n", track, str);
-
- sid = ass_alloc_style(track);
-
- style = track->styles + sid;
- target = style;
-// fill style with some default values
- style->ScaleX = 100.;
- style->ScaleY = 100.;
-
- while (1) {
- NEXT(q, tname);
- NEXT(p, token);
-
-// ALIAS(TertiaryColour,OutlineColour) // ignore TertiaryColour; it appears only in SSA, and is overridden by BackColour
-
- if (0) { // cool ;)
- STRVAL(Name)
- if ((strcmp(target->Name, "Default")==0) || (strcmp(target->Name, "*Default")==0))
- track->default_style = sid;
- STRVAL(FontName)
- COLORVAL(PrimaryColour)
- COLORVAL(SecondaryColour)
- COLORVAL(OutlineColour) // TertiaryColor
- COLORVAL(BackColour)
- // SSA uses BackColour for both outline and shadow
- // this will destroy SSA's TertiaryColour, but i'm not going to use it anyway
- if (track->track_type == TRACK_TYPE_SSA)
- target->OutlineColour = target->BackColour;
- FPVAL(FontSize)
- INTVAL(Bold)
- INTVAL(Italic)
- INTVAL(Underline)
- INTVAL(StrikeOut)
- FPVAL(Spacing)
- INTVAL(Angle)
- INTVAL(BorderStyle)
- INTVAL(Alignment)
- if (track->track_type == TRACK_TYPE_ASS)
- target->Alignment = numpad2align(target->Alignment);
- INTVAL(MarginL)
- INTVAL(MarginR)
- INTVAL(MarginV)
- INTVAL(Encoding)
- FPVAL(ScaleX)
- FPVAL(ScaleY)
- FPVAL(Outline)
- FPVAL(Shadow)
- }
- }
- style->ScaleX /= 100.;
- style->ScaleY /= 100.;
- style->Bold = !!style->Bold;
- style->Italic = !!style->Italic;
- style->Underline = !!style->Underline;
- if (!style->Name)
- style->Name = strdup("Default");
- if (!style->FontName)
- style->FontName = strdup("Arial");
- // skip '@' at the start of the font name
- if (*style->FontName == '@') {
- p = style->FontName;
- style->FontName = strdup(p + 1);
- free(p);
- }
- free(format);
- return 0;
-
-}
-
-static int process_styles_line(ass_track_t* track, char *str)
-{
- if (!strncmp(str,"Format:", 7)) {
- char* p = str + 7;
- skip_spaces(&p);
- track->style_format = strdup(p);
- mp_msg(MSGT_ASS, MSGL_DBG2, "Style format: %s\n", track->style_format);
- } else if (!strncmp(str,"Style:", 6)) {
- char* p = str + 6;
- skip_spaces(&p);
- process_style(track, p);
- }
- return 0;
-}
-
-static int process_info_line(ass_track_t* track, char *str)
-{
- if (!strncmp(str, "PlayResX:", 9)) {
- track->PlayResX = atoi(str + 9);
- } else if (!strncmp(str,"PlayResY:", 9)) {
- track->PlayResY = atoi(str + 9);
- } else if (!strncmp(str,"Timer:", 6)) {
- track->Timer = atof(str + 6);
- } else if (!strncmp(str,"WrapStyle:", 10)) {
- track->WrapStyle = atoi(str + 10);
- } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
- track->ScaledBorderAndShadow = parse_bool(str + 22);
- }
- return 0;
-}
-
-static int process_events_line(ass_track_t* track, char *str)
-{
- if (!strncmp(str, "Format:", 7)) {
- char* p = str + 7;
- skip_spaces(&p);
- track->event_format = strdup(p);
- mp_msg(MSGT_ASS, MSGL_DBG2, "Event format: %s\n", track->event_format);
- } else if (!strncmp(str, "Dialogue:", 9)) {
- // This should never be reached for embedded subtitles.
- // They have slightly different format and are parsed in ass_process_chunk,
- // called directly from demuxer
- int eid;
- ass_event_t* event;
-
- str += 9;
- skip_spaces(&str);
-
- eid = ass_alloc_event(track);
- event = track->events + eid;
-
- process_event_tail(track, event, str, 0);
- } else {
- mp_msg(MSGT_ASS, MSGL_V, "Not understood: %s \n", str);
- }
- return 0;
-}
-
-// Copied from mkvtoolnix
-static unsigned char* decode_chars(unsigned char c1, unsigned char c2,
- unsigned char c3, unsigned char c4, unsigned char* dst, int cnt)
-{
- uint32_t value;
- unsigned char bytes[3];
- int i;
-
- value = ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 - 33);
- bytes[2] = value & 0xff;
- bytes[1] = (value & 0xff00) >> 8;
- bytes[0] = (value & 0xff0000) >> 16;
-
- for (i = 0; i < cnt; ++i)
- *dst++ = bytes[i];
- return dst;
-}
-
-static int decode_font(ass_track_t* track)
-{
- unsigned char* p;
- unsigned char* q;
- int i;
- int size; // original size
- int dsize; // decoded size
- unsigned char* buf = 0;
-
- mp_msg(MSGT_ASS, MSGL_V, "font: %d bytes encoded data \n", track->parser_priv->fontdata_used);
- size = track->parser_priv->fontdata_used;
- if (size % 4 == 1) {
- mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_BadEncodedDataSize);
- goto error_decode_font;
- }
- buf = malloc(size / 4 * 3 + 2);
- q = buf;
- for (i = 0, p = (unsigned char*)track->parser_priv->fontdata; i < size / 4; i++, p+=4) {
- q = decode_chars(p[0], p[1], p[2], p[3], q, 3);
- }
- if (size % 4 == 2) {
- q = decode_chars(p[0], p[1], 0, 0, q, 1);
- } else if (size % 4 == 3) {
- q = decode_chars(p[0], p[1], p[2], 0, q, 2);
- }
- dsize = q - buf;
- assert(dsize <= size / 4 * 3 + 2);
-
- if (track->library->extract_fonts) {
- ass_add_font(track->library, track->parser_priv->fontname, (char*)buf, dsize);
- buf = 0;
- }
-
-error_decode_font:
- if (buf) free(buf);
- free(track->parser_priv->fontname);
- free(track->parser_priv->fontdata);
- track->parser_priv->fontname = 0;
- track->parser_priv->fontdata = 0;
- track->parser_priv->fontdata_size = 0;
- track->parser_priv->fontdata_used = 0;
- return 0;
-}
-
-static int process_fonts_line(ass_track_t* track, char *str)
-{
- int len;
-
- if (!strncmp(str, "fontname:", 9)) {
- char* p = str + 9;
- skip_spaces(&p);
- if (track->parser_priv->fontname) {
- decode_font(track);
- }
- track->parser_priv->fontname = strdup(p);
- mp_msg(MSGT_ASS, MSGL_V, "fontname: %s\n", track->parser_priv->fontname);
- return 0;
- }
-
- if (!track->parser_priv->fontname) {
- mp_msg(MSGT_ASS, MSGL_V, "Not understood: %s \n", str);
- return 0;
- }
-
- len = strlen(str);
- if (len > 80) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FontLineTooLong, len, str);
- return 0;
- }
- if (track->parser_priv->fontdata_used + len > track->parser_priv->fontdata_size) {
- track->parser_priv->fontdata_size += 100 * 1024;
- track->parser_priv->fontdata = realloc(track->parser_priv->fontdata, track->parser_priv->fontdata_size);
- }
- memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, str, len);
- track->parser_priv->fontdata_used += len;
-
- return 0;
-}
-
-/**
- * \brief Parse a header line
- * \param track track
- * \param str string to parse, zero-terminated
-*/
-static int process_line(ass_track_t* track, char *str)
-{
- if (!strncasecmp(str, "[Script Info]", 13)) {
- track->parser_priv->state = PST_INFO;
- } else if (!strncasecmp(str, "[V4 Styles]", 11)) {
- track->parser_priv->state = PST_STYLES;
- track->track_type = TRACK_TYPE_SSA;
- } else if (!strncasecmp(str, "[V4+ Styles]", 12)) {
- track->parser_priv->state = PST_STYLES;
- track->track_type = TRACK_TYPE_ASS;
- } else if (!strncasecmp(str, "[Events]", 8)) {
- track->parser_priv->state = PST_EVENTS;
- } else if (!strncasecmp(str, "[Fonts]", 7)) {
- track->parser_priv->state = PST_FONTS;
- } else {
- switch (track->parser_priv->state) {
- case PST_INFO:
- process_info_line(track, str);
- break;
- case PST_STYLES:
- process_styles_line(track, str);
- break;
- case PST_EVENTS:
- process_events_line(track, str);
- break;
- case PST_FONTS:
- process_fonts_line(track, str);
- break;
- default:
- break;
- }
- }
-
- // there is no explicit end-of-font marker in ssa/ass
- if ((track->parser_priv->state != PST_FONTS) && (track->parser_priv->fontname))
- decode_font(track);
-
- return 0;
-}
-
-static int process_text(ass_track_t* track, char* str)
-{
- char* p = str;
- while(1) {
- char* q;
- while (1) {
- if ((*p=='\r')||(*p=='\n')) ++p;
- else if (p[0]=='\xef' && p[1]=='\xbb' && p[2]=='\xbf') p+=3; // U+FFFE (BOM)
- else break;
- }
- for (q=p; ((*q!='\0')&&(*q!='\r')&&(*q!='\n')); ++q) {};
- if (q==p)
- break;
- if (*q != '\0')
- *(q++) = '\0';
- process_line(track, p);
- if (*q == '\0')
- break;
- p = q;
- }
- return 0;
-}
-
-/**
- * \brief Process a chunk of subtitle stream data.
- * \param track track
- * \param data string to parse
- * \param size length of data
-*/
-void ass_process_data(ass_track_t* track, char* data, int size)
-{
- char* str = malloc(size + 1);
-
- memcpy(str, data, size);
- str[size] = '\0';
-
- mp_msg(MSGT_ASS, MSGL_V, "event: %s\n", str);
- process_text(track, str);
- free(str);
-}
-
-/**
- * \brief Process CodecPrivate section of subtitle stream
- * \param track track
- * \param data string to parse
- * \param size length of data
- CodecPrivate section contains [Stream Info] and [V4+ Styles] ([V4 Styles] for SSA) sections
-*/
-void ass_process_codec_private(ass_track_t* track, char *data, int size)
-{
- ass_process_data(track, data, size);
-
- if (!track->event_format) {
- // probably an mkv produced by ancient mkvtoolnix
- // such files don't have [Events] and Format: headers
- track->parser_priv->state = PST_EVENTS;
- if (track->track_type == TRACK_TYPE_SSA)
- track->event_format = strdup("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text");
- else
- track->event_format = strdup("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text");
- }
-
- process_force_style(track);
-}
-
-static int check_duplicate_event(ass_track_t* track, int ReadOrder)
-{
- int i;
- for (i = 0; i<track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
- if (track->events[i].ReadOrder == ReadOrder)
- return 1;
- return 0;
-}
-
-/**
- * \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary).
- * \param track track
- * \param data string to parse
- * \param size length of data
- * \param timecode starting time of the event (milliseconds)
- * \param duration duration of the event (milliseconds)
-*/
-void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration)
-{
- char* str;
- int eid;
- char* p;
- char* token;
- ass_event_t* event;
-
- if (!track->event_format) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing);
- return;
- }
-
- str = malloc(size + 1);
- memcpy(str, data, size);
- str[size] = '\0';
- mp_msg(MSGT_ASS, MSGL_V, "event at %" PRId64 ", +%" PRId64 ": %s \n", (int64_t)timecode, (int64_t)duration, str);
-
- eid = ass_alloc_event(track);
- event = track->events + eid;
-
- p = str;
-
- do {
- NEXT(p, token);
- event->ReadOrder = atoi(token);
- if (check_duplicate_event(track, event->ReadOrder))
- break;
-
- NEXT(p, token);
- event->Layer = atoi(token);
-
- process_event_tail(track, event, p, 3);
-
- event->Start = timecode;
- event->Duration = duration;
-
- free(str);
- return;
-// dump_events(tid);
- } while (0);
- // some error
- ass_free_event(track, eid);
- track->n_events--;
- free(str);
-}
-
-#ifdef CONFIG_ICONV
-/** \brief recode buffer to utf-8
- * constraint: codepage != 0
- * \param data pointer to text buffer
- * \param size buffer size
- * \return a pointer to recoded buffer, caller is responsible for freeing it
-**/
-static char* sub_recode(char* data, size_t size, char* codepage)
-{
- static iconv_t icdsc = (iconv_t)(-1);
- char* tocp = "UTF-8";
- char* outbuf;
- assert(codepage);
-
- {
- const char* cp_tmp = codepage;
-#ifdef CONFIG_ENCA
- char enca_lang[3], enca_fallback[100];
- if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2
- || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) {
- cp_tmp = guess_buffer_cp((unsigned char*)data, size, enca_lang, enca_fallback);
- }
-#endif
- if ((icdsc = iconv_open (tocp, cp_tmp)) != (iconv_t)(-1)){
- mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: opened iconv descriptor.\n");
- } else
- mp_msg(MSGT_ASS,MSGL_ERR,MSGTR_LIBASS_ErrorOpeningIconvDescriptor);
- }
-
- {
- size_t osize = size;
- size_t ileft = size;
- size_t oleft = size - 1;
- char* ip;
- char* op;
- size_t rc;
- int clear = 0;
-
- outbuf = malloc(osize);
- ip = data;
- op = outbuf;
-
- while (1) {
- if (ileft)
- rc = iconv(icdsc, &ip, &ileft, &op, &oleft);
- else {// clear the conversion state and leave
- clear = 1;
- rc = iconv(icdsc, NULL, NULL, &op, &oleft);
- }
- if (rc == (size_t)(-1)) {
- if (errno == E2BIG) {
- size_t offset = op - outbuf;
- outbuf = (char*)realloc(outbuf, osize + size);
- op = outbuf + offset;
- osize += size;
- oleft += size;
- } else {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorRecodingFile);
- return NULL;
- }
- } else
- if (clear)
- break;
- }
- outbuf[osize - oleft - 1] = 0;
- }
-
- if (icdsc != (iconv_t)(-1)) {
- (void)iconv_close(icdsc);
- icdsc = (iconv_t)(-1);
- mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: closed iconv descriptor.\n");
- }
-
- return outbuf;
-}
-#endif // ICONV
-
-/**
- * \brief read file contents into newly allocated buffer
- * \param fname file name
- * \param bufsize out: file size
- * \return pointer to file contents. Caller is responsible for its deallocation.
- */
-static char* read_file(char* fname, size_t *bufsize)
-{
- int res;
- long sz;
- long bytes_read;
- char* buf;
-
- FILE* fp = fopen(fname, "rb");
- if (!fp) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname);
- return 0;
- }
- res = fseek(fp, 0, SEEK_END);
- if (res == -1) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FseekFailed, fname);
- fclose(fp);
- return 0;
- }
-
- sz = ftell(fp);
- rewind(fp);
-
- if (sz > 10*1024*1024) {
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname);
- fclose(fp);
- return 0;
- }
-
- mp_msg(MSGT_ASS, MSGL_V, "file size: %ld\n", sz);
-
- buf = malloc(sz + 1);
- assert(buf);
- bytes_read = 0;
- do {
- res = fread(buf + bytes_read, 1, sz - bytes_read, fp);
- if (res <= 0) {
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno, strerror(errno));
- fclose(fp);
- free(buf);
- return 0;
- }
- bytes_read += res;
- } while (sz - bytes_read > 0);
- buf[sz] = '\0';
- fclose(fp);
-
- if (bufsize)
- *bufsize = sz;
- return buf;
-}
-
-/*
- * \param buf pointer to subtitle text in utf-8
- */
-static ass_track_t* parse_memory(ass_library_t* library, char* buf)
-{
- ass_track_t* track;
- int i;
-
- track = ass_new_track(library);
-
- // process header
- process_text(track, buf);
-
- // external SSA/ASS subs does not have ReadOrder field
- for (i = 0; i < track->n_events; ++i)
- track->events[i].ReadOrder = i;
-
- // there is no explicit end-of-font marker in ssa/ass
- if (track->parser_priv->fontname)
- decode_font(track);
-
- if (track->track_type == TRACK_TYPE_UNKNOWN) {
- ass_free_track(track);
- return 0;
- }
-
- process_force_style(track);
-
- return track;
-}
-
-/**
- * \brief Read subtitles from memory.
- * \param library libass library object
- * \param buf pointer to subtitles text
- * \param bufsize size of buffer
- * \param codepage recode buffer contents from given codepage
- * \return newly allocated track
-*/
-ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize, char* codepage)
-{
- ass_track_t* track;
- int need_free = 0;
-
- if (!buf)
- return 0;
-
-#ifdef CONFIG_ICONV
- if (codepage)
- buf = sub_recode(buf, bufsize, codepage);
- if (!buf)
- return 0;
- else
- need_free = 1;
-#endif
- track = parse_memory(library, buf);
- if (need_free)
- free(buf);
- if (!track)
- return 0;
-
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory, track->n_styles, track->n_events);
- return track;
-}
-
-char* read_file_recode(char* fname, char* codepage, size_t* size)
-{
- char* buf;
- size_t bufsize;
-
- buf = read_file(fname, &bufsize);
- if (!buf)
- return 0;
-#ifdef CONFIG_ICONV
- if (codepage) {
- char* tmpbuf = sub_recode(buf, bufsize, codepage);
- free(buf);
- buf = tmpbuf;
- }
- if (!buf)
- return 0;
-#endif
- *size = bufsize;
- return buf;
-}
-
-/**
- * \brief Read subtitles from file.
- * \param library libass library object
- * \param fname file name
- * \param codepage recode buffer contents from given codepage
- * \return newly allocated track
-*/
-ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage)
-{
- char* buf;
- ass_track_t* track;
- size_t bufsize;
-
- buf = read_file_recode(fname, codepage, &bufsize);
- if (!buf)
- return 0;
- track = parse_memory(library, buf);
- free(buf);
- if (!track)
- return 0;
-
- track->name = strdup(fname);
-
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname, track->n_styles, track->n_events);
-
-// dump_events(forced_tid);
- return track;
-}
-
-/**
- * \brief read styles from file into already initialized track
- */
-int ass_read_styles(ass_track_t* track, char* fname, char* codepage)
-{
- char* buf;
- parser_state_t old_state;
- size_t sz;
-
- buf = read_file(fname, &sz);
- if (!buf)
- return 1;
-#ifdef CONFIG_ICONV
- if (codepage) {
- char* tmpbuf;
- tmpbuf = sub_recode(buf, sz, codepage);
- free(buf);
- buf = tmpbuf;
- }
- if (!buf)
- return 0;
-#endif
-
- old_state = track->parser_priv->state;
- track->parser_priv->state = PST_STYLES;
- process_text(track, buf);
- track->parser_priv->state = old_state;
-
- return 0;
-}
-
-long long ass_step_sub(ass_track_t* track, long long now, int movement) {
- int i;
-
- if (movement == 0) return 0;
- if (track->n_events == 0) return 0;
-
- if (movement < 0)
- for (i = 0; (i < track->n_events) && ((long long)(track->events[i].Start + track->events[i].Duration) <= now); ++i) {}
- else
- for (i = track->n_events - 1; (i >= 0) && ((long long)(track->events[i].Start) > now); --i) {}
-
- // -1 and n_events are ok
- assert(i >= -1); assert(i <= track->n_events);
- i += movement;
- if (i < 0) i = 0;
- if (i >= track->n_events) i = track->n_events - 1;
- return ((long long)track->events[i].Start) - now;
-}
-
-ass_track_t* ass_new_track(ass_library_t* library) {
- ass_track_t* track = calloc(1, sizeof(ass_track_t));
- track->library = library;
- track->ScaledBorderAndShadow = 1;
- track->parser_priv = calloc(1, sizeof(parser_priv_t));
- return track;
-}
diff --git a/libass/ass.h b/libass/ass.h
deleted file mode 100644
index e98b4264b7..0000000000
--- a/libass/ass.h
+++ /dev/null
@@ -1,229 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_ASS_H
-#define LIBASS_ASS_H
-
-#include <stdio.h>
-#include "ass_types.h"
-
-/// Libass renderer object. Contents are private.
-typedef struct ass_renderer_s ass_renderer_t;
-
-/// a linked list of images produced by ass renderer
-typedef struct ass_image_s {
- int w, h; // bitmap width/height
- int stride; // bitmap stride
- unsigned char* bitmap; // 1bpp stride*h alpha buffer
- uint32_t color; // RGBA
- int dst_x, dst_y; // bitmap placement inside the video frame
-
- struct ass_image_s* next; // linked list
-} ass_image_t;
-
-/// Hinting type
-typedef enum {ASS_HINTING_NONE = 0,
- ASS_HINTING_LIGHT,
- ASS_HINTING_NORMAL,
- ASS_HINTING_NATIVE
-} ass_hinting_t;
-
-/**
- * \brief initialize the library
- * \return library handle or NULL if failed
- */
-ass_library_t* ass_library_init(void);
-
-/**
- * \brief finalize the library
- * \param priv library handle
- */
-void ass_library_done(ass_library_t*);
-
-/**
- * \brief set private font directory
- * It is used for saving embedded fonts and also in font lookup.
- */
-void ass_set_fonts_dir(ass_library_t* priv, const char* fonts_dir);
-
-void ass_set_extract_fonts(ass_library_t* priv, int extract);
-
-void ass_set_style_overrides(ass_library_t* priv, char** list);
-
-/**
- * \brief initialize the renderer
- * \param priv library handle
- * \return renderer handle or NULL if failed
- */
-ass_renderer_t* ass_renderer_init(ass_library_t*);
-
-/**
- * \brief finalize the renderer
- * \param priv renderer handle
- */
-void ass_renderer_done(ass_renderer_t* priv);
-
-void ass_set_frame_size(ass_renderer_t* priv, int w, int h);
-void ass_set_margins(ass_renderer_t* priv, int t, int b, int l, int r);
-void ass_set_use_margins(ass_renderer_t* priv, int use);
-void ass_set_aspect_ratio(ass_renderer_t* priv, double ar);
-void ass_set_font_scale(ass_renderer_t* priv, double font_scale);
-void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht);
-void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing);
-
-/**
- * \brief set font lookup defaults
- */
-int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family);
-
-/**
- * \brief set font lookup defaults, don't use fontconfig even if it is available
- */
-int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const char* default_family);
-
-/**
- * \brief render a frame, producing a list of ass_image_t
- * \param priv library
- * \param track subtitle track
- * \param now video timestamp in milliseconds
- */
-ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change);
-
-
-// The following functions operate on track objects and do not need an ass_renderer //
-
-/**
- * \brief allocate a new empty track object
- * \return pointer to empty track
- */
-ass_track_t* ass_new_track(ass_library_t*);
-
-/**
- * \brief deallocate track and all its child objects (styles and events)
- * \param track track to deallocate
- */
-void ass_free_track(ass_track_t* track);
-
-/**
- * \brief allocate new style
- * \param track track
- * \return newly allocated style id
- */
-int ass_alloc_style(ass_track_t* track);
-
-/**
- * \brief allocate new event
- * \param track track
- * \return newly allocated event id
- */
-int ass_alloc_event(ass_track_t* track);
-
-/**
- * \brief delete a style
- * \param track track
- * \param sid style id
- * Deallocates style data. Does not modify track->n_styles.
- */
-void ass_free_style(ass_track_t* track, int sid);
-
-/**
- * \brief delete an event
- * \param track track
- * \param eid event id
- * Deallocates event data. Does not modify track->n_events.
- */
-void ass_free_event(ass_track_t* track, int eid);
-
-/**
- * \brief Parse a chunk of subtitle stream data.
- * \param track track
- * \param data string to parse
- * \param size length of data
- */
-void ass_process_data(ass_track_t* track, char* data, int size);
-
-/**
- * \brief Parse Codec Private section of subtitle stream
- * \param track target track
- * \param data string to parse
- * \param size length of data
- */
-void ass_process_codec_private(ass_track_t* track, char *data, int size);
-
-/**
- * \brief Parse a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary).
- * \param track track
- * \param data string to parse
- * \param size length of data
- * \param timecode starting time of the event (milliseconds)
- * \param duration duration of the event (milliseconds)
-*/
-void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration);
-
-char* read_file_recode(char* fname, char* codepage, size_t* size);
-
-/**
- * \brief Read subtitles from file.
- * \param fname file name
- * \return newly allocated track
-*/
-ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage);
-
-/**
- * \brief Read subtitles from memory.
- * \param library libass library object
- * \param buf pointer to subtitles text
- * \param bufsize size of buffer
- * \param codepage recode buffer contents from given codepage
- * \return newly allocated track
-*/
-ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize, char* codepage);
-/**
- * \brief read styles from file into already initialized track
- * \return 0 on success
- */
-int ass_read_styles(ass_track_t* track, char* fname, char* codepage);
-
-/**
- * \brief Add a memory font.
- * \param name attachment name
- * \param data binary font data
- * \param data_size data size
-*/
-void ass_add_font(ass_library_t* library, char* name, char* data, int data_size);
-
-/**
- * \brief Remove all fonts stored in ass_library object
- */
-void ass_clear_fonts(ass_library_t* library);
-
-/**
- * \brief Calculates timeshift from now to the start of some other subtitle event, depending on movement parameter
- * \param track subtitle track
- * \param now current time, ms
- * \param movement how many events to skip from the one currently displayed
- * +2 means "the one after the next", -1 means "previous"
- * \return timeshift, ms
- */
-long long ass_step_sub(ass_track_t* track, long long now, int movement);
-
-#endif /* LIBASS_ASS_H */
diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c
deleted file mode 100644
index 302827af10..0000000000
--- a/libass/ass_bitmap.c
+++ /dev/null
@@ -1,336 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-#include "mputils.h"
-#include "ass_bitmap.h"
-
-struct ass_synth_priv_s {
- int tmp_w, tmp_h;
- unsigned short* tmp;
-
- int g_r;
- int g_w;
-
- unsigned *g;
- unsigned *gt2;
-
- double radius;
-};
-
-static const unsigned int maxcolor = 255;
-static const unsigned base = 256;
-
-static int generate_tables(ass_synth_priv_t* priv, double radius)
-{
- double A = log(1.0/base)/(radius*radius*2);
- int mx, i;
- double volume_diff, volume_factor = 0;
- unsigned volume;
-
- if (priv->radius == radius)
- return 0;
- else
- priv->radius = radius;
-
- priv->g_r = ceil(radius);
- priv->g_w = 2*priv->g_r+1;
-
- if (priv->g_r) {
- priv->g = realloc(priv->g, priv->g_w * sizeof(unsigned));
- priv->gt2 = realloc(priv->gt2, 256 * priv->g_w * sizeof(unsigned));
- if (priv->g==NULL || priv->gt2==NULL) {
- return -1;
- }
- }
-
- if (priv->g_r) {
- // gaussian curve with volume = 256
- for (volume_diff=10000000; volume_diff>0.0000001; volume_diff*=0.5){
- volume_factor+= volume_diff;
- volume=0;
- for (i = 0; i<priv->g_w; ++i) {
- priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
- volume+= priv->g[i];
- }
- if(volume>256) volume_factor-= volume_diff;
- }
- volume=0;
- for (i = 0; i<priv->g_w; ++i) {
- priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
- volume+= priv->g[i];
- }
-
- // gauss table:
- for(mx=0;mx<priv->g_w;mx++){
- for(i=0;i<256;i++){
- priv->gt2[mx+i*priv->g_w] = i*priv->g[mx];
- }
- }
- }
-
- return 0;
-}
-
-static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
-{
- if (priv->tmp_w >= w && priv->tmp_h >= h)
- return;
- if (priv->tmp_w == 0)
- priv->tmp_w = 64;
- if (priv->tmp_h == 0)
- priv->tmp_h = 64;
- while (priv->tmp_w < w) priv->tmp_w *= 2;
- while (priv->tmp_h < h) priv->tmp_h *= 2;
- if (priv->tmp)
- free(priv->tmp);
- priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
-}
-
-ass_synth_priv_t* ass_synth_init(double radius)
-{
- ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
- generate_tables(priv, radius);
- return priv;
-}
-
-void ass_synth_done(ass_synth_priv_t* priv)
-{
- if (priv->tmp)
- free(priv->tmp);
- if (priv->g)
- free(priv->g);
- if (priv->gt2)
- free(priv->gt2);
- free(priv);
-}
-
-static bitmap_t* alloc_bitmap(int w, int h)
-{
- bitmap_t* bm;
- bm = calloc(1, sizeof(bitmap_t));
- bm->buffer = malloc(w*h);
- bm->w = w;
- bm->h = h;
- bm->left = bm->top = 0;
- return bm;
-}
-
-void ass_free_bitmap(bitmap_t* bm)
-{
- if (bm) {
- if (bm->buffer) free(bm->buffer);
- free(bm);
- }
-}
-
-static bitmap_t* copy_bitmap(const bitmap_t* src)
-{
- bitmap_t* dst = alloc_bitmap(src->w, src->h);
- dst->left = src->left;
- dst->top = src->top;
- memcpy(dst->buffer, src->buffer, src->w * src->h);
- return dst;
-}
-
-static int check_glyph_area(FT_Glyph glyph)
-{
- FT_BBox bbox;
- long long dx, dy;
- FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
- dx = bbox.xMax - bbox.xMin;
- dy = bbox.yMax - bbox.yMin;
- if (dx * dy > 8000000) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_GlyphBBoxTooLarge, (int)dx, (int)dy);
- return 1;
- } else
- return 0;
-}
-
-static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
-{
- FT_BitmapGlyph bg;
- FT_Bitmap* bit;
- bitmap_t* bm;
- int w, h;
- unsigned char* src;
- unsigned char* dst;
- int i;
- int error;
-
- if (check_glyph_area(glyph))
- return 0;
- error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_To_BitmapError, error);
- return 0;
- }
-
- bg = (FT_BitmapGlyph)glyph;
- bit = &(bg->bitmap);
- if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UnsupportedPixelMode, (int)(bit->pixel_mode));
- FT_Done_Glyph(glyph);
- return 0;
- }
-
- w = bit->width;
- h = bit->rows;
- bm = alloc_bitmap(w + 2*bord, h + 2*bord);
- memset(bm->buffer, 0, bm->w * bm->h);
- bm->left = bg->left - bord;
- bm->top = - bg->top - bord;
-
- src = bit->buffer;
- dst = bm->buffer + bord + bm->w * bord;
- for (i = 0; i < h; ++i) {
- memcpy(dst, src, w);
- src += bit->pitch;
- dst += bm->w;
- }
-
- FT_Done_Glyph(glyph);
- return bm;
-}
-
-/**
- * \brief fix outline bitmap and generate shadow bitmap
- * Two things are done here:
- * 1. Glyph bitmap is subtracted from outline bitmap. This way looks much better in some cases.
- * 2. Shadow bitmap is created as a sum of glyph and outline bitmaps.
- */
-static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
-{
- int x, y;
- const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
- const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
- const int r = bm_o->left + bm_o->w < bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
- const int b = bm_o->top + bm_o->h < bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
-
- bitmap_t* bm_s = copy_bitmap(bm_o);
-
- unsigned char* g = bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
- unsigned char* o = bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
- unsigned char* s = bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left);
-
- for (y = 0; y < b - t; ++y) {
- for (x = 0; x < r - l; ++x) {
- unsigned char c_g, c_o;
- c_g = g[x];
- c_o = o[x];
- o[x] = (c_o > c_g) ? c_o - (c_g/2) : 0;
- s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
- }
- g += bm_g->w;
- o += bm_o->w;
- s += bm_s->w;
- }
-
- assert(bm_s);
- return bm_s;
-}
-
-/**
- * \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
- * This blur is the same as the one employed by vsfilter.
- */
-static void be_blur(unsigned char *buf, int w, int h) {
- unsigned int x, y;
- unsigned int old_sum, new_sum;
-
- for (y=0; y<h; y++) {
- old_sum = 2 * buf[y*w];
- for (x=0; x<w-1; x++) {
- new_sum = buf[y*w+x] + buf[y*w+x+1];
- buf[y*w+x] = (old_sum + new_sum) >> 2;
- old_sum = new_sum;
- }
- }
-
- for (x=0; x<w; x++) {
- old_sum = 2 * buf[x];
- for (y=0; y<h-1; y++) {
- new_sum = buf[y*w+x] + buf[(y+1)*w+x];
- buf[y*w+x] = (old_sum + new_sum) >> 2;
- old_sum = new_sum;
- }
- }
-}
-
-int glyph_to_bitmap(ass_synth_priv_t* priv_blur,
- FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g,
- bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius)
-{
- int bord = be ? (be/4+1) : 0;
- blur_radius *= 2;
- bord = (blur_radius > 0.0) ? blur_radius : bord;
-
- assert(bm_g && bm_o && bm_s);
-
- *bm_g = *bm_o = *bm_s = 0;
-
- if (glyph)
- *bm_g = glyph_to_bitmap_internal(glyph, bord);
- if (!*bm_g)
- return 1;
-
- if (outline_glyph) {
- *bm_o = glyph_to_bitmap_internal(outline_glyph, bord);
- if (!*bm_o) {
- ass_free_bitmap(*bm_g);
- return 1;
- }
- }
- if (*bm_o)
- resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
- resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
-
- if (be) {
- while (be--) {
- if (*bm_o)
- be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h);
- else
- be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h);
- }
- } else {
- if (blur_radius > 0.0) {
- generate_tables(priv_blur, blur_radius);
- if (*bm_o)
- blur((*bm_o)->buffer, priv_blur->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
- else
- blur((*bm_g)->buffer, priv_blur->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv_blur->gt2, priv_blur->g_r, priv_blur->g_w);
- }
- }
- if (*bm_o)
- *bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
- else
- *bm_s = copy_bitmap(*bm_g);
-
- assert(bm_s);
- return 0;
-}
diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h
deleted file mode 100644
index c0b4ad201f..0000000000
--- a/libass/ass_bitmap.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_BITMAP_H
-#define LIBASS_BITMAP_H
-
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-typedef struct ass_synth_priv_s ass_synth_priv_t;
-
-ass_synth_priv_t* ass_synth_init(double);
-void ass_synth_done(ass_synth_priv_t* priv);
-
-typedef struct bitmap_s {
- int left, top;
- int w, h; // width, height
- unsigned char* buffer; // w x h buffer
-} bitmap_t;
-
-/**
- * \brief perform glyph rendering
- * \param glyph original glyph
- * \param outline_glyph "border" glyph, produced from original by FreeType's glyph stroker
- * \param bm_g out: pointer to the bitmap of original glyph is returned here
- * \param bm_o out: pointer to the bitmap of outline (border) glyph is returned here
- * \param bm_g out: pointer to the bitmap of glyph shadow is returned here
- * \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
- */
-int glyph_to_bitmap(ass_synth_priv_t* priv_blur, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be, double blur_radius);
-
-void ass_free_bitmap(bitmap_t* bm);
-
-#endif /* LIBASS_BITMAP_H */
diff --git a/libass/ass_cache.c b/libass/ass_cache.c
deleted file mode 100644
index 2150d27ec2..0000000000
--- a/libass/ass_cache.c
+++ /dev/null
@@ -1,385 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-
-#include <assert.h>
-
-#include "mputils.h"
-#include "ass.h"
-#include "ass_fontconfig.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-
-
-typedef struct hashmap_item_s {
- void* key;
- void* value;
- struct hashmap_item_s* next;
-} hashmap_item_t;
-typedef hashmap_item_t* hashmap_item_p;
-
-struct hashmap_s {
- int nbuckets;
- size_t key_size, value_size;
- hashmap_item_p* root;
- hashmap_item_dtor_t item_dtor; // a destructor for hashmap key/value pairs
- hashmap_key_compare_t key_compare;
- hashmap_hash_t hash;
- // stats
- int hit_count;
- int miss_count;
- int count;
-};
-
-#define FNV1_32A_INIT (unsigned)0x811c9dc5
-
-static inline unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval)
-{
- unsigned char *bp = buf;
- unsigned char *be = bp + len;
- while (bp < be) {
- hval ^= (unsigned)*bp++;
- hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
- }
- return hval;
-}
-static inline unsigned fnv_32a_str(char* str, unsigned hval)
-{
- unsigned char* s = (unsigned char*)str;
- while (*s) {
- hval ^= (unsigned)*s++;
- hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
- }
- return hval;
-}
-
-static unsigned hashmap_hash(void* buf, size_t len)
-{
- return fnv_32a_buf(buf, len, FNV1_32A_INIT);
-}
-
-static int hashmap_key_compare(void* a, void* b, size_t size)
-{
- return memcmp(a, b, size) == 0;
-}
-
-static void hashmap_item_dtor(void* key, size_t key_size, void* value, size_t value_size)
-{
- free(key);
- free(value);
-}
-
-hashmap_t* hashmap_init(size_t key_size, size_t value_size, int nbuckets,
- hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
- hashmap_hash_t hash)
-{
- hashmap_t* map = calloc(1, sizeof(hashmap_t));
- map->nbuckets = nbuckets;
- map->key_size = key_size;
- map->value_size = value_size;
- map->root = calloc(nbuckets, sizeof(hashmap_item_p));
- map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
- map->key_compare = key_compare ? key_compare : hashmap_key_compare;
- map->hash = hash ? hash : hashmap_hash;
- return map;
-}
-
-void hashmap_done(hashmap_t* map)
-{
- int i;
- // print stats
- if (map->count > 0 || map->hit_count + map->miss_count > 0)
- mp_msg(MSGT_ASS, MSGL_V, "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
- map->hit_count + map->miss_count, map->hit_count, map->miss_count, map->count);
-
- for (i = 0; i < map->nbuckets; ++i) {
- hashmap_item_t* item = map->root[i];
- while (item) {
- hashmap_item_t* next = item->next;
- map->item_dtor(item->key, map->key_size, item->value, map->value_size);
- free(item);
- item = next;
- }
- }
- free(map->root);
- free(map);
-}
-
-// does nothing if key already exists
-void* hashmap_insert(hashmap_t* map, void* key, void* value)
-{
- unsigned hash = map->hash(key, map->key_size);
- hashmap_item_t** next = map->root + (hash % map->nbuckets);
- while (*next) {
- if (map->key_compare(key, (*next)->key, map->key_size))
- return (*next)->value;
- next = &((*next)->next);
- assert(next);
- }
- (*next) = malloc(sizeof(hashmap_item_t));
- (*next)->key = malloc(map->key_size);
- (*next)->value = malloc(map->value_size);
- memcpy((*next)->key, key, map->key_size);
- memcpy((*next)->value, value, map->value_size);
- (*next)->next = 0;
-
- map->count ++;
- return (*next)->value;
-}
-
-void* hashmap_find(hashmap_t* map, void* key)
-{
- unsigned hash = map->hash(key, map->key_size);
- hashmap_item_t* item = map->root[hash % map->nbuckets];
- while (item) {
- if (map->key_compare(key, item->key, map->key_size)) {
- map->hit_count++;
- return item->value;
- }
- item = item->next;
- }
- map->miss_count++;
- return 0;
-}
-
-//---------------------------------
-// font cache
-
-hashmap_t* font_cache;
-
-static unsigned font_desc_hash(void* buf, size_t len)
-{
- ass_font_desc_t* desc = buf;
- unsigned hval;
- hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
- hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
- hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
- return hval;
-}
-
-static int font_compare(void* key1, void* key2, size_t key_size) {
- ass_font_desc_t* a = key1;
- ass_font_desc_t* b = key2;
- if (strcmp(a->family, b->family) != 0)
- return 0;
- if (a->bold != b->bold)
- return 0;
- if (a->italic != b->italic)
- return 0;
- if (a->treat_family_as_pattern != b->treat_family_as_pattern)
- return 0;
- return 1;
-}
-
-static void font_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
-{
- ass_font_free(value);
- free(key);
-}
-
-ass_font_t* ass_font_cache_find(ass_font_desc_t* desc)
-{
- return hashmap_find(font_cache, desc);
-}
-
-/**
- * \brief Add a face struct to cache.
- * \param font font struct
-*/
-void* ass_font_cache_add(ass_font_t* font)
-{
- return hashmap_insert(font_cache, &(font->desc), font);
-}
-
-void ass_font_cache_init(void)
-{
- font_cache = hashmap_init(sizeof(ass_font_desc_t),
- sizeof(ass_font_t),
- 1000,
- font_hash_dtor, font_compare, font_desc_hash);
-}
-
-void ass_font_cache_done(void)
-{
- hashmap_done(font_cache);
-}
-
-
-// Create hash/compare functions for bitmap and glyph
-#define CREATE_HASH_FUNCTIONS
-#include "ass_cache_template.c"
-#define CREATE_COMPARISON_FUNCTIONS
-#include "ass_cache_template.c"
-
-//---------------------------------
-// bitmap cache
-
-hashmap_t* bitmap_cache;
-
-static void bitmap_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
-{
- bitmap_hash_val_t* v = value;
- if (v->bm) ass_free_bitmap(v->bm);
- if (v->bm_o) ass_free_bitmap(v->bm_o);
- if (v->bm_s) ass_free_bitmap(v->bm_s);
- free(key);
- free(value);
-}
-
-void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val)
-{
- return hashmap_insert(bitmap_cache, key, val);
-}
-
-/**
- * \brief Get a bitmap from bitmap cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key)
-{
- return hashmap_find(bitmap_cache, key);
-}
-
-void ass_bitmap_cache_init(void)
-{
- bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t),
- sizeof(bitmap_hash_val_t),
- 0xFFFF + 13,
- bitmap_hash_dtor, bitmap_compare,
- bitmap_hash);
-}
-
-void ass_bitmap_cache_done(void)
-{
- hashmap_done(bitmap_cache);
-}
-
-void ass_bitmap_cache_reset(void)
-{
- ass_bitmap_cache_done();
- ass_bitmap_cache_init();
-}
-
-//---------------------------------
-// glyph cache
-
-hashmap_t* glyph_cache;
-
-static void glyph_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
-{
- glyph_hash_val_t* v = value;
- if (v->glyph) FT_Done_Glyph(v->glyph);
- if (v->outline_glyph) FT_Done_Glyph(v->outline_glyph);
- free(key);
- free(value);
-}
-
-void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val)
-{
- return hashmap_insert(glyph_cache, key, val);
-}
-
-/**
- * \brief Get a glyph from glyph cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key)
-{
- return hashmap_find(glyph_cache, key);
-}
-
-void ass_glyph_cache_init(void)
-{
- glyph_cache = hashmap_init(sizeof(glyph_hash_key_t),
- sizeof(glyph_hash_val_t),
- 0xFFFF + 13,
- glyph_hash_dtor, glyph_compare, glyph_hash);
-}
-
-void ass_glyph_cache_done(void)
-{
- hashmap_done(glyph_cache);
-}
-
-void ass_glyph_cache_reset(void)
-{
- ass_glyph_cache_done();
- ass_glyph_cache_init();
-}
-
-
-//---------------------------------
-// composite cache
-
-hashmap_t* composite_cache;
-
-static void composite_hash_dtor(void* key, size_t key_size, void* value, size_t value_size)
-{
- composite_hash_val_t* v = value;
- free(v->a);
- free(v->b);
- free(key);
- free(value);
-}
-
-void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val)
-{
- return hashmap_insert(composite_cache, key, val);
-}
-
-/**
- * \brief Get a composite bitmap from composite cache.
- * \param key hash key
- * \return requested hash val or 0 if not found
-*/
-composite_hash_val_t* cache_find_composite(composite_hash_key_t* key)
-{
- return hashmap_find(composite_cache, key);
-}
-
-void ass_composite_cache_init(void)
-{
- composite_cache = hashmap_init(sizeof(composite_hash_key_t),
- sizeof(composite_hash_val_t),
- 0xFFFF + 13,
- composite_hash_dtor, NULL, NULL);
-}
-
-void ass_composite_cache_done(void)
-{
- hashmap_done(composite_cache);
-}
-
-void ass_composite_cache_reset(void)
-{
- ass_composite_cache_done();
- ass_composite_cache_init();
-}
diff --git a/libass/ass_cache.h b/libass/ass_cache.h
deleted file mode 100644
index 863ba6fdf6..0000000000
--- a/libass/ass_cache.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_CACHE_H
-#define LIBASS_CACHE_H
-
-#include "ass.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-
-void ass_font_cache_init(void);
-ass_font_t* ass_font_cache_find(ass_font_desc_t* desc);
-void* ass_font_cache_add(ass_font_t* font);
-void ass_font_cache_done(void);
-
-
-// Create definitions for bitmap_hash_key and glyph_hash_key
-#define CREATE_STRUCT_DEFINITIONS
-#include "ass_cache_template.c"
-
-typedef struct bitmap_hash_val_s {
- bitmap_t* bm; // the actual bitmaps
- bitmap_t* bm_o;
- bitmap_t* bm_s;
-} bitmap_hash_val_t;
-
-void ass_bitmap_cache_init(void);
-void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val);
-bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key);
-void ass_bitmap_cache_reset(void);
-void ass_bitmap_cache_done(void);
-
-
-// Cache for composited bitmaps
-typedef struct composite_hash_key_s {
- int aw, ah, bw, bh;
- int ax, ay, bx, by;
- bitmap_hash_key_t a;
- bitmap_hash_key_t b;
-} composite_hash_key_t;
-
-typedef struct composite_hash_val_s {
- unsigned char* a;
- unsigned char* b;
-} composite_hash_val_t;
-
-void ass_composite_cache_init(void);
-void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val);
-composite_hash_val_t* cache_find_composite(composite_hash_key_t* key);
-void ass_composite_cache_reset(void);
-void ass_composite_cache_done(void);
-
-
-typedef struct glyph_hash_val_s {
- FT_Glyph glyph;
- FT_Glyph outline_glyph;
- FT_BBox bbox_scaled; // bbox after scaling, but before rotation
- FT_Vector advance; // 26.6, advance distance to the next bitmap in line
-} glyph_hash_val_t;
-
-void ass_glyph_cache_init(void);
-void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val);
-glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key);
-void ass_glyph_cache_reset(void);
-void ass_glyph_cache_done(void);
-
-typedef struct hashmap_s hashmap_t;
-typedef void (*hashmap_item_dtor_t)(void* key, size_t key_size, void* value, size_t value_size);
-typedef int (*hashmap_key_compare_t)(void* key1, void* key2, size_t key_size);
-typedef unsigned (*hashmap_hash_t)(void* key, size_t key_size);
-
-hashmap_t* hashmap_init(size_t key_size, size_t value_size, int nbuckets,
- hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
- hashmap_hash_t hash);
-void hashmap_done(hashmap_t* map);
-void* hashmap_insert(hashmap_t* map, void* key, void* value);
-void* hashmap_find(hashmap_t* map, void* key);
-
-#endif /* LIBASS_CACHE_H */
diff --git a/libass/ass_cache_template.c b/libass/ass_cache_template.c
deleted file mode 100644
index 7f9ec95f57..0000000000
--- a/libass/ass_cache_template.c
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifdef CREATE_STRUCT_DEFINITIONS
-#undef CREATE_STRUCT_DEFINITIONS
-#define START(funcname, structname) \
- typedef struct structname {
-#define GENERIC(type, member) \
- type member;
-#define FTVECTOR(member) \
- FT_Vector member;
-#define END(typedefnamename) \
- } typedefnamename;
-
-#elif defined(CREATE_COMPARISON_FUNCTIONS)
-#undef CREATE_COMPARISON_FUNCTIONS
-#define START(funcname, structname) \
- static int funcname##_compare(void *key1, void *key2, size_t key_size) \
- { \
- struct structname *a = key1; \
- struct structname *b = key2; \
- return // conditions follow
-#define GENERIC(type, member) \
- a->member == b->member &&
-#define FTVECTOR(member) \
- a->member.x == b->member.x && a->member.y == b->member.y &&
-#define END(typedefname) \
- 1; \
- }
-
-#elif defined(CREATE_HASH_FUNCTIONS)
-#undef CREATE_HASH_FUNCTIONS
-#define START(funcname, structname) \
- static unsigned funcname##_hash(void *buf, size_t len) \
- { \
- struct structname *p = buf; \
- unsigned hval = FNV1_32A_INIT;
-#define GENERIC(type, member) \
- hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
-#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
-#define END(typedefname) \
- return hval; \
- }
-
-#else
-#error missing defines
-#endif
-
-
-
-// describes a bitmap; bitmaps with equivalents structs are considered identical
-START(bitmap, bipmap_hash_key_s)
- GENERIC(char, bitmap) // bool : true = bitmap, false = outline
- GENERIC(ass_font_t *, font)
- GENERIC(double, size) // font size
- GENERIC(uint32_t, ch) // character code
- GENERIC(unsigned, outline) // border width, 16.16 fixed point value
- GENERIC(int, bold)
- GENERIC(int, italic)
- GENERIC(char, be) // blur edges
- GENERIC(double, blur) // gaussian blur
- GENERIC(unsigned, scale_x) // 16.16
- GENERIC(unsigned, scale_y) // 16.16
- GENERIC(int, frx) // signed 16.16
- GENERIC(int, fry) // signed 16.16
- GENERIC(int, frz) // signed 16.16
- // shift vector that was added to glyph before applying rotation
- // = 0, if frx = fry = frx = 0
- // = (glyph base point) - (rotation origin), otherwise
- GENERIC(int, shift_x)
- GENERIC(int, shift_y)
- FTVECTOR(advance) // subpixel shift vector
-END(bitmap_hash_key_t)
-
-// describes an outline glyph
-START(glyph, glyph_hash_key_s)
- GENERIC(ass_font_t *, font)
- GENERIC(double, size) // font size
- GENERIC(uint32_t, ch) // character code
- GENERIC(int, bold)
- GENERIC(int, italic)
- GENERIC(unsigned, scale_x) // 16.16
- GENERIC(unsigned, scale_y) // 16.16
- FTVECTOR(advance) // subpixel shift vector
- GENERIC(unsigned, outline) // border width, 16.16
-END(glyph_hash_key_t)
-
-#undef START
-#undef GENERIC
-#undef FTVECTOR
-#undef END
diff --git a/libass/ass_font.c b/libass/ass_font.c
deleted file mode 100644
index 73ee1c4a5b..0000000000
--- a/libass/ass_font.c
+++ /dev/null
@@ -1,371 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_SYNTHESIS_H
-#include FT_GLYPH_H
-#include FT_TRUETYPE_TABLES_H
-
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-#include "ass_fontconfig.h"
-#include "ass_utils.h"
-#include "mputils.h"
-
-/**
- * Select Microfost Unicode CharMap, if the font has one.
- * Otherwise, let FreeType decide.
- */
-static void charmap_magic(FT_Face face)
-{
- int i;
- for (i = 0; i < face->num_charmaps; ++i) {
- FT_CharMap cmap = face->charmaps[i];
- unsigned pid = cmap->platform_id;
- unsigned eid = cmap->encoding_id;
- if (pid == 3 /*microsoft*/ && (eid == 1 /*unicode bmp*/ || eid == 10 /*full unicode*/)) {
- FT_Set_Charmap(face, cmap);
- return;
- }
- }
-
- if (!face->charmap) {
- if (face->num_charmaps == 0) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoCharmaps);
- return;
- }
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoCharmapAutodetected);
- FT_Set_Charmap(face, face->charmaps[0]);
- return;
- }
-}
-
-static void update_transform(ass_font_t* font)
-{
- int i;
- FT_Matrix m;
- m.xx = double_to_d16(font->scale_x);
- m.yy = double_to_d16(font->scale_y);
- m.xy = m.yx = 0;
- for (i = 0; i < font->n_faces; ++i)
- FT_Set_Transform(font->faces[i], &m, &font->v);
-}
-
-/**
- * \brief find a memory font by name
- */
-static int find_font(ass_library_t* library, char* name)
-{
- int i;
- for (i = 0; i < library->num_fontdata; ++i)
- if (strcasecmp(name, library->fontdata[i].name) == 0)
- return i;
- return -1;
-}
-
-static void face_set_size(FT_Face face, double size);
-
-static void buggy_font_workaround(FT_Face face)
-{
- // Some fonts have zero Ascender/Descender fields in 'hhea' table.
- // In this case, get the information from 'os2' table or, as
- // a last resort, from face.bbox.
- if (face->ascender + face->descender == 0 || face->height == 0) {
- TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
- if (os2) {
- face->ascender = os2->sTypoAscender;
- face->descender = os2->sTypoDescender;
- face->height = face->ascender - face->descender;
- } else {
- face->ascender = face->bbox.yMax;
- face->descender = face->bbox.yMin;
- face->height = face->ascender - face->descender;
- }
- }
-}
-
-/**
- * \brief Select a face with the given charcode and add it to ass_font_t
- * \return index of the new face in font->faces, -1 if failed
- */
-static int add_face(void* fc_priv, ass_font_t* font, uint32_t ch)
-{
- char* path;
- int index;
- FT_Face face;
- int error;
- int mem_idx;
-
- if (font->n_faces == ASS_FONT_MAX_FACES)
- return -1;
-
- path = fontconfig_select(fc_priv, font->desc.family, font->desc.treat_family_as_pattern, font->desc.bold,
- font->desc.italic, &index, ch);
- if (!path)
- return -1;
-
- mem_idx = find_font(font->library, path);
- if (mem_idx >= 0) {
- error = FT_New_Memory_Face(font->ftlibrary, (unsigned char*)font->library->fontdata[mem_idx].data,
- font->library->fontdata[mem_idx].size, 0, &face);
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, path);
- return -1;
- }
- } else {
- error = FT_New_Face(font->ftlibrary, path, index, &face);
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningFont, path, index);
- return -1;
- }
- }
- charmap_magic(face);
- buggy_font_workaround(face);
-
- font->faces[font->n_faces++] = face;
- update_transform(font);
- face_set_size(face, font->size);
- return font->n_faces - 1;
-}
-
-/**
- * \brief Create a new ass_font_t according to "desc" argument
- */
-ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc)
-{
- int error;
- ass_font_t* fontp;
- ass_font_t font;
-
- fontp = ass_font_cache_find(desc);
- if (fontp)
- return fontp;
-
- font.library = library;
- font.ftlibrary = ftlibrary;
- font.n_faces = 0;
- font.desc.family = strdup(desc->family);
- font.desc.treat_family_as_pattern = desc->treat_family_as_pattern;
- font.desc.bold = desc->bold;
- font.desc.italic = desc->italic;
-
- font.scale_x = font.scale_y = 1.;
- font.v.x = font.v.y = 0;
- font.size = 0.;
-
- error = add_face(fc_priv, &font, 0);
- if (error == -1) {
- free(font.desc.family);
- return 0;
- } else
- return ass_font_cache_add(&font);
-}
-
-/**
- * \brief Set font transformation matrix and shift vector
- **/
-void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v)
-{
- font->scale_x = scale_x;
- font->scale_y = scale_y;
- font->v.x = v->x;
- font->v.y = v->y;
- update_transform(font);
-}
-
-static void face_set_size(FT_Face face, double size)
-{
-#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
- TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
- TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
- double mscale = 1.;
- FT_Size_RequestRec rq;
- FT_Size_Metrics *m = &face->size->metrics;
- // VSFilter uses metrics from TrueType OS/2 table
- // The idea was borrowed from asa (http://asa.diac24.net)
- if (hori && os2) {
- int hori_height = hori->Ascender - hori->Descender;
- int os2_height = os2->usWinAscent + os2->usWinDescent;
- if (hori_height && os2_height)
- mscale = (double)hori_height / os2_height;
- }
- memset(&rq, 0, sizeof(rq));
- rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
- rq.width = 0;
- rq.height = double_to_d6(size * mscale);
- rq.horiResolution = rq.vertResolution = 0;
- FT_Request_Size(face, &rq);
- m->ascender /= mscale;
- m->descender /= mscale;
- m->height /= mscale;
-#else
- FT_Set_Char_Size(face, 0, double_to_d6(size), 0, 0);
-#endif
-}
-
-/**
- * \brief Set font size
- **/
-void ass_font_set_size(ass_font_t* font, double size)
-{
- int i;
- if (font->size != size) {
- font->size = size;
- for (i = 0; i < font->n_faces; ++i)
- face_set_size(font->faces[i], size);
- }
-}
-
-/**
- * \brief Get maximal font ascender and descender.
- * \param ch character code
- * The values are extracted from the font face that provides glyphs for the given character
- **/
-void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc)
-{
- int i;
- for (i = 0; i < font->n_faces; ++i) {
- FT_Face face = font->faces[i];
- if (FT_Get_Char_Index(face, ch)) {
- *asc = face->size->metrics.ascender;
- *desc = - face->size->metrics.descender;
- return;
- }
- }
-
- *asc = *desc = 0;
-}
-
-/**
- * \brief Get a glyph
- * \param ch character code
- **/
-FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting)
-{
- int error;
- int index = 0;
- int i;
- FT_Glyph glyph;
- FT_Face face = 0;
- int flags = 0;
-
- if (ch < 0x20)
- return 0;
- if (font->n_faces == 0)
- return 0;
-
- for (i = 0; i < font->n_faces; ++i) {
- face = font->faces[i];
- index = FT_Get_Char_Index(face, ch);
- if (index)
- break;
- }
-
-#ifdef CONFIG_FONTCONFIG
- if (index == 0) {
- int face_idx;
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont,
- ch, font->desc.family, font->desc.bold, font->desc.italic);
- face_idx = add_face(fontconfig_priv, font, ch);
- if (face_idx >= 0) {
- face = font->faces[face_idx];
- index = FT_Get_Char_Index(face, ch);
- if (index == 0) {
- mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
- ch, font->desc.family, font->desc.bold, font->desc.italic);
- }
- }
- }
-#endif
-
- switch (hinting) {
- case ASS_HINTING_NONE: flags = FT_LOAD_NO_HINTING; break;
- case ASS_HINTING_LIGHT: flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break;
- case ASS_HINTING_NORMAL: flags = FT_LOAD_FORCE_AUTOHINT; break;
- case ASS_HINTING_NATIVE: flags = 0; break;
- }
-
- error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
- return 0;
- }
-
-#if (FREETYPE_MAJOR > 2) || \
- ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
- ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
-// FreeType >= 2.1.10 required
- if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
- (font->desc.italic > 55)) {
- FT_GlyphSlot_Oblique(face->glyph);
- }
-#endif
- error = FT_Get_Glyph(face->glyph, &glyph);
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
- return 0;
- }
-
- return glyph;
-}
-
-/**
- * \brief Get kerning for the pair of glyphs.
- **/
-FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2)
-{
- FT_Vector v = {0, 0};
- int i;
-
- for (i = 0; i < font->n_faces; ++i) {
- FT_Face face = font->faces[i];
- int i1 = FT_Get_Char_Index(face, c1);
- int i2 = FT_Get_Char_Index(face, c2);
- if (i1 && i2) {
- if (FT_HAS_KERNING(face))
- FT_Get_Kerning(face, i1, i2, FT_KERNING_DEFAULT, &v);
- return v;
- }
- if (i1 || i2) // these glyphs are from different font faces, no kerning information
- return v;
- }
- return v;
-}
-
-/**
- * \brief Deallocate ass_font_t
- **/
-void ass_font_free(ass_font_t* font)
-{
- int i;
- for (i = 0; i < font->n_faces; ++i)
- if (font->faces[i]) FT_Done_Face(font->faces[i]);
- if (font->desc.family) free(font->desc.family);
- free(font);
-}
diff --git a/libass/ass_font.h b/libass/ass_font.h
deleted file mode 100644
index 520431821b..0000000000
--- a/libass/ass_font.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_FONT_H
-#define LIBASS_FONT_H
-
-#include <stdint.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-#include "ass.h"
-#include "ass_types.h"
-
-typedef struct ass_font_desc_s {
- char* family;
- unsigned bold;
- unsigned italic;
- int treat_family_as_pattern;
-} ass_font_desc_t;
-
-#define ASS_FONT_MAX_FACES 10
-
-typedef struct ass_font_s {
- ass_font_desc_t desc;
- ass_library_t* library;
- FT_Library ftlibrary;
- FT_Face faces[ASS_FONT_MAX_FACES];
- int n_faces;
- double scale_x, scale_y; // current transform
- FT_Vector v; // current shift
- double size;
-} ass_font_t;
-
-ass_font_t* ass_font_new(ass_library_t* library, FT_Library ftlibrary, void* fc_priv, ass_font_desc_t* desc);
-void ass_font_set_transform(ass_font_t* font, double scale_x, double scale_y, FT_Vector* v);
-void ass_font_set_size(ass_font_t* font, double size);
-void ass_font_get_asc_desc(ass_font_t* font, uint32_t ch, int* asc, int* desc);
-FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting);
-FT_Vector ass_font_get_kerning(ass_font_t* font, uint32_t c1, uint32_t c2);
-void ass_font_free(ass_font_t* font);
-
-#endif /* LIBASS_FONT_H */
diff --git a/libass/ass_fontconfig.c b/libass/ass_fontconfig.c
deleted file mode 100644
index 0b030bdf85..0000000000
--- a/libass/ass_fontconfig.c
+++ /dev/null
@@ -1,516 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#include "mputils.h"
-#include "ass.h"
-#include "ass_library.h"
-#include "ass_fontconfig.h"
-
-#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#include <fontconfig/fcfreetype.h>
-#endif
-
-struct fc_instance_s {
-#ifdef CONFIG_FONTCONFIG
- FcConfig* config;
-#endif
- char* family_default;
- char* path_default;
- int index_default;
-};
-
-#ifdef CONFIG_FONTCONFIG
-
-// 4yo fontconfig does not have these.
-// They are only needed for debug output, anyway.
-#ifndef FC_FULLNAME
-#define FC_FULLNAME "fullname"
-#endif
-#ifndef FC_EMBOLDEN
-#define FC_EMBOLDEN "embolden"
-#endif
-
-/**
- * \brief Low-level font selection.
- * \param priv private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-static char* _select_font(fc_instance_t* priv, const char* family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int* index, uint32_t code)
-{
- FcBool rc;
- FcResult result;
- FcPattern *pat = NULL, *rpat = NULL;
- int r_index, r_slant, r_weight;
- FcChar8 *r_family, *r_style, *r_file, *r_fullname;
- FcBool r_outline, r_embolden;
- FcCharSet* r_charset;
- FcFontSet* fset = NULL;
- int curf;
- char* retval = NULL;
- int family_cnt;
-
- *index = 0;
-
- if (treat_family_as_pattern)
- pat = FcNameParse((const FcChar8*)family);
- else
- pat = FcPatternCreate();
-
- if (!pat)
- goto error;
-
- if (!treat_family_as_pattern) {
- FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family);
-
- // In SSA/ASS fonts are sometimes referenced by their "full name",
- // which is usually a concatenation of family name and font
- // style (ex. Ottawa Bold). Full name is available from
- // FontConfig pattern element FC_FULLNAME, but it is never
- // used for font matching.
- // Therefore, I'm removing words from the end of the name one
- // by one, and adding shortened names to the pattern. It seems
- // that the first value (full name in this case) has
- // precedence in matching.
- // An alternative approach could be to reimplement FcFontSort
- // using FC_FULLNAME instead of FC_FAMILY.
- family_cnt = 1;
- {
- char* s = strdup(family);
- char* p = s + strlen(s);
- while (--p > s)
- if (*p == ' ' || *p == '-') {
- *p = '\0';
- FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)s);
- ++ family_cnt;
- }
- free(s);
- }
- }
- FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
- FcPatternAddInteger(pat, FC_SLANT, italic);
- FcPatternAddInteger(pat, FC_WEIGHT, bold);
-
- FcDefaultSubstitute(pat);
-
- rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
- if (!rc)
- goto error;
-
- fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
- if (!fset)
- goto error;
-
- for (curf = 0; curf < fset->nfont; ++curf) {
- FcPattern* curp = fset->fonts[curf];
-
- result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
- if (result != FcResultMatch)
- continue;
- if (r_outline != FcTrue)
- continue;
- if (!code)
- break;
- result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
- if (result != FcResultMatch)
- continue;
- if (FcCharSetHasChar(r_charset, code))
- break;
- }
-
- if (curf >= fset->nfont)
- goto error;
-
-#if (FC_VERSION >= 20297)
- if (!treat_family_as_pattern) {
- // Remove all extra family names from original pattern.
- // After this, FcFontRenderPrepare will select the most relevant family
- // name in case there are more than one of them.
- for (; family_cnt > 1; --family_cnt)
- FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
- }
-#endif
-
- rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
- if (!rpat)
- goto error;
-
- result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
- if (result != FcResultMatch)
- goto error;
- *index = r_index;
-
- result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
- if (result != FcResultMatch)
- goto error;
- retval = strdup((const char*)r_file);
-
- result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
- if (result != FcResultMatch)
- r_family = NULL;
-
- result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
- if (result != FcResultMatch)
- r_fullname = NULL;
-
- if (!treat_family_as_pattern &&
- !(r_family && strcasecmp((const char*)r_family, family) == 0) &&
- !(r_fullname && strcasecmp((const char*)r_fullname, family) == 0))
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne,
- (const char*)(r_fullname ? r_fullname : r_family), family);
-
- result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
- if (result != FcResultMatch)
- r_style = NULL;
-
- result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
- if (result != FcResultMatch)
- r_slant = 0;
-
- result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
- if (result != FcResultMatch)
- r_weight = 0;
-
- result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
- if (result != FcResultMatch)
- r_embolden = 0;
-
- mp_msg(MSGT_ASS, MSGL_V, "[ass] Font info: family '%s', style '%s', fullname '%s',"
- " slant %d, weight %d%s\n",
- (const char*)r_family, (const char*)r_style, (const char*)r_fullname,
- r_slant, r_weight, r_embolden ? ", embolden" : "");
-
- error:
- if (pat) FcPatternDestroy(pat);
- if (rpat) FcPatternDestroy(rpat);
- if (fset) FcFontSetDestroy(fset);
- return retval;
-}
-
-/**
- * \brief Find a font. Use default family or path if necessary.
- * \param priv_ private data
- * \param family font family
- * \param treat_family_as_pattern treat family as fontconfig pattern
- * \param bold font weight value
- * \param italic font slant value
- * \param index out: font index inside a file
- * \param code: the character that should be present in the font, can be 0
- * \return font file path
-*/
-char* fontconfig_select(fc_instance_t* priv, const char* family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int* index, uint32_t code)
-{
- char* res = 0;
- if (!priv->config) {
- *index = priv->index_default;
- return priv->path_default;
- }
- if (family && *family)
- res = _select_font(priv, family, treat_family_as_pattern, bold, italic, index, code);
- if (!res && priv->family_default) {
- res = _select_font(priv, priv->family_default, 0, bold, italic, index, code);
- if (res)
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFontFamily,
- family, bold, italic, res, *index);
- }
- if (!res && priv->path_default) {
- res = priv->path_default;
- *index = priv->index_default;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingDefaultFont,
- family, bold, italic, res, *index);
- }
- if (!res) {
- res = _select_font(priv, "Arial", 0, bold, italic, index, code);
- if (res)
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_UsingArialFontFamily,
- family, bold, italic, res, *index);
- }
- if (res)
- mp_msg(MSGT_ASS, MSGL_V, "fontconfig_select: (%s, %d, %d) -> %s, %d\n",
- family, bold, italic, res, *index);
- return res;
-}
-
-#if (FC_VERSION < 20402)
-static char* validate_fname(char* name)
-{
- char* fname;
- char* p;
- char* q;
- unsigned code;
- int sz = strlen(name);
-
- q = fname = malloc(sz + 1);
- p = name;
- while (*p) {
- code = utf8_get_char(&p);
- if (code == 0)
- break;
- if ( (code > 0x7F) ||
- (code == '\\') ||
- (code == '/') ||
- (code == ':') ||
- (code == '*') ||
- (code == '?') ||
- (code == '<') ||
- (code == '>') ||
- (code == '|') ||
- (code == 0))
- {
- *q++ = '_';
- } else {
- *q++ = code;
- }
- if (p - name > sz)
- break;
- }
- *q = 0;
- return fname;
-}
-#endif
-
-/**
- * \brief Process memory font.
- * \param priv private data
- * \param library library object
- * \param ftlibrary freetype library object
- * \param idx index of the processed font in library->fontdata
- * With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace.
- * With older FontConfig versions, save the font to ~/.mplayer/fonts.
-*/
-static void process_fontdata(fc_instance_t* priv, ass_library_t* library, FT_Library ftlibrary, int idx)
-{
- int rc;
- const char* name = library->fontdata[idx].name;
- const char* data = library->fontdata[idx].data;
- int data_size = library->fontdata[idx].size;
-
-#if (FC_VERSION < 20402)
- struct stat st;
- char* fname;
- const char* fonts_dir = library->fonts_dir;
- char buf[1000];
- FILE* fp = NULL;
-
- if (!fonts_dir)
- return;
- rc = stat(fonts_dir, &st);
- if (rc) {
- int res;
-#ifndef __MINGW32__
- res = mkdir(fonts_dir, 0700);
-#else
- res = mkdir(fonts_dir);
-#endif
- if (res) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FailedToCreateDirectory, fonts_dir);
- }
- } else if (!S_ISDIR(st.st_mode)) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NotADirectory, fonts_dir);
- }
-
- fname = validate_fname((char*)name);
-
- snprintf(buf, 1000, "%s/%s", fonts_dir, fname);
- free(fname);
-
- fp = fopen(buf, "wb");
- if (!fp) return;
-
- fwrite(data, data_size, 1, fp);
- fclose(fp);
-
-#else // (FC_VERSION >= 20402)
- FT_Face face;
- FcPattern* pattern;
- FcFontSet* fset;
- FcBool res;
- int face_index, num_faces = 1;
-
- for (face_index = 0; face_index < num_faces; ++face_index) {
- rc = FT_New_Memory_Face(ftlibrary, (unsigned char*)data, data_size, face_index, &face);
- if (rc) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorOpeningMemoryFont, name);
- return;
- }
- num_faces = face->num_faces;
-
- pattern = FcFreeTypeQueryFace(face, (unsigned char*)name, 0, FcConfigGetBlanks(priv->config));
- if (!pattern) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFreeTypeQueryFace");
- FT_Done_Face(face);
- return;
- }
-
- fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication
- if (!fset) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcConfigGetFonts");
- FT_Done_Face(face);
- return;
- }
-
- res = FcFontSetAdd(fset, pattern);
- if (!res) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FunctionCallFailed, "FcFontSetAdd");
- FT_Done_Face(face);
- return;
- }
-
- FT_Done_Face(face);
- }
-#endif
-}
-
-/**
- * \brief Init fontconfig.
- * \param library libass library object
- * \param ftlibrary freetype library object
- * \param family default font family
- * \param path default font path
- * \return pointer to fontconfig private data
-*/
-fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path, int fc)
-{
- int rc;
- fc_instance_t* priv = calloc(1, sizeof(fc_instance_t));
- const char* dir = library->fonts_dir;
- int i;
-
- if (!fc) {
- mp_msg(MSGT_ASS, MSGL_WARN,
- MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
- goto exit;
- }
-
- rc = FcInit();
- assert(rc);
-
- priv->config = FcConfigGetCurrent();
- if (!priv->config) {
- mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed);
- goto exit;
- }
-
- for (i = 0; i < library->num_fontdata; ++i)
- process_fontdata(priv, library, ftlibrary, i);
-
- if (dir) {
- if (FcDirCacheValid((const FcChar8 *)dir) == FcFalse)
- {
- mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_UpdatingFontCache);
- if (FcGetVersion() >= 20390 && FcGetVersion() < 20400)
- mp_msg(MSGT_ASS, MSGL_WARN,
- MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported);
- // FontConfig >= 2.4.0 updates cache automatically in FcConfigAppFontAddDir()
- if (FcGetVersion() < 20390) {
- FcFontSet* fcs;
- FcStrSet* fss;
- fcs = FcFontSetCreate();
- fss = FcStrSetCreate();
- rc = FcStrSetAdd(fss, (const FcChar8*)dir);
- if (!rc) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcStrSetAddFailed);
- goto ErrorFontCache;
- }
-
- rc = FcDirScan(fcs, fss, NULL, FcConfigGetBlanks(priv->config),
- (const FcChar8 *)dir, FcFalse);
- if (!rc) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirScanFailed);
- goto ErrorFontCache;
- }
-
- rc = FcDirSave(fcs, fss, (const FcChar8 *)dir);
- if (!rc) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcDirSave);
- goto ErrorFontCache;
- }
- ErrorFontCache:
- ;
- }
- }
-
- rc = FcConfigAppFontAddDir(priv->config, (const FcChar8*)dir);
- if (!rc) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FcConfigAppFontAddDirFailed);
- }
- }
-
- priv->family_default = family ? strdup(family) : NULL;
-exit:
- priv->path_default = path ? strdup(path) : NULL;
- priv->index_default = 0;
-
- return priv;
-}
-
-#else /* CONFIG_FONTCONFIG */
-
-char* fontconfig_select(fc_instance_t* priv, const char* family, int treat_family_as_pattern,
- unsigned bold, unsigned italic, int* index, uint32_t code)
-{
- *index = priv->index_default;
- return priv->path_default;
-}
-
-fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path, int fc)
-{
- fc_instance_t* priv;
-
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed);
-
- priv = calloc(1, sizeof(fc_instance_t));
-
- priv->path_default = strdup(path);
- priv->index_default = 0;
- return priv;
-}
-
-#endif
-
-void fontconfig_done(fc_instance_t* priv)
-{
- // don't call FcFini() here, library can still be used by some code
- if (priv && priv->path_default) free(priv->path_default);
- if (priv && priv->family_default) free(priv->family_default);
- if (priv) free(priv);
-}
diff --git a/libass/ass_fontconfig.h b/libass/ass_fontconfig.h
deleted file mode 100644
index 77806909cf..0000000000
--- a/libass/ass_fontconfig.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_FONTCONFIG_H
-#define LIBASS_FONTCONFIG_H
-
-#include <stdint.h>
-#include "ass_types.h"
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#endif
-
-typedef struct fc_instance_s fc_instance_t;
-
-fc_instance_t* fontconfig_init(ass_library_t* library, FT_Library ftlibrary, const char* family, const char* path, int fc);
-char* fontconfig_select(fc_instance_t* priv, const char* family, int treat_family_as_pattern, unsigned bold, unsigned italic, int* index, uint32_t code);
-void fontconfig_done(fc_instance_t* priv);
-
-#endif /* LIBASS_FONTCONFIG_H */
diff --git a/libass/ass_library.c b/libass/ass_library.c
deleted file mode 100644
index 304f2326de..0000000000
--- a/libass/ass_library.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ass.h"
-#include "ass_library.h"
-
-
-ass_library_t* ass_library_init(void)
-{
- return calloc(1, sizeof(ass_library_t));
-}
-
-void ass_library_done(ass_library_t* priv)
-{
- if (priv) {
- ass_set_fonts_dir(priv, NULL);
- ass_set_style_overrides(priv, NULL);
- ass_clear_fonts(priv);
- free(priv);
- }
-}
-
-void ass_set_fonts_dir(ass_library_t* priv, const char* fonts_dir)
-{
- if (priv->fonts_dir)
- free(priv->fonts_dir);
-
- priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0;
-}
-
-void ass_set_extract_fonts(ass_library_t* priv, int extract)
-{
- priv->extract_fonts = !!extract;
-}
-
-void ass_set_style_overrides(ass_library_t* priv, char** list)
-{
- char** p;
- char** q;
- int cnt;
-
- if (priv->style_overrides) {
- for (p = priv->style_overrides; *p; ++p)
- free(*p);
- free(priv->style_overrides);
- }
-
- if (!list) return;
-
- for (p = list, cnt = 0; *p; ++p, ++cnt) {}
-
- priv->style_overrides = malloc((cnt + 1) * sizeof(char*));
- for (p = list, q = priv->style_overrides; *p; ++p, ++q)
- *q = strdup(*p);
- priv->style_overrides[cnt] = NULL;
-}
-
-static void grow_array(void **array, int nelem, size_t elsize)
-{
- if (!(nelem & 31))
- *array = realloc(*array, (nelem + 32) * elsize);
-}
-
-void ass_add_font(ass_library_t* priv, char* name, char* data, int size)
-{
- int idx = priv->num_fontdata;
- if (!name || !data || !size)
- return;
- grow_array((void**)&priv->fontdata, priv->num_fontdata, sizeof(*priv->fontdata));
-
- priv->fontdata[idx].name = strdup(name);
-
- priv->fontdata[idx].data = malloc(size);
- memcpy(priv->fontdata[idx].data, data, size);
-
- priv->fontdata[idx].size = size;
-
- priv->num_fontdata ++;
-}
-
-void ass_clear_fonts(ass_library_t* priv)
-{
- int i;
- for (i = 0; i < priv->num_fontdata; ++i) {
- free(priv->fontdata[i].name);
- free(priv->fontdata[i].data);
- }
- free(priv->fontdata);
- priv->fontdata = NULL;
- priv->num_fontdata = 0;
-}
diff --git a/libass/ass_library.h b/libass/ass_library.h
deleted file mode 100644
index ecf46f342e..0000000000
--- a/libass/ass_library.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_LIBRARY_H
-#define LIBASS_LIBRARY_H
-
-typedef struct ass_fontdata_s {
- char* name;
- char* data;
- int size;
-} ass_fontdata_t;
-
-struct ass_library_s {
- char* fonts_dir;
- int extract_fonts;
- char** style_overrides;
-
- ass_fontdata_t* fontdata;
- int num_fontdata;
-};
-
-#endif /* LIBASS_LIBRARY_H */
diff --git a/libass/ass_mp.c b/libass/ass_mp.c
deleted file mode 100644
index b3c78b60ac..0000000000
--- a/libass/ass_mp.c
+++ /dev/null
@@ -1,279 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <inttypes.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "mp_msg.h"
-#include "get_path.h"
-
-#include "ass.h"
-#include "ass_utils.h"
-#include "ass_mp.h"
-#include "ass_library.h"
-
-#ifdef CONFIG_FONTCONFIG
-#include <fontconfig/fontconfig.h>
-#endif
-
-// libass-related command line options
-ass_library_t* ass_library;
-int ass_enabled = 0;
-float ass_font_scale = 1.;
-float ass_line_spacing = 0.;
-int ass_top_margin = 0;
-int ass_bottom_margin = 0;
-#if defined(FC_VERSION) && (FC_VERSION >= 20402)
-int extract_embedded_fonts = 1;
-#else
-int extract_embedded_fonts = 0;
-#endif
-char **ass_force_style_list = NULL;
-int ass_use_margins = 0;
-char* ass_color = NULL;
-char* ass_border_color = NULL;
-char* ass_styles_file = NULL;
-int ass_hinting = ASS_HINTING_NATIVE + 4; // native hinting for unscaled osd
-
-#ifdef CONFIG_FONTCONFIG
-extern int font_fontconfig;
-#else
-static int font_fontconfig = -1;
-#endif
-extern char* font_name;
-extern char* sub_font_name;
-extern float text_font_scale_factor;
-extern int subtitle_autoscale;
-
-#ifdef CONFIG_ICONV
-extern char* sub_cp;
-#else
-static char* sub_cp = 0;
-#endif
-
-void process_force_style(ass_track_t* track);
-
-ass_track_t* ass_default_track(ass_library_t* library) {
- ass_track_t* track = ass_new_track(library);
-
- track->track_type = TRACK_TYPE_ASS;
- track->Timer = 100.;
- track->PlayResY = 288;
- track->WrapStyle = 0;
-
- if (ass_styles_file)
- ass_read_styles(track, ass_styles_file, sub_cp);
-
- if (track->n_styles == 0) {
- ass_style_t* style;
- int sid;
- double fs;
- uint32_t c1, c2;
-
- sid = ass_alloc_style(track);
- style = track->styles + sid;
- style->Name = strdup("Default");
- style->FontName = (font_fontconfig >= 0 && sub_font_name) ? strdup(sub_font_name) : (font_fontconfig >= 0 && font_name) ? strdup(font_name) : strdup("Sans");
- style->treat_fontname_as_pattern = 1;
-
- fs = track->PlayResY * text_font_scale_factor / 100.;
- // approximate autoscale coefficients
- if (subtitle_autoscale == 2)
- fs *= 1.3;
- else if (subtitle_autoscale == 3)
- fs *= 1.4;
- style->FontSize = fs;
-
- if (ass_color) c1 = strtoll(ass_color, NULL, 16);
- else c1 = 0xFFFF0000;
- if (ass_border_color) c2 = strtoll(ass_border_color, NULL, 16);
- else c2 = 0x00000000;
-
- style->PrimaryColour = c1;
- style->SecondaryColour = c1;
- style->OutlineColour = c2;
- style->BackColour = 0x00000000;
- style->BorderStyle = 1;
- style->Alignment = 2;
- style->Outline = 2;
- style->MarginL = 10;
- style->MarginR = 10;
- style->MarginV = 5;
- style->ScaleX = 1.;
- style->ScaleY = 1.;
- }
-
- process_force_style(track);
- return track;
-}
-
-static int check_duplicate_plaintext_event(ass_track_t* track)
-{
- int i;
- ass_event_t* evt = track->events + track->n_events - 1;
-
- for (i = 0; i<track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
- if (track->events[i].Start == evt->Start &&
- track->events[i].Duration == evt->Duration &&
- strcmp(track->events[i].Text, evt->Text) == 0)
- return 1;
- return 0;
-}
-
-/**
- * \brief Convert subtitle to ass_event_t for the given track
- * \param ass_track_t track
- * \param sub subtitle to convert
- * \return event id
- * note: assumes that subtitle is _not_ fps-based; caller must manually correct
- * Start and Duration in other case.
- **/
-int ass_process_subtitle(ass_track_t* track, subtitle* sub)
-{
- int eid;
- ass_event_t* event;
- int len = 0, j;
- char* p;
- char* end;
-
- eid = ass_alloc_event(track);
- event = track->events + eid;
-
- event->Start = sub->start * 10;
- event->Duration = (sub->end - sub->start) * 10;
- event->Style = 0;
-
- for (j = 0; j < sub->lines; ++j)
- len += sub->text[j] ? strlen(sub->text[j]) : 0;
-
- len += 2 * sub->lines; // '\N', including the one after the last line
- len += 6; // {\anX}
- len += 1; // '\0'
-
- event->Text = malloc(len);
- end = event->Text + len;
- p = event->Text;
-
- if (sub->alignment)
- p += snprintf(p, end - p, "{\\an%d}", sub->alignment);
-
- for (j = 0; j < sub->lines; ++j)
- p += snprintf(p, end - p, "%s\\N", sub->text[j]);
-
- if (sub->lines > 0) p-=2; // remove last "\N"
- *p = 0;
-
- if (check_duplicate_plaintext_event(track)) {
- ass_free_event(track, eid);
- track->n_events--;
- return -1;
- }
-
- mp_msg(MSGT_ASS, MSGL_V, "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n",
- (int64_t)event->Start, (int64_t)event->Duration, event->Text);
-
- return eid;
-}
-
-
-/**
- * \brief Convert subdata to ass_track
- * \param subdata subtitles struct from subreader
- * \param fps video framerate
- * \return newly allocated ass_track, filled with subtitles from subdata
- */
-ass_track_t* ass_read_subdata(ass_library_t* library, sub_data* subdata, double fps) {
- ass_track_t* track;
- int i;
-
- track = ass_default_track(library);
- track->name = subdata->filename ? strdup(subdata->filename) : 0;
-
- for (i = 0; i < subdata->sub_num; ++i) {
- int eid = ass_process_subtitle(track, subdata->subtitles + i);
- if (eid < 0)
- continue;
- if (!subdata->sub_uses_time) {
- track->events[eid].Start *= 100. / fps;
- track->events[eid].Duration *= 100. / fps;
- }
- }
- return track;
-}
-
-void ass_configure(ass_renderer_t* priv, int w, int h, int unscaled) {
- int hinting;
- ass_set_frame_size(priv, w, h);
- ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0);
- ass_set_use_margins(priv, ass_use_margins);
- ass_set_font_scale(priv, ass_font_scale);
- if (!unscaled && (ass_hinting & 4))
- hinting = 0;
- else
- hinting = ass_hinting & 3;
- ass_set_hinting(priv, hinting);
- ass_set_line_spacing(priv, ass_line_spacing);
-}
-
-void ass_configure_fonts(ass_renderer_t* priv) {
- char *dir, *path, *family;
- dir = get_path("fonts");
- if (font_fontconfig < 0 && sub_font_name) path = strdup(sub_font_name);
- else if (font_fontconfig < 0 && font_name) path = strdup(font_name);
- else path = get_path("subfont.ttf");
- if (font_fontconfig >= 0 && sub_font_name) family = strdup(sub_font_name);
- else if (font_fontconfig >= 0 && font_name) family = strdup(font_name);
- else family = 0;
-
- if (font_fontconfig >= 0)
- ass_set_fonts(priv, path, family);
- else
- ass_set_fonts_nofc(priv, path, family);
-
- free(dir);
- free(path);
- free(family);
-}
-
-ass_library_t* ass_init(void) {
- ass_library_t* priv;
- char* path = get_path("fonts");
- priv = ass_library_init();
- ass_set_fonts_dir(priv, path);
- ass_set_extract_fonts(priv, extract_embedded_fonts);
- ass_set_style_overrides(priv, ass_force_style_list);
- free(path);
- return priv;
-}
-
-int ass_force_reload = 0; // flag set if global ass-related settings were changed
-
-ass_image_t* ass_mp_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change) {
- if (ass_force_reload) {
- ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0);
- ass_set_use_margins(priv, ass_use_margins);
- ass_set_font_scale(priv, ass_font_scale);
- ass_force_reload = 0;
- }
- return ass_render_frame(priv, track, now, detect_change);
-}
diff --git a/libass/ass_mp.h b/libass/ass_mp.h
deleted file mode 100644
index 64b411a550..0000000000
--- a/libass/ass_mp.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_MP_H
-#define LIBASS_MP_H
-
-#include "subreader.h"
-#include "ass_types.h"
-#include "ass.h"
-
-extern ass_library_t* ass_library;
-extern int ass_enabled;
-extern float ass_font_scale;
-extern float ass_line_spacing;
-extern int ass_top_margin;
-extern int ass_bottom_margin;
-extern int extract_embedded_fonts;
-extern char **ass_force_style_list;
-extern int ass_use_margins;
-extern char* ass_color;
-extern char* ass_border_color;
-extern char* ass_styles_file;
-extern int ass_hinting;
-
-ass_track_t* ass_default_track(ass_library_t* library);
-int ass_process_subtitle(ass_track_t* track, subtitle* sub);
-ass_track_t* ass_read_subdata(ass_library_t* library, sub_data* subdata, double fps);
-
-void ass_configure(ass_renderer_t* priv, int w, int h, int hinting);
-void ass_configure_fonts(ass_renderer_t* priv);
-ass_library_t* ass_init(void);
-
-typedef struct {
- ass_image_t* imgs;
- int changed;
-} mp_eosd_images_t;
-
-extern int ass_force_reload;
-ass_image_t* ass_mp_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change);
-
-#endif /* LIBASS_MP_H */
diff --git a/libass/ass_render.c b/libass/ass_render.c
deleted file mode 100644
index e3896e89a4..0000000000
--- a/libass/ass_render.c
+++ /dev/null
@@ -1,2616 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <math.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_STROKER_H
-#include FT_GLYPH_H
-#include FT_SYNTHESIS_H
-
-#include "mputils.h"
-
-#include "ass.h"
-#include "ass_font.h"
-#include "ass_bitmap.h"
-#include "ass_cache.h"
-#include "ass_utils.h"
-#include "ass_fontconfig.h"
-#include "ass_library.h"
-
-#define MAX_GLYPHS 3000
-#define MAX_LINES 300
-#define BLUR_MAX_RADIUS 50.0
-#define MAX_BE 100
-#define ROUND(x) ((int) ((x) + .5))
-#define SUBPIXEL_MASK 56 // d6 bitmask for subpixel accuracy adjustment
-
-static int last_render_id = 0;
-
-typedef struct ass_settings_s {
- int frame_width;
- int frame_height;
- double font_size_coeff; // font size multiplier
- double line_spacing; // additional line spacing (in frame pixels)
- int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin.
- int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height.
- int left_margin;
- int right_margin;
- int use_margins; // 0 - place all subtitles inside original frame
- // 1 - use margins for placing toptitles and subtitles
- double aspect; // frame aspect ratio, d_width / d_height.
- ass_hinting_t hinting;
-
- char* default_font;
- char* default_family;
-} ass_settings_t;
-
-// a rendered event
-typedef struct event_images_s {
- ass_image_t* imgs;
- int top, height;
- int detect_collisions;
- int shift_direction;
- ass_event_t* event;
-} event_images_t;
-
-struct ass_renderer_s {
- ass_library_t* library;
- FT_Library ftlibrary;
- fc_instance_t* fontconfig_priv;
- ass_settings_t settings;
- int render_id;
- ass_synth_priv_t* synth_priv;
-
- ass_image_t* images_root; // rendering result is stored here
- ass_image_t* prev_images_root;
-
- event_images_t* eimg; // temporary buffer for sorting rendered events
- int eimg_size; // allocated buffer size
-};
-
-typedef enum {EF_NONE = 0, EF_KARAOKE, EF_KARAOKE_KF, EF_KARAOKE_KO} effect_t;
-
-// describes a glyph
-// glyph_info_t and text_info_t are used for text centering and word-wrapping operations
-typedef struct glyph_info_s {
- unsigned symbol;
- FT_Glyph glyph;
- FT_Glyph outline_glyph;
- bitmap_t* bm; // glyph bitmap
- bitmap_t* bm_o; // outline bitmap
- bitmap_t* bm_s; // shadow bitmap
- FT_BBox bbox;
- FT_Vector pos;
- char linebreak; // the first (leading) glyph of some line ?
- uint32_t c[4]; // colors
- FT_Vector advance; // 26.6
- effect_t effect_type;
- int effect_timing; // time duration of current karaoke word
- // after process_karaoke_effects: distance in pixels from the glyph origin.
- // part of the glyph to the left of it is displayed in a different color.
- int effect_skip_timing; // delay after the end of last karaoke word
- int asc, desc; // font max ascender and descender
-// int height;
- int be; // blur edges
- double blur; // gaussian blur
- double shadow;
- double frx, fry, frz; // rotation
-
- bitmap_hash_key_t hash_key;
-} glyph_info_t;
-
-typedef struct line_info_s {
- int asc, desc;
-} line_info_t;
-
-typedef struct text_info_s {
- glyph_info_t* glyphs;
- int length;
- line_info_t lines[MAX_LINES];
- int n_lines;
- int height;
-} text_info_t;
-
-
-// Renderer state.
-// Values like current font face, color, screen position, clipping and so on are stored here.
-typedef struct render_context_s {
- ass_event_t* event;
- ass_style_t* style;
-
- ass_font_t* font;
- char* font_path;
- double font_size;
-
- FT_Stroker stroker;
- int alignment; // alignment overrides go here; if zero, style value will be used
- double frx, fry, frz;
- enum { EVENT_NORMAL, // "normal" top-, sub- or mid- title
- EVENT_POSITIONED, // happens after pos(,), margins are ignored
- EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited
- EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects
- } evt_type;
- double pos_x, pos_y; // position
- double org_x, org_y; // origin
- char have_origin; // origin is explicitly defined; if 0, get_base_point() is used
- double scale_x, scale_y;
- double hspacing; // distance between letters, in pixels
- double border; // outline width
- uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA
- int clip_x0, clip_y0, clip_x1, clip_y1;
- char detect_collisions;
- uint32_t fade; // alpha from \fad
- char be; // blur edges
- double blur; // gaussian blur
- double shadow;
- int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags
-
- effect_t effect_type;
- int effect_timing;
- int effect_skip_timing;
-
- enum { SCROLL_LR, // left-to-right
- SCROLL_RL,
- SCROLL_TB, // top-to-bottom
- SCROLL_BT
- } scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL
- int scroll_shift;
-
- // face properties
- char* family;
- unsigned bold;
- unsigned italic;
- int treat_family_as_pattern;
-
-} render_context_t;
-
-// frame-global data
-typedef struct frame_context_s {
- ass_renderer_t* ass_priv;
- int width, height; // screen dimensions
- int orig_height; // frame height ( = screen height - margins )
- int orig_width; // frame width ( = screen width - margins )
- int orig_height_nocrop; // frame height ( = screen height - margins + cropheight)
- int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth)
- ass_track_t* track;
- long long time; // frame's timestamp, ms
- double font_scale;
- double font_scale_x; // x scale applied to all glyphs to preserve text aspect ratio
- double border_scale;
-} frame_context_t;
-
-static ass_renderer_t* ass_renderer;
-static ass_settings_t* global_settings;
-static text_info_t text_info;
-static render_context_t render_context;
-static frame_context_t frame_context;
-
-struct render_priv_s {
- int top, height;
- int render_id;
-};
-
-static void ass_lazy_track_init(void)
-{
- ass_track_t* track = frame_context.track;
- if (track->PlayResX && track->PlayResY)
- return;
- if (!track->PlayResX && !track->PlayResY) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined);
- track->PlayResX = 384;
- track->PlayResY = 288;
- } else {
- double orig_aspect = (global_settings->aspect * frame_context.height * frame_context.orig_width) /
- frame_context.orig_height / frame_context.width;
- if (!track->PlayResY && track->PlayResX == 1280) {
- track->PlayResY = 1024;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY);
- } else if (!track->PlayResY) {
- track->PlayResY = track->PlayResX / orig_aspect + .5;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_PlayResYUndefinedSettingY, track->PlayResY);
- } else if (!track->PlayResX && track->PlayResY == 1024) {
- track->PlayResX = 1280;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX);
- } else if (!track->PlayResX) {
- track->PlayResX = track->PlayResY * orig_aspect + .5;
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_PlayResXUndefinedSettingX, track->PlayResX);
- }
- }
-}
-
-ass_renderer_t* ass_renderer_init(ass_library_t* library)
-{
- int error;
- FT_Library ft;
- ass_renderer_t* priv = 0;
- int vmajor, vminor, vpatch;
-
- memset(&render_context, 0, sizeof(render_context));
- memset(&frame_context, 0, sizeof(frame_context));
- memset(&text_info, 0, sizeof(text_info));
-
- error = FT_Init_FreeType( &ft );
- if ( error ) {
- mp_msg(MSGT_ASS, MSGL_FATAL, MSGTR_LIBASS_FT_Init_FreeTypeFailed);
- goto ass_init_exit;
- }
-
- FT_Library_Version(ft, &vmajor, &vminor, &vpatch);
- mp_msg(MSGT_ASS, MSGL_V, "FreeType library version: %d.%d.%d\n",
- vmajor, vminor, vpatch);
- mp_msg(MSGT_ASS, MSGL_V, "FreeType headers version: %d.%d.%d\n",
- FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
-
- priv = calloc(1, sizeof(ass_renderer_t));
- if (!priv) {
- FT_Done_FreeType(ft);
- goto ass_init_exit;
- }
-
- priv->synth_priv = ass_synth_init(BLUR_MAX_RADIUS);
-
- priv->library = library;
- priv->ftlibrary = ft;
- // images_root and related stuff is zero-filled in calloc
-
- ass_font_cache_init();
- ass_bitmap_cache_init();
- ass_composite_cache_init();
- ass_glyph_cache_init();
-
- text_info.glyphs = calloc(MAX_GLYPHS, sizeof(glyph_info_t));
-
-ass_init_exit:
- if (priv) mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_Init);
- else mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_InitFailed);
-
- return priv;
-}
-
-void ass_renderer_done(ass_renderer_t* priv)
-{
- ass_font_cache_done();
- ass_bitmap_cache_done();
- ass_composite_cache_done();
- ass_glyph_cache_done();
- if (render_context.stroker) {
- FT_Stroker_Done(render_context.stroker);
- render_context.stroker = 0;
- }
- if (priv && priv->ftlibrary) FT_Done_FreeType(priv->ftlibrary);
- if (priv && priv->fontconfig_priv) fontconfig_done(priv->fontconfig_priv);
- if (priv && priv->synth_priv) ass_synth_done(priv->synth_priv);
- if (priv && priv->eimg) free(priv->eimg);
- if (priv) free(priv);
- if (text_info.glyphs) free(text_info.glyphs);
-}
-
-/**
- * \brief Create a new ass_image_t
- * Parameters are the same as ass_image_t fields.
- */
-static ass_image_t* my_draw_bitmap(unsigned char* bitmap, int bitmap_w, int bitmap_h, int stride, int dst_x, int dst_y, uint32_t color)
-{
- ass_image_t* img = calloc(1, sizeof(ass_image_t));
-
- img->w = bitmap_w;
- img->h = bitmap_h;
- img->stride = stride;
- img->bitmap = bitmap;
- img->color = color;
- img->dst_x = dst_x;
- img->dst_y = dst_y;
-
- return img;
-}
-
-/**
- * \brief convert bitmap glyph into ass_image_t struct(s)
- * \param bit freetype bitmap glyph, FT_PIXEL_MODE_GRAY
- * \param dst_x bitmap x coordinate in video frame
- * \param dst_y bitmap y coordinate in video frame
- * \param color first color, RGBA
- * \param color2 second color, RGBA
- * \param brk x coordinate relative to glyph origin, color is used to the left of brk, color2 - to the right
- * \param tail pointer to the last image's next field, head of the generated list should be stored here
- * \return pointer to the new list tail
- * Performs clipping. Uses my_draw_bitmap for actual bitmap convertion.
- */
-static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t color, uint32_t color2, int brk, ass_image_t** tail)
-{
- // brk is relative to dst_x
- // color = color left of brk
- // color2 = color right of brk
- int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap
- int clip_x0, clip_y0, clip_x1, clip_y1;
- int tmp;
- ass_image_t* img;
-
- dst_x += bm->left;
- dst_y += bm->top;
- brk -= bm->left;
-
- // clipping
- clip_x0 = render_context.clip_x0;
- clip_y0 = render_context.clip_y0;
- clip_x1 = render_context.clip_x1;
- clip_y1 = render_context.clip_y1;
- b_x0 = 0;
- b_y0 = 0;
- b_x1 = bm->w;
- b_y1 = bm->h;
-
- tmp = dst_x - clip_x0;
- if (tmp < 0) {
- mp_msg(MSGT_ASS, MSGL_DBG2, "clip left\n");
- b_x0 = - tmp;
- }
- tmp = dst_y - clip_y0;
- if (tmp < 0) {
- mp_msg(MSGT_ASS, MSGL_DBG2, "clip top\n");
- b_y0 = - tmp;
- }
- tmp = clip_x1 - dst_x - bm->w;
- if (tmp < 0) {
- mp_msg(MSGT_ASS, MSGL_DBG2, "clip right\n");
- b_x1 = bm->w + tmp;
- }
- tmp = clip_y1 - dst_y - bm->h;
- if (tmp < 0) {
- mp_msg(MSGT_ASS, MSGL_DBG2, "clip bottom\n");
- b_y1 = bm->h + tmp;
- }
-
- if ((b_y0 >= b_y1) || (b_x0 >= b_x1))
- return tail;
-
- if (brk > b_x0) { // draw left part
- if (brk > b_x1) brk = b_x1;
- img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0,
- brk - b_x0, b_y1 - b_y0, bm->w,
- dst_x + b_x0, dst_y + b_y0, color);
- *tail = img;
- tail = &img->next;
- }
- if (brk < b_x1) { // draw right part
- if (brk < b_x0) brk = b_x0;
- img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk,
- b_x1 - brk, b_y1 - b_y0, bm->w,
- dst_x + brk, dst_y + b_y0, color2);
- *tail = img;
- tail = &img->next;
- }
- return tail;
-}
-
-/**
- * \brief Calculate overlapping area of two consecutive bitmaps and in case they
- * overlap, composite them together
- * Mainly useful for translucent glyphs and especially borders, to avoid the
- * luminance adding up where they overlap (which looks ugly)
- */
-static void render_overlap(ass_image_t** last_tail, ass_image_t** tail, bitmap_hash_key_t *last_hash, bitmap_hash_key_t* hash) {
- int left, top, bottom, right;
- int old_left, old_top, w, h, cur_left, cur_top;
- int x, y, opos, cpos;
- char m;
- composite_hash_key_t hk;
- composite_hash_val_t *hv;
- composite_hash_key_t *nhk;
- int ax = (*last_tail)->dst_x;
- int ay = (*last_tail)->dst_y;
- int aw = (*last_tail)->w;
- int as = (*last_tail)->stride;
- int ah = (*last_tail)->h;
- int bx = (*tail)->dst_x;
- int by = (*tail)->dst_y;
- int bw = (*tail)->w;
- int bs = (*tail)->stride;
- int bh = (*tail)->h;
- unsigned char* a;
- unsigned char* b;
-
- if ((*last_tail)->bitmap == (*tail)->bitmap)
- return;
-
- if ((*last_tail)->color != (*tail)->color)
- return;
-
- // Calculate overlap coordinates
- left = (ax > bx) ? ax : bx;
- top = (ay > by) ? ay : by;
- right = ((ax+aw) < (bx+bw)) ? (ax+aw) : (bx+bw);
- bottom = ((ay+ah) < (by+bh)) ? (ay+ah) : (by+bh);
- if ((right <= left) || (bottom <= top))
- return;
- old_left = left-ax;
- old_top = top-ay;
- w = right-left;
- h = bottom-top;
- cur_left = left-bx;
- cur_top = top-by;
-
- // Query cache
- memset(&hk, 0, sizeof(hk));
- memcpy(&hk.a, last_hash, sizeof(*last_hash));
- memcpy(&hk.b, hash, sizeof(*hash));
- hk.aw = aw;
- hk.ah = ah;
- hk.bw = bw;
- hk.bh = bh;
- hk.ax = ax;
- hk.ay = ay;
- hk.bx = bx;
- hk.by = by;
- hv = cache_find_composite(&hk);
- if (hv) {
- (*last_tail)->bitmap = hv->a;
- (*tail)->bitmap = hv->b;
- return;
- }
-
- // Allocate new bitmaps and copy over data
- a = (*last_tail)->bitmap;
- b = (*tail)->bitmap;
- (*last_tail)->bitmap = malloc(as*ah);
- (*tail)->bitmap = malloc(bs*bh);
- memcpy((*last_tail)->bitmap, a, as*ah);
- memcpy((*tail)->bitmap, b, bs*bh);
-
- // Composite overlapping area
- for (y=0; y<h; y++)
- for (x=0; x<w; x++) {
- opos = (old_top+y)*(as) + (old_left+x);
- cpos = (cur_top+y)*(bs) + (cur_left+x);
- m = (a[opos] > b[cpos]) ? a[opos] : b[cpos];
- (*last_tail)->bitmap[opos] = 0;
- (*tail)->bitmap[cpos] = m;
- }
-
- // Insert bitmaps into the cache
- nhk = calloc(1, sizeof(*nhk));
- memcpy(nhk, &hk, sizeof(*nhk));
- hv = calloc(1, sizeof(*hv));
- hv->a = (*last_tail)->bitmap;
- hv->b = (*tail)->bitmap;
- cache_add_composite(nhk, hv);
-}
-
-/**
- * \brief Convert text_info_t struct to ass_image_t list
- * Splits glyphs in halves when needed (for \kf karaoke).
- */
-static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
-{
- int pen_x, pen_y;
- int i;
- bitmap_t* bm;
- ass_image_t* head;
- ass_image_t** tail = &head;
- ass_image_t** last_tail = 0;
- ass_image_t** here_tail = 0;
- bitmap_hash_key_t* last_hash = 0;
-
- for (i = 0; i < text_info->length; ++i) {
- glyph_info_t* info = text_info->glyphs + i;
- if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0))
- continue;
-
- pen_x = dst_x + info->pos.x + ROUND(info->shadow * frame_context.border_scale);
- pen_y = dst_y + info->pos.y + ROUND(info->shadow * frame_context.border_scale);
- bm = info->bm_s;
-
- here_tail = tail;
- tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail);
- if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0))
- render_overlap(last_tail, here_tail, last_hash, &info->hash_key);
- last_tail = here_tail;
- last_hash = &info->hash_key;
- }
-
- last_tail = 0;
- for (i = 0; i < text_info->length; ++i) {
- glyph_info_t* info = text_info->glyphs + i;
- if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o)
- continue;
-
- pen_x = dst_x + info->pos.x;
- pen_y = dst_y + info->pos.y;
- bm = info->bm_o;
-
- if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) {
- // do nothing
- } else {
- here_tail = tail;
- tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail);
- if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0))
- render_overlap(last_tail, here_tail, last_hash, &info->hash_key);
- last_tail = here_tail;
- last_hash = &info->hash_key;
- }
- }
- for (i = 0; i < text_info->length; ++i) {
- glyph_info_t* info = text_info->glyphs + i;
- if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm)
- continue;
-
- pen_x = dst_x + info->pos.x;
- pen_y = dst_y + info->pos.y;
- bm = info->bm;
-
- if ((info->effect_type == EF_KARAOKE) || (info->effect_type == EF_KARAOKE_KO)) {
- if (info->effect_timing > info->bbox.xMax)
- tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail);
- else
- tail = render_glyph(bm, pen_x, pen_y, info->c[1], 0, 1000000, tail);
- } else if (info->effect_type == EF_KARAOKE_KF) {
- tail = render_glyph(bm, pen_x, pen_y, info->c[0], info->c[1], info->effect_timing, tail);
- } else
- tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail);
- }
-
- *tail = 0;
- return head;
-}
-
-/**
- * \brief Mapping between script and screen coordinates
- */
-static int x2scr(double x) {
- return x*frame_context.orig_width_nocrop / frame_context.track->PlayResX +
- FFMAX(global_settings->left_margin, 0);
-}
-static double x2scr_pos(double x) {
- return x*frame_context.orig_width / frame_context.track->PlayResX +
- global_settings->left_margin;
-}
-/**
- * \brief Mapping between script and screen coordinates
- */
-static double y2scr(double y) {
- return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
- FFMAX(global_settings->top_margin, 0);
-}
-static double y2scr_pos(double y) {
- return y * frame_context.orig_height / frame_context.track->PlayResY +
- global_settings->top_margin;
-}
-
-// the same for toptitles
-static int y2scr_top(double y) {
- if (global_settings->use_margins)
- return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY;
- else
- return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
- FFMAX(global_settings->top_margin, 0);
-}
-// the same for subtitles
-static int y2scr_sub(double y) {
- if (global_settings->use_margins)
- return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
- FFMAX(global_settings->top_margin, 0) +
- FFMAX(global_settings->bottom_margin, 0);
- else
- return y * frame_context.orig_height_nocrop / frame_context.track->PlayResY +
- FFMAX(global_settings->top_margin, 0);
-}
-
-static void compute_string_bbox( text_info_t* info, FT_BBox *abbox ) {
- FT_BBox bbox;
- int i;
-
- if (text_info.length > 0) {
- bbox.xMin = 32000;
- bbox.xMax = -32000;
- bbox.yMin = - d6_to_int(text_info.lines[0].asc) + text_info.glyphs[0].pos.y;
- bbox.yMax = d6_to_int(text_info.height - text_info.lines[0].asc) + text_info.glyphs[0].pos.y;
-
- for (i = 0; i < text_info.length; ++i) {
- int s = text_info.glyphs[i].pos.x;
- int e = s + d6_to_int(text_info.glyphs[i].advance.x);
- bbox.xMin = FFMIN(bbox.xMin, s);
- bbox.xMax = FFMAX(bbox.xMax, e);
- }
- } else
- bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
-
- /* return string bbox */
- *abbox = bbox;
-}
-
-
-/**
- * \brief Check if starting part of (*p) matches sample. If true, shift p to the first symbol after the matching part.
- */
-static inline int mystrcmp(char** p, const char* sample) {
- int len = strlen(sample);
- if (strncmp(*p, sample, len) == 0) {
- (*p) += len;
- return 1;
- } else
- return 0;
-}
-
-static void change_font_size(double sz)
-{
- double size = sz * frame_context.font_scale;
-
- if (size < 1)
- size = 1;
- else if (size > frame_context.height * 2)
- size = frame_context.height * 2;
-
- ass_font_set_size(render_context.font, size);
-
- render_context.font_size = sz;
-}
-
-/**
- * \brief Change current font, using setting from render_context.
- */
-static void update_font(void)
-{
- unsigned val;
- ass_renderer_t* priv = frame_context.ass_priv;
- ass_font_desc_t desc;
- desc.family = strdup(render_context.family);
- desc.treat_family_as_pattern = render_context.treat_family_as_pattern;
-
- val = render_context.bold;
- // 0 = normal, 1 = bold, >1 = exact weight
- if (val == 0) val = 80; // normal
- else if (val == 1) val = 200; // bold
- desc.bold = val;
-
- val = render_context.italic;
- if (val == 0) val = 0; // normal
- else if (val == 1) val = 110; //italic
- desc.italic = val;
-
- render_context.font = ass_font_new(priv->library, priv->ftlibrary, priv->fontconfig_priv, &desc);
- free(desc.family);
-
- if (render_context.font)
- change_font_size(render_context.font_size);
-}
-
-/**
- * \brief Change border width
- * negative value resets border to style value
- */
-static void change_border(double border)
-{
- int b;
- if (!render_context.font) return;
-
- if (border < 0) {
- if (render_context.style->BorderStyle == 1)
- border = render_context.style->Outline;
- else
- border = 1.;
- }
- render_context.border = border;
-
- b = 64 * border * frame_context.border_scale;
- if (b > 0) {
- if (!render_context.stroker) {
- int error;
-#if (FREETYPE_MAJOR > 2) || ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR > 1))
- error = FT_Stroker_New( ass_renderer->ftlibrary, &render_context.stroker );
-#else // < 2.2
- error = FT_Stroker_New( render_context.font->faces[0]->memory, &render_context.stroker );
-#endif
- if (error) {
- mp_msg(MSGT_ASS, MSGL_V, "failed to get stroker\n");
- render_context.stroker = 0;
- }
- }
- if (render_context.stroker)
- FT_Stroker_Set( render_context.stroker, b,
- FT_STROKER_LINECAP_ROUND,
- FT_STROKER_LINEJOIN_ROUND,
- 0 );
- } else {
- FT_Stroker_Done(render_context.stroker);
- render_context.stroker = 0;
- }
-}
-
-#define _r(c) ((c)>>24)
-#define _g(c) (((c)>>16)&0xFF)
-#define _b(c) (((c)>>8)&0xFF)
-#define _a(c) ((c)&0xFF)
-
-/**
- * \brief Calculate a weighted average of two colors
- * calculates c1*(1-a) + c2*a, but separately for each component except alpha
- */
-static void change_color(uint32_t* var, uint32_t new, double pwr)
-{
- (*var)= ((uint32_t)(_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) +
- ((uint32_t)(_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) +
- ((uint32_t)(_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) +
- _a(*var);
-}
-
-// like change_color, but for alpha component only
-static void change_alpha(uint32_t* var, uint32_t new, double pwr)
-{
- *var = (_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) + (_a(*var) * (1 - pwr) + _a(new) * pwr);
-}
-
-/**
- * \brief Multiply two alpha values
- * \param a first value
- * \param b second value
- * \return result of multiplication
- * Parameters and result are limited by 0xFF.
- */
-static uint32_t mult_alpha(uint32_t a, uint32_t b)
-{
- return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF;
-}
-
-/**
- * \brief Calculate alpha value by piecewise linear function
- * Used for \fad, \fade implementation.
- */
-static unsigned interpolate_alpha(long long now,
- long long t1, long long t2, long long t3, long long t4,
- unsigned a1, unsigned a2, unsigned a3)
-{
- unsigned a;
- double cf;
- if (now <= t1) {
- a = a1;
- } else if (now >= t4) {
- a = a3;
- } else if (now < t2) { // and > t1
- cf = ((double)(now - t1)) / (t2 - t1);
- a = a1 * (1 - cf) + a2 * cf;
- } else if (now > t3) {
- cf = ((double)(now - t3)) / (t4 - t3);
- a = a2 * (1 - cf) + a3 * cf;
- } else { // t2 <= now <= t3
- a = a2;
- }
-
- return a;
-}
-
-static void reset_render_context(void);
-
-/**
- * \brief Parse style override tag.
- * \param p string to parse
- * \param pwr multiplier for some tag effects (comes from \t tags)
- */
-static char* parse_tag(char* p, double pwr) {
-#define skip_to(x) while ((*p != (x)) && (*p != '}') && (*p != 0)) { ++p;}
-#define skip(x) if (*p == (x)) ++p; else { return p; }
-
- skip_to('\\');
- skip('\\');
- if ((*p == '}') || (*p == 0))
- return p;
-
- // New tags introduced in vsfilter 2.39
- if (mystrcmp(&p, "xbord")) {
- double val;
- if (mystrtod(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\xbord%.2f\n", val);
- } else if (mystrcmp(&p, "ybord")) {
- double val;
- if (mystrtod(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\ybord%.2f\n", val);
- } else if (mystrcmp(&p, "xshad")) {
- int val;
- if (mystrtoi(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\xshad%d\n", val);
- } else if (mystrcmp(&p, "yshad")) {
- int val;
- if (mystrtoi(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\yshad%d\n", val);
- } else if (mystrcmp(&p, "fax")) {
- int val;
- if (mystrtoi(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\fax%d\n", val);
- } else if (mystrcmp(&p, "fay")) {
- int val;
- if (mystrtoi(&p, &val))
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\fay%d\n", val);
- } else if (mystrcmp(&p, "iclip")) {
- int x0, y0, x1, y1;
- int res = 1;
- skip('(');
- res &= mystrtoi(&p, &x0);
- skip(',');
- res &= mystrtoi(&p, &y0);
- skip(',');
- res &= mystrtoi(&p, &x1);
- skip(',');
- res &= mystrtoi(&p, &y1);
- skip(')');
- mp_msg(MSGT_ASS, MSGL_V, "stub: \\iclip(%d,%d,%d,%d)\n", x0, y0, x1, y1);
- } else if (mystrcmp(&p, "blur")) {
- double val;
- if (mystrtod(&p, &val)) {
- val = (val < 0) ? 0 : val;
- val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val;
- render_context.blur = val;
- } else
- render_context.blur = 0.0;
- // ASS standard tags
- } else if (mystrcmp(&p, "fsc")) {
- char tp = *p++;
- double val;
- if (tp == 'x') {
- if (mystrtod(&p, &val)) {
- val /= 100;
- render_context.scale_x = render_context.scale_x * ( 1 - pwr) + val * pwr;
- } else
- render_context.scale_x = render_context.style->ScaleX;
- } else if (tp == 'y') {
- if (mystrtod(&p, &val)) {
- val /= 100;
- render_context.scale_y = render_context.scale_y * ( 1 - pwr) + val * pwr;
- } else
- render_context.scale_y = render_context.style->ScaleY;
- }
- } else if (mystrcmp(&p, "fsp")) {
- double val;
- if (mystrtod(&p, &val))
- render_context.hspacing = render_context.hspacing * ( 1 - pwr ) + val * pwr;
- else
- render_context.hspacing = render_context.style->Spacing;
- } else if (mystrcmp(&p, "fs")) {
- double val;
- if (mystrtod(&p, &val))
- val = render_context.font_size * ( 1 - pwr ) + val * pwr;
- else
- val = render_context.style->FontSize;
- if (render_context.font)
- change_font_size(val);
- } else if (mystrcmp(&p, "bord")) {
- double val;
- if (mystrtod(&p, &val))
- val = render_context.border * ( 1 - pwr ) + val * pwr;
- else
- val = -1.; // reset to default
- change_border(val);
- } else if (mystrcmp(&p, "move")) {
- double x1, x2, y1, y2;
- long long t1, t2, delta_t, t;
- double x, y;
- double k;
- skip('(');
- mystrtod(&p, &x1);
- skip(',');
- mystrtod(&p, &y1);
- skip(',');
- mystrtod(&p, &x2);
- skip(',');
- mystrtod(&p, &y2);
- if (*p == ',') {
- skip(',');
- mystrtoll(&p, &t1);
- skip(',');
- mystrtoll(&p, &t2);
- mp_msg(MSGT_ASS, MSGL_DBG2, "movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %" PRId64 ")\n",
- x1, y1, x2, y2, (int64_t)t1, (int64_t)t2);
- } else {
- t1 = 0;
- t2 = render_context.event->Duration;
- mp_msg(MSGT_ASS, MSGL_DBG2, "movement: (%f, %f) -> (%f, %f)\n", x1, y1, x2, y2);
- }
- skip(')');
- delta_t = t2 - t1;
- t = frame_context.time - render_context.event->Start;
- if (t < t1)
- k = 0.;
- else if (t > t2)
- k = 1.;
- else k = ((double)(t - t1)) / delta_t;
- x = k * (x2 - x1) + x1;
- y = k * (y2 - y1) + y1;
- if (render_context.evt_type != EVENT_POSITIONED) {
- render_context.pos_x = x;
- render_context.pos_y = y;
- render_context.detect_collisions = 0;
- render_context.evt_type = EVENT_POSITIONED;
- }
- } else if (mystrcmp(&p, "frx")) {
- double val;
- if (mystrtod(&p, &val)) {
- val *= M_PI / 180;
- render_context.frx = val * pwr + render_context.frx * (1-pwr);
- } else
- render_context.frx = 0.;
- } else if (mystrcmp(&p, "fry")) {
- double val;
- if (mystrtod(&p, &val)) {
- val *= M_PI / 180;
- render_context.fry = val * pwr + render_context.fry * (1-pwr);
- } else
- render_context.fry = 0.;
- } else if (mystrcmp(&p, "frz") || mystrcmp(&p, "fr")) {
- double val;
- if (mystrtod(&p, &val)) {
- val *= M_PI / 180;
- render_context.frz = val * pwr + render_context.frz * (1-pwr);
- } else
- render_context.frz = M_PI * render_context.style->Angle / 180.;
- } else if (mystrcmp(&p, "fn")) {
- char* start = p;
- char* family;
- skip_to('\\');
- if (p > start) {
- family = malloc(p - start + 1);
- strncpy(family, start, p - start);
- family[p - start] = '\0';
- } else
- family = strdup(render_context.style->FontName);
- if (render_context.family)
- free(render_context.family);
- render_context.family = family;
- update_font();
- } else if (mystrcmp(&p, "alpha")) {
- uint32_t val;
- int i;
- if (strtocolor(&p, &val)) {
- unsigned char a = val >> 24;
- for (i = 0; i < 4; ++i)
- change_alpha(&render_context.c[i], a, pwr);
- } else {
- change_alpha(&render_context.c[0], render_context.style->PrimaryColour, pwr);
- change_alpha(&render_context.c[1], render_context.style->SecondaryColour, pwr);
- change_alpha(&render_context.c[2], render_context.style->OutlineColour, pwr);
- change_alpha(&render_context.c[3], render_context.style->BackColour, pwr);
- }
- // FIXME: simplify
- } else if (mystrcmp(&p, "an")) {
- int val;
- if (mystrtoi(&p, &val) && val) {
- int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment
- mp_msg(MSGT_ASS, MSGL_DBG2, "an %d\n", val);
- if (v != 0) v = 3 - v;
- val = ((val - 1) % 3) + 1; // horizontal alignment
- val += v*4;
- mp_msg(MSGT_ASS, MSGL_DBG2, "align %d\n", val);
- render_context.alignment = val;
- } else
- render_context.alignment = render_context.style->Alignment;
- } else if (mystrcmp(&p, "a")) {
- int val;
- if (mystrtoi(&p, &val) && val)
- render_context.alignment = val;
- else
- render_context.alignment = render_context.style->Alignment;
- } else if (mystrcmp(&p, "pos")) {
- double v1, v2;
- skip('(');
- mystrtod(&p, &v1);
- skip(',');
- mystrtod(&p, &v2);
- skip(')');
- mp_msg(MSGT_ASS, MSGL_DBG2, "pos(%f, %f)\n", v1, v2);
- if (render_context.evt_type == EVENT_POSITIONED) {
- mp_msg(MSGT_ASS, MSGL_V, "Subtitle has a new \\pos "
- "after \\move or \\pos, ignoring\n");
- } else {
- render_context.evt_type = EVENT_POSITIONED;
- render_context.detect_collisions = 0;
- render_context.pos_x = v1;
- render_context.pos_y = v2;
- }
- } else if (mystrcmp(&p, "fad")) {
- int a1, a2, a3;
- long long t1, t2, t3, t4;
- if (*p == 'e') ++p; // either \fad or \fade
- skip('(');
- mystrtoi(&p, &a1);
- skip(',');
- mystrtoi(&p, &a2);
- if (*p == ')') {
- // 2-argument version (\fad, according to specs)
- // a1 and a2 are fade-in and fade-out durations
- t1 = 0;
- t4 = render_context.event->Duration;
- t2 = a1;
- t3 = t4 - a2;
- a1 = 0xFF;
- a2 = 0;
- a3 = 0xFF;
- } else {
- // 6-argument version (\fade)
- // a1 and a2 (and a3) are opacity values
- skip(',');
- mystrtoi(&p, &a3);
- skip(',');
- mystrtoll(&p, &t1);
- skip(',');
- mystrtoll(&p, &t2);
- skip(',');
- mystrtoll(&p, &t3);
- skip(',');
- mystrtoll(&p, &t4);
- }
- skip(')');
- render_context.fade = interpolate_alpha(frame_context.time - render_context.event->Start, t1, t2, t3, t4, a1, a2, a3);
- } else if (mystrcmp(&p, "org")) {
- int v1, v2;
- skip('(');
- mystrtoi(&p, &v1);
- skip(',');
- mystrtoi(&p, &v2);
- skip(')');
- mp_msg(MSGT_ASS, MSGL_DBG2, "org(%d, %d)\n", v1, v2);
- // render_context.evt_type = EVENT_POSITIONED;
- if (!render_context.have_origin) {
- render_context.org_x = v1;
- render_context.org_y = v2;
- render_context.have_origin = 1;
- render_context.detect_collisions = 0;
- }
- } else if (mystrcmp(&p, "t")) {
- double v[3];
- int v1, v2;
- double v3;
- int cnt;
- long long t1, t2, t, delta_t;
- double k;
- skip('(');
- for (cnt = 0; cnt < 3; ++cnt) {
- if (*p == '\\')
- break;
- v[cnt] = strtod(p, &p);
- skip(',');
- }
- if (cnt == 3) {
- v1 = v[0]; v2 = v[1]; v3 = v[2];
- } else if (cnt == 2) {
- v1 = v[0]; v2 = v[1]; v3 = 1.;
- } else if (cnt == 1) {
- v1 = 0; v2 = render_context.event->Duration; v3 = v[0];
- } else { // cnt == 0
- v1 = 0; v2 = render_context.event->Duration; v3 = 1.;
- }
- render_context.detect_collisions = 0;
- t1 = v1;
- t2 = v2;
- delta_t = v2 - v1;
- if (v3 < 0.)
- v3 = 0.;
- t = frame_context.time - render_context.event->Start; // FIXME: move to render_context
- if (t <= t1)
- k = 0.;
- else if (t >= t2)
- k = 1.;
- else {
- assert(delta_t != 0.);
- k = pow(((double)(t - t1)) / delta_t, v3);
- }
- while (*p == '\\')
- p = parse_tag(p, k); // maybe k*pwr ? no, specs forbid nested \t's
- skip_to(')'); // in case there is some unknown tag or a comment
- skip(')');
- } else if (mystrcmp(&p, "clip")) {
- int x0, y0, x1, y1;
- int res = 1;
- skip('(');
- res &= mystrtoi(&p, &x0);
- skip(',');
- res &= mystrtoi(&p, &y0);
- skip(',');
- res &= mystrtoi(&p, &x1);
- skip(',');
- res &= mystrtoi(&p, &y1);
- skip(')');
- if (res) {
- render_context.clip_x0 = render_context.clip_x0 * (1-pwr) + x0 * pwr;
- render_context.clip_x1 = render_context.clip_x1 * (1-pwr) + x1 * pwr;
- render_context.clip_y0 = render_context.clip_y0 * (1-pwr) + y0 * pwr;
- render_context.clip_y1 = render_context.clip_y1 * (1-pwr) + y1 * pwr;
- } else {
- render_context.clip_x0 = 0;
- render_context.clip_y0 = 0;
- render_context.clip_x1 = frame_context.track->PlayResX;
- render_context.clip_y1 = frame_context.track->PlayResY;
- }
- } else if (mystrcmp(&p, "c")) {
- uint32_t val;
- if (!strtocolor(&p, &val))
- val = render_context.style->PrimaryColour;
- mp_msg(MSGT_ASS, MSGL_DBG2, "color: %X\n", val);
- change_color(&render_context.c[0], val, pwr);
- } else if ((*p >= '1') && (*p <= '4') && (++p) && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) {
- char n = *(p-2);
- int cidx = n - '1';
- char cmd = *(p-1);
- uint32_t val;
- assert((n >= '1') && (n <= '4'));
- if (!strtocolor(&p, &val))
- switch(n) {
- case '1': val = render_context.style->PrimaryColour; break;
- case '2': val = render_context.style->SecondaryColour; break;
- case '3': val = render_context.style->OutlineColour; break;
- case '4': val = render_context.style->BackColour; break;
- default : val = 0; break; // impossible due to assert; avoid compilation warning
- }
- switch (cmd) {
- case 'c': change_color(render_context.c + cidx, val, pwr); break;
- case 'a': change_alpha(render_context.c + cidx, val >> 24, pwr); break;
- default: mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BadCommand, n, cmd); break;
- }
- mp_msg(MSGT_ASS, MSGL_DBG2, "single c/a at %f: %c%c = %X \n", pwr, n, cmd, render_context.c[cidx]);
- } else if (mystrcmp(&p, "r")) {
- reset_render_context();
- } else if (mystrcmp(&p, "be")) {
- int val;
- if (mystrtoi(&p, &val)) {
- // Clamp to a safe upper limit, since high values need excessive CPU
- val = (val < 0) ? 0 : val;
- val = (val > MAX_BE) ? MAX_BE : val;
- render_context.be = val;
- } else
- render_context.be = 0;
- } else if (mystrcmp(&p, "b")) {
- int b;
- if (mystrtoi(&p, &b)) {
- if (pwr >= .5)
- render_context.bold = b;
- } else
- render_context.bold = render_context.style->Bold;
- update_font();
- } else if (mystrcmp(&p, "i")) {
- int i;
- if (mystrtoi(&p, &i)) {
- if (pwr >= .5)
- render_context.italic = i;
- } else
- render_context.italic = render_context.style->Italic;
- update_font();
- } else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) {
- int val = 0;
- mystrtoi(&p, &val);
- render_context.effect_type = EF_KARAOKE_KF;
- if (render_context.effect_timing)
- render_context.effect_skip_timing += render_context.effect_timing;
- render_context.effect_timing = val * 10;
- } else if (mystrcmp(&p, "ko")) {
- int val = 0;
- mystrtoi(&p, &val);
- render_context.effect_type = EF_KARAOKE_KO;
- if (render_context.effect_timing)
- render_context.effect_skip_timing += render_context.effect_timing;
- render_context.effect_timing = val * 10;
- } else if (mystrcmp(&p, "k")) {
- int val = 0;
- mystrtoi(&p, &val);
- render_context.effect_type = EF_KARAOKE;
- if (render_context.effect_timing)
- render_context.effect_skip_timing += render_context.effect_timing;
- render_context.effect_timing = val * 10;
- } else if (mystrcmp(&p, "shad")) {
- int val;
- if (mystrtoi(&p, &val))
- render_context.shadow = val;
- else
- render_context.shadow = render_context.style->Shadow;
- } else if (mystrcmp(&p, "pbo")) {
- int val = 0;
- mystrtoi(&p, &val); // ignored
- } else if (mystrcmp(&p, "p")) {
- int val;
- if (!mystrtoi(&p, &val))
- val = 0;
- render_context.drawing_mode = !!val;
- }
-
- return p;
-
-#undef skip
-#undef skip_to
-}
-
-/**
- * \brief Get next ucs4 char from string, parsing and executing style overrides
- * \param str string pointer
- * \return ucs4 code of the next char
- * On return str points to the unparsed part of the string
- */
-static unsigned get_next_char(char** str)
-{
- char* p = *str;
- unsigned chr;
- if (*p == '{') { // '\0' goes here
- p++;
- while (1) {
- p = parse_tag(p, 1.);
- if (*p == '}') { // end of tag
- p++;
- if (*p == '{') {
- p++;
- continue;
- } else
- break;
- } else if (*p != '\\')
- mp_msg(MSGT_ASS, MSGL_V, "Unable to parse: \"%s\" \n", p);
- if (*p == 0)
- break;
- }
- }
- if (*p == '\t') {
- ++p;
- *str = p;
- return ' ';
- }
- if (*p == '\\') {
- if ((*(p+1) == 'N') || ((*(p+1) == 'n') && (frame_context.track->WrapStyle == 2))) {
- p += 2;
- *str = p;
- return '\n';
- } else if ((*(p+1) == 'n') || (*(p+1) == 'h')) {
- p += 2;
- *str = p;
- return ' ';
- }
- }
- chr = utf8_get_char((const char **)&p);
- *str = p;
- return chr;
-}
-
-static void apply_transition_effects(ass_event_t* event)
-{
- int v[4];
- int cnt;
- char* p = event->Effect;
-
- if (!p || !*p) return;
-
- cnt = 0;
- while (cnt < 4 && (p = strchr(p, ';'))) {
- v[cnt++] = atoi(++p);
- }
-
- if (strncmp(event->Effect, "Banner;", 7) == 0) {
- int delay;
- if (cnt < 1) {
- mp_msg(MSGT_ASS, MSGL_V, "Error parsing effect: %s \n", event->Effect);
- return;
- }
- if (cnt >= 2 && v[1] == 0) // right-to-left
- render_context.scroll_direction = SCROLL_RL;
- else // left-to-right
- render_context.scroll_direction = SCROLL_LR;
-
- delay = v[0];
- if (delay == 0) delay = 1; // ?
- render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay;
- render_context.evt_type = EVENT_HSCROLL;
- return;
- }
-
- if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
- render_context.scroll_direction = SCROLL_BT;
- } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
- render_context.scroll_direction = SCROLL_TB;
- } else {
- mp_msg(MSGT_ASS, MSGL_V, "Unknown transition effect: %s \n", event->Effect);
- return;
- }
- // parse scroll up/down parameters
- {
- int delay;
- int y0, y1;
- if (cnt < 3) {
- mp_msg(MSGT_ASS, MSGL_V, "Error parsing effect: %s \n", event->Effect);
- return;
- }
- delay = v[2];
- if (delay == 0) delay = 1; // ?
- render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay;
- if (v[0] < v[1]) {
- y0 = v[0]; y1 = v[1];
- } else {
- y0 = v[1]; y1 = v[0];
- }
- if (y1 == 0)
- y1 = frame_context.track->PlayResY; // y0=y1=0 means fullscreen scrolling
- render_context.clip_y0 = y0;
- render_context.clip_y1 = y1;
- render_context.evt_type = EVENT_VSCROLL;
- render_context.detect_collisions = 0;
- }
-
-}
-
-/**
- * \brief partially reset render_context to style values
- * Works like {\r}: resets some style overrides
- */
-static void reset_render_context(void)
-{
- render_context.c[0] = render_context.style->PrimaryColour;
- render_context.c[1] = render_context.style->SecondaryColour;
- render_context.c[2] = render_context.style->OutlineColour;
- render_context.c[3] = render_context.style->BackColour;
- render_context.font_size = render_context.style->FontSize;
-
- if (render_context.family)
- free(render_context.family);
- render_context.family = strdup(render_context.style->FontName);
- render_context.treat_family_as_pattern = render_context.style->treat_fontname_as_pattern;
- render_context.bold = render_context.style->Bold;
- render_context.italic = render_context.style->Italic;
- update_font();
-
- change_border(-1.);
- render_context.scale_x = render_context.style->ScaleX;
- render_context.scale_y = render_context.style->ScaleY;
- render_context.hspacing = render_context.style->Spacing;
- render_context.be = 0;
- render_context.blur = 0.0;
- render_context.shadow = render_context.style->Shadow;
- render_context.frx = render_context.fry = 0.;
- render_context.frz = M_PI * render_context.style->Angle / 180.;
-
- // FIXME: does not reset unsupported attributes.
-}
-
-/**
- * \brief Start new event. Reset render_context.
- */
-static void init_render_context(ass_event_t* event)
-{
- render_context.event = event;
- render_context.style = frame_context.track->styles + event->Style;
-
- reset_render_context();
-
- render_context.evt_type = EVENT_NORMAL;
- render_context.alignment = render_context.style->Alignment;
- render_context.pos_x = 0;
- render_context.pos_y = 0;
- render_context.org_x = 0;
- render_context.org_y = 0;
- render_context.have_origin = 0;
- render_context.clip_x0 = 0;
- render_context.clip_y0 = 0;
- render_context.clip_x1 = frame_context.track->PlayResX;
- render_context.clip_y1 = frame_context.track->PlayResY;
- render_context.detect_collisions = 1;
- render_context.fade = 0;
- render_context.drawing_mode = 0;
- render_context.effect_type = EF_NONE;
- render_context.effect_timing = 0;
- render_context.effect_skip_timing = 0;
-
- apply_transition_effects(event);
-}
-
-static void free_render_context(void)
-{
-}
-
-/**
- * \brief Get normal and outline (border) glyphs
- * \param symbol ucs4 char
- * \param info out: struct filled with extracted data
- * \param advance subpixel shift vector used for cache lookup
- * Tries to get both glyphs from cache.
- * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker,
- * and add them to cache.
- * The glyphs are returned in info->glyph and info->outline_glyph
- */
-static void get_outline_glyph(int symbol, glyph_info_t* info, FT_Vector* advance)
-{
- int error;
- glyph_hash_val_t* val;
- glyph_hash_key_t key;
- memset(&key, 0, sizeof(key));
- key.font = render_context.font;
- key.size = render_context.font_size;
- key.ch = symbol;
- key.scale_x = (render_context.scale_x * 0xFFFF);
- key.scale_y = (render_context.scale_y * 0xFFFF);
- key.advance = *advance;
- key.bold = render_context.bold;
- key.italic = render_context.italic;
- key.outline = render_context.border * 0xFFFF;
-
- memset(info, 0, sizeof(glyph_info_t));
-
- val = cache_find_glyph(&key);
- if (val) {
- FT_Glyph_Copy(val->glyph, &info->glyph);
- if (val->outline_glyph)
- FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph);
- info->bbox = val->bbox_scaled;
- info->advance.x = val->advance.x;
- info->advance.y = val->advance.y;
- } else {
- glyph_hash_val_t v;
- info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol, global_settings->hinting);
- if (!info->glyph)
- return;
- info->advance.x = d16_to_d6(info->glyph->advance.x);
- info->advance.y = d16_to_d6(info->glyph->advance.y);
- FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox);
-
- if (render_context.stroker) {
- info->outline_glyph = info->glyph;
- error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_context.stroker, 0 , 0 ); // don't destroy original
- if (error) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error);
- }
- }
-
- memset(&v, 0, sizeof(v));
- FT_Glyph_Copy(info->glyph, &v.glyph);
- if (info->outline_glyph)
- FT_Glyph_Copy(info->outline_glyph, &v.outline_glyph);
- v.advance = info->advance;
- v.bbox_scaled = info->bbox;
- cache_add_glyph(&key, &v);
- }
-}
-
-static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz);
-
-/**
- * \brief Get bitmaps for a glyph
- * \param info glyph info
- * Tries to get glyph bitmaps from bitmap cache.
- * If they can't be found, they are generated by rotating and rendering the glyph.
- * After that, bitmaps are added to the cache.
- * They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow).
- */
-static void get_bitmap_glyph(glyph_info_t* info)
-{
- bitmap_hash_val_t* val;
- bitmap_hash_key_t* key = &info->hash_key;
-
- val = cache_find_bitmap(key);
-/* val = 0; */
-
- if (val) {
- info->bm = val->bm;
- info->bm_o = val->bm_o;
- info->bm_s = val->bm_s;
- } else {
- FT_Vector shift;
- bitmap_hash_val_t hash_val;
- int error;
- info->bm = info->bm_o = info->bm_s = 0;
- if (info->glyph && info->symbol != '\n' && info->symbol != 0) {
- // calculating rotation shift vector (from rotation origin to the glyph basepoint)
- shift.x = int_to_d6(info->hash_key.shift_x);
- shift.y = int_to_d6(info->hash_key.shift_y);
- // apply rotation
- transform_3d(shift, &info->glyph, &info->outline_glyph, info->frx, info->fry, info->frz);
-
- // render glyph
- error = glyph_to_bitmap(ass_renderer->synth_priv,
- info->glyph, info->outline_glyph,
- &info->bm, &info->bm_o,
- &info->bm_s, info->be, info->blur * frame_context.border_scale);
- if (error)
- info->symbol = 0;
-
- // add bitmaps to cache
- hash_val.bm_o = info->bm_o;
- hash_val.bm = info->bm;
- hash_val.bm_s = info->bm_s;
- cache_add_bitmap(&(info->hash_key), &hash_val);
- }
- }
- // deallocate glyphs
- if (info->glyph)
- FT_Done_Glyph(info->glyph);
- if (info->outline_glyph)
- FT_Done_Glyph(info->outline_glyph);
-}
-
-/**
- * This function goes through text_info and calculates text parameters.
- * The following text_info fields are filled:
- * height
- * lines[].height
- * lines[].asc
- * lines[].desc
- */
-static void measure_text(void)
-{
- int cur_line = 0, max_asc = 0, max_desc = 0;
- int i;
- text_info.height = 0;
- for (i = 0; i < text_info.length + 1; ++i) {
- if ((i == text_info.length) || text_info.glyphs[i].linebreak) {
- text_info.lines[cur_line].asc = max_asc;
- text_info.lines[cur_line].desc = max_desc;
- text_info.height += max_asc + max_desc;
- cur_line ++;
- max_asc = max_desc = 0;
- }
- if (i < text_info.length) {
- glyph_info_t* cur = text_info.glyphs + i;
- if (cur->asc > max_asc)
- max_asc = cur->asc;
- if (cur->desc > max_desc)
- max_desc = cur->desc;
- }
- }
- text_info.height += (text_info.n_lines - 1) * double_to_d6(global_settings->line_spacing);
-}
-
-/**
- * \brief rearrange text between lines
- * \param max_text_width maximal text line width in pixels
- * The algo is similar to the one in libvo/sub.c:
- * 1. Place text, wrapping it when current line is full
- * 2. Try moving words from the end of a line to the beginning of the next one while it reduces
- * the difference in lengths between this two lines.
- * The result may not be optimal, but usually is good enough.
- */
-static void wrap_lines_smart(int max_text_width)
-{
- int i, j;
- glyph_info_t *cur, *s1, *e1, *s2, *s3, *w;
- int last_space;
- int break_type;
- int exit;
- int pen_shift_x;
- int pen_shift_y;
- int cur_line;
-
- last_space = -1;
- text_info.n_lines = 1;
- break_type = 0;
- s1 = text_info.glyphs; // current line start
- for (i = 0; i < text_info.length; ++i) {
- int break_at, s_offset, len;
- cur = text_info.glyphs + i;
- break_at = -1;
- s_offset = s1->bbox.xMin + s1->pos.x;
- len = (cur->bbox.xMax + cur->pos.x) - s_offset;
-
- if (cur->symbol == '\n') {
- break_type = 2;
- break_at = i;
- mp_msg(MSGT_ASS, MSGL_DBG2, "forced line break at %d\n", break_at);
- }
-
- if ((len >= max_text_width) && (frame_context.track->WrapStyle != 2)) {
- break_type = 1;
- break_at = last_space;
- if (break_at == -1)
- break_at = i - 1;
- if (break_at == -1)
- break_at = 0;
- mp_msg(MSGT_ASS, MSGL_DBG2, "overfill at %d\n", i);
- mp_msg(MSGT_ASS, MSGL_DBG2, "line break at %d\n", break_at);
- }
-
- if (break_at != -1) {
- // need to use one more line
- // marking break_at+1 as start of a new line
- int lead = break_at + 1; // the first symbol of the new line
- if (text_info.n_lines >= MAX_LINES) {
- // to many lines !
- // no more linebreaks
- for (j = lead; j < text_info.length; ++j)
- text_info.glyphs[j].linebreak = 0;
- break;
- }
- if (lead < text_info.length)
- text_info.glyphs[lead].linebreak = break_type;
- last_space = -1;
- s1 = text_info.glyphs + lead;
- s_offset = s1->bbox.xMin + s1->pos.x;
- text_info.n_lines ++;
- }
-
- if (cur->symbol == ' ')
- last_space = i;
-
- // make sure the hard linebreak is not forgotten when
- // there was a new soft linebreak just inserted
- if (cur->symbol == '\n' && break_type == 1)
- i--;
- }
-#define DIFF(x,y) (((x) < (y)) ? (y - x) : (x - y))
- exit = 0;
- while (!exit) {
- exit = 1;
- w = s3 = text_info.glyphs;
- s1 = s2 = 0;
- for (i = 0; i <= text_info.length; ++i) {
- cur = text_info.glyphs + i;
- if ((i == text_info.length) || cur->linebreak) {
- s1 = s2;
- s2 = s3;
- s3 = cur;
- if (s1 && (s2->linebreak == 1)) { // have at least 2 lines, and linebreak is 'soft'
- int l1, l2, l1_new, l2_new;
-
- w = s2;
- do { --w; } while ((w > s1) && (w->symbol == ' '));
- while ((w > s1) && (w->symbol != ' ')) { --w; }
- e1 = w;
- while ((e1 > s1) && (e1->symbol == ' ')) { --e1; }
- if (w->symbol == ' ') ++w;
-
- l1 = ((s2-1)->bbox.xMax + (s2-1)->pos.x) - (s1->bbox.xMin + s1->pos.x);
- l2 = ((s3-1)->bbox.xMax + (s3-1)->pos.x) - (s2->bbox.xMin + s2->pos.x);
- l1_new = (e1->bbox.xMax + e1->pos.x) - (s1->bbox.xMin + s1->pos.x);
- l2_new = ((s3-1)->bbox.xMax + (s3-1)->pos.x) - (w->bbox.xMin + w->pos.x);
-
- if (DIFF(l1_new, l2_new) < DIFF(l1, l2)) {
- w->linebreak = 1;
- s2->linebreak = 0;
- exit = 0;
- }
- }
- }
- if (i == text_info.length)
- break;
- }
-
- }
- assert(text_info.n_lines >= 1);
-#undef DIFF
-
- measure_text();
-
- pen_shift_x = 0;
- pen_shift_y = 0;
- cur_line = 1;
- for (i = 0; i < text_info.length; ++i) {
- cur = text_info.glyphs + i;
- if (cur->linebreak) {
- int height = text_info.lines[cur_line - 1].desc + text_info.lines[cur_line].asc;
- cur_line ++;
- pen_shift_x = - cur->pos.x;
- pen_shift_y += d6_to_int(height + double_to_d6(global_settings->line_spacing));
- mp_msg(MSGT_ASS, MSGL_DBG2, "shifting from %d to %d by (%d, %d)\n", i, text_info.length - 1, pen_shift_x, pen_shift_y);
- }
- cur->pos.x += pen_shift_x;
- cur->pos.y += pen_shift_y;
- }
-}
-
-/**
- * \brief determine karaoke effects
- * Karaoke effects cannot be calculated during parse stage (get_next_char()),
- * so they are done in a separate step.
- * Parse stage: when karaoke style override is found, its parameters are stored in the next glyph's
- * (the first glyph of the karaoke word)'s effect_type and effect_timing.
- * This function:
- * 1. sets effect_type for all glyphs in the word (_karaoke_ word)
- * 2. sets effect_timing for all glyphs to x coordinate of the border line between the left and right karaoke parts
- * (left part is filled with PrimaryColour, right one - with SecondaryColour).
- */
-static void process_karaoke_effects(void)
-{
- glyph_info_t *cur, *cur2;
- glyph_info_t *s1, *e1; // start and end of the current word
- glyph_info_t *s2; // start of the next word
- int i;
- int timing; // current timing
- int tm_start, tm_end; // timings at start and end of the current word
- int tm_current;
- double dt;
- int x;
- int x_start, x_end;
-
- tm_current = frame_context.time - render_context.event->Start;
- timing = 0;
- s1 = s2 = 0;
- for (i = 0; i <= text_info.length; ++i) {
- cur = text_info.glyphs + i;
- if ((i == text_info.length) || (cur->effect_type != EF_NONE)) {
- s1 = s2;
- s2 = cur;
- if (s1) {
- e1 = s2 - 1;
- tm_start = timing + s1->effect_skip_timing;
- tm_end = tm_start + s1->effect_timing;
- timing = tm_end;
- x_start = 1000000;
- x_end = -1000000;
- for (cur2 = s1; cur2 <= e1; ++cur2) {
- x_start = FFMIN(x_start, cur2->bbox.xMin + cur2->pos.x);
- x_end = FFMAX(x_end, cur2->bbox.xMax + cur2->pos.x);
- }
-
- dt = (tm_current - tm_start);
- if ((s1->effect_type == EF_KARAOKE) || (s1->effect_type == EF_KARAOKE_KO)) {
- if (dt > 0)
- x = x_end + 1;
- else
- x = x_start;
- } else if (s1->effect_type == EF_KARAOKE_KF) {
- dt /= (tm_end - tm_start);
- x = x_start + (x_end - x_start) * dt;
- } else {
- mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_UnknownEffectType_InternalError);
- continue;
- }
-
- for (cur2 = s1; cur2 <= e1; ++cur2) {
- cur2->effect_type = s1->effect_type;
- cur2->effect_timing = x - cur2->pos.x;
- }
- }
- }
- }
-}
-
-/**
- * \brief Calculate base point for positioning and rotation
- * \param bbox text bbox
- * \param alignment alignment
- * \param bx, by out: base point coordinates
- */
-static void get_base_point(FT_BBox bbox, int alignment, int* bx, int* by)
-{
- const int halign = alignment & 3;
- const int valign = alignment & 12;
- if (bx)
- switch(halign) {
- case HALIGN_LEFT:
- *bx = bbox.xMin;
- break;
- case HALIGN_CENTER:
- *bx = (bbox.xMax + bbox.xMin) / 2;
- break;
- case HALIGN_RIGHT:
- *bx = bbox.xMax;
- break;
- }
- if (by)
- switch(valign) {
- case VALIGN_TOP:
- *by = bbox.yMin;
- break;
- case VALIGN_CENTER:
- *by = (bbox.yMax + bbox.yMin) / 2;
- break;
- case VALIGN_SUB:
- *by = bbox.yMax;
- break;
- }
-}
-
-/**
- * \brief Apply transformation to outline points of a glyph
- * Applies rotations given by frx, fry and frz and projects the points back
- * onto the screen plane.
- */
-static void transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry, double frz) {
- double sx = sin(frx);
- double sy = sin(fry);
- double sz = sin(frz);
- double cx = cos(frx);
- double cy = cos(fry);
- double cz = cos(frz);
- FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline;
- FT_Vector* p = outline->points;
- double x, y, z, xx, yy, zz;
- int i;
-
- for (i=0; i<outline->n_points; i++) {
- x = p[i].x + shift.x;
- y = p[i].y + shift.y;
- z = 0.;
-
- xx = x*cz + y*sz;
- yy = -(x*sz - y*cz);
- zz = z;
-
- x = xx;
- y = yy*cx + zz*sx;
- z = yy*sx - zz*cx;
-
- xx = x*cy + z*sy;
- yy = y;
- zz = x*sy - z*cy;
-
- zz = FFMAX(zz, -19000);
-
- x = (xx * 20000) / (zz + 20000);
- y = (yy * 20000) / (zz + 20000);
- p[i].x = x - shift.x + 0.5;
- p[i].y = y - shift.y + 0.5;
- }
-}
-
-/**
- * \brief Apply 3d transformation to several objects
- * \param shift FreeType vector
- * \param glyph FreeType glyph
- * \param glyph2 FreeType glyph
- * \param frx x-axis rotation angle
- * \param fry y-axis rotation angle
- * \param frz z-axis rotation angle
- * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it.
- */
-static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz)
-{
- frx = - frx;
- frz = - frz;
- if (frx != 0. || fry != 0. || frz != 0.) {
- if (glyph && *glyph)
- transform_3d_points(shift, *glyph, frx, fry, frz);
-
- if (glyph2 && *glyph2)
- transform_3d_points(shift, *glyph2, frx, fry, frz);
- }
-}
-
-
-/**
- * \brief Main ass rendering function, glues everything together
- * \param event event to render
- * \param event_images struct containing resulting images, will also be initialized
- * Process event, appending resulting ass_image_t's to images_root.
- */
-static int ass_render_event(ass_event_t* event, event_images_t* event_images)
-{
- char* p;
- FT_UInt previous;
- FT_UInt num_glyphs;
- FT_Vector pen;
- unsigned code;
- FT_BBox bbox;
- int i, j;
- FT_Vector shift;
- int MarginL, MarginR, MarginV;
- int last_break;
- int alignment, halign, valign;
- int device_x = 0, device_y = 0;
-
- if (event->Style >= frame_context.track->n_styles) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_NoStyleFound);
- return 1;
- }
- if (!event->Text) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_EmptyEvent);
- return 1;
- }
-
- init_render_context(event);
-
- text_info.length = 0;
- pen.x = 0;
- pen.y = 0;
- previous = 0;
- num_glyphs = 0;
- p = event->Text;
- // Event parsing.
- while (1) {
- // get next char, executing style override
- // this affects render_context
- do {
- code = get_next_char(&p);
- } while (code && render_context.drawing_mode); // skip everything in drawing mode
-
- // face could have been changed in get_next_char
- if (!render_context.font) {
- free_render_context();
- return 1;
- }
-
- if (code == 0)
- break;
-
- if (text_info.length >= MAX_GLYPHS) {
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_MAX_GLYPHS_Reached,
- (int)(event - frame_context.track->events), event->Start, event->Duration, event->Text);
- break;
- }
-
- if ( previous && code ) {
- FT_Vector delta;
- delta = ass_font_get_kerning(render_context.font, previous, code);
- pen.x += delta.x * render_context.scale_x;
- pen.y += delta.y * render_context.scale_y;
- }
-
- shift.x = pen.x & SUBPIXEL_MASK;
- shift.y = pen.y & SUBPIXEL_MASK;
-
- if (render_context.evt_type == EVENT_POSITIONED) {
- shift.x += double_to_d6(x2scr_pos(render_context.pos_x)) & SUBPIXEL_MASK;
- shift.y -= double_to_d6(y2scr_pos(render_context.pos_y)) & SUBPIXEL_MASK;
- }
-
- ass_font_set_transform(render_context.font,
- render_context.scale_x * frame_context.font_scale_x,
- render_context.scale_y,
- &shift );
-
- get_outline_glyph(code, text_info.glyphs + text_info.length, &shift);
-
- text_info.glyphs[text_info.length].pos.x = pen.x >> 6;
- text_info.glyphs[text_info.length].pos.y = pen.y >> 6;
-
- pen.x += text_info.glyphs[text_info.length].advance.x;
- pen.x += double_to_d6(render_context.hspacing);
- pen.y += text_info.glyphs[text_info.length].advance.y;
-
- previous = code;
-
- text_info.glyphs[text_info.length].symbol = code;
- text_info.glyphs[text_info.length].linebreak = 0;
- for (i = 0; i < 4; ++i) {
- uint32_t clr = render_context.c[i];
- change_alpha(&clr, mult_alpha(_a(clr), render_context.fade), 1.);
- text_info.glyphs[text_info.length].c[i] = clr;
- }
- text_info.glyphs[text_info.length].effect_type = render_context.effect_type;
- text_info.glyphs[text_info.length].effect_timing = render_context.effect_timing;
- text_info.glyphs[text_info.length].effect_skip_timing = render_context.effect_skip_timing;
- text_info.glyphs[text_info.length].be = render_context.be;
- text_info.glyphs[text_info.length].blur = render_context.blur;
- text_info.glyphs[text_info.length].shadow = render_context.shadow;
- text_info.glyphs[text_info.length].frx = render_context.frx;
- text_info.glyphs[text_info.length].fry = render_context.fry;
- text_info.glyphs[text_info.length].frz = render_context.frz;
- ass_font_get_asc_desc(render_context.font, code,
- &text_info.glyphs[text_info.length].asc,
- &text_info.glyphs[text_info.length].desc);
- text_info.glyphs[text_info.length].asc *= render_context.scale_y;
- text_info.glyphs[text_info.length].desc *= render_context.scale_y;
-
- // fill bitmap_hash_key
- text_info.glyphs[text_info.length].hash_key.font = render_context.font;
- text_info.glyphs[text_info.length].hash_key.size = render_context.font_size;
- text_info.glyphs[text_info.length].hash_key.outline = render_context.border * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.scale_x = render_context.scale_x * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.scale_y = render_context.scale_y * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.frx = render_context.frx * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.fry = render_context.fry * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.frz = render_context.frz * 0xFFFF;
- text_info.glyphs[text_info.length].hash_key.bold = render_context.bold;
- text_info.glyphs[text_info.length].hash_key.italic = render_context.italic;
- text_info.glyphs[text_info.length].hash_key.ch = code;
- text_info.glyphs[text_info.length].hash_key.advance = shift;
- text_info.glyphs[text_info.length].hash_key.be = render_context.be;
- text_info.glyphs[text_info.length].hash_key.blur = render_context.blur;
-
- text_info.length++;
-
- render_context.effect_type = EF_NONE;
- render_context.effect_timing = 0;
- render_context.effect_skip_timing = 0;
- }
-
- if (text_info.length == 0) {
- // no valid symbols in the event; this can be smth like {comment}
- free_render_context();
- return 1;
- }
-
- // depends on glyph x coordinates being monotonous, so it should be done before line wrap
- process_karaoke_effects();
-
- // alignments
- alignment = render_context.alignment;
- halign = alignment & 3;
- valign = alignment & 12;
-
- MarginL = (event->MarginL) ? event->MarginL : render_context.style->MarginL;
- MarginR = (event->MarginR) ? event->MarginR : render_context.style->MarginR;
- MarginV = (event->MarginV) ? event->MarginV : render_context.style->MarginV;
-
- if (render_context.evt_type != EVENT_HSCROLL) {
- int max_text_width;
-
- // calculate max length of a line
- max_text_width = x2scr(frame_context.track->PlayResX - MarginR) - x2scr(MarginL);
-
- // rearrange text in several lines
- wrap_lines_smart(max_text_width);
-
- // align text
- last_break = -1;
- for (i = 1; i < text_info.length + 1; ++i) { // (text_info.length + 1) is the end of the last line
- if ((i == text_info.length) || text_info.glyphs[i].linebreak) {
- int width, shift = 0;
- glyph_info_t* first_glyph = text_info.glyphs + last_break + 1;
- glyph_info_t* last_glyph = text_info.glyphs + i - 1;
-
- while ((last_glyph > first_glyph) && ((last_glyph->symbol == '\n') || (last_glyph->symbol == 0)))
- last_glyph --;
-
- width = last_glyph->pos.x + d6_to_int(last_glyph->advance.x) - first_glyph->pos.x;
- if (halign == HALIGN_LEFT) { // left aligned, no action
- shift = 0;
- } else if (halign == HALIGN_RIGHT) { // right aligned
- shift = max_text_width - width;
- } else if (halign == HALIGN_CENTER) { // centered
- shift = (max_text_width - width) / 2;
- }
- for (j = last_break + 1; j < i; ++j) {
- text_info.glyphs[j].pos.x += shift;
- }
- last_break = i - 1;
- }
- }
- } else { // render_context.evt_type == EVENT_HSCROLL
- measure_text();
- }
-
- // determing text bounding box
- compute_string_bbox(&text_info, &bbox);
-
- // determine device coordinates for text
-
- // x coordinate for everything except positioned events
- if (render_context.evt_type == EVENT_NORMAL ||
- render_context.evt_type == EVENT_VSCROLL) {
- device_x = x2scr(MarginL);
- } else if (render_context.evt_type == EVENT_HSCROLL) {
- if (render_context.scroll_direction == SCROLL_RL)
- device_x = x2scr(frame_context.track->PlayResX - render_context.scroll_shift);
- else if (render_context.scroll_direction == SCROLL_LR)
- device_x = x2scr(render_context.scroll_shift) - (bbox.xMax - bbox.xMin);
- }
-
- // y coordinate for everything except positioned events
- if (render_context.evt_type == EVENT_NORMAL ||
- render_context.evt_type == EVENT_HSCROLL) {
- if (valign == VALIGN_TOP) { // toptitle
- device_y = y2scr_top(MarginV) + d6_to_int(text_info.lines[0].asc);
- } else if (valign == VALIGN_CENTER) { // midtitle
- int scr_y = y2scr(frame_context.track->PlayResY / 2);
- device_y = scr_y - (bbox.yMax - bbox.yMin) / 2;
- } else { // subtitle
- int scr_y;
- if (valign != VALIGN_SUB)
- mp_msg(MSGT_ASS, MSGL_V, "Invalid valign, supposing 0 (subtitle)\n");
- scr_y = y2scr_sub(frame_context.track->PlayResY - MarginV);
- device_y = scr_y;
- device_y -= d6_to_int(text_info.height);
- device_y += d6_to_int(text_info.lines[0].asc);
- }
- } else if (render_context.evt_type == EVENT_VSCROLL) {
- if (render_context.scroll_direction == SCROLL_TB)
- device_y = y2scr(render_context.clip_y0 + render_context.scroll_shift) - (bbox.yMax - bbox.yMin);
- else if (render_context.scroll_direction == SCROLL_BT)
- device_y = y2scr(render_context.clip_y1 - render_context.scroll_shift);
- }
-
- // positioned events are totally different
- if (render_context.evt_type == EVENT_POSITIONED) {
- int base_x = 0;
- int base_y = 0;
- mp_msg(MSGT_ASS, MSGL_DBG2, "positioned event at %f, %f\n", render_context.pos_x, render_context.pos_y);
- get_base_point(bbox, alignment, &base_x, &base_y);
- device_x = x2scr_pos(render_context.pos_x) - base_x;
- device_y = y2scr_pos(render_context.pos_y) - base_y;
- }
-
- // fix clip coordinates (they depend on alignment)
- if (render_context.evt_type == EVENT_NORMAL ||
- render_context.evt_type == EVENT_HSCROLL ||
- render_context.evt_type == EVENT_VSCROLL) {
- render_context.clip_x0 = x2scr(render_context.clip_x0);
- render_context.clip_x1 = x2scr(render_context.clip_x1);
- if (valign == VALIGN_TOP) {
- render_context.clip_y0 = y2scr_top(render_context.clip_y0);
- render_context.clip_y1 = y2scr_top(render_context.clip_y1);
- } else if (valign == VALIGN_CENTER) {
- render_context.clip_y0 = y2scr(render_context.clip_y0);
- render_context.clip_y1 = y2scr(render_context.clip_y1);
- } else if (valign == VALIGN_SUB) {
- render_context.clip_y0 = y2scr_sub(render_context.clip_y0);
- render_context.clip_y1 = y2scr_sub(render_context.clip_y1);
- }
- } else if (render_context.evt_type == EVENT_POSITIONED) {
- render_context.clip_x0 = x2scr_pos(render_context.clip_x0);
- render_context.clip_x1 = x2scr_pos(render_context.clip_x1);
- render_context.clip_y0 = y2scr_pos(render_context.clip_y0);
- render_context.clip_y1 = y2scr_pos(render_context.clip_y1);
- }
-
- // calculate rotation parameters
- {
- FT_Vector center;
-
- if (render_context.have_origin) {
- center.x = x2scr(render_context.org_x);
- center.y = y2scr(render_context.org_y);
- } else {
- int bx = 0, by = 0;
- get_base_point(bbox, alignment, &bx, &by);
- center.x = device_x + bx;
- center.y = device_y + by;
- }
-
- for (i = 0; i < text_info.length; ++i) {
- glyph_info_t* info = text_info.glyphs + i;
-
- if (info->hash_key.frx || info->hash_key.fry || info->hash_key.frz) {
- info->hash_key.shift_x = info->pos.x + device_x - center.x;
- info->hash_key.shift_y = - (info->pos.y + device_y - center.y);
- } else {
- info->hash_key.shift_x = 0;
- info->hash_key.shift_y = 0;
- }
- }
- }
-
- // convert glyphs to bitmaps
- for (i = 0; i < text_info.length; ++i)
- get_bitmap_glyph(text_info.glyphs + i);
-
- memset(event_images, 0, sizeof(*event_images));
- event_images->top = device_y - d6_to_int(text_info.lines[0].asc);
- event_images->height = d6_to_int(text_info.height);
- event_images->detect_collisions = render_context.detect_collisions;
- event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1;
- event_images->event = event;
- event_images->imgs = render_text(&text_info, device_x, device_y);
-
- free_render_context();
-
- return 0;
-}
-
-/**
- * \brief deallocate image list
- * \param img list pointer
- */
-static void ass_free_images(ass_image_t* img)
-{
- while (img) {
- ass_image_t* next = img->next;
- free(img);
- img = next;
- }
-}
-
-static void ass_reconfigure(ass_renderer_t* priv)
-{
- priv->render_id = ++last_render_id;
- ass_glyph_cache_reset();
- ass_bitmap_cache_reset();
- ass_composite_cache_reset();
- ass_free_images(priv->prev_images_root);
- priv->prev_images_root = 0;
-}
-
-void ass_set_frame_size(ass_renderer_t* priv, int w, int h)
-{
- if (priv->settings.frame_width != w || priv->settings.frame_height != h) {
- priv->settings.frame_width = w;
- priv->settings.frame_height = h;
- if (priv->settings.aspect == 0.)
- priv->settings.aspect = ((double)w) / h;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_margins(ass_renderer_t* priv, int t, int b, int l, int r)
-{
- if (priv->settings.left_margin != l ||
- priv->settings.right_margin != r ||
- priv->settings.top_margin != t ||
- priv->settings.bottom_margin != b) {
- priv->settings.left_margin = l;
- priv->settings.right_margin = r;
- priv->settings.top_margin = t;
- priv->settings.bottom_margin = b;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_use_margins(ass_renderer_t* priv, int use)
-{
- priv->settings.use_margins = use;
-}
-
-void ass_set_aspect_ratio(ass_renderer_t* priv, double ar)
-{
- if (priv->settings.aspect != ar) {
- priv->settings.aspect = ar;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_font_scale(ass_renderer_t* priv, double font_scale)
-{
- if (priv->settings.font_size_coeff != font_scale) {
- priv->settings.font_size_coeff = font_scale;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_hinting(ass_renderer_t* priv, ass_hinting_t ht)
-{
- if (priv->settings.hinting != ht) {
- priv->settings.hinting = ht;
- ass_reconfigure(priv);
- }
-}
-
-void ass_set_line_spacing(ass_renderer_t* priv, double line_spacing)
-{
- priv->settings.line_spacing = line_spacing;
-}
-
-static int ass_set_fonts_(ass_renderer_t* priv, const char* default_font, const char* default_family, int fc)
-{
- if (priv->settings.default_font)
- free(priv->settings.default_font);
- if (priv->settings.default_family)
- free(priv->settings.default_family);
-
- priv->settings.default_font = default_font ? strdup(default_font) : 0;
- priv->settings.default_family = default_family ? strdup(default_family) : 0;
-
- if (priv->fontconfig_priv)
- fontconfig_done(priv->fontconfig_priv);
- priv->fontconfig_priv = fontconfig_init(priv->library, priv->ftlibrary, default_family, default_font, fc);
-
- return !!priv->fontconfig_priv;
-}
-
-int ass_set_fonts(ass_renderer_t* priv, const char* default_font, const char* default_family)
-{
- return ass_set_fonts_(priv, default_font, default_family, 1);
-}
-
-int ass_set_fonts_nofc(ass_renderer_t* priv, const char* default_font, const char* default_family)
-{
- return ass_set_fonts_(priv, default_font, default_family, 0);
-}
-
-/**
- * \brief Start a new frame
- */
-static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long now)
-{
- ass_renderer = priv;
- global_settings = &priv->settings;
-
- if (!priv->settings.frame_width && !priv->settings.frame_height)
- return 1; // library not initialized
-
- if (track->n_events == 0)
- return 1; // nothing to do
-
- frame_context.ass_priv = priv;
- frame_context.width = global_settings->frame_width;
- frame_context.height = global_settings->frame_height;
- frame_context.orig_width = global_settings->frame_width - global_settings->left_margin - global_settings->right_margin;
- frame_context.orig_height = global_settings->frame_height - global_settings->top_margin - global_settings->bottom_margin;
- frame_context.orig_width_nocrop = global_settings->frame_width -
- FFMAX(global_settings->left_margin, 0) -
- FFMAX(global_settings->right_margin, 0);
- frame_context.orig_height_nocrop = global_settings->frame_height -
- FFMAX(global_settings->top_margin, 0) -
- FFMAX(global_settings->bottom_margin, 0);
- frame_context.track = track;
- frame_context.time = now;
-
- ass_lazy_track_init();
-
- frame_context.font_scale = global_settings->font_size_coeff *
- frame_context.orig_height / frame_context.track->PlayResY;
- if (frame_context.track->ScaledBorderAndShadow)
- frame_context.border_scale = ((double)frame_context.orig_height) / frame_context.track->PlayResY;
- else
- frame_context.border_scale = 1.;
-
- frame_context.font_scale_x = 1.;
-
- priv->prev_images_root = priv->images_root;
- priv->images_root = 0;
-
- return 0;
-}
-
-static int cmp_event_layer(const void* p1, const void* p2)
-{
- ass_event_t* e1 = ((event_images_t*)p1)->event;
- ass_event_t* e2 = ((event_images_t*)p2)->event;
- if (e1->Layer < e2->Layer)
- return -1;
- if (e1->Layer > e2->Layer)
- return 1;
- if (e1->ReadOrder < e2->ReadOrder)
- return -1;
- if (e1->ReadOrder > e2->ReadOrder)
- return 1;
- return 0;
-}
-
-#define MAX_EVENTS 100
-
-static render_priv_t* get_render_priv(ass_event_t* event)
-{
- if (!event->render_priv)
- event->render_priv = calloc(1, sizeof(render_priv_t));
- // FIXME: check render_id
- if (ass_renderer->render_id != event->render_priv->render_id) {
- memset(event->render_priv, 0, sizeof(render_priv_t));
- event->render_priv->render_id = ass_renderer->render_id;
- }
- return event->render_priv;
-}
-
-typedef struct segment_s {
- int a, b; // top and height
-} segment_t;
-
-static int overlap(segment_t* s1, segment_t* s2)
-{
- if (s1->a >= s2->b || s2->a >= s1->b)
- return 0;
- return 1;
-}
-
-static int cmp_segment(const void* p1, const void* p2)
-{
- return ((segment_t*)p1)->a - ((segment_t*)p2)->a;
-}
-
-static void shift_event(event_images_t* ei, int shift)
-{
- ass_image_t* cur = ei->imgs;
- while (cur) {
- cur->dst_y += shift;
- // clip top and bottom
- if (cur->dst_y < 0) {
- int clip = - cur->dst_y;
- cur->h -= clip;
- cur->bitmap += clip * cur->stride;
- cur->dst_y = 0;
- }
- if (cur->dst_y + cur->h >= frame_context.height) {
- int clip = cur->dst_y + cur->h - frame_context.height;
- cur->h -= clip;
- }
- if (cur->h <= 0) {
- cur->h = 0;
- cur->dst_y = 0;
- }
- cur = cur->next;
- }
- ei->top += shift;
-}
-
-// dir: 1 - move down
-// -1 - move up
-static int fit_segment(segment_t* s, segment_t* fixed, int* cnt, int dir)
-{
- int i;
- int shift = 0;
-
- if (dir == 1) // move down
- for (i = 0; i < *cnt; ++i) {
- if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b)
- continue;
- shift = fixed[i].b - s->a;
- }
- else // dir == -1, move up
- for (i = *cnt-1; i >= 0; --i) {
- if (s->b + shift <= fixed[i].a || s->a + shift >= fixed[i].b)
- continue;
- shift = fixed[i].a - s->b;
- }
-
- fixed[*cnt].a = s->a + shift;
- fixed[*cnt].b = s->b + shift;
- (*cnt)++;
- qsort(fixed, *cnt, sizeof(segment_t), cmp_segment);
-
- return shift;
-}
-
-static void fix_collisions(event_images_t* imgs, int cnt)
-{
- segment_t used[MAX_EVENTS];
- int cnt_used = 0;
- int i, j;
-
- // fill used[] with fixed events
- for (i = 0; i < cnt; ++i) {
- render_priv_t* priv;
- if (!imgs[i].detect_collisions) continue;
- priv = get_render_priv(imgs[i].event);
- if (priv->height > 0) { // it's a fixed event
- segment_t s;
- s.a = priv->top;
- s.b = priv->top + priv->height;
- if (priv->height != imgs[i].height) { // no, it's not
- mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_EventHeightHasChanged);
- priv->top = 0;
- priv->height = 0;
- }
- for (j = 0; j < cnt_used; ++j)
- if (overlap(&s, used + j)) { // no, it's not
- priv->top = 0;
- priv->height = 0;
- }
- if (priv->height > 0) { // still a fixed event
- used[cnt_used].a = priv->top;
- used[cnt_used].b = priv->top + priv->height;
- cnt_used ++;
- shift_event(imgs + i, priv->top - imgs[i].top);
- }
- }
- }
- qsort(used, cnt_used, sizeof(segment_t), cmp_segment);
-
- // try to fit other events in free spaces
- for (i = 0; i < cnt; ++i) {
- render_priv_t* priv;
- if (!imgs[i].detect_collisions) continue;
- priv = get_render_priv(imgs[i].event);
- if (priv->height == 0) { // not a fixed event
- int shift;
- segment_t s;
- s.a = imgs[i].top;
- s.b = imgs[i].top + imgs[i].height;
- shift = fit_segment(&s, used, &cnt_used, imgs[i].shift_direction);
- if (shift) shift_event(imgs + i, shift);
- // make it fixed
- priv->top = imgs[i].top;
- priv->height = imgs[i].height;
- }
-
- }
-}
-
-/**
- * \brief compare two images
- * \param i1 first image
- * \param i2 second image
- * \return 0 if identical, 1 if different positions, 2 if different content
- */
-static int ass_image_compare(ass_image_t *i1, ass_image_t *i2)
-{
- if (i1->w != i2->w) return 2;
- if (i1->h != i2->h) return 2;
- if (i1->stride != i2->stride) return 2;
- if (i1->color != i2->color) return 2;
- if (i1->bitmap != i2->bitmap)
- return 2;
- if (i1->dst_x != i2->dst_x) return 1;
- if (i1->dst_y != i2->dst_y) return 1;
- return 0;
-}
-
-/**
- * \brief compare current and previous image list
- * \param priv library handle
- * \return 0 if identical, 1 if different positions, 2 if different content
- */
-static int ass_detect_change(ass_renderer_t *priv)
-{
- ass_image_t* img, *img2;
- int diff;
-
- img = priv->prev_images_root;
- img2 = priv->images_root;
- diff = 0;
- while (img && diff < 2) {
- ass_image_t* next, *next2;
- next = img->next;
- if (img2) {
- int d = ass_image_compare(img, img2);
- if (d > diff) diff = d;
- next2 = img2->next;
- } else {
- // previous list is shorter
- diff = 2;
- break;
- }
- img = next;
- img2 = next2;
- }
-
- // is the previous list longer?
- if (img2)
- diff = 2;
-
- return diff;
-}
-
-/**
- * \brief render a frame
- * \param priv library handle
- * \param track track
- * \param now current video timestamp (ms)
- * \param detect_change a value describing how the new images differ from the previous ones will be written here:
- * 0 if identical, 1 if different positions, 2 if different content.
- * Can be NULL, in that case no detection is performed.
- */
-ass_image_t* ass_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change)
-{
- int i, cnt, rc;
- event_images_t* last;
- ass_image_t** tail;
-
- // init frame
- rc = ass_start_frame(priv, track, now);
- if (rc != 0)
- return 0;
-
- // render events separately
- cnt = 0;
- for (i = 0; i < track->n_events; ++i) {
- ass_event_t* event = track->events + i;
- if ( (event->Start <= now) && (now < (event->Start + event->Duration)) ) {
- if (cnt >= priv->eimg_size) {
- priv->eimg_size += 100;
- priv->eimg = realloc(priv->eimg, priv->eimg_size * sizeof(event_images_t));
- }
- rc = ass_render_event(event, priv->eimg + cnt);
- if (!rc) ++cnt;
- }
- }
-
- // sort by layer
- qsort(priv->eimg, cnt, sizeof(event_images_t), cmp_event_layer);
-
- // call fix_collisions for each group of events with the same layer
- last = priv->eimg;
- for (i = 1; i < cnt; ++i)
- if (last->event->Layer != priv->eimg[i].event->Layer) {
- fix_collisions(last, priv->eimg + i - last);
- last = priv->eimg + i;
- }
- if (cnt > 0)
- fix_collisions(last, priv->eimg + cnt - last);
-
- // concat lists
- tail = &ass_renderer->images_root;
- for (i = 0; i < cnt; ++i) {
- ass_image_t* cur = priv->eimg[i].imgs;
- while (cur) {
- *tail = cur;
- tail = &cur->next;
- cur = cur->next;
- }
- }
-
- if (detect_change)
- *detect_change = ass_detect_change(priv);
-
- // free the previous image list
- ass_free_images(priv->prev_images_root);
- priv->prev_images_root = 0;
-
- return ass_renderer->images_root;
-}
diff --git a/libass/ass_types.h b/libass/ass_types.h
deleted file mode 100644
index d43fef3137..0000000000
--- a/libass/ass_types.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_TYPES_H
-#define LIBASS_TYPES_H
-
-#include <stdint.h>
-
-#define VALIGN_SUB 0
-#define VALIGN_CENTER 8
-#define VALIGN_TOP 4
-#define HALIGN_LEFT 1
-#define HALIGN_CENTER 2
-#define HALIGN_RIGHT 3
-
-/// ass Style: line
-typedef struct ass_style_s {
- char* Name;
- char* FontName;
- double FontSize;
- uint32_t PrimaryColour;
- uint32_t SecondaryColour;
- uint32_t OutlineColour;
- uint32_t BackColour;
- int Bold;
- int Italic;
- int Underline;
- int StrikeOut;
- double ScaleX;
- double ScaleY;
- double Spacing;
- int Angle;
- int BorderStyle;
- double Outline;
- double Shadow;
- int Alignment;
- int MarginL;
- int MarginR;
- int MarginV;
-// int AlphaLevel;
- int Encoding;
- int treat_fontname_as_pattern;
-} ass_style_t;
-
-typedef struct render_priv_s render_priv_t;
-
-/// ass_event_t corresponds to a single Dialogue line
-/// Text is stored as-is, style overrides will be parsed later
-typedef struct ass_event_s {
- long long Start; // ms
- long long Duration; // ms
-
- int ReadOrder;
- int Layer;
- int Style;
- char* Name;
- int MarginL;
- int MarginR;
- int MarginV;
- char* Effect;
- char* Text;
-
- render_priv_t* render_priv;
-} ass_event_t;
-
-typedef struct parser_priv_s parser_priv_t;
-
-typedef struct ass_library_s ass_library_t;
-
-/// ass track represent either an external script or a matroska subtitle stream (no real difference between them)
-/// it can be used in rendering after the headers are parsed (i.e. events format line read)
-typedef struct ass_track_s {
- int n_styles; // amount used
- int max_styles; // amount allocated
- int n_events;
- int max_events;
- ass_style_t* styles; // array of styles, max_styles length, n_styles used
- ass_event_t* events; // the same as styles
-
- char* style_format; // style format line (everything after "Format: ")
- char* event_format; // event format line
-
- enum {TRACK_TYPE_UNKNOWN = 0, TRACK_TYPE_ASS, TRACK_TYPE_SSA} track_type;
-
- // script header fields
- int PlayResX;
- int PlayResY;
- double Timer;
- int WrapStyle;
- char ScaledBorderAndShadow;
-
-
- int default_style; // index of default style
- char* name; // file name in case of external subs, 0 for streams
-
- ass_library_t* library;
- parser_priv_t* parser_priv;
-} ass_track_t;
-
-#endif /* LIBASS_TYPES_H */
diff --git a/libass/ass_utils.c b/libass/ass_utils.c
deleted file mode 100644
index 9a89e8afae..0000000000
--- a/libass/ass_utils.c
+++ /dev/null
@@ -1,135 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <ft2build.h>
-#include FT_GLYPH_H
-
-#include "mputils.h"
-#include "ass_utils.h"
-
-int mystrtoi(char** p, int* res)
-{
- // NOTE: base argument is ignored, but not used in libass anyway
- double temp_res;
- char* start = *p;
- temp_res = strtod(*p, p);
- *res = (int) (temp_res + 0.5);
- if (*p != start) return 1;
- else return 0;
-}
-
-int mystrtoll(char** p, long long* res)
-{
- double temp_res;
- char* start = *p;
- temp_res = strtod(*p, p);
- *res = (long long) (temp_res + 0.5);
- if (*p != start) return 1;
- else return 0;
-}
-
-int mystrtou32(char** p, int base, uint32_t* res)
-{
- char* start = *p;
- *res = strtoll(*p, p, base);
- if (*p != start) return 1;
- else return 0;
-}
-
-int mystrtod(char** p, double* res)
-{
- char* start = *p;
- *res = strtod(*p, p);
- if (*p != start) return 1;
- else return 0;
-}
-
-int strtocolor(char** q, uint32_t* res)
-{
- uint32_t color = 0;
- int result;
- char* p = *q;
-
- if (*p == '&') ++p;
- else mp_msg(MSGT_ASS, MSGL_DBG2, "suspicious color format: \"%s\"\n", p);
-
- if (*p == 'H' || *p == 'h') {
- ++p;
- result = mystrtou32(&p, 16, &color);
- } else {
- result = mystrtou32(&p, 0, &color);
- }
-
- {
- unsigned char* tmp = (unsigned char*)(&color);
- unsigned char b;
- b = tmp[0]; tmp[0] = tmp[3]; tmp[3] = b;
- b = tmp[1]; tmp[1] = tmp[2]; tmp[2] = b;
- }
- if (*p == '&') ++p;
- *q = p;
-
- *res = color;
- return result;
-}
-
-// Return a boolean value for a string
-char parse_bool(char* str) {
- while (*str == ' ' || *str == '\t')
- str++;
- if (!strncasecmp(str, "yes", 3))
- return 1;
- else if (strtol(str, NULL, 10) > 0)
- return 1;
- return 0;
-}
-
-#if 0
-static void sprint_tag(uint32_t tag, char* dst)
-{
- dst[0] = (tag >> 24) & 0xFF;
- dst[1] = (tag >> 16) & 0xFF;
- dst[2] = (tag >> 8) & 0xFF;
- dst[3] = tag & 0xFF;
- dst[4] = 0;
-}
-
-void dump_glyph(FT_Glyph g)
-{
- char tag[5];
- int i;
- FT_OutlineGlyph og = (FT_OutlineGlyph)g;
- FT_Outline* o = &(og->outline);
- sprint_tag(g->format, tag);
- printf("glyph: %p \n", g);
- printf("format: %s \n", tag);
- printf("outline: %p \n", o);
- printf("contours: %d, points: %d, points ptr: %p \n", o->n_contours, o->n_points, o->points);
- for (i = 0; i < o->n_points; ++i) {
- printf(" point %f, %f \n", d6_to_double(o->points[i].x), d6_to_double(o->points[i].y));
- }
-}
-#endif
diff --git a/libass/ass_utils.h b/libass/ass_utils.h
deleted file mode 100644
index 8c5f3e8f49..0000000000
--- a/libass/ass_utils.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// -*- c-basic-offset: 8; indent-tabs-mode: t -*-
-// vim:ts=8:sw=8:noet:ai:
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_UTILS_H
-#define LIBASS_UTILS_H
-
-#include <stdint.h>
-
-int mystrtoi(char** p, int* res);
-int mystrtoll(char** p, long long* res);
-int mystrtou32(char** p, int base, uint32_t* res);
-int mystrtod(char** p, double* res);
-int strtocolor(char** q, uint32_t* res);
-char parse_bool(char* str);
-
-static inline int d6_to_int(int x) {
- return (x + 32) >> 6;
-}
-static inline int d16_to_int(int x) {
- return (x + 32768) >> 16;
-}
-static inline int int_to_d6(int x) {
- return x << 6;
-}
-static inline int int_to_d16(int x) {
- return x << 16;
-}
-static inline int d16_to_d6(int x) {
- return (x + 512) >> 10;
-}
-static inline int d6_to_d16(int x) {
- return x << 10;
-}
-static inline double d6_to_double(int x) {
- return x / 64.;
-}
-static inline int double_to_d6(double x) {
- return (int)(x * 64);
-}
-static inline double d16_to_double(int x) {
- return ((double)x) / 0x10000;
-}
-static inline int double_to_d16(double x) {
- return (int)(x * 0x10000);
-}
-
-#endif /* LIBASS_UTILS_H */
diff --git a/libass/mputils.h b/libass/mputils.h
deleted file mode 100644
index cff269357f..0000000000
--- a/libass/mputils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
- *
- * This file is part of libass.
- *
- * libass is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * libass is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef LIBASS_MPUTILS_H
-#define LIBASS_MPUTILS_H
-
-#include "mp_msg.h"
-#include "help_mp.h"
-#include "libvo/font_load.h" // for blur()
-#include "subreader.h" // for guess_buffer_cp
-#include "libvo/sub.h" // for utf8_get_char
-#include "libavutil/common.h"
-
-#endif /* LIBASS_MPUTILS_H */
diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
index b13b148600..4c2f9bef7c 100644
--- a/libmpcodecs/vf_ass.c
+++ b/libmpcodecs/vf_ass.c
@@ -42,8 +42,7 @@
#include "m_option.h"
#include "m_struct.h"
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
#define _r(c) ((c)>>24)
#define _g(c) (((c)>>16)&0xFF)
@@ -97,7 +96,7 @@ static int config(struct vf_instance* vf,
if (vf->priv->ass_priv) {
ass_configure(vf->priv->ass_priv, vf->priv->outw, vf->priv->outh, 0);
- ass_set_aspect_ratio(vf->priv->ass_priv, ((double)d_width) / d_height);
+ ass_set_aspect_ratio(vf->priv->ass_priv, 1, 1);
}
return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt);
diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
index 2e4257fb21..6ec5904053 100644
--- a/libmpcodecs/vf_vo.c
+++ b/libmpcodecs/vf_vo.c
@@ -12,8 +12,7 @@
#include "libvo/video_out.h"
#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
extern ass_track_t* ass_track;
#endif
@@ -28,6 +27,7 @@ struct vf_priv_s {
#ifdef CONFIG_ASS
ass_renderer_t* ass_priv;
int prev_visibility;
+ double scale_ratio;
#endif
};
#define video_out (vf->priv->vo)
@@ -67,6 +67,8 @@ static int config(struct vf_instance* vf,
return 0;
#ifdef CONFIG_ASS
+ vf->priv->scale_ratio = (double) d_width / d_height * height / width;
+
if (vf->priv->ass_priv)
ass_configure(vf->priv->ass_priv, width, height, !!(vf->default_caps & VFCAP_EOSD_UNSCALED));
#endif
@@ -133,7 +135,7 @@ static int control(struct vf_instance* vf, int request, void* data)
if (vo_control(video_out, VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) {
ass_set_frame_size(vf->priv->ass_priv, res.w, res.h);
ass_set_margins(vf->priv->ass_priv, res.mt, res.mb, res.ml, res.mr);
- ass_set_aspect_ratio(vf->priv->ass_priv, (double)res.w / res.h);
+ ass_set_aspect_ratio(vf->priv->ass_priv, vf->priv->scale_ratio, 1);
}
images.imgs = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed);
diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c
index 5c05dbf585..9c984a11a9 100644
--- a/libmpdemux/demux_mkv.c
+++ b/libmpdemux/demux_mkv.c
@@ -44,8 +44,7 @@
#include "subreader.h"
#include "libvo/sub.h"
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
#include "libavutil/common.h"
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index c9142f1441..349131f12b 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -42,10 +42,7 @@
#include "libaf/af_format.h"
-#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
-#endif
+#include "ass_mp.h"
#ifdef CONFIG_LIBAVCODEC
#include "libavcodec/avcodec.h"
diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c
index 602829164d..ceb70ec32e 100644
--- a/libvo/vo_gl.c
+++ b/libvo/vo_gl.c
@@ -32,8 +32,7 @@
#include "gl_common.h"
#include "aspect.h"
#include "fastmemcpy.h"
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
static const vo_info_t info =
{
diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c
index 597edeb8b3..281bfe60e2 100644
--- a/libvo/vo_vdpau.c
+++ b/libvo/vo_vdpau.c
@@ -50,8 +50,7 @@
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
static vo_info_t info = {
"VDPAU with X11",
diff --git a/mencoder.c b/mencoder.c
index 6627332c17..47b0efb8a1 100644
--- a/mencoder.c
+++ b/mencoder.c
@@ -221,10 +221,7 @@ void mplayer_put_key(struct mp_fifo *fifo, int code)
{
}
-#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
-#endif
+#include "ass_mp.h"
char *current_module;
#include "mpcommon.h"
diff --git a/mp_msg.c b/mp_msg.c
index 5b573a389f..7314dd25af 100644
--- a/mp_msg.c
+++ b/mp_msg.c
@@ -165,16 +165,14 @@ static void print_msg_module(FILE* stream, int mod)
fprintf(stream, ": ");
}
-void mp_msg(int mod, int lev, const char *format, ... ){
- va_list va;
+void mp_msg_va(int mod, int lev, const char *format, va_list va)
+{
char tmp[MSGSIZE_MAX];
FILE *stream = lev <= MSGL_WARN ? stderr : stdout;
static int header = 1;
if (!mp_msg_test(mod, lev)) return; // do not display
- va_start(va, format);
vsnprintf(tmp, MSGSIZE_MAX, format, va);
- va_end(va);
tmp[MSGSIZE_MAX-2] = '\n';
tmp[MSGSIZE_MAX-1] = 0;
@@ -218,6 +216,15 @@ void mp_msg(int mod, int lev, const char *format, ... ){
fflush(stream);
}
+void mp_msg(int mod, int lev, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ mp_msg_va(mod, lev, format, va);
+ va_end(va);
+}
+
+
char *mp_gtext(const char *string)
{
return string;
diff --git a/mp_msg.h b/mp_msg.h
index a19da44d0a..91b6b86449 100644
--- a/mp_msg.h
+++ b/mp_msg.h
@@ -1,6 +1,8 @@
#ifndef MPLAYER_MP_MSG_H
#define MPLAYER_MP_MSG_H
+#include <stdarg.h>
+
// defined in mplayer.c and mencoder.c
extern int verbose;
@@ -116,6 +118,8 @@ int mp_msg_test(int mod, int lev);
char *mp_gtext(const char *string);
#define mp_tmsg mp_msg
+void mp_msg_va(int mod, int lev, const char *format, va_list va);
+
#ifdef __GNUC__
void mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4)));
# ifdef MP_DEBUG
diff --git a/mpcommon.c b/mpcommon.c
index 053a46d5a4..83cf2b6881 100644
--- a/mpcommon.c
+++ b/mpcommon.c
@@ -22,8 +22,7 @@
double sub_last_pts = -303;
#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
+#include "ass_mp.h"
ass_track_t* ass_track = 0; // current track to render
#endif
diff --git a/mplayer.c b/mplayer.c
index ac02447eb5..8697e47a85 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -309,10 +309,7 @@ char *vobsub_name=NULL;
int subcc_enabled=0;
int suboverlap_enabled = 1;
-#ifdef CONFIG_ASS
-#include "libass/ass.h"
-#include "libass/ass_mp.h"
-#endif
+#include "ass_mp.h"
char* current_module=NULL; // for debugging