<div dir="ltr"><div>Here are examples of video and subtitle files which reproduce bug:</div><div><br></div><a href="http://www.archive.org/download/MIT6.046JF05MPEG4/ocw-6.046-02nov2005-220k_512kb.mp4">http://www.archive.org/download/MIT6.046JF05MPEG4/ocw-6.046-02nov2005-220k_512kb.mp4</a><br>
<div><a href="http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-046j-introduction-to-algorithms-sma-5503-fall-2005/video-lectures/lecture-14-competitive-analysis-self-organizing-lists/ocw-6.046-lec14.srt">http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-046j-introduction-to-algorithms-sma-5503-fall-2005/video-lectures/lecture-14-competitive-analysis-self-organizing-lists/ocw-6.046-lec14.srt</a><br>
</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Nov 15, 2013 at 12:35 PM, Maxim Bublis <span dir="ltr"><<a href="mailto:b@codemonkey.ru" target="_blank">b@codemonkey.ru</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Sorry for message duplications, something gone wrong with my internet connection.</div><div class="gmail_extra">
<div><div class="h5"><br><br><div class="gmail_quote">On Fri, Nov 15, 2013 at 1:34 AM, Maxim Bublis <span dir="ltr"><<a href="mailto:b@codemonkey.ru" target="_blank">b@codemonkey.ru</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This patch fixes SubRip subtitles parsing with missing microseconds.<br>
This patch also makes redundant SUB_TYPE_SUBRIP_DOT format as both<br>
delimiters (dot and comma) are now supported equally.<br>
<br>
---<br>
 modules/demux/subtitle.c | 140 +++++++++++++++++++++++++++++++++--------------<br>
 1 file changed, 99 insertions(+), 41 deletions(-)<br>
<br>
diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c<br>
index 9435ba7..a9c3e45 100644<br>
--- a/modules/demux/subtitle.c<br>
+++ b/modules/demux/subtitle.c<br>
@@ -95,7 +95,6 @@ enum<br>
     SUB_TYPE_UNKNOWN = -1,<br>
     SUB_TYPE_MICRODVD,<br>
     SUB_TYPE_SUBRIP,<br>
-    SUB_TYPE_SUBRIP_DOT, /* Invalid SubRip file (dot instead of comma) */<br>
     SUB_TYPE_SSA1,<br>
     SUB_TYPE_SSA2_4,<br>
     SUB_TYPE_ASS,<br>
@@ -171,7 +170,6 @@ struct demux_sys_t<br>
<br>
 static int  ParseMicroDvd   ( demux_t *, subtitle_t *, int );<br>
 static int  ParseSubRip     ( demux_t *, subtitle_t *, int );<br>
-static int  ParseSubRipDot  ( demux_t *, subtitle_t *, int );<br>
 static int  ParseSubViewer  ( demux_t *, subtitle_t *, int );<br>
 static int  ParseSSA        ( demux_t *, subtitle_t *, int );<br>
 static int  ParseVplayer    ( demux_t *, subtitle_t *, int );<br>
@@ -198,7 +196,6 @@ static const struct<br>
 {<br>
     { "microdvd",   SUB_TYPE_MICRODVD,    "MicroDVD",    ParseMicroDvd },<br>
     { "subrip",     SUB_TYPE_SUBRIP,      "SubRIP",      ParseSubRip },<br>
-    { "subrip-dot", SUB_TYPE_SUBRIP_DOT,  "SubRIP(Dot)", ParseSubRipDot },<br>
     { "subviewer",  SUB_TYPE_SUBVIEWER,   "SubViewer",   ParseSubViewer },<br>
     { "ssa1",       SUB_TYPE_SSA1,        "SSA-1",       ParseSSA },<br>
     { "ssa2-4",     SUB_TYPE_SSA2_4,      "SSA-2/3/4",   ParseSSA },<br>
@@ -335,21 +332,29 @@ static int Open ( vlc_object_t *p_this )<br>
                 p_sys->i_type = SUB_TYPE_MICRODVD;<br>
                 break;<br>
             }<br>
-            else if( sscanf( s,<br>
-                             "%d:%d:%d,%d --> %d:%d:%d,%d",<br>
+            else if( sscanf( s, "%d:%d:%d,%d --> %d:%d:%d,%d",<br>
                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
-                             &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )<br>
-            {<br>
-                p_sys->i_type = SUB_TYPE_SUBRIP;<br>
-                break;<br>
-            }<br>
-            else if( sscanf( s,<br>
-                             "%d:%d:%d.%d --> %d:%d:%d.%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 ||<br>
+                     sscanf( s, "%d:%d:%d --> %d:%d:%d,%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
+                             &i_dummy,&i_dummy,&i_dummy ) == 7 ||<br>
+                     sscanf( s, "%d:%d:%d,%d --> %d:%d:%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
+                             &i_dummy,&i_dummy,&i_dummy ) == 7 ||<br>
+                     sscanf( s, "%d:%d:%d.%d --> %d:%d:%d.%d",<br>
                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
-                             &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 ||<br>
+                     sscanf( s, "%d:%d:%d --> %d:%d:%d.%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
+                             &i_dummy,&i_dummy,&i_dummy ) == 7 ||<br>
+                     sscanf( s, "%d:%d:%d.%d --> %d:%d:%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,&i_dummy,<br>
+                             &i_dummy,&i_dummy,&i_dummy ) == 7 ||<br>
+                     sscanf( s, "%d:%d:%d --> %d:%d:%d",<br>
+                             &i_dummy,&i_dummy,&i_dummy,<br>
+                             &i_dummy,&i_dummy,&i_dummy ) == 6 )<br>
             {<br>
-                msg_Err( p_demux, "Detected invalid SubRip file, playing anyway" );<br>
-                p_sys->i_type = SUB_TYPE_SUBRIP_DOT;<br>
+                p_sys->i_type = SUB_TYPE_SUBRIP;<br>
                 break;<br>
             }<br>
             else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )<br>
@@ -899,7 +904,7 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle,<br>
  *  We ignore line number for SubRip<br>
  */<br>
 static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,<br>
-                                 const char *psz_fmt,<br>
+                                 int (* pf_parse_timing)(subtitle_t *, const char *),<br>
                                  bool b_replace_br )<br>
 {<br>
     demux_sys_t *p_sys = p_demux->p_sys;<br>
@@ -909,26 +914,14 @@ static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,<br>
     for( ;; )<br>
     {<br>
         const char *s = TextGetLine( txt );<br>
-        int h1, m1, s1, d1, h2, m2, s2, d2;<br>
<br>
         if( !s )<br>
             return VLC_EGENERIC;<br>
<br>
-        if( sscanf( s, psz_fmt,<br>
-                    &h1, &m1, &s1, &d1,<br>
-                    &h2, &m2, &s2, &d2 ) == 8 )<br>
+        if( pf_parse_timing( p_subtitle, s) == VLC_SUCCESS &&<br>
+            p_subtitle->i_start < p_subtitle->i_stop )<br>
         {<br>
-            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +<br>
-                                    (int64_t)m1 * 60*1000 +<br>
-                                    (int64_t)s1 * 1000 +<br>
-                                    (int64_t)d1 ) * 1000;<br>
-<br>
-            p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +<br>
-                                    (int64_t)m2 * 60*1000 +<br>
-                                    (int64_t)s2 * 1000 +<br>
-                                    (int64_t)d2 ) * 1000;<br>
-            if( p_subtitle->i_start < p_subtitle->i_stop )<br>
-                break;<br>
+            break;<br>
         }<br>
     }<br>
<br>
@@ -972,6 +965,56 @@ static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,<br>
         }<br>
     }<br>
 }<br>
+<br>
+/* subtitle_ParseSubRipTimingValue<br>
+ * Parses SubRip timing value.<br>
+ */<br>
+static int subtitle_ParseSubRipTimingValue(int64_t *timing_value,<br>
+                                           const char *s)<br>
+{<br>
+    int h1, m1, s1, d1 = 0;<br>
+<br>
+    if ( sscanf( s, "%d:%d:%d,%d",<br>
+                 &h1, &m1, &s1, &d1 ) == 4 ||<br>
+         sscanf( s, "%d:%d:%d.%d",<br>
+                 &h1, &m1, &s1, &d1 ) == 4 ||<br>
+         sscanf( s, "%d:%d:%d",<br>
+                 &h1, &m1, &s1) == 3 )<br>
+    {<br>
+        (*timing_value) = ( (int64_t)h1 * 3600 * 1000 +<br>
+                            (int64_t)m1 * 60 * 1000 +<br>
+                            (int64_t)s1 * 1000 +<br>
+                            (int64_t)d1 ) * 1000;<br>
+<br>
+        return VLC_SUCCESS;<br>
+    }<br>
+<br>
+    return VLC_EGENERIC;<br>
+}<br>
+<br>
+/* subtitle_ParseSubRipTiming<br>
+ * Parses SubRip timing.<br>
+ */<br>
+static int subtitle_ParseSubRipTiming( subtitle_t *p_subtitle,<br>
+                                       const char *s )<br>
+{<br>
+    int i_result = VLC_EGENERIC;<br>
+    char *psz_start, *psz_stop;<br>
+    psz_start = malloc( strlen(s) );<br>
+    psz_stop = malloc( strlen(s) );<br>
+<br>
+    if( sscanf( s, "%s --> %s", psz_start, psz_stop) == 2 &&<br>
+        subtitle_ParseSubRipTimingValue( &p_subtitle->i_start, psz_start ) == VLC_SUCCESS &&<br>
+        subtitle_ParseSubRipTimingValue( &p_subtitle->i_stop,  psz_stop ) == VLC_SUCCESS )<br>
+    {<br>
+        i_result = VLC_SUCCESS;<br>
+    }<br>
+<br>
+    free(psz_start);<br>
+    free(psz_stop);<br>
+<br>
+    return i_result;<br>
+}<br>
 /* ParseSubRip<br>
  */<br>
 static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,<br>
@@ -979,20 +1022,35 @@ static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,<br>
 {<br>
     VLC_UNUSED( i_idx );<br>
     return ParseSubRipSubViewer( p_demux, p_subtitle,<br>
-                                 "%d:%d:%d,%d --> %d:%d:%d,%d",<br>
+                                 &subtitle_ParseSubRipTiming,<br>
                                  false );<br>
 }<br>
-/* ParseSubRipDot<br>
- * Special version for buggy file using '.' instead of ','<br>
+<br>
+/* subtitle_ParseSubViewerTiming<br>
+ * Parses SubViewer timing.<br>
  */<br>
-static int  ParseSubRipDot( demux_t *p_demux, subtitle_t *p_subtitle,<br>
-                            int i_idx )<br>
+static int subtitle_ParseSubViewerTiming( subtitle_t *p_subtitle,<br>
+                                   const char *s )<br>
 {<br>
-    VLC_UNUSED( i_idx );<br>
-    return ParseSubRipSubViewer( p_demux, p_subtitle,<br>
-                                 "%d:%d:%d.%d --> %d:%d:%d.%d",<br>
-                                 false );<br>
+    int h1, m1, s1, d1, h2, m2, s2, d2;<br>
+<br>
+    if( sscanf( s, "%d:%d:%d.%d,%d:%d:%d.%d",<br>
+                &h1, &m1, &s1, &d1, &h2, &m2, &s2, &d2) == 8 )<br>
+    {<br>
+        p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +<br>
+                                (int64_t)m1 * 60*1000 +<br>
+                                (int64_t)s1 * 1000 +<br>
+                                (int64_t)d1 ) * 1000;<br>
+<br>
+        p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +<br>
+                                (int64_t)m2 * 60*1000 +<br>
+                                (int64_t)s2 * 1000 +<br>
+                                (int64_t)d2 ) * 1000;<br>
+        return VLC_SUCCESS;<br>
+    }<br>
+    return VLC_EGENERIC;<br>
 }<br>
+<br>
 /* ParseSubViewer<br>
  */<br>
 static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,<br>
@@ -1001,7 +1059,7 @@ static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,<br>
     VLC_UNUSED( i_idx );<br>
<br>
     return ParseSubRipSubViewer( p_demux, p_subtitle,<br>
-                                 "%d:%d:%d.%d,%d:%d:%d.%d",<br>
+                                 &subtitle_ParseSubViewerTiming,<br>
                                  true );<br>
 }<br>
<span><font color="#888888"><br>
--<br>
Maxim Bublis<br>
<br>
</font></span></blockquote></div><br><br clear="all"><div><br></div></div></div><span class="HOEnZb"><font color="#888888">-- <br>Maxim Bublis
</font></span></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Maxim Bublis
</div>