# include "config.h"
#endif
-#include <vlc/vlc.h>
+#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout.h>
#include <vlc_osd.h>
#include <assert.h>
-typedef struct line_desc_t line_desc_t;
-
/*****************************************************************************
- * 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 *,
- bool, bool, int * );
-static int BuildDone( vlc_object_t*, const char *, vlc_value_t, vlc_value_t,
- void* );
-#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")
"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" )
#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") };
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 */
line_desc_t *p_next;
};
+static line_desc_t *NewLine( int );
typedef struct font_stack_t font_stack_t;
struct font_stack_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, vlc_mutex_t **pp_lock );
+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 int FontBuilderDone( vlc_object_t*, const char *, vlc_value_t, vlc_value_t,
+ void* );
#endif
/*****************************************************************************
int i_default_font_size;
int i_display_height;
#ifdef HAVE_FONTCONFIG
+ vlc_mutex_t *p_fontconfig_lock;
+ bool b_fontconfig_ok;
FcConfig *p_fontconfig;
- bool b_fontconfig_ok;
- vlc_mutex_t fontconfig_lock;
#endif
input_attachment_t **pp_font_attachments;
int i_font_attachments;
+
+ vlc_object_t *p_fontbuilder;
};
/*****************************************************************************
char *psz_fontfile = NULL;
int i_error;
vlc_value_t val;
- vlc_object_t *p_fontbuilder;
/* 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;
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" );
}
#ifdef HAVE_FONTCONFIG
- vlc_mutex_init( &p_sys->fontconfig_lock );
p_sys->b_fontconfig_ok = false;
p_sys->p_fontconfig = NULL;
-
- /* Check for an existing Fontbuilder thread */
- vlc_mutex_t *lock = var_AcquireMutex( "fontbuilder" );
- p_fontbuilder = vlc_object_find_name( p_filter->p_libvlc,
- "fontlist builder",
- FIND_CHILD );
-
- if( ! p_fontbuilder )
- {
- /* Create the FontBuilder 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.
- */
-
- p_fontbuilder = vlc_object_create( p_filter->p_libvlc,
- VLC_OBJECT_GENERIC );
- if( p_fontbuilder )
- {
- p_fontbuilder->psz_object_name = strdup( "fontlist builder" );
- vlc_object_attach( p_fontbuilder, p_filter->p_libvlc );
-
- var_Create( p_fontbuilder, "build-done", VLC_VAR_BOOL );
- var_SetBool( p_fontbuilder, "build-done", false );
- var_AddCallback( p_fontbuilder, "build-done", BuildDone, p_sys );
-
- if( vlc_thread_create( p_fontbuilder,
- "fontlist builder",
- FontBuilder,
- VLC_THREAD_PRIORITY_LOW,
- 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
- {
- vlc_object_release( p_fontbuilder );
- }
- }
- else
- {
- vlc_object_release( p_fontbuilder );
- }
- vlc_mutex_unlock( lock );
-
+ p_sys->p_fontbuilder = FontBuilderAttach( p_filter, &p_sys->p_fontconfig_lock );
#endif
p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face );
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_t *lock = var_AcquireMutex( "fontbuilder" );
- vlc_object_t *p_fontbuilder = vlc_object_find_name( p_filter->p_libvlc,
- "fontlist builder", FIND_CHILD );
- if( p_fontbuilder )
- {
- var_DelCallback( p_fontbuilder, "build-done", BuildDone, p_sys );
- vlc_object_release( p_fontbuilder );
- }
- vlc_mutex_unlock( lock );
-
- 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_object_t *FontBuilderAttach( filter_t *p_filter, vlc_mutex_t **pp_lock )
+{
+ /* Check for an existing Fontbuilder thread */
+ vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" );
+ 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 );
+
+ var_Create( p_fontbuilder, "build-done", VLC_VAR_BOOL );
+ var_SetBool( p_fontbuilder, "build-done", false );
+
+ if( vlc_thread_create( p_fontbuilder,
+ "fontlist builder",
+ FontBuilderThread,
+ VLC_THREAD_PRIORITY_LOW,
+ false ) )
+ {
+ msg_Warn( p_filter, "fontconfig database builder thread can't "
+ "be launched. Font styling support will be limited." );
+ }
+ }
+ }
+ if( p_fontbuilder )
+ {
+ var_AddCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter );
+ var_TriggerCallback( p_fontbuilder, "build-done" );
+ }
+ vlc_mutex_unlock( p_lock );
+ *pp_lock = p_lock;
+ return p_fontbuilder;
+}
+static void FontBuilderDetach( filter_t *p_filter, vlc_object_t *p_fontbuilder )
+{
+ vlc_mutex_t *lock = var_AcquireMutex( "fontbuilder" );
+ if( p_fontbuilder )
+ {
+ const bool b_alive = vlc_object_alive( p_fontbuilder );
+
+ var_DelCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter );
+
+ /* We wait for the thread on the first FontBuilderDetach */
+ if( b_alive )
+ {
+ vlc_object_kill( p_fontbuilder );
+ vlc_mutex_unlock( lock );
-static void FontBuilder( vlc_object_t *p_this )
+ /* 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( lock );
+ }
+ vlc_object_release( p_fontbuilder );
+ }
+ vlc_mutex_unlock( lock );
+}
+static void FontBuilderThread( vlc_object_t *p_this )
{
FcConfig *p_fontconfig = FcInitLoadConfig();
- vlc_mutex_t *lock;
vlc_thread_ready( p_this );
{
mtime_t t1, t2;
+ //msg_Dbg( p_this, "Building font database..." );
msg_Dbg( p_this, "Building font database..." );
t1 = mdate();
if(! FcConfigBuildFonts( p_fontconfig ))
msg_Dbg( p_this, "Finished building font database." );
msg_Dbg( p_this, "Took %ld seconds", (long)((t2 - t1)/1000000) );
- lock = var_AcquireMutex( "fontbuilder" );
+ vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" );
+ p_this->p_private = p_fontconfig;
+ vlc_mutex_unlock( p_lock );
var_SetBool( p_this, "build-done", true );
+ }
+}
+static void FontBuilderDestructor( vlc_object_t *p_this )
+{
+ FcConfig *p_fontconfig = p_this->p_private;
+ if( p_fontconfig )
FcConfigDestroy( p_fontconfig );
- vlc_mutex_unlock( lock );
- }
- vlc_object_detach( p_this );
- vlc_object_release( p_this );
}
+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;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if( newval.b_bool )
+ {
+ vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" );
+
+ p_sys->b_fontconfig_ok = true;
+ p_sys->p_fontconfig = p_this->p_private;
+
+ vlc_mutex_unlock( p_lock );
+ }
+ VLC_UNUSED(psz_var);
+ VLC_UNUSED(oldval);
+ return VLC_SUCCESS;
+}
#endif
/*****************************************************************************
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
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 )
/* 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;
{
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;
return VLC_EGENERIC;
}
-static int BuildDone( vlc_object_t *p_this, const char *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *param )
-{
- (void)p_this;
- (void)psz_var;
- (void)oldval;
- ((filter_sys_t*)param)->b_fontconfig_ok = newval.b_bool;
- assert( newval.b_bool );
- return VLC_SUCCESS;
-}
-
static int ProcessLines( filter_t *p_filter,
uint32_t *psz_text,
int i_len,
! p_new_positions ||
! p_levels )
{
- msg_Err( p_filter, "out of memory" );
free( p_levels );
free( p_old_positions );
free( p_new_positions );
/* 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;
- vlc_mutex_lock( &p_sys->fontconfig_lock );
+ char *psz_fontfile = NULL;
- 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( &p_sys->fontconfig_lock );
+ vlc_mutex_lock( p_sys->p_fontconfig_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( p_sys->p_fontconfig_lock );
if( psz_fontfile && ! *psz_fontfile )
{
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( !(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 );
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 );