]> git.sesse.net Git - vlc/blob - modules/demux/util/sub.c
a921c942812f7b545f0511b1b11425d1ba3d084f
[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: sub.c,v 1.52 2004/02/22 15:59:53 fenrir Exp $
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", 25.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->p_input = p_input;
278
279     if( !psz_name || !*psz_name )
280     {
281         msg_Err( p_sub, "no subtitle file specified" );
282         return VLC_EGENERIC;
283     }
284
285     /* *** load the file *** */
286     if( text_load( &txt, psz_name ) )
287     {
288         msg_Err( p_sub, "cannot open `%s' subtitle file", psz_name );
289         return VLC_EGENERIC;
290     }
291
292     msg_Dbg( p_sub, "opened `%s'", psz_name );
293
294     var_Get( p_sub, "sub-fps", &val );
295     if( val.i_int >= 1.0 )
296     {
297         i_microsecperframe = (mtime_t)( (float)1000000 / val.f_float );
298     }
299     else if( val.f_float <= 0 )
300     {
301         i_microsecperframe = 40000; /* default: 25fps */
302     }
303
304     var_Get( p_sub, "sub-type", &val);
305     if( val.psz_string && *val.psz_string )
306     {
307         int i;
308
309         for( i = 0; ; i++ )
310         {
311             if( sub_read_subtitle_function[i].psz_type_name == NULL )
312             {
313                 i_sub_type = SUB_TYPE_UNKNOWN;
314                 break;
315             }
316             if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
317                          val.psz_string ) )
318             {
319                 i_sub_type = sub_read_subtitle_function[i].i_type;
320                 break;
321             }
322         }
323     }
324     else
325     {
326         i_sub_type = SUB_TYPE_UNKNOWN;
327     }
328     FREE( val.psz_string );
329
330     /* *** Now try to autodetect subtitle format *** */
331     if( i_sub_type == SUB_TYPE_UNKNOWN )
332     {
333         int     i_try;
334         char    *s;
335
336         msg_Dbg( p_input, "trying to autodetect file format" );
337         for( i_try = 0; i_try < MAX_TRY; i_try++ )
338         {
339             int i_dummy;
340
341             if( ( s = text_get_line( &txt ) ) == NULL )
342             {
343                 break;
344             }
345
346             if( local_stristr( s, "<SAMI>" ) )
347             {
348                 i_sub_type = SUB_TYPE_SAMI;
349                 break;
350             }
351             else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
352                      sscanf( s, "{%d}{}", &i_dummy ) == 1)
353             {
354                 i_sub_type = SUB_TYPE_MICRODVD;
355                 break;
356             }
357             else if( sscanf( s,
358                              "%d:%d:%d,%d --> %d:%d:%d,%d",
359                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
360                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
361             {
362                 i_sub_type = SUB_TYPE_SUBRIP;
363                 break;
364             }
365             else if( sscanf( s,
366                              "!: This is a Sub Station Alpha v%d.x script.",
367                              &i_dummy ) == 1)
368             {
369                 if( i_dummy <= 1 )
370                 {
371                     i_sub_type = SUB_TYPE_SSA1;
372                 }
373                 else
374                 {
375                     i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
376                 }
377                 break;
378             }
379             else if( local_stristr( s, "This is a Sub Station Alpha v4 script" ) )
380             {
381                 i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
382                 break;
383             }
384             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
385             {
386                 i_sub_type = SUB_TYPE_SSA2_4; /* could be wrong */
387                 break;
388             }
389             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
390                      sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
391             {
392                 i_sub_type = SUB_TYPE_VPLAYER;
393                 break;
394             }
395             else if( local_stristr( s, "# VobSub index file" ) )
396             {
397                 i_sub_type = SUB_TYPE_VOBSUB;
398                 break;
399             }
400         }
401
402         text_rewind( &txt );
403     }
404
405     /* *** Load this file in memory *** */
406     for( i = 0; ; i++ )
407     {
408         if( sub_read_subtitle_function[i].i_type == SUB_TYPE_UNKNOWN )
409         {
410             msg_Dbg( p_input, "unknown subtitle file" );
411             text_unload( &txt );
412             return VLC_EGENERIC;
413         }
414
415         if( sub_read_subtitle_function[i].i_type == i_sub_type )
416         {
417             msg_Dbg( p_input, "detected %s format",
418                     sub_read_subtitle_function[i].psz_name );
419             p_sub->i_sub_type = i_sub_type;
420             pf_read_subtitle = sub_read_subtitle_function[i].pf_read_subtitle;
421             break;
422         }
423     }
424
425     for( i_max = 0;; )
426     {
427         if( p_sub->i_subtitles >= i_max )
428         {
429             i_max += 128;
430             if( !( p_sub->subtitle = realloc( p_sub->subtitle,
431                                               sizeof(subtitle_t) * i_max ) ) )
432             {
433                 msg_Err( p_sub, "out of memory");
434                 return VLC_ENOMEM;
435             }
436         }
437         if( pf_read_subtitle( p_sub, &txt,
438                               p_sub->subtitle + p_sub->i_subtitles,
439                               i_microsecperframe ) < 0 )
440         {
441             break;
442         }
443         p_sub->i_subtitles++;
444     }
445     msg_Dbg( p_sub, "loaded %d subtitles", p_sub->i_subtitles );
446
447     /* *** Close the file *** */
448     text_unload( &txt );
449
450     /* *** fix subtitle (order and time) *** */
451     p_sub->i_subtitle = 0;  /* will be modified by sub_fix */
452     
453     if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
454     {
455         sub_fix( p_sub );
456     }
457
458     /* *** add subtitle ES *** */
459     if( p_sub->i_sub_type == SUB_TYPE_VOBSUB )
460     {
461         int i_len = strlen( psz_name );
462         char *psz_vobname = strdup(psz_name);
463
464         strcpy( psz_vobname + i_len - 4, ".sub" );
465
466         /* open file */
467         if( !( p_sub->p_vobsub_file = fopen( psz_vobname, "rb" ) ) )
468         {
469             msg_Err( p_sub, "couldn't open .sub Vobsub file: %s", psz_vobname );
470         }
471         free( psz_vobname );
472
473         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
474     }
475     else if( p_sub->i_sub_type == SUB_TYPE_SSA1 ||
476              p_sub->i_sub_type == SUB_TYPE_SSA2_4 )
477     {
478         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
479     }
480     else
481     {
482         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
483     }
484     if( p_sub->psz_header != NULL )
485     {
486         fmt.i_extra = strlen( p_sub->psz_header ) + 1;
487         fmt.p_extra = strdup( p_sub->psz_header );
488     }
489     p_sub->p_es = es_out_Add( p_input->p_es_out, &fmt );
490     p_sub->i_previously_selected = 0;
491
492     return VLC_SUCCESS;
493 }
494
495 /*****************************************************************************
496  * sub_demux: Send subtitle to decoder until i_maxdate
497  *****************************************************************************/
498 static int  sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
499 {
500     input_thread_t *p_input = p_sub->p_input;
501     vlc_bool_t     b;
502
503     es_out_Control( p_input->p_es_out, ES_OUT_GET_ES_STATE, p_sub->p_es, &b );
504     if( b && !p_sub->i_previously_selected )
505     {
506         p_sub->i_previously_selected = 1;
507         p_sub->pf_seek( p_sub, i_maxdate );
508         return VLC_SUCCESS;
509     }
510     else if( !b && p_sub->i_previously_selected )
511     {
512         p_sub->i_previously_selected = 0;
513         return VLC_SUCCESS;
514     }
515
516     if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
517     {
518         while( p_sub->i_subtitle < p_sub->i_subtitles &&
519                p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate )
520         {
521             block_t *p_block;
522             int i_len = strlen( p_sub->subtitle[p_sub->i_subtitle].psz_text ) + 1;
523
524             if( i_len <= 1 )
525             {
526                 /* empty subtitle */
527                 p_sub->i_subtitle++;
528                 continue;
529             }
530
531             if( ( p_block = block_New( p_sub->p_input, i_len ) ) == NULL )
532             {
533                 p_sub->i_subtitle++;
534                 continue;
535             }
536
537             /* XXX we should convert all demuxers to use es_out_Control to set pcr and
538              * then remove that */
539             p_block->i_pts =
540                 input_ClockGetTS( p_sub->p_input,
541                                   p_sub->p_input->stream.p_selected_program,
542                                   p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);
543             p_block->i_dts = 0;
544             if( p_sub->subtitle[p_sub->i_subtitle].i_stop > 0 )
545             {
546                 /* FIXME kludge i_dts means end of display... */
547                 p_block->i_dts =
548                     input_ClockGetTS( p_sub->p_input,
549                                   p_sub->p_input->stream.p_selected_program,
550                                   p_sub->subtitle[p_sub->i_subtitle].i_stop *9/100);
551             }
552
553             memcpy( p_block->p_buffer, p_sub->subtitle[p_sub->i_subtitle].psz_text, i_len );
554
555             if( p_block->i_pts > 0 )
556             {
557                 es_out_Send( p_input->p_es_out, p_sub->p_es, p_block );
558             }
559             else
560             {
561                 block_Release( p_block );
562             }
563             p_sub->i_subtitle++;
564         }
565     }
566     else
567     {
568         while( p_sub->i_subtitle < p_sub->i_subtitles &&
569                p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate )
570         {
571             int i_pos = p_sub->subtitle[p_sub->i_subtitle].i_vobsub_location;
572             block_t *p_block;
573             int i_size = 0;
574
575             /* first compute SPU size */
576             if( p_sub->i_subtitle + 1 < p_sub->i_subtitles )
577             {
578                 i_size = p_sub->subtitle[p_sub->i_subtitle+1].i_vobsub_location - i_pos;
579             }
580             if( i_size <= 0 ) i_size = 65535;   /* Invalid or EOF */
581
582             /* Seek at the right place (could be avoid if sub_seek is fixed to do his job) */
583             if( fseek( p_sub->p_vobsub_file, i_pos, SEEK_SET ) )
584             {
585                 msg_Warn( p_sub, "cannot seek at right vobsub location %d", i_pos );
586                 p_sub->i_subtitle++;
587                 continue;
588             }
589
590             /* allocate a packet */
591             if( ( p_block = block_New( p_sub, i_size ) ) == NULL )
592             {
593                 p_sub->i_subtitle++;
594                 continue;
595             }
596
597             /* read data */
598             p_block->i_buffer = fread( p_block->p_buffer, 1, i_size, p_sub->p_vobsub_file );
599             if( p_block->i_buffer <= 6 )
600             {
601                 block_Release( p_block );
602                 p_sub->i_subtitle++;
603                 continue;
604             }
605
606             /* pts */
607             p_block->i_pts =
608                 input_ClockGetTS( p_sub->p_input,
609                                   p_sub->p_input->stream.p_selected_program,
610                                   p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);
611
612             /* demux this block */
613             DemuxVobSub( p_sub, p_block );
614
615             p_sub->i_subtitle++;
616         }
617     }
618     return VLC_SUCCESS;
619 }
620
621 /*****************************************************************************
622  * sub_seek: Seek to i_date
623  *****************************************************************************/
624 static int  sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date )
625 {
626     /* should be fast enough... */
627     p_sub->i_subtitle = 0;
628     while( p_sub->i_subtitle < p_sub->i_subtitles &&
629            p_sub->subtitle[p_sub->i_subtitle].i_start < i_date )
630     {
631         p_sub->i_subtitle++;
632     }
633     return( 0 );
634 }
635
636 /*****************************************************************************
637  * sub_close: Close subtitle demux
638  *****************************************************************************/
639 static void sub_close( subtitle_demux_t *p_sub )
640 {
641     if( p_sub->subtitle )
642     {
643         int i;
644         for( i = 0; i < p_sub->i_subtitles; i++ )
645         {
646             if( p_sub->subtitle[i].psz_text )
647             {
648                 free( p_sub->subtitle[i].psz_text );
649             }
650         }
651         free( p_sub->subtitle );
652     }
653     if( p_sub->p_vobsub_file )
654     {
655         fclose( p_sub->p_vobsub_file );
656     }
657 }
658
659 /*****************************************************************************
660  * sub_fix: fix time stamp and order of subtitle
661  *****************************************************************************/
662 static void  sub_fix( subtitle_demux_t *p_sub )
663 {
664     int     i;
665     mtime_t i_delay;
666     int     i_index;
667     int     i_done;
668     vlc_value_t val;
669
670     /* *** fix order (to be sure...) *** */
671     /* We suppose that there are near in order and this durty bubble sort
672      * wont take too much time
673      */
674     do
675     {
676         i_done = 1;
677         for( i_index = 1; i_index < p_sub->i_subtitles; i_index++ )
678         {
679             if( p_sub->subtitle[i_index].i_start <
680                     p_sub->subtitle[i_index - 1].i_start )
681             {
682                 subtitle_t sub_xch;
683                 memcpy( &sub_xch,
684                         p_sub->subtitle + i_index - 1,
685                         sizeof( subtitle_t ) );
686                 memcpy( p_sub->subtitle + i_index - 1,
687                         p_sub->subtitle + i_index,
688                         sizeof( subtitle_t ) );
689                 memcpy( p_sub->subtitle + i_index,
690                         &sub_xch,
691                         sizeof( subtitle_t ) );
692                 i_done = 0;
693             }
694         }
695     } while( !i_done );
696
697     /* *** and at the end add delay *** */
698     var_Get( p_sub, "sub-delay", &val );
699     i_delay = (mtime_t) val.i_int * 100000;
700     if( i_delay != 0 )
701     {
702         for( i = 0; i < p_sub->i_subtitles; i++ )
703         {
704             p_sub->subtitle[i].i_start += i_delay;
705             p_sub->subtitle[i].i_stop += i_delay;
706             if( p_sub->subtitle[i].i_start < 0 )
707             {
708                 p_sub->i_subtitle = i + 1;
709             }
710         }
711     }
712 }
713
714
715
716 /*****************************************************************************
717  * Specific Subtitle function
718  *****************************************************************************/
719 static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
720 {
721     /*
722      * each line:
723      *  {n1}{n2}Line1|Line2|Line3....
724      * where n1 and n2 are the video frame number...
725      *
726      */
727     char *s;
728
729     char buffer_text[MAX_LINE + 1];
730     unsigned int    i_start;
731     unsigned int    i_stop;
732     unsigned int i;
733     
734     p_subtitle->i_start = 0;
735     p_subtitle->i_stop  = 0;
736     p_subtitle->i_vobsub_location  = 0;
737     p_subtitle->psz_text = NULL;
738
739     for( ;; )
740     {
741         if( ( s = text_get_line( txt ) ) == NULL )
742         {
743             return( VLC_EGENERIC );
744         }
745         i_start = 0;
746         i_stop  = 0;
747
748         memset( buffer_text, '\0', MAX_LINE );
749         if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
750             sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
751         {
752             break;
753         }
754     }
755     /* replace | by \n */
756     for( i = 0; i < strlen( buffer_text ); i++ )
757     {
758         if( buffer_text[i] == '|' )
759         {
760             buffer_text[i] = '\n';
761         }
762     }
763     p_subtitle->i_start = (mtime_t)i_start * (mtime_t)i_microsecperframe;
764     p_subtitle->i_stop  = (mtime_t)i_stop  * (mtime_t)i_microsecperframe;
765     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
766     return( 0 );
767 }
768
769 static int  sub_SubRipRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
770 {
771     /*
772      * n
773      * h1:m1:s1,d1 --> h2:m2:s2,d2
774      * Line1
775      * Line2
776      * ...
777      * [empty line]
778      *
779      */
780     char *s;
781     char buffer_text[ 10 * MAX_LINE];
782     int  i_buffer_text;
783     mtime_t     i_start;
784     mtime_t     i_stop;
785
786     p_subtitle->i_start = 0;
787     p_subtitle->i_stop  = 0;
788     p_subtitle->i_vobsub_location  = 0;
789     p_subtitle->psz_text = NULL;
790
791     for( ;; )
792     {
793         int h1, m1, s1, d1, h2, m2, s2, d2;
794         if( ( s = text_get_line( txt ) ) == NULL )
795         {
796             return( VLC_EGENERIC );
797         }
798         if( sscanf( s,
799                     "%d:%d:%d,%d --> %d:%d:%d,%d",
800                     &h1, &m1, &s1, &d1,
801                     &h2, &m2, &s2, &d2 ) == 8 )
802         {
803             i_start = ( (mtime_t)h1 * 3600*1000 +
804                         (mtime_t)m1 * 60*1000 +
805                         (mtime_t)s1 * 1000 +
806                         (mtime_t)d1 ) * 1000;
807
808             i_stop  = ( (mtime_t)h2 * 3600*1000 +
809                         (mtime_t)m2 * 60*1000 +
810                         (mtime_t)s2 * 1000 +
811                         (mtime_t)d2 ) * 1000;
812
813             /* Now read text until an empty line */
814             for( i_buffer_text = 0;; )
815             {
816                 int i_len;
817                 if( ( s = text_get_line( txt ) ) == NULL )
818                 {
819                     return( VLC_EGENERIC );
820                 }
821
822                 i_len = strlen( s );
823                 if( i_len <= 1 )
824                 {
825                     /* empty line -> end of this subtitle */
826                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
827                     p_subtitle->i_start = i_start;
828                     p_subtitle->i_stop = i_stop;
829                     p_subtitle->psz_text = strdup( buffer_text );
830                     return( 0 );
831                 }
832                 else
833                 {
834                     if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
835                     {
836                         memcpy( buffer_text + i_buffer_text,
837                                 s,
838                                 i_len );
839                         i_buffer_text += i_len;
840
841                         buffer_text[i_buffer_text] = '\n';
842                         i_buffer_text++;
843                     }
844                 }
845             }
846         }
847     }
848 }
849
850
851 static int  sub_SSARead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
852 {
853     char buffer_text[ 10 * MAX_LINE];
854     char *s;
855     mtime_t     i_start;
856     mtime_t     i_stop;
857
858     p_subtitle->i_start = 0;
859     p_subtitle->i_stop  = 0;
860     p_subtitle->i_vobsub_location  = 0;
861     p_subtitle->psz_text = NULL;
862
863     for( ;; )
864     {
865         int h1, m1, s1, c1, h2, m2, s2, c2;
866         int i_dummy;
867
868         if( ( s = text_get_line( txt ) ) == NULL )
869         {
870             return( VLC_EGENERIC );
871         }
872         p_subtitle->psz_text = malloc( strlen( s ) );
873
874         if( sscanf( s,
875                     "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d%[^\r\n]",
876                     &i_dummy,
877                     &h1, &m1, &s1, &c1,
878                     &h2, &m2, &s2, &c2,
879                     buffer_text ) == 10 )
880         {
881             i_start = ( (mtime_t)h1 * 3600*1000 +
882                         (mtime_t)m1 * 60*1000 +
883                         (mtime_t)s1 * 1000 +
884                         (mtime_t)c1 * 10 ) * 1000;
885
886             i_stop  = ( (mtime_t)h2 * 3600*1000 +
887                         (mtime_t)m2 * 60*1000 +
888                         (mtime_t)s2 * 1000 +
889                         (mtime_t)c2 * 10 ) * 1000;
890
891             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
892             if( p_sub->i_sub_type == SUB_TYPE_SSA1 )
893             {
894                 sprintf( p_subtitle->psz_text, ",%d%s", i_dummy, strdup( buffer_text) );
895             }
896             else
897             {
898                 sprintf( p_subtitle->psz_text, ",%d,%s", i_dummy, strdup( buffer_text) );
899             }
900             p_subtitle->i_start = i_start;
901             p_subtitle->i_stop = i_stop;
902             return( 0 );
903         }
904         else
905         {
906             /* All the other stuff we add to the header field */
907             if( p_sub->psz_header != NULL )
908             {
909                 if( !( p_sub->psz_header = realloc( p_sub->psz_header,
910                           strlen( p_sub->psz_header ) + strlen( s ) + 2 ) ) )
911                 {
912                     msg_Err( p_sub, "out of memory");
913                     return VLC_ENOMEM;
914                 }
915                 p_sub->psz_header = strcat( p_sub->psz_header, strdup( s ) );
916                 p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
917             }
918             else
919             {
920                 if( !( p_sub->psz_header = malloc( strlen( s ) + 2 ) ) )
921                 {
922                     msg_Err( p_sub, "out of memory");
923                     return VLC_ENOMEM;
924                 }
925                 p_sub->psz_header = strdup( s );
926                 p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
927             }
928         }
929     }
930 }
931
932 static int  sub_Vplayer( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
933 {
934     /*
935      * each line:
936      *  h:m:s:Line1|Line2|Line3....
937      *  or
938      *  h:m:s Line1|Line2|Line3....
939      * where n1 and n2 are the video frame number...
940      *
941      */
942     char *p;
943     char buffer_text[MAX_LINE + 1];
944     mtime_t    i_start;
945     unsigned int i;
946     
947     p_subtitle->i_start = 0;
948     p_subtitle->i_stop  = 0;
949     p_subtitle->i_vobsub_location  = 0;
950     p_subtitle->psz_text = NULL;
951
952     for( ;; )
953     {
954         int h, m, s;
955         char c;
956
957         if( ( p = text_get_line( txt ) ) == NULL )
958         {
959             return( VLC_EGENERIC );
960         }
961
962         i_start = 0;
963
964         memset( buffer_text, '\0', MAX_LINE );
965         if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
966         {
967             i_start = ( (mtime_t)h * 3600*1000 +
968                         (mtime_t)m * 60*1000 +
969                         (mtime_t)s * 1000 ) * 1000;
970             break;
971         }
972     }
973
974     /* replace | by \n */
975     for( i = 0; i < strlen( buffer_text ); i++ )
976     {
977         if( buffer_text[i] == '|' )
978         {
979             buffer_text[i] = '\n';
980         }
981     }
982     p_subtitle->i_start = i_start;
983
984     p_subtitle->i_stop  = 0;
985     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
986     return( 0 );
987 }
988
989 static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
990 {
991     if( psz_start )
992     {
993         if( local_stristr( psz_start, psz_str ) )
994         {
995             char *s = local_stristr( psz_start, psz_str );
996
997             s += strlen( psz_str );
998
999             return( s );
1000         }
1001     }
1002     for( ;; )
1003     {
1004         char *p;
1005         if( ( p = text_get_line( txt ) ) == NULL )
1006         {
1007             return NULL;
1008         }
1009         if( local_stristr( p, psz_str ) )
1010         {
1011             char *s = local_stristr( p, psz_str );
1012
1013             s += strlen( psz_str );
1014
1015             return(  s);
1016         }
1017     }
1018 }
1019
1020 static int  sub_Sami( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
1021 {
1022     char *p;
1023     int i_start;
1024
1025     int  i_text;
1026     char buffer_text[10*MAX_LINE + 1];
1027
1028     p_subtitle->i_start = 0;
1029     p_subtitle->i_stop  = 0;
1030     p_subtitle->i_vobsub_location  = 0;
1031     p_subtitle->psz_text = NULL;
1032
1033 #define ADDC( c ) \
1034     if( i_text < 10*MAX_LINE )      \
1035     {                               \
1036         buffer_text[i_text++] = c;  \
1037         buffer_text[i_text] = '\0'; \
1038     }
1039
1040     /* search "Start=" */
1041     if( !( p = sub_SamiSearch( txt, NULL, "Start=" ) ) )
1042     {
1043         return VLC_EGENERIC;
1044     }
1045
1046     /* get start value */
1047     i_start = strtol( p, &p, 0 );
1048
1049     /* search <P */
1050     if( !( p = sub_SamiSearch( txt, p, "<P" ) ) )
1051     {
1052         return VLC_EGENERIC;
1053     }
1054     /* search > */
1055     if( !( p = sub_SamiSearch( txt, p, ">" ) ) )
1056     {
1057         return VLC_EGENERIC;
1058     }
1059
1060     i_text = 0;
1061     buffer_text[0] = '\0';
1062     /* now get all txt until  a "Start=" line */
1063     for( ;; )
1064     {
1065         if( *p )
1066         {
1067             if( *p == '<' )
1068             {
1069                 if( !strncasecmp( p, "<br", 3 ) )
1070                 {
1071                     ADDC( '\n' );
1072                 }
1073                 else if( local_stristr( p, "Start=" ) )
1074                 {
1075                     text_previous_line( txt );
1076                     break;
1077                 }
1078                 p = sub_SamiSearch( txt, p, ">" );
1079             }
1080             else if( !strncmp( p, "&nbsp;", 6 ) )
1081             {
1082                 ADDC( ' ' );
1083                 p += 6;
1084             }
1085             else if( *p == '\t' )
1086             {
1087                 ADDC( ' ' );
1088                 p++;
1089             }
1090             else
1091             {
1092                 ADDC( *p );
1093                 p++;
1094             }
1095         }
1096         else
1097         {
1098             p = text_get_line( txt );
1099         }
1100
1101         if( p == NULL )
1102         {
1103             break;
1104         }
1105     }
1106
1107     p_subtitle->i_start = i_start * 1000;
1108     p_subtitle->i_stop  = 0;
1109     p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
1110
1111     return( VLC_SUCCESS );
1112 #undef ADDC
1113 }
1114
1115 static int  sub_VobSubIDX( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
1116 {
1117     /*
1118      * Parse the idx file. Each line:
1119      * timestamp: hh:mm:ss:mss, filepos: loc
1120      * hexint is the hex location of the vobsub in the .sub file
1121      *
1122      */
1123     char *p;
1124     char buffer_text[MAX_LINE + 1];
1125     unsigned int    i_start, i_location;
1126
1127     p_subtitle->i_start = 0;
1128     p_subtitle->i_stop  = 0;
1129     p_subtitle->i_vobsub_location  = 0;
1130     p_subtitle->psz_text = NULL;
1131
1132     for( ;; )
1133     {
1134         unsigned int h, m, s, ms, loc;
1135
1136         if( ( p = text_get_line( txt ) ) == NULL )
1137         {
1138             return( VLC_EGENERIC );
1139         }
1140         i_start = 0;
1141
1142         memset( buffer_text, '\0', MAX_LINE );
1143         if( sscanf( p, "timestamp: %d:%d:%d:%d, filepos: %x%[^\r\n]",
1144                     &h, &m, &s, &ms, &loc, buffer_text ) == 5 )
1145         {
1146             i_start = ( (mtime_t)h * 3600*1000 +
1147                         (mtime_t)m * 60*1000 +
1148                         (mtime_t)s * 1000 +
1149                         (mtime_t)ms ) * 1000;
1150             i_location = loc;
1151             break;
1152         }
1153     }
1154     p_subtitle->i_start = (mtime_t)i_start;
1155     p_subtitle->i_stop  = 0;
1156     p_subtitle->psz_text = NULL;
1157     p_subtitle->i_vobsub_location = i_location;
1158     fprintf( stderr, "time: %x, location: %x\n", i_start, i_location );
1159     return( 0 );
1160 }
1161
1162 static int  DemuxVobSub( subtitle_demux_t *p_demux, block_t *p_bk )
1163 {
1164     uint8_t     *p = p_bk->p_buffer;
1165     uint8_t     *p_end = &p_bk->p_buffer[p_bk->i_buffer];
1166
1167     while( p < p_end )
1168     {
1169         int i_size = ps_pkt_size( p, p_end - p );
1170         block_t *p_pkt;
1171         int      i_id;
1172         int      i_spu;
1173
1174         if( i_size <= 0 )
1175         {
1176             break;
1177         }
1178         if( p[0] != 0 || p[1] != 0 || p[2] != 0x01 )
1179         {
1180             msg_Warn( p_demux, "invalid PES" );
1181             break;
1182         }
1183
1184         if( p[3] != 0xbd )
1185         {
1186             msg_Dbg( p_demux, "we don't need these ps packets (id=0x1%2.2x)", p[3] );
1187             p += i_size;
1188             continue;
1189         }
1190
1191         /* Create a block */
1192         p_pkt = block_New( p_demux, i_size );
1193         memcpy( p_pkt->p_buffer, p, i_size);
1194         p += i_size;
1195
1196         i_id = ps_pkt_id( p_pkt );
1197         if( (i_id&0xffe0) != 0xbd20 ||
1198             ps_pkt_parse_pes( p_pkt, 1 ) )
1199         {
1200             block_Release( p_pkt );
1201             continue;
1202         }
1203         i_spu = i_id&0x1f;
1204         msg_Dbg( p_demux, "SPU track %d size %d", i_spu, i_size );
1205
1206         /* FIXME i_spu == determines which of the spu tracks we will show. */
1207         if( p_demux->p_es && i_spu == 0 )
1208         {
1209             p_pkt->i_pts = p_bk->i_pts;
1210             p_pkt->i_dts = 0;
1211             es_out_Send( p_demux->p_input->p_es_out, p_demux->p_es, p_pkt );
1212
1213             p_bk->i_pts = 0;    /* only first packet has a pts */
1214         }
1215         else
1216         {
1217             block_Release( p_pkt );
1218             continue;
1219         }
1220     }
1221
1222     return VLC_SUCCESS;
1223 }