diff options
Diffstat (limited to 'sub/sd_ass.c')
-rw-r--r-- | sub/sd_ass.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/sub/sd_ass.c b/sub/sd_ass.c new file mode 100644 index 0000000000..ba5710611e --- /dev/null +++ b/sub/sd_ass.c @@ -0,0 +1,154 @@ +/* + * 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <ass/ass.h> +#include <assert.h> +#include <string.h> + +#include "talloc.h" + +#include "mpcommon.h" +#include "libmpdemux/stheader.h" +#include "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; + + if (sh->initialized) { + ctx = sh->context; + } else { + ctx = talloc_zero(NULL, struct sd_ass_priv); + sh->context = ctx; + if (sh->type == 'a') { + ctx->ass_track = ass_new_track(ass_library); + if (sh->extradata) + ass_process_codec_private(ctx->ass_track, sh->extradata, + sh->extradata_len); + } else + ctx->ass_track = mp_ass_default_track(ass_library); + } + + assert(osd->ass_track == NULL); + osd->ass_track = ctx->ass_track; + osd->vsfilter_aspect = sh->type == 'a'; + osd->ass_track_changed = true; +} + +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(track, data, data_len, + (long long)(pts*1000 + 0.5), + (long long)(duration*1000 + 0.5)); + 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; +} + +static void uninit(struct sh_sub *sh) +{ + struct sd_ass_priv *ctx = sh->context; + + ass_free_track(ctx->ass_track); + talloc_free(ctx); +} + +const struct sd_functions sd_ass = { + .init = init, + .decode = decode, + .reset = reset, + .switch_off = switch_off, + .uninit = uninit, +}; |