]> git.sesse.net Git - vlc/blob - modules/demux/subtitle.c
16ca09c1f0e3ba3ecbc7f2bad658b28dea823a24
[vlc] / modules / demux / subtitle.c
1 /*****************************************************************************
2  * subtitle.c: Demux for subtitle text files.
3  *****************************************************************************
4  * Copyright (C) 1999-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Derk-Jan Hartman <hartman at videolan dot org>
9  *          Jean-Baptiste Kempf <jb@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_input.h>
37
38 #include <errno.h>
39 #ifdef HAVE_SYS_TYPES_H
40 #   include <sys/types.h>
41 #endif
42 #include <ctype.h>
43
44 #include <vlc_demux.h>
45 #include <vlc_charset.h>
46
47 /*****************************************************************************
48  * Module descriptor
49  *****************************************************************************/
50 static int  Open ( vlc_object_t *p_this );
51 static void Close( vlc_object_t *p_this );
52
53 #define SUB_DELAY_LONGTEXT \
54     N_("Apply a delay to all subtitles (in 1/10s, eg 100 means 10s).")
55 #define SUB_FPS_LONGTEXT \
56     N_("Override the normal frames per second settings. " \
57     "This will only work with MicroDVD and SubRIP (SRT) subtitles.")
58 #define SUB_TYPE_LONGTEXT \
59     N_("Force the subtiles format. Valid values are : \"microdvd\", " \
60     "\"subrip\", \"subviewer\", \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\", " \
61     "\"sami\", \"dvdsubtitle\", \"mpl2\", \"aqt\", \"pjs\", "\
62     "\"mpsub\", \"jacosub\", \"psb\", \"realtext\", \"dks\", \"subviewer1\", " \
63     " and \"auto\" (meaning autodetection, this should always work).")
64
65 static const char *const ppsz_sub_type[] =
66 {
67     "auto", "microdvd", "subrip", "subviewer", "ssa1",
68     "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle", "mpl2",
69     "aqt", "pjs", "mpsub", "jacosub", "psb", "realtext", "dks",
70     "subviewer1"
71 };
72
73 vlc_module_begin();
74     set_shortname( N_("Subtitles"));
75     set_description( N_("Text subtitles parser") );
76     set_capability( "demux", 0 );
77     set_category( CAT_INPUT );
78     set_subcategory( SUBCAT_INPUT_DEMUX );
79     add_float( "sub-fps", 0.0, NULL,
80                N_("Frames per second"),
81                SUB_FPS_LONGTEXT, true );
82     add_integer( "sub-delay", 0, NULL,
83                N_("Subtitles delay"),
84                SUB_DELAY_LONGTEXT, true );
85     add_string( "sub-type", "auto", NULL, N_("Subtitles format"),
86                 SUB_TYPE_LONGTEXT, true );
87         change_string_list( ppsz_sub_type, NULL, NULL );
88     set_callbacks( Open, Close );
89
90     add_shortcut( "subtitle" );
91 vlc_module_end();
92
93 /*****************************************************************************
94  * Prototypes:
95  *****************************************************************************/
96 enum
97 {
98     SUB_TYPE_UNKNOWN = -1,
99     SUB_TYPE_MICRODVD,
100     SUB_TYPE_SUBRIP,
101     SUB_TYPE_SSA1,
102     SUB_TYPE_SSA2_4,
103     SUB_TYPE_ASS,
104     SUB_TYPE_VPLAYER,
105     SUB_TYPE_SAMI,
106     SUB_TYPE_SUBVIEWER, /* SUBVIEWER 2 */
107     SUB_TYPE_DVDSUBTITLE, /* Mplayer calls it subviewer2 */
108     SUB_TYPE_MPL2,
109     SUB_TYPE_AQT,
110     SUB_TYPE_PJS,
111     SUB_TYPE_MPSUB,
112     SUB_TYPE_JACOSUB,
113     SUB_TYPE_PSB,
114     SUB_TYPE_RT,
115     SUB_TYPE_DKS,
116     SUB_TYPE_SUBVIEW1 /* SUBVIEWER 1 - mplayer calls it subrip09,
117                          and Gnome subtitles SubViewer 1.0 */
118 };
119
120 typedef struct
121 {
122     int     i_line_count;
123     int     i_line;
124     char    **line;
125 } text_t;
126
127 static int  TextLoad( text_t *, stream_t *s );
128 static void TextUnload( text_t * );
129
130 typedef struct
131 {
132     int64_t i_start;
133     int64_t i_stop;
134
135     char    *psz_text;
136 } subtitle_t;
137
138
139 struct demux_sys_t
140 {
141     int         i_type;
142     text_t      txt;
143     es_out_id_t *es;
144
145     int64_t     i_next_demux_date;
146     int64_t     i_microsecperframe;
147
148     char        *psz_header;
149     int         i_subtitle;
150     int         i_subtitles;
151     subtitle_t  *subtitle;
152
153     int64_t     i_length;
154
155     /* */
156     struct
157     {
158         bool b_inited;
159
160         int i_comment;
161         int i_time_resolution;
162         int i_time_shift;
163     } jss;
164     struct
165     {
166         bool  b_inited;
167
168         float f_total;
169         float f_factor;
170     } mpsub;
171 };
172
173 static int  ParseMicroDvd   ( demux_t *, subtitle_t *, int );
174 static int  ParseSubRip     ( demux_t *, subtitle_t *, int );
175 static int  ParseSubViewer  ( demux_t *, subtitle_t *, int );
176 static int  ParseSSA        ( demux_t *, subtitle_t *, int );
177 static int  ParseVplayer    ( demux_t *, subtitle_t *, int );
178 static int  ParseSami       ( demux_t *, subtitle_t *, int );
179 static int  ParseDVDSubtitle( demux_t *, subtitle_t *, int );
180 static int  ParseMPL2       ( demux_t *, subtitle_t *, int );
181 static int  ParseAQT        ( demux_t *, subtitle_t *, int );
182 static int  ParsePJS        ( demux_t *, subtitle_t *, int );
183 static int  ParseMPSub      ( demux_t *, subtitle_t *, int );
184 static int  ParseJSS        ( demux_t *, subtitle_t *, int );
185 static int  ParsePSB        ( demux_t *, subtitle_t *, int );
186 static int  ParseRealText   ( demux_t *, subtitle_t *, int );
187 static int  ParseDKS        ( demux_t *, subtitle_t *, int );
188 static int  ParseSubViewer1 ( demux_t *, subtitle_t *, int );
189
190 static const struct
191 {
192     const char *psz_type_name;
193     int  i_type;
194     const char *psz_name;
195     int  (*pf_read)( demux_t *, subtitle_t*, int );
196 } sub_read_subtitle_function [] =
197 {
198     { "microdvd",   SUB_TYPE_MICRODVD,    "MicroDVD",    ParseMicroDvd },
199     { "subrip",     SUB_TYPE_SUBRIP,      "SubRIP",      ParseSubRip },
200     { "subviewer",  SUB_TYPE_SUBVIEWER,   "SubViewer",   ParseSubViewer },
201     { "ssa1",       SUB_TYPE_SSA1,        "SSA-1",       ParseSSA },
202     { "ssa2-4",     SUB_TYPE_SSA2_4,      "SSA-2/3/4",   ParseSSA },
203     { "ass",        SUB_TYPE_ASS,         "SSA/ASS",     ParseSSA },
204     { "vplayer",    SUB_TYPE_VPLAYER,     "VPlayer",     ParseVplayer },
205     { "sami",       SUB_TYPE_SAMI,        "SAMI",        ParseSami },
206     { "dvdsubtitle",SUB_TYPE_DVDSUBTITLE, "DVDSubtitle", ParseDVDSubtitle },
207     { "mpl2",       SUB_TYPE_MPL2,        "MPL2",        ParseMPL2 },
208     { "aqt",        SUB_TYPE_AQT,         "AQTitle",     ParseAQT },
209     { "pjs",        SUB_TYPE_PJS,         "PhoenixSub",  ParsePJS },
210     { "mpsub",      SUB_TYPE_MPSUB,       "MPSub",       ParseMPSub },
211     { "jacosub",    SUB_TYPE_JACOSUB,     "JacoSub",     ParseJSS },
212     { "psb",        SUB_TYPE_PSB,         "PowerDivx",   ParsePSB },
213     { "realtext",   SUB_TYPE_RT,          "RealText",    ParseRealText },
214     { "dks",        SUB_TYPE_DKS,         "DKS",         ParseDKS },
215     { "subviewer1", SUB_TYPE_SUBVIEW1,    "Subviewer 1", ParseSubViewer1 },
216     { NULL,         SUB_TYPE_UNKNOWN,     "Unknown",     NULL }
217 };
218 /* When adding support for more formats, be sure to add their file extension
219  * to src/input/subtitles.c to enable auto-detection.
220  */
221
222 static int Demux( demux_t * );
223 static int Control( demux_t *, int, va_list );
224
225 /*static void Fix( demux_t * );*/
226
227 /*****************************************************************************
228  * Module initializer
229  *****************************************************************************/
230 static int Open ( vlc_object_t *p_this )
231 {
232     demux_t        *p_demux = (demux_t*)p_this;
233     demux_sys_t    *p_sys;
234     es_format_t    fmt;
235     float          f_fps;
236     char           *psz_type;
237     int  (*pf_read)( demux_t *, subtitle_t*, int );
238     int            i, i_max;
239
240     if( !p_demux->b_force )
241     {
242         msg_Dbg( p_demux, "subtitle demux discarded" );
243         return VLC_EGENERIC;
244     }
245
246     p_demux->pf_demux = Demux;
247     p_demux->pf_control = Control;
248     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
249     if( p_sys == NULL )
250         return VLC_ENOMEM;
251
252     p_sys->psz_header         = NULL;
253     p_sys->i_subtitle         = 0;
254     p_sys->i_subtitles        = 0;
255     p_sys->subtitle           = NULL;
256     p_sys->i_microsecperframe = 40000;
257
258     p_sys->jss.b_inited       = false;
259     p_sys->mpsub.b_inited     = false;
260
261     /* Get the FPS */
262     f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" ); /* FIXME */
263     if( f_fps >= 1.0 )
264         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
265
266     msg_Dbg( p_demux, "Movie fps: %f", f_fps );
267
268     /* Check for override of the fps */
269     f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
270     if( f_fps >= 1.0 )
271     {
272         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
273         msg_Dbg( p_demux, "Override subtitle fps %f", f_fps );
274     }
275
276     /* Get or probe the type */
277     p_sys->i_type = SUB_TYPE_UNKNOWN;
278     psz_type = var_CreateGetString( p_demux, "sub-type" );
279     if( psz_type && *psz_type )
280     {
281         int i;
282
283         for( i = 0; ; i++ )
284         {
285             if( sub_read_subtitle_function[i].psz_type_name == NULL )
286                 break;
287
288             if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
289                          psz_type ) )
290             {
291                 p_sys->i_type = sub_read_subtitle_function[i].i_type;
292                 break;
293             }
294         }
295     }
296     free( psz_type );
297
298     /* Probe if unknown type */
299     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
300     {
301         int     i_try;
302         char    *s = NULL;
303
304         msg_Dbg( p_demux, "autodetecting subtitle format" );
305         for( i_try = 0; i_try < 256; i_try++ )
306         {
307             int i_dummy;
308             char p_dummy;
309
310             if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
311                 break;
312
313             if( strcasestr( s, "<SAMI>" ) )
314             {
315                 p_sys->i_type = SUB_TYPE_SAMI;
316                 break;
317             }
318             else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
319                      sscanf( s, "{%d}{}", &i_dummy ) == 1)
320             {
321                 p_sys->i_type = SUB_TYPE_MICRODVD;
322                 break;
323             }
324             else if( sscanf( s,
325                              "%d:%d:%d,%d --> %d:%d:%d,%d",
326                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
327                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
328             {
329                 p_sys->i_type = SUB_TYPE_SUBRIP;
330                 break;
331             }
332             else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
333             {
334                 p_sys->i_type = SUB_TYPE_SSA1;
335                 break;
336             }
337             else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
338             {
339                 p_sys->i_type = SUB_TYPE_ASS;
340                 break;
341             }
342             else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
343             {
344                 p_sys->i_type = SUB_TYPE_SSA2_4;
345                 break;
346             }
347             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
348             {
349                 p_sys->i_type = SUB_TYPE_SSA2_4;
350                 break;
351             }
352             else if( !strncasecmp( s, "Dialogue:", 9  ) )
353             {
354                 p_sys->i_type = SUB_TYPE_ASS;
355                 break;
356             }
357             else if( strcasestr( s, "[INFORMATION]" ) )
358             {
359                 p_sys->i_type = SUB_TYPE_SUBVIEWER; /* I hope this will work */
360                 break;
361             }
362             else if( sscanf( s, "%d:%d:%d.%d %d:%d:%d",
363                                  &i_dummy, &i_dummy, &i_dummy, &i_dummy,
364                                  &i_dummy, &i_dummy, &i_dummy ) == 7 ||
365                      sscanf( s, "@%d @%d", &i_dummy, &i_dummy) == 2)
366             {
367                 p_sys->i_type = SUB_TYPE_JACOSUB;
368                 break;
369             }
370             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
371                      sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
372             {
373                 p_sys->i_type = SUB_TYPE_VPLAYER;
374                 break;
375             }
376             else if( sscanf( s, "{T %d:%d:%d:%d", &i_dummy, &i_dummy,
377                              &i_dummy, &i_dummy ) == 4 )
378             {
379                 p_sys->i_type = SUB_TYPE_DVDSUBTITLE;
380                 break;
381             }
382             else if( sscanf( s, "[%d:%d:%d]%c",
383                      &i_dummy, &i_dummy, &i_dummy, &p_dummy ) == 4 )
384             {
385                 p_sys->i_type = SUB_TYPE_DKS;
386                 break;
387             }
388             else if( strstr( s, "*** START SCRIPT" ) )
389             {
390                 p_sys->i_type = SUB_TYPE_SUBVIEW1;
391                 break;
392             }
393             else if( sscanf( s, "[%d][%d]", &i_dummy, &i_dummy ) == 2 ||
394                      sscanf( s, "[%d][]", &i_dummy ) == 1)
395             {
396                 p_sys->i_type = SUB_TYPE_MPL2;
397                 break;
398             }
399             else if( sscanf (s, "FORMAT=%d", &i_dummy) == 1 ||
400                      ( sscanf (s, "FORMAT=TIM%c", &p_dummy) == 1
401                        && p_dummy =='E' ) )
402             {
403                 p_sys->i_type = SUB_TYPE_MPSUB;
404                 break;
405             }
406             else if( sscanf( s, "-->> %d", &i_dummy) == 1 )
407             {
408                 p_sys->i_type = SUB_TYPE_AQT;
409                 break;
410             }
411             else if( sscanf( s, "%d,%d,", &i_dummy, &i_dummy ) == 2 )
412             {
413                 p_sys->i_type = SUB_TYPE_PJS;
414                 break;
415             }
416             else if( sscanf( s, "{%d:%d:%d}",
417                                 &i_dummy, &i_dummy, &i_dummy ) == 3 )
418             {
419                 p_sys->i_type = SUB_TYPE_PSB;
420                 break;
421             }
422             else if( strcasestr( s, "<time" ) )
423             {
424                 p_sys->i_type = SUB_TYPE_RT;
425                 break;
426             }
427
428             free( s );
429             s = NULL;
430         }
431
432         free( s );
433
434         /* It will nearly always work even for non seekable stream thanks the
435          * caching system, and if it fails we lose just a few sub */
436         if( stream_Seek( p_demux->s, 0 ) )
437         {
438             msg_Warn( p_demux, "failed to rewind" );
439         }
440     }
441
442     /* Quit on unknown subtitles */
443     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
444     {
445         msg_Err( p_demux, "failed to recognize subtitle type" );
446         free( p_sys );
447         return VLC_EGENERIC;
448     }
449
450     for( i = 0; ; i++ )
451     {
452         if( sub_read_subtitle_function[i].i_type == p_sys->i_type )
453         {
454             msg_Dbg( p_demux, "detected %s format",
455                      sub_read_subtitle_function[i].psz_name );
456             pf_read = sub_read_subtitle_function[i].pf_read;
457             break;
458         }
459     }
460
461     msg_Dbg( p_demux, "loading all subtitles..." );
462
463     /* Load the whole file */
464     TextLoad( &p_sys->txt, p_demux->s );
465
466     /* Parse it */
467     for( i_max = 0;; )
468     {
469         if( p_sys->i_subtitles >= i_max )
470         {
471             i_max += 500;
472             if( !( p_sys->subtitle = realloc( p_sys->subtitle,
473                                               sizeof(subtitle_t) * i_max ) ) )
474             {
475                 free( p_sys->subtitle );
476                 TextUnload( &p_sys->txt );
477                 free( p_sys );
478                 return VLC_ENOMEM;
479             }
480         }
481
482         if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles],
483                      p_sys->i_subtitles ) )
484             break;
485
486         p_sys->i_subtitles++;
487     }
488     /* Unload */
489     TextUnload( &p_sys->txt );
490
491     msg_Dbg(p_demux, "loaded %d subtitles", p_sys->i_subtitles );
492
493     /* Fix subtitle (order and time) *** */
494     p_sys->i_subtitle = 0;
495     p_sys->i_length = 0;
496     if( p_sys->i_subtitles > 0 )
497     {
498         p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_stop;
499         /* +1 to avoid 0 */
500         if( p_sys->i_length <= 0 )
501             p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_start+1;
502     }
503
504     /* *** add subtitle ES *** */
505     if( p_sys->i_type == SUB_TYPE_SSA1 ||
506              p_sys->i_type == SUB_TYPE_SSA2_4 ||
507              p_sys->i_type == SUB_TYPE_ASS )
508     {
509         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
510     }
511     else
512     {
513         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
514     }
515     if( p_sys->psz_header != NULL )
516     {
517         fmt.i_extra = strlen( p_sys->psz_header ) + 1;
518         fmt.p_extra = strdup( p_sys->psz_header );
519     }
520     p_sys->es = es_out_Add( p_demux->out, &fmt );
521
522     return VLC_SUCCESS;
523 }
524
525 /*****************************************************************************
526  * Close: Close subtitle demux
527  *****************************************************************************/
528 static void Close( vlc_object_t *p_this )
529 {
530     demux_t *p_demux = (demux_t*)p_this;
531     demux_sys_t *p_sys = p_demux->p_sys;
532     int i;
533
534     for( i = 0; i < p_sys->i_subtitles; i++ )
535         free( p_sys->subtitle[i].psz_text );
536     free( p_sys->subtitle );
537
538     free( p_sys );
539 }
540
541 /*****************************************************************************
542  * Control:
543  *****************************************************************************/
544 static int Control( demux_t *p_demux, int i_query, va_list args )
545 {
546     demux_sys_t *p_sys = p_demux->p_sys;
547     int64_t *pi64, i64;
548     double *pf, f;
549
550     switch( i_query )
551     {
552         case DEMUX_GET_LENGTH:
553             pi64 = (int64_t*)va_arg( args, int64_t * );
554             *pi64 = p_sys->i_length;
555             return VLC_SUCCESS;
556
557         case DEMUX_GET_TIME:
558             pi64 = (int64_t*)va_arg( args, int64_t * );
559             if( p_sys->i_subtitle < p_sys->i_subtitles )
560             {
561                 *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
562                 return VLC_SUCCESS;
563             }
564             return VLC_EGENERIC;
565
566         case DEMUX_SET_TIME:
567             i64 = (int64_t)va_arg( args, int64_t );
568             p_sys->i_subtitle = 0;
569             while( p_sys->i_subtitle < p_sys->i_subtitles )
570             {
571                 const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
572
573                 if( p_subtitle->i_start > i64 )
574                     break;
575                 if( p_subtitle->i_stop > p_subtitle->i_start && p_subtitle->i_stop > i64 )
576                     break;
577
578                 p_sys->i_subtitle++;
579             }
580
581             if( p_sys->i_subtitle >= p_sys->i_subtitles )
582                 return VLC_EGENERIC;
583             return VLC_SUCCESS;
584
585         case DEMUX_GET_POSITION:
586             pf = (double*)va_arg( args, double * );
587             if( p_sys->i_subtitle >= p_sys->i_subtitles )
588             {
589                 *pf = 1.0;
590             }
591             else if( p_sys->i_subtitles > 0 )
592             {
593                 *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
594                       (double)p_sys->i_length;
595             }
596             else
597             {
598                 *pf = 0.0;
599             }
600             return VLC_SUCCESS;
601
602         case DEMUX_SET_POSITION:
603             f = (double)va_arg( args, double );
604             i64 = f * p_sys->i_length;
605
606             p_sys->i_subtitle = 0;
607             while( p_sys->i_subtitle < p_sys->i_subtitles &&
608                    p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
609             {
610                 p_sys->i_subtitle++;
611             }
612             if( p_sys->i_subtitle >= p_sys->i_subtitles )
613                 return VLC_EGENERIC;
614             return VLC_SUCCESS;
615
616         case DEMUX_SET_NEXT_DEMUX_TIME:
617             p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
618             return VLC_SUCCESS;
619
620         case DEMUX_GET_FPS:
621         case DEMUX_GET_META:
622         case DEMUX_GET_ATTACHMENTS:
623         case DEMUX_GET_TITLE_INFO:
624         case DEMUX_HAS_UNSUPPORTED_META:
625         case DEMUX_CAN_RECORD:
626             return VLC_EGENERIC;
627
628         default:
629             msg_Err( p_demux, "unknown query %d in subtitle control", i_query );
630             return VLC_EGENERIC;
631     }
632 }
633
634 /*****************************************************************************
635  * Demux: Send subtitle to decoder
636  *****************************************************************************/
637 static int Demux( demux_t *p_demux )
638 {
639     demux_sys_t *p_sys = p_demux->p_sys;
640     int64_t i_maxdate;
641
642     if( p_sys->i_subtitle >= p_sys->i_subtitles )
643         return 0;
644
645     i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
646     if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
647     {
648         /* Should not happen */
649         i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
650     }
651
652     while( p_sys->i_subtitle < p_sys->i_subtitles &&
653            p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
654     {
655         const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
656
657         block_t *p_block;
658         int i_len = strlen( p_subtitle->psz_text ) + 1;
659
660         if( i_len <= 1 || p_subtitle->i_start < 0 )
661         {
662             p_sys->i_subtitle++;
663             continue;
664         }
665
666         if( ( p_block = block_New( p_demux, i_len ) ) == NULL )
667         {
668             p_sys->i_subtitle++;
669             continue;
670         }
671
672         p_block->i_dts =
673         p_block->i_pts = 1 + p_subtitle->i_start;
674         if( p_subtitle->i_stop > 0 && p_subtitle->i_stop >= p_subtitle->i_start )
675             p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
676
677         memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
678
679         es_out_Send( p_demux->out, p_sys->es, p_block );
680
681         p_sys->i_subtitle++;
682     }
683
684     /* */
685     p_sys->i_next_demux_date = 0;
686
687     return 1;
688 }
689
690 /*****************************************************************************
691  * Fix: fix time stamp and order of subtitle
692  *****************************************************************************/
693 #ifdef USE_THIS_UNUSED_PIECE_OF_CODE
694 static void Fix( demux_t *p_demux )
695 {
696     demux_sys_t *p_sys = p_demux->p_sys;
697     bool b_done;
698     int     i_index;
699
700     /* *** fix order (to be sure...) *** */
701     /* We suppose that there are near in order and this durty bubble sort
702      * wont take too much time
703      */
704     do
705     {
706         b_done = true;
707         for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
708         {
709             if( p_sys->subtitle[i_index].i_start <
710                     p_sys->subtitle[i_index - 1].i_start )
711             {
712                 subtitle_t sub_xch;
713                 memcpy( &sub_xch,
714                         p_sys->subtitle + i_index - 1,
715                         sizeof( subtitle_t ) );
716                 memcpy( p_sys->subtitle + i_index - 1,
717                         p_sys->subtitle + i_index,
718                         sizeof( subtitle_t ) );
719                 memcpy( p_sys->subtitle + i_index,
720                         &sub_xch,
721                         sizeof( subtitle_t ) );
722                 b_done = false;
723             }
724         }
725     } while( !b_done );
726 }
727 #endif
728
729 static int TextLoad( text_t *txt, stream_t *s )
730 {
731     int   i_line_max;
732
733     /* init txt */
734     i_line_max          = 500;
735     txt->i_line_count   = 0;
736     txt->i_line         = 0;
737     txt->line           = calloc( i_line_max, sizeof( char * ) );
738
739     /* load the complete file */
740     for( ;; )
741     {
742         char *psz = stream_ReadLine( s );
743
744         if( psz == NULL )
745             break;
746
747         txt->line[txt->i_line_count++] = psz;
748         if( txt->i_line_count >= i_line_max )
749         {
750             i_line_max += 100;
751             txt->line = realloc( txt->line, i_line_max * sizeof( char * ) );
752         }
753     }
754
755     if( txt->i_line_count <= 0 )
756     {
757         free( txt->line );
758         return VLC_EGENERIC;
759     }
760
761     return VLC_SUCCESS;
762 }
763 static void TextUnload( text_t *txt )
764 {
765     int i;
766
767     for( i = 0; i < txt->i_line_count; i++ )
768     {
769         free( txt->line[i] );
770     }
771     free( txt->line );
772     txt->i_line       = 0;
773     txt->i_line_count = 0;
774 }
775
776 static char *TextGetLine( text_t *txt )
777 {
778     if( txt->i_line >= txt->i_line_count )
779         return( NULL );
780
781     return txt->line[txt->i_line++];
782 }
783 static void TextPreviousLine( text_t *txt )
784 {
785     if( txt->i_line > 0 )
786         txt->i_line--;
787 }
788
789 /*****************************************************************************
790  * Specific Subtitle function
791  *****************************************************************************/
792 /* ParseMicroDvd:
793  *  Format:
794  *      {n1}{n2}Line1|Line2|Line3....
795  *  where n1 and n2 are the video frame number (n2 can be empty)
796  */
797 static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle,
798                           int i_idx )
799 {
800     VLC_UNUSED( i_idx );
801     demux_sys_t *p_sys = p_demux->p_sys;
802     text_t      *txt = &p_sys->txt;
803     char *psz_text;
804     int  i_start;
805     int  i_stop;
806     int  i;
807
808     for( ;; )
809     {
810         const char *s = TextGetLine( txt );
811         if( !s )
812             return VLC_EGENERIC;
813
814         psz_text = malloc( strlen(s) + 1 );
815         if( !psz_text )
816             return VLC_ENOMEM;
817
818         i_start = 0;
819         i_stop  = 0;
820         if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, psz_text ) == 2 ||
821             sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
822         {
823             float f_fps;
824             if( i_start != 1 || i_stop != 1 )
825                 break;
826
827             /* We found a possible setting of the framerate "{1}{1}23.976" */
828             /* Check if it's usable, and if the sub-fps is not set */
829             f_fps = us_strtod( psz_text, NULL );
830             if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
831                 p_sys->i_microsecperframe = (int64_t)((float)1000000 / f_fps);
832         }
833         free( psz_text );
834     }
835
836     /* replace | by \n */
837     for( i = 0; psz_text[i] != '\0'; i++ )
838     {
839         if( psz_text[i] == '|' )
840             psz_text[i] = '\n';
841     }
842
843     /* */
844     p_subtitle->i_start  = i_start * p_sys->i_microsecperframe;
845     p_subtitle->i_stop   = i_stop  * p_sys->i_microsecperframe;
846     p_subtitle->psz_text = psz_text;
847     return VLC_SUCCESS;
848 }
849
850 /* ParseSubRipSubViewer
851  *  Format SubRip
852  *      n
853  *      h1:m1:s1,d1 --> h2:m2:s2,d2
854  *      Line1
855  *      Line2
856  *      ....
857  *      [Empty line]
858  *  Format SubViewer v1/v2
859  *      h1:m1:s1.d1,h2:m2:s2.d2
860  *      Line1[br]Line2
861  *      Line3
862  *      ...
863  *      [empty line]
864  *  We ignore line number for SubRip
865  */
866 static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
867                                  const char *psz_fmt,
868                                  bool b_replace_br )
869 {
870     demux_sys_t *p_sys = p_demux->p_sys;
871     text_t      *txt = &p_sys->txt;
872     char    *psz_text;
873
874     for( ;; )
875     {
876         const char *s = TextGetLine( txt );
877         int h1, m1, s1, d1, h2, m2, s2, d2;
878
879         if( !s )
880             return VLC_EGENERIC;
881
882         if( sscanf( s, psz_fmt,
883                     &h1, &m1, &s1, &d1,
884                     &h2, &m2, &s2, &d2 ) == 8 )
885         {
886             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
887                                     (int64_t)m1 * 60*1000 +
888                                     (int64_t)s1 * 1000 +
889                                     (int64_t)d1 ) * 1000;
890
891             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
892                                     (int64_t)m2 * 60*1000 +
893                                     (int64_t)s2 * 1000 +
894                                     (int64_t)d2 ) * 1000;
895             break;
896         }
897     }
898
899     /* Now read text until an empty line */
900     psz_text = strdup("");
901     if( !psz_text )
902         return VLC_ENOMEM;
903
904     for( ;; )
905     {
906         const char *s = TextGetLine( txt );
907         int i_len;
908         int i_old;
909
910         i_len = s ? strlen( s ) : 0;
911         if( i_len <= 0 )
912         {
913             p_subtitle->psz_text = psz_text;
914             return VLC_SUCCESS;
915         }
916
917         i_old = strlen( psz_text );
918         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
919         if( !psz_text )
920         {
921             return VLC_ENOMEM;
922         }
923         strcat( psz_text, s );
924         strcat( psz_text, "\n" );
925
926         /* replace [br] by \n */
927         if( b_replace_br )
928         {
929             char *p;
930
931             while( ( p = strstr( psz_text, "[br]" ) ) )
932             {
933                 *p++ = '\n';
934                 memmove( p, &p[3], strlen(&p[3])+1 );
935             }
936         }
937     }
938 }
939 /* ParseSubRip
940  */
941 static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,
942                          int i_idx )
943 {
944     VLC_UNUSED( i_idx );
945     return ParseSubRipSubViewer( p_demux, p_subtitle,
946                                  "%d:%d:%d,%d --> %d:%d:%d,%d",
947                                  false );
948 }
949 /* ParseSubViewer
950  */
951 static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
952                             int i_idx )
953 {
954     VLC_UNUSED( i_idx );
955
956     return ParseSubRipSubViewer( p_demux, p_subtitle,
957                                  "%d:%d:%d.%d,%d:%d:%d.%d",
958                                  true );
959 }
960
961 /* ParseSSA
962  */
963 static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle,
964                       int i_idx )
965 {
966     demux_sys_t *p_sys = p_demux->p_sys;
967     text_t      *txt = &p_sys->txt;
968
969     for( ;; )
970     {
971         const char *s = TextGetLine( txt );
972         int h1, m1, s1, c1, h2, m2, s2, c2;
973         char *psz_text;
974         char temp[16];
975
976         if( !s )
977             return VLC_EGENERIC;
978
979         /* We expect (SSA2-4):
980          * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
981          * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
982          *
983          * 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.
984          */
985
986         /* For ASS:
987          * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
988          * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
989          */
990
991         /* The output text is - at least, not removing numbers - 18 chars shorter than the input text. */
992         psz_text = malloc( strlen(s) );
993         if( !psz_text )
994             return VLC_ENOMEM;
995
996         if( sscanf( s,
997                     "Dialogue: %15[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
998                     temp,
999                     &h1, &m1, &s1, &c1,
1000                     &h2, &m2, &s2, &c2,
1001                     psz_text ) == 10 )
1002         {
1003             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
1004             /* (Layer comes from ASS specs ... it's empty for SSA.) */
1005             if( p_sys->i_type == SUB_TYPE_SSA1 )
1006             {
1007                 /* SSA1 has only 8 commas before the text starts, not 9 */
1008                 memmove( &psz_text[1], psz_text, strlen(psz_text)+1 );
1009                 psz_text[0] = ',';
1010             }
1011             else
1012             {
1013                 int i_layer = ( p_sys->i_type == SUB_TYPE_ASS ) ? atoi( temp ) : 0;
1014
1015                 /* ReadOrder, Layer, %s(rest of fields) */
1016                 snprintf( temp, sizeof(temp), "%d,%d,", i_idx, i_layer );
1017                 memmove( psz_text + strlen(temp), psz_text, strlen(psz_text)+1 );
1018                 memcpy( psz_text, temp, strlen(temp) );
1019             }
1020
1021             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1022                                     (int64_t)m1 * 60*1000 +
1023                                     (int64_t)s1 * 1000 +
1024                                     (int64_t)c1 * 10 ) * 1000;
1025             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1026                                     (int64_t)m2 * 60*1000 +
1027                                     (int64_t)s2 * 1000 +
1028                                     (int64_t)c2 * 10 ) * 1000;
1029             p_subtitle->psz_text = psz_text;
1030             return VLC_SUCCESS;
1031         }
1032         free( psz_text );
1033
1034         /* All the other stuff we add to the header field */
1035         if( !p_sys->psz_header )
1036             p_sys->psz_header = strdup( "" );
1037         if( !p_sys->psz_header )
1038             return VLC_ENOMEM;
1039
1040         p_sys->psz_header =
1041             realloc( p_sys->psz_header,
1042                      strlen( p_sys->psz_header ) + strlen( s ) + 2 );
1043         strcat( p_sys->psz_header,  s );
1044         strcat( p_sys->psz_header, "\n" );
1045     }
1046 }
1047
1048 /* ParseVplayer
1049  *  Format
1050  *      h:m:s:Line1|Line2|Line3....
1051  *  or
1052  *      h:m:s Line1|Line2|Line3....
1053  */
1054 static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle,
1055                           int i_idx )
1056 {
1057     VLC_UNUSED( i_idx );
1058
1059     demux_sys_t *p_sys = p_demux->p_sys;
1060     text_t      *txt = &p_sys->txt;
1061     char *psz_text;
1062     int i;
1063
1064     for( ;; )
1065     {
1066         const char *s = TextGetLine( txt );
1067         int h1, m1, s1;
1068
1069         if( !s )
1070             return VLC_EGENERIC;
1071
1072         psz_text = malloc( strlen( s ) + 1 );
1073         if( !psz_text )
1074             return VLC_ENOMEM;
1075
1076         if( sscanf( s, "%d:%d:%d%*c%[^\r\n]",
1077                     &h1, &m1, &s1, psz_text ) == 4 )
1078         {
1079             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1080                                     (int64_t)m1 * 60*1000 +
1081                                     (int64_t)s1 * 1000 ) * 1000;
1082             p_subtitle->i_stop  = 0;
1083             break;
1084         }
1085         free( psz_text );
1086     }
1087
1088     /* replace | by \n */
1089     for( i = 0; psz_text[i] != '\0'; i++ )
1090     {
1091         if( psz_text[i] == '|' )
1092             psz_text[i] = '\n';
1093     }
1094     p_subtitle->psz_text = psz_text;
1095     return VLC_SUCCESS;
1096 }
1097
1098 /* ParseSami
1099  */
1100 static char *ParseSamiSearch( text_t *txt,
1101                               char *psz_start, const char *psz_str )
1102 {
1103     if( psz_start && strcasestr( psz_start, psz_str ) )
1104     {
1105         char *s = strcasestr( psz_start, psz_str );
1106         return &s[strlen( psz_str )];
1107     }
1108
1109     for( ;; )
1110     {
1111         char *p = TextGetLine( txt );
1112         if( !p )
1113             return NULL;
1114
1115         if( strcasestr( p, psz_str ) )
1116         {
1117             char *s = strcasestr( p, psz_str );
1118             return &s[strlen( psz_str )];
1119         }
1120     }
1121 }
1122 static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1123 {
1124     VLC_UNUSED( i_idx );
1125     demux_sys_t *p_sys = p_demux->p_sys;
1126     text_t      *txt = &p_sys->txt;
1127
1128     char *s;
1129     int64_t i_start;
1130
1131     unsigned int i_text;
1132     char text[8192]; /* Arbitrary but should be long enough */
1133
1134     /* search "Start=" */
1135     if( !( s = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1136         return VLC_EGENERIC;
1137
1138     /* get start value */
1139     i_start = strtol( s, &s, 0 );
1140
1141     /* search <P */
1142     if( !( s = ParseSamiSearch( txt, s, "<P" ) ) )
1143         return VLC_EGENERIC;
1144
1145     /* search > */
1146     if( !( s = ParseSamiSearch( txt, s, ">" ) ) )
1147         return VLC_EGENERIC;
1148
1149     i_text = 0;
1150     text[0] = '\0';
1151     /* now get all txt until  a "Start=" line */
1152     for( ;; )
1153     {
1154         char c = '\0';
1155         /* Search non empty line */
1156         while( s && *s == '\0' )
1157             s = TextGetLine( txt );
1158         if( !s )
1159             break;
1160
1161         if( *s == '<' )
1162         {
1163             if( !strncasecmp( s, "<br", 3 ) )
1164             {
1165                 c = '\n';
1166             }
1167             else if( strcasestr( s, "Start=" ) )
1168             {
1169                 TextPreviousLine( txt );
1170                 break;
1171             }
1172             s = ParseSamiSearch( txt, s, ">" );
1173         }
1174         else if( !strncmp( s, "&nbsp;", 6 ) )
1175         {
1176             c = ' ';
1177             s += 6;
1178         }
1179         else if( *s == '\t' )
1180         {
1181             c = ' ';
1182             s++;
1183         }
1184         else
1185         {
1186             c = *s;
1187             s++;
1188         }
1189         if( c != '\0' && i_text+1 < sizeof(text) )
1190         {
1191             text[i_text++] = c;
1192             text[i_text] = '\0';
1193         }
1194     }
1195
1196     p_subtitle->i_start = i_start * 1000;
1197     p_subtitle->i_stop  = 0;
1198     p_subtitle->psz_text = strdup( text );
1199
1200     return VLC_SUCCESS;
1201 }
1202
1203 /* ParseDVDSubtitle
1204  *  Format
1205  *      {T h1:m1:s1:c1
1206  *      Line1
1207  *      Line2
1208  *      ...
1209  *      }
1210  * TODO it can have a header
1211  *      { HEAD
1212  *          ...
1213  *          CODEPAGE=...
1214  *          FORMAT=...
1215  *          LANG=English
1216  *      }
1217  *      LANG support would be cool
1218  *      CODEPAGE is probably mandatory FIXME
1219  */
1220 static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle,
1221                              int i_idx )
1222 {
1223     VLC_UNUSED( i_idx );
1224
1225     demux_sys_t *p_sys = p_demux->p_sys;
1226     text_t      *txt = &p_sys->txt;
1227     char *psz_text;
1228
1229     for( ;; )
1230     {
1231         const char *s = TextGetLine( txt );
1232         int h1, m1, s1, c1;
1233
1234         if( !s )
1235             return VLC_EGENERIC;
1236
1237         if( sscanf( s,
1238                     "{T %d:%d:%d:%d",
1239                     &h1, &m1, &s1, &c1 ) == 4 )
1240         {
1241             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1242                                     (int64_t)m1 * 60*1000 +
1243                                     (int64_t)s1 * 1000 +
1244                                     (int64_t)c1 * 10) * 1000;
1245             p_subtitle->i_stop = 0;
1246             break;
1247         }
1248     }
1249
1250     /* Now read text until a line containing "}" */
1251     psz_text = strdup("");
1252     if( !psz_text )
1253         return VLC_ENOMEM;
1254     for( ;; )
1255     {
1256         const char *s = TextGetLine( txt );
1257         int i_len;
1258         int i_old;
1259
1260         if( !s )
1261         {
1262             free( psz_text );
1263             return VLC_EGENERIC;
1264         }
1265
1266         i_len = strlen( s );
1267         if( i_len == 1 && s[0] == '}')
1268         {
1269             p_subtitle->psz_text = psz_text;
1270             return VLC_SUCCESS;
1271         }
1272
1273         i_old = strlen( psz_text );
1274         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1275         if( !psz_text )
1276             return VLC_ENOMEM;
1277         strcat( psz_text, s );
1278         strcat( psz_text, "\n" );
1279     }
1280 }
1281
1282 /* ParseMPL2
1283  *  Format
1284  *     [n1][n2]Line1|Line2|Line3...
1285  *  where n1 and n2 are the video frame number (n2 can be empty)
1286  */
1287 static int ParseMPL2( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1288 {
1289     VLC_UNUSED( i_idx );
1290
1291     demux_sys_t *p_sys = p_demux->p_sys;
1292     text_t      *txt = &p_sys->txt;
1293     char *psz_text;
1294     int i;
1295
1296     for( ;; )
1297     {
1298         const char *s = TextGetLine( txt );
1299         int i_start;
1300         int i_stop;
1301
1302         if( !s )
1303             return VLC_EGENERIC;
1304
1305         psz_text = malloc( strlen(s) + 1 );
1306         if( !psz_text )
1307             return VLC_ENOMEM;
1308
1309         i_start = 0;
1310         i_stop  = 0;
1311         if( sscanf( s, "[%d][] %[^\r\n]", &i_start, psz_text ) == 2 ||
1312             sscanf( s, "[%d][%d] %[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
1313         {
1314             p_subtitle->i_start = (int64_t)i_start * 100000;
1315             p_subtitle->i_stop  = (int64_t)i_stop  * 100000;
1316             break;
1317         }
1318         free( psz_text );
1319     }
1320
1321     for( i = 0; psz_text[i] != '\0'; )
1322     {
1323         /* replace | by \n */
1324         if( psz_text[i] == '|' )
1325             psz_text[i] = '\n';
1326
1327         /* Remove italic */
1328         if( psz_text[i] == '/' && ( i == 0 || psz_text[i-1] == '\n' ) )
1329             memmove( &psz_text[i], &psz_text[i+1], strlen(&psz_text[i+1])+1 );
1330         else
1331             i++;
1332     }
1333     p_subtitle->psz_text = psz_text;
1334     return VLC_SUCCESS;
1335 }
1336
1337 static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1338 {
1339     VLC_UNUSED( i_idx );
1340
1341     demux_sys_t *p_sys = p_demux->p_sys;
1342     text_t      *txt = &p_sys->txt;
1343     char *psz_text = strdup( "" );
1344     int i_old = 0;
1345     int i_firstline = 1;
1346
1347     for( ;; )
1348     {
1349         int t; /* Time */
1350
1351         const char *s = TextGetLine( txt );
1352
1353         if( !s )
1354             return VLC_EGENERIC;
1355
1356         /* Data Lines */
1357         if( sscanf (s, "-->> %d", &t) == 1)
1358         {
1359             p_subtitle->i_start = (int64_t)t; /* * FPS*/
1360             p_subtitle->i_stop  = 0;
1361
1362             /* Starting of a subtitle */
1363             if( i_firstline )
1364             {
1365                 i_firstline = 0;
1366             }
1367             /* We have been too far: end of the subtitle, begin of next */
1368             else
1369             {
1370                 TextPreviousLine( txt );
1371                 break;
1372             }
1373         }
1374         /* Text Lines */
1375         else
1376         {
1377             i_old = strlen( psz_text ) + 1;
1378             psz_text = realloc( psz_text, i_old + strlen( s ) + 1 );
1379             if( !psz_text )
1380                  return VLC_ENOMEM;
1381             strcat( psz_text, s );
1382             strcat( psz_text, "\n" );
1383             if( txt->i_line == txt->i_line_count )
1384                 break;
1385         }
1386     }
1387     p_subtitle->psz_text = psz_text;
1388     return VLC_SUCCESS;
1389 }
1390
1391 static int ParsePJS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1392 {
1393     VLC_UNUSED( i_idx );
1394
1395     demux_sys_t *p_sys = p_demux->p_sys;
1396     text_t      *txt = &p_sys->txt;
1397     char *psz_text;
1398     int i;
1399
1400     for( ;; )
1401     {
1402         const char *s = TextGetLine( txt );
1403         int t1, t2;
1404
1405         if( !s )
1406             return VLC_EGENERIC;
1407
1408         psz_text = malloc( strlen(s) + 1 );
1409         if( !psz_text )
1410             return VLC_ENOMEM;
1411
1412         /* Data Lines */
1413         if( sscanf (s, "%d,%d,\"%[^\n\r]", &t1, &t2, psz_text ) == 3 )
1414         {
1415             /* 1/10th of second ? Frame based ? FIXME */
1416             p_subtitle->i_start = 10 * t1;
1417             p_subtitle->i_stop = 10 * t2;
1418             /* Remove latest " */
1419             psz_text[ strlen(psz_text) - 1 ] = '\0';
1420
1421             break;
1422         }
1423         free( psz_text );
1424     }
1425
1426     /* replace | by \n */
1427     for( i = 0; psz_text[i] != '\0'; i++ )
1428     {
1429         if( psz_text[i] == '|' )
1430             psz_text[i] = '\n';
1431     }
1432
1433     p_subtitle->psz_text = psz_text;
1434     msg_Dbg( p_demux, "%s", psz_text );
1435     return VLC_SUCCESS;
1436 }
1437
1438 static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1439 {
1440     VLC_UNUSED( i_idx );
1441
1442     demux_sys_t *p_sys = p_demux->p_sys;
1443     text_t      *txt = &p_sys->txt;
1444     char *psz_text = strdup( "" );
1445
1446     if( !p_sys->mpsub.b_inited )
1447     {
1448         p_sys->mpsub.f_total = 0.0;
1449         p_sys->mpsub.f_factor = 0.0;
1450
1451         p_sys->mpsub.b_inited = true;
1452     }
1453
1454     for( ;; )
1455     {
1456         float f1, f2;
1457         char p_dummy;
1458         char *psz_temp;
1459
1460         const char *s = TextGetLine( txt );
1461         if( !s )
1462             return VLC_EGENERIC;
1463
1464         if( strstr( s, "FORMAT" ) )
1465         {
1466             if( sscanf (s, "FORMAT=TIM%c", &p_dummy ) == 1 && p_dummy == 'E')
1467             {
1468                 p_sys->mpsub.f_factor = 100.0;
1469                 break;
1470             }
1471
1472             psz_temp = malloc( strlen(s) );
1473             if( !psz_temp )
1474                 return VLC_ENOMEM;
1475
1476             if( sscanf( s, "FORMAT=%[^\r\n]", psz_temp ) )
1477             {
1478                 float f_fps;
1479                 f_fps = us_strtod( psz_temp, NULL );
1480                 if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
1481                     var_SetFloat( p_demux, "sub-fps", f_fps );
1482
1483                 p_sys->mpsub.f_factor = 1.0;
1484                 free( psz_temp );
1485                 break;
1486             }
1487             free( psz_temp );
1488         }
1489         /* Data Lines */
1490         f1 = us_strtod( s, &psz_temp );
1491         if( *psz_temp )
1492         {
1493             f2 = us_strtod( psz_temp, NULL );
1494             p_sys->mpsub.f_total += f1 * p_sys->mpsub.f_factor;
1495             p_subtitle->i_start = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1496             p_sys->mpsub.f_total += f2 * p_sys->mpsub.f_factor;
1497             p_subtitle->i_stop = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1498             break;
1499         }
1500     }
1501
1502     for( ;; )
1503     {
1504         const char *s = TextGetLine( txt );
1505
1506         if( !s )
1507             return VLC_EGENERIC;
1508
1509         int i_len = strlen( s );
1510         if( i_len == 0 )
1511             break;
1512
1513         int i_old = strlen( psz_text );
1514
1515         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1516         if( !psz_text )
1517              return VLC_ENOMEM;
1518
1519         strcat( psz_text, s );
1520         strcat( psz_text, "\n" );
1521     }
1522
1523     p_subtitle->psz_text = psz_text;
1524     return VLC_SUCCESS;
1525 }
1526
1527 static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1528 {
1529     VLC_UNUSED( i_idx );
1530
1531     demux_sys_t  *p_sys = p_demux->p_sys;
1532     text_t       *txt = &p_sys->txt;
1533     char         *psz_text, *psz_orig;
1534     char         *psz_text2, *psz_orig2;
1535     int h1, h2, m1, m2, s1, s2, f1, f2;
1536
1537     if( !p_sys->jss.b_inited )
1538     {
1539         p_sys->jss.i_comment = 0;
1540         p_sys->jss.i_time_resolution = 30;
1541         p_sys->jss.i_time_shift = 0;
1542
1543         p_sys->jss.b_inited = true;
1544     }
1545
1546     /* Parse the main lines */
1547     for( ;; )
1548     {
1549         const char *s = TextGetLine( txt );
1550         if( !s )
1551             return VLC_EGENERIC;
1552
1553         psz_orig = malloc( strlen( s ) + 1 );
1554         if( !psz_orig )
1555             return VLC_ENOMEM;
1556         psz_text = psz_orig;
1557
1558         /* Complete time lines */
1559         if( sscanf( s, "%d:%d:%d.%d %d:%d:%d.%d %[^\n\r]",
1560                     &h1, &m1, &s1, &f1, &h2, &m2, &s2, &f2, psz_text ) == 9 )
1561         {
1562             p_subtitle->i_start = ( (int64_t)( h1 *3600 + m1 * 60 + s1 ) +
1563                 (int64_t)( ( f1 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
1564                 * 1000000;
1565             p_subtitle->i_stop = ( (int64_t)( h2 *3600 + m2 * 60 + s2 ) +
1566                 (int64_t)( ( f2 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
1567                 * 1000000;
1568             break;
1569         }
1570         /* Short time lines */
1571         else if( sscanf( s, "@%d @%d %[^\n\r]", &f1, &f2, psz_text ) == 3 )
1572         {
1573             p_subtitle->i_start = (int64_t)(
1574                     ( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1575             p_subtitle->i_stop = (int64_t)(
1576                     ( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1577             break;
1578         }
1579         /* General Directive lines */
1580         /* Only TIME and SHIFT are supported so far */
1581         else if( s[0] == '#' )
1582         {
1583             int h = 0, m =0, sec = 1, f = 1;
1584             unsigned shift = 1;
1585             int inv = 1;
1586
1587             strcpy( psz_text, s );
1588
1589             switch( toupper( psz_text[1] ) )
1590             {
1591             case 'S':
1592                  shift = isalpha( psz_text[2] ) ? 6 : 2 ;
1593
1594                  if( sscanf( &psz_text[shift], "%d", &h ) )
1595                  {
1596                      /* Negative shifting */
1597                      if( h < 0 )
1598                      {
1599                          h *= -1;
1600                          inv = -1;
1601                      }
1602
1603                      if( sscanf( &psz_text[shift], "%*d:%d", &m ) )
1604                      {
1605                          if( sscanf( &psz_text[shift], "%*d:%*d:%d", &sec ) )
1606                          {
1607                              sscanf( &psz_text[shift], "%*d:%*d:%*d.%d", &f );
1608                          }
1609                          else
1610                          {
1611                              h = 0;
1612                              sscanf( &psz_text[shift], "%d:%d.%d",
1613                                      &m, &sec, &f );
1614                              m *= inv;
1615                          }
1616                      }
1617                      else
1618                      {
1619                          h = m = 0;
1620                          sscanf( &psz_text[shift], "%d.%d", &sec, &f);
1621                          sec *= inv;
1622                      }
1623                      p_sys->jss.i_time_shift = ( ( h * 3600 + m * 60 + sec )
1624                          * p_sys->jss.i_time_resolution + f ) * inv;
1625                  }
1626                  break;
1627
1628             case 'T':
1629                 shift = isalpha( psz_text[2] ) ? 8 : 2 ;
1630
1631                 sscanf( &psz_text[shift], "%d", &p_sys->jss.i_time_resolution );
1632                 break;
1633             }
1634             free( psz_orig );
1635             continue;
1636         }
1637         else
1638             /* Unkown type line, probably a comment */
1639         {
1640             free( psz_orig );
1641             continue;
1642         }
1643     }
1644         
1645         while( psz_text[ strlen( psz_text ) - 1 ] == '\\' )
1646         {
1647         const char *s2 = TextGetLine( txt );
1648
1649         if( !s2 )
1650             return VLC_EGENERIC;
1651
1652         int i_len = strlen( s2 );
1653         if( i_len == 0 )
1654             break;
1655
1656         int i_old = strlen( psz_text );
1657
1658         psz_text = realloc( psz_text, i_old + i_len + 1 );
1659         if( !psz_text )
1660              return VLC_ENOMEM;
1661
1662                 psz_orig = psz_text;
1663         strcat( psz_text, s2 );
1664         }
1665
1666     /* Skip the blanks */
1667     while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1668
1669     /* Parse the directives */
1670     if( isalpha( *psz_text ) || *psz_text == '[' )
1671     {
1672         while( *psz_text != ' ' )
1673         { psz_text++ ;};
1674
1675         /* Directives are NOT parsed yet */
1676         /* This has probably a better place in a decoder ? */
1677         /* directive = malloc( strlen( psz_text ) + 1 );
1678            if( sscanf( psz_text, "%s %[^\n\r]", directive, psz_text2 ) == 2 )*/
1679     }
1680
1681     /* Skip the blanks after directives */
1682     while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1683
1684     /* Clean all the lines from inline comments and other stuffs */
1685     psz_orig2 = calloc( strlen( psz_text) + 1, 1 );
1686     psz_text2 = psz_orig2;
1687
1688     for( ; *psz_text != '\0' && *psz_text != '\n' && *psz_text != '\r'; )
1689     {
1690         switch( *psz_text )
1691         {
1692         case '{':
1693             p_sys->jss.i_comment++;
1694             break;
1695         case '}':
1696             if( p_sys->jss.i_comment )
1697             {
1698                 p_sys->jss.i_comment = 0;
1699                 if( (*(psz_text + 1 ) ) == ' ' ) psz_text++;
1700             }
1701             break;
1702         case '~':
1703             if( !p_sys->jss.i_comment )
1704             {
1705                 *psz_text2 = ' ';
1706                 psz_text2++;
1707             }
1708             break;
1709         case ' ':
1710         case '\t':
1711             if( (*(psz_text + 1 ) ) == ' ' || (*(psz_text + 1 ) ) == '\t' )
1712                 break;
1713             if( !p_sys->jss.i_comment )
1714             {
1715                 *psz_text2 = ' ';
1716                 psz_text2++;
1717             }
1718             break;
1719         case '\\':
1720             if( (*(psz_text + 1 ) ) == 'n' )
1721             {
1722                 *psz_text2 = '\n';
1723                 psz_text++;
1724                 psz_text2++;
1725                 break;
1726             }
1727             if( ( toupper(*(psz_text + 1 ) ) == 'C' ) ||
1728                     ( toupper(*(psz_text + 1 ) ) == 'F' ) )
1729             {
1730                 psz_text++; psz_text++;
1731                 break;
1732             }
1733             if( (*(psz_text + 1 ) ) == 'B' || (*(psz_text + 1 ) ) == 'b' ||
1734                 (*(psz_text + 1 ) ) == 'I' || (*(psz_text + 1 ) ) == 'i' ||
1735                 (*(psz_text + 1 ) ) == 'U' || (*(psz_text + 1 ) ) == 'u' ||
1736                 (*(psz_text + 1 ) ) == 'D' || (*(psz_text + 1 ) ) == 'N' )
1737             {
1738                 psz_text++;
1739                 break;
1740             }
1741             if( (*(psz_text + 1 ) ) == '~' || (*(psz_text + 1 ) ) == '{' ||
1742                 (*(psz_text + 1 ) ) == '\\' )
1743                 psz_text++;
1744             else if( *(psz_text + 1 ) == '\r' ||  *(psz_text + 1 ) == '\n' ||
1745                      *(psz_text + 1 ) == '\0' )
1746             {
1747                                 psz_text++;
1748             }
1749             break;
1750         default:
1751             if( !p_sys->jss.i_comment )
1752             {
1753                 *psz_text2 = *psz_text;
1754                 psz_text2++;
1755             }
1756         }
1757         psz_text++;
1758     }
1759
1760     p_subtitle->psz_text = psz_orig2;
1761     msg_Dbg( p_demux, "%s", p_subtitle->psz_text );
1762     free( psz_orig );
1763     return VLC_SUCCESS;
1764 }
1765
1766 static int ParsePSB( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1767 {
1768     VLC_UNUSED( i_idx );
1769
1770     demux_sys_t *p_sys = p_demux->p_sys;
1771     text_t      *txt = &p_sys->txt;
1772     char *psz_text;
1773     int i;
1774
1775     for( ;; )
1776     {
1777         int h1, m1, s1;
1778         int h2, m2, s2;
1779         const char *s = TextGetLine( txt );
1780
1781         if( !s )
1782             return VLC_EGENERIC;
1783
1784         psz_text = malloc( strlen( s ) + 1 );
1785         if( !psz_text )
1786             return VLC_ENOMEM;
1787
1788         if( sscanf( s, "{%d:%d:%d}{%d:%d:%d}%[^\r\n]",
1789                     &h1, &m1, &s1, &h2, &m2, &s2, psz_text ) == 7 )
1790         {
1791             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1792                                     (int64_t)m1 * 60*1000 +
1793                                     (int64_t)s1 * 1000 ) * 1000;
1794             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1795                                     (int64_t)m2 * 60*1000 +
1796                                     (int64_t)s2 * 1000 ) * 1000;
1797             break;
1798         }
1799         free( psz_text );
1800     }
1801
1802     /* replace | by \n */
1803     for( i = 0; psz_text[i] != '\0'; i++ )
1804     {
1805         if( psz_text[i] == '|' )
1806             psz_text[i] = '\n';
1807     }
1808     p_subtitle->psz_text = psz_text;
1809     return VLC_SUCCESS;
1810 }
1811
1812 static int64_t ParseRealTime( char *psz, int *h, int *m, int *s, int *f )
1813 {
1814     if( strlen( psz ) == 0 ) return 0;
1815     if( sscanf( psz, "%d:%d:%d.%d", h, m, s, f ) == 4 ||
1816             sscanf( psz, "%d:%d.%d", m, s, f ) == 3 ||
1817             sscanf( psz, "%d.%d", s, f ) == 2 ||
1818             sscanf( psz, "%d:%d", m, s ) == 2 ||
1819             sscanf( psz, "%d", s ) == 1 )
1820     {
1821         return (int64_t)((( *h * 60 + *m ) * 60 ) + *s ) * 1000 * 1000
1822                + (int64_t)*f * 10 * 1000;
1823     }
1824     else return VLC_EGENERIC;
1825 }
1826
1827 static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1828 {
1829     VLC_UNUSED( i_idx );
1830     demux_sys_t *p_sys = p_demux->p_sys;
1831     text_t      *txt = &p_sys->txt;
1832     char *psz_text;
1833     char psz_end[12]= "", psz_begin[12] = "";
1834
1835     for( ;; )
1836     {
1837         int h1 = 0, m1 = 0, s1 = 0, f1 = 0;
1838         int h2 = 0, m2 = 0, s2 = 0, f2 = 0;
1839         const char *s = TextGetLine( txt );
1840
1841         if( !s )
1842             return VLC_EGENERIC;
1843
1844         psz_text = malloc( strlen( s ) + 1 );
1845         if( !psz_text )
1846             return VLC_ENOMEM;
1847
1848         /* Find the good begining. This removes extra spaces at the beginning
1849            of the line.*/
1850         char *psz_temp = strcasestr( s, "<time");
1851         if( psz_temp != NULL )
1852         {
1853             /* Line has begin and end */
1854             if( ( sscanf( psz_temp,
1855                   "<%*[t|T]ime %*[b|B]egin=\"%[^\"]\" %*[e|E]nd=\"%[^\"]%*[^>]%[^\n\r]",
1856                             psz_begin, psz_end, psz_text) != 3 ) &&
1857                     /* Line has begin and no end */
1858                     ( sscanf( psz_temp,
1859                               "<%*[t|T]ime %*[b|B]egin=\"%[^\"]\"%*[^>]%[^\n\r]",
1860                               psz_begin, psz_text ) != 2) )
1861                 /* Line is not recognized */
1862             {
1863                 free( psz_text );
1864                 continue;
1865             }
1866
1867             /* Get the times */
1868             int64_t i_time = ParseRealTime( psz_begin, &h1, &m1, &s1, &f1 );
1869             if( i_time >= 0)
1870             {
1871                 p_subtitle->i_start = i_time;
1872             }
1873
1874             i_time = ParseRealTime( psz_end, &h2, &m2, &s2, &f2 );
1875             if( i_time >= 0 )
1876             {
1877                 p_subtitle->i_stop = i_time;
1878             }
1879             break;
1880         }
1881         /* Line is not recognized */
1882         else continue;
1883         free( psz_text );
1884     }
1885
1886     /* Get the following Lines */
1887     for( ;; )
1888     {
1889         const char *s = TextGetLine( txt );
1890
1891         if( !s )
1892             return VLC_EGENERIC;
1893
1894         int i_len = strlen( s );
1895         if( i_len == 0 ) break;
1896
1897         if( strcasestr( s, "<time" ) ||
1898             strcasestr( s, "<clear/") )
1899         {
1900             TextPreviousLine( txt );
1901             break;
1902         }
1903
1904         int i_old = strlen( psz_text );
1905
1906         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1907         if( !psz_text )
1908             return VLC_ENOMEM;
1909
1910         strcat( psz_text, s );
1911         strcat( psz_text, "\n" );
1912     }
1913
1914     /* Remove the starting ">" that remained after the sscanf */
1915     memmove( &psz_text[0], &psz_text[1], strlen( psz_text ) );
1916
1917     p_subtitle->psz_text = psz_text;
1918
1919     return VLC_SUCCESS;
1920 }
1921
1922 static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1923 {
1924     VLC_UNUSED( i_idx );
1925
1926     demux_sys_t *p_sys = p_demux->p_sys;
1927     text_t      *txt = &p_sys->txt;
1928     char *psz_text;
1929
1930     for( ;; )
1931     {
1932         int h1, m1, s1;
1933         int h2, m2, s2;
1934         char *s = TextGetLine( txt );
1935
1936         if( !s )
1937             return VLC_EGENERIC;
1938
1939         psz_text = malloc( strlen( s ) + 1 );
1940         if( !psz_text )
1941             return VLC_ENOMEM;
1942
1943         if( sscanf( s, "[%d:%d:%d]%[^\r\n]",
1944                     &h1, &m1, &s1, psz_text ) == 4 )
1945         {
1946             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1947                                     (int64_t)m1 * 60*1000 +
1948                                     (int64_t)s1 * 1000 ) * 1000;
1949
1950             char *s = TextGetLine( txt );
1951             if( !s )
1952                 return VLC_EGENERIC;
1953
1954             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
1955                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1956                                         (int64_t)m2 * 60*1000 +
1957                                         (int64_t)s2 * 1000 ) * 1000;
1958             break;
1959         }
1960         free( psz_text );
1961     }
1962
1963     /* replace [br] by \n */
1964     char *p;
1965     while( ( p = strstr( psz_text, "[br]" ) ) )
1966     {
1967         *p++ = '\n';
1968         memmove( p, &p[3], strlen(&p[3])+1 );
1969     }
1970
1971     p_subtitle->psz_text = psz_text;
1972     return VLC_SUCCESS;
1973 }
1974
1975 static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1976 {
1977     VLC_UNUSED( i_idx );
1978
1979     demux_sys_t *p_sys = p_demux->p_sys;
1980     text_t      *txt = &p_sys->txt;
1981     char *psz_text;
1982
1983     for( ;; )
1984     {
1985         int h1, m1, s1;
1986         int h2, m2, s2;
1987         char *s = TextGetLine( txt );
1988
1989         if( !s )
1990             return VLC_EGENERIC;
1991
1992         if( sscanf( s, "[%d:%d:%d]", &h1, &m1, &s1 ) == 3 )
1993         {
1994             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1995                                     (int64_t)m1 * 60*1000 +
1996                                     (int64_t)s1 * 1000 ) * 1000;
1997
1998             char *s = TextGetLine( txt );
1999             if( !s )
2000                 return VLC_EGENERIC;
2001
2002             psz_text = strdup( s );
2003             if( !psz_text )
2004                 return VLC_ENOMEM;
2005
2006             s = TextGetLine( txt );
2007             if( !s )
2008                 return VLC_EGENERIC;
2009
2010             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
2011                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
2012                                         (int64_t)m2 * 60*1000 +
2013                                         (int64_t)s2 * 1000 ) * 1000;
2014             break;
2015         }
2016     }
2017
2018     p_subtitle->psz_text = psz_text;
2019
2020     return VLC_SUCCESS;
2021 }
2022