📄 subsdec.c
字号:
/* Create a new subpicture region */ memset( &fmt, 0, sizeof(video_format_t) ); fmt.i_chroma = VLC_FOURCC('T','E','X','T'); fmt.i_aspect = 0; fmt.i_width = fmt.i_height = 0; fmt.i_x_offset = fmt.i_y_offset = 0; p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt ); if( !p_spu->p_region ) { msg_Err( p_dec, "cannot allocate SPU region" ); free( psz_subtitle ); p_dec->pf_spu_buffer_del( p_dec, p_spu ); return NULL; } /* Decode and format the subpicture unit */ if( p_dec->fmt_in.i_codec != VLC_FOURCC('s','s','a',' ') ) { /* Normal text subs, easy markup */ p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM | p_sys->i_align; p_spu->i_x = p_sys->i_align ? 20 : 0; p_spu->i_y = 10; /* Remove formatting from string */ p_spu->p_region->psz_text = StripTags( psz_subtitle ); if( var_CreateGetBool( p_dec, "subsdec-formatted" ) ) { p_spu->p_region->psz_html = CreateHtmlSubtitle( psz_subtitle ); } p_spu->i_start = p_block->i_pts; p_spu->i_stop = p_block->i_pts + p_block->i_length; p_spu->b_ephemer = (p_block->i_length == 0); p_spu->b_absolute = false; } else { /* Decode SSA/USF strings */ if( p_dec->fmt_in.i_codec == VLC_FOURCC('s','s','a',' ') ) ParseSSAString( p_dec, psz_subtitle, p_spu ); p_spu->i_start = p_block->i_pts; p_spu->i_stop = p_block->i_pts + p_block->i_length; p_spu->b_ephemer = (p_block->i_length == 0); p_spu->b_absolute = false; p_spu->i_original_picture_width = p_sys->i_original_width; p_spu->i_original_picture_height = p_sys->i_original_height; } free( psz_subtitle ); return p_spu;}char* GotoNextLine( char *psz_text ){ char *p_newline = psz_text; while( p_newline[0] != '\0' ) { if( p_newline[0] == '\n' || p_newline[0] == '\r' ) { p_newline++; while( p_newline[0] == '\n' || p_newline[0] == '\r' ) p_newline++; break; } else p_newline++; } return p_newline;}/* Function now handles tags with attribute values, and tries * to deal with &' commands too. It no longer modifies the string * in place, so that the original text can be reused */static char *StripTags( char *psz_subtitle ){ char *psz_text_start; char *psz_text; psz_text = psz_text_start = malloc( strlen( psz_subtitle ) + 1 ); if( !psz_text_start ) return NULL; while( *psz_subtitle ) { if( *psz_subtitle == '<' ) { if( strncasecmp( psz_subtitle, "<br/>", 5 ) == 0 ) *psz_text++ = '\n'; psz_subtitle += strcspn( psz_subtitle, ">" ); } else if( *psz_subtitle == '&' ) { if( !strncasecmp( psz_subtitle, "<", 4 )) { *psz_text++ = '<'; psz_subtitle += strcspn( psz_subtitle, ";" ); } else if( !strncasecmp( psz_subtitle, ">", 4 )) { *psz_text++ = '>'; psz_subtitle += strcspn( psz_subtitle, ";" ); } else if( !strncasecmp( psz_subtitle, "&", 5 )) { *psz_text++ = '&'; psz_subtitle += strcspn( psz_subtitle, ";" ); } else if( !strncasecmp( psz_subtitle, """, 6 )) { *psz_text++ = '\"'; psz_subtitle += strcspn( psz_subtitle, ";" ); } else { /* Assume it is just a normal ampersand */ *psz_text++ = '&'; } } else { *psz_text++ = *psz_subtitle; } psz_subtitle++; } *psz_text = '\0'; psz_text_start = realloc( psz_text_start, strlen( psz_text_start ) + 1 ); return psz_text_start;}/* Try to respect any style tags present in the subtitle string. The main * problem here is a lack of adequate specs for the subtitle formats. * SSA/ASS and USF are both detail spec'ed -- but they are handled elsewhere. * SAMI has a detailed spec, but extensive rework is needed in the demux * code to prevent all this style information being excised, as it presently * does. * That leaves the others - none of which were (I guess) originally intended * to be carrying style information. Over time people have used them that way. * In the absence of specifications from which to work, the tags supported * have been restricted to the simple set permitted by the USF DTD, ie. : * Basic: <br>, <i>, <b>, <u> * Extended: <font> * Attributes: face * family * size * color * outline-color * shadow-color * outline-level * shadow-level * back-color * alpha * There is also the further restriction that the subtitle be well-formed * as an XML entity, ie. the HTML sentence: * <b><i>Bold and Italics</b></i> * doesn't qualify because the tags aren't nested one inside the other. * <text> tags are automatically added to the output to ensure * well-formedness. * If the text doesn't qualify for any reason, a NULL string is * returned, and the rendering engine will fall back to the * plain text version of the subtitle. */static void HtmlNPut( char **ppsz_html, const char *psz_text, int i_max ){ const int i_len = strlen(psz_text); strncpy( *ppsz_html, psz_text, i_max ); *ppsz_html += __MIN(i_max,i_len);}static void HtmlPut( char **ppsz_html, const char *psz_text ){ strcpy( *ppsz_html, psz_text ); *ppsz_html += strlen(psz_text);}static void HtmlCopy( char **ppsz_html, char **ppsz_subtitle, const char *psz_text ){ HtmlPut( ppsz_html, psz_text ); *ppsz_subtitle += strlen(psz_text);}static char *CreateHtmlSubtitle( char *psz_subtitle ){ char *psz_tag = malloc( ( strlen( psz_subtitle ) / 3 ) + 1 ); if( !psz_tag ) return NULL; size_t i_buf_size = strlen( psz_subtitle ) + 100; char *psz_html_start = malloc( i_buf_size ); psz_tag[ 0 ] = '\0'; if( psz_html_start == NULL ) { free( psz_tag ); return NULL; } char *psz_html = psz_html_start; strcpy( psz_html, "<text>" ); psz_html += 6; while( *psz_subtitle ) { if( *psz_subtitle == '\n' ) { HtmlPut( &psz_html, "<br/>" ); psz_subtitle++; } else if( *psz_subtitle == '<' ) { if( !strncasecmp( psz_subtitle, "<br/>", 5 )) { HtmlCopy( &psz_html, &psz_subtitle, "<br/>" ); } else if( !strncasecmp( psz_subtitle, "<b>", 3 ) ) { HtmlCopy( &psz_html, &psz_subtitle, "<b>" ); strcat( psz_tag, "b" ); } else if( !strncasecmp( psz_subtitle, "<i>", 3 ) ) { HtmlCopy( &psz_html, &psz_subtitle, "<i>" ); strcat( psz_tag, "i" ); } else if( !strncasecmp( psz_subtitle, "<u>", 3 ) ) { HtmlCopy( &psz_html, &psz_subtitle, "<u>" ); strcat( psz_tag, "u" ); } else if( !strncasecmp( psz_subtitle, "<font ", 6 )) { const char *psz_attribs[] = { "face=", "family=", "size=", "color=", "outline-color=", "shadow-color=", "outline-level=", "shadow-level=", "back-color=", "alpha=", NULL }; HtmlCopy( &psz_html, &psz_subtitle, "<font " ); strcat( psz_tag, "f" ); while( *psz_subtitle != '>' ) { int k; for( k=0; psz_attribs[ k ]; k++ ) { int i_len = strlen( psz_attribs[ k ] ); if( !strncasecmp( psz_subtitle, psz_attribs[k], i_len ) ) { /* */ HtmlPut( &psz_html, psz_attribs[k] ); psz_subtitle += i_len; /* */ if( *psz_subtitle == '"' ) { psz_subtitle++; i_len = strcspn( psz_subtitle, "\"" ); } else { i_len = strcspn( psz_subtitle, " \t>" ); } HtmlPut( &psz_html, "\"" ); if( !strcmp( psz_attribs[ k ], "color=" ) && *psz_subtitle >= '0' && *psz_subtitle <= '9' ) HtmlPut( &psz_html, "#" ); HtmlNPut( &psz_html, psz_subtitle, i_len ); HtmlPut( &psz_html, "\"" ); psz_subtitle += i_len; if( *psz_subtitle == '\"' ) psz_subtitle++; break; } } if( psz_attribs[ k ] == NULL ) { /* Jump over unrecognised tag */ int i_len = strcspn( psz_subtitle, "\"" ) + 1; i_len += strcspn( psz_subtitle + i_len, "\"" ) + 1; psz_subtitle += i_len; } while (*psz_subtitle == ' ') *psz_html++ = *psz_subtitle++; } *psz_html++ = *psz_subtitle++; } else if( !strncmp( psz_subtitle, "</", 2 )) { bool b_match = false; int i_len = strlen( psz_tag ) - 1; char *psz_lastTag = NULL; if( i_len >= 0 ) { psz_lastTag = psz_tag + i_len; i_len = 0; switch( *psz_lastTag ) { case 'b': b_match = !strncasecmp( psz_subtitle, "</b>", 4 ); i_len = 4; break; case 'i': b_match = !strncasecmp( psz_subtitle, "</i>", 4 ); i_len = 4; break; case 'u': b_match = !strncasecmp( psz_subtitle, "</u>", 4 ); i_len = 4; break; case 'f': b_match = !strncasecmp( psz_subtitle, "</font>", 7 ); i_len = 7; break; } } if( ! b_match ) { /* Not well formed -- kill everything */ free( psz_html_start ); psz_html_start = NULL; break; } *psz_lastTag = '\0'; strncpy( psz_html, psz_subtitle, i_len ); psz_html += i_len; psz_subtitle += i_len; } else { psz_subtitle += strcspn( psz_subtitle, ">" ); } } else if( *psz_subtitle == '&' ) { if( !strncasecmp( psz_subtitle, "<", 4 )) { HtmlCopy( &psz_html, &psz_subtitle, "<" ); } else if( !strncasecmp( psz_subtitle, ">", 4 )) { HtmlCopy( &psz_html, &psz_subtitle, ">" ); } else if( !strncasecmp( psz_subtitle, "&", 5 )) { HtmlCopy( &psz_html, &psz_subtitle, "&" ); } else { HtmlPut( &psz_html, "&" ); psz_subtitle++; } } else { *psz_html = *psz_subtitle; if( psz_html > psz_html_start ) { /* Check for double whitespace */ if( ( *psz_html == ' ' || *psz_html == '\t' ) && ( *(psz_html-1) == ' ' || *(psz_html-1) == '\t' ) ) { HtmlPut( &psz_html, NO_BREAKING_SPACE ); psz_html--; } } psz_html++; psz_subtitle++; } if( ( size_t )( psz_html - psz_html_start ) > i_buf_size - 50 ) { int i_len = psz_html - psz_html_start; i_buf_size += 200; psz_html_start = realloc( psz_html_start, i_buf_size ); psz_html = psz_html_start + i_len; *psz_html = '\0'; } } strcpy( psz_html, "</text>" ); psz_html += 7; if( psz_tag[ 0 ] != '\0' ) { /* Not well formed -- kill everything */ free( psz_html_start ); psz_html_start = NULL; } else if( psz_html_start ) { /* Shrink the memory requirements */ psz_html_start = realloc( psz_html_start, psz_html - psz_html_start + 1 ); } free( psz_tag ); return psz_html_start;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -