[MPlayer-dev-eng] [RFC] subtitle cleanup
Reimar Döffinger
Reimar.Doeffinger at stud.uni-karlsruhe.de
Fri Jan 5 17:49:56 CET 2007
Hello,
On Thu, Dec 21, 2006 at 11:26:23PM +0100, Reimar D?ffinger wrote:
> On Thu, Dec 21, 2006 at 07:19:47PM +0100, Reimar D?ffinger wrote:
> > attached patch moves subtitle stuff (only mov for now) to mplayer.c.
> > Biggest problem right now is that it breaks vobsubs embedded in mp4
> > (http://samples.mplayerhq.hu/sub/NeroMP4/unsupported-embedded-subs-2.mp4),
> > it seems that the vobsub code ignores pts values or something like
> > this...
>
> Improved version with less code in mplayer.c and a lot of code in
> demux_mkv.c replaced by shared code in sub.c.
An update that hopefully encompasses most remarks made.
Greetings,
Reimar Döffinger
-------------- next part --------------
Index: mplayer.c
===================================================================
--- mplayer.c (revision 21828)
+++ mplayer.c (working copy)
@@ -2893,6 +2894,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 +2912,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 +2956,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;
}
Index: subreader.h
===================================================================
--- subreader.h (revision 21828)
+++ subreader.h (working copy)
@@ -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
Index: subreader.c
===================================================================
--- subreader.c (revision 21828)
+++ subreader.c (working copy)
@@ -2254,6 +2254,76 @@
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 = 0;
+ 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 = 0;
+ buf[pos++] = c;
+ if (c)
+ double_newline = 0;
+ 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;
+ 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;
Index: libmpdemux/demux_mov.c
===================================================================
--- libmpdemux/demux_mov.c (revision 21828)
+++ libmpdemux/demux_mov.c (working copy)
@@ -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;
Index: libmpdemux/demux_mkv.c
===================================================================
--- libmpdemux/demux_mkv.c (revision 21828)
+++ libmpdemux/demux_mkv.c (working copy)
@@ -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; 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)
@@ -2855,9 +2852,6 @@
}
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)
{
@@ -2892,15 +2886,6 @@
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 +2894,19 @@
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_add_text(&mkv_d->subs, ptr1, strlen(ptr1),
+ (timecode + block_duration) / 1000.0f);
+
sub_utf8 = 1;
#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 +2916,10 @@
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);
+ vo_sub = &mkv_d->subs;
+ if (sub_clear_text(&mkv_d->subs, pts))
+ vo_osd_changed(OSDTYPE_SUBTITLE);
}
// Taken from demux_real.c. Thanks to the original developpers :)
More information about the MPlayer-dev-eng
mailing list