[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