00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029
00030 #include <errno.h>
00031 #ifdef HAVE_SYS_TYPES_H
00032 # include <sys/types.h>
00033 #endif
00034 #include <ctype.h>
00035
00036 #include <vlc/vlc.h>
00037 #include <vlc/input.h>
00038 #include "vlc_video.h"
00039
00040
00041
00042
00043 static int Open ( vlc_object_t *p_this );
00044 static void Close( vlc_object_t *p_this );
00045
00046 #define SUB_DELAY_LONGTEXT \
00047 "Delay subtitles (in 1/10s)"
00048 #define SUB_FPS_LONGTEXT \
00049 "Override frames per second. " \
00050 "It will only work with MicroDVD subtitles."
00051 #define SUB_TYPE_LONGTEXT \
00052 "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\" " \
00053 "\"sami\" (auto for autodetection, it should always work)."
00054 static char *ppsz_sub_type[] =
00055 {
00056 "auto", "microdvd", "subrip", "subviewer", "ssa1",
00057 "ssa2-4", "ass", "vplayer", "sami"
00058 };
00059
00060 vlc_module_begin();
00061 set_shortname( _("Subtitles"));
00062 set_description( _("Text subtitles demux") );
00063 set_capability( "demux2", 0 );
00064 set_category( CAT_INPUT );
00065 set_subcategory( SUBCAT_INPUT_DEMUX );
00066 add_float( "sub-fps", 0.0, NULL,
00067 N_("Frames per second"),
00068 SUB_FPS_LONGTEXT, VLC_TRUE );
00069 add_integer( "sub-delay", 0, NULL,
00070 N_("Subtitles delay"),
00071 SUB_DELAY_LONGTEXT, VLC_TRUE );
00072 add_string( "sub-type", "auto", NULL, "Subtitles fileformat",
00073 SUB_TYPE_LONGTEXT, VLC_TRUE );
00074 change_string_list( ppsz_sub_type, 0, 0 );
00075 set_callbacks( Open, Close );
00076
00077 add_shortcut( "subtitle" );
00078 vlc_module_end();
00079
00080
00081
00082
00083 enum
00084 {
00085 SUB_TYPE_UNKNOWN = -1,
00086 SUB_TYPE_MICRODVD,
00087 SUB_TYPE_SUBRIP,
00088 SUB_TYPE_SSA1,
00089 SUB_TYPE_SSA2_4,
00090 SUB_TYPE_ASS,
00091 SUB_TYPE_VPLAYER,
00092 SUB_TYPE_SAMI,
00093 SUB_TYPE_SUBVIEWER,
00094 };
00095
00096 typedef struct
00097 {
00098 int i_line_count;
00099 int i_line;
00100 char **line;
00101 } text_t;
00102 static int TextLoad( text_t *, stream_t *s );
00103 static void TextUnload( text_t * );
00104
00105 typedef struct
00106 {
00107 int64_t i_start;
00108 int64_t i_stop;
00109
00110 char *psz_text;
00111 } subtitle_t;
00112
00113
00114 struct demux_sys_t
00115 {
00116 int i_type;
00117 text_t txt;
00118 es_out_id_t *es;
00119
00120 int64_t i_next_demux_date;
00121
00122 int64_t i_microsecperframe;
00123 int64_t i_original_mspf;
00124
00125 char *psz_header;
00126 int i_subtitle;
00127 int i_subtitles;
00128 subtitle_t *subtitle;
00129
00130 int64_t i_length;
00131 };
00132
00133 static int ParseMicroDvd ( demux_t *, subtitle_t * );
00134 static int ParseSubRip ( demux_t *, subtitle_t * );
00135 static int ParseSubViewer( demux_t *, subtitle_t * );
00136 static int ParseSSA ( demux_t *, subtitle_t * );
00137 static int ParseVplayer ( demux_t *, subtitle_t * );
00138 static int ParseSami ( demux_t *, subtitle_t * );
00139
00140 static struct
00141 {
00142 char *psz_type_name;
00143 int i_type;
00144 char *psz_name;
00145 int (*pf_read)( demux_t *, subtitle_t* );
00146 } sub_read_subtitle_function [] =
00147 {
00148 { "microdvd", SUB_TYPE_MICRODVD, "MicroDVD", ParseMicroDvd },
00149 { "subrip", SUB_TYPE_SUBRIP, "SubRIP", ParseSubRip },
00150 { "subviewer", SUB_TYPE_SUBVIEWER, "SubViewer",ParseSubViewer },
00151 { "ssa1", SUB_TYPE_SSA1, "SSA-1", ParseSSA },
00152 { "ssa2-4", SUB_TYPE_SSA2_4, "SSA-2/3/4",ParseSSA },
00153 { "ass", SUB_TYPE_ASS, "SSA/ASS", ParseSSA },
00154 { "vplayer", SUB_TYPE_VPLAYER, "VPlayer", ParseVplayer },
00155 { "sami", SUB_TYPE_SAMI, "SAMI", ParseSami },
00156 { NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL }
00157 };
00158
00159 static int Demux( demux_t * );
00160 static int Control( demux_t *, int, va_list );
00161
00162
00163
00164
00165
00166
00167 static int Open ( vlc_object_t *p_this )
00168 {
00169 demux_t *p_demux = (demux_t*)p_this;
00170 demux_sys_t *p_sys;
00171 es_format_t fmt;
00172 float f_fps;
00173 char *psz_type;
00174 int (*pf_read)( demux_t *, subtitle_t* );
00175 int i, i_max;
00176
00177 if( strcmp( p_demux->psz_demux, "subtitle" ) )
00178 {
00179 msg_Dbg( p_demux, "subtitle demux discarded" );
00180 return VLC_EGENERIC;
00181 }
00182
00183 p_demux->pf_demux = Demux;
00184 p_demux->pf_control = Control;
00185 p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00186 p_sys->psz_header = NULL;
00187 p_sys->i_subtitle = 0;
00188 p_sys->i_subtitles= 0;
00189 p_sys->subtitle = NULL;
00190
00191
00192
00193 f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
00194 if( f_fps >= 1.0 )
00195 {
00196 p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
00197 }
00198 else
00199 {
00200 p_sys->i_microsecperframe = 0;
00201 }
00202
00203 f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" );
00204 if( f_fps >= 1.0 )
00205 {
00206 p_sys->i_original_mspf = (int64_t)( (float)1000000 / f_fps );
00207 }
00208 else
00209 {
00210 p_sys->i_original_mspf = 0;
00211 }
00212
00213
00214 p_sys->i_type = SUB_TYPE_UNKNOWN;
00215 psz_type = var_CreateGetString( p_demux, "sub-type" );
00216 if( *psz_type )
00217 {
00218 int i;
00219
00220 for( i = 0; ; i++ )
00221 {
00222 if( sub_read_subtitle_function[i].psz_type_name == NULL )
00223 break;
00224
00225 if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
00226 psz_type ) )
00227 {
00228 p_sys->i_type = sub_read_subtitle_function[i].i_type;
00229 break;
00230 }
00231 }
00232 }
00233 free( psz_type );
00234
00235
00236 if( p_sys->i_type == SUB_TYPE_UNKNOWN )
00237 {
00238 int i_try;
00239 char *s = NULL;
00240
00241 msg_Dbg( p_demux, "autodetecting subtitle format" );
00242 for( i_try = 0; i_try < 256; i_try++ )
00243 {
00244 int i_dummy;
00245
00246 if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
00247 break;
00248
00249 if( strcasestr( s, "<SAMI>" ) )
00250 {
00251 p_sys->i_type = SUB_TYPE_SAMI;
00252 break;
00253 }
00254 else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
00255 sscanf( s, "{%d}{}", &i_dummy ) == 1)
00256 {
00257 p_sys->i_type = SUB_TYPE_MICRODVD;
00258 break;
00259 }
00260 else if( sscanf( s,
00261 "%d:%d:%d,%d --> %d:%d:%d,%d",
00262 &i_dummy,&i_dummy,&i_dummy,&i_dummy,
00263 &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
00264 {
00265 p_sys->i_type = SUB_TYPE_SUBRIP;
00266 break;
00267 }
00268 else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) )
00269 {
00270 p_sys->i_type = SUB_TYPE_SSA1;
00271 break;
00272 }
00273 else if( !strncasecmp( s, "ScriptType: v4.00+", 18 ) )
00274 {
00275 p_sys->i_type = SUB_TYPE_ASS;
00276 break;
00277 }
00278 else if( !strncasecmp( s, "ScriptType: v4.00", 17 ) )
00279 {
00280 p_sys->i_type = SUB_TYPE_SSA2_4;
00281 break;
00282 }
00283 else if( !strncasecmp( s, "Dialogue: Marked", 16 ) )
00284 {
00285 p_sys->i_type = SUB_TYPE_SSA2_4;
00286 break;
00287 }
00288 else if( !strncasecmp( s, "Dialogue:", 9 ) )
00289 {
00290 p_sys->i_type = SUB_TYPE_ASS;
00291 break;
00292 }
00293 else if( strcasestr( s, "[INFORMATION]" ) )
00294 {
00295 p_sys->i_type = SUB_TYPE_SUBVIEWER;
00296 break;
00297 }
00298 else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
00299 sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
00300 {
00301 p_sys->i_type = SUB_TYPE_VPLAYER;
00302 break;
00303 }
00304
00305 free( s );
00306 s = NULL;
00307 }
00308
00309 if( s ) free( s );
00310
00311
00312
00313 if( stream_Seek( p_demux->s, 0 ) )
00314 {
00315 msg_Warn( p_demux, "failed to rewind" );
00316 }
00317 }
00318 if( p_sys->i_type == SUB_TYPE_UNKNOWN )
00319 {
00320 msg_Err( p_demux, "failed to recognize subtitle type" );
00321 free( p_sys );
00322 return VLC_EGENERIC;
00323 }
00324
00325 for( i = 0; ; i++ )
00326 {
00327 if( sub_read_subtitle_function[i].i_type == p_sys->i_type )
00328 {
00329 msg_Dbg( p_demux, "detected %s format",
00330 sub_read_subtitle_function[i].psz_name );
00331 pf_read = sub_read_subtitle_function[i].pf_read;
00332 break;
00333 }
00334 }
00335
00336 msg_Dbg( p_demux, "loading all subtitles..." );
00337
00338
00339 TextLoad( &p_sys->txt, p_demux->s );
00340
00341
00342 for( i_max = 0;; )
00343 {
00344 if( p_sys->i_subtitles >= i_max )
00345 {
00346 i_max += 500;
00347 if( !( p_sys->subtitle = realloc( p_sys->subtitle,
00348 sizeof(subtitle_t) * i_max ) ) )
00349 {
00350 msg_Err( p_demux, "out of memory");
00351 if( p_sys->subtitle != NULL )
00352 free( p_sys->subtitle );
00353 TextUnload( &p_sys->txt );
00354 free( p_sys );
00355 return VLC_ENOMEM;
00356 }
00357 }
00358
00359 if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles] ) )
00360 break;
00361
00362 p_sys->i_subtitles++;
00363 }
00364
00365 TextUnload( &p_sys->txt );
00366
00367 msg_Dbg(p_demux, "loaded %d subtitles", p_sys->i_subtitles );
00368
00369
00370 p_sys->i_subtitle = 0;
00371 p_sys->i_length = 0;
00372 if( p_sys->i_subtitles > 0 )
00373 {
00374 p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_stop;
00375
00376 if( p_sys->i_length <= 0 )
00377 p_sys->i_length = p_sys->subtitle[p_sys->i_subtitles-1].i_start+1;
00378 }
00379
00380
00381 if( p_sys->i_type == SUB_TYPE_SSA1 ||
00382 p_sys->i_type == SUB_TYPE_SSA2_4 ||
00383 p_sys->i_type == SUB_TYPE_ASS )
00384 {
00385 es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
00386 }
00387 else
00388 {
00389 es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
00390 }
00391 if( p_sys->psz_header != NULL )
00392 {
00393 fmt.i_extra = strlen( p_sys->psz_header ) + 1;
00394 fmt.p_extra = strdup( p_sys->psz_header );
00395 }
00396 p_sys->es = es_out_Add( p_demux->out, &fmt );
00397
00398 return VLC_SUCCESS;
00399 }
00400
00401
00402
00403
00404 static void Close( vlc_object_t *p_this )
00405 {
00406 demux_t *p_demux = (demux_t*)p_this;
00407 demux_sys_t *p_sys = p_demux->p_sys;
00408 int i;
00409
00410 for( i = 0; i < p_sys->i_subtitles; i++ )
00411 {
00412 if( p_sys->subtitle[i].psz_text )
00413 free( p_sys->subtitle[i].psz_text );
00414 }
00415 if( p_sys->subtitle )
00416 free( p_sys->subtitle );
00417
00418 free( p_sys );
00419 }
00420
00421
00422
00423
00424 static int Control( demux_t *p_demux, int i_query, va_list args )
00425 {
00426 demux_sys_t *p_sys = p_demux->p_sys;
00427 int64_t *pi64, i64;
00428 double *pf, f;
00429
00430 switch( i_query )
00431 {
00432 case DEMUX_GET_LENGTH:
00433 pi64 = (int64_t*)va_arg( args, int64_t * );
00434 *pi64 = p_sys->i_length;
00435 return VLC_SUCCESS;
00436
00437 case DEMUX_GET_TIME:
00438 pi64 = (int64_t*)va_arg( args, int64_t * );
00439 if( p_sys->i_subtitle < p_sys->i_subtitles )
00440 {
00441 *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
00442 return VLC_SUCCESS;
00443 }
00444 return VLC_EGENERIC;
00445
00446 case DEMUX_SET_TIME:
00447 i64 = (int64_t)va_arg( args, int64_t );
00448 p_sys->i_subtitle = 0;
00449 while( p_sys->i_subtitle < p_sys->i_subtitles &&
00450 p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
00451 {
00452 p_sys->i_subtitle++;
00453 }
00454
00455 if( p_sys->i_subtitle >= p_sys->i_subtitles )
00456 return VLC_EGENERIC;
00457 return VLC_SUCCESS;
00458
00459 case DEMUX_GET_POSITION:
00460 pf = (double*)va_arg( args, double * );
00461 if( p_sys->i_subtitle >= p_sys->i_subtitles )
00462 {
00463 *pf = 1.0;
00464 }
00465 else if( p_sys->i_subtitles > 0 )
00466 {
00467 *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
00468 (double)p_sys->i_length;
00469 }
00470 else
00471 {
00472 *pf = 0.0;
00473 }
00474 return VLC_SUCCESS;
00475
00476 case DEMUX_SET_POSITION:
00477 f = (double)va_arg( args, double );
00478 i64 = f * p_sys->i_length;
00479
00480 p_sys->i_subtitle = 0;
00481 while( p_sys->i_subtitle < p_sys->i_subtitles &&
00482 p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
00483 {
00484 p_sys->i_subtitle++;
00485 }
00486 if( p_sys->i_subtitle >= p_sys->i_subtitles )
00487 return VLC_EGENERIC;
00488 return VLC_SUCCESS;
00489
00490 case DEMUX_SET_NEXT_DEMUX_TIME:
00491 p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
00492 return VLC_SUCCESS;
00493
00494 case DEMUX_GET_FPS:
00495 case DEMUX_GET_META:
00496 case DEMUX_GET_TITLE_INFO:
00497 return VLC_EGENERIC;
00498
00499 default:
00500 msg_Err( p_demux, "unknown query in subtitle control" );
00501 return VLC_EGENERIC;
00502 }
00503 }
00504
00505
00506
00507
00508 static int Demux( demux_t *p_demux )
00509 {
00510 demux_sys_t *p_sys = p_demux->p_sys;
00511 int64_t i_maxdate;
00512
00513 if( p_sys->i_subtitle >= p_sys->i_subtitles )
00514 return 0;
00515
00516 i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );;
00517 if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
00518 {
00519
00520 i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
00521 }
00522
00523 while( p_sys->i_subtitle < p_sys->i_subtitles &&
00524 p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
00525 {
00526 block_t *p_block;
00527 int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1;
00528
00529 if( i_len <= 1 )
00530 {
00531
00532 p_sys->i_subtitle++;
00533 continue;
00534 }
00535
00536 if( ( p_block = block_New( p_demux, i_len ) ) == NULL )
00537 {
00538 p_sys->i_subtitle++;
00539 continue;
00540 }
00541
00542 if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 )
00543 {
00544 p_sys->i_subtitle++;
00545 continue;
00546 }
00547
00548 p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start;
00549 p_block->i_dts = p_block->i_pts;
00550 if( p_sys->subtitle[p_sys->i_subtitle].i_stop > 0 )
00551 {
00552 p_block->i_length =
00553 p_sys->subtitle[p_sys->i_subtitle].i_stop - p_block->i_pts;
00554 }
00555
00556 memcpy( p_block->p_buffer,
00557 p_sys->subtitle[p_sys->i_subtitle].psz_text, i_len );
00558 if( p_block->i_pts > 0 )
00559 {
00560 es_out_Send( p_demux->out, p_sys->es, p_block );
00561 }
00562 else
00563 {
00564 block_Release( p_block );
00565 }
00566 p_sys->i_subtitle++;
00567 }
00568
00569
00570 p_sys->i_next_demux_date = 0;
00571
00572 return 1;
00573 }
00574
00575
00576
00577
00578 #ifdef USE_THIS_UNUSED_PIECE_OF_CODE
00579 static void Fix( demux_t *p_demux )
00580 {
00581 demux_sys_t *p_sys = p_demux->p_sys;
00582 vlc_bool_t b_done;
00583 int i_index;
00584
00585
00586
00587
00588
00589 do
00590 {
00591 b_done = VLC_TRUE;
00592 for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
00593 {
00594 if( p_sys->subtitle[i_index].i_start <
00595 p_sys->subtitle[i_index - 1].i_start )
00596 {
00597 subtitle_t sub_xch;
00598 memcpy( &sub_xch,
00599 p_sys->subtitle + i_index - 1,
00600 sizeof( subtitle_t ) );
00601 memcpy( p_sys->subtitle + i_index - 1,
00602 p_sys->subtitle + i_index,
00603 sizeof( subtitle_t ) );
00604 memcpy( p_sys->subtitle + i_index,
00605 &sub_xch,
00606 sizeof( subtitle_t ) );
00607 b_done = VLC_FALSE;
00608 }
00609 }
00610 } while( !b_done );
00611 }
00612 #endif
00613
00614 static int TextLoad( text_t *txt, stream_t *s )
00615 {
00616 int i_line_max;
00617
00618
00619 i_line_max = 500;
00620 txt->i_line_count = 0;
00621 txt->i_line = 0;
00622 txt->line = calloc( i_line_max, sizeof( char * ) );
00623
00624
00625 for( ;; )
00626 {
00627 char *psz = stream_ReadLine( s );
00628
00629 if( psz == NULL )
00630 break;
00631
00632 txt->line[txt->i_line_count++] = psz;
00633 if( txt->i_line_count >= i_line_max )
00634 {
00635 i_line_max += 100;
00636 txt->line = realloc( txt->line, i_line_max * sizeof( char * ) );
00637 }
00638 }
00639
00640 if( txt->i_line_count <= 0 )
00641 {
00642 free( txt->line );
00643 return VLC_EGENERIC;
00644 }
00645
00646 return VLC_SUCCESS;
00647 }
00648 static void TextUnload( text_t *txt )
00649 {
00650 int i;
00651
00652 for( i = 0; i < txt->i_line_count; i++ )
00653 {
00654 free( txt->line[i] );
00655 }
00656 free( txt->line );
00657 txt->i_line = 0;
00658 txt->i_line_count = 0;
00659 }
00660
00661 static char *TextGetLine( text_t *txt )
00662 {
00663 if( txt->i_line >= txt->i_line_count )
00664 return( NULL );
00665
00666 return txt->line[txt->i_line++];
00667 }
00668 static void TextPreviousLine( text_t *txt )
00669 {
00670 if( txt->i_line > 0 )
00671 txt->i_line--;
00672 }
00673
00674
00675
00676
00677 #define MAX_LINE 8192
00678 static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
00679 {
00680 demux_sys_t *p_sys = p_demux->p_sys;
00681 text_t *txt = &p_sys->txt;
00682
00683
00684
00685
00686
00687
00688 char *s;
00689
00690 char buffer_text[MAX_LINE + 1];
00691 int i_start;
00692 int i_stop;
00693 unsigned int i;
00694
00695 int i_microsecperframe = 40000;
00696 if( p_sys->i_microsecperframe > 0 )
00697 i_microsecperframe = p_sys->i_microsecperframe;
00698
00699 p_subtitle->i_start = 0;
00700 p_subtitle->i_stop = 0;
00701 p_subtitle->psz_text = NULL;
00702
00703 for( ;; )
00704 {
00705 if( ( s = TextGetLine( txt ) ) == NULL )
00706 {
00707 return( VLC_EGENERIC );
00708 }
00709 i_start = 0;
00710 i_stop = 0;
00711
00712 memset( buffer_text, '\0', MAX_LINE );
00713 if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
00714 sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
00715 {
00716 break;
00717 }
00718 }
00719
00720 for( i = 0; i < strlen( buffer_text ); i++ )
00721 {
00722 if( buffer_text[i] == '|' )
00723 {
00724 buffer_text[i] = '\n';
00725 }
00726 }
00727
00728 p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
00729 p_subtitle->i_stop = (int64_t)i_stop * i_microsecperframe;
00730 p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
00731 return( 0 );
00732 }
00733
00734 static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle )
00735 {
00736 demux_sys_t *p_sys = p_demux->p_sys;
00737 text_t *txt = &p_sys->txt;
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748 char *s;
00749 char buffer_text[ 10 * MAX_LINE];
00750 int i_buffer_text;
00751 int64_t i_start;
00752 int64_t i_stop;
00753
00754 p_subtitle->i_start = 0;
00755 p_subtitle->i_stop = 0;
00756 p_subtitle->psz_text = NULL;
00757
00758 for( ;; )
00759 {
00760 int h1, m1, s1, d1, h2, m2, s2, d2;
00761 if( ( s = TextGetLine( txt ) ) == NULL )
00762 {
00763 return( VLC_EGENERIC );
00764 }
00765 if( sscanf( s,
00766 "%d:%d:%d,%d --> %d:%d:%d,%d",
00767 &h1, &m1, &s1, &d1,
00768 &h2, &m2, &s2, &d2 ) == 8 )
00769 {
00770 i_start = ( (int64_t)h1 * 3600*1000 +
00771 (int64_t)m1 * 60*1000 +
00772 (int64_t)s1 * 1000 +
00773 (int64_t)d1 ) * 1000;
00774
00775 i_stop = ( (int64_t)h2 * 3600*1000 +
00776 (int64_t)m2 * 60*1000 +
00777 (int64_t)s2 * 1000 +
00778 (int64_t)d2 ) * 1000;
00779
00780
00781 for( i_buffer_text = 0;; )
00782 {
00783 int i_len;
00784 if( ( s = TextGetLine( txt ) ) == NULL )
00785 {
00786 return( VLC_EGENERIC );
00787 }
00788
00789 i_len = strlen( s );
00790 if( i_len <= 0 )
00791 {
00792
00793 buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
00794 p_subtitle->i_start = i_start;
00795 p_subtitle->i_stop = i_stop;
00796 p_subtitle->psz_text = strdup( buffer_text );
00797
00798 if( p_sys->i_microsecperframe != 0 &&
00799 p_sys->i_original_mspf != 0)
00800 {
00801 p_subtitle->i_start = (int64_t)i_start *
00802 p_sys->i_microsecperframe/
00803 p_sys->i_original_mspf;
00804 p_subtitle->i_stop = (int64_t)i_stop *
00805 p_sys->i_microsecperframe /
00806 p_sys->i_original_mspf;
00807 }
00808 return 0;
00809 }
00810 else
00811 {
00812 if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
00813 {
00814 memcpy( buffer_text + i_buffer_text,
00815 s,
00816 i_len );
00817 i_buffer_text += i_len;
00818
00819 buffer_text[i_buffer_text] = '\n';
00820 i_buffer_text++;
00821 }
00822 }
00823 }
00824 }
00825 }
00826 }
00827
00828 static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle )
00829 {
00830 demux_sys_t *p_sys = p_demux->p_sys;
00831 text_t *txt = &p_sys->txt;
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 char *s;
00842 char buffer_text[ 10 * MAX_LINE];
00843 int i_buffer_text;
00844 int64_t i_start;
00845 int64_t i_stop;
00846
00847 p_subtitle->i_start = 0;
00848 p_subtitle->i_stop = 0;
00849 p_subtitle->psz_text = NULL;
00850
00851 for( ;; )
00852 {
00853 int h1, m1, s1, d1, h2, m2, s2, d2;
00854 if( ( s = TextGetLine( txt ) ) == NULL )
00855 {
00856 return( VLC_EGENERIC );
00857 }
00858 if( sscanf( s,
00859 "%d:%d:%d.%d,%d:%d:%d.%d",
00860 &h1, &m1, &s1, &d1,
00861 &h2, &m2, &s2, &d2 ) == 8 )
00862 {
00863 i_start = ( (int64_t)h1 * 3600*1000 +
00864 (int64_t)m1 * 60*1000 +
00865 (int64_t)s1 * 1000 +
00866 (int64_t)d1 ) * 1000;
00867
00868 i_stop = ( (int64_t)h2 * 3600*1000 +
00869 (int64_t)m2 * 60*1000 +
00870 (int64_t)s2 * 1000 +
00871 (int64_t)d2 ) * 1000;
00872
00873
00874 for( i_buffer_text = 0;; )
00875 {
00876 int i_len, i;
00877 if( ( s = TextGetLine( txt ) ) == NULL )
00878 {
00879 return( VLC_EGENERIC );
00880 }
00881
00882 i_len = strlen( s );
00883 if( i_len <= 0 )
00884 {
00885
00886 buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
00887 p_subtitle->i_start = i_start;
00888 p_subtitle->i_stop = i_stop;
00889
00890
00891 for( i = 0; i < i_buffer_text - 3; i++ )
00892 {
00893 if( buffer_text[i] == '[' && buffer_text[i+1] == 'b' &&
00894 buffer_text[i+2] == 'r' && buffer_text[i+3] == ']' )
00895 {
00896 char *temp = buffer_text + i + 1;
00897 buffer_text[i] = '\n';
00898 memmove( temp, temp+3, strlen( temp ) -3 );
00899 temp[strlen( temp )-3] = '\0';
00900 }
00901 }
00902 p_subtitle->psz_text = strdup( buffer_text );
00903 return( 0 );
00904 }
00905 else
00906 {
00907 if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
00908 {
00909 memcpy( buffer_text + i_buffer_text,
00910 s,
00911 i_len );
00912 i_buffer_text += i_len;
00913
00914 buffer_text[i_buffer_text] = '\n';
00915 i_buffer_text++;
00916 }
00917 }
00918 }
00919 }
00920 }
00921 }
00922
00923
00924 static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
00925 {
00926 demux_sys_t *p_sys = p_demux->p_sys;
00927 text_t *txt = &p_sys->txt;
00928
00929 char buffer_text[ 10 * MAX_LINE];
00930 char buffer_text2[ 10 * MAX_LINE];
00931 char *s;
00932 int64_t i_start;
00933 int64_t i_stop;
00934
00935 p_subtitle->i_start = 0;
00936 p_subtitle->i_stop = 0;
00937 p_subtitle->psz_text = NULL;
00938
00939 for( ;; )
00940 {
00941 int h1, m1, s1, c1, h2, m2, s2, c2;
00942
00943 if( ( s = TextGetLine( txt ) ) == NULL )
00944 {
00945 return( VLC_EGENERIC );
00946 }
00947 p_subtitle->psz_text = malloc( strlen( s ) );
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960 if( sscanf( s,
00961 "Dialogue: %[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
00962 buffer_text2,
00963 &h1, &m1, &s1, &c1,
00964 &h2, &m2, &s2, &c2,
00965 buffer_text ) == 10 )
00966 {
00967 i_start = ( (int64_t)h1 * 3600*1000 +
00968 (int64_t)m1 * 60*1000 +
00969 (int64_t)s1 * 1000 +
00970 (int64_t)c1 * 10 ) * 1000;
00971
00972 i_stop = ( (int64_t)h2 * 3600*1000 +
00973 (int64_t)m2 * 60*1000 +
00974 (int64_t)s2 * 1000 +
00975 (int64_t)c2 * 10 ) * 1000;
00976
00977
00978
00979 if( p_sys->i_type == SUB_TYPE_SSA1 )
00980 {
00981 sprintf( p_subtitle->psz_text,
00982 ",%s", strdup( buffer_text) );
00983 }
00984 else
00985 {
00986 sprintf( p_subtitle->psz_text,
00987 ",,%s", strdup( buffer_text) );
00988 }
00989 p_subtitle->i_start = i_start;
00990 p_subtitle->i_stop = i_stop;
00991 return 0;
00992 }
00993 else
00994 {
00995
00996 if( p_sys->psz_header != NULL )
00997 {
00998 if( !( p_sys->psz_header = realloc( p_sys->psz_header,
00999 strlen( p_sys->psz_header ) + 1 + strlen( s ) + 2 ) ) )
01000 {
01001 msg_Err( p_demux, "out of memory");
01002 return VLC_ENOMEM;
01003 }
01004 p_sys->psz_header = strcat( p_sys->psz_header, s );
01005 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
01006 }
01007 else
01008 {
01009 if( !( p_sys->psz_header = malloc( strlen( s ) + 2 ) ) )
01010 {
01011 msg_Err( p_demux, "out of memory");
01012 return VLC_ENOMEM;
01013 }
01014 p_sys->psz_header = s;
01015 p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
01016 }
01017 }
01018 }
01019 }
01020
01021 static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle )
01022 {
01023 demux_sys_t *p_sys = p_demux->p_sys;
01024 text_t *txt = &p_sys->txt;
01025
01026
01027
01028
01029
01030
01031
01032
01033 char *p;
01034 char buffer_text[MAX_LINE + 1];
01035 int64_t i_start;
01036 unsigned int i;
01037
01038 p_subtitle->i_start = 0;
01039 p_subtitle->i_stop = 0;
01040 p_subtitle->psz_text = NULL;
01041
01042 for( ;; )
01043 {
01044 int h, m, s;
01045 char c;
01046
01047 if( ( p = TextGetLine( txt ) ) == NULL )
01048 {
01049 return( VLC_EGENERIC );
01050 }
01051
01052 i_start = 0;
01053
01054 memset( buffer_text, '\0', MAX_LINE );
01055 if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
01056 {
01057 i_start = ( (int64_t)h * 3600*1000 +
01058 (int64_t)m * 60*1000 +
01059 (int64_t)s * 1000 ) * 1000;
01060 break;
01061 }
01062 }
01063
01064
01065 for( i = 0; i < strlen( buffer_text ); i++ )
01066 {
01067 if( buffer_text[i] == '|' )
01068 {
01069 buffer_text[i] = '\n';
01070 }
01071 }
01072 p_subtitle->i_start = i_start;
01073
01074 p_subtitle->i_stop = 0;
01075 p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
01076 return( 0 );
01077 }
01078
01079 static char *ParseSamiSearch( text_t *txt, char *psz_start, char *psz_str )
01080 {
01081 if( psz_start )
01082 {
01083 if( strcasestr( psz_start, psz_str ) )
01084 {
01085 char *s = strcasestr( psz_start, psz_str );
01086
01087 s += strlen( psz_str );
01088
01089 return( s );
01090 }
01091 }
01092 for( ;; )
01093 {
01094 char *p;
01095 if( ( p = TextGetLine( txt ) ) == NULL )
01096 {
01097 return NULL;
01098 }
01099 if( strcasestr( p, psz_str ) )
01100 {
01101 char *s = strcasestr( p, psz_str );
01102
01103 s += strlen( psz_str );
01104
01105 return( s);
01106 }
01107 }
01108 }
01109
01110 static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle )
01111 {
01112 demux_sys_t *p_sys = p_demux->p_sys;
01113 text_t *txt = &p_sys->txt;
01114
01115 char *p;
01116 int64_t i_start;
01117
01118 int i_text;
01119 char buffer_text[10*MAX_LINE + 1];
01120
01121 p_subtitle->i_start = 0;
01122 p_subtitle->i_stop = 0;
01123 p_subtitle->psz_text = NULL;
01124
01125 #define ADDC( c ) \
01126 if( i_text < 10*MAX_LINE ) \
01127 { \
01128 buffer_text[i_text++] = c; \
01129 buffer_text[i_text] = '\0'; \
01130 }
01131
01132
01133 if( !( p = ParseSamiSearch( txt, NULL, "Start=" ) ) )
01134 {
01135 return VLC_EGENERIC;
01136 }
01137
01138
01139 i_start = strtol( p, &p, 0 );
01140
01141
01142 if( !( p = ParseSamiSearch( txt, p, "<P" ) ) )
01143 {
01144 return VLC_EGENERIC;
01145 }
01146
01147 if( !( p = ParseSamiSearch( txt, p, ">" ) ) )
01148 {
01149 return VLC_EGENERIC;
01150 }
01151
01152 i_text = 0;
01153 buffer_text[0] = '\0';
01154
01155 for( ;; )
01156 {
01157 if( *p )
01158 {
01159 if( *p == '<' )
01160 {
01161 if( !strncasecmp( p, "<br", 3 ) )
01162 {
01163 ADDC( '\n' );
01164 }
01165 else if( strcasestr( p, "Start=" ) )
01166 {
01167 TextPreviousLine( txt );
01168 break;
01169 }
01170 p = ParseSamiSearch( txt, p, ">" );
01171 }
01172 else if( !strncmp( p, " ", 6 ) )
01173 {
01174 ADDC( ' ' );
01175 p += 6;
01176 }
01177 else if( *p == '\t' )
01178 {
01179 ADDC( ' ' );
01180 p++;
01181 }
01182 else
01183 {
01184 ADDC( *p );
01185 p++;
01186 }
01187 }
01188 else
01189 {
01190 p = TextGetLine( txt );
01191 }
01192
01193 if( p == NULL )
01194 {
01195 break;
01196 }
01197 }
01198
01199 p_subtitle->i_start = i_start * 1000;
01200 p_subtitle->i_stop = 0;
01201 p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
01202
01203 return( VLC_SUCCESS );
01204 #undef ADDC
01205 }