X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Ffreetype.c;h=19b96ab71737519376f052cdf8a4b35d960d9fc2;hb=9e17b696a46b8498c66bc0261e3d90804ee5dea0;hp=c1b874831bbe3476965f0071d17921ffe9adbc20;hpb=f76916ea4acf5da9823e3d057bec765a8c8e1502;p=vlc diff --git a/modules/misc/freetype.c b/modules/misc/freetype.c index c1b874831b..19b96ab717 100644 --- a/modules/misc/freetype.c +++ b/modules/misc/freetype.c @@ -1,4 +1,3 @@ -#include /***************************************************************************** * freetype.c : Put text on the video, using freetype2 ***************************************************************************** @@ -28,24 +27,21 @@ * Preamble *****************************************************************************/ -#ifdef HAVE_LINUX_LIMITS_H -# include +#ifdef HAVE_CONFIG_H +# include "config.h" #endif -#include -#include +#include +#include #include -#include #include #include #include #include +#include #include - -#ifdef HAVE_ERRNO_H -# include -#endif +#include #include #include FT_FREETYPE_H @@ -76,35 +72,14 @@ #include #endif -typedef struct line_desc_t line_desc_t; +#include /***************************************************************************** - * Local prototypes + * Module descriptor *****************************************************************************/ static int Create ( vlc_object_t * ); static void Destroy( vlc_object_t * ); -static int LoadFontsFromAttachments( filter_t *p_filter ); - -/* The RenderText call maps to pf_render_string, defined in vlc_filter.h */ -static int RenderText( filter_t *, subpicture_region_t *, - subpicture_region_t * ); -#ifdef HAVE_FONTCONFIG -static int RenderHtml( filter_t *, subpicture_region_t *, - subpicture_region_t * ); -static char *FontConfig_Select( FcConfig *, const char *, - vlc_bool_t, vlc_bool_t, int * ); -#endif -static line_desc_t *NewLine( int ); - -static int GetFontSize( filter_t *p_filter ); -static int SetFontSize( filter_t *, int ); -static void YUVFromRGB( uint32_t i_argb, - uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ); - -/***************************************************************************** - * Module descriptor - *****************************************************************************/ #define FONT_TEXT N_("Font") #define FONT_LONGTEXT N_("Filename for the font you want to use") #define FONTSIZE_TEXT N_("Font size in pixels") @@ -126,9 +101,9 @@ static void YUVFromRGB( uint32_t i_argb, "fonts that will be rendered on the video. If absolute font size is set, "\ "relative size will be overriden." ) -static int pi_sizes[] = { 20, 18, 16, 12, 6 }; -static const char *ppsz_sizes_text[] = { N_("Smaller"), N_("Small"), N_("Normal"), - N_("Large"), N_("Larger") }; +static const int pi_sizes[] = { 20, 18, 16, 12, 6 }; +static const char *const ppsz_sizes_text[] = { + N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") }; #define YUVP_TEXT N_("Use YUVP renderer") #define YUVP_LONGTEXT N_("This renders the font using \"paletized YUV\". " \ "This option is only needed if you want to encode into DVB subtitles" ) @@ -140,54 +115,79 @@ static const char *ppsz_sizes_text[] = { N_("Smaller"), N_("Small"), N_("Normal" #define EFFECT_OUTLINE 2 #define EFFECT_OUTLINE_FAT 3 -static int pi_effects[] = { 1, 2, 3 }; -static const char *ppsz_effects_text[] = { N_("Background"),N_("Outline"), - N_("Fat Outline") }; -static int pi_color_values[] = { +static int const pi_effects[] = { 1, 2, 3 }; +static const char *const ppsz_effects_text[] = { + N_("Background"),N_("Outline"), N_("Fat Outline") }; +static const int pi_color_values[] = { 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF }; -static const char *ppsz_color_descriptions[] = { +static const char *const ppsz_color_descriptions[] = { N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") }; -vlc_module_begin(); - set_shortname( _("Text renderer")); - set_description( _("Freetype2 font renderer") ); - set_category( CAT_VIDEO ); - set_subcategory( SUBCAT_VIDEO_SUBPIC ); +vlc_module_begin () + set_shortname( N_("Text renderer")) + set_description( N_("Freetype2 font renderer") ) + set_category( CAT_VIDEO ) + set_subcategory( SUBCAT_VIDEO_SUBPIC ) add_file( "freetype-font", DEFAULT_FONT, NULL, FONT_TEXT, FONT_LONGTEXT, - VLC_FALSE ); + false ) add_integer( "freetype-fontsize", 0, NULL, FONTSIZE_TEXT, - FONTSIZE_LONGTEXT, VLC_TRUE ); + FONTSIZE_LONGTEXT, true ) /* opacity valid on 0..255, with default 255 = fully opaque */ add_integer_with_range( "freetype-opacity", 255, 0, 255, NULL, - OPACITY_TEXT, OPACITY_LONGTEXT, VLC_TRUE ); + OPACITY_TEXT, OPACITY_LONGTEXT, true ) /* hook to the color values list, with default 0x00ffffff = white */ add_integer( "freetype-color", 0x00FFFFFF, NULL, COLOR_TEXT, - COLOR_LONGTEXT, VLC_FALSE ); - change_integer_list( pi_color_values, ppsz_color_descriptions, 0 ); + COLOR_LONGTEXT, false ) + change_integer_list( pi_color_values, ppsz_color_descriptions, NULL ) add_integer( "freetype-rel-fontsize", 16, NULL, FONTSIZER_TEXT, - FONTSIZER_LONGTEXT, VLC_FALSE ); - change_integer_list( pi_sizes, ppsz_sizes_text, 0 ); + FONTSIZER_LONGTEXT, false ) + change_integer_list( pi_sizes, ppsz_sizes_text, NULL ) add_integer( "freetype-effect", 2, NULL, EFFECT_TEXT, - EFFECT_LONGTEXT, VLC_FALSE ); - change_integer_list( pi_effects, ppsz_effects_text, 0 ); + EFFECT_LONGTEXT, false ) + change_integer_list( pi_effects, ppsz_effects_text, NULL ) add_bool( "freetype-yuvp", 0, NULL, YUVP_TEXT, - YUVP_LONGTEXT, VLC_TRUE ); - set_capability( "text renderer", 100 ); - add_shortcut( "text" ); - set_callbacks( Create, Destroy ); -vlc_module_end(); + YUVP_LONGTEXT, true ) + set_capability( "text renderer", 100 ) + add_shortcut( "text" ) + set_callbacks( Create, Destroy ) +vlc_module_end () + + + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ + +/* The RenderText call maps to pf_render_string, defined in vlc_filter.h */ +static int RenderText( filter_t *, subpicture_region_t *, + subpicture_region_t * ); +#ifdef HAVE_FONTCONFIG +static int RenderHtml( filter_t *, subpicture_region_t *, + subpicture_region_t * ); +static char *FontConfig_Select( FcConfig *, const char *, + bool, bool, int * ); +#endif + + +static int LoadFontsFromAttachments( filter_t *p_filter ); +static int GetFontSize( filter_t *p_filter ); +static int SetFontSize( filter_t *, int ); +static void YUVFromRGB( uint32_t i_argb, + uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ); + +typedef struct line_desc_t line_desc_t; struct line_desc_t { /** NULL-terminated list of glyphs making the string */ @@ -201,7 +201,7 @@ struct line_desc_t uint32_t *p_fg_rgb; uint32_t *p_bg_rgb; uint8_t *p_fg_bg_ratio; /* 0x00=100% FG --> 0x7F=100% BG */ - vlc_bool_t b_new_color_mode; + bool b_new_color_mode; /** underline information -- only supplied if text should be underlined */ uint16_t *pi_underline_offset; uint16_t *pi_underline_thickness; @@ -213,34 +213,31 @@ struct line_desc_t line_desc_t *p_next; }; - -typedef struct font_stack_t font_stack_t; -struct font_stack_t -{ - char *psz_name; - int i_size; - uint32_t i_color; /* ARGB */ - uint32_t i_karaoke_bg_color; /* ARGB */ - - font_stack_t *p_next; -}; +static line_desc_t *NewLine( int ); typedef struct { int i_font_size; uint32_t i_font_color; /* ARGB */ uint32_t i_karaoke_bg_color; /* ARGB */ - vlc_bool_t b_italic; - vlc_bool_t b_bold; - vlc_bool_t b_underline; + bool b_italic; + bool b_bold; + bool b_underline; char *psz_fontname; } ft_style_t; static int Render( filter_t *, subpicture_region_t *, line_desc_t *, int, int); static void FreeLines( line_desc_t * ); static void FreeLine( line_desc_t * ); + #ifdef HAVE_FONTCONFIG -static void FontBuilder( vlc_object_t *p_this); +static vlc_object_t *FontBuilderAttach( filter_t *p_filter ); +static void FontBuilderDetach( filter_t *p_filter, vlc_object_t *p_fontbuilder ); +static void* FontBuilderThread( vlc_object_t *p_this); +static void FontBuilderDestructor( vlc_object_t *p_this ); +static void FontBuilderGetFcConfig( filter_t *p_filter, vlc_object_t *p_fontbuilder ); +static int FontBuilderDone( vlc_object_t*, const char *, vlc_value_t, vlc_value_t, + void* ); #endif /***************************************************************************** @@ -253,7 +250,7 @@ struct filter_sys_t { FT_Library p_library; /* handle to library */ FT_Face p_face; /* handle to face object */ - vlc_bool_t i_use_kerning; + bool i_use_kerning; uint8_t i_font_opacity; int i_font_color; int i_font_size; @@ -262,15 +259,22 @@ struct filter_sys_t int i_default_font_size; int i_display_height; #ifdef HAVE_FONTCONFIG + bool b_fontconfig_ok; FcConfig *p_fontconfig; - vlc_bool_t b_fontconfig_ok; - vlc_mutex_t fontconfig_lock; #endif input_attachment_t **pp_font_attachments; int i_font_attachments; + + vlc_object_t *p_fontbuilder; }; +#define UCHAR uint32_t +#define TR_DEFAULT_FONT FC_DEFAULT_FONT +#define TR_FONT_STYLE_PTR ft_style_t * + +#include "text_renderer.h" + /***************************************************************************** * Create: allocates osd-text video thread output method ***************************************************************************** @@ -278,19 +282,16 @@ struct filter_sys_t *****************************************************************************/ static int Create( vlc_object_t *p_this ) { - filter_t *p_filter = (filter_t *)p_this; - filter_sys_t *p_sys; - char *psz_fontfile = NULL; - int i_error; - vlc_value_t val; + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys; + char *psz_fontfile = NULL; + int i_error; + vlc_value_t val; /* Allocate structure */ p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) ); if( !p_sys ) - { - msg_Err( p_filter, "out of memory" ); return VLC_ENOMEM; - } p_sys->p_face = 0; p_sys->p_library = 0; p_sys->i_font_size = 0; @@ -319,13 +320,10 @@ static int Create( vlc_object_t *p_this ) psz_fontfile = val.psz_string; if( !psz_fontfile || !*psz_fontfile ) { - if( psz_fontfile ) free( psz_fontfile ); + free( psz_fontfile ); psz_fontfile = (char *)malloc( PATH_MAX + 1 ); if( !psz_fontfile ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } #ifdef WIN32 GetWindowsDirectory( psz_fontfile, PATH_MAX + 1 ); strcat( psz_fontfile, "\\fonts\\arial.ttf" ); @@ -337,38 +335,6 @@ static int Create( vlc_object_t *p_this ) #endif } -#ifdef HAVE_FONTCONFIG - vlc_mutex_init( p_filter, &p_sys->fontconfig_lock ); - p_sys->b_fontconfig_ok = VLC_FALSE; - - p_sys->p_fontconfig = FcInitLoadConfig(); - - if( p_sys->p_fontconfig ) - { - /* Normally this doesn't take very long, but an initial build of - * the fontconfig database or the addition of a lot of new fonts - * can cause it to take several minutes for a large number of fonts. - * Even a small number can take several seconds - much longer than - * we can afford to block, so we build the list in the background - * and if it succeeds we allow fontconfig to be used. - */ - if( vlc_thread_create( p_filter, "fontlist builder", FontBuilder, - VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) ) - { - /* Don't destroy the fontconfig object - we won't be able to do - * italics or bold or change the font face, but we will still - * be able to do underline and change the font size. - */ - msg_Warn( p_filter, "fontconfig database builder thread can't " - "be launched. Font styling support will be limited." ); - }; - } - else - { - msg_Warn( p_filter, "Couldn't initialise Fontconfig. " - "Font styling won't be available." ); - } -#endif i_error = FT_Init_FreeType( &p_sys->p_library ); if( i_error ) { @@ -395,24 +361,29 @@ static int Create( vlc_object_t *p_this ) goto error; } +#ifdef HAVE_FONTCONFIG + p_sys->b_fontconfig_ok = false; + p_sys->p_fontconfig = NULL; + p_sys->p_fontbuilder = FontBuilderAttach( p_filter ); +#endif + p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face ); var_Get( p_filter, "freetype-fontsize", &val ); p_sys->i_default_font_size = val.i_int; if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error; - if( psz_fontfile ) free( psz_fontfile ); + free( psz_fontfile ); p_sys->pp_font_attachments = NULL; p_sys->i_font_attachments = 0; p_filter->pf_render_text = RenderText; #ifdef HAVE_FONTCONFIG - if( p_sys->p_fontconfig ) - p_filter->pf_render_html = RenderHtml; - else + p_filter->pf_render_html = RenderHtml; +#else + p_filter->pf_render_html = NULL; #endif - p_filter->pf_render_html = NULL; LoadFontsFromAttachments( p_filter ); @@ -421,7 +392,7 @@ static int Create( vlc_object_t *p_this ) error: if( p_sys->p_face ) FT_Done_Face( p_sys->p_face ); if( p_sys->p_library ) FT_Done_FreeType( p_sys->p_library ); - if( psz_fontfile ) free( psz_fontfile ); + free( psz_fontfile ); free( p_sys ); return VLC_EGENERIC; } @@ -441,64 +412,170 @@ static void Destroy( vlc_object_t *p_this ) int k; for( k = 0; k < p_sys->i_font_attachments; k++ ) - { vlc_input_attachment_Delete( p_sys->pp_font_attachments[k] ); - } free( p_sys->pp_font_attachments ); } #ifdef HAVE_FONTCONFIG - vlc_mutex_destroy( &p_sys->fontconfig_lock ); + FontBuilderDetach( p_filter, p_sys->p_fontbuilder ); +#endif - if( p_sys->p_fontconfig ) - { - FcConfigDestroy( p_sys->p_fontconfig ); - p_sys->p_fontconfig = NULL; - } /* FcFini asserts calling the subfunction FcCacheFini() * even if no other library functions have been made since FcInit(), * so don't call it. */ -#endif + FT_Done_Face( p_sys->p_face ); FT_Done_FreeType( p_sys->p_library ); free( p_sys ); } #ifdef HAVE_FONTCONFIG +static vlc_mutex_t fb_lock = VLC_STATIC_MUTEX; -static void FontBuilder( vlc_object_t *p_this) +static vlc_object_t *FontBuilderAttach( filter_t *p_filter ) { - filter_t *p_filter = (filter_t*)p_this; - filter_sys_t *p_sys = p_filter->p_sys; - time_t t1, t2; + /* Check for an existing Fontbuilder thread */ + vlc_mutex_lock( &fb_lock ); + vlc_object_t *p_fontbuilder = + vlc_object_find_name( p_filter->p_libvlc, + "fontlist builder", FIND_CHILD ); + + if( !p_fontbuilder ) + { + /* Create the FontBuilderThread thread as a child of a top-level + * object, so that it can survive the destruction of the + * freetype object - the fontlist only needs to be built once, + * and calling the fontbuild a second time while the first is + * still in progress can cause thread instabilities. + * + * XXX The fontbuilder will be destroy as soon as it is unused. + */ + + p_fontbuilder = vlc_object_create( p_filter->p_libvlc, + sizeof(vlc_object_t) ); + if( p_fontbuilder ) + { + p_fontbuilder->psz_object_name = strdup( "fontlist builder" ); + p_fontbuilder->p_private = NULL; + vlc_object_set_destructor( p_fontbuilder, FontBuilderDestructor ); + + vlc_object_attach( p_fontbuilder, p_filter->p_libvlc ); - /* Find the session to announce */ - vlc_mutex_lock( &p_sys->fontconfig_lock ); + var_Create( p_fontbuilder, "build-done", VLC_VAR_BOOL ); + var_SetBool( p_fontbuilder, "build-done", false ); + var_Create( p_fontbuilder, "build-joined", VLC_VAR_BOOL ); + var_SetBool( p_fontbuilder, "build-joined", false ); - msg_Dbg( p_filter, "Building font database..." ); - time(&t1); - if(! FcConfigBuildFonts( p_sys->p_fontconfig )) + if( vlc_thread_create( p_fontbuilder, + "fontlist builder", + FontBuilderThread, + VLC_THREAD_PRIORITY_LOW ) ) + { + msg_Warn( p_filter, "fontconfig database builder thread can't " + "be launched. Font styling support will be limited." ); + } + } + } + else + vlc_object_hold( p_fontbuilder ); + if( p_fontbuilder ) { - /* Don't destroy the fontconfig object - we won't be able to do - * italics or bold or change the font face, but we will still - * be able to do underline and change the font size. - */ - msg_Err( p_filter, "fontconfig database can't be built. " - "Font styling won't be available" ); + var_AddCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter ); + FontBuilderGetFcConfig( p_filter, p_fontbuilder ); + } + vlc_mutex_unlock( &fb_lock ); + return p_fontbuilder; +} +static void FontBuilderDetach( filter_t *p_filter, vlc_object_t *p_fontbuilder ) +{ + vlc_mutex_lock( &fb_lock ); + if( p_fontbuilder ) + { + var_DelCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter ); + + /* We wait for the thread on the first FontBuilderDetach */ + if( !var_GetBool( p_fontbuilder, "build-joined" ) ) + { + var_SetBool( p_fontbuilder, "build-joined", true ); + vlc_mutex_unlock( &fb_lock ); + /* We need to unlock otherwise we may not join (the thread waiting + * for the lock). It is safe to unlock as no one else will try a + * join and we have a reference on the object) */ + vlc_thread_join( p_fontbuilder ); + vlc_mutex_lock( &fb_lock ); + } + vlc_object_release( p_fontbuilder ); } - time(&t2); + vlc_mutex_unlock( &fb_lock ); +} +static void* FontBuilderThread( vlc_object_t *p_this ) +{ + FcConfig *p_fontconfig = FcInitLoadConfig(); - msg_Dbg( p_filter, "Finished building font database." ); - if( t1 > 0 && t2 > 0 ) - msg_Dbg( p_filter, "Took %ld seconds", t2 - t1 ); + if( p_fontconfig ) + { + mtime_t t1, t2; + int canc = vlc_savecancel (); - FcConfigSetCurrent( p_sys->p_fontconfig ); - p_sys->b_fontconfig_ok = VLC_TRUE; + //msg_Dbg( p_this, "Building font database..." ); + msg_Dbg( p_this, "Building font database..." ); + t1 = mdate(); + if(! FcConfigBuildFonts( p_fontconfig )) + { + /* Don't destroy the fontconfig object - we won't be able to do + * italics or bold or change the font face, but we will still + * be able to do underline and change the font size. + */ + msg_Err( p_this, "fontconfig database can't be built. " + "Font styling won't be available" ); + } + t2 = mdate(); + + msg_Dbg( p_this, "Finished building font database." ); + msg_Dbg( p_this, "Took %ld seconds", (long)((t2 - t1)/1000000) ); + + vlc_mutex_lock( &fb_lock ); + p_this->p_private = p_fontconfig; + vlc_mutex_unlock( &fb_lock ); + + var_SetBool( p_this, "build-done", true ); + vlc_restorecancel (canc); + } + return NULL; +} +static void FontBuilderGetFcConfig( filter_t *p_filter, vlc_object_t *p_fontbuilder ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + + p_sys->p_fontconfig = p_fontbuilder->p_private; + p_sys->b_fontconfig_ok = p_fontbuilder->p_private != NULL; +} +static void FontBuilderDestructor( vlc_object_t *p_this ) +{ + FcConfig *p_fontconfig = p_this->p_private; - vlc_mutex_unlock( &p_sys->fontconfig_lock ); + if( p_fontconfig ) + FcConfigDestroy( p_fontconfig ); } +static int FontBuilderDone( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *param ) +{ + filter_t *p_filter = param; + + if( newval.b_bool ) + { + vlc_mutex_lock( &fb_lock ); + + FontBuilderGetFcConfig( p_filter, p_this ); + vlc_mutex_unlock( &fb_lock ); + } + + VLC_UNUSED(psz_var); + VLC_UNUSED(oldval); + return VLC_SUCCESS; +} #endif /***************************************************************************** @@ -567,7 +644,7 @@ static int LoadFontsFromAttachments( filter_t *p_filter ) static int Render( filter_t *p_filter, subpicture_region_t *p_region, line_desc_t *p_line, int i_width, int i_height ) { - static uint8_t pi_gamma[16] = + static const uint8_t pi_gamma[16] = {0x00, 0x52, 0x84, 0x96, 0xb8, 0xca, 0xdc, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -576,7 +653,6 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, int i, x, y, i_pitch; uint8_t i_y; /* YUV values, derived from incoming RGB */ int8_t i_u, i_v; - subpicture_region_t *p_region_tmp; /* Create a new subpicture region */ memset( &fmt, 0, sizeof(video_format_t) ); @@ -589,16 +665,12 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, if( p_region->fmt.i_visible_height > 0 ) fmt.i_visible_height = p_region->fmt.i_visible_height; fmt.i_x_offset = fmt.i_y_offset = 0; - p_region_tmp = spu_CreateRegion( p_filter, &fmt ); - if( !p_region_tmp ) - { - msg_Err( p_filter, "cannot allocate SPU region" ); - return VLC_EGENERIC; - } - p_region->fmt = p_region_tmp->fmt; - p_region->picture = p_region_tmp->picture; - free( p_region_tmp ); + assert( !p_region->p_picture ); + p_region->p_picture = picture_New( fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_aspect ); + if( !p_region->p_picture ) + return VLC_EGENERIC; + p_region->fmt = fmt; /* Calculate text color components */ i_y = (uint8_t)(( 66 * p_line->i_red + 129 * p_line->i_green + @@ -629,8 +701,8 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, (int)fmt.p_palette->palette[i][3] * (255 - p_line->i_alpha) / 255; } - p_dst = p_region->picture.Y_PIXELS; - i_pitch = p_region->picture.Y_PITCH; + p_dst = p_region->p_picture->Y_PIXELS; + i_pitch = p_region->p_picture->Y_PITCH; /* Initialize the region pixels */ memset( p_dst, 0, i_pitch * p_region->fmt.i_height ); @@ -682,21 +754,21 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, /* Outlining (find something better than nearest neighbour filtering ?) */ if( 1 ) { - uint8_t *p_dst = p_region->picture.Y_PIXELS; + uint8_t *p_dst = p_region->p_picture->Y_PIXELS; uint8_t *p_top = p_dst; /* Use 1st line as a cache */ uint8_t left, current; for( y = 1; y < (int)fmt.i_height - 1; y++ ) { if( y > 1 ) memcpy( p_top, p_dst, fmt.i_width ); - p_dst += p_region->picture.Y_PITCH; + p_dst += p_region->p_picture->Y_PITCH; left = 0; for( x = 1; x < (int)fmt.i_width - 1; x++ ) { current = p_dst[x]; p_dst[x] = ( 8 * (int)p_dst[x] + left + p_dst[x+1] + p_top[x -1]+ p_top[x] + p_top[x+1] + - p_dst[x -1 + p_region->picture.Y_PITCH ] + p_dst[x + p_region->picture.Y_PITCH] + p_dst[x + 1 + p_region->picture.Y_PITCH]) / 16; + p_dst[x -1 + p_region->p_picture->Y_PITCH ] + p_dst[x + p_region->p_picture->Y_PITCH] + p_dst[x + 1 + p_region->p_picture->Y_PITCH]) / 16; left = current; } } @@ -706,22 +778,22 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region, return VLC_SUCCESS; } -static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_bool_t b_ul_next_char, +static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, bool b_ul_next_char, FT_BitmapGlyph p_this_glyph, FT_Vector *p_this_glyph_pos, FT_BitmapGlyph p_next_glyph, FT_Vector *p_next_glyph_pos, int i_glyph_tmax, int i_align_offset, - uint8_t i_y, uint8_t i_u, uint8_t i_v, uint8_t i_alpha, + uint8_t i_y, uint8_t i_u, uint8_t i_v, subpicture_region_t *p_region) { int y, x, z; int i_pitch; uint8_t *p_dst_y,*p_dst_u,*p_dst_v,*p_dst_a; - p_dst_y = p_region->picture.Y_PIXELS; - p_dst_u = p_region->picture.U_PIXELS; - p_dst_v = p_region->picture.V_PIXELS; - p_dst_a = p_region->picture.A_PIXELS; - i_pitch = p_region->picture.A_PITCH; + p_dst_y = p_region->p_picture->Y_PIXELS; + p_dst_u = p_region->p_picture->U_PIXELS; + p_dst_v = p_region->p_picture->V_PIXELS; + p_dst_a = p_region->p_picture->A_PIXELS; + i_pitch = p_region->p_picture->A_PITCH; int i_offset = ( p_this_glyph_pos->y + i_glyph_tmax + i_line_offset + 3 ) * i_pitch + p_this_glyph_pos->x + p_this_glyph->left + 3 + i_align_offset; @@ -737,7 +809,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo } for( x = 0; x < i_extra; x++ ) { - vlc_bool_t b_ok = VLC_TRUE; + bool b_ok = true; /* break the underline around the tails of any glyphs which cross it */ for( z = x - i_line_thickness; @@ -751,7 +823,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo if( ( p_next_glyph->bitmap.rows > i_row ) && p_next_glyph->bitmap.buffer[p_next_glyph->bitmap.width * i_row + z-i_extra] ) { - b_ok = VLC_FALSE; + b_ok = false; } } else if ((z > 0 ) && (z < p_this_glyph->bitmap.width)) @@ -761,7 +833,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo if( ( p_this_glyph->bitmap.rows > i_row ) && p_this_glyph->bitmap.buffer[p_this_glyph->bitmap.width * i_row + z] ) { - b_ok = VLC_FALSE; + b_ok = false; } } } @@ -780,8 +852,8 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo static void DrawBlack( line_desc_t *p_line, int i_width, subpicture_region_t *p_region, int xoffset, int yoffset ) { - uint8_t *p_dst = p_region->picture.A_PIXELS; - int i_pitch = p_region->picture.A_PITCH; + uint8_t *p_dst = p_region->p_picture->A_PIXELS; + int i_pitch = p_region->p_picture->A_PITCH; int x,y; for( ; p_line != NULL; p_line = p_line->p_next ) @@ -844,7 +916,6 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, video_format_t fmt; int i, x, y, i_pitch, i_alpha; uint8_t i_y, i_u, i_v; /* YUV values, derived from incoming RGB */ - subpicture_region_t *p_region_tmp; if( i_width == 0 || i_height == 0 ) return VLC_SUCCESS; @@ -860,16 +931,11 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, if( p_region->fmt.i_visible_height > 0 ) fmt.i_visible_height = p_region->fmt.i_visible_height; fmt.i_x_offset = fmt.i_y_offset = 0; - p_region_tmp = spu_CreateRegion( p_filter, &fmt ); - if( !p_region_tmp ) - { - msg_Err( p_filter, "cannot allocate SPU region" ); - return VLC_EGENERIC; - } - p_region->fmt = p_region_tmp->fmt; - p_region->picture = p_region_tmp->picture; - free( p_region_tmp ); + p_region->p_picture = picture_New( fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_aspect ); + if( !p_region->p_picture ) + return VLC_EGENERIC; + p_region->fmt = fmt; /* Calculate text color components */ YUVFromRGB( (p_line->i_red << 16) | @@ -878,11 +944,11 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, &i_y, &i_u, &i_v); i_alpha = p_line->i_alpha; - p_dst_y = p_region->picture.Y_PIXELS; - p_dst_u = p_region->picture.U_PIXELS; - p_dst_v = p_region->picture.V_PIXELS; - p_dst_a = p_region->picture.A_PIXELS; - i_pitch = p_region->picture.A_PITCH; + p_dst_y = p_region->p_picture->Y_PIXELS; + p_dst_u = p_region->p_picture->U_PIXELS; + p_dst_v = p_region->p_picture->V_PIXELS; + p_dst_a = p_region->p_picture->A_PIXELS; + i_pitch = p_region->p_picture->A_PITCH; /* Initialize the region pixels */ if( p_filter->p_sys->i_effect != EFFECT_BACKGROUND ) @@ -1012,7 +1078,7 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region, p_line->pp_glyphs[i], &(p_line->p_glyph_pos[i]), p_line->pp_glyphs[i+1], &(p_line->p_glyph_pos[i+1]), i_glyph_tmax, i_align_offset, - i_y, i_u, i_v, i_alpha, + i_y, i_u, i_v, p_region); } } @@ -1085,10 +1151,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, psz_unicode = psz_unicode_orig = malloc( ( strlen(psz_string) + 1 ) * sizeof(uint32_t) ); if( psz_unicode == NULL ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } #if defined(WORDS_BIGENDIAN) iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" ); #else @@ -1108,15 +1171,16 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, i_out_bytes = i_in_bytes * sizeof( uint32_t ); i_out_bytes_left = i_out_bytes; p_out_buffer = (char *)psz_unicode; - i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, &i_in_bytes, + i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, + &i_in_bytes, &p_out_buffer, &i_out_bytes_left ); vlc_iconv_close( iconv_handle ); if( i_in_bytes ) { - msg_Warn( p_filter, "failed to convert string to unicode (%s), " - "bytes left %d", strerror(errno), (int)i_in_bytes ); + msg_Warn( p_filter, "failed to convert string to unicode (%m), " + "bytes left %u", (unsigned)i_in_bytes ); goto error; } *(uint32_t*)p_out_buffer = 0; @@ -1126,19 +1190,17 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, #if defined(HAVE_FRIBIDI) { uint32_t *p_fribidi_string; - int start_pos, pos = 0; + int32_t start_pos, pos = 0; p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) ); if( !p_fribidi_string ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } /* Do bidi conversion line-by-line */ - while(pos < i_string_length) + while( pos < i_string_length ) { - while(pos < i_string_length) { + while( pos < i_string_length ) + { i_char = psz_unicode[pos]; if (i_char != '\r' && i_char != '\n') break; @@ -1146,7 +1208,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, ++pos; } start_pos = pos; - while(pos < i_string_length) { + while( pos < i_string_length ) + { i_char = psz_unicode[pos]; if (i_char == '\r' || i_char == '\n') break; @@ -1155,8 +1218,11 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, if (pos > start_pos) { FriBidiCharType base_dir = FRIBIDI_TYPE_LTR; - fribidi_log2vis((FriBidiChar*)psz_unicode + start_pos, pos - start_pos, - &base_dir, (FriBidiChar*)p_fribidi_string + start_pos, 0, 0, 0); + fribidi_log2vis((FriBidiChar*)psz_unicode + start_pos, + pos - start_pos, + &base_dir, + (FriBidiChar*)p_fribidi_string + start_pos, + 0, 0, 0); } } @@ -1169,10 +1235,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, /* Calculate relative glyph positions and a bounding box for the * entire string */ if( !(p_line = NewLine( strlen( psz_string ))) ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } p_lines = p_line; i_pen_x = i_pen_y = 0; i_previous = i = 0; @@ -1193,10 +1256,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, { psz_line_start = psz_unicode; if( !(p_next = NewLine( strlen( psz_string ))) ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } p_line->p_next = p_next; p_line->i_width = line.xMax; p_line->i_height = face->size->metrics.height >> 6; @@ -1259,17 +1319,29 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) { + FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] ); p_line->pp_glyphs[ i ] = NULL; FreeLine( p_line ); p_line = NewLine( strlen( psz_string )); if( p_prev ) p_prev->p_next = p_line; else p_lines = p_line; + uint32_t *psz_unicode_saved = psz_unicode; while( psz_unicode > psz_line_start && *psz_unicode != ' ' ) { psz_unicode--; } if( psz_unicode == psz_line_start ) + { /* try harder to break that line */ + psz_unicode = psz_unicode_saved; + while( psz_unicode > psz_line_start && + *psz_unicode != '_' && *psz_unicode != '/' && + *psz_unicode != '\\' && *psz_unicode != '.' ) + { + psz_unicode--; + } + } + if( psz_unicode == psz_line_start ) { msg_Warn( p_filter, "unbreakable string" ); goto error; @@ -1313,20 +1385,20 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, else RenderYUVA( p_filter, p_region_out, p_lines, result.x, result.y ); - if( psz_unicode_orig ) free( psz_unicode_orig ); + free( psz_unicode_orig ); FreeLines( p_lines ); return VLC_SUCCESS; error: - if( psz_unicode_orig ) free( psz_unicode_orig ); + free( psz_unicode_orig ); FreeLines( p_lines ); return VLC_EGENERIC; } #ifdef HAVE_FONTCONFIG static ft_style_t *CreateStyle( char *psz_fontname, int i_font_size, - uint32_t i_font_color, uint32_t i_karaoke_bg_color, vlc_bool_t b_bold, - vlc_bool_t b_italic, vlc_bool_t b_uline ) + uint32_t i_font_color, uint32_t i_karaoke_bg_color, bool b_bold, + bool b_italic, bool b_uline ) { ft_style_t *p_style = malloc( sizeof( ft_style_t )); @@ -1348,18 +1420,17 @@ static void DeleteStyle( ft_style_t *p_style ) { if( p_style ) { - if( p_style->psz_fontname ) - free( p_style->psz_fontname ); + free( p_style->psz_fontname ); free( p_style ); } } -static vlc_bool_t StyleEquals( ft_style_t *s1, ft_style_t *s2 ) +static bool StyleEquals( ft_style_t *s1, ft_style_t *s2 ) { if( !s1 || !s2 ) - return VLC_FALSE; + return false; if( s1 == s2 ) - return VLC_TRUE; + return true; if(( s1->i_font_size == s2->i_font_size ) && ( s1->i_font_color == s2->i_font_color ) && @@ -1368,97 +1439,9 @@ static vlc_bool_t StyleEquals( ft_style_t *s1, ft_style_t *s2 ) ( s1->b_underline == s2->b_underline ) && ( !strcmp( s1->psz_fontname, s2->psz_fontname ))) { - return VLC_TRUE; - } - return VLC_FALSE; -} - -static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size, - uint32_t i_color, uint32_t i_karaoke_bg_color ) -{ - font_stack_t *p_new; - - if( !p_font ) - return VLC_EGENERIC; - - p_new = malloc( sizeof( font_stack_t ) ); - if( ! p_new ) - return VLC_ENOMEM; - - p_new->p_next = NULL; - - if( psz_name ) - p_new->psz_name = strdup( psz_name ); - else - p_new->psz_name = NULL; - - p_new->i_size = i_size; - p_new->i_color = i_color; - p_new->i_karaoke_bg_color = i_karaoke_bg_color; - - if( !*p_font ) - { - *p_font = p_new; + return true; } - else - { - font_stack_t *p_last; - - for( p_last = *p_font; - p_last->p_next; - p_last = p_last->p_next ) - ; - - p_last->p_next = p_new; - } - return VLC_SUCCESS; -} - -static int PopFont( font_stack_t **p_font ) -{ - font_stack_t *p_last, *p_next_to_last; - - if( !p_font || !*p_font ) - return VLC_EGENERIC; - - p_next_to_last = NULL; - for( p_last = *p_font; - p_last->p_next; - p_last = p_last->p_next ) - { - p_next_to_last = p_last; - } - - if( p_next_to_last ) - p_next_to_last->p_next = NULL; - else - *p_font = NULL; - - free( p_last->psz_name ); - free( p_last ); - - return VLC_SUCCESS; -} - -static int PeekFont( font_stack_t **p_font, char **psz_name, int *i_size, - uint32_t *i_color, uint32_t *i_karaoke_bg_color ) -{ - font_stack_t *p_last; - - if( !p_font || !*p_font ) - return VLC_EGENERIC; - - for( p_last=*p_font; - p_last->p_next; - p_last=p_last->p_next ) - ; - - *psz_name = p_last->psz_name; - *i_size = p_last->i_size; - *i_color = p_last->i_color; - *i_karaoke_bg_color = p_last->i_karaoke_bg_color; - - return VLC_SUCCESS; + return false; } static void IconvText( filter_t *p_filter, const char *psz_string, @@ -1499,8 +1482,8 @@ static void IconvText( filter_t *p_filter, const char *psz_string, if( i_in_bytes ) { - msg_Warn( p_filter, "failed to convert string to unicode (%s), " - "bytes left %d", strerror(errno), (int)i_in_bytes ); + msg_Warn( p_filter, "failed to convert string to unicode (%m), " + "bytes left %u", (unsigned)i_in_bytes ); } else { @@ -1517,8 +1500,8 @@ static void IconvText( filter_t *p_filter, const char *psz_string, } static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys, - font_stack_t **p_fonts, vlc_bool_t b_bold, vlc_bool_t b_italic, - vlc_bool_t b_uline ) + font_stack_t **p_fonts, bool b_bold, bool b_italic, + bool b_uline ) { ft_style_t *p_style = NULL; @@ -1537,7 +1520,7 @@ static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys, } static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, - vlc_bool_t b_uline, int i_karaoke_bgcolor, + bool b_uline, int i_karaoke_bgcolor, line_desc_t *p_line, uint32_t *psz_unicode, int *pi_pen_x, int i_pen_y, int *pi_start, FT_Vector *p_result ) @@ -1545,7 +1528,7 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, FT_BBox line; int i_yMin, i_yMax; int i; - vlc_bool_t b_first_on_line = VLC_TRUE; + bool b_first_on_line = true; int i_previous = 0; int i_pen_x_start = *pi_pen_x; @@ -1571,7 +1554,7 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, i_yMax = line.yMax; if( line.xMax > 0 ) - b_first_on_line = VLC_FALSE; + b_first_on_line = false; while( *psz_unicode && ( *psz_unicode != '\n' ) ) { @@ -1635,10 +1618,9 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) { - while( --i > *pi_start ) - { + for( ; i >= *pi_start; i-- ) FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] ); - } + i = *pi_start; while( psz_unicode > psz_unicode_start && *psz_unicode != ' ' ) { @@ -1662,8 +1644,6 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, p_result->x = __MAX( p_result->x, line.xMax ); p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, i_yMax - i_yMin ) ); - - *pi_start = i; return VLC_SUCCESS; } else @@ -1704,9 +1684,8 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, { *psz_unicode_start = '\0'; } - else + else if( psz_unicode > psz_unicode_start ) { - psz_unicode++; for( i=0; psz_unicode[ i ]; i++ ) psz_unicode_start[ i ] = psz_unicode[ i ]; psz_unicode_start[ i ] = '\0'; @@ -1715,86 +1694,6 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, return VLC_SUCCESS; } -static int HandleFontAttributes( xml_reader_t *p_xml_reader, - font_stack_t **p_fonts, int i_scale ) -{ - int rv; - char *psz_fontname = NULL; - uint32_t i_font_color = 0xffffff; - int i_font_alpha = 0; - uint32_t i_karaoke_bg_color = 0x00ffffff; - int i_font_size = 24; - - /* Default all attributes to the top font in the stack -- in case not - * all attributes are specified in the sub-font - */ - if( VLC_SUCCESS == PeekFont( p_fonts, - &psz_fontname, - &i_font_size, - &i_font_color, - &i_karaoke_bg_color )) - { - psz_fontname = strdup( psz_fontname ); - i_font_size = i_font_size * 1000 / i_scale; - } - i_font_alpha = (i_font_color >> 24) & 0xff; - i_font_color &= 0x00ffffff; - - while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) - { - char *psz_name = xml_ReaderName( p_xml_reader ); - char *psz_value = xml_ReaderValue( p_xml_reader ); - - if( psz_name && psz_value ) - { - if( !strcasecmp( "face", psz_name ) ) - { - if( psz_fontname ) free( psz_fontname ); - psz_fontname = strdup( psz_value ); - } - 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 ); - } - else if( !strcasecmp( "color", psz_name ) && - ( psz_value[0] == '#' ) ) - { - i_font_color = strtol( psz_value + 1, NULL, 16 ); - i_font_color &= 0x00ffffff; - } - else if( !strcasecmp( "alpha", psz_name ) && - ( psz_value[0] == '#' ) ) - { - i_font_alpha = strtol( psz_value + 1, NULL, 16 ); - i_font_alpha &= 0xff; - } - free( psz_name ); - free( psz_value ); - } - } - rv = PushFont( p_fonts, - psz_fontname, - i_font_size * i_scale / 1000, - (i_font_color & 0xffffff) | ((i_font_alpha & 0xff) << 24), - i_karaoke_bg_color ); - - free( psz_fontname ); - - return rv; -} - static void SetupLine( filter_t *p_filter, const char *psz_text_in, uint32_t **psz_text_out, uint32_t *pi_runs, uint32_t **ppi_run_lengths, ft_style_t ***ppp_styles, @@ -1851,254 +1750,6 @@ static void SetupLine( filter_t *p_filter, const char *psz_text_in, if( p_style ) DeleteStyle( p_style ); } -static void SetKaraokeLen( uint32_t i_runs, uint32_t *pi_run_lengths, - uint32_t i_k_runs, uint32_t *pi_k_run_lengths ) -{ - /* Karaoke tags _PRECEDE_ the text they specify a duration - * for, therefore we are working out the length for the - * previous tag, and first time through we have nothing - */ - if( pi_k_run_lengths ) - { - int i_chars = 0; - uint32_t i; - - /* Work out how many characters are presently in the string - */ - for( i = 0; i < i_runs; i++ ) - i_chars += pi_run_lengths[ i ]; - - /* Subtract away those we've already allocated to other - * karaoke tags - */ - for( i = 0; i < i_k_runs; i++ ) - i_chars -= pi_k_run_lengths[ i ]; - - pi_k_run_lengths[ i_k_runs - 1 ] = i_chars; - } -} - -static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs, - uint32_t **ppi_k_run_lengths, - uint32_t **ppi_k_durations ) -{ - while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) - { - char *psz_name = xml_ReaderName( p_xml_reader ); - char *psz_value = xml_ReaderValue( p_xml_reader ); - - if( psz_name && psz_value && - !strcasecmp( "t", psz_name ) ) - { - if( ppi_k_durations && ppi_k_run_lengths ) - { - (*pi_k_runs)++; - - if( *ppi_k_durations ) - { - *ppi_k_durations = (uint32_t *) - realloc( *ppi_k_durations, - *pi_k_runs * sizeof( uint32_t ) ); - } - else if( *pi_k_runs == 1 ) - { - *ppi_k_durations = (uint32_t *) - malloc( *pi_k_runs * sizeof( uint32_t ) ); - } - - if( *ppi_k_run_lengths ) - { - *ppi_k_run_lengths = (uint32_t *) - realloc( *ppi_k_run_lengths, - *pi_k_runs * sizeof( uint32_t ) ); - } - else if( *pi_k_runs == 1 ) - { - *ppi_k_run_lengths = (uint32_t *) - malloc( *pi_k_runs * sizeof( uint32_t ) ); - } - if( *ppi_k_durations ) - (*ppi_k_durations)[ *pi_k_runs - 1 ] = atoi( psz_value ); - - if( *ppi_k_run_lengths ) - (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0; - } - } - if( psz_name ) free( psz_name ); - if( psz_value ) free( psz_value ); - } -} - -static int ProcessNodes( filter_t *p_filter, - xml_reader_t *p_xml_reader, - text_style_t *p_font_style, - uint32_t *psz_text, - int *pi_len, - - uint32_t *pi_runs, - uint32_t **ppi_run_lengths, - ft_style_t ***ppp_styles, - - vlc_bool_t b_karaoke, - uint32_t *pi_k_runs, - uint32_t **ppi_k_run_lengths, - uint32_t **ppi_k_durations ) -{ - int rv = VLC_SUCCESS; - filter_sys_t *p_sys = p_filter->p_sys; - uint32_t *psz_text_orig = psz_text; - font_stack_t *p_fonts = NULL; - vlc_value_t val; - int i_scale = 1000; - - char *psz_node = NULL; - - vlc_bool_t b_italic = VLC_FALSE; - vlc_bool_t b_bold = VLC_FALSE; - vlc_bool_t b_uline = VLC_FALSE; - - if( VLC_SUCCESS == var_Get( p_filter, "scale", &val )) - i_scale = val.i_int; - - if( p_font_style ) - { - rv = PushFont( &p_fonts, - p_font_style->psz_fontname, - p_font_style->i_font_size * i_scale / 1000, - (p_font_style->i_font_color & 0xffffff) | - ((p_font_style->i_font_alpha & 0xff) << 24), - (p_font_style->i_karaoke_background_color & 0xffffff) | - ((p_font_style->i_karaoke_background_alpha & 0xff) << 24)); - - if( p_font_style->i_style_flags & STYLE_BOLD ) - b_bold = VLC_TRUE; - if( p_font_style->i_style_flags & STYLE_ITALIC ) - b_italic = VLC_TRUE; - if( p_font_style->i_style_flags & STYLE_UNDERLINE ) - b_uline = VLC_TRUE; - } - else - { - rv = PushFont( &p_fonts, - FC_DEFAULT_FONT, - p_sys->i_font_size, - 0x00ffffff, - 0x00ffffff ); - } - if( rv != VLC_SUCCESS ) - return rv; - - while ( ( xml_ReaderRead( p_xml_reader ) == 1 ) ) - { - switch ( xml_ReaderNodeType( p_xml_reader ) ) - { - case XML_READER_NONE: - break; - case XML_READER_ENDELEM: - psz_node = xml_ReaderName( p_xml_reader ); - - if( psz_node ) - { - if( !strcasecmp( "font", psz_node ) ) - PopFont( &p_fonts ); - else if( !strcasecmp( "b", psz_node ) ) - b_bold = VLC_FALSE; - else if( !strcasecmp( "i", psz_node ) ) - b_italic = VLC_FALSE; - else if( !strcasecmp( "u", psz_node ) ) - b_uline = VLC_FALSE; - - free( psz_node ); - } - break; - case XML_READER_STARTELEM: - psz_node = xml_ReaderName( p_xml_reader ); - if( psz_node ) - { - if( !strcasecmp( "font", psz_node ) ) - rv = HandleFontAttributes( p_xml_reader, &p_fonts, i_scale ); - else if( !strcasecmp( "b", psz_node ) ) - b_bold = VLC_TRUE; - else if( !strcasecmp( "i", psz_node ) ) - b_italic = VLC_TRUE; - else if( !strcasecmp( "u", psz_node ) ) - b_uline = VLC_TRUE; - else if( !strcasecmp( "br", psz_node ) ) - { - SetupLine( p_filter, "\n", &psz_text, - pi_runs, ppi_run_lengths, ppp_styles, - GetStyleFromFontStack( p_sys, - &p_fonts, - b_bold, - b_italic, - b_uline ) ); - } - else if( !strcasecmp( "k", psz_node ) ) - { - /* Only valid in karaoke */ - if( b_karaoke ) - { - if( *pi_k_runs > 0 ) - { - SetKaraokeLen( *pi_runs, *ppi_run_lengths, - *pi_k_runs, *ppi_k_run_lengths ); - } - SetupKaraoke( p_xml_reader, pi_k_runs, - ppi_k_run_lengths, ppi_k_durations ); - } - } - - free( psz_node ); - } - break; - case XML_READER_TEXT: - psz_node = xml_ReaderValue( p_xml_reader ); - if( psz_node ) - { - /* 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 " ); - } - SetupLine( p_filter, psz_node, &psz_text, - pi_runs, ppi_run_lengths, ppp_styles, - GetStyleFromFontStack( p_sys, - &p_fonts, - b_bold, - b_italic, - b_uline ) ); - free( psz_node ); - } - break; - } - if( rv != VLC_SUCCESS ) - { - psz_text = psz_text_orig; - break; - } - } - if( b_karaoke ) - { - SetKaraokeLen( *pi_runs, *ppi_run_lengths, - *pi_k_runs, *ppi_k_run_lengths ); - } - - *pi_len = psz_text - psz_text_orig; - - while( VLC_SUCCESS == PopFont( &p_fonts ) ); - - return rv; -} - static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style_t *p_style ) { int k; @@ -2117,7 +1768,7 @@ static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style { if( p_face ) { - vlc_bool_t match = !strcasecmp( p_face->family_name, + bool match = !strcasecmp( p_face->family_name, p_style->psz_fontname ); if( p_face->style_flags & FT_STYLE_FLAG_BOLD ) @@ -2155,7 +1806,7 @@ static int ProcessLines( filter_t *p_filter, FT_Vector *p_result, - vlc_bool_t b_karaoke, + bool b_karaoke, uint32_t i_k_runs, uint32_t *pi_k_run_lengths, uint32_t *pi_k_durations ) @@ -2215,13 +1866,12 @@ static int ProcessLines( filter_t *p_filter, ! p_new_positions || ! p_levels ) { - msg_Err( p_filter, "out of memory" ); - if( p_levels ) free( p_levels ); - if( p_old_positions ) free( p_old_positions ); - if( p_new_positions ) free( p_new_positions ); - if( p_fribidi_string ) free( p_fribidi_string ); - if( pp_char_styles_new ) free( pp_char_styles_new ); - if( pi_karaoke_bar ) free( pi_karaoke_bar ); + free( p_levels ); + free( p_old_positions ); + free( p_new_positions ); + free( p_fribidi_string ); + free( pp_char_styles_new ); + free( pi_karaoke_bar ); free( pp_char_styles ); return VLC_ENOMEM; @@ -2329,8 +1979,8 @@ static int ProcessLines( filter_t *p_filter, i_start_pos += pi_k_run_lengths[ k ]; } } - if( p_levels ) free( p_levels ); - if( p_new_positions ) free( p_new_positions ); + free( p_levels ); + free( p_new_positions ); FT_Vector tmp_result; @@ -2360,19 +2010,33 @@ static int ProcessLines( filter_t *p_filter, /* Look for a match amongst our attachments first */ CheckForEmbeddedFont( p_sys, &p_face, p_style ); - if( ! p_face && p_sys->b_fontconfig_ok ) + if( ! p_face ) { - char *psz_fontfile; + char *psz_fontfile = NULL; - vlc_mutex_lock( &p_sys->fontconfig_lock ); - - psz_fontfile = FontConfig_Select( p_sys->p_fontconfig, - p_style->psz_fontname, - p_style->b_bold, - p_style->b_italic, - &i_idx ); + vlc_mutex_lock( &fb_lock ); + if( p_sys->b_fontconfig_ok ) + { + /* FIXME Is there really a race condition between FontConfig_Select with default fontconfig(NULL) + * and FcConfigBuildFonts ? If not it would be better to remove the check on b_fontconfig_ok */ + psz_fontfile = FontConfig_Select( p_sys->p_fontconfig, + p_style->psz_fontname, + p_style->b_bold, + p_style->b_italic, + &i_idx ); + } + vlc_mutex_unlock( &fb_lock ); - vlc_mutex_unlock( &p_sys->fontconfig_lock ); + if( psz_fontfile && ! *psz_fontfile ) + { + msg_Warn( p_filter, "Fontconfig was unable to find a font: \"%s\" %s" + " so using default font", p_style->psz_fontname, + ((p_style->b_bold && p_style->b_italic) ? "(Bold,Italic)" : + (p_style->b_bold ? "(Bold)" : + (p_style->b_italic ? "(Italic)" : ""))) ); + free( psz_fontfile ); + psz_fontfile = NULL; + } if( psz_fontfile ) { @@ -2384,8 +2048,7 @@ static int ProcessLines( filter_t *p_filter, #if defined(HAVE_FRIBIDI) free( psz_text ); #endif - if( pi_karaoke_bar ) - free( pi_karaoke_bar ); + free( pi_karaoke_bar ); return VLC_EGENERIC; } free( psz_fontfile ); @@ -2411,8 +2074,7 @@ static int ProcessLines( filter_t *p_filter, #if defined(HAVE_FRIBIDI) free( psz_text ); #endif - if( pi_karaoke_bar ) - free( pi_karaoke_bar ); + free( pi_karaoke_bar ); return VLC_EGENERIC; } p_sys->i_use_kerning = @@ -2423,15 +2085,13 @@ static int ProcessLines( filter_t *p_filter, malloc( (k - i_prev + 1) * sizeof( uint32_t )); if( !psz_unicode ) { - msg_Err( p_filter, "out of memory" ); if( p_face ) FT_Done_Face( p_face ); free( pp_char_styles ); free( psz_unicode ); #if defined(HAVE_FRIBIDI) free( psz_text ); #endif - if( pi_karaoke_bar ) - free( pi_karaoke_bar ); + free( pi_karaoke_bar ); return VLC_ENOMEM; } memcpy( psz_unicode, psz_text + i_prev, @@ -2443,22 +2103,20 @@ static int ProcessLines( filter_t *p_filter, { if( !(p_line = NewLine( i_len - i_prev)) ) { - msg_Err( p_filter, "out of memory" ); if( p_face ) FT_Done_Face( p_face ); free( pp_char_styles ); free( psz_unicode ); #if defined(HAVE_FRIBIDI) free( psz_text ); #endif - if( pi_karaoke_bar ) - free( pi_karaoke_bar ); + free( pi_karaoke_bar ); return VLC_ENOMEM; } /* New Color mode only works in YUVA rendering mode -- * (RGB mode has palette constraints on it). We therefore * need to populate the legacy colour fields also. */ - p_line->b_new_color_mode = VLC_TRUE; + p_line->b_new_color_mode = true; p_line->i_alpha = ( p_style->i_font_color & 0xff000000 ) >> 24; p_line->i_red = ( p_style->i_font_color & 0x00ff0000 ) >> 16; p_line->i_green = ( p_style->i_font_color & 0x0000ff00 ) >> 8; @@ -2485,8 +2143,7 @@ static int ProcessLines( filter_t *p_filter, #if defined(HAVE_FRIBIDI) free( psz_text ); #endif - if( pi_karaoke_bar ) - free( pi_karaoke_bar ); + free( pi_karaoke_bar ); return VLC_EGENERIC; } @@ -2497,6 +2154,16 @@ static int ProcessLines( filter_t *p_filter, p_prev = p_line; p_line = NULL; + + if( *psz_unicode == '\n') + { + uint32_t *c_ptr; + + for( c_ptr = psz_unicode; *c_ptr; c_ptr++ ) + { + *c_ptr = *(c_ptr+1); + } + } } } free( psz_unicode ); @@ -2574,13 +2241,13 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, p_sub = stream_MemoryNew( VLC_OBJECT(p_filter), (uint8_t *) p_region_in->psz_html, strlen( p_region_in->psz_html ), - VLC_TRUE ); + true ); if( p_sub ) { p_xml = xml_Create( p_filter ); if( p_xml ) { - vlc_bool_t b_karaoke = VLC_FALSE; + bool b_karaoke = false; p_xml_reader = xml_ReaderCreate( p_xml, p_sub ); if( p_xml_reader ) @@ -2595,16 +2262,17 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, /* We're going to have to render the text a number * of times to show the progress marker on the text. */ - var_SetBool( p_filter, "text-rerender", VLC_TRUE ); - b_karaoke = VLC_TRUE; + var_SetBool( p_filter, "text-rerender", true ); + b_karaoke = true; } else if( !strcasecmp( "text", psz_node ) ) { - b_karaoke = VLC_FALSE; + b_karaoke = false; } else { /* Only text and karaoke tags are supported */ + msg_Dbg( p_filter, "Unsupported top-level tag '%s' ignored.", psz_node ); xml_ReaderDelete( p_xml, p_xml_reader ); p_xml_reader = NULL; rv = VLC_EGENERIC; @@ -2617,7 +2285,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, if( p_xml_reader ) { uint32_t *psz_text; - int i_len; + int i_len = 0; uint32_t i_runs = 0; uint32_t i_k_runs = 0; uint32_t *pi_run_lengths = NULL; @@ -2636,6 +2304,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, rv = ProcessNodes( p_filter, p_xml_reader, p_region_in->p_style, psz_text, &i_len, &i_runs, &pi_run_lengths, &pp_styles, + b_karaoke, &i_k_runs, &pi_k_run_lengths, &pi_k_durations ); @@ -2686,7 +2355,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, } static char* FontConfig_Select( FcConfig* priv, const char* family, - vlc_bool_t b_bold, vlc_bool_t b_italic, int *i_idx ) + bool b_bold, bool b_italic, int *i_idx ) { FcResult result; FcPattern *pat, *p_pat; @@ -2698,8 +2367,8 @@ static char* FontConfig_Select( FcConfig* priv, const char* family, FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family ); FcPatternAddBool( pat, FC_OUTLINE, FcTrue ); - FcPatternAddInteger( pat, FC_SLANT, b_italic ? 1000 : 0 ); - FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? 1000 : 0 ); + FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN ); + FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL ); FcDefaultSubstitute( pat ); @@ -2802,19 +2471,18 @@ static line_desc_t *NewLine( int i_count ) ( p_line->pi_underline_offset == NULL ) || ( p_line->pi_underline_thickness == NULL ) ) { - if( p_line->pi_underline_thickness ) - free( p_line->pi_underline_thickness ); - if( p_line->pi_underline_offset ) free( p_line->pi_underline_offset ); - if( p_line->p_fg_rgb ) free( p_line->p_fg_rgb ); - if( p_line->p_bg_rgb ) free( p_line->p_bg_rgb ); - if( p_line->p_fg_bg_ratio ) free( p_line->p_fg_bg_ratio ); - if( p_line->p_glyph_pos ) free( p_line->p_glyph_pos ); - if( p_line->pp_glyphs ) free( p_line->pp_glyphs ); + free( p_line->pi_underline_thickness ); + free( p_line->pi_underline_offset ); + free( p_line->p_fg_rgb ); + free( p_line->p_bg_rgb ); + free( p_line->p_fg_bg_ratio ); + free( p_line->p_glyph_pos ); + free( p_line->pp_glyphs ); free( p_line ); return NULL; } p_line->pp_glyphs[0] = NULL; - p_line->b_new_color_mode = VLC_FALSE; + p_line->b_new_color_mode = false; return p_line; } @@ -2835,9 +2503,12 @@ static int GetFontSize( filter_t *p_filter ) else { var_Get( p_filter, "freetype-rel-fontsize", &val ); - i_size = (int)p_filter->fmt_out.video.i_height / val.i_int; - p_filter->p_sys->i_display_height = - p_filter->fmt_out.video.i_height; + if( val.i_int > 0 ) + { + i_size = (int)p_filter->fmt_out.video.i_height / val.i_int; + p_filter->p_sys->i_display_height = + p_filter->fmt_out.video.i_height; + } } if( i_size <= 0 ) {