Commit 4d4eb334 authored by Laurent Aimar's avatar Laurent Aimar

all: Subtitle improvment patch by Bernie Purcell.

Author comments:

It makes the following changes:
* Changes to vout_subpictures.c to create some new variables which
renderers are free to use to render time-specific subtitling
information, such as karaoke. One of these variables allows for the text
region to not be permanently converted to YUVA/YUVP - so that more than
one pass can be made on the subtitle - so that it will update correctly
over time. If a rendering module doesn't use or change any of the
variables it behaves the same as usual, with the text region being
rendered just the once to a YUVA/YUVP region and then just blended to
the video on future passes.

* Changes to alignment implementation: no longer use the i_text_align
field of font_style_t at all; require the alignment to be correctly
setup solely in the subpicture_region_t's i_align field (this is so that
the alignment initially inherited from a style can be overridden). This
meant minor changes to freetype.c and quartztext.c as well as the
deletion of the i_text_align field in vlc_osd.h. It also involved some
changes in subsdec.c, where most of the work in this patch occurs.

* Minor change to quartztext.c to correct the interpretation of font
size parameter, making it consistent with a similar change being made in
subsdec.c, and to strip out multiple whitespace in html subtitles
(Similar changes to the freetype.c module have already been made as part
of a separate larger patch submission to fix problems with bidirectional
styled text in that module)

* Adds 2 new fields for carrying karaoke specific information to the
text_style_t struct in vlc_osd.h. Changed the default_text_style's
definition to agree with the changes made in the fields of text_style_t
struct.

* Support for <image> and <karaoke> subtitles in subsdec.c. (Full
working karaoke also requires an as-yet unsubmitted patch to the
renderers to implement)

* Support for more than one subpicture_region_t per timestamp, with each
subpicture region being able to have its own alignment and margins and
type: text or image

* Better calculation of plain-text versions of html subtitles

NB: This patch still makes use of a mechanism of explicitly requesting
the sdl_image module to decode any images it wants. The main reason for
this is that the bmp decoder in ffmpeg (the image decoder with the
highest score) presently only handles 16, 24 and 32 bit depths. An
alternative is for us to switch off the bmp support in ffmpeg for the
time being and the segment of code in subsdec.c that explicitly requests
this module (along with one line added to sdl_image.c) can be removed.
I'm not fussed by either implementation, but this way probably affects
fewer other modules, so have submitted it this way.
parent 50975df6
...@@ -249,10 +249,13 @@ struct text_style_t ...@@ -249,10 +249,13 @@ struct text_style_t
int i_background_alpha;/**< The transparency of the background. int i_background_alpha;/**< The transparency of the background.
0x00 is fully opaque, 0x00 is fully opaque,
0xFF fully transparent */ 0xFF fully transparent */
int i_karaoke_background_color;/**< Background color for karaoke 0xRRGGBB */
int i_karaoke_background_alpha;/**< The transparency of the karaoke bg.
0x00 is fully opaque,
0xFF fully transparent */
int i_outline_width; /**< The width of the outline in pixels */ int i_outline_width; /**< The width of the outline in pixels */
int i_shadow_width; /**< The width of the shadow in pixels */ int i_shadow_width; /**< The width of the shadow in pixels */
int i_spacing; /**< The spaceing between glyphs in pixels */ int i_spacing; /**< The spaceing between glyphs in pixels */
int i_text_align; /**< An alignment hint for the text */
}; };
/* Style flags for \ref text_style_t */ /* Style flags for \ref text_style_t */
...@@ -265,7 +268,7 @@ struct text_style_t ...@@ -265,7 +268,7 @@ struct text_style_t
#define STYLE_STRIKEOUT 64 #define STYLE_STRIKEOUT 64
static const text_style_t default_text_style = { NULL, 22, 0xffffff, 0xff, STYLE_OUTLINE, static const text_style_t default_text_style = { NULL, 22, 0xffffff, 0xff, STYLE_OUTLINE,
0x000000, 0xff, 0x000000, 0xff, 0xffffff, 0x80, 1, 0, -1, 0 }; 0x000000, 0xff, 0x000000, 0xff, 0xffffff, 0x80, 0xffffff, 0xff, 1, 0, -1 };
......
...@@ -52,6 +52,7 @@ static picture_t *DecodeBlock ( decoder_t *, block_t ** ); ...@@ -52,6 +52,7 @@ static picture_t *DecodeBlock ( decoder_t *, block_t ** );
vlc_module_begin(); vlc_module_begin();
set_category( CAT_INPUT ); set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_VCODEC ); set_subcategory( SUBCAT_INPUT_VCODEC );
set_shortname( _("SDL Image decoder"));
set_description( _("SDL_image video decoder") ); set_description( _("SDL_image video decoder") );
set_capability( "decoder", 60 ); set_capability( "decoder", 60 );
set_callbacks( OpenDecoder, CloseDecoder ); set_callbacks( OpenDecoder, CloseDecoder );
......
This diff is collapsed.
...@@ -486,13 +486,11 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, ...@@ -486,13 +486,11 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region,
if( p_line->i_width < i_width ) if( p_line->i_width < i_width )
{ {
if( ( p_region->p_style && p_region->p_style->i_text_align == SUBPICTURE_ALIGN_RIGHT ) || if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT )
( !p_region->p_style && (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT ) )
{ {
i_align_offset = i_width - p_line->i_width; i_align_offset = i_width - p_line->i_width;
} }
else if( ( p_region->p_style && p_region->p_style->i_text_align != SUBPICTURE_ALIGN_LEFT ) || else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT )
( !p_region->p_style && (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT ) )
{ {
i_align_offset = ( i_width - p_line->i_width ) / 2; i_align_offset = ( i_width - p_line->i_width ) / 2;
} }
...@@ -637,13 +635,11 @@ static void DrawBlack( line_desc_t *p_line, int i_width, subpicture_region_t *p_ ...@@ -637,13 +635,11 @@ static void DrawBlack( line_desc_t *p_line, int i_width, subpicture_region_t *p_
if( p_line->i_width < i_width ) if( p_line->i_width < i_width )
{ {
if( ( p_region->p_style && p_region->p_style->i_text_align == SUBPICTURE_ALIGN_RIGHT ) || if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT )
( !p_region->p_style && (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT ) )
{ {
i_align_offset = i_width - p_line->i_width; i_align_offset = i_width - p_line->i_width;
} }
else if( ( p_region->p_style && p_region->p_style->i_text_align != SUBPICTURE_ALIGN_LEFT ) || else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT )
( !p_region->p_style && (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT ) )
{ {
i_align_offset = ( i_width - p_line->i_width ) / 2; i_align_offset = ( i_width - p_line->i_width ) / 2;
} }
...@@ -789,13 +785,11 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, ...@@ -789,13 +785,11 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region,
if( p_line->i_width < i_width ) if( p_line->i_width < i_width )
{ {
if( ( p_region->p_style && p_region->p_style->i_text_align == SUBPICTURE_ALIGN_RIGHT ) || if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT )
( !p_region->p_style && (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT ) )
{ {
i_align_offset = i_width - p_line->i_width; i_align_offset = i_width - p_line->i_width;
} }
else if( ( p_region->p_style && p_region->p_style->i_text_align != SUBPICTURE_ALIGN_LEFT ) || else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT )
( !p_region->p_style && (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT ) )
{ {
i_align_offset = ( i_width - p_line->i_width ) / 2; i_align_offset = ( i_width - p_line->i_width ) / 2;
} }
...@@ -1784,12 +1778,12 @@ static int ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, ...@@ -1784,12 +1778,12 @@ static int ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader,
int i_whitespace = strspn( s, "\t\r\n " ); int i_whitespace = strspn( s, "\t\r\n " );
if( i_whitespace > 1 ) if( i_whitespace > 1 )
memmove( s + 1, memmove( &s[1],
s + i_whitespace, &s[i_whitespace],
strlen( s ) - i_whitespace + 1 ); strlen( s ) - i_whitespace + 1 );
*s = ' '; *s++ = ' ';
s = strpbrk( s+1, "\t\r\n " ); s = strpbrk( s, "\t\r\n " );
} }
SetupLine( p_filter, psz_node, &psz_text, SetupLine( p_filter, psz_node, &psz_text,
pi_runs, ppi_run_lengths, ppp_styles, pi_runs, ppi_run_lengths, ppp_styles,
......
...@@ -559,6 +559,18 @@ static void ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, ...@@ -559,6 +559,18 @@ static void ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader,
} }
else if( !strcasecmp( "size", psz_name ) ) else if( !strcasecmp( "size", psz_name ) )
{ {
if( ( *psz_value == '+' ) || ( *psz_value == '-' ) )
{
int i_value = atoi( psz_value );
if( ( i_value >= -5 ) && ( i_value <= 5 ) )
i_font_size += ( i_value * i_font_size ) / 10;
else if( i_value < -5 )
i_font_size = - i_value;
else if( i_value > 5 )
i_font_size = i_value;
}
else
i_font_size = atoi( psz_value ); i_font_size = atoi( psz_value );
} }
else if( !strcasecmp( "color", psz_name ) && else if( !strcasecmp( "color", psz_name ) &&
...@@ -624,6 +636,21 @@ static void ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, ...@@ -624,6 +636,21 @@ static void ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader,
{ {
uint32_t i_string_length; uint32_t i_string_length;
// Turn any multiple-whitespaces into single spaces
char *s = strpbrk( psz_node, "\t\r\n " );
while( s )
{
int i_whitespace = strspn( s, "\t\r\n " );
if( i_whitespace > 1 )
memmove( &s[1],
&s[i_whitespace],
strlen( s ) - i_whitespace + 1 );
*s++ = ' ';
s = strpbrk( s, "\t\r\n " );
}
ConvertToUTF16( psz_node, &i_string_length, &psz_text ); ConvertToUTF16( psz_node, &i_string_length, &psz_text );
psz_text += i_string_length; psz_text += i_string_length;
...@@ -881,12 +908,7 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, UniCha ...@@ -881,12 +908,7 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, UniCha
if( psz_utf16_str != NULL ) if( psz_utf16_str != NULL )
{ {
int i_text_align = 0; int i_text_align = p_region->i_align & 0x3;
if( p_region->p_style )
i_text_align = p_region->p_style->i_text_align;
else
i_text_align = p_region->i_align & 0x3;
p_offScreen = Compose( i_text_align, psz_utf16_str, i_text_len, p_offScreen = Compose( i_text_align, psz_utf16_str, i_text_len,
i_runs, pi_run_lengths, pp_styles, i_runs, pi_run_lengths, pp_styles,
......
...@@ -653,6 +653,8 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, ...@@ -653,6 +653,8 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend ) while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend )
{ {
video_format_t orig_fmt = p_region->fmt;
vlc_bool_t b_rerender_text = VLC_FALSE;
int i_fade_alpha = 255; int i_fade_alpha = 255;
int i_x_offset = p_region->i_x + i_subpic_x; int i_x_offset = p_region->i_x + i_subpic_x;
int i_y_offset = p_region->i_y + p_subpic->i_y; int i_y_offset = p_region->i_y + p_subpic->i_y;
...@@ -661,6 +663,36 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, ...@@ -661,6 +663,36 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
{ {
if( p_spu->p_text && p_spu->p_text->p_module ) if( p_spu->p_text && p_spu->p_text->p_module )
{ {
vlc_value_t val;
/* Setup 3 variables which can be used to render time-dependent
* text (and effects). The first indicates the total amount of
* time the text will be on screen, the second the amount of time
* it has already been on screen (can be a negative value as text
* is layed out before it is rendered) and the third is a feedback
* variable from the renderer - if the renderer sets it then this
* particular text is time-dependent, eg. the visual progress bar
* inside the text in karaoke and the text needs to be rendered
* multiple times in order for the effect to work - we therefore
* need to return the region to its original state at the end of
* the loop, instead of leaving it in YUVA or YUVP
* Any renderer which is unaware of how to render time-dependent
* text can happily ignore the variables and render the text the
* same as usual - it should at least show up on screen, but the
* effect won't change the text over time.
*/
var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME );
val.i_time = p_subpic->i_stop - p_subpic->i_start;
var_Set( p_spu->p_text, "spu-duration", val );
var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME );
val.i_time = mdate() - p_subpic->i_start;
var_Set( p_spu->p_text, "spu-elapsed", val );
var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL );
var_SetBool( p_spu->p_text, "text-rerender", VLC_FALSE );
if( p_spu->p_text->pf_render_html && p_region->psz_html ) if( p_spu->p_text->pf_render_html && p_region->psz_html )
{ {
p_spu->p_text->pf_render_html( p_spu->p_text, p_spu->p_text->pf_render_html( p_spu->p_text,
...@@ -671,6 +703,12 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, ...@@ -671,6 +703,12 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
p_spu->p_text->pf_render_text( p_spu->p_text, p_spu->p_text->pf_render_text( p_spu->p_text,
p_region, p_region ); p_region, p_region );
} }
b_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" );
var_Destroy( p_spu->p_text, "spu-duration" );
var_Destroy( p_spu->p_text, "spu-elapsed" );
var_Destroy( p_spu->p_text, "text-rerender" );
} }
} }
...@@ -855,6 +893,16 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt, ...@@ -855,6 +893,16 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
p_pic_src, &p_region->picture, i_x_offset, i_y_offset, p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
i_fade_alpha * p_subpic->i_alpha / 255 ); i_fade_alpha * p_subpic->i_alpha / 255 );
if( b_rerender_text )
{
/* Some forms of subtitles need to be re-rendered more than once,
* eg. karaoke. We therefore restore the region to its pre-rendered
* state, so the next time through everything is calculated again.
*/
p_region->picture.pf_release( &p_region->picture );
memset( &p_region->picture, 0, sizeof( picture_t ) );
p_region->fmt = orig_fmt;
}
p_region = p_region->p_next; p_region = p_region->p_next;
} }
......
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