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 #include <sys/types.h>
00032
00033 #include <vlc/vlc.h>
00034 #include <vlc/input.h>
00035 #include "vlc_video.h"
00036
00037 #include "ps.h"
00038
00039 #define MAX_LINE 8192
00040
00041
00042
00043
00044 static int Open ( vlc_object_t *p_this );
00045 static void Close( vlc_object_t *p_this );
00046
00047 vlc_module_begin();
00048 set_description( _("Vobsub subtitles demux") );
00049 set_category( CAT_INPUT );
00050 set_subcategory( SUBCAT_INPUT_DEMUX );
00051 set_capability( "demux2", 1 );
00052
00053 set_callbacks( Open, Close );
00054
00055 add_shortcut( "vobsub" );
00056 add_shortcut( "subtitle" );
00057 vlc_module_end();
00058
00059
00060
00061
00062
00063 typedef struct
00064 {
00065 int i_line_count;
00066 int i_line;
00067 char **line;
00068 } text_t;
00069 static int TextLoad( text_t *, stream_t *s );
00070 static void TextUnload( text_t * );
00071
00072 typedef struct
00073 {
00074 int64_t i_start;
00075 int i_vobsub_location;
00076 } subtitle_t;
00077
00078 typedef struct
00079 {
00080 es_format_t fmt;
00081 es_out_id_t *p_es;
00082 int i_track_id;
00083
00084 int i_current_subtitle;
00085 int i_subtitles;
00086 subtitle_t *p_subtitles;
00087 } vobsub_track_t;
00088
00089 struct demux_sys_t
00090 {
00091 int64_t i_next_demux_date;
00092 int64_t i_length;
00093
00094 text_t txt;
00095 FILE *p_vobsub_file;
00096
00097
00098 int i_tracks;
00099 vobsub_track_t *track;
00100
00101 int i_original_frame_width;
00102 int i_original_frame_height;
00103 };
00104
00105 static int Demux( demux_t * );
00106 static int Control( demux_t *, int, va_list );
00107
00108 static int ParseVobSubIDX( demux_t * );
00109 static int DemuxVobSub( demux_t *, block_t *);
00110
00111
00112
00113
00114 static int Open ( vlc_object_t *p_this )
00115 {
00116 demux_t *p_demux = (demux_t*)p_this;
00117 demux_sys_t *p_sys;
00118 char *psz_vobname, *s;
00119 int i_len;
00120
00121 if( ( s = stream_ReadLine( p_demux->s ) ) != NULL )
00122 {
00123 if( !strcasestr( s, "# VobSub index file" ) )
00124 {
00125 msg_Dbg( p_demux, "this doesn't seem to be a vobsub file" );
00126 free( s );
00127 if( stream_Seek( p_demux->s, 0 ) )
00128 {
00129 msg_Warn( p_demux, "failed to rewind" );
00130 }
00131 return VLC_EGENERIC;
00132 }
00133 free( s );
00134
00135 }
00136 else
00137 {
00138 msg_Dbg( p_demux, "could not read vobsub IDX file" );
00139 return VLC_EGENERIC;
00140 }
00141
00142 p_demux->pf_demux = Demux;
00143 p_demux->pf_control = Control;
00144 p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00145 p_sys->i_length = 0;
00146 p_sys->p_vobsub_file = NULL;
00147 p_sys->i_tracks = 0;
00148 p_sys->track = (vobsub_track_t *)malloc( sizeof( vobsub_track_t ) );
00149 p_sys->i_original_frame_width = -1;
00150 p_sys->i_original_frame_height = -1;
00151
00152
00153 TextLoad( &p_sys->txt, p_demux->s );
00154
00155
00156 ParseVobSubIDX( p_demux );
00157
00158
00159 TextUnload( &p_sys->txt );
00160
00161
00162 if( p_sys->i_tracks > 0 )
00163 {
00164 int i;
00165 for( i = 0; i < p_sys->i_tracks; i++ )
00166 {
00167 if( p_sys->track[i].i_subtitles > 1 )
00168 {
00169 if( p_sys->track[i].p_subtitles[p_sys->track[i].i_subtitles-1].i_start > p_sys->i_length )
00170 p_sys->i_length = (int64_t) p_sys->track[i].p_subtitles[p_sys->track[i].i_subtitles-1].i_start + ( 1 *1000 *1000 );
00171 }
00172 }
00173 }
00174
00175 i_len = strlen( p_demux->psz_path );
00176 psz_vobname = strdup( p_demux->psz_path );
00177
00178 strcpy( psz_vobname + i_len - 4, ".sub" );
00179
00180
00181 if( !( p_sys->p_vobsub_file = fopen( psz_vobname, "rb" ) ) )
00182 {
00183 msg_Err( p_demux, "couldn't open .sub Vobsub file: %s",
00184 psz_vobname );
00185 free( p_sys );
00186 free( psz_vobname );
00187 return VLC_EGENERIC;
00188 }
00189 free( psz_vobname );
00190
00191 return VLC_SUCCESS;
00192 }
00193
00194
00195
00196
00197 static void Close( vlc_object_t *p_this )
00198 {
00199 demux_t *p_demux = (demux_t*)p_this;
00200 demux_sys_t *p_sys = p_demux->p_sys;
00201
00202
00203
00204
00205
00206 if( p_sys->p_vobsub_file )
00207 fclose( p_sys->p_vobsub_file );
00208
00209 free( p_sys );
00210 }
00211
00212
00213
00214
00215 static int Control( demux_t *p_demux, int i_query, va_list args )
00216 {
00217 demux_sys_t *p_sys = p_demux->p_sys;
00218 int64_t *pi64, i64;
00219 int i;
00220 double *pf, f;
00221
00222 switch( i_query )
00223 {
00224 case DEMUX_GET_LENGTH:
00225 pi64 = (int64_t*)va_arg( args, int64_t * );
00226 *pi64 = (int64_t) p_sys->i_length;
00227 return VLC_SUCCESS;
00228
00229 case DEMUX_GET_TIME:
00230 pi64 = (int64_t*)va_arg( args, int64_t * );
00231 for( i = 0; i < p_sys->i_tracks; i++ )
00232 {
00233 vlc_bool_t b_selected;
00234
00235 es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
00236 p_sys->track[i].p_es, &b_selected );
00237 if( b_selected ) break;
00238 }
00239 if( i < p_sys->i_tracks && p_sys->track[i].i_current_subtitle < p_sys->track[i].i_subtitles )
00240 {
00241 *pi64 = p_sys->track[i].p_subtitles[p_sys->track[i].i_current_subtitle].i_start;
00242 return VLC_SUCCESS;
00243 }
00244 return VLC_EGENERIC;
00245
00246 case DEMUX_SET_TIME:
00247 i64 = (int64_t)va_arg( args, int64_t );
00248 for( i = 0; i < p_sys->i_tracks; i++ )
00249 {
00250 p_sys->track[i].i_current_subtitle = 0;
00251 while( p_sys->track[i].i_current_subtitle < p_sys->track[i].i_subtitles &&
00252 p_sys->track[i].p_subtitles[p_sys->track[i].i_current_subtitle].i_start < i64 )
00253 {
00254 p_sys->track[i].i_current_subtitle++;
00255 }
00256
00257 if( p_sys->track[i].i_current_subtitle >= p_sys->track[i].i_subtitles )
00258 return VLC_EGENERIC;
00259 }
00260 return VLC_SUCCESS;
00261
00262 case DEMUX_GET_POSITION:
00263 pf = (double*)va_arg( args, double * );
00264 for( i = 0; i < p_sys->i_tracks; i++ )
00265 {
00266 vlc_bool_t b_selected;
00267
00268 es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
00269 p_sys->track[i].p_es, &b_selected );
00270 if( b_selected ) break;
00271 }
00272 if( p_sys->track[i].i_current_subtitle >= p_sys->track[i].i_subtitles )
00273 {
00274 *pf = 1.0;
00275 }
00276 else if( p_sys->track[i].i_subtitles > 0 )
00277 {
00278 *pf = (double)p_sys->track[i].p_subtitles[p_sys->track[i].i_current_subtitle].i_start /
00279 (double)p_sys->i_length;
00280 }
00281 else
00282 {
00283 *pf = 0.0;
00284 }
00285 return VLC_SUCCESS;
00286
00287 case DEMUX_SET_POSITION:
00288 f = (double)va_arg( args, double );
00289 i64 = (int64_t) f * p_sys->i_length;
00290
00291 for( i = 0; i < p_sys->i_tracks; i++ )
00292 {
00293 p_sys->track[i].i_current_subtitle = 0;
00294 while( p_sys->track[i].i_current_subtitle < p_sys->track[i].i_subtitles &&
00295 p_sys->track[i].p_subtitles[p_sys->track[i].i_current_subtitle].i_start < i64 )
00296 {
00297 p_sys->track[i].i_current_subtitle++;
00298 }
00299 if( p_sys->track[i].i_current_subtitle >= p_sys->track[i].i_subtitles )
00300 return VLC_EGENERIC;
00301 }
00302 return VLC_SUCCESS;
00303
00304 case DEMUX_SET_NEXT_DEMUX_TIME:
00305 p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
00306 return VLC_SUCCESS;
00307
00308 case DEMUX_GET_FPS:
00309 case DEMUX_GET_META:
00310 case DEMUX_GET_TITLE_INFO:
00311 return VLC_EGENERIC;
00312
00313 default:
00314 msg_Err( p_demux, "unknown query in subtitle control" );
00315 return VLC_EGENERIC;
00316 }
00317 }
00318
00319
00320
00321
00322 static int Demux( demux_t *p_demux )
00323 {
00324 demux_sys_t *p_sys = p_demux->p_sys;
00325 int64_t i_maxdate;
00326 int i;
00327
00328 for( i = 0; i < p_sys->i_tracks; i++ )
00329 {
00330 #define tk p_sys->track[i]
00331 if( tk.i_current_subtitle >= tk.i_subtitles )
00332 continue;
00333
00334 i_maxdate = (int64_t) p_sys->i_next_demux_date;
00335 if( i_maxdate <= 0 && tk.i_current_subtitle < tk.i_subtitles )
00336 {
00337
00338 i_maxdate = (int64_t) tk.p_subtitles[tk.i_current_subtitle].i_start + 1;
00339 }
00340
00341 while( tk.i_current_subtitle < tk.i_subtitles &&
00342 tk.p_subtitles[tk.i_current_subtitle].i_start < i_maxdate )
00343 {
00344 int i_pos = tk.p_subtitles[tk.i_current_subtitle].i_vobsub_location;
00345 block_t *p_block;
00346 int i_size = 0;
00347
00348
00349 if( tk.i_current_subtitle + 1 < tk.i_subtitles )
00350 {
00351 i_size = tk.p_subtitles[tk.i_current_subtitle+1].i_vobsub_location - i_pos;
00352 }
00353 if( i_size <= 0 ) i_size = 65535;
00354
00355
00356 if( fseek( p_sys->p_vobsub_file, i_pos, SEEK_SET ) )
00357 {
00358 msg_Warn( p_demux,
00359 "cannot seek at right vobsub location %d", i_pos );
00360 tk.i_current_subtitle++;
00361 continue;
00362 }
00363
00364
00365 if( ( p_block = block_New( p_demux, i_size ) ) == NULL )
00366 {
00367 tk.i_current_subtitle++;
00368 continue;
00369 }
00370
00371
00372 p_block->i_buffer = fread( p_block->p_buffer, 1, i_size,
00373 p_sys->p_vobsub_file );
00374 if( p_block->i_buffer <= 6 )
00375 {
00376 block_Release( p_block );
00377 tk.i_current_subtitle++;
00378 continue;
00379 }
00380
00381
00382 p_block->i_pts = tk.p_subtitles[tk.i_current_subtitle].i_start;
00383
00384
00385 DemuxVobSub( p_demux, p_block );
00386
00387 tk.i_current_subtitle++;
00388 }
00389 #undef tk
00390 }
00391
00392
00393 p_sys->i_next_demux_date = 0;
00394
00395 return 1;
00396 }
00397
00398 static int TextLoad( text_t *txt, stream_t *s )
00399 {
00400 int i_line_max;
00401
00402
00403 i_line_max = 500;
00404 txt->i_line_count = 0;
00405 txt->i_line = 0;
00406 txt->line = calloc( i_line_max, sizeof( char * ) );
00407
00408
00409 for( ;; )
00410 {
00411 char *psz = stream_ReadLine( s );
00412
00413 if( psz == NULL )
00414 break;
00415
00416 txt->line[txt->i_line_count++] = psz;
00417 if( txt->i_line_count >= i_line_max )
00418 {
00419 i_line_max += 100;
00420 txt->line = realloc( txt->line, i_line_max * sizeof( char*) );
00421 }
00422 }
00423
00424 if( txt->i_line_count <= 0 )
00425 {
00426 free( txt->line );
00427 return VLC_EGENERIC;
00428 }
00429
00430 return VLC_SUCCESS;
00431 }
00432 static void TextUnload( text_t *txt )
00433 {
00434 int i;
00435
00436 for( i = 0; i < txt->i_line_count; i++ )
00437 {
00438 free( txt->line[i] );
00439 }
00440 free( txt->line );
00441 txt->i_line = 0;
00442 txt->i_line_count = 0;
00443 }
00444
00445 static char *TextGetLine( text_t *txt )
00446 {
00447 if( txt->i_line >= txt->i_line_count )
00448 return( NULL );
00449
00450 return txt->line[txt->i_line++];
00451 }
00452
00453 static int ParseVobSubIDX( demux_t *p_demux )
00454 {
00455 demux_sys_t *p_sys = p_demux->p_sys;
00456 text_t *txt = &p_sys->txt;
00457 char *line;
00458 vobsub_track_t *current_tk;
00459
00460 for( ;; )
00461 {
00462 if( ( line = TextGetLine( txt ) ) == NULL )
00463 {
00464 return( VLC_EGENERIC );
00465 }
00466
00467 if( *line == 0 || *line == '\r' || *line == '\n' || *line == '#' )
00468 continue;
00469 else if( !strncmp( "size:", line, 5 ) )
00470 {
00471
00472 if( sscanf( line, "size: %dx%d",
00473 &p_sys->i_original_frame_width, &p_sys->i_original_frame_height ) == 2 )
00474 {
00475 msg_Dbg( p_demux, "original frame size: %dx%d", p_sys->i_original_frame_width, p_sys->i_original_frame_height );
00476 }
00477 else
00478 {
00479 msg_Warn( p_demux, "reading original frame size failed" );
00480 }
00481 }
00482 else if( !strncmp( "id:", line, 3 ) )
00483 {
00484 char language[20];
00485 int i_track_id;
00486 es_format_t fmt;
00487
00488
00489 if( sscanf( line, "id: %2s, index: %d",
00490 language, &i_track_id ) == 2 )
00491 {
00492 p_sys->i_tracks++;
00493 p_sys->track = (vobsub_track_t*)realloc( p_sys->track, sizeof( vobsub_track_t ) * (p_sys->i_tracks + 1 ) );
00494
00495
00496 current_tk = &p_sys->track[p_sys->i_tracks - 1];
00497 memset( current_tk, 0, sizeof( vobsub_track_t ) );
00498 current_tk->i_current_subtitle = 0;
00499 current_tk->i_subtitles = 0;
00500 current_tk->p_subtitles = (subtitle_t*)malloc( sizeof( subtitle_t ) );;
00501 current_tk->i_track_id = i_track_id;
00502
00503 es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
00504 fmt.subs.spu.i_original_frame_width = p_sys->i_original_frame_width;
00505 fmt.subs.spu.i_original_frame_height = p_sys->i_original_frame_height;
00506 fmt.psz_language = strdup( language );
00507 current_tk->p_es = es_out_Add( p_demux->out, &fmt );
00508
00509 msg_Dbg( p_demux, "new vobsub track detected" );
00510 }
00511 else
00512 {
00513 msg_Warn( p_demux, "reading new track failed" );
00514 }
00515 }
00516 else if( !strncmp( line, "timestamp:", 10 ) )
00517 {
00518
00519
00520
00521
00522
00523 int h, m, s, ms, loc;
00524 int64_t i_start, i_location = 0;
00525
00526 vobsub_track_t *current_tk = &p_sys->track[p_sys->i_tracks - 1];
00527
00528 if( sscanf( line, "timestamp: %d:%d:%d:%d, filepos: %x",
00529 &h, &m, &s, &ms, &loc ) == 5 )
00530 {
00531 subtitle_t *current_sub;
00532
00533 i_start = (int64_t) ( h * 3600*1000 +
00534 m * 60*1000 +
00535 s * 1000 +
00536 ms ) * 1000;
00537 i_location = loc;
00538
00539 current_tk->i_subtitles++;
00540 current_tk->p_subtitles = (subtitle_t*)realloc( current_tk->p_subtitles, sizeof( subtitle_t ) * (current_tk->i_subtitles + 1 ) );
00541 current_sub = ¤t_tk->p_subtitles[current_tk->i_subtitles - 1];
00542
00543 current_sub->i_start = (int64_t) i_start;
00544 current_sub->i_vobsub_location = i_location;
00545 }
00546 }
00547 }
00548 return( 0 );
00549 }
00550
00551 static int DemuxVobSub( demux_t *p_demux, block_t *p_bk )
00552 {
00553 demux_sys_t *p_sys = p_demux->p_sys;
00554 uint8_t *p = p_bk->p_buffer;
00555 uint8_t *p_end = &p_bk->p_buffer[p_bk->i_buffer];
00556 int i;
00557
00558 while( p < p_end )
00559 {
00560 int i_size = ps_pkt_size( p, p_end - p );
00561 block_t *p_pkt;
00562 int i_id;
00563 int i_spu;
00564
00565 if( i_size <= 0 )
00566 {
00567 break;
00568 }
00569 if( p[0] != 0 || p[1] != 0 || p[2] != 0x01 )
00570 {
00571 msg_Warn( p_demux, "invalid PES" );
00572 break;
00573 }
00574
00575 if( p[3] != 0xbd )
00576 {
00577
00578 p += i_size;
00579 continue;
00580 }
00581
00582
00583 p_pkt = block_New( p_demux, i_size );
00584 memcpy( p_pkt->p_buffer, p, i_size);
00585 p += i_size;
00586
00587 i_id = ps_pkt_id( p_pkt );
00588 if( (i_id&0xffe0) != 0xbd20 ||
00589 ps_pkt_parse_pes( p_pkt, 1 ) )
00590 {
00591 block_Release( p_pkt );
00592 continue;
00593 }
00594 i_spu = i_id&0x1f;
00595
00596
00597 for( i = 0; i < p_sys->i_tracks; i++ )
00598 {
00599 #define tk p_sys->track[i]
00600 p_pkt->i_dts = p_pkt->i_pts = p_bk->i_pts;
00601 p_pkt->i_length = 0;
00602
00603 if( tk.p_es && tk.i_track_id == i_spu )
00604 {
00605 es_out_Send( p_demux->out, tk.p_es, p_pkt );
00606 p_bk->i_pts = 0;
00607 break;
00608 }
00609 else if( i == p_sys->i_tracks - 1 )
00610 {
00611 block_Release( p_pkt );
00612 }
00613 #undef tk
00614 }
00615 }
00616
00617 return VLC_SUCCESS;
00618 }