]> git.sesse.net Git - vlc/blob - modules/demux/subtitle.c
Fix compilation
[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_Warn( 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             if( p_subtitle->i_start < p_subtitle->i_stop )
896                 break;
897         }
898     }
899
900     /* Now read text until an empty line */
901     psz_text = strdup("");
902     if( !psz_text )
903         return VLC_ENOMEM;
904
905     for( ;; )
906     {
907         const char *s = TextGetLine( txt );
908         int i_len;
909         int i_old;
910
911         i_len = s ? strlen( s ) : 0;
912         if( i_len <= 0 )
913         {
914             p_subtitle->psz_text = psz_text;
915             return VLC_SUCCESS;
916         }
917
918         i_old = strlen( psz_text );
919         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
920         if( !psz_text )
921         {
922             return VLC_ENOMEM;
923         }
924         strcat( psz_text, s );
925         strcat( psz_text, "\n" );
926
927         /* replace [br] by \n */
928         if( b_replace_br )
929         {
930             char *p;
931
932             while( ( p = strstr( psz_text, "[br]" ) ) )
933             {
934                 *p++ = '\n';
935                 memmove( p, &p[3], strlen(&p[3])+1 );
936             }
937         }
938     }
939 }
940 /* ParseSubRip
941  */
942 static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,
943                          int i_idx )
944 {
945     VLC_UNUSED( i_idx );
946     return ParseSubRipSubViewer( p_demux, p_subtitle,
947                                  "%d:%d:%d,%d --> %d:%d:%d,%d",
948                                  false );
949 }
950 /* ParseSubViewer
951  */
952 static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
953                             int i_idx )
954 {
955     VLC_UNUSED( i_idx );
956
957     return ParseSubRipSubViewer( p_demux, p_subtitle,
958                                  "%d:%d:%d.%d,%d:%d:%d.%d",
959                                  true );
960 }
961
962 /* ParseSSA
963  */
964 static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle,
965                       int i_idx )
966 {
967     demux_sys_t *p_sys = p_demux->p_sys;
968     text_t      *txt = &p_sys->txt;
969
970     for( ;; )
971     {
972         const char *s = TextGetLine( txt );
973         int h1, m1, s1, c1, h2, m2, s2, c2;
974         char *psz_text;
975         char temp[16];
976
977         if( !s )
978             return VLC_EGENERIC;
979
980         /* We expect (SSA2-4):
981          * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
982          * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
983          *
984          * 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.
985          */
986
987         /* For ASS:
988          * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
989          * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
990          */
991
992         /* The output text is - at least, not removing numbers - 18 chars shorter than the input text. */
993         psz_text = malloc( strlen(s) );
994         if( !psz_text )
995             return VLC_ENOMEM;
996
997         if( sscanf( s,
998                     "Dialogue: %15[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
999                     temp,
1000                     &h1, &m1, &s1, &c1,
1001                     &h2, &m2, &s2, &c2,
1002                     psz_text ) == 10 )
1003         {
1004             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
1005             /* (Layer comes from ASS specs ... it's empty for SSA.) */
1006             if( p_sys->i_type == SUB_TYPE_SSA1 )
1007             {
1008                 /* SSA1 has only 8 commas before the text starts, not 9 */
1009                 memmove( &psz_text[1], psz_text, strlen(psz_text)+1 );
1010                 psz_text[0] = ',';
1011             }
1012             else
1013             {
1014                 int i_layer = ( p_sys->i_type == SUB_TYPE_ASS ) ? atoi( temp ) : 0;
1015
1016                 /* ReadOrder, Layer, %s(rest of fields) */
1017                 snprintf( temp, sizeof(temp), "%d,%d,", i_idx, i_layer );
1018                 memmove( psz_text + strlen(temp), psz_text, strlen(psz_text)+1 );
1019                 memcpy( psz_text, temp, strlen(temp) );
1020             }
1021
1022             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1023                                     (int64_t)m1 * 60*1000 +
1024                                     (int64_t)s1 * 1000 +
1025                                     (int64_t)c1 * 10 ) * 1000;
1026             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1027                                     (int64_t)m2 * 60*1000 +
1028                                     (int64_t)s2 * 1000 +
1029                                     (int64_t)c2 * 10 ) * 1000;
1030             p_subtitle->psz_text = psz_text;
1031             return VLC_SUCCESS;
1032         }
1033         free( psz_text );
1034
1035         /* All the other stuff we add to the header field */
1036         if( !p_sys->psz_header )
1037             p_sys->psz_header = strdup( "" );
1038         if( !p_sys->psz_header )
1039             return VLC_ENOMEM;
1040
1041         p_sys->psz_header =
1042             realloc( p_sys->psz_header,
1043                      strlen( p_sys->psz_header ) + strlen( s ) + 2 );
1044         strcat( p_sys->psz_header,  s );
1045         strcat( p_sys->psz_header, "\n" );
1046     }
1047 }
1048
1049 /* ParseVplayer
1050  *  Format
1051  *      h:m:s:Line1|Line2|Line3....
1052  *  or
1053  *      h:m:s Line1|Line2|Line3....
1054  */
1055 static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle,
1056                           int i_idx )
1057 {
1058     VLC_UNUSED( i_idx );
1059
1060     demux_sys_t *p_sys = p_demux->p_sys;
1061     text_t      *txt = &p_sys->txt;
1062     char *psz_text;
1063     int i;
1064
1065     for( ;; )
1066     {
1067         const char *s = TextGetLine( txt );
1068         int h1, m1, s1;
1069
1070         if( !s )
1071             return VLC_EGENERIC;
1072
1073         psz_text = malloc( strlen( s ) + 1 );
1074         if( !psz_text )
1075             return VLC_ENOMEM;
1076
1077         if( sscanf( s, "%d:%d:%d%*c%[^\r\n]",
1078                     &h1, &m1, &s1, psz_text ) == 4 )
1079         {
1080             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1081                                     (int64_t)m1 * 60*1000 +
1082                                     (int64_t)s1 * 1000 ) * 1000;
1083             p_subtitle->i_stop  = 0;
1084             break;
1085         }
1086         free( psz_text );
1087     }
1088
1089     /* replace | by \n */
1090     for( i = 0; psz_text[i] != '\0'; i++ )
1091     {
1092         if( psz_text[i] == '|' )
1093             psz_text[i] = '\n';
1094     }
1095     p_subtitle->psz_text = psz_text;
1096     return VLC_SUCCESS;
1097 }
1098
1099 /* ParseSami
1100  */
1101 static char *ParseSamiSearch( text_t *txt,
1102                               char *psz_start, const char *psz_str )
1103 {
1104     if( psz_start && strcasestr( psz_start, psz_str ) )
1105     {
1106         char *s = strcasestr( psz_start, psz_str );
1107         return &s[strlen( psz_str )];
1108     }
1109
1110     for( ;; )
1111     {
1112         char *p = TextGetLine( txt );
1113         if( !p )
1114             return NULL;
1115
1116         if( strcasestr( p, psz_str ) )
1117         {
1118             char *s = strcasestr( p, psz_str );
1119             return &s[strlen( psz_str )];
1120         }
1121     }
1122 }
1123 static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1124 {
1125     VLC_UNUSED( i_idx );
1126     demux_sys_t *p_sys = p_demux->p_sys;
1127     text_t      *txt = &p_sys->txt;
1128
1129     char *s;
1130     int64_t i_start;
1131
1132     unsigned int i_text;
1133     char text[8192]; /* Arbitrary but should be long enough */
1134
1135     /* search "Start=" */
1136     if( !( s = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1137         return VLC_EGENERIC;
1138
1139     /* get start value */
1140     i_start = strtol( s, &s, 0 );
1141
1142     /* search <P */
1143     if( !( s = ParseSamiSearch( txt, s, "<P" ) ) )
1144         return VLC_EGENERIC;
1145
1146     /* search > */
1147     if( !( s = ParseSamiSearch( txt, s, ">" ) ) )
1148         return VLC_EGENERIC;
1149
1150     i_text = 0;
1151     text[0] = '\0';
1152     /* now get all txt until  a "Start=" line */
1153     for( ;; )
1154     {
1155         char c = '\0';
1156         /* Search non empty line */
1157         while( s && *s == '\0' )
1158             s = TextGetLine( txt );
1159         if( !s )
1160             break;
1161
1162         if( *s == '<' )
1163         {
1164             if( !strncasecmp( s, "<br", 3 ) )
1165             {
1166                 c = '\n';
1167             }
1168             else if( strcasestr( s, "Start=" ) )
1169             {
1170                 TextPreviousLine( txt );
1171                 break;
1172             }
1173             s = ParseSamiSearch( txt, s, ">" );
1174         }
1175         else if( !strncmp( s, "&nbsp;", 6 ) )
1176         {
1177             c = ' ';
1178             s += 6;
1179         }
1180         else if( *s == '\t' )
1181         {
1182             c = ' ';
1183             s++;
1184         }
1185         else
1186         {
1187             c = *s;
1188             s++;
1189         }
1190         if( c != '\0' && i_text+1 < sizeof(text) )
1191         {
1192             text[i_text++] = c;
1193             text[i_text] = '\0';
1194         }
1195     }
1196
1197     p_subtitle->i_start = i_start * 1000;
1198     p_subtitle->i_stop  = 0;
1199     p_subtitle->psz_text = strdup( text );
1200
1201     return VLC_SUCCESS;
1202 }
1203
1204 /* ParseDVDSubtitle
1205  *  Format
1206  *      {T h1:m1:s1:c1
1207  *      Line1
1208  *      Line2
1209  *      ...
1210  *      }
1211  * TODO it can have a header
1212  *      { HEAD
1213  *          ...
1214  *          CODEPAGE=...
1215  *          FORMAT=...
1216  *          LANG=English
1217  *      }
1218  *      LANG support would be cool
1219  *      CODEPAGE is probably mandatory FIXME
1220  */
1221 static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle,
1222                              int i_idx )
1223 {
1224     VLC_UNUSED( i_idx );
1225
1226     demux_sys_t *p_sys = p_demux->p_sys;
1227     text_t      *txt = &p_sys->txt;
1228     char *psz_text;
1229
1230     for( ;; )
1231     {
1232         const char *s = TextGetLine( txt );
1233         int h1, m1, s1, c1;
1234
1235         if( !s )
1236             return VLC_EGENERIC;
1237
1238         if( sscanf( s,
1239                     "{T %d:%d:%d:%d",
1240                     &h1, &m1, &s1, &c1 ) == 4 )
1241         {
1242             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1243                                     (int64_t)m1 * 60*1000 +
1244                                     (int64_t)s1 * 1000 +
1245                                     (int64_t)c1 * 10) * 1000;
1246             p_subtitle->i_stop = 0;
1247             break;
1248         }
1249     }
1250
1251     /* Now read text until a line containing "}" */
1252     psz_text = strdup("");
1253     if( !psz_text )
1254         return VLC_ENOMEM;
1255     for( ;; )
1256     {
1257         const char *s = TextGetLine( txt );
1258         int i_len;
1259         int i_old;
1260
1261         if( !s )
1262         {
1263             free( psz_text );
1264             return VLC_EGENERIC;
1265         }
1266
1267         i_len = strlen( s );
1268         if( i_len == 1 && s[0] == '}')
1269         {
1270             p_subtitle->psz_text = psz_text;
1271             return VLC_SUCCESS;
1272         }
1273
1274         i_old = strlen( psz_text );
1275         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1276         if( !psz_text )
1277             return VLC_ENOMEM;
1278         strcat( psz_text, s );
1279         strcat( psz_text, "\n" );
1280     }
1281 }
1282
1283 /* ParseMPL2
1284  *  Format
1285  *     [n1][n2]Line1|Line2|Line3...
1286  *  where n1 and n2 are the video frame number (n2 can be empty)
1287  */
1288 static int ParseMPL2( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1289 {
1290     VLC_UNUSED( i_idx );
1291
1292     demux_sys_t *p_sys = p_demux->p_sys;
1293     text_t      *txt = &p_sys->txt;
1294     char *psz_text;
1295     int i;
1296
1297     for( ;; )
1298     {
1299         const char *s = TextGetLine( txt );
1300         int i_start;
1301         int i_stop;
1302
1303         if( !s )
1304             return VLC_EGENERIC;
1305
1306         psz_text = malloc( strlen(s) + 1 );
1307         if( !psz_text )
1308             return VLC_ENOMEM;
1309
1310         i_start = 0;
1311         i_stop  = 0;
1312         if( sscanf( s, "[%d][] %[^\r\n]", &i_start, psz_text ) == 2 ||
1313             sscanf( s, "[%d][%d] %[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
1314         {
1315             p_subtitle->i_start = (int64_t)i_start * 100000;
1316             p_subtitle->i_stop  = (int64_t)i_stop  * 100000;
1317             break;
1318         }
1319         free( psz_text );
1320     }
1321
1322     for( i = 0; psz_text[i] != '\0'; )
1323     {
1324         /* replace | by \n */
1325         if( psz_text[i] == '|' )
1326             psz_text[i] = '\n';
1327
1328         /* Remove italic */
1329         if( psz_text[i] == '/' && ( i == 0 || psz_text[i-1] == '\n' ) )
1330             memmove( &psz_text[i], &psz_text[i+1], strlen(&psz_text[i+1])+1 );
1331         else
1332             i++;
1333     }
1334     p_subtitle->psz_text = psz_text;
1335     return VLC_SUCCESS;
1336 }
1337
1338 static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1339 {
1340     VLC_UNUSED( i_idx );
1341
1342     demux_sys_t *p_sys = p_demux->p_sys;
1343     text_t      *txt = &p_sys->txt;
1344     char *psz_text = strdup( "" );
1345     int i_old = 0;
1346     int i_firstline = 1;
1347
1348     for( ;; )
1349     {
1350         int t; /* Time */
1351
1352         const char *s = TextGetLine( txt );
1353
1354         if( !s )
1355         {
1356             free( psz_text );
1357             return VLC_EGENERIC;
1358         }
1359
1360         /* Data Lines */
1361         if( sscanf (s, "-->> %d", &t) == 1)
1362         {
1363             p_subtitle->i_start = (int64_t)t; /* * FPS*/
1364             p_subtitle->i_stop  = 0;
1365
1366             /* Starting of a subtitle */
1367             if( i_firstline )
1368             {
1369                 i_firstline = 0;
1370             }
1371             /* We have been too far: end of the subtitle, begin of next */
1372             else
1373             {
1374                 TextPreviousLine( txt );
1375                 break;
1376             }
1377         }
1378         /* Text Lines */
1379         else
1380         {
1381             i_old = strlen( psz_text ) + 1;
1382             psz_text = realloc( psz_text, i_old + strlen( s ) + 1 );
1383             if( !psz_text )
1384                  return VLC_ENOMEM;
1385             strcat( psz_text, s );
1386             strcat( psz_text, "\n" );
1387             if( txt->i_line == txt->i_line_count )
1388                 break;
1389         }
1390     }
1391     p_subtitle->psz_text = psz_text;
1392     return VLC_SUCCESS;
1393 }
1394
1395 static int ParsePJS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1396 {
1397     VLC_UNUSED( i_idx );
1398
1399     demux_sys_t *p_sys = p_demux->p_sys;
1400     text_t      *txt = &p_sys->txt;
1401     char *psz_text;
1402     int i;
1403
1404     for( ;; )
1405     {
1406         const char *s = TextGetLine( txt );
1407         int t1, t2;
1408
1409         if( !s )
1410             return VLC_EGENERIC;
1411
1412         psz_text = malloc( strlen(s) + 1 );
1413         if( !psz_text )
1414             return VLC_ENOMEM;
1415
1416         /* Data Lines */
1417         if( sscanf (s, "%d,%d,\"%[^\n\r]", &t1, &t2, psz_text ) == 3 )
1418         {
1419             /* 1/10th of second ? Frame based ? FIXME */
1420             p_subtitle->i_start = 10 * t1;
1421             p_subtitle->i_stop = 10 * t2;
1422             /* Remove latest " */
1423             psz_text[ strlen(psz_text) - 1 ] = '\0';
1424
1425             break;
1426         }
1427         free( psz_text );
1428     }
1429
1430     /* replace | by \n */
1431     for( i = 0; psz_text[i] != '\0'; i++ )
1432     {
1433         if( psz_text[i] == '|' )
1434             psz_text[i] = '\n';
1435     }
1436
1437     p_subtitle->psz_text = psz_text;
1438     msg_Dbg( p_demux, "%s", psz_text );
1439     return VLC_SUCCESS;
1440 }
1441
1442 static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1443 {
1444     VLC_UNUSED( i_idx );
1445
1446     demux_sys_t *p_sys = p_demux->p_sys;
1447     text_t      *txt = &p_sys->txt;
1448     char *psz_text = strdup( "" );
1449
1450     if( !p_sys->mpsub.b_inited )
1451     {
1452         p_sys->mpsub.f_total = 0.0;
1453         p_sys->mpsub.f_factor = 0.0;
1454
1455         p_sys->mpsub.b_inited = true;
1456     }
1457
1458     for( ;; )
1459     {
1460         float f1, f2;
1461         char p_dummy;
1462         char *psz_temp;
1463
1464         const char *s = TextGetLine( txt );
1465         if( !s )
1466         {
1467             free( psz_text );
1468             return VLC_EGENERIC;
1469         }
1470
1471         if( strstr( s, "FORMAT" ) )
1472         {
1473             if( sscanf (s, "FORMAT=TIM%c", &p_dummy ) == 1 && p_dummy == 'E')
1474             {
1475                 p_sys->mpsub.f_factor = 100.0;
1476                 break;
1477             }
1478
1479             psz_temp = malloc( strlen(s) );
1480             if( !psz_temp )
1481             {
1482                 free( psz_text );
1483                 return VLC_ENOMEM;
1484             }
1485
1486             if( sscanf( s, "FORMAT=%[^\r\n]", psz_temp ) )
1487             {
1488                 float f_fps;
1489                 f_fps = us_strtod( psz_temp, NULL );
1490                 if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
1491                     var_SetFloat( p_demux, "sub-fps", f_fps );
1492
1493                 p_sys->mpsub.f_factor = 1.0;
1494                 free( psz_temp );
1495                 break;
1496             }
1497             free( psz_temp );
1498         }
1499         /* Data Lines */
1500         f1 = us_strtod( s, &psz_temp );
1501         if( *psz_temp )
1502         {
1503             f2 = us_strtod( psz_temp, NULL );
1504             p_sys->mpsub.f_total += f1 * p_sys->mpsub.f_factor;
1505             p_subtitle->i_start = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1506             p_sys->mpsub.f_total += f2 * p_sys->mpsub.f_factor;
1507             p_subtitle->i_stop = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1508             break;
1509         }
1510     }
1511
1512     for( ;; )
1513     {
1514         const char *s = TextGetLine( txt );
1515
1516         if( !s )
1517         {
1518             free( psz_text );
1519             return VLC_EGENERIC;
1520         }
1521
1522         int i_len = strlen( s );
1523         if( i_len == 0 )
1524             break;
1525
1526         int i_old = strlen( psz_text );
1527
1528         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1529         if( !psz_text )
1530              return VLC_ENOMEM;
1531
1532         strcat( psz_text, s );
1533         strcat( psz_text, "\n" );
1534     }
1535
1536     p_subtitle->psz_text = psz_text;
1537     return VLC_SUCCESS;
1538 }
1539
1540 static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1541 {
1542     VLC_UNUSED( i_idx );
1543
1544     demux_sys_t  *p_sys = p_demux->p_sys;
1545     text_t       *txt = &p_sys->txt;
1546     char         *psz_text, *psz_orig;
1547     char         *psz_text2, *psz_orig2;
1548     int h1, h2, m1, m2, s1, s2, f1, f2;
1549
1550     if( !p_sys->jss.b_inited )
1551     {
1552         p_sys->jss.i_comment = 0;
1553         p_sys->jss.i_time_resolution = 30;
1554         p_sys->jss.i_time_shift = 0;
1555
1556         p_sys->jss.b_inited = true;
1557     }
1558
1559     /* Parse the main lines */
1560     for( ;; )
1561     {
1562         const char *s = TextGetLine( txt );
1563         if( !s )
1564             return VLC_EGENERIC;
1565
1566         psz_orig = malloc( strlen( s ) + 1 );
1567         if( !psz_orig )
1568             return VLC_ENOMEM;
1569         psz_text = psz_orig;
1570
1571         /* Complete time lines */
1572         if( sscanf( s, "%d:%d:%d.%d %d:%d:%d.%d %[^\n\r]",
1573                     &h1, &m1, &s1, &f1, &h2, &m2, &s2, &f2, psz_text ) == 9 )
1574         {
1575             p_subtitle->i_start = ( (int64_t)( h1 *3600 + m1 * 60 + s1 ) +
1576                 (int64_t)( ( f1 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
1577                 * 1000000;
1578             p_subtitle->i_stop = ( (int64_t)( h2 *3600 + m2 * 60 + s2 ) +
1579                 (int64_t)( ( f2 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
1580                 * 1000000;
1581             break;
1582         }
1583         /* Short time lines */
1584         else if( sscanf( s, "@%d @%d %[^\n\r]", &f1, &f2, psz_text ) == 3 )
1585         {
1586             p_subtitle->i_start = (int64_t)(
1587                     ( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1588             p_subtitle->i_stop = (int64_t)(
1589                     ( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1590             break;
1591         }
1592         /* General Directive lines */
1593         /* Only TIME and SHIFT are supported so far */
1594         else if( s[0] == '#' )
1595         {
1596             int h = 0, m =0, sec = 1, f = 1;
1597             unsigned shift = 1;
1598             int inv = 1;
1599
1600             strcpy( psz_text, s );
1601
1602             switch( toupper( psz_text[1] ) )
1603             {
1604             case 'S':
1605                  shift = isalpha( psz_text[2] ) ? 6 : 2 ;
1606
1607                  if( sscanf( &psz_text[shift], "%d", &h ) )
1608                  {
1609                      /* Negative shifting */
1610                      if( h < 0 )
1611                      {
1612                          h *= -1;
1613                          inv = -1;
1614                      }
1615
1616                      if( sscanf( &psz_text[shift], "%*d:%d", &m ) )
1617                      {
1618                          if( sscanf( &psz_text[shift], "%*d:%*d:%d", &sec ) )
1619                          {
1620                              sscanf( &psz_text[shift], "%*d:%*d:%*d.%d", &f );
1621                          }
1622                          else
1623                          {
1624                              h = 0;
1625                              sscanf( &psz_text[shift], "%d:%d.%d",
1626                                      &m, &sec, &f );
1627                              m *= inv;
1628                          }
1629                      }
1630                      else
1631                      {
1632                          h = m = 0;
1633                          sscanf( &psz_text[shift], "%d.%d", &sec, &f);
1634                          sec *= inv;
1635                      }
1636                      p_sys->jss.i_time_shift = ( ( h * 3600 + m * 60 + sec )
1637                          * p_sys->jss.i_time_resolution + f ) * inv;
1638                  }
1639                  break;
1640
1641             case 'T':
1642                 shift = isalpha( psz_text[2] ) ? 8 : 2 ;
1643
1644                 sscanf( &psz_text[shift], "%d", &p_sys->jss.i_time_resolution );
1645                 break;
1646             }
1647             free( psz_orig );
1648             continue;
1649         }
1650         else
1651             /* Unkown type line, probably a comment */
1652         {
1653             free( psz_orig );
1654             continue;
1655         }
1656     }
1657         
1658     while( psz_text[ strlen( psz_text ) - 1 ] == '\\' )
1659     {
1660         const char *s2 = TextGetLine( txt );
1661
1662         if( !s2 )
1663         {
1664             free( psz_orig );
1665             return VLC_EGENERIC;
1666         }
1667
1668         int i_len = strlen( s2 );
1669         if( i_len == 0 )
1670             break;
1671
1672         int i_old = strlen( psz_text );
1673
1674         psz_text = realloc( psz_text, i_old + i_len + 1 );
1675         if( !psz_text )
1676              return VLC_ENOMEM;
1677
1678                 psz_orig = psz_text;
1679         strcat( psz_text, s2 );
1680     }
1681
1682     /* Skip the blanks */
1683     while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1684
1685     /* Parse the directives */
1686     if( isalpha( *psz_text ) || *psz_text == '[' )
1687     {
1688         while( *psz_text != ' ' )
1689         { psz_text++ ;};
1690
1691         /* Directives are NOT parsed yet */
1692         /* This has probably a better place in a decoder ? */
1693         /* directive = malloc( strlen( psz_text ) + 1 );
1694            if( sscanf( psz_text, "%s %[^\n\r]", directive, psz_text2 ) == 2 )*/
1695     }
1696
1697     /* Skip the blanks after directives */
1698     while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1699
1700     /* Clean all the lines from inline comments and other stuffs */
1701     psz_orig2 = calloc( strlen( psz_text) + 1, 1 );
1702     psz_text2 = psz_orig2;
1703
1704     for( ; *psz_text != '\0' && *psz_text != '\n' && *psz_text != '\r'; )
1705     {
1706         switch( *psz_text )
1707         {
1708         case '{':
1709             p_sys->jss.i_comment++;
1710             break;
1711         case '}':
1712             if( p_sys->jss.i_comment )
1713             {
1714                 p_sys->jss.i_comment = 0;
1715                 if( (*(psz_text + 1 ) ) == ' ' ) psz_text++;
1716             }
1717             break;
1718         case '~':
1719             if( !p_sys->jss.i_comment )
1720             {
1721                 *psz_text2 = ' ';
1722                 psz_text2++;
1723             }
1724             break;
1725         case ' ':
1726         case '\t':
1727             if( (*(psz_text + 1 ) ) == ' ' || (*(psz_text + 1 ) ) == '\t' )
1728                 break;
1729             if( !p_sys->jss.i_comment )
1730             {
1731                 *psz_text2 = ' ';
1732                 psz_text2++;
1733             }
1734             break;
1735         case '\\':
1736             if( (*(psz_text + 1 ) ) == 'n' )
1737             {
1738                 *psz_text2 = '\n';
1739                 psz_text++;
1740                 psz_text2++;
1741                 break;
1742             }
1743             if( ( toupper(*(psz_text + 1 ) ) == 'C' ) ||
1744                     ( toupper(*(psz_text + 1 ) ) == 'F' ) )
1745             {
1746                 psz_text++; psz_text++;
1747                 break;
1748             }
1749             if( (*(psz_text + 1 ) ) == 'B' || (*(psz_text + 1 ) ) == 'b' ||
1750                 (*(psz_text + 1 ) ) == 'I' || (*(psz_text + 1 ) ) == 'i' ||
1751                 (*(psz_text + 1 ) ) == 'U' || (*(psz_text + 1 ) ) == 'u' ||
1752                 (*(psz_text + 1 ) ) == 'D' || (*(psz_text + 1 ) ) == 'N' )
1753             {
1754                 psz_text++;
1755                 break;
1756             }
1757             if( (*(psz_text + 1 ) ) == '~' || (*(psz_text + 1 ) ) == '{' ||
1758                 (*(psz_text + 1 ) ) == '\\' )
1759                 psz_text++;
1760             else if( *(psz_text + 1 ) == '\r' ||  *(psz_text + 1 ) == '\n' ||
1761                      *(psz_text + 1 ) == '\0' )
1762             {
1763                                 psz_text++;
1764             }
1765             break;
1766         default:
1767             if( !p_sys->jss.i_comment )
1768             {
1769                 *psz_text2 = *psz_text;
1770                 psz_text2++;
1771             }
1772         }
1773         psz_text++;
1774     }
1775
1776     p_subtitle->psz_text = psz_orig2;
1777     msg_Dbg( p_demux, "%s", p_subtitle->psz_text );
1778     free( psz_orig );
1779     return VLC_SUCCESS;
1780 }
1781
1782 static int ParsePSB( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1783 {
1784     VLC_UNUSED( i_idx );
1785
1786     demux_sys_t *p_sys = p_demux->p_sys;
1787     text_t      *txt = &p_sys->txt;
1788     char *psz_text;
1789     int i;
1790
1791     for( ;; )
1792     {
1793         int h1, m1, s1;
1794         int h2, m2, s2;
1795         const char *s = TextGetLine( txt );
1796
1797         if( !s )
1798             return VLC_EGENERIC;
1799
1800         psz_text = malloc( strlen( s ) + 1 );
1801         if( !psz_text )
1802             return VLC_ENOMEM;
1803
1804         if( sscanf( s, "{%d:%d:%d}{%d:%d:%d}%[^\r\n]",
1805                     &h1, &m1, &s1, &h2, &m2, &s2, psz_text ) == 7 )
1806         {
1807             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1808                                     (int64_t)m1 * 60*1000 +
1809                                     (int64_t)s1 * 1000 ) * 1000;
1810             p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1811                                     (int64_t)m2 * 60*1000 +
1812                                     (int64_t)s2 * 1000 ) * 1000;
1813             break;
1814         }
1815         free( psz_text );
1816     }
1817
1818     /* replace | by \n */
1819     for( i = 0; psz_text[i] != '\0'; i++ )
1820     {
1821         if( psz_text[i] == '|' )
1822             psz_text[i] = '\n';
1823     }
1824     p_subtitle->psz_text = psz_text;
1825     return VLC_SUCCESS;
1826 }
1827
1828 static int64_t ParseRealTime( char *psz, int *h, int *m, int *s, int *f )
1829 {
1830     if( strlen( psz ) == 0 ) return 0;
1831     if( sscanf( psz, "%d:%d:%d.%d", h, m, s, f ) == 4 ||
1832             sscanf( psz, "%d:%d.%d", m, s, f ) == 3 ||
1833             sscanf( psz, "%d.%d", s, f ) == 2 ||
1834             sscanf( psz, "%d:%d", m, s ) == 2 ||
1835             sscanf( psz, "%d", s ) == 1 )
1836     {
1837         return (int64_t)((( *h * 60 + *m ) * 60 ) + *s ) * 1000 * 1000
1838                + (int64_t)*f * 10 * 1000;
1839     }
1840     else return VLC_EGENERIC;
1841 }
1842
1843 static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1844 {
1845     VLC_UNUSED( i_idx );
1846     demux_sys_t *p_sys = p_demux->p_sys;
1847     text_t      *txt = &p_sys->txt;
1848     char *psz_text = NULL;
1849
1850     for( ;; )
1851     {
1852         int h1 = 0, m1 = 0, s1 = 0, f1 = 0;
1853         int h2 = 0, m2 = 0, s2 = 0, f2 = 0;
1854         const char *s = TextGetLine( txt );
1855         free( psz_text );
1856
1857         if( !s )
1858             return VLC_EGENERIC;
1859
1860         psz_text = malloc( strlen( s ) + 1 );
1861         if( !psz_text )
1862             return VLC_ENOMEM;
1863
1864         /* Find the good begining. This removes extra spaces at the beginning
1865            of the line.*/
1866         char *psz_temp = strcasestr( s, "<time");
1867         if( psz_temp != NULL )
1868         {
1869             char psz_end[12], psz_begin[12];
1870             /* Line has begin and end */
1871             if( ( sscanf( psz_temp,
1872                   "<%*[t|T]ime %*[b|B]egin=\"%11[^\"]\" %*[e|E]nd=\"%11[^\"]%*[^>]%[^\n\r]",
1873                             psz_begin, psz_end, psz_text) != 3 ) &&
1874                     /* Line has begin and no end */
1875                     ( sscanf( psz_temp,
1876                               "<%*[t|T]ime %*[b|B]egin=\"%11[^\"]\"%*[^>]%[^\n\r]",
1877                               psz_begin, psz_text ) != 2) )
1878                 /* Line is not recognized */
1879             {
1880                 continue;
1881             }
1882
1883             /* Get the times */
1884             int64_t i_time = ParseRealTime( psz_begin, &h1, &m1, &s1, &f1 );
1885             if( i_time >= 0)
1886             {
1887                 p_subtitle->i_start = i_time;
1888             }
1889
1890             i_time = ParseRealTime( psz_end, &h2, &m2, &s2, &f2 );
1891             if( i_time >= 0 )
1892             {
1893                 p_subtitle->i_stop = i_time;
1894             }
1895             break;
1896         }
1897     }
1898
1899     /* Get the following Lines */
1900     for( ;; )
1901     {
1902         const char *s = TextGetLine( txt );
1903
1904         if( !s )
1905         {
1906             free( psz_text );
1907             return VLC_EGENERIC;
1908         }
1909
1910         int i_len = strlen( s );
1911         if( i_len == 0 ) break;
1912
1913         if( strcasestr( s, "<time" ) ||
1914             strcasestr( s, "<clear/") )
1915         {
1916             TextPreviousLine( txt );
1917             break;
1918         }
1919
1920         int i_old = strlen( psz_text );
1921
1922         psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1923         if( !psz_text )
1924             return VLC_ENOMEM;
1925
1926         strcat( psz_text, s );
1927         strcat( psz_text, "\n" );
1928     }
1929
1930     /* Remove the starting ">" that remained after the sscanf */
1931     memmove( &psz_text[0], &psz_text[1], strlen( psz_text ) );
1932
1933     p_subtitle->psz_text = psz_text;
1934
1935     return VLC_SUCCESS;
1936 }
1937
1938 static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1939 {
1940     VLC_UNUSED( i_idx );
1941
1942     demux_sys_t *p_sys = p_demux->p_sys;
1943     text_t      *txt = &p_sys->txt;
1944     char *psz_text;
1945
1946     for( ;; )
1947     {
1948         int h1, m1, s1;
1949         int h2, m2, s2;
1950         char *s = TextGetLine( txt );
1951
1952         if( !s )
1953             return VLC_EGENERIC;
1954
1955         psz_text = malloc( strlen( s ) + 1 );
1956         if( !psz_text )
1957             return VLC_ENOMEM;
1958
1959         if( sscanf( s, "[%d:%d:%d]%[^\r\n]",
1960                     &h1, &m1, &s1, psz_text ) == 4 )
1961         {
1962             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1963                                     (int64_t)m1 * 60*1000 +
1964                                     (int64_t)s1 * 1000 ) * 1000;
1965
1966             char *s = TextGetLine( txt );
1967             if( !s )
1968             {
1969                 free( psz_text );
1970                 return VLC_EGENERIC;
1971             }
1972
1973             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
1974                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
1975                                         (int64_t)m2 * 60*1000 +
1976                                         (int64_t)s2 * 1000 ) * 1000;
1977             break;
1978         }
1979         free( psz_text );
1980     }
1981
1982     /* replace [br] by \n */
1983     char *p;
1984     while( ( p = strstr( psz_text, "[br]" ) ) )
1985     {
1986         *p++ = '\n';
1987         memmove( p, &p[3], strlen(&p[3])+1 );
1988     }
1989
1990     p_subtitle->psz_text = psz_text;
1991     return VLC_SUCCESS;
1992 }
1993
1994 static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1995 {
1996     VLC_UNUSED( i_idx );
1997
1998     demux_sys_t *p_sys = p_demux->p_sys;
1999     text_t      *txt = &p_sys->txt;
2000     char *psz_text;
2001
2002     for( ;; )
2003     {
2004         int h1, m1, s1;
2005         int h2, m2, s2;
2006         char *s = TextGetLine( txt );
2007
2008         if( !s )
2009             return VLC_EGENERIC;
2010
2011         if( sscanf( s, "[%d:%d:%d]", &h1, &m1, &s1 ) == 3 )
2012         {
2013             p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
2014                                     (int64_t)m1 * 60*1000 +
2015                                     (int64_t)s1 * 1000 ) * 1000;
2016
2017             char *s = TextGetLine( txt );
2018             if( !s )
2019                 return VLC_EGENERIC;
2020
2021             psz_text = strdup( s );
2022             if( !psz_text )
2023                 return VLC_ENOMEM;
2024
2025             s = TextGetLine( txt );
2026             if( !s )
2027             {
2028                 free( psz_text );
2029                 return VLC_EGENERIC;
2030             }
2031
2032             if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
2033                 p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
2034                                         (int64_t)m2 * 60*1000 +
2035                                         (int64_t)s2 * 1000 ) * 1000;
2036             break;
2037         }
2038     }
2039
2040     p_subtitle->psz_text = psz_text;
2041
2042     return VLC_SUCCESS;
2043 }
2044