diff --git a/ass_mp.c b/ass_mp.c index 31acb521b8..364adafd64 100644 --- a/ass_mp.c +++ b/ass_mp.c @@ -154,7 +154,7 @@ static int check_duplicate_plaintext_event(ASS_Track *track) * note: assumes that subtitle is _not_ fps-based; caller must manually correct * Start and Duration in other case. **/ -int ass_process_subtitle(ASS_Track *track, subtitle *sub) +static int ass_process_subtitle(ASS_Track *track, subtitle *sub) { int eid; ASS_Event *event; diff --git a/ass_mp.h b/ass_mp.h index 0694426898..2966f9527a 100644 --- a/ass_mp.h +++ b/ass_mp.h @@ -44,7 +44,6 @@ extern char *ass_styles_file; extern int ass_hinting; ASS_Track *ass_default_track(ASS_Library *library); -int ass_process_subtitle(ASS_Track *track, subtitle *sub); ASS_Track *ass_read_subdata(ASS_Library *library, sub_data *subdata, double fps); ASS_Track *ass_read_stream(ASS_Library *library, const char *fname, char *charset); diff --git a/sub/sd_ass.c b/sub/sd_ass.c index a25d50a805..5eae2ebc28 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "talloc.h" @@ -27,11 +28,20 @@ #include "libvo/sub.h" #include "ass_mp.h" #include "sd.h" +#include "subassconvert.h" struct sd_ass_priv { struct ass_track *ass_track; + bool incomplete_event; }; +static void free_last_event(ASS_Track *track) +{ + assert(track->n_events > 0); + ass_free_event(track, track->n_events - 1); + track->n_events--; +} + static void init(struct sh_sub *sh, struct osd_state *osd) { struct sd_ass_priv *ctx; @@ -57,28 +67,71 @@ static void init(struct sh_sub *sh, struct osd_state *osd) static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration) { + unsigned char *text = data; struct sd_ass_priv *ctx = sh->context; + ASS_Track *track = ctx->ass_track; if (sh->type == 'a') { // ssa/ass subs - ass_process_chunk(ctx->ass_track, data, data_len, + ass_process_chunk(track, data, data_len, (long long)(pts*1000 + 0.5), (long long)(duration*1000 + 0.5)); - } else { // plaintext subs - if (pts != MP_NOPTS_VALUE) { - subtitle tmp_subs = {0}; - if (duration <= 0) - duration = 3; - sub_add_text(&tmp_subs, data, data_len, pts + duration); - tmp_subs.start = pts * 100; - tmp_subs.end = (pts + duration) * 100; - ass_process_subtitle(ctx->ass_track, &tmp_subs); - sub_clear_text(&tmp_subs, MP_NOPTS_VALUE); - } + return; } + // plaintext subs + if (pts == MP_NOPTS_VALUE) { + mp_msg(MSGT_SUBREADER, MSGL_WARN, "Subtitle without pts, ignored\n"); + return; + } + long long ipts = pts * 1000 + 0.5; + long long iduration = duration * 1000 + 0.5; + if (ctx->incomplete_event) { + ctx->incomplete_event = false; + ASS_Event *event = track->events + track->n_events - 1; + if (ipts <= event->Start) + free_last_event(track); + else + event->Duration = ipts - event->Start; + } + // Note: we rely on there being guaranteed 0 bytes after data packets + int len = strlen(text); + if (len < 5) { + // Some tracks use a whitespace (but not empty) packet to mark end + // of previous subtitle. + for (int i = 0; i < len; i++) + if (!strchr(" \f\n\r\t\v", text[i])) + goto not_all_whitespace; + return; + } + not_all_whitespace:; + char buf[500]; + subassconvert_subrip(text, buf, sizeof(buf)); + for (int i = 0; i < track->n_events; i++) + if (track->events[i].Start == ipts + && (duration <= 0 || track->events[i].Duration == iduration) + && strcmp(track->events[i].Text, buf) == 0) + return; // We've already added this subtitle + if (duration <= 0) { + iduration = 10000; + ctx->incomplete_event = true; + } + int eid = ass_alloc_event(track); + ASS_Event *event = track->events + eid; + event->Start = ipts; + event->Duration = iduration; + event->Text = strdup(buf); +} + +static void reset(struct sh_sub *sh, struct osd_state *osd) +{ + struct sd_ass_priv *ctx = sh->context; + if (ctx->incomplete_event) + free_last_event(ctx->ass_track); + ctx->incomplete_event = false; } static void switch_off(struct sh_sub *sh, struct osd_state *osd) { + reset(sh, osd); osd->ass_track = NULL; } @@ -93,6 +146,7 @@ static void uninit(struct sh_sub *sh) const struct sd_functions sd_ass = { .init = init, .decode = decode, + .reset = reset, .switch_off = switch_off, .uninit = uninit, };