]> git.sesse.net Git - vlc/blobdiff - modules/demux/util/sub.c
* include/configuration.h: some small re-work of the config declaration macros.
[vlc] / modules / demux / util / sub.c
index 37848087719aba0d1f2c01d71c4af111b36ebd7c..624bfd0f867608574301dcc37e6c119537de1730 100644 (file)
@@ -2,7 +2,7 @@
  * sub.c
  *****************************************************************************
  * Copyright (C) 1999-2003 VideoLAN
- * $Id: sub.c,v 1.28 2003/10/11 22:40:04 hartman Exp $
+ * $Id: sub.c,v 1.35 2003/11/05 00:39:16 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/types.h>
+#include <ctype.h>
 
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 #include "vlc_video.h"
+#include <codecs.h>
 
 #include "sub.h"
 
@@ -51,8 +53,8 @@ static void sub_close( subtitle_demux_t *p_sub );
 
 static void sub_fix( subtitle_demux_t *p_sub );
 
-static char *ppsz_sub_type[] = { "microdvd", "subrip", "ssa1", "ssa2-4", "vplayer", "sami", NULL };
-
+static char *ppsz_sub_type[] = { "auto", "microdvd", "subrip", "ssa1",
+  "ssa2-4", "vplayer", "sami", "vobsub" };
 
 /*****************************************************************************
  * Module descriptor
@@ -64,7 +66,7 @@ static char *ppsz_sub_type[] = { "microdvd", "subrip", "ssa1", "ssa2-4", "vplaye
     "It will only work with MicroDVD subtitles."
 #define SUB_TYPE_LONGTEXT \
     "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"vplayer\" " \
-    "\"sami\" (nothing for autodetection, it should always work)."
+    "\"sami\" (auto for autodetection, it should always work)."
 
 vlc_module_begin();
     set_description( _("Text subtitles demux") );
@@ -76,9 +78,9 @@ vlc_module_begin();
         add_integer( "sub-delay", 0, NULL,
                      "Delay subtitles (in 1/10s)",
                      SUB_DELAY_LONGTEXT, VLC_TRUE );
-        add_string_from_list( "sub-type", NULL, ppsz_sub_type, NULL,
-                              "subtitles type",
-                              SUB_TYPE_LONGTEXT, VLC_TRUE );
+        add_string( "sub-type", "auto", NULL, "subtitles type",
+                    SUB_TYPE_LONGTEXT, VLC_TRUE );
+            change_string_list( ppsz_sub_type, 0, 0 );
     set_callbacks( Open, NULL );
 vlc_module_end();
 
@@ -202,30 +204,55 @@ static void text_rewind( text_t *txt )
     txt->i_line = 0;
 }
 
-static int  sub_MicroDvdRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
-static int  sub_SubRipRead  ( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
-static int  sub_SSA1Read    ( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
-static int  sub_SSA2_4Read  ( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
-static int  sub_Vplayer     ( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
-static int  sub_Sami        ( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_SubRipRead  ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_SSARead     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_Vplayer     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_Sami        ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
+static int  sub_VobSub      ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
 
 static struct
 {
     char *psz_type_name;
     int  i_type;
     char *psz_name;
-    int  (*pf_read_subtitle)    ( text_t *, subtitle_t*, mtime_t );
+    int  (*pf_read_subtitle)    ( subtitle_demux_t *, text_t *, subtitle_t*, mtime_t );
 } sub_read_subtitle_function [] =
 {
     { "microdvd",   SUB_TYPE_MICRODVD,  "MicroDVD", sub_MicroDvdRead },
     { "subrip",     SUB_TYPE_SUBRIP,    "SubRIP",   sub_SubRipRead },
-    { "ssa1",       SUB_TYPE_SSA1,      "SSA-1",    sub_SSA1Read },
-    { "ssa2-4",     SUB_TYPE_SSA2_4,    "SSA-2/3/4",sub_SSA2_4Read },
+    { "ssa1",       SUB_TYPE_SSA1,      "SSA-1",    sub_SSARead },
+    { "ssa2-4",     SUB_TYPE_SSA2_4,    "SSA-2/3/4",sub_SSARead },
     { "vplayer",    SUB_TYPE_VPLAYER,   "VPlayer",  sub_Vplayer },
     { "sami",       SUB_TYPE_SAMI,      "SAMI",     sub_Sami },
-    { NULL,         SUB_TYPE_UNKNOWN,   "Unknow",   NULL }
+    { "vobsub",     SUB_TYPE_VOBSUB,    "VobSub",   sub_VobSub },
+    { NULL,         SUB_TYPE_UNKNOWN,   "Unknown",  NULL }
 };
 
+static char * local_stristr( char *psz_big, char *psz_little)
+{
+    char *p_pos = psz_big;
+
+    if (!psz_big || !psz_little || !*psz_little) return psz_big;
+
+    while (*p_pos)
+    {
+       if (toupper(*p_pos) == toupper(*psz_little))
+        {
+           char * psz_cur1 = p_pos + 1;
+           char * psz_cur2 = psz_little + 1;
+           while (*psz_cur1 && *psz_cur2 && toupper(*psz_cur1) == toupper(*psz_cur2))
+            {
+               psz_cur1++;
+               psz_cur2++;
+           }
+           if (!*psz_cur2) return p_pos;
+       }
+       p_pos++;
+    }
+    return NULL;
+}
+
 /*****************************************************************************
  * sub_open: Open a subtitle file and add subtitle ES
  *****************************************************************************/
@@ -241,7 +268,7 @@ static int  sub_open ( subtitle_demux_t *p_sub,
     int     i;
     int     i_sub_type;
     int     i_max;
-    int (*pf_read_subtitle)( text_t *, subtitle_t *, mtime_t ) = NULL;
+    int (*pf_read_subtitle)( subtitle_demux_t *, text_t *, subtitle_t *, mtime_t ) = NULL;
 
     p_sub->i_sub_type = SUB_TYPE_UNKNOWN;
     p_sub->p_es = NULL;
@@ -255,7 +282,7 @@ static int  sub_open ( subtitle_demux_t *p_sub,
         if( psz_name ) free( psz_name );
         return VLC_EGENERIC;
     }
-    
+
     /* *** load the file *** */
     if( text_load( &txt, psz_name ) )
     {
@@ -319,7 +346,7 @@ static int  sub_open ( subtitle_demux_t *p_sub,
                 break;
             }
 
-            if( strstr( s, "<SAMI>" ) )
+            if( local_stristr( s, "<SAMI>" ) )
             {
                 i_sub_type = SUB_TYPE_SAMI;
                 break;
@@ -348,17 +375,18 @@ static int  sub_open ( subtitle_demux_t *p_sub,
                 }
                 else
                 {
-                    i_sub_type = SUB_TYPE_SSA2_4; // I hop this will work
+                    i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
                 }
                 break;
             }
-            else if( strstr( s, "This is a Sub Station Alpha v4 script" ) )
+            else if( local_stristr( s, "This is a Sub Station Alpha v4 script" ) )
             {
-                i_sub_type = SUB_TYPE_SSA2_4; // I hop this will work
+                i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
+                break;
             }
-            else if( !strncmp( s, "Dialogue: Marked", 16  ) )
+            else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
             {
-                i_sub_type = SUB_TYPE_SSA2_4; // could be wrong
+                i_sub_type = SUB_TYPE_SSA2_4; /* could be wrong */
                 break;
             }
             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
@@ -367,6 +395,11 @@ static int  sub_open ( subtitle_demux_t *p_sub,
                 i_sub_type = SUB_TYPE_VPLAYER;
                 break;
             }
+            else if( local_stristr( s, "# VobSub index file" ) )
+            {
+                i_sub_type = SUB_TYPE_VOBSUB;
+                break;
+            }
         }
 
         text_rewind( &txt );
@@ -386,6 +419,7 @@ static int  sub_open ( subtitle_demux_t *p_sub,
         {
             msg_Dbg( p_input, "detected %s format",
                     sub_read_subtitle_function[i].psz_name );
+            p_sub->i_sub_type = i_sub_type;
             pf_read_subtitle = sub_read_subtitle_function[i].pf_read_subtitle;
             break;
         }
@@ -398,15 +432,23 @@ static int  sub_open ( subtitle_demux_t *p_sub,
             i_max += 128;
             if( p_sub->subtitle )
             {
-                p_sub->subtitle = realloc( p_sub->subtitle,
-                                           sizeof( subtitle_t ) * i_max );
+                if( !( p_sub->subtitle = realloc( p_sub->subtitle,
+                                           sizeof( subtitle_t ) * i_max ) ) )
+                {
+                    msg_Err( p_sub, "out of memory");
+                    return VLC_ENOMEM;
+                }
             }
             else
             {
-                p_sub->subtitle = malloc( sizeof( subtitle_t ) * i_max );
+                if( !(  p_sub->subtitle = malloc( sizeof( subtitle_t ) * i_max ) ) )
+                {
+                    msg_Err( p_sub, "out of memory");
+                    return VLC_ENOMEM;
+                }
             }
         }
-        if( pf_read_subtitle( &txt,
+        if( pf_read_subtitle( p_sub, &txt,
                               p_sub->subtitle + p_sub->i_subtitles,
                               i_microsecperframe ) < 0 )
         {
@@ -420,8 +462,11 @@ static int  sub_open ( subtitle_demux_t *p_sub,
     text_unload( &txt );
 
     /* *** fix subtitle (order and time) *** */
-    p_sub->i_subtitle = 0;  // will be modified by sub_fix
-    sub_fix( p_sub );
+    p_sub->i_subtitle = 0;  /* will be modified by sub_fix */
+    if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
+    {
+        sub_fix( p_sub );
+    }
 
     /* *** add subtitle ES *** */
     vlc_mutex_lock( &p_input->stream.stream_lock );
@@ -431,7 +476,28 @@ static int  sub_open ( subtitle_demux_t *p_sub,
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
     p_sub->p_es->i_stream_id = 0xff - i_track_id;    /* FIXME */
-    p_sub->p_es->i_fourcc    = VLC_FOURCC( 's','u','b','t' );
+    
+    if( p_sub->psz_header != NULL )
+    {
+        p_sub->p_es->p_demux_data = malloc( sizeof( subtitle_data_t ) );
+        p_sub->p_es->p_demux_data->psz_header = strdup( p_sub->psz_header );
+        free( p_sub->psz_header );
+    }
+
+    if( p_sub->i_sub_type == SUB_TYPE_VOBSUB )
+    {
+        p_sub->p_es->i_fourcc    = VLC_FOURCC( 's','p','u',' ' );
+        /* open vobsub file */
+    }
+    else if( p_sub->i_sub_type == SUB_TYPE_SSA1 ||
+             p_sub->i_sub_type == SUB_TYPE_SSA2_4 )
+    {
+        p_sub->p_es->i_fourcc    = VLC_FOURCC( 's','s','a',' ' );
+    }
+    else
+    {
+        p_sub->p_es->i_fourcc    = VLC_FOURCC( 's','u','b','t' );
+    }
 
     p_sub->i_previously_selected = 0;
     return VLC_SUCCESS;
@@ -561,8 +627,8 @@ static void sub_close( subtitle_demux_t *p_sub )
         free( p_sub->subtitle );
     }
 }
+
 /*****************************************************************************
- *
  * sub_fix: fix time stamp and order of subtitle
  *****************************************************************************/
 static void  sub_fix( subtitle_demux_t *p_sub )
@@ -622,7 +688,7 @@ static void  sub_fix( subtitle_demux_t *p_sub )
 /*****************************************************************************
  * Specific Subtitle function
  *****************************************************************************/
-static int  sub_MicroDvdRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
+static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
 {
     /*
      * each line:
@@ -667,7 +733,7 @@ static int  sub_MicroDvdRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_mic
     return( 0 );
 }
 
-static int  sub_SubRipRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
+static int  sub_SubRipRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
 {
     /*
      * n
@@ -718,7 +784,7 @@ static int  sub_SubRipRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_micro
                 i_len = strlen( s );
                 if( i_len <= 1 )
                 {
-                    // empty line -> end of this subtitle
+                    /* empty line -> end of this subtitle */
                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
                     p_subtitle->i_start = i_start;
                     p_subtitle->i_stop = i_stop;
@@ -744,15 +810,12 @@ static int  sub_SubRipRead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_micro
 }
 
 
-static int  sub_SSARead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe, int i_comma_count )
+static int  sub_SSARead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
 {
     char buffer_text[ 10 * MAX_LINE];
     char *s;
-    char *p_buffer_text;
     mtime_t     i_start;
     mtime_t     i_stop;
-    int         i_comma;
-    int         i_text;
 
     for( ;; )
     {
@@ -763,8 +826,10 @@ static int  sub_SSARead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsec
         {
             return( VLC_EGENERIC );
         }
+        p_subtitle->psz_text = malloc( strlen( s ) );
+
         if( sscanf( s,
-                    "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
+                    "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d%[^\r\n]",
                     &i_dummy,
                     &h1, &m1, &s1, &c1,
                     &h2, &m2, &s2, &c2,
@@ -780,59 +845,48 @@ static int  sub_SSARead( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsec
                         (mtime_t)s2 * 1000 +
                         (mtime_t)c2 * 10 ) * 1000;
 
-            p_buffer_text = buffer_text;
-            i_comma = 3;
-            while( i_comma < i_comma_count &&
-                   *p_buffer_text != '\0' )
+            /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
+            if( p_sub->i_sub_type == SUB_TYPE_SSA1 )
             {
-                if( *p_buffer_text == ',' )
-                {
-                    i_comma++;
-                }
-                p_buffer_text++;
+                sprintf( p_subtitle->psz_text, ",%d%s", i_dummy, strdup( buffer_text) );
             }
-            p_subtitle->psz_text = malloc( strlen( p_buffer_text ) + 1);
-            i_text = 0;
-            while( *p_buffer_text )
+            else
             {
-                if( *p_buffer_text == '\\' && ( *p_buffer_text =='n' || *p_buffer_text =='N' ) )
-                {
-                    p_subtitle->psz_text[i_text] = '\n';
-                    i_text++;
-                    p_buffer_text += 2;
-                }
-                else if( *p_buffer_text == '{' && *p_buffer_text == '\\')
+                sprintf( p_subtitle->psz_text, ",%d,%s", i_dummy, strdup( buffer_text) );
+            }
+            p_subtitle->i_start = i_start;
+            p_subtitle->i_stop = i_stop;
+            return( 0 );
+        }
+        else
+        {
+            /* All the other stuff we add to the header field */
+            if( p_sub->psz_header != NULL )
+            {
+                if( !( p_sub->psz_header = realloc( p_sub->psz_header,
+                          strlen( p_sub->psz_header ) + strlen( s ) + 2 ) ) )
                 {
-                    while( *p_buffer_text && *p_buffer_text != '}' )
-                    {
-                        p_buffer_text++;
-                    }
+                    msg_Err( p_sub, "out of memory");
+                    return VLC_ENOMEM;
                 }
-                else
+                p_sub->psz_header = strcat( p_sub->psz_header, strdup( s ) );
+                p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
+            }
+            else
+            {
+                if( !( p_sub->psz_header = malloc( strlen( s ) + 2 ) ) )
                 {
-                    p_subtitle->psz_text[i_text] = *p_buffer_text;
-                    i_text++;
-                    p_buffer_text++;
+                    msg_Err( p_sub, "out of memory");
+                    return VLC_ENOMEM;
                 }
+                p_sub->psz_header = strdup( s );
+                p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
             }
-            p_subtitle->psz_text[i_text] = '\0';
-            p_subtitle->i_start = i_start;
-            p_subtitle->i_stop = i_stop;
-            return( 0 );
         }
     }
 }
 
-static int  sub_SSA1Read( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
-{
-    return( sub_SSARead( txt, p_subtitle, i_microsecperframe, 8 ) );
-}
-static int  sub_SSA2_4Read( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
-{
-    return( sub_SSARead( txt, p_subtitle, i_microsecperframe, 9 ) );
-}
-
-static int  sub_Vplayer( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
+static int  sub_Vplayer( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
 {
     /*
      * each line:
@@ -888,9 +942,9 @@ static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
 {
     if( psz_start )
     {
-        if( strstr( psz_start, psz_str ) )
+        if( local_stristr( psz_start, psz_str ) )
         {
-            char *s = strstr( psz_start, psz_str );
+            char *s = local_stristr( psz_start, psz_str );
 
             s += strlen( psz_str );
 
@@ -904,9 +958,9 @@ static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
         {
             return NULL;
         }
-        if( strstr( p, psz_str ) )
+        if( local_stristr( p, psz_str ) )
         {
-            char *s = strstr( p, psz_str );
+            char *s = local_stristr( p, psz_str );
 
             s += strlen( psz_str );
 
@@ -915,7 +969,7 @@ static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
     }
 }
 
-static int  sub_Sami( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
+static int  sub_Sami( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
 {
     char *p;
     int i_start;
@@ -958,11 +1012,11 @@ static int  sub_Sami( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecper
         {
             if( *p == '<' )
             {
-                if( !strncmp( p, "<br", 3 ) || !strncmp( p, "<BR", 3 ) )
+                if( !strncasecmp( p, "<br", 3 ) )
                 {
                     ADDC( '\n' );
                 }
-                else if( strstr( p, "Start=" ) )
+                else if( local_stristr( p, "Start=" ) )
                 {
                     text_previous_line( txt );
                     break;
@@ -1004,3 +1058,46 @@ static int  sub_Sami( text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecper
 #undef ADDC
 }
 
+static int  sub_VobSub( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
+{
+    /*
+     * Parse the idx file. Each line:
+     * timestamp: hh:mm:ss:mss, filepos: loc
+     * hexint is the hex location of the vobsub in the .sub file
+     *
+     */
+    char *p;
+
+    char buffer_text[MAX_LINE + 1];
+    uint32_t    i_start, i_location;
+
+    for( ;; )
+    {
+        unsigned int h, m, s, ms, loc;
+
+        if( ( p = text_get_line( txt ) ) == NULL )
+        {
+            return( VLC_EGENERIC );
+        }
+        i_start = 0;
+
+        memset( buffer_text, '\0', MAX_LINE );
+        if( sscanf( p, "timestamp: %d:%d:%d:%d, filepos: %x%[^\r\n]",
+                    &h, &m, &s, &ms, &loc, buffer_text ) == 5 )
+        {
+            i_start = ( (mtime_t)h * 3600*1000 +
+                        (mtime_t)m * 60*1000 +
+                        (mtime_t)s * 1000 +
+                        (mtime_t)ms ) * 1000;
+            i_location = loc;
+            break;
+        }
+    }
+    p_subtitle->i_start = (mtime_t)i_start;
+    p_subtitle->i_stop  = 0;
+    p_subtitle->i_vobsub_location = i_location;
+    fprintf( stderr, "time: %x, location: %x\n", i_start, i_location );
+    return( 0 );
+}
+
+