summaryrefslogtreecommitdiffstats
path: root/sub/sd_ass.c
diff options
context:
space:
mode:
Diffstat (limited to 'sub/sd_ass.c')
-rw-r--r--sub/sd_ass.c78
1 files changed, 66 insertions, 12 deletions
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 <stdlib.h>
#include <ass/ass.h>
#include <assert.h>
+#include <string.h>
#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,
};