685
793
/*****************************************************************************
686
794
* Specific Subtitle function
687
795
*****************************************************************************/
688
#define MAX_LINE 8192 /* must store the null terminator */
689
#define MAX_LINE_STR "8191" /* used in *scanf() regexps */
690
static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
798
* {n1}{n2}Line1|Line2|Line3....
799
* where n1 and n2 are the video frame number (n2 can be empty)
801
static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle,
692
805
demux_sys_t *p_sys = p_demux->p_sys;
693
806
text_t *txt = &p_sys->txt;
696
* {n1}{n2}Line1|Line2|Line3....
697
* where n1 and n2 are the video frame number...
698
* {n2} can also be {}
702
char buffer_text[MAX_LINE + 1];
707
/* Try sub-fps value if set, movie rate if know, else 25fps (40000) */
708
int i_microsecperframe = p_sys->i_original_mspf > 0 ? p_sys->i_original_mspf : 40000;
709
if( p_sys->i_microsecperframe > 0 )
710
i_microsecperframe = p_sys->i_microsecperframe;
712
p_subtitle->i_start = 0;
713
p_subtitle->i_stop = 0;
714
p_subtitle->psz_text = NULL;
719
if( ( s = TextGetLine( txt ) ) == NULL )
721
return( VLC_EGENERIC );
814
const char *s = TextGetLine( txt );
818
psz_text = malloc( strlen(s) + 1 );
726
memset( buffer_text, '\0', MAX_LINE + 1 );
727
if( sscanf( s, "{%d}{}%"MAX_LINE_STR"[^\r\n]", &i_start, buffer_text ) == 2 ||
728
sscanf( s, "{%d}{%d}%"MAX_LINE_STR"[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
824
if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, psz_text ) == 2 ||
825
sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
828
if( i_start != 1 || i_stop != 1 )
831
/* We found a possible setting of the framerate "{1}{1}23.976" */
832
/* Check if it's usable, and if the sub-fps is not set */
833
f_fps = us_strtod( psz_text, NULL );
834
if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
835
p_sys->i_microsecperframe = (int64_t)((float)1000000 / f_fps);
840
/* replace | by \n */
841
for( i = 0; psz_text[i] != '\0'; i++ )
843
if( psz_text[i] == '|' )
848
p_subtitle->i_start = i_start * p_sys->i_microsecperframe;
849
p_subtitle->i_stop = i_stop * p_sys->i_microsecperframe;
850
p_subtitle->psz_text = psz_text;
854
/* ParseSubRipSubViewer
857
* h1:m1:s1,d1 --> h2:m2:s2,d2
862
* Format SubViewer v1/v2
863
* h1:m1:s1.d1,h2:m2:s2.d2
868
* We ignore line number for SubRip
870
static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
874
demux_sys_t *p_sys = p_demux->p_sys;
875
text_t *txt = &p_sys->txt;
880
const char *s = TextGetLine( txt );
881
int h1, m1, s1, d1, h2, m2, s2, d2;
886
if( sscanf( s, psz_fmt,
888
&h2, &m2, &s2, &d2 ) == 8 )
890
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
891
(int64_t)m1 * 60*1000 +
893
(int64_t)d1 ) * 1000;
895
p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +
896
(int64_t)m2 * 60*1000 +
898
(int64_t)d2 ) * 1000;
733
if( i_start == 1 && i_stop == 1 )
735
/* We found a possible setting of the framerate "{1}{1}23.976" */
736
/* Use it unless sub-fps was set */
737
float tmp = us_strtod( buffer_text, NULL );
738
if( tmp > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
739
p_sys->i_microsecperframe = (int64_t)( (float)1000000 / tmp );
743
/* replace | by \n */
744
for( i = 0; i < strlen( buffer_text ); i++ )
746
if( buffer_text[i] == '|' )
748
buffer_text[i] = '\n';
752
p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
753
p_subtitle->i_stop = (int64_t)i_stop * i_microsecperframe;
754
p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
758
static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle )
760
demux_sys_t *p_sys = p_demux->p_sys;
761
text_t *txt = &p_sys->txt;
765
* h1:m1:s1,d1 --> h2:m2:s2,d2
773
char buffer_text[ 10 * MAX_LINE];
778
p_subtitle->i_start = 0;
779
p_subtitle->i_stop = 0;
780
p_subtitle->psz_text = NULL;
784
int h1, m1, s1, d1, h2, m2, s2, d2;
785
if( ( s = TextGetLine( txt ) ) == NULL )
787
return( VLC_EGENERIC );
790
"%d:%d:%d,%d --> %d:%d:%d,%d",
792
&h2, &m2, &s2, &d2 ) == 8 )
794
i_start = ( (int64_t)h1 * 3600*1000 +
795
(int64_t)m1 * 60*1000 +
797
(int64_t)d1 ) * 1000;
799
i_stop = ( (int64_t)h2 * 3600*1000 +
800
(int64_t)m2 * 60*1000 +
802
(int64_t)d2 ) * 1000;
804
/* Now read text until an empty line */
805
for( i_buffer_text = 0;; )
808
if( ( s = TextGetLine( txt ) ) == NULL )
810
return( VLC_EGENERIC );
816
/* empty line -> end of this subtitle */
817
buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
818
p_subtitle->i_start = i_start;
819
p_subtitle->i_stop = i_stop;
820
p_subtitle->psz_text = strdup( buffer_text );
821
/* If framerate is available, use sub-fps */
822
if( p_sys->i_microsecperframe != 0 &&
823
p_sys->i_original_mspf != 0)
825
p_subtitle->i_start = (int64_t)i_start *
826
p_sys->i_microsecperframe/
827
p_sys->i_original_mspf;
828
p_subtitle->i_stop = (int64_t)i_stop *
829
p_sys->i_microsecperframe /
830
p_sys->i_original_mspf;
836
if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
838
memcpy( buffer_text + i_buffer_text,
841
i_buffer_text += i_len;
843
buffer_text[i_buffer_text] = '\n';
852
static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle )
854
demux_sys_t *p_sys = p_demux->p_sys;
855
text_t *txt = &p_sys->txt;
858
* h1:m1:s1.d1,h2:m2:s2.d2
863
* ( works with subviewer and subviewer v2 )
866
char buffer_text[ 10 * MAX_LINE];
871
p_subtitle->i_start = 0;
872
p_subtitle->i_stop = 0;
873
p_subtitle->psz_text = NULL;
877
int h1, m1, s1, d1, h2, m2, s2, d2;
878
if( ( s = TextGetLine( txt ) ) == NULL )
880
return( VLC_EGENERIC );
883
"%d:%d:%d.%d,%d:%d:%d.%d",
885
&h2, &m2, &s2, &d2 ) == 8 )
887
i_start = ( (int64_t)h1 * 3600*1000 +
888
(int64_t)m1 * 60*1000 +
890
(int64_t)d1 ) * 1000;
892
i_stop = ( (int64_t)h2 * 3600*1000 +
893
(int64_t)m2 * 60*1000 +
895
(int64_t)d2 ) * 1000;
897
/* Now read text until an empty line */
898
for( i_buffer_text = 0;; )
901
if( ( s = TextGetLine( txt ) ) == NULL )
903
return( VLC_EGENERIC );
909
/* empty line -> end of this subtitle */
910
buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
911
p_subtitle->i_start = i_start;
912
p_subtitle->i_stop = i_stop;
914
/* replace [br] by \n */
915
for( i = 0; i < i_buffer_text - 3; i++ )
917
if( buffer_text[i] == '[' && buffer_text[i+1] == 'b' &&
918
buffer_text[i+2] == 'r' && buffer_text[i+3] == ']' )
920
char *temp = buffer_text + i + 1;
921
buffer_text[i] = '\n';
922
memmove( temp, temp+3, strlen( temp ) -3 );
923
temp[strlen( temp )-3] = '\0';
926
p_subtitle->psz_text = strdup( buffer_text );
931
if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
933
memcpy( buffer_text + i_buffer_text,
936
i_buffer_text += i_len;
938
buffer_text[i_buffer_text] = '\n';
948
static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
950
demux_sys_t *p_sys = p_demux->p_sys;
951
text_t *txt = &p_sys->txt;
953
char buffer_text[ 10 * MAX_LINE + 1];
954
char buffer_text2[ 10 * MAX_LINE + 1];
959
p_subtitle->i_start = 0;
960
p_subtitle->i_stop = 0;
961
p_subtitle->psz_text = NULL;
903
/* Now read text until an empty line */
904
psz_text = strdup("");
909
const char *s = TextGetLine( txt );
922
p_subtitle->psz_text = psz_text;
926
i_old = strlen( psz_text );
927
psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
930
strcat( psz_text, s );
931
strcat( psz_text, "\n" );
933
/* replace [br] by \n */
938
while( ( p = strstr( psz_text, "[br]" ) ) )
941
memmove( p, &p[3], strlen(&p[3])+1 );
948
static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,
952
return ParseSubRipSubViewer( p_demux, p_subtitle,
953
"%d:%d:%d,%d --> %d:%d:%d,%d",
958
static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
963
return ParseSubRipSubViewer( p_demux, p_subtitle,
964
"%d:%d:%d.%d,%d:%d:%d.%d",
970
static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle,
973
demux_sys_t *p_sys = p_demux->p_sys;
974
text_t *txt = &p_sys->txt;
978
const char *s = TextGetLine( txt );
965
979
int h1, m1, s1, c1, h2, m2, s2, c2;
967
if( ( s = TextGetLine( txt ) ) == NULL )
969
return( VLC_EGENERIC );
971
p_subtitle->psz_text = malloc( strlen( s ) );
973
986
/* We expect (SSA2-4):
974
987
* Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
981
994
* Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
982
995
* Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
998
/* The output text is - at least, not removing numbers - 18 chars shorter than the input text. */
999
psz_text = malloc( strlen(s) );
985
"Dialogue: %"MAX_LINE_STR"0[^,],%d:%d:%d.%d,%d:%d:%d.%d,%"MAX_LINE_STR"0[^\r\n]",
1004
"Dialogue: %15[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
987
1006
&h1, &m1, &s1, &c1,
988
1007
&h2, &m2, &s2, &c2,
989
buffer_text ) == 10 )
991
i_start = ( (int64_t)h1 * 3600*1000 +
992
(int64_t)m1 * 60*1000 +
994
(int64_t)c1 * 10 ) * 1000;
996
i_stop = ( (int64_t)h2 * 3600*1000 +
997
(int64_t)m2 * 60*1000 +
999
(int64_t)c2 * 10 ) * 1000;
1001
1010
/* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
1002
1011
/* (Layer comes from ASS specs ... it's empty for SSA.) */
1003
1012
if( p_sys->i_type == SUB_TYPE_SSA1 )
1005
sprintf( p_subtitle->psz_text,
1006
",%s", strdup( buffer_text) ); /* SSA1 has only 8 commas before the text starts, not 9 */
1010
sprintf( p_subtitle->psz_text,
1011
",,%s", strdup( buffer_text) ); /* ReadOrder, Layer, %s(rest of fields) */
1013
p_subtitle->i_start = i_start;
1014
p_subtitle->i_stop = i_stop;
1019
/* All the other stuff we add to the header field */
1020
if( p_sys->psz_header != NULL )
1022
if( !( p_sys->psz_header = realloc( p_sys->psz_header,
1023
strlen( p_sys->psz_header ) + 1 + strlen( s ) + 2 ) ) )
1025
msg_Err( p_demux, "out of memory");
1028
p_sys->psz_header = strcat( p_sys->psz_header, s );
1029
p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1033
if( !( p_sys->psz_header = malloc( strlen( s ) + 2 ) ) )
1035
msg_Err( p_demux, "out of memory");
1038
p_sys->psz_header = s;
1039
p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1014
/* SSA1 has only 8 commas before the text starts, not 9 */
1015
memmove( &psz_text[1], psz_text, strlen(psz_text)+1 );
1020
int i_layer = ( p_sys->i_type == SUB_TYPE_ASS ) ? atoi( temp ) : 0;
1022
/* ReadOrder, Layer, %s(rest of fields) */
1023
snprintf( temp, sizeof(temp), "%d,%d,", i_idx, i_layer );
1024
memmove( psz_text + strlen(temp), psz_text, strlen(psz_text)+1 );
1025
memcpy( psz_text, temp, strlen(temp) );
1028
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1029
(int64_t)m1 * 60*1000 +
1030
(int64_t)s1 * 1000 +
1031
(int64_t)c1 * 10 ) * 1000;
1032
p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +
1033
(int64_t)m2 * 60*1000 +
1034
(int64_t)s2 * 1000 +
1035
(int64_t)c2 * 10 ) * 1000;
1036
p_subtitle->psz_text = psz_text;
1041
/* All the other stuff we add to the header field */
1042
if( !p_sys->psz_header )
1043
p_sys->psz_header = strdup( "" );
1044
if( !p_sys->psz_header )
1048
realloc( p_sys->psz_header,
1049
strlen( p_sys->psz_header ) + strlen( s ) + 2 );
1050
strcat( p_sys->psz_header, s );
1051
strcat( p_sys->psz_header, "\n" );
1045
static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle )
1057
* h:m:s:Line1|Line2|Line3....
1059
* h:m:s Line1|Line2|Line3....
1061
static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle,
1064
VLC_UNUSED( i_idx );
1047
1066
demux_sys_t *p_sys = p_demux->p_sys;
1048
1067
text_t *txt = &p_sys->txt;
1052
* h:m:s:Line1|Line2|Line3....
1054
* h:m:s Line1|Line2|Line3....
1058
char buffer_text[MAX_LINE + 1];
1062
p_subtitle->i_start = 0;
1063
p_subtitle->i_stop = 0;
1064
p_subtitle->psz_text = NULL;
1071
if( ( p = TextGetLine( txt ) ) == NULL )
1073
return( VLC_EGENERIC );
1078
memset( buffer_text, '\0', MAX_LINE + 1 );
1079
if( sscanf( p, "%d:%d:%d%[ :]%"MAX_LINE_STR"0[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
1081
i_start = ( (int64_t)h * 3600*1000 +
1082
(int64_t)m * 60*1000 +
1083
(int64_t)s * 1000 ) * 1000;
1073
const char *s = TextGetLine( txt );
1077
return VLC_EGENERIC;
1079
psz_text = malloc( strlen( s ) + 1 );
1083
if( sscanf( s, "%d:%d:%d%*c%[^\r\n]",
1084
&h1, &m1, &s1, psz_text ) == 4 )
1086
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1087
(int64_t)m1 * 60*1000 +
1088
(int64_t)s1 * 1000 ) * 1000;
1089
p_subtitle->i_stop = 0;
1088
1095
/* replace | by \n */
1089
for( i = 0; i < strlen( buffer_text ); i++ )
1096
for( i = 0; psz_text[i] != '\0'; i++ )
1091
if( buffer_text[i] == '|' )
1093
buffer_text[i] = '\n';
1098
if( psz_text[i] == '|' )
1096
p_subtitle->i_start = i_start;
1098
p_subtitle->i_stop = 0;
1099
p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
1101
p_subtitle->psz_text = psz_text;
1103
static char *ParseSamiSearch( text_t *txt, char *psz_start, char *psz_str )
1107
static char *ParseSamiSearch( text_t *txt,
1108
char *psz_start, const char *psz_str )
1110
if( psz_start && strcasestr( psz_start, psz_str ) )
1107
if( strcasestr( psz_start, psz_str ) )
1109
char *s = strcasestr( psz_start, psz_str );
1111
s += strlen( psz_str );
1112
char *s = strcasestr( psz_start, psz_str );
1113
return &s[strlen( psz_str )];
1119
if( ( p = TextGetLine( txt ) ) == NULL )
1118
char *p = TextGetLine( txt );
1123
1122
if( strcasestr( p, psz_str ) )
1125
1124
char *s = strcasestr( p, psz_str );
1127
s += strlen( psz_str );
1125
return &s[strlen( psz_str )];
1134
static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle )
1129
static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1131
VLC_UNUSED( i_idx );
1136
1132
demux_sys_t *p_sys = p_demux->p_sys;
1137
1133
text_t *txt = &p_sys->txt;
1140
1136
int64_t i_start;
1143
char buffer_text[10*MAX_LINE + 1];
1145
p_subtitle->i_start = 0;
1146
p_subtitle->i_stop = 0;
1147
p_subtitle->psz_text = NULL;
1150
if( i_text < 10*MAX_LINE ) \
1152
buffer_text[i_text++] = c; \
1153
buffer_text[i_text] = '\0'; \
1138
unsigned int i_text;
1139
char text[8192]; /* Arbitrary but should be long enough */
1156
1141
/* search "Start=" */
1157
if( !( p = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1142
if( !( s = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1159
1143
return VLC_EGENERIC;
1162
1145
/* get start value */
1163
i_start = strtol( p, &p, 0 );
1146
i_start = strtol( s, &s, 0 );
1165
1148
/* search <P */
1166
if( !( p = ParseSamiSearch( txt, p, "<P" ) ) )
1149
if( !( s = ParseSamiSearch( txt, s, "<P" ) ) )
1168
1150
return VLC_EGENERIC;
1171
if( !( p = ParseSamiSearch( txt, p, ">" ) ) )
1153
if( !( s = ParseSamiSearch( txt, s, ">" ) ) )
1173
1154
return VLC_EGENERIC;
1177
buffer_text[0] = '\0';
1178
1158
/* now get all txt until a "Start=" line */
1185
if( !strncasecmp( p, "<br", 3 ) )
1189
else if( strcasestr( p, "Start=" ) )
1191
TextPreviousLine( txt );
1194
p = ParseSamiSearch( txt, p, ">" );
1196
else if( !strncmp( p, " ", 6 ) )
1201
else if( *p == '\t' )
1162
/* Search non empty line */
1163
while( s && *s == '\0' )
1164
s = TextGetLine( txt );
1170
if( !strncasecmp( s, "<br", 3 ) )
1174
else if( strcasestr( s, "Start=" ) )
1176
TextPreviousLine( txt );
1179
s = ParseSamiSearch( txt, s, ">" );
1181
else if( !strncmp( s, " ", 6 ) )
1186
else if( *s == '\t' )
1214
p = TextGetLine( txt );
1196
if( c != '\0' && i_text+1 < sizeof(text) )
1199
text[i_text] = '\0';
1223
1203
p_subtitle->i_start = i_start * 1000;
1224
1204
p_subtitle->i_stop = 0;
1225
p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
1205
p_subtitle->psz_text = strdup( text );
1227
return( VLC_SUCCESS );
1231
static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle )
1217
* TODO it can have a header
1224
* LANG support would be cool
1225
* CODEPAGE is probably mandatory FIXME
1227
static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle,
1230
VLC_UNUSED( i_idx );
1233
1232
demux_sys_t *p_sys = p_demux->p_sys;
1234
1233
text_t *txt = &p_sys->txt;
1245
char buffer_text[ 10 * MAX_LINE];
1249
p_subtitle->i_start = 0;
1250
p_subtitle->i_stop = 0;
1251
p_subtitle->psz_text = NULL;
1238
const char *s = TextGetLine( txt );
1255
1239
int h1, m1, s1, c1;
1256
if( ( s = TextGetLine( txt ) ) == NULL )
1258
return( VLC_EGENERIC );
1242
return VLC_EGENERIC;
1261
1245
"{T %d:%d:%d:%d",
1262
1246
&h1, &m1, &s1, &c1 ) == 4 )
1264
i_start = ( (int64_t)h1 * 3600*1000 +
1265
(int64_t)m1 * 60*1000 +
1266
(int64_t)s1 * 1000 +
1267
(int64_t)c1 * 10) * 1000;
1269
/* Now read text until a line containing "}" */
1270
for( i_buffer_text = 0;; )
1273
if( ( s = TextGetLine( txt ) ) == NULL )
1275
return( VLC_EGENERIC );
1278
i_len = strlen( s );
1279
if( i_len == 1 && s[0] == '}' )
1281
/* "}" -> end of this subtitle */
1282
buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
1283
p_subtitle->i_start = i_start;
1284
p_subtitle->i_stop = 0;
1285
p_subtitle->psz_text = strdup( buffer_text );
1290
if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
1292
memcpy( buffer_text + i_buffer_text,
1295
i_buffer_text += i_len;
1297
buffer_text[i_buffer_text] = '\n';
1248
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1249
(int64_t)m1 * 60*1000 +
1250
(int64_t)s1 * 1000 +
1251
(int64_t)c1 * 10) * 1000;
1252
p_subtitle->i_stop = 0;
1257
/* Now read text until a line containing "}" */
1258
psz_text = strdup("");
1263
const char *s = TextGetLine( txt );
1270
return VLC_EGENERIC;
1273
i_len = strlen( s );
1274
if( i_len == 1 && s[0] == '}')
1276
p_subtitle->psz_text = psz_text;
1280
i_old = strlen( psz_text );
1281
psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1284
strcat( psz_text, s );
1285
strcat( psz_text, "\n" );
1291
* [n1][n2]Line1|Line2|Line3...
1292
* where n1 and n2 are the video frame number (n2 can be empty)
1294
static int ParseMPL2( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1296
VLC_UNUSED( i_idx );
1298
demux_sys_t *p_sys = p_demux->p_sys;
1299
text_t *txt = &p_sys->txt;
1305
const char *s = TextGetLine( txt );
1310
return VLC_EGENERIC;
1312
psz_text = malloc( strlen(s) + 1 );
1318
if( sscanf( s, "[%d][] %[^\r\n]", &i_start, psz_text ) == 2 ||
1319
sscanf( s, "[%d][%d] %[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
1321
p_subtitle->i_start = (int64_t)i_start * 100000;
1322
p_subtitle->i_stop = (int64_t)i_stop * 100000;
1328
for( i = 0; psz_text[i] != '\0'; )
1330
/* replace | by \n */
1331
if( psz_text[i] == '|' )
1335
if( psz_text[i] == '/' && ( i == 0 || psz_text[i-1] == '\n' ) )
1336
memmove( &psz_text[i], &psz_text[i+1], strlen(&psz_text[i+1])+1 );
1340
p_subtitle->psz_text = psz_text;
1344
static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1346
VLC_UNUSED( i_idx );
1348
demux_sys_t *p_sys = p_demux->p_sys;
1349
text_t *txt = &p_sys->txt;
1350
char *psz_text = strdup( "" );
1352
int i_firstline = 1;
1358
const char *s = TextGetLine( txt );
1361
return VLC_EGENERIC;
1364
if( sscanf (s, "-->> %d", &t) == 1)
1366
p_subtitle->i_start = (int64_t)t; /* * FPS*/
1367
p_subtitle->i_stop = 0;
1369
/* Starting of a subtitle */
1374
/* We have been too far: end of the subtitle, begin of next */
1377
TextPreviousLine( txt );
1384
i_old = strlen( psz_text ) + 1;
1385
psz_text = realloc( psz_text, i_old + strlen( s ) + 1 );
1388
strcat( psz_text, s );
1389
strcat( psz_text, "\n" );
1390
if( txt->i_line == txt->i_line_count )
1394
p_subtitle->psz_text = psz_text;
1398
static int ParsePJS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1400
VLC_UNUSED( i_idx );
1402
demux_sys_t *p_sys = p_demux->p_sys;
1403
text_t *txt = &p_sys->txt;
1409
const char *s = TextGetLine( txt );
1413
return VLC_EGENERIC;
1415
psz_text = malloc( strlen(s) + 1 );
1420
if( sscanf (s, "%d,%d,\"%[^\n\r]", &t1, &t2, psz_text ) == 3 )
1422
/* 1/10th of second ? Frame based ? FIXME */
1423
p_subtitle->i_start = 10 * t1;
1424
p_subtitle->i_stop = 10 * t2;
1425
/* Remove latest " */
1426
psz_text[ strlen(psz_text) - 1 ] = '\0';
1433
/* replace | by \n */
1434
for( i = 0; psz_text[i] != '\0'; i++ )
1436
if( psz_text[i] == '|' )
1440
p_subtitle->psz_text = psz_text;
1441
msg_Dbg( p_demux, "%s", psz_text );
1445
static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1447
VLC_UNUSED( i_idx );
1449
demux_sys_t *p_sys = p_demux->p_sys;
1450
text_t *txt = &p_sys->txt;
1451
char *psz_text = strdup( "" );
1453
if( !p_sys->mpsub.b_inited )
1455
p_sys->mpsub.f_total = 0.0;
1456
p_sys->mpsub.f_factor = 0.0;
1458
p_sys->mpsub.b_inited = true;
1467
const char *s = TextGetLine( txt );
1469
return VLC_EGENERIC;
1471
if( strstr( s, "FORMAT" ) )
1473
if( sscanf (s, "FORMAT=TIM%c", &p_dummy ) == 1 && p_dummy == 'E')
1475
p_sys->mpsub.f_factor = 100.0;
1479
psz_temp = malloc( strlen(s) );
1483
if( sscanf( s, "FORMAT=%[^\r\n]", psz_temp ) )
1486
f_fps = us_strtod( psz_temp, NULL );
1487
if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
1488
var_SetFloat( p_demux, "sub-fps", f_fps );
1490
p_sys->mpsub.f_factor = 1.0;
1497
f1 = us_strtod( s, &psz_temp );
1500
f2 = us_strtod( psz_temp, NULL );
1501
p_sys->mpsub.f_total += f1 * p_sys->mpsub.f_factor;
1502
p_subtitle->i_start = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1503
p_sys->mpsub.f_total += f2 * p_sys->mpsub.f_factor;
1504
p_subtitle->i_stop = (int64_t)(10000.0 * p_sys->mpsub.f_total);
1511
const char *s = TextGetLine( txt );
1514
return VLC_EGENERIC;
1516
int i_len = strlen( s );
1520
int i_old = strlen( psz_text );
1522
psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1526
strcat( psz_text, s );
1527
strcat( psz_text, "\n" );
1530
p_subtitle->psz_text = psz_text;
1534
static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1536
VLC_UNUSED( i_idx );
1538
demux_sys_t *p_sys = p_demux->p_sys;
1539
text_t *txt = &p_sys->txt;
1540
char *psz_text, *psz_orig;
1541
char *psz_text2, *psz_orig2;
1542
int h1, h2, m1, m2, s1, s2, f1, f2;
1544
if( !p_sys->jss.b_inited )
1546
p_sys->jss.i_comment = 0;
1547
p_sys->jss.i_time_resolution = 30;
1548
p_sys->jss.i_time_shift = 0;
1550
p_sys->jss.b_inited = true;
1553
/* Parse the main lines */
1556
const char *s = TextGetLine( txt );
1558
return VLC_EGENERIC;
1560
psz_orig = malloc( strlen( s ) + 1 );
1563
psz_text = psz_orig;
1565
/* Complete time lines */
1566
if( sscanf( s, "%d:%d:%d.%d %d:%d:%d.%d %[^\n\r]",
1567
&h1, &m1, &s1, &f1, &h2, &m2, &s2, &f2, psz_text ) == 9 )
1569
p_subtitle->i_start = ( (int64_t)( h1 *3600 + m1 * 60 + s1 ) +
1570
(int64_t)( ( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution ) )
1572
p_subtitle->i_stop = ( (int64_t)( h2 *3600 + m2 * 60 + s2 ) +
1573
(int64_t)( ( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution ) )
1577
/* Short time lines */
1578
else if( sscanf( s, "@%d @%d %[^\n\r]", &f1, &f2, psz_text ) == 3 )
1580
p_subtitle->i_start = (int64_t)(
1581
( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1582
p_subtitle->i_stop = (int64_t)(
1583
( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
1586
/* General Directive lines */
1587
/* Only TIME and SHIFT are supported so far */
1588
else if( s[0] == '#' )
1590
int h = 0, m =0, sec = 1, f = 1;
1594
strcpy( psz_text, s );
1596
switch( toupper( psz_text[1] ) )
1599
shift = isalpha( psz_text[2] ) ? 6 : 2 ;
1601
if( sscanf( &psz_text[shift], "%d", &h ) )
1603
/* Negative shifting */
1610
if( sscanf( &psz_text[shift], "%*d:%d", &m ) )
1612
if( sscanf( &psz_text[shift], "%*d:%*d:%d", &sec ) )
1614
sscanf( &psz_text[shift], "%*d:%*d:%*d.%d", &f );
1619
sscanf( &psz_text[shift], "%d:%d.%d",
1627
sscanf( &psz_text[shift], "%d.%d", &sec, &f);
1630
p_sys->jss.i_time_shift = ( ( h * 3600 + m * 60 + sec )
1631
* p_sys->jss.i_time_resolution + f ) * inv;
1636
shift = isalpha( psz_text[2] ) ? 8 : 2 ;
1638
sscanf( &psz_text[shift], "%d", &p_sys->jss.i_time_resolution );
1645
/* Unkown type line, probably a comment */
1652
while( psz_text[ strlen( psz_text ) - 1 ] == '\\' )
1654
const char *s2 = TextGetLine( txt );
1657
return VLC_EGENERIC;
1659
int i_len = strlen( s2 );
1663
int i_old = strlen( psz_text );
1665
psz_text = realloc( psz_text, i_old + i_len + 1 );
1669
psz_orig = psz_text;
1670
strcat( psz_text, s2 );
1673
/* Skip the blanks */
1674
while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1676
/* Parse the directives */
1677
if( isalpha( *psz_text ) || *psz_text == '[' )
1679
while( *psz_text != ' ' )
1682
/* Directives are NOT parsed yet */
1683
/* This has probably a better place in a decoder ? */
1684
/* directive = malloc( strlen( psz_text ) + 1 );
1685
if( sscanf( psz_text, "%s %[^\n\r]", directive, psz_text2 ) == 2 )*/
1688
/* Skip the blanks after directives */
1689
while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
1691
/* Clean all the lines from inline comments and other stuffs */
1692
psz_orig2 = calloc( strlen( psz_text) + 1, 1 );
1693
psz_text2 = psz_orig2;
1695
for( ; *psz_text != '\0' && *psz_text != '\n' && *psz_text != '\r'; )
1700
p_sys->jss.i_comment++;
1703
if( p_sys->jss.i_comment )
1705
p_sys->jss.i_comment = 0;
1706
if( (*(psz_text + 1 ) ) == ' ' ) psz_text++;
1710
if( !p_sys->jss.i_comment )
1718
if( (*(psz_text + 1 ) ) == ' ' || (*(psz_text + 1 ) ) == '\t' )
1720
if( !p_sys->jss.i_comment )
1727
if( (*(psz_text + 1 ) ) == 'n' )
1734
if( ( toupper(*(psz_text + 1 ) ) == 'C' ) ||
1735
( toupper(*(psz_text + 1 ) ) == 'F' ) )
1737
psz_text++; psz_text++;
1740
if( (*(psz_text + 1 ) ) == 'B' || (*(psz_text + 1 ) ) == 'b' ||
1741
(*(psz_text + 1 ) ) == 'I' || (*(psz_text + 1 ) ) == 'i' ||
1742
(*(psz_text + 1 ) ) == 'U' || (*(psz_text + 1 ) ) == 'u' ||
1743
(*(psz_text + 1 ) ) == 'D' || (*(psz_text + 1 ) ) == 'N' )
1748
if( (*(psz_text + 1 ) ) == '~' || (*(psz_text + 1 ) ) == '{' ||
1749
(*(psz_text + 1 ) ) == '\\' )
1751
else if( *(psz_text + 1 ) == '\r' || *(psz_text + 1 ) == '\n' ||
1752
*(psz_text + 1 ) == '\0' )
1758
if( !p_sys->jss.i_comment )
1760
*psz_text2 = *psz_text;
1767
p_subtitle->psz_text = psz_orig2;
1768
msg_Dbg( p_demux, "%s", p_subtitle->psz_text );
1773
static int ParsePSB( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1775
VLC_UNUSED( i_idx );
1777
demux_sys_t *p_sys = p_demux->p_sys;
1778
text_t *txt = &p_sys->txt;
1786
const char *s = TextGetLine( txt );
1789
return VLC_EGENERIC;
1791
psz_text = malloc( strlen( s ) + 1 );
1795
if( sscanf( s, "{%d:%d:%d}{%d:%d:%d}%[^\r\n]",
1796
&h1, &m1, &s1, &h2, &m2, &s2, psz_text ) == 7 )
1798
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1799
(int64_t)m1 * 60*1000 +
1800
(int64_t)s1 * 1000 ) * 1000;
1801
p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +
1802
(int64_t)m2 * 60*1000 +
1803
(int64_t)s2 * 1000 ) * 1000;
1809
/* replace | by \n */
1810
for( i = 0; psz_text[i] != '\0'; i++ )
1812
if( psz_text[i] == '|' )
1815
p_subtitle->psz_text = psz_text;
1819
static int64_t ParseRealTime( char *psz, int *h, int *m, int *s, int *f )
1821
if( strlen( psz ) == 0 ) return 0;
1822
if( sscanf( psz, "%d:%d:%d.%d", h, m, s, f ) == 4 ||
1823
sscanf( psz, "%d:%d.%d", m, s, f ) == 3 ||
1824
sscanf( psz, "%d.%d", s, f ) == 2 ||
1825
sscanf( psz, "%d:%d", m, s ) == 2 ||
1826
sscanf( psz, "%d", s ) == 1 )
1828
return (int64_t)((( *h * 60 + *m ) * 60 ) + *s ) * 1000 * 1000
1829
+ (int64_t)*f * 10 * 1000;
1831
else return VLC_EGENERIC;
1834
static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1836
VLC_UNUSED( i_idx );
1837
demux_sys_t *p_sys = p_demux->p_sys;
1838
text_t *txt = &p_sys->txt;
1840
char psz_end[12]= "", psz_begin[12] = "";
1844
int h1 = 0, m1 = 0, s1 = 0, f1 = 0;
1845
int h2 = 0, m2 = 0, s2 = 0, f2 = 0;
1846
const char *s = TextGetLine( txt );
1849
return VLC_EGENERIC;
1851
psz_text = malloc( strlen( s ) + 1 );
1855
/* Find the good begining. This removes extra spaces at the beginning
1857
char *psz_temp = strcasestr( s, "<time");
1858
if( psz_temp != NULL )
1860
/* Line has begin and end */
1861
if( ( sscanf( psz_temp,
1862
"<%*[t|T]ime %*[b|B]egin=\"%[^\"]\" %*[e|E]nd=\"%[^\"]%*[^>]%[^\n\r]",
1863
psz_begin, psz_end, psz_text) != 3 ) &&
1864
/* Line has begin and no end */
1866
"<%*[t|T]ime %*[b|B]egin=\"%[^\"]\"%*[^>]%[^\n\r]",
1867
psz_begin, psz_text ) != 2) )
1868
/* Line is not recognized */
1875
int64_t i_time = ParseRealTime( psz_begin, &h1, &m1, &s1, &f1 );
1878
p_subtitle->i_start = i_time;
1881
i_time = ParseRealTime( psz_end, &h2, &m2, &s2, &f2 );
1884
p_subtitle->i_stop = i_time;
1888
/* Line is not recognized */
1893
/* Get the following Lines */
1896
const char *s = TextGetLine( txt );
1899
return VLC_EGENERIC;
1901
int i_len = strlen( s );
1902
if( i_len == 0 ) break;
1904
if( strcasestr( s, "<time" ) ||
1905
strcasestr( s, "<clear/") )
1907
TextPreviousLine( txt );
1911
int i_old = strlen( psz_text );
1913
psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
1917
strcat( psz_text, s );
1918
strcat( psz_text, "\n" );
1921
/* Remove the starting ">" that remained after the sscanf */
1922
memmove( &psz_text[0], &psz_text[1], strlen( psz_text ) );
1924
p_subtitle->psz_text = psz_text;
1929
static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1931
VLC_UNUSED( i_idx );
1933
demux_sys_t *p_sys = p_demux->p_sys;
1934
text_t *txt = &p_sys->txt;
1941
char *s = TextGetLine( txt );
1944
return VLC_EGENERIC;
1946
psz_text = malloc( strlen( s ) + 1 );
1950
if( sscanf( s, "[%d:%d:%d]%[^\r\n]",
1951
&h1, &m1, &s1, psz_text ) == 4 )
1953
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
1954
(int64_t)m1 * 60*1000 +
1955
(int64_t)s1 * 1000 ) * 1000;
1957
char *s = TextGetLine( txt );
1959
return VLC_EGENERIC;
1961
if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
1962
p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +
1963
(int64_t)m2 * 60*1000 +
1964
(int64_t)s2 * 1000 ) * 1000;
1970
/* replace [br] by \n */
1972
while( ( p = strstr( psz_text, "[br]" ) ) )
1975
memmove( p, &p[3], strlen(&p[3])+1 );
1978
p_subtitle->psz_text = psz_text;
1982
static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1984
VLC_UNUSED( i_idx );
1986
demux_sys_t *p_sys = p_demux->p_sys;
1987
text_t *txt = &p_sys->txt;
1994
char *s = TextGetLine( txt );
1997
return VLC_EGENERIC;
1999
if( sscanf( s, "[%d:%d:%d]", &h1, &m1, &s1 ) == 3 )
2001
p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
2002
(int64_t)m1 * 60*1000 +
2003
(int64_t)s1 * 1000 ) * 1000;
2005
char *s = TextGetLine( txt );
2007
return VLC_EGENERIC;
2009
psz_text = strdup( s );
2013
s = TextGetLine( txt );
2015
return VLC_EGENERIC;
2017
if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
2018
p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +
2019
(int64_t)m2 * 60*1000 +
2020
(int64_t)s2 * 1000 ) * 1000;
2025
p_subtitle->psz_text = psz_text;