]> git.sesse.net Git - vlc/blobdiff - modules/demux/subtitle.c
prepare release. We still need to update the Changelog
[vlc] / modules / demux / subtitle.c
index 8133c0680fad799cc72a8a7e078fc78ec3941051..060ddef0aab9f8c6aac53723e648b942af8c7416 100644 (file)
 #include <vlc/input.h>
 #include "vlc_video.h"
 
-
-#if (!defined( WIN32 ) || defined(__MINGW32__))
-#    include <dirent.h>
-#endif
-
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -54,17 +49,20 @@ static void Close( vlc_object_t *p_this );
     "Override frames per second. " \
     "It will only work with MicroDVD subtitles."
 #define SUB_TYPE_LONGTEXT \
-    "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"vplayer\" " \
+    "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\" " \
     "\"sami\" (auto for autodetection, it should always work)."
 static char *ppsz_sub_type[] =
 {
     "auto", "microdvd", "subrip", "subviewer", "ssa1",
-    "ssa2-4", "vplayer", "sami"
+    "ssa2-4", "ass", "vplayer", "sami"
 };
 
 vlc_module_begin();
+    set_shortname( _("Subtitles"));
     set_description( _("Text subtitles demux") );
     set_capability( "demux2", 0 );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_DEMUX );
     add_float( "sub-fps", 0.0, NULL,
                N_("Frames per second"),
                SUB_FPS_LONGTEXT, VLC_TRUE );
@@ -89,6 +87,7 @@ enum
     SUB_TYPE_SUBRIP,
     SUB_TYPE_SSA1,
     SUB_TYPE_SSA2_4,
+    SUB_TYPE_ASS,
     SUB_TYPE_VPLAYER,
     SUB_TYPE_SAMI,
     SUB_TYPE_SUBVIEWER,
@@ -151,6 +150,7 @@ static struct
     { "subviewer",  SUB_TYPE_SUBVIEWER, "SubViewer",ParseSubViewer },
     { "ssa1",       SUB_TYPE_SSA1,      "SSA-1",    ParseSSA },
     { "ssa2-4",     SUB_TYPE_SSA2_4,    "SSA-2/3/4",ParseSSA },
+    { "ass",        SUB_TYPE_ASS,       "SSA/ASS",  ParseSSA },
     { "vplayer",    SUB_TYPE_VPLAYER,   "VPlayer",  ParseVplayer },
     { "sami",       SUB_TYPE_SAMI,      "SAMI",     ParseSami },
     { NULL,         SUB_TYPE_UNKNOWN,   "Unknown",  NULL }
@@ -190,12 +190,15 @@ static int Open ( vlc_object_t *p_this )
 
 
     /* Get the FPS */
-    p_sys->i_microsecperframe = 40000; /* default to 25 fps */
     f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
     if( f_fps >= 1.0 )
     {
         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
     }
+    else
+    {
+        p_sys->i_microsecperframe = 0;
+    }
 
     f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" );
     if( f_fps >= 1.0 )
@@ -262,28 +265,29 @@ static int Open ( vlc_object_t *p_this )
                 p_sys->i_type = SUB_TYPE_SUBRIP;
                 break;
             }
-            else if( sscanf( s,
-                             "!: This is a Sub Station Alpha v%d.x script.",
-                             &i_dummy ) == 1)
+            else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
             {
-                if( i_dummy <= 1 )
-                {
-                    p_sys->i_type = SUB_TYPE_SSA1;
-                }
-                else
-                {
-                    p_sys->i_type = SUB_TYPE_SSA2_4; /* I hope this will work */
-                }
+                p_sys->i_type = SUB_TYPE_SSA1;
+                break;
+            }
+            else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
+            {
+                p_sys->i_type = SUB_TYPE_ASS;
                 break;
             }
-            else if( strcasestr( s, "This is a Sub Station Alpha v4 script" ) )
+            else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
             {
-                p_sys->i_type = SUB_TYPE_SSA2_4; /* I hope this will work */
+                p_sys->i_type = SUB_TYPE_SSA2_4;
                 break;
             }
             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
             {
-                p_sys->i_type = SUB_TYPE_SSA2_4; /* could be wrong */
+                p_sys->i_type = SUB_TYPE_SSA2_4;
+                break;
+            }
+            else if( !strncasecmp( s, "Dialogue:", 9  ) )
+            {
+                p_sys->i_type = SUB_TYPE_ASS;
                 break;
             }
             else if( strcasestr( s, "[INFORMATION]" ) )
@@ -370,7 +374,8 @@ static int Open ( vlc_object_t *p_this )
 
     /* *** add subtitle ES *** */
     if( p_sys->i_type == SUB_TYPE_SSA1 ||
-             p_sys->i_type == SUB_TYPE_SSA2_4 )
+             p_sys->i_type == SUB_TYPE_SSA2_4 ||
+             p_sys->i_type == SUB_TYPE_ASS )
     {
         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
     }
@@ -503,7 +508,7 @@ static int Demux( demux_t *p_demux )
     if( p_sys->i_subtitle >= p_sys->i_subtitles )
         return 0;
 
-    i_maxdate = p_sys->i_next_demux_date;
+    i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
     if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
     {
         /* Should not happen */
@@ -671,7 +676,7 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
      * each line:
      *  {n1}{n2}Line1|Line2|Line3....
      * where n1 and n2 are the video frame number...
-     *
+     * {n2} can also be {}
      */
     char *s;
 
@@ -680,6 +685,10 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
     int    i_stop;
     unsigned int i;
 
+    int i_microsecperframe = 40000; /* default to 25 fps */
+    if( p_sys->i_microsecperframe > 0 ) 
+        i_microsecperframe = p_sys->i_microsecperframe;
+    
     p_subtitle->i_start = 0;
     p_subtitle->i_stop  = 0;
     p_subtitle->psz_text = NULL;
@@ -709,8 +718,8 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
         }
     }
 
-    p_subtitle->i_start = (int64_t)i_start * p_sys->i_microsecperframe;
-    p_subtitle->i_stop  = (int64_t)i_stop  * p_sys->i_microsecperframe;
+    p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
+    p_subtitle->i_stop  = (int64_t)i_stop  * i_microsecperframe;
     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
     return( 0 );
 }
@@ -911,6 +920,7 @@ static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
     text_t      *txt = &p_sys->txt;
 
     char buffer_text[ 10 * MAX_LINE];
+    char buffer_text2[ 10 * MAX_LINE];
     char *s;
     int64_t     i_start;
     int64_t     i_stop;
@@ -922,7 +932,6 @@ static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
     for( ;; )
     {
         int h1, m1, s1, c1, h2, m2, s2, c2;
-        int i_dummy;
 
         if( ( s = TextGetLine( txt ) ) == NULL )
         {
@@ -930,9 +939,20 @@ static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
         }
         p_subtitle->psz_text = malloc( strlen( s ) );
 
+        /* We expect (SSA2-4):
+         * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+         * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
+         *
+         * SSA-1 is similar but only has 8 commas up untill the subtitle text. Probably the Effect field is no present, but not 100 % sure.
+         */
+
+        /* For ASS:
+         * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+         * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
+         */
         if( sscanf( s,
-                    "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d%[^\r\n]",
-                    &i_dummy,
+                    "Dialogue: %[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
+                    buffer_text2,
                     &h1, &m1, &s1, &c1,
                     &h2, &m2, &s2, &c2,
                     buffer_text ) == 10 )
@@ -948,15 +968,16 @@ static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
                         (int64_t)c2 * 10 ) * 1000;
 
             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
+            /* (Layer comes from ASS specs ... it's empty for SSA.) */
             if( p_sys->i_type == SUB_TYPE_SSA1 )
             {
                 sprintf( p_subtitle->psz_text,
-                         ",%d%s", i_dummy, strdup( buffer_text) );
+                         ",%s", strdup( buffer_text) ); /* SSA1 has only 8 commas before the text starts, not 9 */
             }
             else
             {
                 sprintf( p_subtitle->psz_text,
-                         ",%d,%s", i_dummy, strdup( buffer_text) );
+                         ",,%s", strdup( buffer_text) ); /* ReadOrder, Layer, %s(rest of fields) */
             }
             p_subtitle->i_start = i_start;
             p_subtitle->i_stop = i_stop;