1
0
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:
reimar 2007-01-06 19:07:58 +00:00
parent 20a7d46a88
commit 61e4a80191
5 changed files with 110 additions and 171 deletions

View File

@ -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 :)

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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