Commit f2e43bd7 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen Committed by Jean-Baptiste Kempf

Subtitle renderers: Merge RenderText & RenderHTML

The current workflow is often parsing a subtitle format, then convert it
in a common HTML and then push it to the renderer as HTML. The renderer
will reparse the HTML and try to render it. Of course, that means that
only one renderer can do that correctly, and so we bloat the freetype
renderer as much as we can.
It also means that we have 2 render callbacks for subtitles, one for
normal text and one for styled text, and we sometimes reparse the HTML
to remove the tags, for the first.

We now only use a text_segment, with new segments at every style change;
an unique render function and the renderer can decide to honor or not
the style.

It's a big commit, so regressions can arise, but it was tested for most
common cases.
parent b8ce6743
......@@ -136,15 +136,11 @@ struct filter_t
struct
{
int (*pf_text) ( filter_t *, subpicture_region_t *,
subpicture_region_t *,
const vlc_fourcc_t * );
int (*pf_html) ( filter_t *, subpicture_region_t *,
int (*pf_render) ( filter_t *, subpicture_region_t *,
subpicture_region_t *,
const vlc_fourcc_t * );
} render;
#define pf_render_text u.render.pf_text
#define pf_render_html u.render.pf_html
#define pf_render u.render.pf_render
} u;
......
......@@ -65,8 +65,6 @@ struct subpicture_region_t
int i_alpha; /**< transparency */
text_segment_t *p_text; /**< subtitle text, made of a list of segments */
char *psz_html; /**< HTML version of subtitle (NULL = use psz_text) */
text_style_t *p_style; /**< a description of the text style formatting */
bool b_renderbg; /**< render black background under text */
subpicture_region_t *p_next; /**< next region in the list */
......
......@@ -298,7 +298,6 @@ static subpicture_t *render( decoder_t *p_dec, arib_parser_t *p_parser,
p_region->psz_text = strdup( psz_text );
free( psz_text );
p_region->psz_html = NULL;
p_region->psz_fontname = NULL;
p_region->i_font_color = p_buf_region->i_foreground_color;
p_region->i_planewidth = p_buf_region->i_planewidth;
......
......@@ -23,7 +23,6 @@
typedef struct arib_text_region_s
{
char *psz_text;
char *psz_html;
char *psz_fontname;
int i_font_color;
......@@ -97,9 +96,7 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
return;
}
if( p_region->psz_text )
r->p_text = text_segment_New( p_region->psz_text );
r->psz_html = p_region->psz_html ? strdup(p_region->psz_html) : NULL;
r->p_text = text_segment_New( p_region->psz_text );
r->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
subpic->i_original_picture_width = p_region->i_planewidth;
......@@ -107,16 +104,16 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
r->i_x = p_region->i_charleft - (p_region->i_fontwidth + p_region->i_horint / 2) + p_region->i_charleft_adj;
r->i_y = p_region->i_charbottom - (p_region->i_fontheight + p_region->i_verint / 2) + p_region->i_charbottom_adj;
r->p_style = text_style_New();
r->p_style->psz_fontname = p_region->psz_fontname ? strdup( p_region->psz_fontname ) : NULL;
r->p_style->i_font_size = p_region->i_fontheight;
r->p_style->i_font_color = p_region->i_font_color;
r->p_style->i_style_flags = 0;
r->p_text->style = text_style_New();
r->p_text->style->psz_fontname = p_region->psz_fontname ? strdup( p_region->psz_fontname ) : NULL;
r->p_text->style->i_font_size = p_region->i_fontheight;
r->p_text->style->i_font_color = p_region->i_font_color;
r->p_text->style->i_style_flags = 0;
if( p_region->i_fontwidth < p_region->i_fontheight )
{
r->p_style->i_style_flags |= STYLE_HALFWIDTH;
r->p_text->style->i_style_flags |= STYLE_HALFWIDTH;
}
r->p_style->i_spacing = p_region->i_horint;
r->p_text->style->i_spacing = p_region->i_horint;
}
}
static void SubpictureTextDestroy(subpicture_t *subpic)
......@@ -127,7 +124,6 @@ static void SubpictureTextDestroy(subpicture_t *subpic)
for( p_region = sys->p_region; p_region; p_region = p_region_next )
{
free( p_region->psz_text );
free( p_region->psz_html );
free( p_region->psz_fontname );
p_region_next = p_region->p_next;
free( p_region );
......
......@@ -296,7 +296,7 @@ static block_t *Pop( decoder_t *p_dec )
return p_block;
}
static subpicture_t *Subtitle( decoder_t *p_dec, char *psz_subtitle, char *psz_html, mtime_t i_pts )
static subpicture_t *Subtitle( decoder_t *p_dec, char *psz_subtitle, mtime_t i_pts )
{
//decoder_sys_t *p_sys = p_dec->p_sys;
subpicture_t *p_spu = NULL;
......@@ -306,20 +306,16 @@ static subpicture_t *Subtitle( decoder_t *p_dec, char *psz_subtitle, char *psz_h
{
msg_Warn( p_dec, "subtitle without a date" );
free( psz_subtitle );
free( psz_html );
return NULL;
}
EnsureUTF8( psz_subtitle );
if( psz_html )
EnsureUTF8( psz_html );
/* Create the subpicture unit */
p_spu = decoder_NewSubpictureText( p_dec );
if( !p_spu )
{
free( psz_subtitle );
free( psz_html );
return NULL;
}
p_spu->i_start = i_pts;
......@@ -332,11 +328,12 @@ static subpicture_t *Subtitle( decoder_t *p_dec, char *psz_subtitle, char *psz_h
/* The "leavetext" alignment is a special mode where the subpicture
region itself gets aligned, but the text inside it does not */
p_spu_sys->align = SUBPICTURE_ALIGN_LEAVETEXT;
p_spu_sys->text = psz_subtitle;
p_spu_sys->html = psz_html;
p_spu_sys->p_segments = text_segment_New( psz_subtitle );
p_spu_sys->i_font_height_percent = 5;
p_spu_sys->renderbg = true;
free( psz_subtitle );
return p_spu;
}
......@@ -362,9 +359,8 @@ static subpicture_t *Convert( decoder_t *p_dec, block_t *p_block )
if( b_changed )
{
char *psz_subtitle = Eia608Text( &p_sys->eia608, false );
char *psz_html = Eia608Text( &p_sys->eia608, true );
return Subtitle( p_dec, psz_subtitle, psz_html, i_pts );
return Subtitle( p_dec, psz_html, i_pts );
}
return NULL;
}
......
......@@ -702,20 +702,13 @@ static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *
switch( ev->text_markup_type )
{
case kate_markup_none:
p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
break;
case kate_markup_simple:
if( p_sys->b_formatted )
{
/* the HTML renderer expects a top level text tag pair */
char *buffer = NULL;
if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
{
p_spu->p_region->psz_html = buffer;
}
break;
}
/* if not formatted, we fall through */
// p_spu->p_region->p_text = ParseSubtitles(&p_spu->p_region->i_align, ev->text );
;//FIXME
else
p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
break;
default:
/* we don't know about this one, so remove markup and display as text */
{
......@@ -723,6 +716,7 @@ static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *
size_t len0 = strlen( copy ) + 1;
kate_text_remove_markup( ev->text_encoding, copy, &len0 );
p_spu->p_region->p_text = text_segment_New( copy );
free( copy );
}
break;
}
......
......@@ -461,80 +461,15 @@ static subpicture_t *ParseText( decoder_t *p_dec, block_t *p_block )
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM | p_sys->i_align;
p_spu_sys->text = StripTags( psz_subtitle );
if( var_InheritBool( p_dec, "subsdec-formatted" ) )
p_spu_sys->html = CreateHtmlSubtitle( &p_spu_sys->align, psz_subtitle );
char* psz_sub = CreateHtmlSubtitle( &p_spu_sys->align, psz_subtitle );
p_spu_sys->p_segments = text_segment_New( psz_sub );
free( psz_subtitle );
//FIXME: Remove the variable?
//if( var_InheritBool( p_dec, "subsdec-formatted" ) )
return p_spu;
}
/* 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;
free( psz_sub );
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, "&lt;", 4 ))
{
*psz_text++ = '<';
psz_subtitle += strcspn( psz_subtitle, ";" );
}
else if( !strncasecmp( psz_subtitle, "&gt;", 4 ))
{
*psz_text++ = '>';
psz_subtitle += strcspn( psz_subtitle, ";" );
}
else if( !strncasecmp( psz_subtitle, "&amp;", 5 ))
{
*psz_text++ = '&';
psz_subtitle += strcspn( psz_subtitle, ";" );
}
else if( !strncasecmp( psz_subtitle, "&quot;", 6 ))
{
*psz_text++ = '\"';
psz_subtitle += strcspn( psz_subtitle, ";" );
}
else
{
/* Assume it is just a normal ampersand */
*psz_text++ = '&';
}
}
else
{
*psz_text++ = *psz_subtitle;
}
/* Security fix: Account for the case where input ends early */
if( *psz_subtitle == '\0' ) break;
psz_subtitle++;
}
*psz_text = '\0';
char *psz = realloc( psz_text_start, strlen( psz_text_start ) + 1 );
if( psz ) psz_text_start = psz;
return psz_text_start;
return p_spu;
}
/* Try to respect any style tags present in the subtitle string. The main
......
......@@ -8,9 +8,7 @@ typedef struct
} subpicture_updater_sys_option_t;
struct subpicture_updater_sys_t {
char *text;
char *html;
text_segment_t *p_htmlsegments;
text_segment_t *p_segments;
int align;
int x;
......@@ -32,116 +30,6 @@ struct subpicture_updater_sys_t {
int16_t i_drop_shadow_alpha;
};
static void MakeHtmlNewLines( char **ppsz_src )
{
unsigned int i_nlcount = 0;
unsigned i_len = strlen( *ppsz_src );
if ( i_len == 0 ) return;
for ( unsigned i=0; i<i_len; i++ )
if ( (*ppsz_src)[i] == '\n' )
i_nlcount++;
if ( !i_nlcount ) return;
char *psz_dst = malloc( i_len + 1 + (i_nlcount * 4) );
char *ptr = psz_dst;
for ( unsigned i=0; i<i_len; i++ )
{
if ( (*ppsz_src)[i] == '\n' )
{
strcpy( ptr, "<br/>" );
ptr += 5;
} else {
*ptr++ = (*ppsz_src)[i];
}
}
*ptr = 0;
free( *ppsz_src );
*ppsz_src = psz_dst;
}
static void HtmlAppend( char **ppsz_dst, const char *psz_src,
const text_style_t *p_styles, const float f_scale )
{
if ( !ppsz_dst ) return;
int i_return;
char *psz_subtext = NULL;
char *psz_text = NULL;
char *psz_fontsize = NULL;
char *psz_color = NULL;
char *psz_encoded = convert_xml_special_chars( psz_src );
if ( !psz_encoded ) return;
MakeHtmlNewLines( &psz_encoded );
if ( p_styles->i_font_alpha > 0 ) //ARGB
{
i_return = asprintf( &psz_color, " color=\"#%6x\"",
p_styles->i_font_color & 0x00FFFFFF );
if ( i_return < 0 ) psz_color = NULL;
}
if ( p_styles->i_font_size > 0 && f_scale > 0 )
{
i_return = asprintf( &psz_fontsize, " size=\"%u\"",
(unsigned) (f_scale * p_styles->i_font_size) );
if ( i_return < 0 ) psz_fontsize = NULL;
}
i_return = asprintf( &psz_subtext, "%s%s%s%s%s%s%s",
( p_styles->i_style_flags & STYLE_UNDERLINE ) ? "<u>" : "",
( p_styles->i_style_flags & STYLE_BOLD ) ? "<b>" : "",
( p_styles->i_style_flags & STYLE_ITALIC ) ? "<i>" : "",
psz_encoded,
( p_styles->i_style_flags & STYLE_ITALIC ) ? "</i>" : "",
( p_styles->i_style_flags & STYLE_BOLD ) ? "</b>" : "",
( p_styles->i_style_flags & STYLE_UNDERLINE ) ? "</u>" : ""
);
if ( i_return < 0 ) psz_subtext = NULL;
if ( psz_color || psz_fontsize )
{
i_return = asprintf( &psz_text, "<font%s%s>%s</font>",
psz_color ? psz_color : "",
psz_fontsize ? psz_fontsize : "",
psz_subtext );
if ( i_return < 0 ) psz_text = NULL;
free( psz_subtext );
}
else
{
psz_text = psz_subtext;
}
free( psz_fontsize );
free( psz_color );
if ( *ppsz_dst )
{
char *psz_dst = *ppsz_dst;
i_return = asprintf( ppsz_dst, "%s%s", psz_dst, psz_text );
if ( i_return < 0 ) ppsz_dst = NULL;
free( psz_dst );
free( psz_text );
}
else
*ppsz_dst = psz_text;
}
static char *SegmentsToHtml( text_segment_t *p_head, const float f_scale )
{
char *psz_dst = NULL;
char *psz_ret = NULL;
while( p_head )
{
HtmlAppend( &psz_dst, p_head->psz_text, p_head->style, f_scale );
p_head = p_head->p_next;
}
int i_ret = asprintf( &psz_ret, "<text>%s</text>", psz_dst );
if ( i_ret < 0 ) psz_ret = NULL;
free( psz_dst );
return psz_ret;
}
static int SubpictureTextValidate(subpicture_t *subpic,
bool has_src_changed, const video_format_t *fmt_src,
bool has_dst_changed, const video_format_t *fmt_dst,
......@@ -164,6 +52,7 @@ static int SubpictureTextValidate(subpicture_t *subpic,
}
return VLC_EGENERIC;
}
static void SubpictureTextUpdate(subpicture_t *subpic,
const video_format_t *fmt_src,
const video_format_t *fmt_dst,
......@@ -187,14 +76,7 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
if (!r)
return;
r->p_text = sys->text ? text_segment_New( sys->text ): NULL;
if ( sys->p_htmlsegments )
r->psz_html = SegmentsToHtml( sys->p_htmlsegments,
(float) fmt_dst->i_height / fmt_src->i_height );
else if ( sys->html )
r->psz_html = strdup(sys->html);
else
r->psz_html = NULL;
r->p_text = sys->p_segments;
r->i_align = sys->align;
r->b_renderbg = sys->renderbg;
if (!sys->is_fixed) {
......@@ -224,47 +106,43 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
sys->font_color.b_set ||
sys->background_color.b_set )
{
r->p_style = text_style_New();
if (!r->p_style) return;
if (sys->i_font_height_abs_to_src)
sys->i_font_height_percent = sys->i_font_height_abs_to_src * 100 /
fmt_src->i_visible_height;
if (sys->i_font_height_percent)
//FIXME: Is this used for something else than tx3g?
for ( text_segment_t* p_segment = sys->p_segments; p_segment; p_segment = p_segment->p_next )
{
r->p_style->i_font_size = sys->i_font_height_percent *
subpic->i_original_picture_height / 100;
r->p_style->i_font_color = 0xffffff;
r->p_style->i_font_alpha = 0xff;
text_style_t* p_style = p_segment->style;
if (sys->i_font_height_abs_to_src)
sys->i_font_height_percent = sys->i_font_height_abs_to_src * 100 /
fmt_src->i_visible_height;
if (sys->i_font_height_percent)
{
p_style->i_font_size = sys->i_font_height_percent *
subpic->i_original_picture_height / 100;
p_style->i_font_color = 0xffffff;
p_style->i_font_alpha = 0xff;
}
if (sys->style_flags.b_set)
p_style->i_style_flags = sys->style_flags.i_value;
if (sys->font_color.b_set)
p_style->i_font_color = sys->font_color.i_value;
if (sys->background_color.b_set)
p_style->i_background_color = sys->background_color.i_value;
if (sys->i_alpha)
p_style->i_font_alpha = sys->i_alpha;
if (sys->i_drop_shadow)
p_style->i_shadow_width = sys->i_drop_shadow;
if (sys->i_drop_shadow_alpha)
p_style->i_shadow_alpha = sys->i_drop_shadow_alpha;
}
if (sys->style_flags.b_set)
r->p_style->i_style_flags = sys->style_flags.i_value;
if (sys->font_color.b_set)
r->p_style->i_font_color = sys->font_color.i_value;
if (sys->background_color.b_set)
r->p_style->i_background_color = sys->background_color.i_value;
if (sys->i_alpha)
r->p_style->i_font_alpha = sys->i_alpha;
if (sys->i_drop_shadow)
r->p_style->i_shadow_width = sys->i_drop_shadow;
if (sys->i_drop_shadow_alpha)
r->p_style->i_shadow_alpha = sys->i_drop_shadow_alpha;
}
}
static void SubpictureTextDestroy(subpicture_t *subpic)
{
subpicture_updater_sys_t *sys = subpic->updater.p_sys;
free(sys->text);
free(sys->html);
while( sys->p_htmlsegments )
{
text_segment_t *p_segment = sys->p_htmlsegments;
sys->p_htmlsegments = p_segment->p_next;
text_segment_Delete( p_segment );
}
text_segment_ChainDelete( sys->p_segments );
free(sys);
}
......
......@@ -102,7 +102,8 @@ static subpicture_t *ParseText( decoder_t *p_dec, block_t *p_block )
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM | p_sys->i_align;
p_spu_sys->text = psz_subtitle;
p_spu_sys->p_segments = text_segment_New( psz_subtitle );
free( psz_subtitle );
return p_spu;
}
......
......@@ -379,8 +379,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
p_spu->b_absolute = false;
p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM;
p_spu_sys->text = psz_subtitle;
p_spu_sys->p_htmlsegments = p_segment;
p_spu_sys->p_segments = p_segment;
block_Release( p_block );
......
......@@ -429,14 +429,7 @@ static subpicture_region_t *CreateTextRegion( decoder_t *p_dec,
{
ssa_style_t *p_ssa_style = NULL;
p_text_region->psz_html = strndup( psz_subtitle, i_len );
if( ! p_text_region->psz_html )
{
subpicture_region_Delete( p_text_region );
return NULL;
}
p_ssa_style = ParseStyle( p_sys, p_text_region->psz_html );
p_ssa_style = ParseStyle( p_sys, psz_subtitle );
if( !p_ssa_style )
{
int i;
......@@ -452,7 +445,6 @@ static subpicture_region_t *CreateTextRegion( decoder_t *p_dec,
{
msg_Dbg( p_dec, "style is: %s", p_ssa_style->psz_stylename );
p_text_region->p_style = text_style_Duplicate( &p_ssa_style->font_style );
p_text_region->i_align = p_ssa_style->i_align;
/* TODO: Setup % based offsets properly, without adversely affecting
......@@ -464,13 +456,14 @@ static subpicture_region_t *CreateTextRegion( decoder_t *p_dec,
*/
p_text_region->i_x = p_ssa_style->i_margin_h;
p_text_region->i_y = p_ssa_style->i_margin_v;
p_text_region->p_text = text_segment_NewInheritStyle( &p_ssa_style->font_style );
}
else
{
p_text_region->i_align = SUBPICTURE_ALIGN_BOTTOM | i_sys_align;
p_text_region->i_x = i_sys_align ? 20 : 0;
p_text_region->i_y = 10;
p_text_region->p_text = text_segment_New( NULL );
}
/* Look for position arguments which may override the style-based
* defaults.
......@@ -825,45 +818,8 @@ static subpicture_region_t *ParseUSFString( decoder_t *p_dec,
{
char *psz_end = NULL;
if(( !strncasecmp( psz_subtitle, "<text ", 6 )) ||
( !strncasecmp( psz_subtitle, "<text>", 6 )))
{
psz_end = strcasestr( psz_subtitle, "</text>" );
if( psz_end )
{
subpicture_region_t *p_text_region;
psz_end += strcspn( psz_end, ">" ) + 1;
p_text_region = CreateTextRegion( p_dec,
psz_subtitle,
psz_end - psz_subtitle,
p_sys->i_align );
if( p_text_region )
{
p_text_region->p_text = text_segment_New( CreatePlainText( p_text_region->psz_html ) );
if( ! var_CreateGetBool( p_dec, "subsdec-formatted" ) )
{
free( p_text_region->psz_html );
p_text_region->psz_html = NULL;
}
}
if( !p_region_first )
{
p_region_first = p_region_upto = p_text_region;
}
else if( p_text_region )
{
p_region_upto->p_next = p_text_region;
p_region_upto = p_region_upto->p_next;
}
}
}
else if(( !strncasecmp( psz_subtitle, "<karaoke ", 9 )) ||
if(( !strncasecmp( psz_subtitle, "<karaoke ", 9 )) ||
( !strncasecmp( psz_subtitle, "<karaoke>", 9 )))
{
psz_end = strcasestr( psz_subtitle, "</karaoke>" );
......@@ -879,14 +835,6 @@ static subpicture_region_t *ParseUSFString( decoder_t *p_dec,
psz_end - psz_subtitle,
p_sys->i_align );
if( p_text_region )
{
if( ! var_CreateGetBool( p_dec, "subsdec-formatted" ) )
{
free( p_text_region->psz_html );
p_text_region->psz_html = NULL;
}
}
if( !p_region_first )
{
p_region_first = p_region_upto = p_text_region;
......@@ -941,9 +889,6 @@ static subpicture_region_t *ParseUSFString( decoder_t *p_dec,
SetupPositions( p_image_region, psz_subtitle );
p_image_region->p_next = NULL;
p_image_region->p_text = NULL;
p_image_region->psz_html = NULL;
}
if( !p_region_first )
{
......@@ -955,6 +900,33 @@ static subpicture_region_t *ParseUSFString( decoder_t *p_dec,
p_region_upto = p_region_upto->p_next;
}
}
else
{
subpicture_region_t *p_text_region;
psz_end += strcspn( psz_end, ">" ) + 1;
p_text_region = CreateTextRegion( p_dec,
psz_subtitle,
psz_end - psz_subtitle,
p_sys->i_align );
if( p_text_region )
{
free( p_text_region->p_text->psz_text );
p_text_region->p_text->psz_text = CreatePlainText( psz_subtitle );
}
if( !p_region_first )
{
p_region_first = p_region_upto = p_text_region;
}
else if( p_text_region )
{
p_region_upto->p_next = p_text_region;
p_region_upto = p_region_upto->p_next;
}
}
if( psz_end )
psz_subtitle = psz_end - 1;
......
......@@ -384,7 +384,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
if( !p_spu )
goto error;
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
p_spu_sys->text = strdup("");
p_spu_sys->p_segments = text_segment_New("");
p_sys->b_update = true;
p_sys->i_last_page = i_wanted_page;
......@@ -441,7 +441,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
offset++;
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
p_spu_sys->text = strdup( &p_text[offset] );
p_spu_sys->p_segments = text_segment_New( &p_text[offset] );
p_spu_sys->align = i_align;
p_spu_sys->i_font_height_percent = 5;
......
......@@ -913,28 +913,22 @@ static xml_reader_t *GetXMLReader( filter_t *p_filter, stream_t *p_sub )
* needed glyphs into memory. It is used as pf_add_string callback in
* the vout method by this module
*/
static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out,
subpicture_region_t *p_region_in, bool b_html,
static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
filter_sys_t *p_sys = p_filter->p_sys;
if( !p_region_in )
return VLC_EGENERIC;
if( b_html && !p_region_in->psz_html )
return VLC_EGENERIC;
if( !b_html && !p_region_in->p_text && !p_region_in->p_text->psz_text )
return VLC_EGENERIC;
const size_t i_text_max = strlen( b_html ? p_region_in->psz_html
: p_region_in->p_text->psz_text );
text_style_t **pp_styles = NULL;
size_t i_text_length = 0;
uni_char_t *psz_text = SegmentsToTextAndStyles( p_region_in->p_text, &i_text_length, &pp_styles );
uni_char_t *psz_text = calloc( i_text_max, sizeof( *psz_text ) );
text_style_t **pp_styles = calloc( i_text_max, sizeof( *pp_styles ) );
if( !psz_text || !pp_styles )
{
free( psz_text );
free( pp_styles );
return VLC_EGENERIC;
}
......@@ -943,113 +937,15 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out,
/* */
int rv = VLC_SUCCESS;
int i_text_length = 0;
FT_BBox bbox;
int i_max_face_height;
line_desc_t *p_lines = NULL;
uint32_t *pi_k_durations = NULL;
if( b_html )
{
stream_t *p_sub = stream_MemoryNew( VLC_OBJECT(p_filter),
(uint8_t *) p_region_in->psz_html,
strlen( p_region_in->psz_html ),
true );
if( unlikely(p_sub == NULL) )
{
free( psz_text );
free( pp_styles );
return VLC_SUCCESS;
}
xml_reader_t *p_xml_reader = GetXMLReader( p_filter, p_sub );
if( !p_xml_reader )
rv = VLC_EGENERIC;
if( !rv )
{
/* Look for Root Node */
const char *node;
if( xml_ReaderNextNode( p_xml_reader, &node ) == XML_READER_STARTELEM )
{
if( strcasecmp( "karaoke", node ) == 0 )
{
pi_k_durations = calloc( i_text_max, sizeof( *pi_k_durations ) );
}
else if( strcasecmp( "text", node ) != 0 )
{
/* Only text and karaoke tags are supported */
msg_Dbg( p_filter, "Unsupported top-level tag <%s> ignored.",
node );
rv = VLC_EGENERIC;
}
}
else
{
msg_Err( p_filter, "Malformed HTML subtitle" );
rv = VLC_EGENERIC;
}
}
if( !rv )
{
rv = ProcessNodes( p_filter,
psz_text, pp_styles, pi_k_durations, &i_text_length,
p_xml_reader, p_region_in->p_style, &p_filter->p_sys->style );
}
if( p_xml_reader )
p_filter->p_sys->p_xml = xml_ReaderReset( p_xml_reader, NULL );
stream_Delete( p_sub );
}
else
{
text_style_t *p_style;
if( p_region_in->p_style )
{
p_style = CreateStyle( p_region_in->p_style->psz_fontname ? p_region_in->p_style->psz_fontname
: p_sys->style.psz_fontname,
p_region_in->p_style->i_font_size > 0 ? p_region_in->p_style->i_font_size
: p_sys->style.i_font_size,
(p_region_in->p_style->i_font_color & 0xffffff) |
((p_region_in->p_style->i_font_alpha & 0xff) << 24),
0x00ffffff,
p_region_in->p_style->i_style_flags & (STYLE_BOLD |
STYLE_ITALIC |
STYLE_UNDERLINE |
STYLE_STRIKEOUT |
STYLE_HALFWIDTH) );
p_style->i_spacing = p_region_in->p_style->i_spacing;
}
else
{
uint32_t i_font_color = var_InheritInteger( p_filter, "freetype-color" );
i_font_color = VLC_CLIP( i_font_color, 0, 0xFFFFFF );
p_style = CreateStyle( p_sys->style.psz_fontname,
p_sys->style.i_font_size,
(i_font_color & 0xffffff) |
((p_sys->style.i_font_alpha & 0xff) << 24),
0x00ffffff, 0);
}
if( p_sys->style.i_style_flags & STYLE_BOLD )
p_style->i_style_flags |= STYLE_BOLD;
i_text_length = SetupText( p_filter,
psz_text,
pp_styles,
NULL,
p_region_in->p_text->psz_text, p_style, 0 );
}
if( !rv && i_text_length > 0 )
{
rv = LayoutText( p_filter,
&p_lines, &bbox, &i_max_face_height,
psz_text, pp_styles, pi_k_durations, i_text_length );
}
rv = LayoutText( p_filter,
&p_lines, &bbox, &i_max_face_height,
psz_text, pp_styles, pi_k_durations, i_text_length );
p_region_out->i_x = p_region_in->i_x;
p_region_out->i_y = p_region_in->i_y;
......@@ -1107,7 +1003,7 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out,
FreeLines( p_lines );
free( psz_text );
for( int i = 0; i < i_text_length; i++ )
for( size_t i = 0; i < i_text_length; i++ )
{
if( pp_styles[i] && ( i + 1 == i_text_length || pp_styles[i] != pp_styles[i + 1] ) )
text_style_Delete( pp_styles[i] );
......@@ -1118,20 +1014,6 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out,
return rv;
}
static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
return RenderCommon( p_filter, p_region_out, p_region_in, false, p_chroma_list );
}
static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
return RenderCommon( p_filter, p_region_out, p_region_in, true, p_chroma_list );
}
/*****************************************************************************
* Create: allocates osd-text video thread output method
*****************************************************************************
......@@ -1316,8 +1198,7 @@ static int Create( vlc_object_t *p_this )
p_sys->pp_font_attachments = NULL;
p_sys->i_font_attachments = 0;
p_filter->pf_render_text = RenderText;
p_filter->pf_render_html = RenderHtml;
p_filter->pf_render = Render;
LoadFontsFromAttachments( p_filter );
......
......@@ -134,8 +134,7 @@ static int Create( vlc_object_t *p_this )
p_sys->i_width = p_filter->fmt_out.video.i_width;
p_sys->i_height = p_filter->fmt_out.video.i_height;
p_filter->pf_render_text = RenderText;
p_filter->pf_render_html = NULL;
p_filter->pf_render = RenderText;
p_filter->p_sys = p_sys;
/* MUST call this before any RSVG funcs */
......@@ -436,6 +435,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
/* Sanity check */
if( !p_region_in || !p_region_out ) return VLC_EGENERIC;
if( !p_region_in->p_text ) return VLC_EGENERIC;
//FIXME: What should we do when there's more than a single segment?
//Is this refused at codec level?
psz_string = p_region_in->p_text->psz_text;
if( !psz_string || !*psz_string ) return VLC_EGENERIC;
......
......@@ -51,7 +51,6 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
static int OpenRenderer( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t *)p_this;
p_filter->pf_render_text = RenderText;
p_filter->pf_render_html = NULL;
p_filter->pf_render = RenderText;
return VLC_SUCCESS;
}
......@@ -34,6 +34,7 @@
#endif
#include <vlc_common.h>
#include <vlc_charset.h>
#include <vlc_filter.h>
#include <vlc_text_style.h>
......@@ -207,7 +208,7 @@ static void BBoxEnlarge( FT_BBox *p_max, const FT_BBox *p )
static paragraph_t *NewParagraph( filter_t *p_filter,
int i_size,
uni_char_t *p_code_points,
const uni_char_t *p_code_points,
text_style_t **pp_styles,
uint32_t *pi_k_dates,
int i_runs_size )
......@@ -458,11 +459,14 @@ static int ItemizeParagraph( filter_t *p_filter, paragraph_t *p_paragraph )
|| last_script != p_paragraph->p_scripts[ i ]
|| last_level != p_paragraph->p_levels[ i ]
#endif
|| p_last_style->i_font_size != p_paragraph->pp_styles[ i ]->i_font_size
|| ( ( p_last_style->i_style_flags
^ p_paragraph->pp_styles[ i ]->i_style_flags )
& STYLE_HALFWIDTH )
||!FaceStyleEquals( p_last_style, p_paragraph->pp_styles[ i ] ) )
|| ( p_paragraph->pp_styles[ i ] != NULL && (
p_last_style->i_font_size != p_paragraph->pp_styles[ i ]->i_font_size
|| ( ( p_last_style->i_style_flags
^ p_paragraph->pp_styles[ i ]->i_style_flags )
& STYLE_HALFWIDTH )
||!FaceStyleEquals( p_last_style, p_paragraph->pp_styles[ i ] ) )
)
)
{
int i_ret = AddRun( p_filter, p_paragraph, i_last_run_start, i, 0 );
if( i_ret )
......@@ -1203,7 +1207,7 @@ error:
int LayoutText( filter_t *p_filter, line_desc_t **pp_lines,
FT_BBox *p_bbox, int *pi_max_face_height,
uni_char_t *psz_text, text_style_t **pp_styles,
const uni_char_t *psz_text, text_style_t **pp_styles,
uint32_t *pi_k_dates, int i_len )
{
line_desc_t *p_first_line = 0;
......@@ -1311,3 +1315,49 @@ error:
if( p_paragraph ) FreeParagraph( p_paragraph );
return VLC_EGENERIC;
}
uni_char_t* SegmentsToTextAndStyles(const text_segment_t *p_segment, size_t *pi_string_length, text_style_t ***ppp_styles)
{
text_style_t **pp_styles = NULL;
uni_char_t *psz_uni = NULL;
size_t i_size = 0;
for ( const text_segment_t *s = p_segment; s != NULL; s = s->p_next )
{
//FIXME: This is missing a space in between segments.
if ( !s->psz_text )
continue;
size_t i_string_bytes = 0;
uni_char_t *psz_tmp = ToCharset( FREETYPE_TO_UCS, s->psz_text, &i_string_bytes );
if ( !psz_tmp )
{
free( psz_uni );
free( pp_styles );
return NULL;
}
uni_char_t *psz_realloc = realloc(psz_uni, i_size + i_string_bytes);
if ( unlikely( !psz_realloc ) )
{
free( pp_styles );
free( psz_uni );
free( psz_tmp );
return NULL;
}
psz_uni = psz_realloc;
memcpy( psz_uni + i_size, psz_tmp, i_string_bytes );
free( psz_tmp );
text_style_t **pp_styles_realloc = realloc( pp_styles, i_size + i_string_bytes);
if ( unlikely( !pp_styles_realloc ) )
{
free( pp_styles );
free( psz_uni );
return NULL;
}
pp_styles = pp_styles_realloc;
for ( size_t i = i_size; i < (i_size + i_string_bytes) / sizeof(*psz_uni); i++ )
pp_styles[i] = s->style;
i_size += i_string_bytes;
}
*pi_string_length = i_size / sizeof( *psz_uni );
*ppp_styles = pp_styles;
return psz_uni;
}
......@@ -51,7 +51,9 @@ struct line_desc_t
void FreeLines( line_desc_t *p_lines );
line_desc_t *NewLine( int i_count );
int LayoutText( filter_t *p_filter, line_desc_t **pp_lines,
int LayoutText(filter_t *p_filter, line_desc_t **pp_lines,
FT_BBox *p_bbox, int *pi_max_face_height,
uni_char_t *psz_text, text_style_t **pp_styles,
const uni_char_t *psz_text, text_style_t **pp_styles,
uint32_t *pi_k_dates, int i_len );
uni_char_t *SegmentsToTextAndStyles(const text_segment_t *p_segment, size_t *pi_string_length, text_style_t ***ppp_styles );
......@@ -184,8 +184,7 @@ static int Create( vlc_object_t *p_this )
if( SetFont( p_filter, 0 ) != VLC_SUCCESS ) goto error;
free( psz_fontfile );
p_filter->pf_render_text = RenderText;
p_filter->pf_render_html = NULL;
p_filter->pf_render = RenderText;
return VLC_SUCCESS;
error:
......@@ -324,11 +323,11 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
return VLC_EGENERIC;
}
if( p_region_in->p_style )
if( p_region_in->p_text->style )
{
i_font_color = VLC_CLIP( p_region_in->p_style->i_font_color, 0, 0xFFFFFF );
i_font_alpha = VLC_CLIP( p_region_in->p_style->i_font_alpha, 0, 255 );
i_font_size = VLC_CLIP( p_region_in->p_style->i_font_size, 0, 255 );
i_font_color = VLC_CLIP( p_region_in->p_text->style->i_font_color, 0, 0xFFFFFF );
i_font_alpha = VLC_CLIP( p_region_in->p_text->style->i_font_alpha, 0, 255 );
i_font_size = VLC_CLIP( p_region_in->p_text->style->i_font_size, 0, 255 );
}
else
{
......
......@@ -365,7 +365,7 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
if( p_overlay->format.i_chroma == VLC_CODEC_TEXT )
{
p_region->p_text = text_segment_New( p_overlay->data.p_text );
p_region->p_style = text_style_Duplicate( p_overlay->p_fontstyle );
p_region->p_text->style = text_style_Duplicate( p_overlay->p_fontstyle );
}
else
{
......
......@@ -330,7 +330,9 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
p_spu->p_region->i_x = p_sys->i_xoff;
p_spu->p_region->i_y = p_sys->i_yoff;
p_spu->p_region->p_style = text_style_Duplicate( p_sys->p_style );
//FIXME: Provide a way to force a default style to a list of segments
#warning Missing style
//p_spu->p_region->p_style = text_style_Duplicate( p_sys->p_style );
out:
vlc_mutex_unlock( &p_sys->lock );
......
......@@ -500,7 +500,9 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
p_spu->p_region->i_x = p_sys->i_xoff;
p_spu->p_region->i_y = p_sys->i_yoff;
p_spu->p_region->p_style = text_style_Duplicate( p_sys->p_style );
//FIXME: Provide a way to force a default style to a list of segments
#warning Missing style
// p_spu->p_region->p_style = text_style_Duplicate( p_sys->p_style );
if( p_feed->p_pic )
{
......
......@@ -216,7 +216,7 @@ static int SubsdelayCalculateAlpha( filter_t *p_filter, int i_overlapping, int i
static int SubsdelayGetTextRank( char *psz_text );
static bool SubsdelayIsTextEmpty( char *psz_text );
static bool SubsdelayIsTextEmpty( const text_segment_t* p_segment );
/*****************************************************************************
* Subpicture functions
......@@ -1052,8 +1052,8 @@ static void SubpicLocalUpdate( subpicture_t* p_subpic, mtime_t i_ts )
if( p_entry->b_check_empty && p_subpic->p_region )
{
if( SubsdelayIsTextEmpty( p_subpic->p_region->psz_html ) ||
SubsdelayIsTextEmpty( p_subpic->p_region->p_text->psz_text ) )
//FIXME: What if there is more than one segment?
if( SubsdelayIsTextEmpty( p_subpic->p_region->p_text ) )
{
/* remove empty subtitle */
......@@ -1116,8 +1116,7 @@ static void SubpicLocalUpdate( subpicture_t* p_subpic, mtime_t i_ts )
*****************************************************************************/
static bool SubpicIsEmpty( subpicture_t* p_subpic )
{
return ( p_subpic->p_region && ( SubsdelayIsTextEmpty( p_subpic->p_region->psz_html ) ||
SubsdelayIsTextEmpty( p_subpic->p_region->p_text->psz_text ) ) );
return ( p_subpic->p_region && ( SubsdelayIsTextEmpty( p_subpic->p_region->p_text ) ) );
}
/*****************************************************************************
......@@ -1180,17 +1179,10 @@ static int64_t SubsdelayEstimateDelay( filter_t *p_filter, subsdelay_heap_entry_
if( i_mode == SUBSDELAY_MODE_RELATIVE_SOURCE_CONTENT )
{
if( p_entry->p_subpic && p_entry->p_subpic->p_region && ( p_entry->p_subpic->p_region->p_text->psz_text
|| p_entry->p_subpic->p_region->psz_html ) )
if( p_entry->p_subpic && p_entry->p_subpic->p_region && ( p_entry->p_subpic->p_region->p_text ) )
{
if( p_entry->p_subpic->p_region->p_text->psz_text )
{
i_rank = SubsdelayGetTextRank( p_entry->p_subpic->p_region->p_text->psz_text );
}
else
{
i_rank = SubsdelayGetTextRank( p_entry->p_subpic->p_region->psz_html );
}
//FIXME: We only use a single segment here
i_rank = SubsdelayGetTextRank( p_entry->p_subpic->p_region->p_text->psz_text );
return ( i_rank * INT_FACTOR_TO_RANK_FACTOR( i_factor ) );
}
......@@ -1341,13 +1333,18 @@ static int SubsdelayGetTextRank( char *psz_text )
/*****************************************************************************
* SubsdelayIsTextEmpty: Check if the text contains spaces only
*****************************************************************************/
static bool SubsdelayIsTextEmpty( char *psz_text )
static bool SubsdelayIsTextEmpty( const text_segment_t *p_segment )
{
if( !psz_text )
while ( p_segment )
{
return false;
if ( strlen( p_segment->psz_text ) > 0 )
{
size_t offset = strspn( p_segment->psz_text, " " );
if ( p_segment->psz_text[offset] )
return false;
}
p_segment = p_segment->p_next;
}
psz_text += strspn( psz_text, " " );
return !( *psz_text );
return true;
}
......@@ -249,9 +249,6 @@ void subpicture_region_Delete( subpicture_region_t *p_region )
free( p_region->fmt.p_palette );
text_segment_ChainDelete( p_region->p_text );
free( p_region->psz_html );
if( p_region->p_style )
text_style_Delete( p_region->p_style );
free( p_region );
}
......@@ -305,12 +302,6 @@ subpicture_region_t* subpicture_region_Copy( subpicture_region_t *p_region_src )
p_region_dst->i_alpha = p_region_src->i_alpha;
p_region_dst->p_text = text_segment_Copy( p_region_src->p_text );
p_region_dst->psz_html = p_region_src->psz_html ? strdup(p_region_src->psz_html) : NULL;
if (p_region_src->p_style != NULL) {
p_region_dst->p_style = text_style_New();
p_region_dst->p_style = text_style_Copy(p_region_dst->p_style,
p_region_src->p_style);
}
//Palette is already copied by subpicture_region_New, we just have to duplicate p_pixels
for (int i = 0; i < p_region_src->p_picture->i_planes; i++)
......
......@@ -114,16 +114,28 @@ static subpicture_region_t * vout_OSDEpgText(const char *text,
/* Set subpicture parameters */
region->p_text = text_segment_New(text);
if ( unlikely( !region->p_text ) )
{
subpicture_region_Delete( region );
return NULL;
}
region->i_align = 0;
region->i_x = x;
region->i_y = y;
/* Set text style */
region->p_style = text_style_New();
if (region->p_style) {
region->p_style->i_font_size = size;
region->p_style->i_font_color = color;
region->p_style->i_font_alpha = 0;
text_style_t *p_style = text_style_New();
if ( unlikely( !p_style ) )
{
text_segment_Delete( region->p_text );
subpicture_region_Delete( region );
return NULL;
}
region->p_text->style = p_style;
if (p_style) {
p_style->i_font_size = size;
p_style->i_font_color = color;
p_style->i_font_alpha = 0;
}
return region;
......
......@@ -275,10 +275,8 @@ static void SpuRenderText(spu_t *spu, bool *rerender_text,
var_SetInteger(text, "spu-elapsed", elapsed_time);
var_SetBool(text, "text-rerender", false);
if (text->pf_render_html && region->psz_html)
text->pf_render_html(text, region, region, chroma_list);
else if (text->pf_render_text)
text->pf_render_text(text, region, region, chroma_list);
if ( region->p_text )
text->pf_render(text, region, region, chroma_list);
*rerender_text = var_GetBool(text, "text-rerender");
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment