]> git.sesse.net Git - vlc/blob - modules/demux/util/sub.c
* Implement INPUT_GET_SUBDELAY and INPUT_SET_SUBDELAY
[vlc] / modules / demux / util / sub.c
1 /*****************************************************************************
2  * sub.c: subtitle demux for external subtitle files
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Derk-Jan Hartman <hartman at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <ctype.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/input.h>
35 #include "vlc_video.h"
36 #include <codecs.h>
37
38 #include "sub.h"
39
40 #if (!defined( WIN32 ) || defined(__MINGW32__))
41 #    include <dirent.h>
42 #endif
43
44 #define DVD_VIDEO_LB_LEN 2048
45
46 static int  Open ( vlc_object_t *p_this );
47
48 static int  sub_open ( subtitle_demux_t *p_sub,
49                        input_thread_t  *p_input,
50                        char  *psz_name,
51                        mtime_t i_microsecperframe );
52 static int  sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate );
53 static int  sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date );
54 static void sub_close( subtitle_demux_t *p_sub );
55
56 static void sub_fix( subtitle_demux_t *p_sub );
57
58 static char *ppsz_sub_type[] = { "auto", "microdvd", "subrip", "ssa1",
59   "ssa2-4", "vplayer", "sami", "vobsub" };
60
61 /*****************************************************************************
62  * Module descriptor
63  *****************************************************************************/
64 #define SUB_DELAY_LONGTEXT \
65     "Delay subtitles (in 1/10s)"
66 #define SUB_FPS_LONGTEXT \
67     "Override frames per second. " \
68     "It will only work with MicroDVD subtitles."
69 #define SUB_TYPE_LONGTEXT \
70     "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"vplayer\" " \
71     "\"sami\" (auto for autodetection, it should always work)."
72
73 vlc_module_begin();
74     set_description( _("Text subtitles demux") );
75     set_capability( "subtitle demux", 12 );
76     add_float( "sub-fps", 0.0, NULL,
77                N_("Frames per second"),
78                SUB_FPS_LONGTEXT, VLC_TRUE );
79     add_integer( "sub-delay", 0, NULL,
80                  N_("Delay subtitles (in 1/10s)"),
81                  SUB_DELAY_LONGTEXT, VLC_TRUE );
82     add_string( "sub-type", "auto", NULL, "Subtitles fileformat",
83                 SUB_TYPE_LONGTEXT, VLC_TRUE );
84         change_string_list( ppsz_sub_type, 0, 0 );
85     set_callbacks( Open, NULL );
86 vlc_module_end();
87
88 /*****************************************************************************
89  * Module initializer
90  *****************************************************************************/
91 static int Open ( vlc_object_t *p_this )
92 {
93     subtitle_demux_t *p_sub = (subtitle_demux_t*)p_this;
94
95     p_sub->pf_open  = sub_open;
96     p_sub->pf_demux = sub_demux;
97     p_sub->pf_seek  = sub_seek;
98     p_sub->pf_close = sub_close;
99
100     /* Initialize the variables */
101     var_Create( p_this, "sub-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
102     var_Create( p_this, "sub-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
103     var_Create( p_this, "sub-type", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
104
105     return VLC_SUCCESS;
106 }
107 #define MAX_TRY     256
108 #define MAX_LINE    2048
109
110 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
111
112 typedef struct
113 {
114     int     i_line_count;
115     int     i_line;
116     char    **line;
117 } text_t;
118
119 static int  text_load( text_t *txt, char *psz_name )
120 {
121     FILE *f;
122     int   i_line_max;
123
124     /* init txt */
125     i_line_max          = 100;
126     txt->i_line_count   = 0;
127     txt->i_line         = 0;
128     txt->line           = calloc( i_line_max, sizeof( char * ) );
129
130     /* open file */
131     if( !( f = fopen( psz_name, "rb" ) ) )
132     {
133         return VLC_EGENERIC;
134     }
135
136     /* load the complete file */
137     for( ;; )
138     {
139         char buffer[8096];
140         char *p;
141
142         if( fgets( buffer, 8096, f ) <= 0)
143         {
144             break;
145         }
146         while( ( p = strchr( buffer, '\r' ) ) )
147         {
148             *p = '\0';
149         }
150         while( ( p = strchr( buffer, '\n' ) ) )
151         {
152             *p = '\0';
153         }
154
155         txt->line[txt->i_line_count++] = strdup( buffer );
156
157         if( txt->i_line_count >= i_line_max )
158         {
159             i_line_max += 100;
160             txt->line = realloc( txt->line, i_line_max * sizeof( char*) );
161         }
162     }
163
164     fclose( f );
165
166     if( txt->i_line_count <= 0 )
167     {
168         FREE( txt->line );
169         return( VLC_EGENERIC );
170     }
171
172     return( VLC_SUCCESS );
173 }
174 static void text_unload( text_t *txt )
175 {
176     int i;
177
178     for( i = 0; i < txt->i_line_count; i++ )
179     {
180         FREE( txt->line[i] );
181     }
182     FREE( txt->line );
183     txt->i_line       = 0;
184     txt->i_line_count = 0;
185 }
186
187 static char *text_get_line( text_t *txt )
188 {
189     if( txt->i_line >= txt->i_line_count )
190     {
191         return( NULL );
192     }
193
194     return( txt->line[txt->i_line++] );
195 }
196 static void text_previous_line( text_t *txt )
197 {
198     if( txt->i_line > 0 )
199     {
200         txt->i_line--;
201     }
202 }
203 static void text_rewind( text_t *txt )
204 {
205     txt->i_line = 0;
206 }
207
208 static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
209 static int  sub_SubRipRead  ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
210 static int  sub_SSARead     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
211 static int  sub_Vplayer     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
212 static int  sub_Sami        ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
213 static int  sub_VobSubIDX   ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
214
215 static int  DemuxVobSub     ( subtitle_demux_t *, block_t * );
216
217 static struct
218 {
219     char *psz_type_name;
220     int  i_type;
221     char *psz_name;
222     int  (*pf_read_subtitle)    ( subtitle_demux_t *, text_t *, subtitle_t*, mtime_t );
223 } sub_read_subtitle_function [] =
224 {
225     { "microdvd",   SUB_TYPE_MICRODVD,  "MicroDVD", sub_MicroDvdRead },
226     { "subrip",     SUB_TYPE_SUBRIP,    "SubRIP",   sub_SubRipRead },
227     { "ssa1",       SUB_TYPE_SSA1,      "SSA-1",    sub_SSARead },
228     { "ssa2-4",     SUB_TYPE_SSA2_4,    "SSA-2/3/4",sub_SSARead },
229     { "vplayer",    SUB_TYPE_VPLAYER,   "VPlayer",  sub_Vplayer },
230     { "sami",       SUB_TYPE_SAMI,      "SAMI",     sub_Sami },
231     { "vobsub",     SUB_TYPE_VOBSUB,    "VobSub",   sub_VobSubIDX },
232     { NULL,         SUB_TYPE_UNKNOWN,   "Unknown",  NULL }
233 };
234
235 static char * local_stristr( char *psz_big, char *psz_little)
236 {
237     char *p_pos = psz_big;
238
239     if (!psz_big || !psz_little || !*psz_little) return psz_big;
240
241     while (*p_pos)
242     {
243         if (toupper(*p_pos) == toupper(*psz_little))
244         {
245             char * psz_cur1 = p_pos + 1;
246             char * psz_cur2 = psz_little + 1;
247             while (*psz_cur1 && *psz_cur2 && toupper(*psz_cur1) == toupper(*psz_cur2))
248             {
249                 psz_cur1++;
250                 psz_cur2++;
251             }
252             if (!*psz_cur2) return p_pos;
253         }
254         p_pos++;
255     }
256     return NULL;
257 }
258
259 /*****************************************************************************
260  * sub_open: Open a subtitle file and add subtitle ES
261  *****************************************************************************/
262 static int sub_open( subtitle_demux_t *p_sub, input_thread_t  *p_input,
263                      char *psz_name, mtime_t i_microsecperframe )
264 {
265     text_t  txt;
266     vlc_value_t val;
267     es_format_t fmt;
268     int i, i_sub_type, i_max;
269     int (*pf_read_subtitle)( subtitle_demux_t *, text_t *, subtitle_t *,
270                              mtime_t ) = NULL;
271
272     p_sub->i_sub_type = SUB_TYPE_UNKNOWN;
273     p_sub->p_es = NULL;
274     p_sub->i_subtitles = 0;
275     p_sub->subtitle = NULL;
276     p_sub->p_vobsub_file = 0;
277     p_sub->i_original_mspf = i_microsecperframe;
278     p_sub->p_input = p_input;
279
280     if( !psz_name || !*psz_name )
281     {
282         msg_Err( p_sub, "no subtitle file specified" );
283         return VLC_EGENERIC;
284     }
285
286     /* *** load the file *** */
287     if( text_load( &txt, psz_name ) )
288     {
289         msg_Err( p_sub, "cannot open `%s' subtitle file", psz_name );
290         return VLC_EGENERIC;
291     }
292
293     msg_Dbg( p_sub, "opened `%s'", psz_name );
294
295     var_Get( p_sub, "sub-fps", &val );
296     if( val.i_int >= 1.0 )
297     {
298         i_microsecperframe = (mtime_t)( (float)1000000 / val.f_float );
299     }
300     else if( val.f_float == 0 )
301     {
302         /* No value given */
303         i_microsecperframe = 0;
304     }
305     else if( val.f_float <= 0 )
306     {
307         /* invalid value, default = 25fps */
308         i_microsecperframe = 40000;
309     }
310
311     var_Get( p_sub, "sub-type", &val);
312     if( val.psz_string && *val.psz_string )
313     {
314         int i;
315
316         for( i = 0; ; i++ )
317         {
318             if( sub_read_subtitle_function[i].psz_type_name == NULL )
319             {
320                 i_sub_type = SUB_TYPE_UNKNOWN;
321                 break;
322             }
323             if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
324                          val.psz_string ) )
325             {
326                 i_sub_type = sub_read_subtitle_function[i].i_type;
327                 break;
328             }
329         }
330     }
331     else
332     {
333         i_sub_type = SUB_TYPE_UNKNOWN;
334     }
335     FREE( val.psz_string );
336
337     /* *** Now try to autodetect subtitle format *** */
338     if( i_sub_type == SUB_TYPE_UNKNOWN )
339     {
340         int     i_try;
341         char    *s;
342
343         msg_Dbg( p_input, "trying to autodetect file format" );
344         for( i_try = 0; i_try < MAX_TRY; i_try++ )
345         {
346             int i_dummy;
347
348             if( ( s = text_get_line( &txt ) ) == NULL )
349             {
350                 break;
351             }
352
353             if( local_stristr( s, "<SAMI>" ) )
354             {
355                 i_sub_type = SUB_TYPE_SAMI;
356                 break;
357             }
358             else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
359                      sscanf( s, "{%d}{}", &i_dummy ) == 1)
360             {
361                 i_sub_type = SUB_TYPE_MICRODVD;
362                 break;
363             }
364             else if( sscanf( s,
365                              "%d:%d:%d,%d --> %d:%d:%d,%d",
366                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
367                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
368             {
369                 i_sub_type = SUB_TYPE_SUBRIP;
370                 break;
371             }
372             else if( sscanf( s,
373                              "!: This is a Sub Station Alpha v%d.x script.",
374                              &i_dummy ) == 1)
375             {
376                 if( i_dummy <= 1 )
377                 {
378                     i_sub_type = SUB_TYPE_SSA1;
379                 }
380                 else
381                 {
382                     i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
383                 }
384                 break;
385             }
386             else if( local_stristr( s, "This is a Sub Station Alpha v4 script" ) )
387             {
388                 i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
389                 break;
390             }
391             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
392             {
393                 i_sub_type = SUB_TYPE_SSA2_4; /* could be wrong */
394                 break;
395             }
396             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
397                      sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
398             {
399                 i_sub_type = SUB_TYPE_VPLAYER;
400                 break;
401             }
402             else if( local_stristr( s, "# VobSub index file" ) )
403             {
404                 i_sub_type = SUB_TYPE_VOBSUB;
405                 break;
406             }
407         }
408
409         text_rewind( &txt );
410     }
411
412     /* *** Load this file in memory *** */
413     for( i = 0; ; i++ )
414     {
415         if( sub_read_subtitle_function[i].i_type == SUB_TYPE_UNKNOWN )
416         {
417             msg_Dbg( p_input, "unknown subtitle file" );
418             text_unload( &txt );
419             return VLC_EGENERIC;
420         }
421
422         if( sub_read_subtitle_function[i].i_type == i_sub_type )
423         {
424             msg_Dbg( p_input, "detected %s format",
425                     sub_read_subtitle_function[i].psz_name );
426             p_sub->i_sub_type = i_sub_type;
427             pf_read_subtitle = sub_read_subtitle_function[i].pf_read_subtitle;
428             break;
429         }
430     }
431
432     for( i_max = 0;; )
433     {
434         if( p_sub->i_subtitles >= i_max )
435         {
436             i_max += 128;
437             if( !( p_sub->subtitle = realloc( p_sub->subtitle,
438                                               sizeof(subtitle_t) * i_max ) ) )
439             {
440                 msg_Err( p_sub, "out of memory");
441                 return VLC_ENOMEM;
442             }
443         }
444         if( pf_read_subtitle( p_sub, &txt,
445                               p_sub->subtitle + p_sub->i_subtitles,
446                               i_microsecperframe ) < 0 )
447         {
448             break;
449         }
450         p_sub->i_subtitles++;
451     }
452     msg_Dbg( p_sub, "loaded %d subtitles", p_sub->i_subtitles );
453
454     /* *** Close the file *** */
455     text_unload( &txt );
456
457     /* *** fix subtitle (order and time) *** */
458     p_sub->i_subtitle = 0;  /* will be modified by sub_fix */
459     
460     if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
461     {
462         sub_fix( p_sub );
463     }
464
465     /* *** add subtitle ES *** */
466     if( p_sub->i_sub_type == SUB_TYPE_VOBSUB )
467     {
468         int i_len = strlen( psz_name );
469         char *psz_vobname = strdup(psz_name);
470
471         strcpy( psz_vobname + i_len - 4, ".sub" );
472
473         /* open file */
474         if( !( p_sub->p_vobsub_file = fopen( psz_vobname, "rb" ) ) )
475         {
476             msg_Err( p_sub, "couldn't open .sub Vobsub file: %s", psz_vobname );
477         }
478         free( psz_vobname );
479
480         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
481     }
482     else if( p_sub->i_sub_type == SUB_TYPE_SSA1 ||
483              p_sub->i_sub_type == SUB_TYPE_SSA2_4 )
484     {
485         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
486     }
487     else
488     {
489         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
490     }
491     if( p_sub->psz_header != NULL )
492     {
493         fmt.i_extra = strlen( p_sub->psz_header ) + 1;
494         fmt.p_extra = strdup( p_sub->psz_header );
495     }
496     p_sub->p_es = es_out_Add( p_input->p_es_out, &fmt );
497     p_sub->i_previously_selected = 0;
498
499     return VLC_SUCCESS;
500 }
501
502 /*****************************************************************************
503  * sub_demux: Send subtitle to decoder until i_maxdate
504  *****************************************************************************/
505 static int  sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
506 {
507     input_thread_t *p_input = p_sub->p_input;
508     vlc_bool_t     b;
509     vlc_value_t    val;
510     mtime_t i_delay;
511
512     es_out_Control( p_input->p_es_out, ES_OUT_GET_ES_STATE, p_sub->p_es, &b );
513     if( b && !p_sub->i_previously_selected )
514     {
515         p_sub->i_previously_selected = 1;
516         p_sub->pf_seek( p_sub, i_maxdate );
517         return VLC_SUCCESS;
518     }
519     else if( !b && p_sub->i_previously_selected )
520     {
521         p_sub->i_previously_selected = 0;
522         return VLC_SUCCESS;
523     }
524
525     if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
526     {
527         var_Get( p_sub, "sub-delay", &val );
528         i_delay = (mtime_t) val.i_int * 100000;
529         while( p_sub->i_subtitle < p_sub->i_subtitles &&
530                p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate - i_delay )
531         {
532             block_t *p_block;
533             int i_len = strlen( p_sub->subtitle[p_sub->i_subtitle].psz_text ) + 1;
534
535             if( i_len <= 1 )
536             {
537                 /* empty subtitle */
538                 p_sub->i_subtitle++;
539                 continue;
540             }
541
542             if( ( p_block = block_New( p_sub->p_input, i_len ) ) == NULL )
543             {
544                 p_sub->i_subtitle++;
545                 continue;
546             }
547
548             /* XXX we should convert all demuxers to use es_out_Control to set              * pcr and then remove that */
549             if( i_delay != 0 )
550             {
551                 p_sub->subtitle[p_sub->i_subtitle].i_start += i_delay;
552                 p_sub->subtitle[p_sub->i_subtitle].i_stop += i_delay;
553             }
554
555             p_block->i_pts =
556                 input_ClockGetTS( p_sub->p_input,
557                                   p_sub->p_input->stream.p_selected_program,
558                                   p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);
559             p_block->i_dts = 0;
560             if( p_sub->subtitle[p_sub->i_subtitle].i_stop > 0 )
561             {
562                 /* FIXME kludge i_dts means end of display... */
563                 p_block->i_dts =
564                     input_ClockGetTS( p_sub->p_input,
565                                   p_sub->p_input->stream.p_selected_program,
566                                   p_sub->subtitle[p_sub->i_subtitle].i_stop *9/100);
567             }
568
569             memcpy( p_block->p_buffer, p_sub->subtitle[p_sub->i_subtitle].psz_text, i_len );
570             if( p_block->i_pts > 0 )
571             {
572                 es_out_Send( p_input->p_es_out, p_sub->p_es, p_block );
573             }
574             else
575             {
576                 block_Release( p_block );
577             }
578             p_sub->i_subtitle++;
579         }
580     }
581     else
582     {
583         while( p_sub->i_subtitle < p_sub->i_subtitles &&
584                p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate )
585         {
586             int i_pos = p_sub->subtitle[p_sub->i_subtitle].i_vobsub_location;
587             block_t *p_block;
588             int i_size = 0;
589
590             /* first compute SPU size */
591             if( p_sub->i_subtitle + 1 < p_sub->i_subtitles )
592             {
593                 i_size = p_sub->subtitle[p_sub->i_subtitle+1].i_vobsub_location - i_pos;
594             }
595             if( i_size <= 0 ) i_size = 65535;   /* Invalid or EOF */
596
597             /* Seek at the right place (could be avoid if sub_seek is fixed to do his job) */
598             if( fseek( p_sub->p_vobsub_file, i_pos, SEEK_SET ) )
599             {
600                 msg_Warn( p_sub, "cannot seek at right vobsub location %d", i_pos );
601                 p_sub->i_subtitle++;
602                 continue;
603             }
604
605             /* allocate a packet */
606             if( ( p_block = block_New( p_sub, i_size ) ) == NULL )
607             {
608                 p_sub->i_subtitle++;
609                 continue;
610             }
611
612             /* read data */
613             p_block->i_buffer = fread( p_block->p_buffer, 1, i_size, p_sub->p_vobsub_file );
614             if( p_block->i_buffer <= 6 )
615             {
616                 block_Release( p_block );
617                 p_sub->i_subtitle++;
618                 continue;
619             }
620
621             /* pts */
622             p_block->i_pts =
623                 input_ClockGetTS( p_sub->p_input,
624                                   p_sub->p_input->stream.p_selected_program,
625                                   p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);
626
627             /* demux this block */
628             DemuxVobSub( p_sub, p_block );
629
630             p_sub->i_subtitle++;
631         }
632     }
633     return VLC_SUCCESS;
634 }
635
636 /*****************************************************************************
637  * sub_seek: Seek to i_date
638  *****************************************************************************/
639 static int  sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date )
640 {
641     /* should be fast enough... */
642     p_sub->i_subtitle = 0;
643     while( p_sub->i_subtitle < p_sub->i_subtitles &&
644            p_sub->subtitle[p_sub->i_subtitle].i_start < i_date )
645     {
646         p_sub->i_subtitle++;
647     }
648     return( 0 );
649 }
650
651 /*****************************************************************************
652  * sub_close: Close subtitle demux
653  *****************************************************************************/
654 static void sub_close( subtitle_demux_t *p_sub )
655 {
656     if( p_sub->subtitle )
657     {
658         int i;
659         for( i = 0; i < p_sub->i_subtitles; i++ )
660         {
661             if( p_sub->subtitle[i].psz_text )
662             {
663                 free( p_sub->subtitle[i].psz_text );
664             }
665         }
666         free( p_sub->subtitle );
667     }
668     if( p_sub->p_vobsub_file )
669     {
670         fclose( p_sub->p_vobsub_file );
671     }
672 }
673
674 /*****************************************************************************
675  * sub_fix: fix time stamp and order of subtitle
676  *****************************************************************************/
677 static void  sub_fix( subtitle_demux_t *p_sub )
678 {
679     int     i;
680     mtime_t i_delay;
681     int     i_index;
682     int     i_done;
683     vlc_value_t val;
684
685     /* *** fix order (to be sure...) *** */
686     /* We suppose that there are near in order and this durty bubble sort
687      * wont take too much time
688      */
689     do
690     {
691         i_done = 1;
692         for( i_index = 1; i_index < p_sub->i_subtitles; i_index++ )
693         {
694             if( p_sub->subtitle[i_index].i_start <
695                     p_sub->subtitle[i_index - 1].i_start )
696             {
697                 subtitle_t sub_xch;
698                 memcpy( &sub_xch,
699                         p_sub->subtitle + i_index - 1,
700                         sizeof( subtitle_t ) );
701                 memcpy( p_sub->subtitle + i_index - 1,
702                         p_sub->subtitle + i_index,
703                         sizeof( subtitle_t ) );
704                 memcpy( p_sub->subtitle + i_index,
705                         &sub_xch,
706                         sizeof( subtitle_t ) );
707                 i_done = 0;
708             }
709         }
710     } while( !i_done );
711
712     /* *** and at the end add delay *** */
713     var_Get( p_sub, "sub-delay", &val );
714     i_delay = (mtime_t) val.i_int * 100000;
715     if( i_delay != 0 )
716     {
717         for( i = 0; i < p_sub->i_subtitles; i++ )
718         {
719             p_sub->subtitle[i].i_start += i_delay;
720             p_sub->subtitle[i].i_stop += i_delay;
721             if( p_sub->subtitle[i].i_start < 0 )
722             {
723                 p_sub->i_subtitle = i + 1;
724             }
725         }
726     }
727 }
728
729
730
731 /*****************************************************************************
732  * Specific Subtitle function
733  *****************************************************************************/
734 static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
735 {
736     /*
737      * each line:
738      *  {n1}{n2}Line1|Line2|Line3....
739      * where n1 and n2 are the video frame number...
740      *
741      */
742     char *s;
743
744     char buffer_text[MAX_LINE + 1];
745     unsigned int    i_start;
746     unsigned int    i_stop;
747     unsigned int i;
748     
749     p_subtitle->i_start = 0;
750     p_subtitle->i_stop  = 0;
751     p_subtitle->i_vobsub_location  = 0;
752     p_subtitle->psz_text = NULL;
753
754     for( ;; )
755     {
756         if( ( s = text_get_line( txt ) ) == NULL )
757         {
758             return( VLC_EGENERIC );
759         }
760         i_start = 0;
761         i_stop  = 0;
762
763         memset( buffer_text, '\0', MAX_LINE );
764         if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
765             sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
766         {
767             break;
768         }
769     }
770     /* replace | by \n */
771     for( i = 0; i < strlen( buffer_text ); i++ )
772     {
773         if( buffer_text[i] == '|' )
774         {
775             buffer_text[i] = '\n';
776         }
777     }
778     if( i_microsecperframe == 0)
779     {
780         i_microsecperframe = 40000;
781     }
782     p_subtitle->i_start = (mtime_t)i_start * (mtime_t)i_microsecperframe;
783     p_subtitle->i_stop  = (mtime_t)i_stop  * (mtime_t)i_microsecperframe;
784     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
785     return( 0 );
786 }
787
788 static int  sub_SubRipRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
789 {
790     /*
791      * n
792      * h1:m1:s1,d1 --> h2:m2:s2,d2
793      * Line1
794      * Line2
795      * ...
796      * [empty line]
797      *
798      */
799     char *s;
800     char buffer_text[ 10 * MAX_LINE];
801     int  i_buffer_text;
802     mtime_t     i_start;
803     mtime_t     i_stop;
804
805     p_subtitle->i_start = 0;
806     p_subtitle->i_stop  = 0;
807     p_subtitle->i_vobsub_location  = 0;
808     p_subtitle->psz_text = NULL;
809
810     for( ;; )
811     {
812         int h1, m1, s1, d1, h2, m2, s2, d2;
813         if( ( s = text_get_line( txt ) ) == NULL )
814         {
815             return( VLC_EGENERIC );
816         }
817         if( sscanf( s,
818                     "%d:%d:%d,%d --> %d:%d:%d,%d",
819                     &h1, &m1, &s1, &d1,
820                     &h2, &m2, &s2, &d2 ) == 8 )
821         {
822             i_start = ( (mtime_t)h1 * 3600*1000 +
823                         (mtime_t)m1 * 60*1000 +
824                         (mtime_t)s1 * 1000 +
825                         (mtime_t)d1 ) * 1000;
826
827             i_stop  = ( (mtime_t)h2 * 3600*1000 +
828                         (mtime_t)m2 * 60*1000 +
829                         (mtime_t)s2 * 1000 +
830                         (mtime_t)d2 ) * 1000;
831
832             /* Now read text until an empty line */
833             for( i_buffer_text = 0;; )
834             {
835                 int i_len;
836                 if( ( s = text_get_line( txt ) ) == NULL )
837                 {
838                     return( VLC_EGENERIC );
839                 }
840
841                 i_len = strlen( s );
842                 if( i_len <= 1 )
843                 {
844                     /* empty line -> end of this subtitle */
845                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
846                     p_subtitle->i_start = i_start;
847                     p_subtitle->i_stop = i_stop;
848                     p_subtitle->psz_text = strdup( buffer_text );
849                     /* If framerate is available, use sub-fps */
850                     if( i_microsecperframe != 0 && p_sub->i_original_mspf != 0)
851                     {
852                         p_subtitle->i_start = (mtime_t)i_start *
853                                               (mtime_t)p_sub->i_original_mspf /
854                                               (mtime_t)i_microsecperframe;
855                         p_subtitle->i_stop  = (mtime_t)i_stop  *
856                                               (mtime_t)p_sub->i_original_mspf /
857                                               (mtime_t)i_microsecperframe;
858                     }
859                     return( 0 );
860                 }
861                 else
862                 {
863                     if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
864                     {
865                         memcpy( buffer_text + i_buffer_text,
866                                 s,
867                                 i_len );
868                         i_buffer_text += i_len;
869
870                         buffer_text[i_buffer_text] = '\n';
871                         i_buffer_text++;
872                     }
873                 }
874             }
875         }
876     }
877 }
878
879
880 static int  sub_SSARead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
881 {
882     char buffer_text[ 10 * MAX_LINE];
883     char *s;
884     mtime_t     i_start;
885     mtime_t     i_stop;
886
887     p_subtitle->i_start = 0;
888     p_subtitle->i_stop  = 0;
889     p_subtitle->i_vobsub_location  = 0;
890     p_subtitle->psz_text = NULL;
891
892     for( ;; )
893     {
894         int h1, m1, s1, c1, h2, m2, s2, c2;
895         int i_dummy;
896
897         if( ( s = text_get_line( txt ) ) == NULL )
898         {
899             return( VLC_EGENERIC );
900         }
901         p_subtitle->psz_text = malloc( strlen( s ) );
902
903         if( sscanf( s,
904                     "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d%[^\r\n]",
905                     &i_dummy,
906                     &h1, &m1, &s1, &c1,
907                     &h2, &m2, &s2, &c2,
908                     buffer_text ) == 10 )
909         {
910             i_start = ( (mtime_t)h1 * 3600*1000 +
911                         (mtime_t)m1 * 60*1000 +
912                         (mtime_t)s1 * 1000 +
913                         (mtime_t)c1 * 10 ) * 1000;
914
915             i_stop  = ( (mtime_t)h2 * 3600*1000 +
916                         (mtime_t)m2 * 60*1000 +
917                         (mtime_t)s2 * 1000 +
918                         (mtime_t)c2 * 10 ) * 1000;
919
920             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
921             if( p_sub->i_sub_type == SUB_TYPE_SSA1 )
922             {
923                 sprintf( p_subtitle->psz_text, ",%d%s", i_dummy, strdup( buffer_text) );
924             }
925             else
926             {
927                 sprintf( p_subtitle->psz_text, ",%d,%s", i_dummy, strdup( buffer_text) );
928             }
929             p_subtitle->i_start = i_start;
930             p_subtitle->i_stop = i_stop;
931             return( 0 );
932         }
933         else
934         {
935             /* All the other stuff we add to the header field */
936             if( p_sub->psz_header != NULL )
937             {
938                 if( !( p_sub->psz_header = realloc( p_sub->psz_header,
939                           strlen( p_sub->psz_header ) + strlen( s ) + 2 ) ) )
940                 {
941                     msg_Err( p_sub, "out of memory");
942                     return VLC_ENOMEM;
943                 }
944                 p_sub->psz_header = strcat( p_sub->psz_header, strdup( s ) );
945                 p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
946             }
947             else
948             {
949                 if( !( p_sub->psz_header = malloc( strlen( s ) + 2 ) ) )
950                 {
951                     msg_Err( p_sub, "out of memory");
952                     return VLC_ENOMEM;
953                 }
954                 p_sub->psz_header = strdup( s );
955                 p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
956             }
957         }
958     }
959 }
960
961 static int  sub_Vplayer( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
962 {
963     /*
964      * each line:
965      *  h:m:s:Line1|Line2|Line3....
966      *  or
967      *  h:m:s Line1|Line2|Line3....
968      * where n1 and n2 are the video frame number...
969      *
970      */
971     char *p;
972     char buffer_text[MAX_LINE + 1];
973     mtime_t    i_start;
974     unsigned int i;
975     
976     p_subtitle->i_start = 0;
977     p_subtitle->i_stop  = 0;
978     p_subtitle->i_vobsub_location  = 0;
979     p_subtitle->psz_text = NULL;
980
981     for( ;; )
982     {
983         int h, m, s;
984         char c;
985
986         if( ( p = text_get_line( txt ) ) == NULL )
987         {
988             return( VLC_EGENERIC );
989         }
990
991         i_start = 0;
992
993         memset( buffer_text, '\0', MAX_LINE );
994         if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
995         {
996             i_start = ( (mtime_t)h * 3600*1000 +
997                         (mtime_t)m * 60*1000 +
998                         (mtime_t)s * 1000 ) * 1000;
999             break;
1000         }
1001     }
1002
1003     /* replace | by \n */
1004     for( i = 0; i < strlen( buffer_text ); i++ )
1005     {
1006         if( buffer_text[i] == '|' )
1007         {
1008             buffer_text[i] = '\n';
1009         }
1010     }
1011     p_subtitle->i_start = i_start;
1012
1013     p_subtitle->i_stop  = 0;
1014     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
1015     return( 0 );
1016 }
1017
1018 static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
1019 {
1020     if( psz_start )
1021     {
1022         if( local_stristr( psz_start, psz_str ) )
1023         {
1024             char *s = local_stristr( psz_start, psz_str );
1025
1026             s += strlen( psz_str );
1027
1028             return( s );
1029         }
1030     }
1031     for( ;; )
1032     {
1033         char *p;
1034         if( ( p = text_get_line( txt ) ) == NULL )
1035         {
1036             return NULL;
1037         }
1038         if( local_stristr( p, psz_str ) )
1039         {
1040             char *s = local_stristr( p, psz_str );
1041
1042             s += strlen( psz_str );
1043
1044             return(  s);
1045         }
1046     }
1047 }
1048
1049 static int  sub_Sami( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
1050 {
1051     char *p;
1052     int i_start;
1053
1054     int  i_text;
1055     char buffer_text[10*MAX_LINE + 1];
1056
1057     p_subtitle->i_start = 0;
1058     p_subtitle->i_stop  = 0;
1059     p_subtitle->i_vobsub_location  = 0;
1060     p_subtitle->psz_text = NULL;
1061
1062 #define ADDC( c ) \
1063     if( i_text < 10*MAX_LINE )      \
1064     {                               \
1065         buffer_text[i_text++] = c;  \
1066         buffer_text[i_text] = '\0'; \
1067     }
1068
1069     /* search "Start=" */
1070     if( !( p = sub_SamiSearch( txt, NULL, "Start=" ) ) )
1071     {
1072         return VLC_EGENERIC;
1073     }
1074
1075     /* get start value */
1076     i_start = strtol( p, &p, 0 );
1077
1078     /* search <P */
1079     if( !( p = sub_SamiSearch( txt, p, "<P" ) ) )
1080     {
1081         return VLC_EGENERIC;
1082     }
1083     /* search > */
1084     if( !( p = sub_SamiSearch( txt, p, ">" ) ) )
1085     {
1086         return VLC_EGENERIC;
1087     }
1088
1089     i_text = 0;
1090     buffer_text[0] = '\0';
1091     /* now get all txt until  a "Start=" line */
1092     for( ;; )
1093     {
1094         if( *p )
1095         {
1096             if( *p == '<' )
1097             {
1098                 if( !strncasecmp( p, "<br", 3 ) )
1099                 {
1100                     ADDC( '\n' );
1101                 }
1102                 else if( local_stristr( p, "Start=" ) )
1103                 {
1104                     text_previous_line( txt );
1105                     break;
1106                 }
1107                 p = sub_SamiSearch( txt, p, ">" );
1108             }
1109             else if( !strncmp( p, "&nbsp;", 6 ) )
1110             {
1111                 ADDC( ' ' );
1112                 p += 6;
1113             }
1114             else if( *p == '\t' )
1115             {
1116                 ADDC( ' ' );
1117                 p++;
1118             }
1119             else
1120             {
1121                 ADDC( *p );
1122                 p++;
1123             }
1124         }
1125         else
1126         {
1127             p = text_get_line( txt );
1128         }
1129
1130         if( p == NULL )
1131         {
1132             break;
1133         }
1134     }
1135
1136     p_subtitle->i_start = i_start * 1000;
1137     p_subtitle->i_stop  = 0;
1138     p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
1139
1140     return( VLC_SUCCESS );
1141 #undef ADDC
1142 }
1143
1144 static int  sub_VobSubIDX( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
1145 {
1146     /*
1147      * Parse the idx file. Each line:
1148      * timestamp: hh:mm:ss:mss, filepos: loc
1149      * hexint is the hex location of the vobsub in the .sub file
1150      *
1151      */
1152     char *p;
1153     char buffer_text[MAX_LINE + 1];
1154     unsigned int    i_start, i_location;
1155
1156     p_subtitle->i_start = 0;
1157     p_subtitle->i_stop  = 0;
1158     p_subtitle->i_vobsub_location  = 0;
1159     p_subtitle->psz_text = NULL;
1160
1161     for( ;; )
1162     {
1163         unsigned int h, m, s, ms, loc;
1164
1165         if( ( p = text_get_line( txt ) ) == NULL )
1166         {
1167             return( VLC_EGENERIC );
1168         }
1169         i_start = 0;
1170
1171         memset( buffer_text, '\0', MAX_LINE );
1172         if( sscanf( p, "timestamp: %d:%d:%d:%d, filepos: %x%[^\r\n]",
1173                     &h, &m, &s, &ms, &loc, buffer_text ) == 5 )
1174         {
1175             i_start = ( (mtime_t)h * 3600*1000 +
1176                         (mtime_t)m * 60*1000 +
1177                         (mtime_t)s * 1000 +
1178                         (mtime_t)ms ) * 1000;
1179             i_location = loc;
1180             break;
1181         }
1182     }
1183     p_subtitle->i_start = (mtime_t)i_start;
1184     p_subtitle->i_stop  = 0;
1185     p_subtitle->psz_text = NULL;
1186     p_subtitle->i_vobsub_location = i_location;
1187     fprintf( stderr, "time: %x, location: %x\n", i_start, i_location );
1188     return( 0 );
1189 }
1190
1191 static int  DemuxVobSub( subtitle_demux_t *p_demux, block_t *p_bk )
1192 {
1193     uint8_t     *p = p_bk->p_buffer;
1194     uint8_t     *p_end = &p_bk->p_buffer[p_bk->i_buffer];
1195
1196     while( p < p_end )
1197     {
1198         int i_size = ps_pkt_size( p, p_end - p );
1199         block_t *p_pkt;
1200         int      i_id;
1201         int      i_spu;
1202
1203         if( i_size <= 0 )
1204         {
1205             break;
1206         }
1207         if( p[0] != 0 || p[1] != 0 || p[2] != 0x01 )
1208         {
1209             msg_Warn( p_demux, "invalid PES" );
1210             break;
1211         }
1212
1213         if( p[3] != 0xbd )
1214         {
1215             msg_Dbg( p_demux, "we don't need these ps packets (id=0x1%2.2x)", p[3] );
1216             p += i_size;
1217             continue;
1218         }
1219
1220         /* Create a block */
1221         p_pkt = block_New( p_demux, i_size );
1222         memcpy( p_pkt->p_buffer, p, i_size);
1223         p += i_size;
1224
1225         i_id = ps_pkt_id( p_pkt );
1226         if( (i_id&0xffe0) != 0xbd20 ||
1227             ps_pkt_parse_pes( p_pkt, 1 ) )
1228         {
1229             block_Release( p_pkt );
1230             continue;
1231         }
1232         i_spu = i_id&0x1f;
1233         msg_Dbg( p_demux, "SPU track %d size %d", i_spu, i_size );
1234
1235         /* FIXME i_spu == determines which of the spu tracks we will show. */
1236         if( p_demux->p_es && i_spu == 0 )
1237         {
1238             p_pkt->i_pts = p_bk->i_pts;
1239             p_pkt->i_dts = 0;
1240             es_out_Send( p_demux->p_input->p_es_out, p_demux->p_es, p_pkt );
1241
1242             p_bk->i_pts = 0;    /* only first packet has a pts */
1243         }
1244         else
1245         {
1246             block_Release( p_pkt );
1247             continue;
1248         }
1249     }
1250
1251     return VLC_SUCCESS;
1252 }