]> git.sesse.net Git - vlc/blob - modules/demux/subtitle.c
All: string review (refs: #438)
[vlc] / modules / demux / subtitle.c
1 /*****************************************************************************
2  * subtitle.c: Demux for subtitle text files.
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29
30 #include <errno.h>
31 #ifdef HAVE_SYS_TYPES_H
32 #   include <sys/types.h>
33 #endif
34 #include <ctype.h>
35
36 #include <vlc/vlc.h>
37 #include <vlc/input.h>
38 #include "vlc_video.h"
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43 static int  Open ( vlc_object_t *p_this );
44 static void Close( vlc_object_t *p_this );
45
46 #define SUB_DELAY_LONGTEXT \
47     "Apply a delay to all subtitles (in 1/10s, eg 100 means 10s)."
48 #define SUB_FPS_LONGTEXT \
49     "Override the normal frames per second settings. " \
50     "This will only work with MicroDVD and SubRIP (SRT) subtitles."
51 #define SUB_TYPE_LONGTEXT \
52     "Force the subtiles format. Valid values are : \"microdvd\", \"subrip\"," \
53     "\"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\" " \
54     "\"sami\", \"dvdsubtitle\" and \"auto\" (meaning autodetection, this " \
55     "should always work)."
56 static char *ppsz_sub_type[] =
57 {
58     "auto", "microdvd", "subrip", "subviewer", "ssa1",
59     "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle"
60 };
61
62 vlc_module_begin();
63     set_shortname( _("Subtitles"));
64     set_description( _("Text subtitles parser") );
65     set_capability( "demux2", 0 );
66     set_category( CAT_INPUT );
67     set_subcategory( SUBCAT_INPUT_DEMUX );
68     add_float( "sub-fps", 0.0, NULL,
69                N_("Frames per second"),
70                SUB_FPS_LONGTEXT, VLC_TRUE );
71     add_integer( "sub-delay", 0, NULL,
72                N_("Subtitles delay"),
73                SUB_DELAY_LONGTEXT, VLC_TRUE );
74     add_string( "sub-type", "auto", NULL, N_("Subtitles format"),
75                 SUB_TYPE_LONGTEXT, VLC_TRUE );
76         change_string_list( ppsz_sub_type, 0, 0 );
77     set_callbacks( Open, Close );
78
79     add_shortcut( "subtitle" );
80 vlc_module_end();
81
82 /*****************************************************************************
83  * Prototypes:
84  *****************************************************************************/
85 enum
86 {
87     SUB_TYPE_UNKNOWN = -1,
88     SUB_TYPE_MICRODVD,
89     SUB_TYPE_SUBRIP,
90     SUB_TYPE_SSA1,
91     SUB_TYPE_SSA2_4,
92     SUB_TYPE_ASS,
93     SUB_TYPE_VPLAYER,
94     SUB_TYPE_SAMI,
95     SUB_TYPE_SUBVIEWER,
96     SUB_TYPE_DVDSUBTITLE
97 };
98
99 typedef struct
100 {
101     int     i_line_count;
102     int     i_line;
103     char    **line;
104 } text_t;
105 static int  TextLoad( text_t *, stream_t *s );
106 static void TextUnload( text_t * );
107
108 typedef struct
109 {
110     int64_t i_start;
111     int64_t i_stop;
112
113     char    *psz_text;
114 } subtitle_t;
115
116
117 struct demux_sys_t
118 {
119     int         i_type;
120     text_t      txt;
121     es_out_id_t *es;
122
123     int64_t     i_next_demux_date;
124
125     int64_t     i_microsecperframe;
126     int64_t     i_original_mspf;
127
128     char        *psz_header;
129     int         i_subtitle;
130     int         i_subtitles;
131     subtitle_t  *subtitle;
132
133     int64_t     i_length;
134 };
135
136 static int  ParseMicroDvd   ( demux_t *, subtitle_t * );
137 static int  ParseSubRip     ( demux_t *, subtitle_t * );
138 static int  ParseSubViewer  ( demux_t *, subtitle_t * );
139 static int  ParseSSA        ( demux_t *, subtitle_t * );
140 static int  ParseVplayer    ( demux_t *, subtitle_t * );
141 static int  ParseSami       ( demux_t *, subtitle_t * );
142 static int  ParseDVDSubtitle( demux_t *, subtitle_t * );
143
144 static struct
145 {
146     char *psz_type_name;
147     int  i_type;
148     char *psz_name;
149     int  (*pf_read)( demux_t *, subtitle_t* );
150 } sub_read_subtitle_function [] =
151 {
152     { "microdvd",   SUB_TYPE_MICRODVD,    "MicroDVD",    ParseMicroDvd },
153     { "subrip",     SUB_TYPE_SUBRIP,      "SubRIP",      ParseSubRip },
154     { "subviewer",  SUB_TYPE_SUBVIEWER,   "SubViewer",   ParseSubViewer },
155     { "ssa1",       SUB_TYPE_SSA1,        "SSA-1",       ParseSSA },
156     { "ssa2-4",     SUB_TYPE_SSA2_4,      "SSA-2/3/4",   ParseSSA },
157     { "ass",        SUB_TYPE_ASS,         "SSA/ASS",     ParseSSA },
158     { "vplayer",    SUB_TYPE_VPLAYER,     "VPlayer",     ParseVplayer },
159     { "sami",       SUB_TYPE_SAMI,        "SAMI",        ParseSami },
160     { "dvdsubtitle",SUB_TYPE_DVDSUBTITLE, "DVDSubtitle", ParseDVDSubtitle },
161     { NULL,         SUB_TYPE_UNKNOWN,     "Unknown",     NULL }
162 };
163
164 static int Demux( demux_t * );
165 static int Control( demux_t *, int, va_list );
166
167 /*static void Fix( demux_t * );*/
168
169 /*****************************************************************************
170  * Module initializer
171  *****************************************************************************/
172 static int Open ( vlc_object_t *p_this )
173 {
174     demux_t     *p_demux = (demux_t*)p_this;
175     demux_sys_t *p_sys;
176     es_format_t fmt;
177     float f_fps;
178     char *psz_type;
179     int  (*pf_read)( demux_t *, subtitle_t* );
180     int i, i_max;
181
182     if( strcmp( p_demux->psz_demux, "subtitle" ) )
183     {
184         msg_Dbg( p_demux, "subtitle demux discarded" );
185         return VLC_EGENERIC;
186     }
187
188     p_demux->pf_demux = Demux;
189     p_demux->pf_control = Control;
190     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
191     p_sys->psz_header = NULL;
192     p_sys->i_subtitle = 0;
193     p_sys->i_subtitles= 0;
194     p_sys->subtitle   = NULL;
195
196
197     /* Get the FPS */
198     f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
199     if( f_fps >= 1.0 )
200     {
201         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
202     }
203     else
204     {
205         p_sys->i_microsecperframe = 0;
206     }
207
208     f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" );
209     if( f_fps >= 1.0 )
210     {
211         p_sys->i_original_mspf = (int64_t)( (float)1000000 / f_fps );
212     }
213     else
214     {
215         p_sys->i_original_mspf = 0;
216     }
217
218     /* Get or probe the type */
219     p_sys->i_type = SUB_TYPE_UNKNOWN;
220     psz_type = var_CreateGetString( p_demux, "sub-type" );
221     if( *psz_type )
222     {
223         int i;
224
225         for( i = 0; ; i++ )
226         {
227             if( sub_read_subtitle_function[i].psz_type_name == NULL )
228                 break;
229
230             if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
231                          psz_type ) )
232             {
233                 p_sys->i_type = sub_read_subtitle_function[i].i_type;
234                 break;
235             }
236         }
237     }
238     free( psz_type );
239
240     /* Probe if unknown type */
241     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
242     {
243         int     i_try;
244         char    *s = NULL;
245
246         msg_Dbg( p_demux, "autodetecting subtitle format" );
247         for( i_try = 0; i_try < 256; i_try++ )
248         {
249             int i_dummy;
250
251             if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
252                 break;
253
254             if( strcasestr( s, "<SAMI>" ) )
255             {
256                 p_sys->i_type = SUB_TYPE_SAMI;
257                 break;
258             }
259             else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
260                      sscanf( s, "{%d}{}", &i_dummy ) == 1)
261             {
262                 p_sys->i_type = SUB_TYPE_MICRODVD;
263                 break;
264             }
265             else if( sscanf( s,
266                              "%d:%d:%d,%d --> %d:%d:%d,%d",
267                              &i_dummy,&i_dummy,&i_dummy,&i_dummy,
268                              &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
269             {
270                 p_sys->i_type = SUB_TYPE_SUBRIP;
271                 break;
272             }
273             else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
274             {
275                 p_sys->i_type = SUB_TYPE_SSA1;
276                 break;
277             }
278             else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
279             {
280                 p_sys->i_type = SUB_TYPE_ASS;
281                 break;
282             }
283             else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
284             {
285                 p_sys->i_type = SUB_TYPE_SSA2_4;
286                 break;
287             }
288             else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
289             {
290                 p_sys->i_type = SUB_TYPE_SSA2_4;
291                 break;
292             }
293             else if( !strncasecmp( s, "Dialogue:", 9  ) )
294             {
295                 p_sys->i_type = SUB_TYPE_ASS;
296                 break;
297             }
298             else if( strcasestr( s, "[INFORMATION]" ) )
299             {
300                 p_sys->i_type = SUB_TYPE_SUBVIEWER; /* I hope this will work */
301                 break;
302             }
303             else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
304                      sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
305             {
306                 p_sys->i_type = SUB_TYPE_VPLAYER;
307                 break;
308             }
309             else if( sscanf( s, "{T %d:%d:%d:%d", &i_dummy, &i_dummy,
310                              &i_dummy, &i_dummy ) == 4 )
311             {
312                 p_sys->i_type = SUB_TYPE_DVDSUBTITLE;
313                 break;
314             }
315
316             free( s );
317             s = NULL;
318         }
319
320         if( s ) free( s );
321
322         /* It will nearly always work even for non seekable stream thanks the
323          * caching system, and if it fails we loose just a few sub */
324         if( stream_Seek( p_demux->s, 0 ) )
325         {
326             msg_Warn( p_demux, "failed to rewind" );
327         }
328     }
329     if( p_sys->i_type == SUB_TYPE_UNKNOWN )
330     {
331         msg_Err( p_demux, "failed to recognize subtitle type" );
332         free( p_sys );
333         return VLC_EGENERIC;
334     }
335
336     for( i = 0; ; i++ )
337     {
338         if( sub_read_subtitle_function[i].i_type == p_sys->i_type )
339         {
340             msg_Dbg( p_demux, "detected %s format",
341                      sub_read_subtitle_function[i].psz_name );
342             pf_read = sub_read_subtitle_function[i].pf_read;
343             break;
344         }
345     }
346
347     msg_Dbg( p_demux, "loading all subtitles..." );
348
349     /* Load the whole file */
350     TextLoad( &p_sys->txt, p_demux->s );
351
352     /* Parse it */
353     for( i_max = 0;; )
354     {
355         if( p_sys->i_subtitles >= i_max )
356         {
357             i_max += 500;
358             if( !( p_sys->subtitle = realloc( p_sys->subtitle,
359                                               sizeof(subtitle_t) * i_max ) ) )
360             {
361                 msg_Err( p_demux, "out of memory");
362                 if( p_sys->subtitle != NULL )
363                     free( p_sys->subtitle );
364                 TextUnload( &p_sys->txt );
365                 free( p_sys );
366                 return VLC_ENOMEM;
367             }
368         }
369
370         if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles] ) )
371             break;
372
373         p_sys->i_subtitles++;
374     }
375     /* Unload */
376     TextUnload( &p_sys->txt );
377
378     msg_Dbg(p_demux, "loaded %d subtitles", p_sys->i_subtitles );
379
380     /* Fix subtitle (order and time) *** */
381     p_sys->i_subtitle = 0;
382     p_sys->i_length = 0;
383     if( p_sys->i_subtitles > 0 )
384     {
385         p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_stop;
386         /* +1 to avoid 0 */
387         if( p_sys->i_length <= 0 )
388             p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_start+1;
389     }
390
391     /* *** add subtitle ES *** */
392     if( p_sys->i_type == SUB_TYPE_SSA1 ||
393              p_sys->i_type == SUB_TYPE_SSA2_4 ||
394              p_sys->i_type == SUB_TYPE_ASS )
395     {
396         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
397     }
398     else
399     {
400         es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
401     }
402     if( p_sys->psz_header != NULL )
403     {
404         fmt.i_extra = strlen( p_sys->psz_header ) + 1;
405         fmt.p_extra = strdup( p_sys->psz_header );
406     }
407     p_sys->es = es_out_Add( p_demux->out, &fmt );
408
409     return VLC_SUCCESS;
410 }
411
412 /*****************************************************************************
413  * Close: Close subtitle demux
414  *****************************************************************************/
415 static void Close( vlc_object_t *p_this )
416 {
417     demux_t *p_demux = (demux_t*)p_this;
418     demux_sys_t *p_sys = p_demux->p_sys;
419     int i;
420
421     for( i = 0; i < p_sys->i_subtitles; i++ )
422     {
423         if( p_sys->subtitle[i].psz_text )
424             free( p_sys->subtitle[i].psz_text );
425     }
426     if( p_sys->subtitle )
427         free( p_sys->subtitle );
428
429     free( p_sys );
430 }
431
432 /*****************************************************************************
433  * Control:
434  *****************************************************************************/
435 static int Control( demux_t *p_demux, int i_query, va_list args )
436 {
437     demux_sys_t *p_sys = p_demux->p_sys;
438     int64_t *pi64, i64;
439     double *pf, f;
440
441     switch( i_query )
442     {
443         case DEMUX_GET_LENGTH:
444             pi64 = (int64_t*)va_arg( args, int64_t * );
445             *pi64 = p_sys->i_length;
446             return VLC_SUCCESS;
447
448         case DEMUX_GET_TIME:
449             pi64 = (int64_t*)va_arg( args, int64_t * );
450             if( p_sys->i_subtitle < p_sys->i_subtitles )
451             {
452                 *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
453                 return VLC_SUCCESS;
454             }
455             return VLC_EGENERIC;
456
457         case DEMUX_SET_TIME:
458             i64 = (int64_t)va_arg( args, int64_t );
459             p_sys->i_subtitle = 0;
460             while( p_sys->i_subtitle < p_sys->i_subtitles &&
461                    p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
462             {
463                 p_sys->i_subtitle++;
464             }
465
466             if( p_sys->i_subtitle >= p_sys->i_subtitles )
467                 return VLC_EGENERIC;
468             return VLC_SUCCESS;
469
470         case DEMUX_GET_POSITION:
471             pf = (double*)va_arg( args, double * );
472             if( p_sys->i_subtitle >= p_sys->i_subtitles )
473             {
474                 *pf = 1.0;
475             }
476             else if( p_sys->i_subtitles > 0 )
477             {
478                 *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
479                       (double)p_sys->i_length;
480             }
481             else
482             {
483                 *pf = 0.0;
484             }
485             return VLC_SUCCESS;
486
487         case DEMUX_SET_POSITION:
488             f = (double)va_arg( args, double );
489             i64 = f * p_sys->i_length;
490
491             p_sys->i_subtitle = 0;
492             while( p_sys->i_subtitle < p_sys->i_subtitles &&
493                    p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
494             {
495                 p_sys->i_subtitle++;
496             }
497             if( p_sys->i_subtitle >= p_sys->i_subtitles )
498                 return VLC_EGENERIC;
499             return VLC_SUCCESS;
500
501         case DEMUX_SET_NEXT_DEMUX_TIME:
502             p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
503             return VLC_SUCCESS;
504
505         case DEMUX_GET_FPS:
506         case DEMUX_GET_META:
507         case DEMUX_GET_TITLE_INFO:
508             return VLC_EGENERIC;
509
510         default:
511             msg_Err( p_demux, "unknown query in subtitle control" );
512             return VLC_EGENERIC;
513     }
514 }
515
516 /*****************************************************************************
517  * Demux: Send subtitle to decoder
518  *****************************************************************************/
519 static int Demux( demux_t *p_demux )
520 {
521     demux_sys_t *p_sys = p_demux->p_sys;
522     int64_t i_maxdate;
523
524     if( p_sys->i_subtitle >= p_sys->i_subtitles )
525         return 0;
526
527     i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
528     if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
529     {
530         /* Should not happen */
531         i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
532     }
533
534     while( p_sys->i_subtitle < p_sys->i_subtitles &&
535            p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
536     {
537         block_t *p_block;
538         int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1;
539
540         if( i_len <= 1 )
541         {
542             /* empty subtitle */
543             p_sys->i_subtitle++;
544             continue;
545         }
546
547         if( ( p_block = block_New( p_demux, i_len ) ) == NULL )
548         {
549             p_sys->i_subtitle++;
550             continue;
551         }
552
553         if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 )
554         {
555             p_sys->i_subtitle++;
556             continue;
557         }
558
559         p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start;
560         p_block->i_dts = p_block->i_pts;
561         if( p_sys->subtitle[p_sys->i_subtitle].i_stop > 0 )
562         {
563             p_block->i_length =
564                 p_sys->subtitle[p_sys->i_subtitle].i_stop - p_block->i_pts;
565         }
566
567         memcpy( p_block->p_buffer,
568                 p_sys->subtitle[p_sys->i_subtitle].psz_text, i_len );
569         if( p_block->i_pts > 0 )
570         {
571             es_out_Send( p_demux->out, p_sys->es, p_block );
572         }
573         else
574         {
575             block_Release( p_block );
576         }
577         p_sys->i_subtitle++;
578     }
579
580     /* */
581     p_sys->i_next_demux_date = 0;
582
583     return 1;
584 }
585
586 /*****************************************************************************
587  * Fix: fix time stamp and order of subtitle
588  *****************************************************************************/
589 #ifdef USE_THIS_UNUSED_PIECE_OF_CODE
590 static void Fix( demux_t *p_demux )
591 {
592     demux_sys_t *p_sys = p_demux->p_sys;
593     vlc_bool_t b_done;
594     int     i_index;
595
596     /* *** fix order (to be sure...) *** */
597     /* We suppose that there are near in order and this durty bubble sort
598      * wont take too much time
599      */
600     do
601     {
602         b_done = VLC_TRUE;
603         for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
604         {
605             if( p_sys->subtitle[i_index].i_start <
606                     p_sys->subtitle[i_index - 1].i_start )
607             {
608                 subtitle_t sub_xch;
609                 memcpy( &sub_xch,
610                         p_sys->subtitle + i_index - 1,
611                         sizeof( subtitle_t ) );
612                 memcpy( p_sys->subtitle + i_index - 1,
613                         p_sys->subtitle + i_index,
614                         sizeof( subtitle_t ) );
615                 memcpy( p_sys->subtitle + i_index,
616                         &sub_xch,
617                         sizeof( subtitle_t ) );
618                 b_done = VLC_FALSE;
619             }
620         }
621     } while( !b_done );
622 }
623 #endif
624
625 static int TextLoad( text_t *txt, stream_t *s )
626 {
627     int   i_line_max;
628
629     /* init txt */
630     i_line_max          = 500;
631     txt->i_line_count   = 0;
632     txt->i_line         = 0;
633     txt->line           = calloc( i_line_max, sizeof( char * ) );
634
635     /* load the complete file */
636     for( ;; )
637     {
638         char *psz = stream_ReadLine( s );
639
640         if( psz == NULL )
641             break;
642
643         txt->line[txt->i_line_count++] = psz;
644         if( txt->i_line_count >= i_line_max )
645         {
646             i_line_max += 100;
647             txt->line = realloc( txt->line, i_line_max * sizeof( char * ) );
648         }
649     }
650
651     if( txt->i_line_count <= 0 )
652     {
653         free( txt->line );
654         return VLC_EGENERIC;
655     }
656
657     return VLC_SUCCESS;
658 }
659 static void TextUnload( text_t *txt )
660 {
661     int i;
662
663     for( i = 0; i < txt->i_line_count; i++ )
664     {
665         free( txt->line[i] );
666     }
667     free( txt->line );
668     txt->i_line       = 0;
669     txt->i_line_count = 0;
670 }
671
672 static char *TextGetLine( text_t *txt )
673 {
674     if( txt->i_line >= txt->i_line_count )
675         return( NULL );
676
677     return txt->line[txt->i_line++];
678 }
679 static void TextPreviousLine( text_t *txt )
680 {
681     if( txt->i_line > 0 )
682         txt->i_line--;
683 }
684
685 /*****************************************************************************
686  * Specific Subtitle function
687  *****************************************************************************/
688 #define MAX_LINE 8192
689 static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
690 {
691     demux_sys_t *p_sys = p_demux->p_sys;
692     text_t      *txt = &p_sys->txt;
693     /*
694      * each line:
695      *  {n1}{n2}Line1|Line2|Line3....
696      * where n1 and n2 are the video frame number...
697      * {n2} can also be {}
698      */
699     char *s;
700
701     char buffer_text[MAX_LINE + 1];
702     int    i_start;
703     int    i_stop;
704     unsigned int i;
705
706     int i_microsecperframe = 40000; /* default to 25 fps */
707     if( p_sys->i_microsecperframe > 0 )
708         i_microsecperframe = p_sys->i_microsecperframe;
709
710     p_subtitle->i_start = 0;
711     p_subtitle->i_stop  = 0;
712     p_subtitle->psz_text = NULL;
713
714     for( ;; )
715     {
716         if( ( s = TextGetLine( txt ) ) == NULL )
717         {
718             return( VLC_EGENERIC );
719         }
720         i_start = 0;
721         i_stop  = 0;
722
723         memset( buffer_text, '\0', MAX_LINE );
724         if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
725             sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
726         {
727             break;
728         }
729     }
730     /* replace | by \n */
731     for( i = 0; i < strlen( buffer_text ); i++ )
732     {
733         if( buffer_text[i] == '|' )
734         {
735             buffer_text[i] = '\n';
736         }
737     }
738
739     p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
740     p_subtitle->i_stop  = (int64_t)i_stop  * i_microsecperframe;
741     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
742     return( 0 );
743 }
744
745 static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle )
746 {
747     demux_sys_t *p_sys = p_demux->p_sys;
748     text_t      *txt = &p_sys->txt;
749
750     /*
751      * n
752      * h1:m1:s1,d1 --> h2:m2:s2,d2
753      * Line1
754      * Line2
755      * ...
756      * [empty line]
757      *
758      */
759     char *s;
760     char buffer_text[ 10 * MAX_LINE];
761     int  i_buffer_text;
762     int64_t     i_start;
763     int64_t     i_stop;
764
765     p_subtitle->i_start = 0;
766     p_subtitle->i_stop  = 0;
767     p_subtitle->psz_text = NULL;
768
769     for( ;; )
770     {
771         int h1, m1, s1, d1, h2, m2, s2, d2;
772         if( ( s = TextGetLine( txt ) ) == NULL )
773         {
774             return( VLC_EGENERIC );
775         }
776         if( sscanf( s,
777                     "%d:%d:%d,%d --> %d:%d:%d,%d",
778                     &h1, &m1, &s1, &d1,
779                     &h2, &m2, &s2, &d2 ) == 8 )
780         {
781             i_start = ( (int64_t)h1 * 3600*1000 +
782                         (int64_t)m1 * 60*1000 +
783                         (int64_t)s1 * 1000 +
784                         (int64_t)d1 ) * 1000;
785
786             i_stop  = ( (int64_t)h2 * 3600*1000 +
787                         (int64_t)m2 * 60*1000 +
788                         (int64_t)s2 * 1000 +
789                         (int64_t)d2 ) * 1000;
790
791             /* Now read text until an empty line */
792             for( i_buffer_text = 0;; )
793             {
794                 int i_len;
795                 if( ( s = TextGetLine( txt ) ) == NULL )
796                 {
797                     return( VLC_EGENERIC );
798                 }
799
800                 i_len = strlen( s );
801                 if( i_len <= 0 )
802                 {
803                     /* empty line -> end of this subtitle */
804                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
805                     p_subtitle->i_start = i_start;
806                     p_subtitle->i_stop = i_stop;
807                     p_subtitle->psz_text = strdup( buffer_text );
808                     /* If framerate is available, use sub-fps */
809                     if( p_sys->i_microsecperframe != 0 &&
810                         p_sys->i_original_mspf != 0)
811                     {
812                         p_subtitle->i_start = (int64_t)i_start *
813                                               p_sys->i_microsecperframe/
814                                               p_sys->i_original_mspf;
815                         p_subtitle->i_stop  = (int64_t)i_stop  *
816                                               p_sys->i_microsecperframe /
817                                               p_sys->i_original_mspf;
818                     }
819                     return 0;
820                 }
821                 else
822                 {
823                     if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
824                     {
825                         memcpy( buffer_text + i_buffer_text,
826                                 s,
827                                 i_len );
828                         i_buffer_text += i_len;
829
830                         buffer_text[i_buffer_text] = '\n';
831                         i_buffer_text++;
832                     }
833                 }
834             }
835         }
836     }
837 }
838
839 static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle )
840 {
841     demux_sys_t *p_sys = p_demux->p_sys;
842     text_t      *txt = &p_sys->txt;
843
844     /*
845      * h1:m1:s1.d1,h2:m2:s2.d2
846      * Line1[br]Line2
847      * Line3
848      * ...
849      * [empty line]
850      * ( works with subviewer and subviewer v2 )
851      */
852     char *s;
853     char buffer_text[ 10 * MAX_LINE];
854     int  i_buffer_text;
855     int64_t     i_start;
856     int64_t     i_stop;
857
858     p_subtitle->i_start = 0;
859     p_subtitle->i_stop  = 0;
860     p_subtitle->psz_text = NULL;
861
862     for( ;; )
863     {
864         int h1, m1, s1, d1, h2, m2, s2, d2;
865         if( ( s = TextGetLine( txt ) ) == NULL )
866         {
867             return( VLC_EGENERIC );
868         }
869         if( sscanf( s,
870                     "%d:%d:%d.%d,%d:%d:%d.%d",
871                     &h1, &m1, &s1, &d1,
872                     &h2, &m2, &s2, &d2 ) == 8 )
873         {
874             i_start = ( (int64_t)h1 * 3600*1000 +
875                         (int64_t)m1 * 60*1000 +
876                         (int64_t)s1 * 1000 +
877                         (int64_t)d1 ) * 1000;
878
879             i_stop  = ( (int64_t)h2 * 3600*1000 +
880                         (int64_t)m2 * 60*1000 +
881                         (int64_t)s2 * 1000 +
882                         (int64_t)d2 ) * 1000;
883
884             /* Now read text until an empty line */
885             for( i_buffer_text = 0;; )
886             {
887                 int i_len, i;
888                 if( ( s = TextGetLine( txt ) ) == NULL )
889                 {
890                     return( VLC_EGENERIC );
891                 }
892
893                 i_len = strlen( s );
894                 if( i_len <= 0 )
895                 {
896                     /* empty line -> end of this subtitle */
897                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
898                     p_subtitle->i_start = i_start;
899                     p_subtitle->i_stop = i_stop;
900
901                     /* replace [br] by \n */
902                     for( i = 0; i < i_buffer_text - 3; i++ )
903                     {
904                         if( buffer_text[i] == '[' && buffer_text[i+1] == 'b' &&
905                             buffer_text[i+2] == 'r' && buffer_text[i+3] == ']' )
906                         {
907                             char *temp = buffer_text + i + 1;
908                             buffer_text[i] = '\n';
909                             memmove( temp, temp+3, strlen( temp ) -3 );
910                             temp[strlen( temp )-3] = '\0';
911                         }
912                     }
913                     p_subtitle->psz_text = strdup( buffer_text );
914                     return( 0 );
915                 }
916                 else
917                 {
918                     if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
919                     {
920                         memcpy( buffer_text + i_buffer_text,
921                                 s,
922                                 i_len );
923                         i_buffer_text += i_len;
924
925                         buffer_text[i_buffer_text] = '\n';
926                         i_buffer_text++;
927                     }
928                 }
929             }
930         }
931     }
932 }
933
934
935 static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
936 {
937     demux_sys_t *p_sys = p_demux->p_sys;
938     text_t      *txt = &p_sys->txt;
939
940     char buffer_text[ 10 * MAX_LINE];
941     char buffer_text2[ 10 * MAX_LINE];
942     char *s;
943     int64_t     i_start;
944     int64_t     i_stop;
945
946     p_subtitle->i_start = 0;
947     p_subtitle->i_stop  = 0;
948     p_subtitle->psz_text = NULL;
949
950     for( ;; )
951     {
952         int h1, m1, s1, c1, h2, m2, s2, c2;
953
954         if( ( s = TextGetLine( txt ) ) == NULL )
955         {
956             return( VLC_EGENERIC );
957         }
958         p_subtitle->psz_text = malloc( strlen( s ) );
959
960         /* We expect (SSA2-4):
961          * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
962          * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
963          *
964          * SSA-1 is similar but only has 8 commas up untill the subtitle text. Probably the Effect field is no present, but not 100 % sure.
965          */
966
967         /* For ASS:
968          * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
969          * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
970          */
971         if( sscanf( s,
972                     "Dialogue: %[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
973                     buffer_text2,
974                     &h1, &m1, &s1, &c1,
975                     &h2, &m2, &s2, &c2,
976                     buffer_text ) == 10 )
977         {
978             i_start = ( (int64_t)h1 * 3600*1000 +
979                         (int64_t)m1 * 60*1000 +
980                         (int64_t)s1 * 1000 +
981                         (int64_t)c1 * 10 ) * 1000;
982
983             i_stop  = ( (int64_t)h2 * 3600*1000 +
984                         (int64_t)m2 * 60*1000 +
985                         (int64_t)s2 * 1000 +
986                         (int64_t)c2 * 10 ) * 1000;
987
988             /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
989             /* (Layer comes from ASS specs ... it's empty for SSA.) */
990             if( p_sys->i_type == SUB_TYPE_SSA1 )
991             {
992                 sprintf( p_subtitle->psz_text,
993                          ",%s", strdup( buffer_text) ); /* SSA1 has only 8 commas before the text starts, not 9 */
994             }
995             else
996             {
997                 sprintf( p_subtitle->psz_text,
998                          ",,%s", strdup( buffer_text) ); /* ReadOrder, Layer, %s(rest of fields) */
999             }
1000             p_subtitle->i_start = i_start;
1001             p_subtitle->i_stop = i_stop;
1002             return 0;
1003         }
1004         else
1005         {
1006             /* All the other stuff we add to the header field */
1007             if( p_sys->psz_header != NULL )
1008             {
1009                 if( !( p_sys->psz_header = realloc( p_sys->psz_header,
1010                           strlen( p_sys->psz_header ) + 1 + strlen( s ) + 2 ) ) )
1011                 {
1012                     msg_Err( p_demux, "out of memory");
1013                     return VLC_ENOMEM;
1014                 }
1015                 p_sys->psz_header = strcat( p_sys->psz_header,  s );
1016                 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1017             }
1018             else
1019             {
1020                 if( !( p_sys->psz_header = malloc( strlen( s ) + 2 ) ) )
1021                 {
1022                     msg_Err( p_demux, "out of memory");
1023                     return VLC_ENOMEM;
1024                 }
1025                 p_sys->psz_header = s;
1026                 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1027             }
1028         }
1029     }
1030 }
1031
1032 static int  ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle )
1033 {
1034     demux_sys_t *p_sys = p_demux->p_sys;
1035     text_t      *txt = &p_sys->txt;
1036
1037     /*
1038      * each line:
1039      *  h:m:s:Line1|Line2|Line3....
1040      *  or
1041      *  h:m:s Line1|Line2|Line3....
1042      *
1043      */
1044     char *p;
1045     char buffer_text[MAX_LINE + 1];
1046     int64_t    i_start;
1047     unsigned int i;
1048
1049     p_subtitle->i_start = 0;
1050     p_subtitle->i_stop  = 0;
1051     p_subtitle->psz_text = NULL;
1052
1053     for( ;; )
1054     {
1055         int h, m, s;
1056         char c;
1057
1058         if( ( p = TextGetLine( txt ) ) == NULL )
1059         {
1060             return( VLC_EGENERIC );
1061         }
1062
1063         i_start = 0;
1064
1065         memset( buffer_text, '\0', MAX_LINE );
1066         if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
1067         {
1068             i_start = ( (int64_t)h * 3600*1000 +
1069                         (int64_t)m * 60*1000 +
1070                         (int64_t)s * 1000 ) * 1000;
1071             break;
1072         }
1073     }
1074
1075     /* replace | by \n */
1076     for( i = 0; i < strlen( buffer_text ); i++ )
1077     {
1078         if( buffer_text[i] == '|' )
1079         {
1080             buffer_text[i] = '\n';
1081         }
1082     }
1083     p_subtitle->i_start = i_start;
1084
1085     p_subtitle->i_stop  = 0;
1086     p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
1087     return( 0 );
1088 }
1089
1090 static char *ParseSamiSearch( text_t *txt, char *psz_start, char *psz_str )
1091 {
1092     if( psz_start )
1093     {
1094         if( strcasestr( psz_start, psz_str ) )
1095         {
1096             char *s = strcasestr( psz_start, psz_str );
1097
1098             s += strlen( psz_str );
1099
1100             return( s );
1101         }
1102     }
1103     for( ;; )
1104     {
1105         char *p;
1106         if( ( p = TextGetLine( txt ) ) == NULL )
1107         {
1108             return NULL;
1109         }
1110         if( strcasestr( p, psz_str ) )
1111         {
1112             char *s = strcasestr( p, psz_str );
1113
1114             s += strlen( psz_str );
1115
1116             return(  s);
1117         }
1118     }
1119 }
1120
1121 static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle )
1122 {
1123     demux_sys_t *p_sys = p_demux->p_sys;
1124     text_t      *txt = &p_sys->txt;
1125
1126     char *p;
1127     int64_t i_start;
1128
1129     int  i_text;
1130     char buffer_text[10*MAX_LINE + 1];
1131
1132     p_subtitle->i_start = 0;
1133     p_subtitle->i_stop  = 0;
1134     p_subtitle->psz_text = NULL;
1135
1136 #define ADDC( c ) \
1137     if( i_text < 10*MAX_LINE )      \
1138     {                               \
1139         buffer_text[i_text++] = c;  \
1140         buffer_text[i_text] = '\0'; \
1141     }
1142
1143     /* search "Start=" */
1144     if( !( p = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1145     {
1146         return VLC_EGENERIC;
1147     }
1148
1149     /* get start value */
1150     i_start = strtol( p, &p, 0 );
1151
1152     /* search <P */
1153     if( !( p = ParseSamiSearch( txt, p, "<P" ) ) )
1154     {
1155         return VLC_EGENERIC;
1156     }
1157     /* search > */
1158     if( !( p = ParseSamiSearch( txt, p, ">" ) ) )
1159     {
1160         return VLC_EGENERIC;
1161     }
1162
1163     i_text = 0;
1164     buffer_text[0] = '\0';
1165     /* now get all txt until  a "Start=" line */
1166     for( ;; )
1167     {
1168         if( *p )
1169         {
1170             if( *p == '<' )
1171             {
1172                 if( !strncasecmp( p, "<br", 3 ) )
1173                 {
1174                     ADDC( '\n' );
1175                 }
1176                 else if( strcasestr( p, "Start=" ) )
1177                 {
1178                     TextPreviousLine( txt );
1179                     break;
1180                 }
1181                 p = ParseSamiSearch( txt, p, ">" );
1182             }
1183             else if( !strncmp( p, "&nbsp;", 6 ) )
1184             {
1185                 ADDC( ' ' );
1186                 p += 6;
1187             }
1188             else if( *p == '\t' )
1189             {
1190                 ADDC( ' ' );
1191                 p++;
1192             }
1193             else
1194             {
1195                 ADDC( *p );
1196                 p++;
1197             }
1198         }
1199         else
1200         {
1201             p = TextGetLine( txt );
1202         }
1203
1204         if( p == NULL )
1205         {
1206             break;
1207         }
1208     }
1209
1210     p_subtitle->i_start = i_start * 1000;
1211     p_subtitle->i_stop  = 0;
1212     p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
1213
1214     return( VLC_SUCCESS );
1215 #undef ADDC
1216 }
1217
1218 static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle )
1219 {
1220     demux_sys_t *p_sys = p_demux->p_sys;
1221     text_t      *txt = &p_sys->txt;
1222
1223     /*
1224      * {T h1:m1:s1:c1
1225      * Line1
1226      * Line2
1227      * ...
1228      * }
1229      *
1230      */
1231     char *s;
1232     char buffer_text[ 10 * MAX_LINE];
1233     int  i_buffer_text;
1234     int64_t     i_start;
1235
1236     p_subtitle->i_start = 0;
1237     p_subtitle->i_stop  = 0;
1238     p_subtitle->psz_text = NULL;
1239
1240     for( ;; )
1241     {
1242         int h1, m1, s1, c1;
1243         if( ( s = TextGetLine( txt ) ) == NULL )
1244         {
1245             return( VLC_EGENERIC );
1246         }
1247         if( sscanf( s,
1248                     "{T %d:%d:%d:%d",
1249                     &h1, &m1, &s1, &c1 ) == 4 )
1250         {
1251             i_start = ( (int64_t)h1 * 3600*1000 +
1252                         (int64_t)m1 * 60*1000 +
1253                         (int64_t)s1 * 1000 +
1254                         (int64_t)c1 * 10) * 1000;
1255
1256             /* Now read text until a line containing "}" */
1257             for( i_buffer_text = 0;; )
1258             {
1259                 int i_len;
1260                 if( ( s = TextGetLine( txt ) ) == NULL )
1261                 {
1262                     return( VLC_EGENERIC );
1263                 }
1264
1265                 i_len = strlen( s );
1266                 if( i_len == 1 && s[0] == '}' )
1267                 {
1268                     /* "}" -> end of this subtitle */
1269                     buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
1270                     p_subtitle->i_start = i_start;
1271                     p_subtitle->i_stop  = 0;
1272                     p_subtitle->psz_text = strdup( buffer_text );
1273                     return 0;
1274                 }
1275                 else
1276                 {
1277                     if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
1278                     {
1279                         memcpy( buffer_text + i_buffer_text,
1280                                 s,
1281                                 i_len );
1282                         i_buffer_text += i_len;
1283
1284                         buffer_text[i_buffer_text] = '\n';
1285                         i_buffer_text++;
1286                     }
1287                 }
1288             }
1289         }
1290     }
1291 }
1292