[MPlayer-dev-eng] [RFC] subtitle cleanup
Reimar Döffinger
Reimar.Doeffinger at stud.uni-karlsruhe.de
Thu Dec 21 23:26:23 CET 2006
Hello,
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.
Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libvo/sub.c
===================================================================
--- libvo/sub.c (revision 21713)
+++ libvo/sub.c (working copy)
@@ -1004,3 +1004,76 @@
}
return 0;
}
+
+#define MAX_SUBLINE 512
+
+void vo_sub_add_text(const char *txt, int len, double endpts) {
+ int comment = 0;
+ int double_newline = 0;
+ int i, pos;
+ char *buf;
+ if (vo_sub->lines >= SUB_MAX_TEXT) return;
+ pos = 0;
+ buf = malloc(MAX_SUBLINE + 1);
+ vo_sub->text[vo_sub->lines] = buf;
+ vo_sub->endpts[vo_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 (vo_sub->lines >= SUB_MAX_TEXT - 1) {
+ mp_msg(MSGT_VO, MSGL_WARN, "Too many subtitle lines\n");
+ break;
+ }
+ double_newline = 1;
+ vo_sub->lines++;
+ pos = 0;
+ buf = malloc(MAX_SUBLINE + 1);
+ vo_sub->text[vo_sub->lines] = buf;
+ vo_sub->endpts[vo_sub->lines] = endpts;
+ }
+ }
+ buf[pos] = 0;
+ if (vo_sub->lines < SUB_MAX_TEXT &&
+ strlen(vo_sub->text[vo_sub->lines]))
+ vo_sub->lines++;
+ vo_osd_changed(OSDTYPE_SUBTITLE);
+}
+
+#define MP_NOPTS_VALUE (-1LL<<63)
+void vo_sub_clear_text(double pts) {
+ int i = 0;
+ int changed = 0;
+ while (i < vo_sub->lines) {
+ double endpts = vo_sub->endpts[i];
+ if (pts == MP_NOPTS_VALUE || (endpts != MP_NOPTS_VALUE && pts >= endpts)) {
+ int j;
+ free(vo_sub->text[i]);
+ for (j = i + 1; j < vo_sub->lines; j++)
+ vo_sub->text[j - 1] = vo_sub->text[j];
+ vo_sub->lines--;
+ changed = 1;
+ } else
+ i++;
+ }
+ if (changed)
+ vo_osd_changed(OSDTYPE_SUBTITLE);
+}
Index: libvo/sub.h
===================================================================
--- libvo/sub.h (revision 21715)
+++ libvo/sub.h (working copy)
@@ -61,6 +61,8 @@
extern sub_data* subdata; //currently used subtitles
extern subtitle* vo_sub;
+void vo_sub_add_text(const char *txt, int len, double endpts);
+void vo_sub_clear_text(double pts);
extern unsigned char* vo_osd_text;
Index: libmpdemux/demux_mkv.c
===================================================================
--- libmpdemux/demux_mkv.c (revision 21713)
+++ 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))
@@ -2740,9 +2736,6 @@
{
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)
@@ -2890,15 +2885,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. */
@@ -2907,145 +2893,29 @@
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;
+ vo_sub = &mkv_d->subs;
+ vo_sub_add_text(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
+ }
#endif
- vo_sub = &mkv_d->subs;
- vo_osd_changed (OSDTYPE_SUBTITLE);
}
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);
+ vo_sub = &mkv_d->subs;
+ vo_sub_clear_text(pts);
}
// Taken from demux_real.c. Thanks to the original developpers :)
Index: libmpdemux/demux_mov.c
===================================================================
--- libmpdemux/demux_mov.c (revision 21713)
+++ libmpdemux/demux_mov.c (working copy)
@@ -2138,6 +2147,11 @@
x=trak->samples[frame].size;
pos=trak->samples[frame].pos;
}
+if (ds == demuxer->sub && ((sh_sub_t *)ds->sh)->type == 't') {
+ stream_skip(demuxer->stream, 2); // size
+ x -= 2;
+ if (x < 0) x = 0;
+}
if(trak->pos==0 && trak->stream_header_len>0){
// we have to append the stream header...
demux_packet_t* dp=new_demux_packet(x+trak->stream_header_len);
@@ -2155,48 +2169,6 @@
++trak->pos;
- if (demuxer->sub->id >= 0) {
- int samplenr = 0;
- trak = priv->tracks[demuxer->sub->id];
- while (samplenr < trak->samples_size) {
- double subpts = (double)trak->samples[samplenr].pts / (double)trak->timescale;
- if (subpts >= pts) break;
- samplenr++;
- }
- samplenr--;
- if (samplenr < 0)
- vo_sub = NULL;
- else if (samplenr != priv->current_sub) {
- sh_sub_t *sh = demuxer->sub->sh;
- off_t pos = trak->samples[samplenr].pos;
- 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;
- 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;
- }
- priv->current_sub = samplenr;
- }
- vo_osd_changed (OSDTYPE_SUBTITLE);
- }
-
return 1;
}
Index: mplayer.c
===================================================================
--- mplayer.c (revision 21713)
+++ mplayer.c (working copy)
@@ -2892,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;
@@ -2907,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
@@ -2952,6 +2956,21 @@
if (spudec_changed(vo_spudec))
vo_osd_changed(OSDTYPE_SPU);
+ } else if (dvdsub_id >= 0 && type == 't') {
+ double pts = MP_NOPTS_VALUE;
+ static subtitle subs;
+ while (1) {
+ 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) {
+ vo_sub = &subs;
+ vo_sub_clear_text(MP_NOPTS_VALUE);
+ vo_sub_add_text(packet, len, MP_NOPTS_VALUE);
+ }
}
current_module=NULL;
}
Index: subreader.h
===================================================================
--- subreader.h (revision 21713)
+++ 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;
More information about the MPlayer-dev-eng
mailing list