1 /*
2  * This file is part of mpv.
3  *
4  * mpv is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * mpv is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <string.h>
21 #include <math.h>
22 #include <limits.h>
23 
24 #include <libavutil/common.h>
25 #include <ass/ass.h>
26 
27 #include "mpv_talloc.h"
28 
29 #include "config.h"
30 #include "options/m_config.h"
31 #include "options/options.h"
32 #include "common/common.h"
33 #include "common/msg.h"
34 #include "demux/demux.h"
35 #include "video/csputils.h"
36 #include "video/mp_image.h"
37 #include "dec_sub.h"
38 #include "ass_mp.h"
39 #include "sd.h"
40 
41 struct sd_ass_priv {
42     struct ass_library *ass_library;
43     struct ass_renderer *ass_renderer;
44     struct ass_track *ass_track;
45     struct ass_track *shadow_track; // for --sub-ass=no rendering
46     bool is_converted;
47     struct lavc_conv *converter;
48     struct sd_filter **filters;
49     int num_filters;
50     bool clear_once;
51     bool on_top;
52     struct mp_ass_packer *packer;
53     struct sub_bitmap_copy_cache *copy_cache;
54     char last_text[500];
55     struct mp_image_params video_params;
56     struct mp_image_params last_params;
57     int64_t *seen_packets;
58     int num_seen_packets;
59     bool duration_unknown;
60 };
61 
62 static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts);
63 static void fill_plaintext(struct sd *sd, double pts);
64 
65 static const struct sd_filter_functions *const filters[] = {
66     // Note: list order defines filter order.
67     &sd_filter_sdh,
68 #if HAVE_POSIX
69     &sd_filter_regex,
70 #endif
71 #if HAVE_JAVASCRIPT
72     &sd_filter_jsre,
73 #endif
74     NULL,
75 };
76 
77 // Add default styles, if the track does not have any styles yet.
78 // Apply style overrides if the user provides any.
mp_ass_add_default_styles(ASS_Track * track,struct mp_subtitle_opts * opts)79 static void mp_ass_add_default_styles(ASS_Track *track, struct mp_subtitle_opts *opts)
80 {
81     if (opts->ass_styles_file && opts->ass_style_override)
82         ass_read_styles(track, opts->ass_styles_file, NULL);
83 
84     if (track->n_styles == 0) {
85         if (!track->PlayResY) {
86             track->PlayResY = MP_ASS_FONT_PLAYRESY;
87             track->PlayResX = track->PlayResY * 4 / 3;
88         }
89         track->Kerning = true;
90         int sid = ass_alloc_style(track);
91         track->default_style = sid;
92         ASS_Style *style = track->styles + sid;
93         style->Name = strdup("Default");
94         mp_ass_set_style(style, track->PlayResY, opts->sub_style);
95     }
96 
97     if (opts->ass_style_override)
98         ass_process_force_style(track);
99 }
100 
101 static const char *const font_mimetypes[] = {
102     "application/x-truetype-font",
103     "application/vnd.ms-opentype",
104     "application/x-font-ttf",
105     "application/x-font", // probably incorrect
106     "application/font-sfnt",
107     "font/collection",
108     "font/otf",
109     "font/sfnt",
110     "font/ttf",
111     NULL
112 };
113 
114 static const char *const font_exts[] = {".ttf", ".ttc", ".otf", ".otc", NULL};
115 
attachment_is_font(struct mp_log * log,struct demux_attachment * f)116 static bool attachment_is_font(struct mp_log *log, struct demux_attachment *f)
117 {
118     if (!f->name || !f->type || !f->data || !f->data_size)
119         return false;
120     for (int n = 0; font_mimetypes[n]; n++) {
121         if (strcmp(font_mimetypes[n], f->type) == 0)
122             return true;
123     }
124     // fallback: match against file extension
125     char *ext = strlen(f->name) > 4 ? f->name + strlen(f->name) - 4 : "";
126     for (int n = 0; font_exts[n]; n++) {
127         if (strcasecmp(ext, font_exts[n]) == 0) {
128             mp_warn(log, "Loading font attachment '%s' with MIME type %s. "
129                     "Assuming this is a broken Matroska file, which was "
130                     "muxed without setting a correct font MIME type.\n",
131                     f->name, f->type);
132             return true;
133         }
134     }
135     return false;
136 }
137 
add_subtitle_fonts(struct sd * sd)138 static void add_subtitle_fonts(struct sd *sd)
139 {
140     struct sd_ass_priv *ctx = sd->priv;
141     struct mp_subtitle_opts *opts = sd->opts;
142     if (!opts->ass_enabled || !opts->use_embedded_fonts || !sd->attachments)
143         return;
144     for (int i = 0; i < sd->attachments->num_entries; i++) {
145         struct demux_attachment *f = &sd->attachments->entries[i];
146         if (attachment_is_font(sd->log, f))
147             ass_add_font(ctx->ass_library, f->name, f->data, f->data_size);
148     }
149 }
150 
filters_destroy(struct sd * sd)151 static void filters_destroy(struct sd *sd)
152 {
153     struct sd_ass_priv *ctx = sd->priv;
154 
155     for (int n = 0; n < ctx->num_filters; n++) {
156         struct sd_filter *ft = ctx->filters[n];
157         if (ft->driver->uninit)
158             ft->driver->uninit(ft);
159         talloc_free(ft);
160     }
161     ctx->num_filters = 0;
162 }
163 
filters_init(struct sd * sd)164 static void filters_init(struct sd *sd)
165 {
166     struct sd_ass_priv *ctx = sd->priv;
167 
168     filters_destroy(sd);
169 
170     for (int n = 0; filters[n]; n++) {
171         struct sd_filter *ft = talloc_ptrtype(ctx, ft);
172         *ft = (struct sd_filter){
173             .global = sd->global,
174             .log = sd->log,
175             .opts = mp_get_config_group(ft, sd->global, &mp_sub_filter_opts),
176             .driver = filters[n],
177             .codec = "ass",
178             .event_format = ctx->ass_track->event_format,
179         };
180         if (ft->driver->init(ft)) {
181             MP_TARRAY_APPEND(ctx, ctx->filters, ctx->num_filters, ft);
182         } else {
183             talloc_free(ft);
184         }
185     }
186 }
187 
enable_output(struct sd * sd,bool enable)188 static void enable_output(struct sd *sd, bool enable)
189 {
190     struct sd_ass_priv *ctx = sd->priv;
191     if (enable == !!ctx->ass_renderer)
192         return;
193     if (ctx->ass_renderer) {
194         ass_renderer_done(ctx->ass_renderer);
195         ctx->ass_renderer = NULL;
196     } else {
197         ctx->ass_renderer = ass_renderer_init(ctx->ass_library);
198 
199         mp_ass_configure_fonts(ctx->ass_renderer, sd->opts->sub_style,
200                                sd->global, sd->log);
201     }
202 }
203 
assobjects_init(struct sd * sd)204 static void assobjects_init(struct sd *sd)
205 {
206     struct sd_ass_priv *ctx = sd->priv;
207     struct mp_subtitle_opts *opts = sd->opts;
208 
209     ctx->ass_library = mp_ass_init(sd->global, sd->log);
210     ass_set_extract_fonts(ctx->ass_library, opts->use_embedded_fonts);
211 
212     add_subtitle_fonts(sd);
213 
214     if (opts->ass_style_override)
215         ass_set_style_overrides(ctx->ass_library, opts->ass_force_style_list);
216 
217     ctx->ass_track = ass_new_track(ctx->ass_library);
218     ctx->ass_track->track_type = TRACK_TYPE_ASS;
219 
220     ctx->shadow_track = ass_new_track(ctx->ass_library);
221     ctx->shadow_track->PlayResX = 384;
222     ctx->shadow_track->PlayResY = 288;
223     mp_ass_add_default_styles(ctx->shadow_track, opts);
224 
225     char *extradata = sd->codec->extradata;
226     int extradata_size = sd->codec->extradata_size;
227     if (ctx->converter) {
228         extradata = lavc_conv_get_extradata(ctx->converter);
229         extradata_size = extradata ? strlen(extradata) : 0;
230     }
231     if (extradata)
232         ass_process_codec_private(ctx->ass_track, extradata, extradata_size);
233 
234     mp_ass_add_default_styles(ctx->ass_track, opts);
235 
236 #if LIBASS_VERSION >= 0x01302000
237     ass_set_check_readorder(ctx->ass_track, sd->opts->sub_clear_on_seek ? 0 : 1);
238 #endif
239 
240     enable_output(sd, true);
241 }
242 
assobjects_destroy(struct sd * sd)243 static void assobjects_destroy(struct sd *sd)
244 {
245     struct sd_ass_priv *ctx = sd->priv;
246 
247     ass_free_track(ctx->ass_track);
248     ass_free_track(ctx->shadow_track);
249     enable_output(sd, false);
250     ass_library_done(ctx->ass_library);
251 }
252 
init(struct sd * sd)253 static int init(struct sd *sd)
254 {
255     struct sd_ass_priv *ctx = talloc_zero(sd, struct sd_ass_priv);
256     sd->priv = ctx;
257 
258     // Note: accept "null" as alias for "ass", so EDL delay_open subtitle
259     //       streams work.
260     if (strcmp(sd->codec->codec, "ass") != 0 &&
261         strcmp(sd->codec->codec, "null") != 0)
262     {
263         ctx->is_converted = true;
264         ctx->converter = lavc_conv_create(sd->log, sd->codec->codec,
265                                           sd->codec->extradata,
266                                           sd->codec->extradata_size);
267         if (!ctx->converter)
268             return -1;
269 
270         if (strcmp(sd->codec->codec, "eia_608") == 0)
271             ctx->duration_unknown = 1;
272     }
273 
274     assobjects_init(sd);
275     filters_init(sd);
276 
277     ctx->packer = mp_ass_packer_alloc(ctx);
278 
279     return 0;
280 }
281 
282 // Note: pkt is not necessarily a fully valid refcounted packet.
filter_and_add(struct sd * sd,struct demux_packet * pkt)283 static void filter_and_add(struct sd *sd, struct demux_packet *pkt)
284 {
285     struct sd_ass_priv *ctx = sd->priv;
286     struct demux_packet *orig_pkt = pkt;
287 
288     for (int n = 0; n < ctx->num_filters; n++) {
289         struct sd_filter *ft = ctx->filters[n];
290         struct demux_packet *npkt = ft->driver->filter(ft, pkt);
291         if (pkt != npkt && pkt != orig_pkt)
292             talloc_free(pkt);
293         pkt = npkt;
294         if (!pkt)
295             return;
296     }
297 
298     ass_process_chunk(ctx->ass_track, pkt->buffer, pkt->len,
299                       llrint(pkt->pts * 1000),
300                       llrint(pkt->duration * 1000));
301 
302     if (pkt != orig_pkt)
303         talloc_free(pkt);
304 }
305 
306 // Test if the packet with the given file position (used as unique ID) was
307 // already consumed. Return false if the packet is new (and add it to the
308 // internal list), and return true if it was already seen.
check_packet_seen(struct sd * sd,int64_t pos)309 static bool check_packet_seen(struct sd *sd, int64_t pos)
310 {
311     struct sd_ass_priv *priv = sd->priv;
312     int a = 0;
313     int b = priv->num_seen_packets;
314     while (a < b) {
315         int mid = a + (b - a) / 2;
316         int64_t val = priv->seen_packets[mid];
317         if (pos == val)
318             return true;
319         if (pos > val) {
320             a = mid + 1;
321         } else {
322             b = mid;
323         }
324     }
325     MP_TARRAY_INSERT_AT(priv, priv->seen_packets, priv->num_seen_packets, a, pos);
326     return false;
327 }
328 
329 #define UNKNOWN_DURATION (INT_MAX / 1000)
330 
decode(struct sd * sd,struct demux_packet * packet)331 static void decode(struct sd *sd, struct demux_packet *packet)
332 {
333     struct sd_ass_priv *ctx = sd->priv;
334     ASS_Track *track = ctx->ass_track;
335     if (ctx->converter) {
336         if (!sd->opts->sub_clear_on_seek && packet->pos >= 0 &&
337             check_packet_seen(sd, packet->pos))
338             return;
339 
340         double sub_pts = 0;
341         double sub_duration = 0;
342         char **r = lavc_conv_decode(ctx->converter, packet, &sub_pts,
343                                     &sub_duration);
344         if (packet->duration < 0 || sub_duration == UINT32_MAX) {
345             if (!ctx->duration_unknown) {
346                 MP_WARN(sd, "Subtitle with unknown duration.\n");
347                 ctx->duration_unknown = true;
348             }
349             sub_duration = UNKNOWN_DURATION;
350         }
351 
352         for (int n = 0; r && r[n]; n++) {
353             struct demux_packet pkt2 = {
354                 .pts = sub_pts,
355                 .duration = sub_duration,
356                 .buffer = r[n],
357                 .len = strlen(r[n]),
358             };
359             filter_and_add(sd, &pkt2);
360         }
361         if (ctx->duration_unknown) {
362             for (int n = 0; n < track->n_events - 1; n++) {
363                 if (track->events[n].Duration == UNKNOWN_DURATION * 1000) {
364                     track->events[n].Duration = track->events[n + 1].Start -
365                                                 track->events[n].Start;
366                 }
367             }
368         }
369     } else {
370         // Note that for this packet format, libass has an internal mechanism
371         // for discarding duplicate (already seen) packets.
372         filter_and_add(sd, packet);
373     }
374 }
375 
configure_ass(struct sd * sd,struct mp_osd_res * dim,bool converted,ASS_Track * track)376 static void configure_ass(struct sd *sd, struct mp_osd_res *dim,
377                           bool converted, ASS_Track *track)
378 {
379     struct mp_subtitle_opts *opts = sd->opts;
380     struct sd_ass_priv *ctx = sd->priv;
381     ASS_Renderer *priv = ctx->ass_renderer;
382 
383     ass_set_frame_size(priv, dim->w, dim->h);
384     ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr);
385 
386     bool set_use_margins = false;
387     int set_sub_pos = 0;
388     float set_line_spacing = 0;
389     float set_font_scale = 1;
390     int set_hinting = 0;
391     bool set_scale_with_window = false;
392     bool set_scale_by_window = true;
393     bool total_override = false;
394     // With forced overrides, apply the --sub-* specific options
395     if (converted || opts->ass_style_override == 3) { // 'force'
396         set_scale_with_window = opts->sub_scale_with_window;
397         set_use_margins = opts->sub_use_margins;
398         set_scale_by_window = opts->sub_scale_by_window;
399         total_override = true;
400     } else {
401         set_scale_with_window = opts->ass_scale_with_window;
402         set_use_margins = opts->ass_use_margins;
403     }
404     if (converted || opts->ass_style_override) {
405         set_sub_pos = 100 - opts->sub_pos;
406         set_line_spacing = opts->ass_line_spacing;
407         set_hinting = opts->ass_hinting;
408         set_font_scale = opts->sub_scale;
409     }
410     if (set_scale_with_window) {
411         int vidh = dim->h - (dim->mt + dim->mb);
412         set_font_scale *= dim->h / (float)MPMAX(vidh, 1);
413     }
414     if (!set_scale_by_window) {
415         double factor = dim->h / 720.0;
416         if (factor != 0.0)
417             set_font_scale /= factor;
418     }
419     ass_set_use_margins(priv, set_use_margins);
420     ass_set_line_position(priv, set_sub_pos);
421     ass_set_shaper(priv, opts->ass_shaper);
422     int set_force_flags = 0;
423     if (total_override)
424         set_force_flags |= ASS_OVERRIDE_BIT_STYLE | ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE;
425     if (opts->ass_style_override == 4) // 'scale'
426         set_force_flags |= ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE;
427     if (converted)
428         set_force_flags |= ASS_OVERRIDE_BIT_ALIGNMENT;
429 #ifdef ASS_JUSTIFY_AUTO
430     if ((converted || opts->ass_style_override) && opts->ass_justify)
431         set_force_flags |= ASS_OVERRIDE_BIT_JUSTIFY;
432 #endif
433     ass_set_selective_style_override_enabled(priv, set_force_flags);
434     ASS_Style style = {0};
435     mp_ass_set_style(&style, 288, opts->sub_style);
436     ass_set_selective_style_override(priv, &style);
437     free(style.FontName);
438     if (converted && track->default_style < track->n_styles) {
439         mp_ass_set_style(track->styles + track->default_style,
440                          track->PlayResY, opts->sub_style);
441     }
442     ass_set_font_scale(priv, set_font_scale);
443     ass_set_hinting(priv, set_hinting);
444     ass_set_line_spacing(priv, set_line_spacing);
445 }
446 
has_overrides(char * s)447 static bool has_overrides(char *s)
448 {
449     if (!s)
450         return false;
451     return strstr(s, "\\pos") || strstr(s, "\\move") || strstr(s, "\\clip") ||
452            strstr(s, "\\iclip") || strstr(s, "\\org") || strstr(s, "\\p");
453 }
454 
455 #define END(ev) ((ev)->Start + (ev)->Duration)
456 
find_timestamp(struct sd * sd,double pts)457 static long long find_timestamp(struct sd *sd, double pts)
458 {
459     struct sd_ass_priv *priv = sd->priv;
460     if (pts == MP_NOPTS_VALUE)
461         return 0;
462 
463     long long ts = llrint(pts * 1000);
464 
465     if (!sd->opts->sub_fix_timing || sd->opts->ass_style_override == 0)
466         return ts;
467 
468     // Try to fix small gaps and overlaps.
469     ASS_Track *track = priv->ass_track;
470     int threshold = SUB_GAP_THRESHOLD * 1000;
471     int keep = SUB_GAP_KEEP * 1000;
472 
473     // Find the "current" event.
474     ASS_Event *ev[2] = {0};
475     int n_ev = 0;
476     for (int n = 0; n < track->n_events; n++) {
477         ASS_Event *event = &track->events[n];
478         if (ts >= event->Start - threshold && ts <= END(event) + threshold) {
479             if (n_ev >= MP_ARRAY_SIZE(ev))
480                 return ts; // multiple overlaps - give up (probably complex subs)
481             ev[n_ev++] = event;
482         }
483     }
484 
485     if (n_ev != 2)
486         return ts;
487 
488     // Simple/minor heuristic against destroying typesetting.
489     if (ev[0]->Style != ev[1]->Style || has_overrides(ev[0]->Text) ||
490         has_overrides(ev[1]->Text))
491         return ts;
492 
493     // Sort by start timestamps.
494     if (ev[0]->Start > ev[1]->Start)
495         MPSWAP(ASS_Event*, ev[0], ev[1]);
496 
497     // We want to fix partial overlaps only.
498     if (END(ev[0]) >= END(ev[1]))
499         return ts;
500 
501     if (ev[0]->Duration < keep || ev[1]->Duration < keep)
502         return ts;
503 
504     // Gap between the events -> move ts to show the end of the first event.
505     if (ts >= END(ev[0]) && ts < ev[1]->Start && END(ev[0]) < ev[1]->Start &&
506         END(ev[0]) + threshold >= ev[1]->Start)
507         return END(ev[0]) - 1;
508 
509     // Overlap -> move ts to the (exclusive) end of the first event.
510     // Relies on the fact that the ASS_Renderer has no overlap registered, even
511     // if there is one. This happens to work because we never render the
512     // overlapped state, and libass never resolves a collision.
513     if (ts >= ev[1]->Start && ts <= END(ev[0]) && END(ev[0]) > ev[1]->Start &&
514         END(ev[0]) <= ev[1]->Start + threshold)
515         return END(ev[0]);
516 
517     return ts;
518 }
519 
520 #undef END
521 
get_bitmaps(struct sd * sd,struct mp_osd_res dim,int format,double pts)522 static struct sub_bitmaps *get_bitmaps(struct sd *sd, struct mp_osd_res dim,
523                                        int format, double pts)
524 {
525     struct sd_ass_priv *ctx = sd->priv;
526     struct mp_subtitle_opts *opts = sd->opts;
527     bool no_ass = !opts->ass_enabled || ctx->on_top ||
528                   opts->ass_style_override == 5;
529     bool converted = ctx->is_converted || no_ass;
530     ASS_Track *track = no_ass ? ctx->shadow_track : ctx->ass_track;
531     ASS_Renderer *renderer = ctx->ass_renderer;
532     struct sub_bitmaps *res = &(struct sub_bitmaps){0};
533 
534     if (pts == MP_NOPTS_VALUE || !renderer)
535         goto done;
536 
537     // Currently no supported text sub formats support a distinction between forced
538     // and unforced lines, so we just assume everything's unforced and discard everything.
539     // If we ever see a format that makes this distinction, we can add support here.
540     if (opts->forced_subs_only_current)
541         goto done;
542 
543     double scale = dim.display_par;
544     if (!converted && (!opts->ass_style_override ||
545                        opts->ass_vsfilter_aspect_compat))
546     {
547         // Let's use the original video PAR for vsfilter compatibility:
548         double par = ctx->video_params.p_w / (double)ctx->video_params.p_h;
549         if (isnormal(par))
550             scale *= par;
551     }
552     configure_ass(sd, &dim, converted, track);
553     ass_set_pixel_aspect(renderer, scale);
554     if (!converted && (!opts->ass_style_override ||
555                        opts->ass_vsfilter_blur_compat))
556     {
557         ass_set_storage_size(renderer, ctx->video_params.w, ctx->video_params.h);
558     } else {
559         ass_set_storage_size(renderer, 0, 0);
560     }
561     long long ts = find_timestamp(sd, pts);
562     if (ctx->duration_unknown && pts != MP_NOPTS_VALUE) {
563         mp_ass_flush_old_events(track, ts);
564         ctx->num_seen_packets = 0;
565         sd->preload_ok = false;
566     }
567 
568     if (no_ass)
569         fill_plaintext(sd, pts);
570 
571     int changed;
572     ASS_Image *imgs = ass_render_frame(renderer, track, ts, &changed);
573     mp_ass_packer_pack(ctx->packer, &imgs, 1, changed, format, res);
574 
575 done:
576     // mangle_colors() modifies the color field, so copy the thing _before_.
577     res = sub_bitmaps_copy(&ctx->copy_cache, res);
578 
579     if (!converted && res)
580         mangle_colors(sd, res);
581 
582     return res;
583 }
584 
585 struct buf {
586     char *start;
587     int size;
588     int len;
589 };
590 
append(struct buf * b,char c)591 static void append(struct buf *b, char c)
592 {
593     if (b->len < b->size) {
594         b->start[b->len] = c;
595         b->len++;
596     }
597 }
598 
ass_to_plaintext(struct buf * b,const char * in)599 static void ass_to_plaintext(struct buf *b, const char *in)
600 {
601     bool in_tag = false;
602     const char *open_tag_pos = NULL;
603     bool in_drawing = false;
604     while (*in) {
605         if (in_tag) {
606             if (in[0] == '}') {
607                 in += 1;
608                 in_tag = false;
609             } else if (in[0] == '\\' && in[1] == 'p') {
610                 in += 2;
611                 // Skip text between \pN and \p0 tags. A \p without a number
612                 // is the same as \p0, and leading 0s are also allowed.
613                 in_drawing = false;
614                 while (in[0] >= '0' && in[0] <= '9') {
615                     if (in[0] != '0')
616                         in_drawing = true;
617                     in += 1;
618                 }
619             } else {
620                 in += 1;
621             }
622         } else {
623             if (in[0] == '\\' && (in[1] == 'N' || in[1] == 'n')) {
624                 in += 2;
625                 append(b, '\n');
626             } else if (in[0] == '\\' && in[1] == 'h') {
627                 in += 2;
628                 append(b, ' ');
629             } else if (in[0] == '{') {
630                 open_tag_pos = in;
631                 in += 1;
632                 in_tag = true;
633             } else {
634                 if (!in_drawing)
635                     append(b, in[0]);
636                 in += 1;
637             }
638         }
639     }
640     // A '{' without a closing '}' is always visible.
641     if (in_tag) {
642         while (*open_tag_pos)
643             append(b, *open_tag_pos++);
644     }
645 }
646 
647 // Empty string counts as whitespace. Reads s[len-1] even if there are \0s.
is_whitespace_only(char * s,int len)648 static bool is_whitespace_only(char *s, int len)
649 {
650     for (int n = 0; n < len; n++) {
651         if (s[n] != ' ' && s[n] != '\t')
652             return false;
653     }
654     return true;
655 }
656 
get_text_buf(struct sd * sd,double pts,enum sd_text_type type)657 static char *get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
658 {
659     struct sd_ass_priv *ctx = sd->priv;
660     ASS_Track *track = ctx->ass_track;
661 
662     if (pts == MP_NOPTS_VALUE)
663         return NULL;
664     long long ipts = find_timestamp(sd, pts);
665 
666     struct buf b = {ctx->last_text, sizeof(ctx->last_text) - 1};
667 
668     for (int i = 0; i < track->n_events; ++i) {
669         ASS_Event *event = track->events + i;
670         if (ipts >= event->Start && ipts < event->Start + event->Duration) {
671             if (event->Text) {
672                 int start = b.len;
673                 if (type == SD_TEXT_TYPE_PLAIN) {
674                     ass_to_plaintext(&b, event->Text);
675                 } else {
676                     char *t = event->Text;
677                     while (*t)
678                         append(&b, *t++);
679                 }
680                 if (is_whitespace_only(&b.start[start], b.len - start)) {
681                     b.len = start;
682                 } else {
683                     append(&b, '\n');
684                 }
685             }
686         }
687     }
688 
689     b.start[b.len] = '\0';
690 
691     if (b.len > 0 && b.start[b.len - 1] == '\n')
692         b.start[b.len - 1] = '\0';
693 
694     return ctx->last_text;
695 }
696 
get_text(struct sd * sd,double pts,enum sd_text_type type)697 static char *get_text(struct sd *sd, double pts, enum sd_text_type type)
698 {
699     return talloc_strdup(NULL, get_text_buf(sd, pts, type));
700 }
701 
get_times(struct sd * sd,double pts)702 static struct sd_times get_times(struct sd *sd, double pts)
703 {
704     struct sd_ass_priv *ctx = sd->priv;
705     ASS_Track *track = ctx->ass_track;
706     struct sd_times res = { .start = MP_NOPTS_VALUE, .end = MP_NOPTS_VALUE };
707 
708     if (pts == MP_NOPTS_VALUE || ctx->duration_unknown)
709         return res;
710 
711     long long ipts = find_timestamp(sd, pts);
712 
713     for (int i = 0; i < track->n_events; ++i) {
714         ASS_Event *event = track->events + i;
715         if (ipts >= event->Start && ipts < event->Start + event->Duration) {
716             double start = event->Start / 1000.0;
717             double end = event->Duration == UNKNOWN_DURATION ?
718                 MP_NOPTS_VALUE : (event->Start + event->Duration) / 1000.0;
719 
720             if (res.start == MP_NOPTS_VALUE || res.start > start)
721                 res.start = start;
722 
723             if (res.end == MP_NOPTS_VALUE || res.end < end)
724                 res.end = end;
725         }
726     }
727 
728     return res;
729 }
730 
fill_plaintext(struct sd * sd,double pts)731 static void fill_plaintext(struct sd *sd, double pts)
732 {
733     struct sd_ass_priv *ctx = sd->priv;
734     ASS_Track *track = ctx->shadow_track;
735 
736     ass_flush_events(track);
737 
738     char *text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
739     if (!text)
740         return;
741 
742     bstr dst = {0};
743 
744     if (ctx->on_top)
745         bstr_xappend(NULL, &dst, bstr0("{\\a6}"));
746 
747     while (*text) {
748         if (*text == '{')
749             bstr_xappend(NULL, &dst, bstr0("\\"));
750         bstr_xappend(NULL, &dst, (bstr){text, 1});
751         // Break ASS escapes with U+2060 WORD JOINER
752         if (*text == '\\')
753             mp_append_utf8_bstr(NULL, &dst, 0x2060);
754         text++;
755     }
756 
757     if (!dst.start)
758         return;
759 
760     int n = ass_alloc_event(track);
761     ASS_Event *event = track->events + n;
762     event->Start = 0;
763     event->Duration = INT_MAX;
764     event->Style = track->default_style;
765     event->Text = strdup(dst.start);
766 
767     talloc_free(dst.start);
768 }
769 
reset(struct sd * sd)770 static void reset(struct sd *sd)
771 {
772     struct sd_ass_priv *ctx = sd->priv;
773     if (sd->opts->sub_clear_on_seek || ctx->duration_unknown || ctx->clear_once) {
774         ass_flush_events(ctx->ass_track);
775         ctx->num_seen_packets = 0;
776         sd->preload_ok = false;
777         ctx->clear_once = false;
778     }
779     if (ctx->converter)
780         lavc_conv_reset(ctx->converter);
781 }
782 
uninit(struct sd * sd)783 static void uninit(struct sd *sd)
784 {
785     struct sd_ass_priv *ctx = sd->priv;
786 
787     filters_destroy(sd);
788     if (ctx->converter)
789         lavc_conv_uninit(ctx->converter);
790     assobjects_destroy(sd);
791     talloc_free(ctx->copy_cache);
792 }
793 
control(struct sd * sd,enum sd_ctrl cmd,void * arg)794 static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
795 {
796     struct sd_ass_priv *ctx = sd->priv;
797     switch (cmd) {
798     case SD_CTRL_SUB_STEP: {
799         double *a = arg;
800         long long ts = llrint(a[0] * 1000.0);
801         long long res = ass_step_sub(ctx->ass_track, ts, a[1]);
802         if (!res)
803             return false;
804         a[0] += res / 1000.0;
805         return true;
806     }
807     case SD_CTRL_SET_VIDEO_PARAMS:
808         ctx->video_params = *(struct mp_image_params *)arg;
809         return CONTROL_OK;
810     case SD_CTRL_SET_TOP:
811         ctx->on_top = *(bool *)arg;
812         return CONTROL_OK;
813     case SD_CTRL_UPDATE_OPTS: {
814         int flags = (uintptr_t)arg;
815         if (flags & UPDATE_SUB_FILT) {
816             filters_destroy(sd);
817             filters_init(sd);
818             ctx->clear_once = true; // allow reloading on seeks
819         }
820         if (flags & UPDATE_SUB_HARD) {
821             assobjects_destroy(sd);
822             assobjects_init(sd);
823         }
824         return CONTROL_OK;
825     }
826     default:
827         return CONTROL_UNKNOWN;
828     }
829 }
830 
831 const struct sd_functions sd_ass = {
832     .name = "ass",
833     .accept_packets_in_advance = true,
834     .init = init,
835     .decode = decode,
836     .get_bitmaps = get_bitmaps,
837     .get_text = get_text,
838     .get_times = get_times,
839     .control = control,
840     .reset = reset,
841     .select = enable_output,
842     .uninit = uninit,
843 };
844 
845 // Disgusting hack for (xy-)vsfilter color compatibility.
mangle_colors(struct sd * sd,struct sub_bitmaps * parts)846 static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts)
847 {
848     struct mp_subtitle_opts *opts = sd->opts;
849     struct sd_ass_priv *ctx = sd->priv;
850     enum mp_csp csp = 0;
851     enum mp_csp_levels levels = 0;
852     if (opts->ass_vsfilter_color_compat == 0) // "no"
853         return;
854     bool force_601 = opts->ass_vsfilter_color_compat == 3;
855     ASS_Track *track = ctx->ass_track;
856     static const int ass_csp[] = {
857         [YCBCR_BT601_TV]        = MP_CSP_BT_601,
858         [YCBCR_BT601_PC]        = MP_CSP_BT_601,
859         [YCBCR_BT709_TV]        = MP_CSP_BT_709,
860         [YCBCR_BT709_PC]        = MP_CSP_BT_709,
861         [YCBCR_SMPTE240M_TV]    = MP_CSP_SMPTE_240M,
862         [YCBCR_SMPTE240M_PC]    = MP_CSP_SMPTE_240M,
863     };
864     static const int ass_levels[] = {
865         [YCBCR_BT601_TV]        = MP_CSP_LEVELS_TV,
866         [YCBCR_BT601_PC]        = MP_CSP_LEVELS_PC,
867         [YCBCR_BT709_TV]        = MP_CSP_LEVELS_TV,
868         [YCBCR_BT709_PC]        = MP_CSP_LEVELS_PC,
869         [YCBCR_SMPTE240M_TV]    = MP_CSP_LEVELS_TV,
870         [YCBCR_SMPTE240M_PC]    = MP_CSP_LEVELS_PC,
871     };
872     int trackcsp = track->YCbCrMatrix;
873     if (force_601)
874         trackcsp = YCBCR_BT601_TV;
875     // NONE is a bit random, but the intention is: don't modify colors.
876     if (trackcsp == YCBCR_NONE)
877         return;
878     if (trackcsp < sizeof(ass_csp) / sizeof(ass_csp[0]))
879         csp = ass_csp[trackcsp];
880     if (trackcsp < sizeof(ass_levels) / sizeof(ass_levels[0]))
881         levels = ass_levels[trackcsp];
882     if (trackcsp == YCBCR_DEFAULT) {
883         csp = MP_CSP_BT_601;
884         levels = MP_CSP_LEVELS_TV;
885     }
886     // Unknown colorspace (either YCBCR_UNKNOWN, or a valid value unknown to us)
887     if (!csp || !levels)
888         return;
889 
890     struct mp_image_params params = ctx->video_params;
891 
892     if (force_601) {
893         params.color = (struct mp_colorspace){
894             .space = MP_CSP_BT_709,
895             .levels = MP_CSP_LEVELS_TV,
896         };
897     }
898 
899     if (csp == params.color.space && levels == params.color.levels)
900         return;
901 
902     bool basic_conv = params.color.space == MP_CSP_BT_709 &&
903                       params.color.levels == MP_CSP_LEVELS_TV &&
904                       csp == MP_CSP_BT_601 &&
905                       levels == MP_CSP_LEVELS_TV;
906 
907     // With "basic", only do as much as needed for basic compatibility.
908     if (opts->ass_vsfilter_color_compat == 1 && !basic_conv)
909         return;
910 
911     if (params.color.space != ctx->last_params.color.space ||
912         params.color.levels != ctx->last_params.color.levels)
913     {
914         int msgl = basic_conv ? MSGL_V : MSGL_WARN;
915         ctx->last_params = params;
916         MP_MSG(sd, msgl, "mangling colors like vsfilter: "
917                "RGB -> %s %s -> %s %s -> RGB\n",
918                m_opt_choice_str(mp_csp_names, csp),
919                m_opt_choice_str(mp_csp_levels_names, levels),
920                m_opt_choice_str(mp_csp_names, params.color.space),
921                m_opt_choice_str(mp_csp_names, params.color.levels));
922     }
923 
924     // Conversion that VSFilter would use
925     struct mp_csp_params vs_params = MP_CSP_PARAMS_DEFAULTS;
926     vs_params.color.space = csp;
927     vs_params.color.levels = levels;
928     struct mp_cmat vs_yuv2rgb, vs_rgb2yuv;
929     mp_get_csp_matrix(&vs_params, &vs_yuv2rgb);
930     mp_invert_cmat(&vs_rgb2yuv, &vs_yuv2rgb);
931 
932     // Proper conversion to RGB
933     struct mp_csp_params rgb_params = MP_CSP_PARAMS_DEFAULTS;
934     rgb_params.color = params.color;
935     struct mp_cmat vs2rgb;
936     mp_get_csp_matrix(&rgb_params, &vs2rgb);
937 
938     for (int n = 0; n < parts->num_parts; n++) {
939         struct sub_bitmap *sb = &parts->parts[n];
940         uint32_t color = sb->libass.color;
941         int r = (color >> 24u) & 0xff;
942         int g = (color >> 16u) & 0xff;
943         int b = (color >>  8u) & 0xff;
944         int a = 0xff - (color & 0xff);
945         int rgb[3] = {r, g, b}, yuv[3];
946         mp_map_fixp_color(&vs_rgb2yuv, 8, rgb, 8, yuv);
947         mp_map_fixp_color(&vs2rgb, 8, yuv, 8, rgb);
948         sb->libass.color = MP_ASS_RGBA(rgb[0], rgb[1], rgb[2], a);
949     }
950 }
951 
sd_ass_fmt_offset(const char * evt_fmt)952 int sd_ass_fmt_offset(const char *evt_fmt)
953 {
954     // "Text" is always last (as it's arbitrary content in buf), e.g. format:
955     // "Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"
956     int n = 0;
957     while (evt_fmt && (evt_fmt = strchr(evt_fmt, ',')))
958          evt_fmt++, n++;
959     return n-1;  // buffer is without the format's Start/End, with ReadOrder
960 }
961 
sd_ass_pkt_text(struct sd_filter * ft,struct demux_packet * pkt,int offset)962 bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset)
963 {
964     // e.g. pkt->buffer ("4" is ReadOrder): "4,0,Default,,0,0,0,,fifth line"
965     bstr txt = {(char *)pkt->buffer, pkt->len}, t0 = txt;
966     while (offset-- > 0) {
967         int n = bstrchr(txt, ',');
968         if (n < 0) {  // shouldn't happen
969             MP_WARN(ft, "Malformed event '%.*s'\n", BSTR_P(t0));
970             return (bstr){NULL, 0};
971         }
972         txt = bstr_cut(txt, n+1);
973     }
974     return txt;
975 }
976 
sd_ass_to_plaintext(char * out,size_t out_siz,const char * in)977 bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in)
978 {
979     struct buf b = {out, out_siz, 0};
980     ass_to_plaintext(&b, in);
981     if (b.len < out_siz)
982         out[b.len] = 0;
983     return (bstr){out, b.len};
984 }
985