# HG changeset patch # User reimar # Date 1168110478 0 # Node ID b0bc0d81f91b9337792966950d91278d473c3a00 # Parent d4dbadf11019cd968172353add49f82ec39c2a52 Subtitle handling cleanup: factor out code for parsing embedded subtitles and adding and removing of lines in subtitle struct into subreader.c. diff -r d4dbadf11019 -r b0bc0d81f91b libmpdemux/demux_mkv.c --- a/libmpdemux/demux_mkv.c Sat Jan 06 19:02:19 2007 +0000 +++ b/libmpdemux/demux_mkv.c Sat Jan 06 19:07:58 2007 +0000 @@ -166,7 +166,6 @@ 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 @@ 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)) @@ -2725,6 +2721,9 @@ } static void +clear_subtitles(demuxer_t *demuxer, uint64_t timecode, int clear_all); + +static void demux_close_mkv (demuxer_t *demuxer) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; @@ -2735,14 +2734,12 @@ #ifdef USE_ICONV subcp_close(); #endif + clear_subtitles(demuxer, 0, 1); free_cached_dps (demuxer); if (mkv_d->tracks) { for (i=0; inum_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) @@ -2855,15 +2852,12 @@ } 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 @@ #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 @@ 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 @@ 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 :) diff -r d4dbadf11019 -r b0bc0d81f91b libmpdemux/demux_mov.c --- a/libmpdemux/demux_mov.c Sat Jan 06 19:02:19 2007 +0000 +++ b/libmpdemux/demux_mov.c Sat Jan 06 19:07:58 2007 +0000 @@ -2172,29 +2172,15 @@ 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; diff -r d4dbadf11019 -r b0bc0d81f91b mplayer.c --- a/mplayer.c Sat Jan 06 19:02:19 2007 +0000 +++ b/mplayer.c Sat Jan 06 19:07:58 2007 +0000 @@ -2893,6 +2893,9 @@ 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 @@ } // 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 @@ 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; } diff -r d4dbadf11019 -r b0bc0d81f91b subreader.c --- a/subreader.c Sat Jan 06 19:02:19 2007 +0000 +++ b/subreader.c Sat Jan 06 19:07:58 2007 +0000 @@ -2254,6 +2254,77 @@ 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; diff -r d4dbadf11019 -r b0bc0d81f91b subreader.h --- a/subreader.h Sat Jan 06 19:02:19 2007 +0000 +++ b/subreader.h Sat Jan 06 19:07:58 2007 +0000 @@ -48,6 +48,7 @@ unsigned long end; char *text[SUB_MAX_TEXT]; + double endpts[SUB_MAX_TEXT]; unsigned char alignment; } subtitle; @@ -86,4 +87,6 @@ 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