X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fsubtitle.c;h=4faaa9cdcc473b7f4fdfc113fc0ff102b5cca1de;hb=2372b5bee60394962732963df0a037a76da318fe;hp=8883d124d5305d889df7cb55055d27fbfc44bb9c;hpb=a6d22fe5d220c4ad1b0695d0cbc85e1377c30173;p=vlc diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c index 8883d124d5..4faaa9cdcc 100644 --- a/modules/demux/subtitle.c +++ b/modules/demux/subtitle.c @@ -70,25 +70,25 @@ static const char *const ppsz_sub_type[] = "subviewer1" }; -vlc_module_begin(); - set_shortname( N_("Subtitles")); - set_description( N_("Text subtitles parser") ); - set_capability( "demux", 0 ); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_DEMUX ); +vlc_module_begin () + set_shortname( N_("Subtitles")) + set_description( N_("Text subtitles parser") ) + set_capability( "demux", 0 ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_DEMUX ) add_float( "sub-fps", 0.0, NULL, N_("Frames per second"), - SUB_FPS_LONGTEXT, true ); + SUB_FPS_LONGTEXT, true ) add_integer( "sub-delay", 0, NULL, N_("Subtitles delay"), - SUB_DELAY_LONGTEXT, true ); + SUB_DELAY_LONGTEXT, true ) add_string( "sub-type", "auto", NULL, N_("Subtitles format"), - SUB_TYPE_LONGTEXT, true ); - change_string_list( ppsz_sub_type, NULL, NULL ); - set_callbacks( Open, Close ); + SUB_TYPE_LONGTEXT, true ) + change_string_list( ppsz_sub_type, NULL, NULL ) + set_callbacks( Open, Close ) - add_shortcut( "subtitle" ); -vlc_module_end(); + add_shortcut( "subtitle" ) +vlc_module_end () /***************************************************************************** * Prototypes: @@ -98,6 +98,7 @@ enum SUB_TYPE_UNKNOWN = -1, SUB_TYPE_MICRODVD, SUB_TYPE_SUBRIP, + SUB_TYPE_SUBRIP_DOT, /* Invalid SubRip file (dot instead of comma) */ SUB_TYPE_SSA1, SUB_TYPE_SSA2_4, SUB_TYPE_ASS, @@ -172,6 +173,7 @@ struct demux_sys_t static int ParseMicroDvd ( demux_t *, subtitle_t *, int ); static int ParseSubRip ( demux_t *, subtitle_t *, int ); +static int ParseSubRipDot ( demux_t *, subtitle_t *, int ); static int ParseSubViewer ( demux_t *, subtitle_t *, int ); static int ParseSSA ( demux_t *, subtitle_t *, int ); static int ParseVplayer ( demux_t *, subtitle_t *, int ); @@ -197,6 +199,7 @@ static const struct { { "microdvd", SUB_TYPE_MICRODVD, "MicroDVD", ParseMicroDvd }, { "subrip", SUB_TYPE_SUBRIP, "SubRIP", ParseSubRip }, + { "subrip-dot", SUB_TYPE_SUBRIP_DOT, "SubRIP(Dot)", ParseSubRipDot }, { "subviewer", SUB_TYPE_SUBVIEWER, "SubViewer", ParseSubViewer }, { "ssa1", SUB_TYPE_SSA1, "SSA-1", ParseSSA }, { "ssa2-4", SUB_TYPE_SSA2_4, "SSA-2/3/4", ParseSSA }, @@ -215,6 +218,9 @@ static const struct { "subviewer1", SUB_TYPE_SUBVIEW1, "Subviewer 1", ParseSubViewer1 }, { NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL } }; +/* When adding support for more formats, be sure to add their file extension + * to src/input/subtitles.c to enable auto-detection. + */ static int Demux( demux_t * ); static int Control( demux_t *, int, va_list ); @@ -326,6 +332,15 @@ static int Open ( vlc_object_t *p_this ) p_sys->i_type = SUB_TYPE_SUBRIP; break; } + else if( sscanf( s, + "%d:%d:%d.%d --> %d:%d:%d.%d", + &i_dummy,&i_dummy,&i_dummy,&i_dummy, + &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 ) + { + msg_Err( p_demux, "Detected invalid SubRip file, playing anyway" ); + p_sys->i_type = SUB_TYPE_SUBRIP_DOT; + break; + } else if( !strncasecmp( s, "!: This is a Sub Station Alpha v1", 33 ) ) { p_sys->i_type = SUB_TYPE_SSA1; @@ -439,7 +454,7 @@ static int Open ( vlc_object_t *p_this ) /* Quit on unknown subtitles */ if( p_sys->i_type == SUB_TYPE_UNKNOWN ) { - msg_Err( p_demux, "failed to recognize subtitle type" ); + msg_Warn( p_demux, "failed to recognize subtitle type" ); free( p_sys ); return VLC_EGENERIC; } @@ -503,11 +518,11 @@ static int Open ( vlc_object_t *p_this ) p_sys->i_type == SUB_TYPE_SSA2_4 || p_sys->i_type == SUB_TYPE_ASS ) { - es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) ); + es_format_Init( &fmt, SPU_ES, VLC_CODEC_SSA ); } else { - es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) ); + es_format_Init( &fmt, SPU_ES, VLC_CODEC_SUBT ); } if( p_sys->psz_header != NULL ) { @@ -563,9 +578,15 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_SET_TIME: i64 = (int64_t)va_arg( args, int64_t ); p_sys->i_subtitle = 0; - while( p_sys->i_subtitle < p_sys->i_subtitles && - p_sys->subtitle[p_sys->i_subtitle].i_start < i64 ) + while( p_sys->i_subtitle < p_sys->i_subtitles ) { + const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle]; + + if( p_subtitle->i_start > i64 ) + break; + if( p_subtitle->i_stop > p_subtitle->i_start && p_subtitle->i_stop > i64 ) + break; + p_sys->i_subtitle++; } @@ -613,6 +634,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_ATTACHMENTS: case DEMUX_GET_TITLE_INFO: case DEMUX_HAS_UNSUPPORTED_META: + case DEMUX_CAN_RECORD: return VLC_EGENERIC; default: @@ -642,12 +664,13 @@ static int Demux( demux_t *p_demux ) while( p_sys->i_subtitle < p_sys->i_subtitles && p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate ) { + const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle]; + block_t *p_block; - int i_len = strlen( p_sys->subtitle[p_sys->i_subtitle].psz_text ) + 1; + int i_len = strlen( p_subtitle->psz_text ) + 1; - if( i_len <= 1 ) + if( i_len <= 1 || p_subtitle->i_start < 0 ) { - /* empty subtitle */ p_sys->i_subtitle++; continue; } @@ -658,30 +681,15 @@ static int Demux( demux_t *p_demux ) continue; } - if( p_sys->subtitle[p_sys->i_subtitle].i_start < 0 ) - { - p_sys->i_subtitle++; - continue; - } + p_block->i_dts = + p_block->i_pts = 1 + p_subtitle->i_start; + if( p_subtitle->i_stop > 0 && p_subtitle->i_stop >= p_subtitle->i_start ) + p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start; - 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; - } + memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len ); + + es_out_Send( p_demux->out, p_sys->es, p_block ); - 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++; } @@ -896,7 +904,8 @@ static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle, (int64_t)m2 * 60*1000 + (int64_t)s2 * 1000 + (int64_t)d2 ) * 1000; - break; + if( p_subtitle->i_start < p_subtitle->i_stop ) + break; } } @@ -904,19 +913,14 @@ static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle, psz_text = strdup(""); if( !psz_text ) return VLC_ENOMEM; + for( ;; ) { const char *s = TextGetLine( txt ); int i_len; int i_old; - if( !s ) - { - free( psz_text ); - return VLC_EGENERIC; - } - - i_len = strlen( s ); + i_len = s ? strlen( s ) : 0; if( i_len <= 0 ) { p_subtitle->psz_text = psz_text; @@ -926,7 +930,9 @@ static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle, i_old = strlen( psz_text ); psz_text = realloc( psz_text, i_old + i_len + 1 + 1 ); if( !psz_text ) + { return VLC_ENOMEM; + } strcat( psz_text, s ); strcat( psz_text, "\n" ); @@ -953,6 +959,17 @@ static int ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle, "%d:%d:%d,%d --> %d:%d:%d,%d", false ); } +/* ParseSubRipDot + * Special version for buggy file using '.' instead of ',' + */ +static int ParseSubRipDot( demux_t *p_demux, subtitle_t *p_subtitle, + int i_idx ) +{ + VLC_UNUSED( i_idx ); + return ParseSubRipSubViewer( p_demux, p_subtitle, + "%d:%d:%d.%d --> %d:%d:%d.%d", + false ); +} /* ParseSubViewer */ static int ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle, @@ -1358,7 +1375,10 @@ static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) const char *s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } /* Data Lines */ if( sscanf (s, "-->> %d", &t) == 1) @@ -1466,7 +1486,10 @@ static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) const char *s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } if( strstr( s, "FORMAT" ) ) { @@ -1478,7 +1501,10 @@ static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) psz_temp = malloc( strlen(s) ); if( !psz_temp ) + { + free( psz_text ); return VLC_ENOMEM; + } if( sscanf( s, "FORMAT=%[^\r\n]", psz_temp ) ) { @@ -1511,7 +1537,10 @@ static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) const char *s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } int i_len = strlen( s ); if( i_len == 0 ) @@ -1649,12 +1678,15 @@ static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) } } - while( psz_text[ strlen( psz_text ) - 1 ] == '\\' ) - { + while( psz_text[ strlen( psz_text ) - 1 ] == '\\' ) + { const char *s2 = TextGetLine( txt ); if( !s2 ) + { + free( psz_orig ); return VLC_EGENERIC; + } int i_len = strlen( s2 ); if( i_len == 0 ) @@ -1668,7 +1700,7 @@ static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) psz_orig = psz_text; strcat( psz_text, s2 ); - } + } /* Skip the blanks */ while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++; @@ -1836,14 +1868,14 @@ static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) VLC_UNUSED( i_idx ); demux_sys_t *p_sys = p_demux->p_sys; text_t *txt = &p_sys->txt; - char *psz_text; - char psz_end[12]= "", psz_begin[12] = ""; + char *psz_text = NULL; for( ;; ) { int h1 = 0, m1 = 0, s1 = 0, f1 = 0; int h2 = 0, m2 = 0, s2 = 0, f2 = 0; const char *s = TextGetLine( txt ); + free( psz_text ); if( !s ) return VLC_EGENERIC; @@ -1857,17 +1889,17 @@ static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) char *psz_temp = strcasestr( s, "]%[^\n\r]", + "<%*[t|T]ime %*[b|B]egin=\"%11[^\"]\" %*[e|E]nd=\"%11[^\"]%*[^>]%[^\n\r]", psz_begin, psz_end, psz_text) != 3 ) && /* Line has begin and no end */ ( sscanf( psz_temp, - "<%*[t|T]ime %*[b|B]egin=\"%[^\"]\"%*[^>]%[^\n\r]", + "<%*[t|T]ime %*[b|B]egin=\"%11[^\"]\"%*[^>]%[^\n\r]", psz_begin, psz_text ) != 2) ) /* Line is not recognized */ { - free( psz_text ); continue; } @@ -1885,9 +1917,6 @@ static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) } break; } - /* Line is not recognized */ - else continue; - free( psz_text ); } /* Get the following Lines */ @@ -1896,7 +1925,10 @@ static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) const char *s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } int i_len = strlen( s ); if( i_len == 0 ) break; @@ -1956,7 +1988,10 @@ static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx ) char *s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 ) p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 + @@ -2012,7 +2047,10 @@ static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx s = TextGetLine( txt ); if( !s ) + { + free( psz_text ); return VLC_EGENERIC; + } if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 ) p_subtitle->i_stop = ( (int64_t)h2 * 3600*1000 +