1 /*****************************************************************************
2 * subtitle.c: Demux for subtitle text files.
3 *****************************************************************************
4 * Copyright (C) 1999-2004 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Derk-Jan Hartman <hartman at videolan dot org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
37 #include <vlc/input.h>
38 #include "vlc_video.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Open ( vlc_object_t *p_this );
44 static void Close( vlc_object_t *p_this );
46 #define SUB_DELAY_LONGTEXT \
47 "Delay subtitles (in 1/10s)"
48 #define SUB_FPS_LONGTEXT \
49 "Override frames per second. " \
50 "It will only work with MicroDVD subtitles."
51 #define SUB_TYPE_LONGTEXT \
52 "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\" " \
53 "\"sami\", \"dvdsubtitle\" (auto for autodetection, it should always work)."
54 static char *ppsz_sub_type[] =
56 "auto", "microdvd", "subrip", "subviewer", "ssa1",
57 "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle"
61 set_shortname( _("Subtitles"));
62 set_description( _("Text subtitles demux") );
63 set_capability( "demux2", 0 );
64 set_category( CAT_INPUT );
65 set_subcategory( SUBCAT_INPUT_DEMUX );
66 add_float( "sub-fps", 0.0, NULL,
67 N_("Frames per second"),
68 SUB_FPS_LONGTEXT, VLC_TRUE );
69 add_integer( "sub-delay", 0, NULL,
70 N_("Subtitles delay"),
71 SUB_DELAY_LONGTEXT, VLC_TRUE );
72 add_string( "sub-type", "auto", NULL, "Subtitles fileformat",
73 SUB_TYPE_LONGTEXT, VLC_TRUE );
74 change_string_list( ppsz_sub_type, 0, 0 );
75 set_callbacks( Open, Close );
77 add_shortcut( "subtitle" );
80 /*****************************************************************************
82 *****************************************************************************/
85 SUB_TYPE_UNKNOWN = -1,
103 static int TextLoad( text_t *, stream_t *s );
104 static void TextUnload( text_t * );
121 int64_t i_next_demux_date;
123 int64_t i_microsecperframe;
124 int64_t i_original_mspf;
129 subtitle_t *subtitle;
134 static int ParseMicroDvd ( demux_t *, subtitle_t * );
135 static int ParseSubRip ( demux_t *, subtitle_t * );
136 static int ParseSubViewer ( demux_t *, subtitle_t * );
137 static int ParseSSA ( demux_t *, subtitle_t * );
138 static int ParseVplayer ( demux_t *, subtitle_t * );
139 static int ParseSami ( demux_t *, subtitle_t * );
140 static int ParseDVDSubtitle( demux_t *, subtitle_t * );
147 int (*pf_read)( demux_t *, subtitle_t* );
148 } sub_read_subtitle_function [] =
150 { "microdvd", SUB_TYPE_MICRODVD, "MicroDVD", ParseMicroDvd },
151 { "subrip", SUB_TYPE_SUBRIP, "SubRIP", ParseSubRip },
152 { "subviewer", SUB_TYPE_SUBVIEWER, "SubViewer", ParseSubViewer },
153 { "ssa1", SUB_TYPE_SSA1, "SSA-1", ParseSSA },
154 { "ssa2-4", SUB_TYPE_SSA2_4, "SSA-2/3/4", ParseSSA },
155 { "ass", SUB_TYPE_ASS, "SSA/ASS", ParseSSA },
156 { "vplayer", SUB_TYPE_VPLAYER, "VPlayer", ParseVplayer },
157 { "sami", SUB_TYPE_SAMI, "SAMI", ParseSami },
158 { "dvdsubtitle",SUB_TYPE_DVDSUBTITLE, "DVDSubtitle", ParseDVDSubtitle },
159 { NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL }
162 static int Demux( demux_t * );
163 static int Control( demux_t *, int, va_list );
165 /*static void Fix( demux_t * );*/
167 /*****************************************************************************
169 *****************************************************************************/
170 static int Open ( vlc_object_t *p_this )
172 demux_t *p_demux = (demux_t*)p_this;
177 int (*pf_read)( demux_t *, subtitle_t* );
180 if( strcmp( p_demux->psz_demux, "subtitle" ) )
182 msg_Dbg( p_demux, "subtitle demux discarded" );
186 p_demux->pf_demux = Demux;
187 p_demux->pf_control = Control;
188 p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
189 p_sys->psz_header = NULL;
190 p_sys->i_subtitle = 0;
191 p_sys->i_subtitles= 0;
192 p_sys->subtitle = NULL;
196 f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
199 p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
203 p_sys->i_microsecperframe = 0;
206 f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" );
209 p_sys->i_original_mspf = (int64_t)( (float)1000000 / f_fps );
213 p_sys->i_original_mspf = 0;
216 /* Get or probe the type */
217 p_sys->i_type = SUB_TYPE_UNKNOWN;
218 psz_type = var_CreateGetString( p_demux, "sub-type" );
225 if( sub_read_subtitle_function[i].psz_type_name == NULL )
228 if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
231 p_sys->i_type = sub_read_subtitle_function[i].i_type;
238 /* Probe if unknown type */
239 if( p_sys->i_type == SUB_TYPE_UNKNOWN )
244 msg_Dbg( p_demux, "autodetecting subtitle format" );
245 for( i_try = 0; i_try < 256; i_try++ )
249 if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
252 if( strcasestr( s, "<SAMI>" ) )
254 p_sys->i_type = SUB_TYPE_SAMI;
257 else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
258 sscanf( s, "{%d}{}", &i_dummy ) == 1)
260 p_sys->i_type = SUB_TYPE_MICRODVD;
264 "%d:%d:%d,%d --> %d:%d:%d,%d",
265 &i_dummy,&i_dummy,&i_dummy,&i_dummy,
266 &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
268 p_sys->i_type = SUB_TYPE_SUBRIP;
271 else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
273 p_sys->i_type = SUB_TYPE_SSA1;
276 else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
278 p_sys->i_type = SUB_TYPE_ASS;
281 else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
283 p_sys->i_type = SUB_TYPE_SSA2_4;
286 else if( !strncasecmp( s, "Dialogue: Marked", 16 ) )
288 p_sys->i_type = SUB_TYPE_SSA2_4;
291 else if( !strncasecmp( s, "Dialogue:", 9 ) )
293 p_sys->i_type = SUB_TYPE_ASS;
296 else if( strcasestr( s, "[INFORMATION]" ) )
298 p_sys->i_type = SUB_TYPE_SUBVIEWER; /* I hope this will work */
301 else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
302 sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
304 p_sys->i_type = SUB_TYPE_VPLAYER;
307 else if( sscanf( s, "{T %d:%d:%d:%d", &i_dummy, &i_dummy,
308 &i_dummy, &i_dummy ) == 4 )
310 p_sys->i_type = SUB_TYPE_DVDSUBTITLE;
320 /* It will nearly always work even for non seekable stream thanks the
321 * caching system, and if it fails we loose just a few sub */
322 if( stream_Seek( p_demux->s, 0 ) )
324 msg_Warn( p_demux, "failed to rewind" );
327 if( p_sys->i_type == SUB_TYPE_UNKNOWN )
329 msg_Err( p_demux, "failed to recognize subtitle type" );
336 if( sub_read_subtitle_function[i].i_type == p_sys->i_type )
338 msg_Dbg( p_demux, "detected %s format",
339 sub_read_subtitle_function[i].psz_name );
340 pf_read = sub_read_subtitle_function[i].pf_read;
345 msg_Dbg( p_demux, "loading all subtitles..." );
347 /* Load the whole file */
348 TextLoad( &p_sys->txt, p_demux->s );
353 if( p_sys->i_subtitles >= i_max )
356 if( !( p_sys->subtitle = realloc( p_sys->subtitle,
357 sizeof(subtitle_t) * i_max ) ) )
359 msg_Err( p_demux, "out of memory");
360 if( p_sys->subtitle != NULL )
361 free( p_sys->subtitle );
362 TextUnload( &p_sys->txt );
368 if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles] ) )
371 p_sys->i_subtitles++;
374 TextUnload( &p_sys->txt );
376 msg_Dbg(p_demux, "loaded %d subtitles", p_sys->i_subtitles );
378 /* Fix subtitle (order and time) *** */
379 p_sys->i_subtitle = 0;
381 if( p_sys->i_subtitles > 0 )
383 p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_stop;
385 if( p_sys->i_length <= 0 )
386 p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_start+1;
389 /* *** add subtitle ES *** */
390 if( p_sys->i_type == SUB_TYPE_SSA1 ||
391 p_sys->i_type == SUB_TYPE_SSA2_4 ||
392 p_sys->i_type == SUB_TYPE_ASS )
394 es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
398 es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
400 if( p_sys->psz_header != NULL )
402 fmt.i_extra = strlen( p_sys->psz_header ) + 1;
403 fmt.p_extra = strdup( p_sys->psz_header );
405 p_sys->es = es_out_Add( p_demux->out, &fmt );
410 /*****************************************************************************
411 * Close: Close subtitle demux
412 *****************************************************************************/
413 static void Close( vlc_object_t *p_this )
415 demux_t *p_demux = (demux_t*)p_this;
416 demux_sys_t *p_sys = p_demux->p_sys;
419 for( i = 0; i < p_sys->i_subtitles; i++ )
421 if( p_sys->subtitle[i].psz_text )
422 free( p_sys->subtitle[i].psz_text );
424 if( p_sys->subtitle )
425 free( p_sys->subtitle );
430 /*****************************************************************************
432 *****************************************************************************/
433 static int Control( demux_t *p_demux, int i_query, va_list args )
435 demux_sys_t *p_sys = p_demux->p_sys;
441 case DEMUX_GET_LENGTH:
442 pi64 = (int64_t*)va_arg( args, int64_t * );
443 *pi64 = p_sys->i_length;
447 pi64 = (int64_t*)va_arg( args, int64_t * );
448 if( p_sys->i_subtitle < p_sys->i_subtitles )
450 *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
456 i64 = (int64_t)va_arg( args, int64_t );
457 p_sys->i_subtitle = 0;
458 while( p_sys->i_subtitle < p_sys->i_subtitles &&
459 p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
464 if( p_sys->i_subtitle >= p_sys->i_subtitles )
468 case DEMUX_GET_POSITION:
469 pf = (double*)va_arg( args, double * );
470 if( p_sys->i_subtitle >= p_sys->i_subtitles )
474 else if( p_sys->i_subtitles > 0 )
476 *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
477 (double)p_sys->i_length;
485 case DEMUX_SET_POSITION:
486 f = (double)va_arg( args, double );
487 i64 = f * p_sys->i_length;
489 p_sys->i_subtitle = 0;
490 while( p_sys->i_subtitle < p_sys->i_subtitles &&
491 p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
495 if( p_sys->i_subtitle >= p_sys->i_subtitles )
499 case DEMUX_SET_NEXT_DEMUX_TIME:
500 p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
505 case DEMUX_GET_TITLE_INFO:
509 msg_Err( p_demux, "unknown query in subtitle control" );
514 /*****************************************************************************
515 * Demux: Send subtitle to decoder
516 *****************************************************************************/
517 static int Demux( demux_t *p_demux )
519 demux_sys_t *p_sys = p_demux->p_sys;
522 if( p_sys->i_subtitle >= p_sys->i_subtitles )
525 i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
526 if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
528 /* Should not happen */
529 i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
532 while( p_sys->i_subtitle < p_sys->i_subtitles &&
533 p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
536 int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1;
545 if( ( p_block = block_New( p_demux, i_len ) ) == NULL )
551 if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 )
557 p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start;
558 p_block->i_dts = p_block->i_pts;
559 if( p_sys->subtitle[p_sys->i_subtitle].i_stop > 0 )
562 p_sys->subtitle[p_sys->i_subtitle].i_stop - p_block->i_pts;
565 memcpy( p_block->p_buffer,
566 p_sys->subtitle[p_sys->i_subtitle].psz_text, i_len );
567 if( p_block->i_pts > 0 )
569 es_out_Send( p_demux->out, p_sys->es, p_block );
573 block_Release( p_block );
579 p_sys->i_next_demux_date = 0;
584 /*****************************************************************************
585 * Fix: fix time stamp and order of subtitle
586 *****************************************************************************/
587 #ifdef USE_THIS_UNUSED_PIECE_OF_CODE
588 static void Fix( demux_t *p_demux )
590 demux_sys_t *p_sys = p_demux->p_sys;
594 /* *** fix order (to be sure...) *** */
595 /* We suppose that there are near in order and this durty bubble sort
596 * wont take too much time
601 for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
603 if( p_sys->subtitle[i_index].i_start <
604 p_sys->subtitle[i_index - 1].i_start )
608 p_sys->subtitle + i_index - 1,
609 sizeof( subtitle_t ) );
610 memcpy( p_sys->subtitle + i_index - 1,
611 p_sys->subtitle + i_index,
612 sizeof( subtitle_t ) );
613 memcpy( p_sys->subtitle + i_index,
615 sizeof( subtitle_t ) );
623 static int TextLoad( text_t *txt, stream_t *s )
629 txt->i_line_count = 0;
631 txt->line = calloc( i_line_max, sizeof( char * ) );
633 /* load the complete file */
636 char *psz = stream_ReadLine( s );
641 txt->line[txt->i_line_count++] = psz;
642 if( txt->i_line_count >= i_line_max )
645 txt->line = realloc( txt->line, i_line_max * sizeof( char * ) );
649 if( txt->i_line_count <= 0 )
657 static void TextUnload( text_t *txt )
661 for( i = 0; i < txt->i_line_count; i++ )
663 free( txt->line[i] );
667 txt->i_line_count = 0;
670 static char *TextGetLine( text_t *txt )
672 if( txt->i_line >= txt->i_line_count )
675 return txt->line[txt->i_line++];
677 static void TextPreviousLine( text_t *txt )
679 if( txt->i_line > 0 )
683 /*****************************************************************************
684 * Specific Subtitle function
685 *****************************************************************************/
686 #define MAX_LINE 8192
687 static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
689 demux_sys_t *p_sys = p_demux->p_sys;
690 text_t *txt = &p_sys->txt;
693 * {n1}{n2}Line1|Line2|Line3....
694 * where n1 and n2 are the video frame number...
695 * {n2} can also be {}
699 char buffer_text[MAX_LINE + 1];
704 int i_microsecperframe = 40000; /* default to 25 fps */
705 if( p_sys->i_microsecperframe > 0 )
706 i_microsecperframe = p_sys->i_microsecperframe;
708 p_subtitle->i_start = 0;
709 p_subtitle->i_stop = 0;
710 p_subtitle->psz_text = NULL;
714 if( ( s = TextGetLine( txt ) ) == NULL )
716 return( VLC_EGENERIC );
721 memset( buffer_text, '\0', MAX_LINE );
722 if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
723 sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
728 /* replace | by \n */
729 for( i = 0; i < strlen( buffer_text ); i++ )
731 if( buffer_text[i] == '|' )
733 buffer_text[i] = '\n';
737 p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
738 p_subtitle->i_stop = (int64_t)i_stop * i_microsecperframe;
739 p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
743 static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle )
745 demux_sys_t *p_sys = p_demux->p_sys;
746 text_t *txt = &p_sys->txt;
750 * h1:m1:s1,d1 --> h2:m2:s2,d2
758 char buffer_text[ 10 * MAX_LINE];
763 p_subtitle->i_start = 0;
764 p_subtitle->i_stop = 0;
765 p_subtitle->psz_text = NULL;
769 int h1, m1, s1, d1, h2, m2, s2, d2;
770 if( ( s = TextGetLine( txt ) ) == NULL )
772 return( VLC_EGENERIC );
775 "%d:%d:%d,%d --> %d:%d:%d,%d",
777 &h2, &m2, &s2, &d2 ) == 8 )
779 i_start = ( (int64_t)h1 * 3600*1000 +
780 (int64_t)m1 * 60*1000 +
782 (int64_t)d1 ) * 1000;
784 i_stop = ( (int64_t)h2 * 3600*1000 +
785 (int64_t)m2 * 60*1000 +
787 (int64_t)d2 ) * 1000;
789 /* Now read text until an empty line */
790 for( i_buffer_text = 0;; )
793 if( ( s = TextGetLine( txt ) ) == NULL )
795 return( VLC_EGENERIC );
801 /* empty line -> end of this subtitle */
802 buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
803 p_subtitle->i_start = i_start;
804 p_subtitle->i_stop = i_stop;
805 p_subtitle->psz_text = strdup( buffer_text );
806 /* If framerate is available, use sub-fps */
807 if( p_sys->i_microsecperframe != 0 &&
808 p_sys->i_original_mspf != 0)
810 p_subtitle->i_start = (int64_t)i_start *
811 p_sys->i_microsecperframe/
812 p_sys->i_original_mspf;
813 p_subtitle->i_stop = (int64_t)i_stop *
814 p_sys->i_microsecperframe /
815 p_sys->i_original_mspf;
821 if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
823 memcpy( buffer_text + i_buffer_text,
826 i_buffer_text += i_len;
828 buffer_text[i_buffer_text] = '\n';
837 static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle )
839 demux_sys_t *p_sys = p_demux->p_sys;
840 text_t *txt = &p_sys->txt;
843 * h1:m1:s1.d1,h2:m2:s2.d2
848 * ( works with subviewer and subviewer v2 )
851 char buffer_text[ 10 * MAX_LINE];
856 p_subtitle->i_start = 0;
857 p_subtitle->i_stop = 0;
858 p_subtitle->psz_text = NULL;
862 int h1, m1, s1, d1, h2, m2, s2, d2;
863 if( ( s = TextGetLine( txt ) ) == NULL )
865 return( VLC_EGENERIC );
868 "%d:%d:%d.%d,%d:%d:%d.%d",
870 &h2, &m2, &s2, &d2 ) == 8 )
872 i_start = ( (int64_t)h1 * 3600*1000 +
873 (int64_t)m1 * 60*1000 +
875 (int64_t)d1 ) * 1000;
877 i_stop = ( (int64_t)h2 * 3600*1000 +
878 (int64_t)m2 * 60*1000 +
880 (int64_t)d2 ) * 1000;
882 /* Now read text until an empty line */
883 for( i_buffer_text = 0;; )
886 if( ( s = TextGetLine( txt ) ) == NULL )
888 return( VLC_EGENERIC );
894 /* empty line -> end of this subtitle */
895 buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
896 p_subtitle->i_start = i_start;
897 p_subtitle->i_stop = i_stop;
899 /* replace [br] by \n */
900 for( i = 0; i < i_buffer_text - 3; i++ )
902 if( buffer_text[i] == '[' && buffer_text[i+1] == 'b' &&
903 buffer_text[i+2] == 'r' && buffer_text[i+3] == ']' )
905 char *temp = buffer_text + i + 1;
906 buffer_text[i] = '\n';
907 memmove( temp, temp+3, strlen( temp ) -3 );
908 temp[strlen( temp )-3] = '\0';
911 p_subtitle->psz_text = strdup( buffer_text );
916 if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
918 memcpy( buffer_text + i_buffer_text,
921 i_buffer_text += i_len;
923 buffer_text[i_buffer_text] = '\n';
933 static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
935 demux_sys_t *p_sys = p_demux->p_sys;
936 text_t *txt = &p_sys->txt;
938 char buffer_text[ 10 * MAX_LINE];
939 char buffer_text2[ 10 * MAX_LINE];
944 p_subtitle->i_start = 0;
945 p_subtitle->i_stop = 0;
946 p_subtitle->psz_text = NULL;
950 int h1, m1, s1, c1, h2, m2, s2, c2;
952 if( ( s = TextGetLine( txt ) ) == NULL )
954 return( VLC_EGENERIC );
956 p_subtitle->psz_text = malloc( strlen( s ) );
958 /* We expect (SSA2-4):
959 * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
960 * Dialogue: Marked=0,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
962 * 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.
966 * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
967 * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
970 "Dialogue: %[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
974 buffer_text ) == 10 )
976 i_start = ( (int64_t)h1 * 3600*1000 +
977 (int64_t)m1 * 60*1000 +
979 (int64_t)c1 * 10 ) * 1000;
981 i_stop = ( (int64_t)h2 * 3600*1000 +
982 (int64_t)m2 * 60*1000 +
984 (int64_t)c2 * 10 ) * 1000;
986 /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
987 /* (Layer comes from ASS specs ... it's empty for SSA.) */
988 if( p_sys->i_type == SUB_TYPE_SSA1 )
990 sprintf( p_subtitle->psz_text,
991 ",%s", strdup( buffer_text) ); /* SSA1 has only 8 commas before the text starts, not 9 */
995 sprintf( p_subtitle->psz_text,
996 ",,%s", strdup( buffer_text) ); /* ReadOrder, Layer, %s(rest of fields) */
998 p_subtitle->i_start = i_start;
999 p_subtitle->i_stop = i_stop;
1004 /* All the other stuff we add to the header field */
1005 if( p_sys->psz_header != NULL )
1007 if( !( p_sys->psz_header = realloc( p_sys->psz_header,
1008 strlen( p_sys->psz_header ) + 1 + strlen( s ) + 2 ) ) )
1010 msg_Err( p_demux, "out of memory");
1013 p_sys->psz_header = strcat( p_sys->psz_header, s );
1014 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1018 if( !( p_sys->psz_header = malloc( strlen( s ) + 2 ) ) )
1020 msg_Err( p_demux, "out of memory");
1023 p_sys->psz_header = s;
1024 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1030 static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle )
1032 demux_sys_t *p_sys = p_demux->p_sys;
1033 text_t *txt = &p_sys->txt;
1037 * h:m:s:Line1|Line2|Line3....
1039 * h:m:s Line1|Line2|Line3....
1043 char buffer_text[MAX_LINE + 1];
1047 p_subtitle->i_start = 0;
1048 p_subtitle->i_stop = 0;
1049 p_subtitle->psz_text = NULL;
1056 if( ( p = TextGetLine( txt ) ) == NULL )
1058 return( VLC_EGENERIC );
1063 memset( buffer_text, '\0', MAX_LINE );
1064 if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
1066 i_start = ( (int64_t)h * 3600*1000 +
1067 (int64_t)m * 60*1000 +
1068 (int64_t)s * 1000 ) * 1000;
1073 /* replace | by \n */
1074 for( i = 0; i < strlen( buffer_text ); i++ )
1076 if( buffer_text[i] == '|' )
1078 buffer_text[i] = '\n';
1081 p_subtitle->i_start = i_start;
1083 p_subtitle->i_stop = 0;
1084 p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
1088 static char *ParseSamiSearch( text_t *txt, char *psz_start, char *psz_str )
1092 if( strcasestr( psz_start, psz_str ) )
1094 char *s = strcasestr( psz_start, psz_str );
1096 s += strlen( psz_str );
1104 if( ( p = TextGetLine( txt ) ) == NULL )
1108 if( strcasestr( p, psz_str ) )
1110 char *s = strcasestr( p, psz_str );
1112 s += strlen( psz_str );
1119 static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle )
1121 demux_sys_t *p_sys = p_demux->p_sys;
1122 text_t *txt = &p_sys->txt;
1128 char buffer_text[10*MAX_LINE + 1];
1130 p_subtitle->i_start = 0;
1131 p_subtitle->i_stop = 0;
1132 p_subtitle->psz_text = NULL;
1135 if( i_text < 10*MAX_LINE ) \
1137 buffer_text[i_text++] = c; \
1138 buffer_text[i_text] = '\0'; \
1141 /* search "Start=" */
1142 if( !( p = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1144 return VLC_EGENERIC;
1147 /* get start value */
1148 i_start = strtol( p, &p, 0 );
1151 if( !( p = ParseSamiSearch( txt, p, "<P" ) ) )
1153 return VLC_EGENERIC;
1156 if( !( p = ParseSamiSearch( txt, p, ">" ) ) )
1158 return VLC_EGENERIC;
1162 buffer_text[0] = '\0';
1163 /* now get all txt until a "Start=" line */
1170 if( !strncasecmp( p, "<br", 3 ) )
1174 else if( strcasestr( p, "Start=" ) )
1176 TextPreviousLine( txt );
1179 p = ParseSamiSearch( txt, p, ">" );
1181 else if( !strncmp( p, " ", 6 ) )
1186 else if( *p == '\t' )
1199 p = TextGetLine( txt );
1208 p_subtitle->i_start = i_start * 1000;
1209 p_subtitle->i_stop = 0;
1210 p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
1212 return( VLC_SUCCESS );
1216 static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle )
1218 demux_sys_t *p_sys = p_demux->p_sys;
1219 text_t *txt = &p_sys->txt;
1230 char buffer_text[ 10 * MAX_LINE];
1234 p_subtitle->i_start = 0;
1235 p_subtitle->i_stop = 0;
1236 p_subtitle->psz_text = NULL;
1241 if( ( s = TextGetLine( txt ) ) == NULL )
1243 return( VLC_EGENERIC );
1247 &h1, &m1, &s1, &c1 ) == 4 )
1249 i_start = ( (int64_t)h1 * 3600*1000 +
1250 (int64_t)m1 * 60*1000 +
1251 (int64_t)s1 * 1000 +
1252 (int64_t)c1 * 10) * 1000;
1254 /* Now read text until a line containing "}" */
1255 for( i_buffer_text = 0;; )
1258 if( ( s = TextGetLine( txt ) ) == NULL )
1260 return( VLC_EGENERIC );
1263 i_len = strlen( s );
1264 if( i_len == 1 && s[0] == '}' )
1266 /* "}" -> end of this subtitle */
1267 buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
1268 p_subtitle->i_start = i_start;
1269 p_subtitle->i_stop = 0;
1270 p_subtitle->psz_text = strdup( buffer_text );
1275 if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
1277 memcpy( buffer_text + i_buffer_text,
1280 i_buffer_text += i_len;
1282 buffer_text[i_buffer_text] = '\n';