mirror of https://github.com/mpv-player/mpv
Remove internal libass tree
Remove the libass/ directory and use the newest standalone version of the library instead.
This commit is contained in:
parent
6fbcf16cfb
commit
546c3fb53c
10
Makefile
10
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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
1134
libass/ass.c
1134
libass/ass.c
File diff suppressed because it is too large
Load Diff
229
libass/ass.h
229
libass/ass.h
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
279
libass/ass_mp.c
279
libass/ass_mp.c
|
@ -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);
|
||||
}
|
|
@ -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 */
|
2616
libass/ass_render.c
2616
libass/ass_render.c
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 =
|
||||
{
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
15
mp_msg.c
15
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;
|
||||
|
|
4
mp_msg.h
4
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue