From e990fb2ffeaa786339895c8f3b3f104ef536bf39 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 16 Jan 2011 20:03:08 +0200 Subject: subtitles: add framework for subtitle decoders Add a framework for subtitle decoder modules that work more like audio/video decoders do, and change libass rendering of demuxed subtitles to use the new framework. The old subtitle code is messy, with details specific to handling particular subtitle types spread over high-level code. This should make it easier to clean things up and fix some bugs/limitations. --- sub/sd_ass.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 sub/sd_ass.c (limited to 'sub/sd_ass.c') diff --git a/sub/sd_ass.c b/sub/sd_ass.c new file mode 100644 index 0000000000..a25d50a805 --- /dev/null +++ b/sub/sd_ass.c @@ -0,0 +1,98 @@ +/* + * 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 +#include +#include + +#include "talloc.h" + +#include "mpcommon.h" +#include "libmpdemux/stheader.h" +#include "libvo/sub.h" +#include "ass_mp.h" +#include "sd.h" + +struct sd_ass_priv { + struct ass_track *ass_track; +}; + +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 = ass_default_track(ass_library); + } + + assert(osd->ass_track == NULL); + osd->ass_track = ctx->ass_track; +} + +static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, + int data_len, double pts, double duration) +{ + struct sd_ass_priv *ctx = sh->context; + + if (sh->type == 'a') { // ssa/ass subs + ass_process_chunk(ctx->ass_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); + } + } +} + +static void switch_off(struct sh_sub *sh, struct osd_state *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, + .switch_off = switch_off, + .uninit = uninit, +}; -- cgit v1.2.3 From 7bb10e7ce2683da43345a60584c63479751366ff Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Tue, 18 Jan 2011 15:33:36 +0200 Subject: sd_ass: remove subreader use, support plaintext markup Originally, when rendering plaintext subs with libass, the subtitles were first converted to the "struct subtitle" form with sub_add_text() and then from that to libass events. Change sd_ass to convert the subtitles directly to libass events without using the old sub machinery. The new conversion at least fixes some timing issues. Also use the markup support added in the previous commit, so that HTML-style markup is also supported in "plaintext" subs rendered with libass. --- sub/sd_ass.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 12 deletions(-) (limited to 'sub/sd_ass.c') 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, }; -- cgit v1.2.3 From 966340b31a7bc53e922118da1cd4783d6a06483d Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Wed, 19 Jan 2011 20:13:48 +0200 Subject: subs: use correct font aspect ratio for libass + converted subs Rendering of ASS subtitles tries to be bug compatible with VSFilter and stretches fonts when the video is anamorphic (some scripts try to compensate for this VSFilter behavior, so trying to render them "correctly" would give the wrong result). However this behavior is not appropriate for subtitles we converted to ASS format ourselves for libass rendering, as they certainly don't have VSFilter bug workarounds. Change the code to use different behavior for "native" ASS tracks and converted ones. It's questionable whether the VSFilter-compatible behavior is appropriate for external .ass files either, as there could be anamorphic and non-anamorphic versions of the same video and the bug-compatible behavior can only be correct for one alternative at most. However it's probably better to keep it as a default at least, so that extracting a muxed subtitle track and using that does not give behavior different from the original muxed one. The aspect ratio setting is per ASS_Renderer, and changing it resets libass caches. For that reason this commit adds separate renderer instances to use for the "correct" and "VSFilter bug compatible" cases. --- sub/sd_ass.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sub/sd_ass.c') diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 5eae2ebc28..a5879873a9 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -62,6 +62,8 @@ static void init(struct sh_sub *sh, struct osd_state *osd) 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, -- cgit v1.2.3 From a248c2c7a137517061e6271f22b84d43bcd7191d Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Thu, 20 Jan 2011 18:47:18 +0200 Subject: cleanup: rename ass_* functions to mp_ass_* The various ass_* functions were created when libass was part of the MPlayer tree and the distinction between MPlayer-specific and other functions was less clear. Now that libass is a clearly separate library, using the same ass_* namespace for player functions is ugly. Rename the functions to use mp_ass_ prefix instead. --- sub/sd_ass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sub/sd_ass.c') diff --git a/sub/sd_ass.c b/sub/sd_ass.c index a5879873a9..be2740bfa6 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -57,7 +57,7 @@ static void init(struct sh_sub *sh, struct osd_state *osd) ass_process_codec_private(ctx->ass_track, sh->extradata, sh->extradata_len); } else - ctx->ass_track = ass_default_track(ass_library); + ctx->ass_track = mp_ass_default_track(ass_library); } assert(osd->ass_track == NULL); -- cgit v1.2.3 From c9026cb3210205b07e2e068467a18ee40f9259a3 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Wed, 26 Jan 2011 19:40:52 +0200 Subject: sub/OSD: move some related files to sub/ --- sub/sd_ass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sub/sd_ass.c') diff --git a/sub/sd_ass.c b/sub/sd_ass.c index be2740bfa6..ba5710611e 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -25,7 +25,7 @@ #include "mpcommon.h" #include "libmpdemux/stheader.h" -#include "libvo/sub.h" +#include "sub.h" #include "ass_mp.h" #include "sd.h" #include "subassconvert.h" -- cgit v1.2.3