mirror of
https://github.com/mpv-player/mpv
synced 2024-12-24 15:52:25 +00:00
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.
This commit is contained in:
parent
4284cf9ef0
commit
7bb10e7ce2
2
ass_mp.c
2
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;
|
||||
|
1
ass_mp.h
1
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);
|
||||
|
78
sub/sd_ass.c
78
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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user