X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fsubtitle.c;h=cafc285c4a84095767385560a04236c46fd6460c;hb=534a81228d1bd8665ba5447b22faa8144339ebc7;hp=3746d8285cd47e2ca8e4cb837aa5df62de603cbb;hpb=f34f6631f2dc306e03d55e61d53fea96d23f466c;p=vlc diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c index 3746d8285c..cafc285c4a 100644 --- a/modules/demux/subtitle.c +++ b/modules/demux/subtitle.c @@ -1,5 +1,5 @@ /***************************************************************************** - * subtitle.c: Demux for text and vobsub files. + * subtitle.c: Demux for subtitle text files. ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN * $Id$ @@ -28,14 +28,15 @@ #include #include -#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif #include #include #include #include "vlc_video.h" -#include "ps.h" #if (!defined( WIN32 ) || defined(__MINGW32__)) # include @@ -58,22 +59,26 @@ static void Close( vlc_object_t *p_this ); static char *ppsz_sub_type[] = { "auto", "microdvd", "subrip", "subviewer", "ssa1", - "ssa2-4", "vplayer", "sami", "vobsub" + "ssa2-4", "vplayer", "sami" }; vlc_module_begin(); set_description( _("Text subtitles demux") ); set_capability( "demux2", 0 ); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_DEMUX ); add_float( "sub-fps", 0.0, NULL, N_("Frames per second"), SUB_FPS_LONGTEXT, VLC_TRUE ); + add_integer( "sub-delay", 0, NULL, + N_("Subtitles delay"), + SUB_DELAY_LONGTEXT, VLC_TRUE ); add_string( "sub-type", "auto", NULL, "Subtitles fileformat", SUB_TYPE_LONGTEXT, VLC_TRUE ); change_string_list( ppsz_sub_type, 0, 0 ); set_callbacks( Open, Close ); add_shortcut( "subtitle" ); - add_shortcut( "vobsub" ); vlc_module_end(); /***************************************************************************** @@ -89,7 +94,6 @@ enum SUB_TYPE_VPLAYER, SUB_TYPE_SAMI, SUB_TYPE_SUBVIEWER, - SUB_TYPE_VOBSUB, }; typedef struct @@ -103,11 +107,10 @@ static void TextUnload( text_t * ); typedef struct { - mtime_t i_start; - mtime_t i_stop; + int64_t i_start; + int64_t i_stop; char *psz_text; - int i_vobsub_location; } subtitle_t; @@ -120,13 +123,12 @@ struct demux_sys_t int64_t i_next_demux_date; int64_t i_microsecperframe; + int64_t i_original_mspf; char *psz_header; int i_subtitle; int i_subtitles; subtitle_t *subtitle; - FILE *p_vobsub_file; - mtime_t i_original_mspf; int64_t i_length; }; @@ -137,9 +139,6 @@ static int ParseSubViewer( demux_t *, subtitle_t * ); static int ParseSSA ( demux_t *, subtitle_t * ); static int ParseVplayer ( demux_t *, subtitle_t * ); static int ParseSami ( demux_t *, subtitle_t * ); -static int ParseVobSubIDX( demux_t *, subtitle_t * ); - -static int DemuxVobSub( demux_t *, block_t * ); static struct { @@ -156,7 +155,6 @@ static struct { "ssa2-4", SUB_TYPE_SSA2_4, "SSA-2/3/4",ParseSSA }, { "vplayer", SUB_TYPE_VPLAYER, "VPlayer", ParseVplayer }, { "sami", SUB_TYPE_SAMI, "SAMI", ParseSami }, - { "vobsub", SUB_TYPE_VOBSUB, "VobSub", ParseVobSubIDX }, { NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL } }; @@ -165,8 +163,6 @@ static int Control( demux_t *, int, va_list ); static void Fix( demux_t * ); -#define DVD_VIDEO_LB_LEN 2048 - /***************************************************************************** * Module initializer *****************************************************************************/ @@ -180,8 +176,7 @@ static int Open ( vlc_object_t *p_this ) int (*pf_read)( demux_t *, subtitle_t* ); int i, i_max; - if( strcmp( p_demux->psz_demux, "subtitle" ) && - strcmp( p_demux->psz_demux, "vobsub" ) ) + if( strcmp( p_demux->psz_demux, "subtitle" ) ) { msg_Dbg( p_demux, "subtitle demux discarded" ); return VLC_EGENERIC; @@ -194,16 +189,27 @@ static int Open ( vlc_object_t *p_this ) p_sys->i_subtitle = 0; p_sys->i_subtitles= 0; p_sys->subtitle = NULL; - p_sys->p_vobsub_file = NULL; - p_sys->i_original_mspf = 0; /* Get the FPS */ - p_sys->i_microsecperframe = 40000; /* default to 25 fps */ f_fps = var_CreateGetFloat( p_demux, "sub-fps" ); if( f_fps >= 1.0 ) { - p_sys->i_microsecperframe = (mtime_t)( (float)1000000 / f_fps ); + p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps ); + } + else + { + p_sys->i_microsecperframe = 0; + } + + f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" ); + if( f_fps >= 1.0 ) + { + p_sys->i_original_mspf = (int64_t)( (float)1000000 / f_fps ); + } + else + { + p_sys->i_original_mspf = 0; } /* Get or probe the type */ @@ -296,11 +302,6 @@ static int Open ( vlc_object_t *p_this ) p_sys->i_type = SUB_TYPE_VPLAYER; break; } - else if( strcasestr( s, "# VobSub index file" ) ) - { - p_sys->i_type = SUB_TYPE_VOBSUB; - break; - } free( s ); s = NULL; @@ -363,10 +364,6 @@ static int Open ( vlc_object_t *p_this ) /* Fix subtitle (order and time) *** */ p_sys->i_subtitle = 0; - if( p_sys->i_type != SUB_TYPE_VOBSUB ) - { - Fix( p_demux ); - } p_sys->i_length = 0; if( p_sys->i_subtitles > 0 ) { @@ -377,24 +374,7 @@ static int Open ( vlc_object_t *p_this ) } /* *** add subtitle ES *** */ - if( p_sys->i_type == SUB_TYPE_VOBSUB ) - { - int i_len = strlen( p_demux->psz_path ); - char *psz_vobname = strdup( p_demux->psz_path ); - - strcpy( psz_vobname + i_len - 4, ".sub" ); - - /* open file */ - if( !( p_sys->p_vobsub_file = fopen( psz_vobname, "rb" ) ) ) - { - msg_Err( p_demux, "couldn't open .sub Vobsub file: %s", - psz_vobname ); - } - free( psz_vobname ); - - es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) ); - } - else if( p_sys->i_type == SUB_TYPE_SSA1 || + if( p_sys->i_type == SUB_TYPE_SSA1 || p_sys->i_type == SUB_TYPE_SSA2_4 ) { es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) ); @@ -430,9 +410,6 @@ static void Close( vlc_object_t *p_this ) if( p_sys->subtitle ) free( p_sys->subtitle ); - if( p_sys->p_vobsub_file ) - fclose( p_sys->p_vobsub_file ); - free( p_sys ); } @@ -531,111 +508,57 @@ static int Demux( demux_t *p_demux ) if( p_sys->i_subtitle >= p_sys->i_subtitles ) return 0; - i_maxdate = p_sys->i_next_demux_date; + i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent, "spu-delay" );; if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles ) { /* Should not happen */ i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1; } - if( p_sys->i_type != SUB_TYPE_VOBSUB ) + while( p_sys->i_subtitle < p_sys->i_subtitles && + p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate ) { - while( p_sys->i_subtitle < p_sys->i_subtitles && - p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate ) - { - block_t *p_block; - int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1; - - if( i_len <= 1 ) - { - /* empty subtitle */ - p_sys->i_subtitle++; - continue; - } - - if( ( p_block = block_New( p_demux, i_len ) ) == NULL ) - { - p_sys->i_subtitle++; - continue; - } - - if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 ) - { - p_sys->i_subtitle++; - continue; - } - - p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start; - p_block->i_dts = p_block->i_pts; - if( p_sys->subtitle[p_sys->i_subtitle].i_stop > 0 ) - { - p_block->i_length = - p_sys->subtitle[p_sys->i_subtitle].i_stop - p_block->i_pts; - } + block_t *p_block; + int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1; - memcpy( p_block->p_buffer, - p_sys->subtitle[p_sys->i_subtitle].psz_text, i_len ); - if( p_block->i_pts > 0 ) - { - es_out_Send( p_demux->out, p_sys->es, p_block ); - } - else - { - block_Release( p_block ); - } + if( i_len <= 1 ) + { + /* empty subtitle */ p_sys->i_subtitle++; + continue; } - } - else - { - while( p_sys->i_subtitle < p_sys->i_subtitles && - p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate ) - { - int i_pos = p_sys->subtitle[p_sys->i_subtitle].i_vobsub_location; - block_t *p_block; - int i_size = 0; - - /* first compute SPU size */ - if( p_sys->i_subtitle + 1 < p_sys->i_subtitles ) - { - i_size = p_sys->subtitle[p_sys->i_subtitle+1].i_vobsub_location - i_pos; - } - if( i_size <= 0 ) i_size = 65535; /* Invalid or EOF */ - /* Seek at the right place */ - if( fseek( p_sys->p_vobsub_file, i_pos, SEEK_SET ) ) - { - msg_Warn( p_demux, - "cannot seek at right vobsub location %d", i_pos ); - p_sys->i_subtitle++; - continue; - } - - /* allocate a packet */ - if( ( p_block = block_New( p_demux, i_size ) ) == NULL ) - { - p_sys->i_subtitle++; - continue; - } - - /* read data */ - p_block->i_buffer = fread( p_block->p_buffer, 1, i_size, - p_sys->p_vobsub_file ); - if( p_block->i_buffer <= 6 ) - { - block_Release( p_block ); - p_sys->i_subtitle++; - continue; - } + if( ( p_block = block_New( p_demux, i_len ) ) == NULL ) + { + p_sys->i_subtitle++; + continue; + } - /* pts */ - p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start; + if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 ) + { + p_sys->i_subtitle++; + continue; + } - /* demux this block */ - DemuxVobSub( p_demux, p_block ); + p_block->i_pts = p_sys->subtitle[p_sys->i_subtitle].i_start; + p_block->i_dts = p_block->i_pts; + if( p_sys->subtitle[p_sys->i_subtitle].i_stop > 0 ) + { + p_block->i_length = + p_sys->subtitle[p_sys->i_subtitle].i_stop - p_block->i_pts; + } - p_sys->i_subtitle++; + memcpy( p_block->p_buffer, + p_sys->subtitle[p_sys->i_subtitle].psz_text, i_len ); + if( p_block->i_pts > 0 ) + { + es_out_Send( p_demux->out, p_sys->es, p_block ); } + else + { + block_Release( p_block ); + } + p_sys->i_subtitle++; } /* */ @@ -758,13 +681,16 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle ) char *s; char buffer_text[MAX_LINE + 1]; - unsigned int i_start; - unsigned int i_stop; + int i_start; + int i_stop; unsigned int i; + int i_microsecperframe = 40000; /* default to 25 fps */ + if( p_sys->i_microsecperframe > 0 ) + i_microsecperframe = p_sys->i_microsecperframe; + p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; for( ;; ) @@ -792,8 +718,8 @@ static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle ) } } - p_subtitle->i_start = (mtime_t)i_start * p_sys->i_microsecperframe; - p_subtitle->i_stop = (mtime_t)i_stop * p_sys->i_microsecperframe; + p_subtitle->i_start = (int64_t)i_start * i_microsecperframe; + p_subtitle->i_stop = (int64_t)i_stop * i_microsecperframe; p_subtitle->psz_text = strndup( buffer_text, MAX_LINE ); return( 0 ); } @@ -815,12 +741,11 @@ static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle ) char *s; char buffer_text[ 10 * MAX_LINE]; int i_buffer_text; - mtime_t i_start; - mtime_t i_stop; + int64_t i_start; + int64_t i_stop; p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; for( ;; ) @@ -835,15 +760,15 @@ static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle ) &h1, &m1, &s1, &d1, &h2, &m2, &s2, &d2 ) == 8 ) { - i_start = ( (mtime_t)h1 * 3600*1000 + - (mtime_t)m1 * 60*1000 + - (mtime_t)s1 * 1000 + - (mtime_t)d1 ) * 1000; + i_start = ( (int64_t)h1 * 3600*1000 + + (int64_t)m1 * 60*1000 + + (int64_t)s1 * 1000 + + (int64_t)d1 ) * 1000; - i_stop = ( (mtime_t)h2 * 3600*1000 + - (mtime_t)m2 * 60*1000 + - (mtime_t)s2 * 1000 + - (mtime_t)d2 ) * 1000; + i_stop = ( (int64_t)h2 * 3600*1000 + + (int64_t)m2 * 60*1000 + + (int64_t)s2 * 1000 + + (int64_t)d2 ) * 1000; /* Now read text until an empty line */ for( i_buffer_text = 0;; ) @@ -866,12 +791,12 @@ static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle ) if( p_sys->i_microsecperframe != 0 && p_sys->i_original_mspf != 0) { - p_subtitle->i_start = (mtime_t)i_start * - p_sys->i_original_mspf / - p_sys->i_microsecperframe; - p_subtitle->i_stop = (mtime_t)i_stop * - p_sys->i_original_mspf / - p_sys->i_microsecperframe; + p_subtitle->i_start = (int64_t)i_start * + p_sys->i_microsecperframe/ + p_sys->i_original_mspf; + p_subtitle->i_stop = (int64_t)i_stop * + p_sys->i_microsecperframe / + p_sys->i_original_mspf; } return 0; } @@ -909,12 +834,11 @@ static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle ) char *s; char buffer_text[ 10 * MAX_LINE]; int i_buffer_text; - mtime_t i_start; - mtime_t i_stop; + int64_t i_start; + int64_t i_stop; p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; for( ;; ) @@ -929,15 +853,15 @@ static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle ) &h1, &m1, &s1, &d1, &h2, &m2, &s2, &d2 ) == 8 ) { - i_start = ( (mtime_t)h1 * 3600*1000 + - (mtime_t)m1 * 60*1000 + - (mtime_t)s1 * 1000 + - (mtime_t)d1 ) * 1000; + i_start = ( (int64_t)h1 * 3600*1000 + + (int64_t)m1 * 60*1000 + + (int64_t)s1 * 1000 + + (int64_t)d1 ) * 1000; - i_stop = ( (mtime_t)h2 * 3600*1000 + - (mtime_t)m2 * 60*1000 + - (mtime_t)s2 * 1000 + - (mtime_t)d2 ) * 1000; + i_stop = ( (int64_t)h2 * 3600*1000 + + (int64_t)m2 * 60*1000 + + (int64_t)s2 * 1000 + + (int64_t)d2 ) * 1000; /* Now read text until an empty line */ for( i_buffer_text = 0;; ) @@ -997,12 +921,11 @@ static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle ) char buffer_text[ 10 * MAX_LINE]; char *s; - mtime_t i_start; - mtime_t i_stop; + int64_t i_start; + int64_t i_stop; p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; for( ;; ) @@ -1023,15 +946,15 @@ static int ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle ) &h2, &m2, &s2, &c2, buffer_text ) == 10 ) { - i_start = ( (mtime_t)h1 * 3600*1000 + - (mtime_t)m1 * 60*1000 + - (mtime_t)s1 * 1000 + - (mtime_t)c1 * 10 ) * 1000; + i_start = ( (int64_t)h1 * 3600*1000 + + (int64_t)m1 * 60*1000 + + (int64_t)s1 * 1000 + + (int64_t)c1 * 10 ) * 1000; - i_stop = ( (mtime_t)h2 * 3600*1000 + - (mtime_t)m2 * 60*1000 + - (mtime_t)s2 * 1000 + - (mtime_t)c2 * 10 ) * 1000; + i_stop = ( (int64_t)h2 * 3600*1000 + + (int64_t)m2 * 60*1000 + + (int64_t)s2 * 1000 + + (int64_t)c2 * 10 ) * 1000; /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */ if( p_sys->i_type == SUB_TYPE_SSA1 ) @@ -1090,12 +1013,11 @@ static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle ) */ char *p; char buffer_text[MAX_LINE + 1]; - mtime_t i_start; + int64_t i_start; unsigned int i; p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; for( ;; ) @@ -1113,9 +1035,9 @@ static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle ) memset( buffer_text, '\0', MAX_LINE ); if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 ) { - i_start = ( (mtime_t)h * 3600*1000 + - (mtime_t)m * 60*1000 + - (mtime_t)s * 1000 ) * 1000; + i_start = ( (int64_t)h * 3600*1000 + + (int64_t)m * 60*1000 + + (int64_t)s * 1000 ) * 1000; break; } } @@ -1172,14 +1094,13 @@ static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle ) text_t *txt = &p_sys->txt; char *p; - int i_start; + int64_t i_start; int i_text; char buffer_text[10*MAX_LINE + 1]; p_subtitle->i_start = 0; p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; p_subtitle->psz_text = NULL; #define ADDC( c ) \ @@ -1263,117 +1184,3 @@ static int ParseSami( demux_t *p_demux, subtitle_t *p_subtitle ) return( VLC_SUCCESS ); #undef ADDC } - -static int ParseVobSubIDX( demux_t *p_demux, subtitle_t *p_subtitle ) -{ - demux_sys_t *p_sys = p_demux->p_sys; - text_t *txt = &p_sys->txt; - - /* - * Parse the idx file. Each line: - * timestamp: hh:mm:ss:mss, filepos: loc - * hexint is the hex location of the vobsub in the .sub file - * - */ - char *p; - char buffer_text[MAX_LINE + 1]; - unsigned int i_start, i_location; - - p_subtitle->i_start = 0; - p_subtitle->i_stop = 0; - p_subtitle->i_vobsub_location = 0; - p_subtitle->psz_text = NULL; - - for( ;; ) - { - unsigned int h, m, s, ms, loc; - - if( ( p = TextGetLine( txt ) ) == NULL ) - { - return( VLC_EGENERIC ); - } - i_start = 0; - - memset( buffer_text, '\0', MAX_LINE ); - if( sscanf( p, "timestamp: %d:%d:%d:%d, filepos: %x%[^\r\n]", - &h, &m, &s, &ms, &loc, buffer_text ) == 5 ) - { - i_start = ( (mtime_t)h * 3600*1000 + - (mtime_t)m * 60*1000 + - (mtime_t)s * 1000 + - (mtime_t)ms ) * 1000; - i_location = loc; - break; - } - } - p_subtitle->i_start = (mtime_t)i_start; - p_subtitle->i_stop = 0; - p_subtitle->psz_text = NULL; - p_subtitle->i_vobsub_location = i_location; - fprintf( stderr, "time: %x, location: %x\n", i_start, i_location ); - return( 0 ); -} - -static int DemuxVobSub( demux_t *p_demux, block_t *p_bk ) -{ - demux_sys_t *p_sys = p_demux->p_sys; - uint8_t *p = p_bk->p_buffer; - uint8_t *p_end = &p_bk->p_buffer[p_bk->i_buffer]; - - while( p < p_end ) - { - int i_size = ps_pkt_size( p, p_end - p ); - block_t *p_pkt; - int i_id; - int i_spu; - - if( i_size <= 0 ) - { - break; - } - if( p[0] != 0 || p[1] != 0 || p[2] != 0x01 ) - { - msg_Warn( p_demux, "invalid PES" ); - break; - } - - if( p[3] != 0xbd ) - { - msg_Dbg( p_demux, "we don't need these ps packets (id=0x1%2.2x)", p[3] ); - p += i_size; - continue; - } - - /* Create a block */ - p_pkt = block_New( p_demux, i_size ); - memcpy( p_pkt->p_buffer, p, i_size); - p += i_size; - - i_id = ps_pkt_id( p_pkt ); - if( (i_id&0xffe0) != 0xbd20 || - ps_pkt_parse_pes( p_pkt, 1 ) ) - { - block_Release( p_pkt ); - continue; - } - i_spu = i_id&0x1f; - msg_Dbg( p_demux, "SPU track %d size %d", i_spu, i_size ); - - /* FIXME i_spu == determines which of the spu tracks we will show. */ - if( p_sys->es && i_spu == 0 ) - { - p_pkt->i_dts = p_pkt->i_pts = p_bk->i_pts; - p_pkt->i_length = 0; - es_out_Send( p_demux->out, p_sys->es, p_pkt ); - - p_bk->i_pts = 0; /* only first packet has a pts */ - } - else - { - block_Release( p_pkt ); - continue; - } - } - - return VLC_SUCCESS; -}