mirror of
https://github.com/mpv-player/mpv
synced 2025-04-18 05:07:18 +00:00
Subtitle handling cleanup: factor out code for parsing embedded subtitles
and adding and removing of lines in subtitle struct into subreader.c. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@21845 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
20a7d46a88
commit
61e4a80191
@ -166,7 +166,6 @@ typedef struct mkv_demuxer
|
||||
uint64_t tc_scale, cluster_tc, first_tc;
|
||||
int has_first_tc;
|
||||
|
||||
uint64_t clear_subs_at[SUB_MAX_TEXT];
|
||||
subtitle subs;
|
||||
|
||||
uint64_t cluster_size;
|
||||
@ -2490,9 +2489,6 @@ demux_mkv_open (demuxer_t *demuxer)
|
||||
mkv_d->parsed_cues = malloc (sizeof (off_t));
|
||||
mkv_d->parsed_seekhead = malloc (sizeof (off_t));
|
||||
|
||||
for (i=0; i < SUB_MAX_TEXT; i++)
|
||||
mkv_d->subs.text[i] = malloc (256);
|
||||
|
||||
while (!cont)
|
||||
{
|
||||
switch (ebml_read_id (s, NULL))
|
||||
@ -2724,6 +2720,9 @@ demux_mkv_open (demuxer_t *demuxer)
|
||||
return DEMUXER_TYPE_MATROSKA;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_subtitles(demuxer_t *demuxer, uint64_t timecode, int clear_all);
|
||||
|
||||
static void
|
||||
demux_close_mkv (demuxer_t *demuxer)
|
||||
{
|
||||
@ -2735,14 +2734,12 @@ demux_close_mkv (demuxer_t *demuxer)
|
||||
#ifdef USE_ICONV
|
||||
subcp_close();
|
||||
#endif
|
||||
clear_subtitles(demuxer, 0, 1);
|
||||
free_cached_dps (demuxer);
|
||||
if (mkv_d->tracks)
|
||||
{
|
||||
for (i=0; i<mkv_d->num_tracks; i++)
|
||||
demux_mkv_free_trackentry(mkv_d->tracks[i]);
|
||||
for (i=0; i < SUB_MAX_TEXT; i++)
|
||||
if (mkv_d->subs.text[i])
|
||||
free (mkv_d->subs.text[i]);
|
||||
free (mkv_d->tracks);
|
||||
}
|
||||
if (mkv_d->indexes)
|
||||
@ -2854,16 +2851,13 @@ demux_mkv_read_block_lacing (uint8_t *buffer, uint64_t *size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_subtitles(demuxer_t *demuxer, uint64_t timecode, int clear_all);
|
||||
|
||||
static void
|
||||
handle_subtitles(demuxer_t *demuxer, mkv_track_t *track, char *block,
|
||||
int64_t size, uint64_t block_duration, uint64_t timecode)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
char *ptr1, *ptr2;
|
||||
int state, i;
|
||||
char *ptr1;
|
||||
int i;
|
||||
|
||||
if (block_duration == 0)
|
||||
{
|
||||
@ -2883,24 +2877,6 @@ handle_subtitles(demuxer_t *demuxer, mkv_track_t *track, char *block,
|
||||
#endif
|
||||
|
||||
ptr1 = block;
|
||||
while (ptr1 - block <= size && (*ptr1 == '\n' || *ptr1 == '\r'))
|
||||
ptr1++;
|
||||
ptr2 = block + size - 1;
|
||||
while (ptr2 >= block && (*ptr2 == '\n' || *ptr2 == '\r'))
|
||||
{
|
||||
*ptr2 = 0;
|
||||
ptr2--;
|
||||
}
|
||||
|
||||
if (mkv_d->subs.lines > SUB_MAX_TEXT - 2)
|
||||
{
|
||||
mp_msg (MSGT_DEMUX, MSGL_WARN,
|
||||
MSGTR_MPDEMUX_MKV_TooManySublines);
|
||||
return;
|
||||
}
|
||||
ptr2 = mkv_d->subs.text[mkv_d->subs.lines];
|
||||
state = 0;
|
||||
|
||||
if (track->subtitle_type == MATROSKA_SUBTYPE_SSA)
|
||||
{
|
||||
/* Find text section. */
|
||||
@ -2909,94 +2885,18 @@ handle_subtitles(demuxer_t *demuxer, mkv_track_t *track, char *block,
|
||||
i++;
|
||||
if (*ptr1 == '\0') /* Broken line? */
|
||||
return;
|
||||
|
||||
/* Load text. */
|
||||
while (ptr1 - block < size)
|
||||
{
|
||||
if (*ptr1 == '{')
|
||||
state = 1;
|
||||
else if (*ptr1 == '}' && state == 1)
|
||||
state = 2;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
*ptr2++ = *ptr1;
|
||||
if (ptr2 - mkv_d->subs.text[mkv_d->subs.lines] >= 255)
|
||||
break;
|
||||
}
|
||||
ptr1++;
|
||||
|
||||
/* Newline */
|
||||
while (ptr1+1-block < size && *ptr1 == '\\' && (*(ptr1+1)|0x20) == 'n')
|
||||
{
|
||||
mkv_d->clear_subs_at[mkv_d->subs.lines++]
|
||||
= timecode + block_duration;
|
||||
*ptr2 = '\0';
|
||||
if (mkv_d->subs.lines >= SUB_MAX_TEXT)
|
||||
{
|
||||
mp_msg (MSGT_DEMUX, MSGL_WARN,
|
||||
MSGTR_MPDEMUX_MKV_TooManySublinesSkippingAfterFirst,
|
||||
SUB_MAX_TEXT);
|
||||
mkv_d->subs.lines--;
|
||||
ptr1=block+size;
|
||||
break;
|
||||
}
|
||||
ptr2 = mkv_d->subs.text[mkv_d->subs.lines];
|
||||
ptr1 += 2;
|
||||
}
|
||||
|
||||
if (state == 2)
|
||||
state = 0;
|
||||
}
|
||||
*ptr2 = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ptr1 - block < size)
|
||||
{
|
||||
if (*ptr1 == '\n' || *ptr1 == '\r')
|
||||
{
|
||||
if (state == 0) /* normal char --> newline */
|
||||
{
|
||||
*ptr2 = '\0';
|
||||
mkv_d->clear_subs_at[mkv_d->subs.lines++]
|
||||
= timecode + block_duration;
|
||||
if (mkv_d->subs.lines >= SUB_MAX_TEXT)
|
||||
{
|
||||
mp_msg (MSGT_DEMUX, MSGL_WARN,
|
||||
MSGTR_MPDEMUX_MKV_TooManySublinesSkippingAfterFirst,
|
||||
SUB_MAX_TEXT);
|
||||
mkv_d->subs.lines--;
|
||||
ptr1=block+size;
|
||||
break;
|
||||
}
|
||||
ptr2 = mkv_d->subs.text[mkv_d->subs.lines];
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
else if (*ptr1 == '<') /* skip HTML tags */
|
||||
state = 2;
|
||||
else if (*ptr1 == '>')
|
||||
state = 0;
|
||||
else if (state != 2) /* normal character */
|
||||
{
|
||||
state = 0;
|
||||
if ((ptr2 - mkv_d->subs.text[mkv_d->subs.lines]) < 255)
|
||||
*ptr2++ = *ptr1;
|
||||
}
|
||||
ptr1++;
|
||||
}
|
||||
*ptr2 = '\0';
|
||||
}
|
||||
mkv_d->clear_subs_at[mkv_d->subs.lines++] = timecode + block_duration;
|
||||
|
||||
sub_utf8 = 1;
|
||||
sub_add_text(&mkv_d->subs, ptr1, size - (ptr1 - block),
|
||||
(timecode + block_duration) / 1000.0f);
|
||||
#ifdef USE_ASS
|
||||
if (ass_enabled) {
|
||||
mkv_d->subs.start = timecode / 10;
|
||||
mkv_d->subs.end = (timecode + block_duration) / 10;
|
||||
ass_process_subtitle(track->sh_sub.ass_track, &mkv_d->subs);
|
||||
} else
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
vo_sub = &mkv_d->subs;
|
||||
vo_osd_changed (OSDTYPE_SUBTITLE);
|
||||
@ -3006,48 +2906,9 @@ static void
|
||||
clear_subtitles(demuxer_t *demuxer, uint64_t timecode, int clear_all)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
int i, lines_cut = 0;
|
||||
char *tmp;
|
||||
|
||||
/* Clear all? */
|
||||
if (clear_all)
|
||||
{
|
||||
lines_cut = mkv_d->subs.lines;
|
||||
mkv_d->subs.lines = 0;
|
||||
#ifdef USE_ASS
|
||||
if (!ass_enabled)
|
||||
#endif
|
||||
if (lines_cut)
|
||||
{
|
||||
vo_sub = &mkv_d->subs;
|
||||
vo_osd_changed (OSDTYPE_SUBTITLE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear the subtitles if they're obsolete now. */
|
||||
for (i=0; i < mkv_d->subs.lines; i++)
|
||||
{
|
||||
if (mkv_d->clear_subs_at[i] <= timecode)
|
||||
{
|
||||
tmp = mkv_d->subs.text[i];
|
||||
memmove (mkv_d->subs.text+i, mkv_d->subs.text+i+1,
|
||||
(mkv_d->subs.lines-i-1) * sizeof (*mkv_d->subs.text));
|
||||
memmove (mkv_d->clear_subs_at+i, mkv_d->clear_subs_at+i+1,
|
||||
(mkv_d->subs.lines-i-1) * sizeof (*mkv_d->clear_subs_at));
|
||||
mkv_d->subs.text[--mkv_d->subs.lines] = tmp;
|
||||
i--;
|
||||
lines_cut = 1;
|
||||
}
|
||||
}
|
||||
#ifdef USE_ASS
|
||||
if (!ass_enabled)
|
||||
#endif
|
||||
if (lines_cut)
|
||||
{
|
||||
vo_sub = &mkv_d->subs;
|
||||
vo_osd_changed (OSDTYPE_SUBTITLE);
|
||||
}
|
||||
double pts = clear_all ? MP_NOPTS_VALUE : (timecode / 1000.0f);
|
||||
if (sub_clear_text(&mkv_d->subs, pts))
|
||||
vo_osd_changed(OSDTYPE_SUBTITLE);
|
||||
}
|
||||
|
||||
// Taken from demux_real.c. Thanks to the original developpers :)
|
||||
|
@ -2172,29 +2172,15 @@ if(trak->pos==0 && trak->stream_header_len>0){
|
||||
int len = trak->samples[samplenr].size;
|
||||
double subpts = (double)trak->samples[samplenr].pts / (double)trak->timescale;
|
||||
stream_seek(demuxer->stream, pos);
|
||||
if (sh->type == 'v')
|
||||
ds_read_packet(demuxer->sub, demuxer->stream, len, subpts, pos, 0);
|
||||
else {
|
||||
int i;
|
||||
char *line = priv->subtext;
|
||||
if (sh->type != 'v') {
|
||||
stream_skip(demuxer->stream, 2); // size
|
||||
len -= 2;
|
||||
if (len < 0) len = 0;
|
||||
if (len > MOV_MAX_SUBLEN) len = MOV_MAX_SUBLEN;
|
||||
stream_read(demuxer->stream, priv->subtext, len);
|
||||
priv->subtext[len] = 0;
|
||||
priv->subs.lines = 1;
|
||||
priv->subs.text[0] = &priv->subtext;
|
||||
while ((line = strchr(line, '\n'))) {
|
||||
*line++ = 0;
|
||||
priv->subs.text[priv->subs.lines] = line;
|
||||
priv->subs.lines++;
|
||||
}
|
||||
vo_sub = &priv->subs;
|
||||
}
|
||||
ds_read_packet(demuxer->sub, demuxer->stream, len, subpts, pos, 0);
|
||||
priv->current_sub = samplenr;
|
||||
}
|
||||
vo_osd_changed (OSDTYPE_SUBTITLE);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
24
mplayer.c
24
mplayer.c
@ -2893,6 +2893,9 @@ static double playing_audio_pts(sh_audio_t *sh_audio, demux_stream_t *d_audio,
|
||||
|
||||
static void update_subtitles(void)
|
||||
{
|
||||
unsigned char *packet=NULL;
|
||||
int len;
|
||||
char type = d_dvdsub->sh ? ((sh_sub_t *)d_dvdsub->sh)->type : 'v';
|
||||
// find sub
|
||||
if (subdata) {
|
||||
double pts = sh_video->pts;
|
||||
@ -2908,9 +2911,8 @@ static void update_subtitles(void)
|
||||
}
|
||||
|
||||
// DVD sub:
|
||||
if (vo_config_count && vo_spudec) {
|
||||
unsigned char* packet=NULL;
|
||||
int len, timestamp;
|
||||
if (vo_config_count && vo_spudec && type == 'v') {
|
||||
int timestamp;
|
||||
current_module = "spudec";
|
||||
spudec_heartbeat(vo_spudec, 90000*sh_video->timer);
|
||||
/* Get a sub packet from the DVD or a vobsub and make a timestamp
|
||||
@ -2953,6 +2955,22 @@ static void update_subtitles(void)
|
||||
|
||||
if (spudec_changed(vo_spudec))
|
||||
vo_osd_changed(OSDTYPE_SPU);
|
||||
} else if (dvdsub_id >= 0 && type == 't') {
|
||||
double pts = MP_NOPTS_VALUE;
|
||||
while (d_dvdsub->first) {
|
||||
double nextpts = ds_get_next_pts(d_dvdsub);
|
||||
if (nextpts == MP_NOPTS_VALUE || nextpts - sub_delay > sh_video->pts)
|
||||
break;
|
||||
len = ds_get_packet_sub(d_dvdsub, &packet);
|
||||
pts = nextpts - sub_delay;
|
||||
}
|
||||
if (pts != MP_NOPTS_VALUE) {
|
||||
static subtitle subs;
|
||||
sub_clear_text(&subs, MP_NOPTS_VALUE);
|
||||
sub_add_text(&subs, packet, len, MP_NOPTS_VALUE);
|
||||
vo_sub = &subs;
|
||||
vo_osd_changed(OSDTYPE_SUBTITLE);
|
||||
}
|
||||
}
|
||||
current_module=NULL;
|
||||
}
|
||||
|
71
subreader.c
71
subreader.c
@ -2254,6 +2254,77 @@ void sub_free( sub_data * subd )
|
||||
free( subd );
|
||||
}
|
||||
|
||||
#define MAX_SUBLINE 512
|
||||
void sub_add_text(subtitle *sub, const char *txt, int len, double endpts) {
|
||||
int comment = 0;
|
||||
int double_newline = 1; // ignore newlines at the beginning
|
||||
int i, pos;
|
||||
char *buf;
|
||||
if (sub->lines >= SUB_MAX_TEXT) return;
|
||||
pos = 0;
|
||||
buf = malloc(MAX_SUBLINE + 1);
|
||||
sub->text[sub->lines] = buf;
|
||||
sub->endpts[sub->lines] = endpts;
|
||||
for (i = 0; i < len && pos < MAX_SUBLINE; i++) {
|
||||
char c = txt[i];
|
||||
if (c == '<') comment |= 1;
|
||||
if (c == '{') comment |= 2;
|
||||
if (comment) {
|
||||
if (c == '}') comment &= ~2;
|
||||
if (c == '>') comment &= ~1;
|
||||
continue;
|
||||
}
|
||||
if (pos == MAX_SUBLINE - 1) {
|
||||
i--;
|
||||
c = 0;
|
||||
}
|
||||
if (c == '\\' && i + 1 < len) {
|
||||
c = txt[++i];
|
||||
if (c == 'n' || c == 'N') c = 0;
|
||||
}
|
||||
if (c == '\n' || c == '\r') c = 0;
|
||||
if (c) {
|
||||
double_newline = 0;
|
||||
buf[pos++] = c;
|
||||
} else if (!double_newline) {
|
||||
if (sub->lines >= SUB_MAX_TEXT - 1) {
|
||||
mp_msg(MSGT_VO, MSGL_WARN, "Too many subtitle lines\n");
|
||||
break;
|
||||
}
|
||||
double_newline = 1;
|
||||
buf[pos] = 0;
|
||||
sub->lines++;
|
||||
pos = 0;
|
||||
buf = malloc(MAX_SUBLINE + 1);
|
||||
sub->text[sub->lines] = buf;
|
||||
sub->endpts[sub->lines] = endpts;
|
||||
}
|
||||
}
|
||||
buf[pos] = 0;
|
||||
if (sub->lines < SUB_MAX_TEXT &&
|
||||
strlen(sub->text[sub->lines]))
|
||||
sub->lines++;
|
||||
}
|
||||
|
||||
#define MP_NOPTS_VALUE (-1LL<<63)
|
||||
int sub_clear_text(subtitle *sub, double pts) {
|
||||
int i = 0;
|
||||
int changed = 0;
|
||||
while (i < sub->lines) {
|
||||
double endpts = sub->endpts[i];
|
||||
if (pts == MP_NOPTS_VALUE || (endpts != MP_NOPTS_VALUE && pts >= endpts)) {
|
||||
int j;
|
||||
free(sub->text[i]);
|
||||
for (j = i + 1; j < sub->lines; j++)
|
||||
sub->text[j - 1] = sub->text[j];
|
||||
sub->lines--;
|
||||
changed = 1;
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
#ifdef DUMPSUBS
|
||||
int main(int argc, char **argv) { // for testing
|
||||
sub_data *subd;
|
||||
|
@ -48,6 +48,7 @@ typedef struct {
|
||||
unsigned long end;
|
||||
|
||||
char *text[SUB_MAX_TEXT];
|
||||
double endpts[SUB_MAX_TEXT];
|
||||
unsigned char alignment;
|
||||
} subtitle;
|
||||
|
||||
@ -86,4 +87,6 @@ void dump_sami(sub_data* subd, float fps);
|
||||
void sub_free( sub_data * subd );
|
||||
void find_sub(sub_data* subd,int key);
|
||||
void step_sub(sub_data *subd, float pts, int movement);
|
||||
void sub_add_text(subtitle *sub, const char *txt, int len, double endpts);
|
||||
int sub_clear_text(subtitle *sub, double pts);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user