1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
4 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
6 * This file is part of libass.
8 * libass is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * libass is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with libass; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "stream/stream.h"
34 #ifdef CONFIG_FONTCONFIG
35 #include <fontconfig/fontconfig.h>
38 // libass-related command line options
39 ass_library_t
* ass_library
;
41 float ass_font_scale
= 1.;
42 float ass_line_spacing
= 0.;
43 int ass_top_margin
= 0;
44 int ass_bottom_margin
= 0;
45 #if defined(FC_VERSION) && (FC_VERSION >= 20402)
46 int extract_embedded_fonts
= 1;
48 int extract_embedded_fonts
= 0;
50 char **ass_force_style_list
= NULL
;
51 int ass_use_margins
= 0;
52 char* ass_color
= NULL
;
53 char* ass_border_color
= NULL
;
54 char* ass_styles_file
= NULL
;
55 int ass_hinting
= ASS_HINTING_NATIVE
+ 4; // native hinting for unscaled osd
57 #ifdef CONFIG_FONTCONFIG
58 extern int font_fontconfig
;
60 static int font_fontconfig
= -1;
62 extern char* font_name
;
63 extern char* sub_font_name
;
64 extern float text_font_scale_factor
;
65 extern int subtitle_autoscale
;
70 static char* sub_cp
= 0;
73 ass_track_t
* ass_default_track(ass_library_t
* library
) {
74 ass_track_t
* track
= ass_new_track(library
);
76 track
->track_type
= TRACK_TYPE_ASS
;
78 track
->PlayResY
= 288;
82 ass_read_styles(track
, ass_styles_file
, sub_cp
);
84 if (track
->n_styles
== 0) {
90 sid
= ass_alloc_style(track
);
91 style
= track
->styles
+ sid
;
92 style
->Name
= strdup("Default");
93 style
->FontName
= (font_fontconfig
>= 0 && sub_font_name
) ? strdup(sub_font_name
) : (font_fontconfig
>= 0 && font_name
) ? strdup(font_name
) : strdup("Sans");
94 style
->treat_fontname_as_pattern
= 1;
96 fs
= track
->PlayResY
* text_font_scale_factor
/ 100.;
97 // approximate autoscale coefficients
98 if (subtitle_autoscale
== 2)
100 else if (subtitle_autoscale
== 3)
102 style
->FontSize
= fs
;
104 if (ass_color
) c1
= strtoll(ass_color
, NULL
, 16);
105 else c1
= 0xFFFF0000;
106 if (ass_border_color
) c2
= strtoll(ass_border_color
, NULL
, 16);
107 else c2
= 0x00000000;
109 style
->PrimaryColour
= c1
;
110 style
->SecondaryColour
= c1
;
111 style
->OutlineColour
= c2
;
112 style
->BackColour
= 0x00000000;
113 style
->BorderStyle
= 1;
114 style
->Alignment
= 2;
123 process_force_style(track
);
127 static int check_duplicate_plaintext_event(ass_track_t
* track
)
130 ass_event_t
* evt
= track
->events
+ track
->n_events
- 1;
132 for (i
= 0; i
<track
->n_events
- 1; ++i
) // ignoring last event, it is the one we are comparing with
133 if (track
->events
[i
].Start
== evt
->Start
&&
134 track
->events
[i
].Duration
== evt
->Duration
&&
135 strcmp(track
->events
[i
].Text
, evt
->Text
) == 0)
141 * \brief Convert subtitle to ass_event_t for the given track
142 * \param ass_track_t track
143 * \param sub subtitle to convert
145 * note: assumes that subtitle is _not_ fps-based; caller must manually correct
146 * Start and Duration in other case.
148 int ass_process_subtitle(ass_track_t
* track
, subtitle
* sub
)
156 eid
= ass_alloc_event(track
);
157 event
= track
->events
+ eid
;
159 event
->Start
= sub
->start
* 10;
160 event
->Duration
= (sub
->end
- sub
->start
) * 10;
163 for (j
= 0; j
< sub
->lines
; ++j
)
164 len
+= sub
->text
[j
] ? strlen(sub
->text
[j
]) : 0;
166 len
+= 2 * sub
->lines
; // '\N', including the one after the last line
170 event
->Text
= malloc(len
);
171 end
= event
->Text
+ len
;
175 p
+= snprintf(p
, end
- p
, "{\\an%d}", sub
->alignment
);
177 for (j
= 0; j
< sub
->lines
; ++j
)
178 p
+= snprintf(p
, end
- p
, "%s\\N", sub
->text
[j
]);
180 if (sub
->lines
> 0) p
-=2; // remove last "\N"
183 if (check_duplicate_plaintext_event(track
)) {
184 ass_free_event(track
, eid
);
189 mp_msg(MSGT_ASS
, MSGL_V
, "plaintext event at %" PRId64
", +%" PRId64
": %s \n",
190 (int64_t)event
->Start
, (int64_t)event
->Duration
, event
->Text
);
197 * \brief Convert subdata to ass_track
198 * \param subdata subtitles struct from subreader
199 * \param fps video framerate
200 * \return newly allocated ass_track, filled with subtitles from subdata
202 ass_track_t
* ass_read_subdata(ass_library_t
* library
, sub_data
* subdata
, double fps
) {
206 track
= ass_default_track(library
);
207 track
->name
= subdata
->filename
? strdup(subdata
->filename
) : 0;
209 for (i
= 0; i
< subdata
->sub_num
; ++i
) {
210 int eid
= ass_process_subtitle(track
, subdata
->subtitles
+ i
);
213 if (!subdata
->sub_uses_time
) {
214 track
->events
[eid
].Start
*= 100. / fps
;
215 track
->events
[eid
].Duration
*= 100. / fps
;
221 ass_track_t
* ass_read_stream(ass_library_t
* library
, const char *fname
, char *charset
) {
226 size_t buf_alloc
= 0;
229 fd
= open_stream(fname
, NULL
, &i
);
231 mp_msg(MSGT_ASS
, MSGL_WARN
, MSGTR_LIBASS_FopenFailed
, fname
);
234 if (fd
->end_pos
> STREAM_BUFFER_SIZE
)
235 /* read entire file if size is known */
236 buf_alloc
= fd
->end_pos
;
238 if (buf_alloc
>= 100*1024*1024) {
239 mp_msg(MSGT_ASS
, MSGL_INFO
, MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan100M
, fname
);
243 if (buf_alloc
< sz
+ STREAM_BUFFER_SIZE
)
244 buf_alloc
+= STREAM_BUFFER_SIZE
;
245 buf
= realloc(buf
, buf_alloc
+ 1);
246 i
= stream_read(fd
, buf
+ sz
, buf_alloc
- sz
);
256 buf
= realloc(buf
, sz
+ 1);
257 track
= ass_read_memory(library
, buf
, sz
, charset
);
260 track
->name
= strdup(fname
);
266 void ass_configure(ass_renderer_t
* priv
, int w
, int h
, int unscaled
) {
268 ass_set_frame_size(priv
, w
, h
);
269 ass_set_margins(priv
, ass_top_margin
, ass_bottom_margin
, 0, 0);
270 ass_set_use_margins(priv
, ass_use_margins
);
271 ass_set_font_scale(priv
, ass_font_scale
);
272 if (!unscaled
&& (ass_hinting
& 4))
275 hinting
= ass_hinting
& 3;
276 ass_set_hinting(priv
, hinting
);
277 ass_set_line_spacing(priv
, ass_line_spacing
);
280 void ass_configure_fonts(ass_renderer_t
* priv
) {
281 char *dir
, *path
, *family
;
282 dir
= get_path("fonts");
283 if (font_fontconfig
< 0 && sub_font_name
) path
= strdup(sub_font_name
);
284 else if (font_fontconfig
< 0 && font_name
) path
= strdup(font_name
);
285 else path
= get_path("subfont.ttf");
286 if (font_fontconfig
>= 0 && sub_font_name
) family
= strdup(sub_font_name
);
287 else if (font_fontconfig
>= 0 && font_name
) family
= strdup(font_name
);
290 #if defined(LIBASS_VERSION) && LIBASS_VERSION >= 0x00907010
291 ass_set_fonts(priv
, path
, family
, font_fontconfig
, NULL
, 1);
293 if (font_fontconfig
>= 0)
294 ass_set_fonts(priv
, path
, family
);
296 ass_set_fonts_nofc(priv
, path
, family
);
304 ass_library_t
* ass_init(void) {
306 char* path
= get_path("fonts");
307 priv
= ass_library_init();
308 ass_set_fonts_dir(priv
, path
);
309 ass_set_extract_fonts(priv
, extract_embedded_fonts
);
310 ass_set_style_overrides(priv
, ass_force_style_list
);
315 int ass_force_reload
= 0; // flag set if global ass-related settings were changed
317 ass_image_t
* ass_mp_render_frame(ass_renderer_t
*priv
, ass_track_t
* track
, long long now
, int* detect_change
) {
318 if (ass_force_reload
) {
319 ass_set_margins(priv
, ass_top_margin
, ass_bottom_margin
, 0, 0);
320 ass_set_use_margins(priv
, ass_use_margins
);
321 ass_set_font_scale(priv
, ass_font_scale
);
322 ass_force_reload
= 0;
324 return ass_render_frame(priv
, track
, now
, detect_change
);