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