Changeset 2293854f363396b56fc15db8d903e26e1b631383

Show
Ignore:
Timestamp:
10/07/07 22:15:14 (1 year ago)
Author:
Jean-Baptiste Kempf <jb@videolan.org>
git-committer:
Jean-Baptiste Kempf <jb@videolan.org> 1184098514 +0000
git-parent:

[52576d03b9960f225aa40d6c4e1c29e5701925be]

git-author:
Jean-Baptiste Kempf <jb@videolan.org> 1184098514 +0000
Message:

* Adds a raster animation to text tagged with <karaoke> tags (like in USF

files)The timing of the raster is determined by t= tags contained within
the tags. For a demonstration of karaoke refer to the sample file attached.

* Support for bi-directional text needs to behave inside karaoke

tags. (In right to left text the raster needs to move from right to left
instead of left to right - it is supporting this feature that makes this
patch a little more complicated than it would otherwise be)

* Made the internal handling of font color and alpha tags more consistent

and convenient in a few places by storing in one variable as AARRGGBB,
rather than 2.

* Some cleanup of other code.

Patch by Bernie Purcell.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/misc/freetype.c

    r4d4eb33 r2293854  
    9797 
    9898static int SetFontSize( filter_t *, int ); 
     99static void YUVFromRGB( uint32_t i_argb, 
     100                        uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ); 
    99101 
    100102/***************************************************************************** 
     
    194196     *  b_new_color_mode is set, then it becomes possible to 
    195197     *  have multicoloured text within the subtitles. */ 
    196     uint32_t       *p_rgb; 
     198    uint32_t       *p_fg_rgb; 
     199    uint32_t       *p_bg_rgb; 
     200    uint8_t        *p_fg_bg_ratio; /* 0x00=100% FG --> 0x7F=100% BG */ 
    197201    vlc_bool_t      b_new_color_mode; 
    198202    /** underline information -- only supplied if text should be underlined */ 
     
    213217    char          *psz_name; 
    214218    int            i_size; 
    215     int            i_color; 
    216     int            i_alpha; 
     219    uint32_t       i_color;            /* ARGB */ 
     220    uint32_t       i_karaoke_bg_color; /* ARGB */ 
    217221 
    218222    font_stack_t  *p_next; 
     
    222226{ 
    223227    int         i_font_size; 
    224     uint32_t    i_font_color; /* ARGB */ 
     228    uint32_t    i_font_color;         /* ARGB */ 
     229    uint32_t    i_karaoke_bg_color;   /* ARGB */ 
    225230    vlc_bool_t  b_italic; 
    226231    vlc_bool_t  b_bold; 
     
    712717 
    713718    /* Calculate text color components */ 
    714     i_y = (uint8_t)__MIN(abs( 2104 * p_line->i_red  + 4130 * p_line->i_green + 
    715                       802 * p_line->i_blue + 4096 + 131072 ) >> 13, 235); 
    716     i_u = (uint8_t)__MIN(abs( -1214 * p_line->i_red  + -2384 * p_line->i_green + 
    717                      3598 * p_line->i_blue + 4096 + 1048576) >> 13, 240); 
    718     i_v = (uint8_t)__MIN(abs( 3598 * p_line->i_red + -3013 * p_line->i_green + 
    719                       -585 * p_line->i_blue + 4096 + 1048576) >> 13, 240); 
     719    YUVFromRGB( (p_line->i_red   << 16) | 
     720                (p_line->i_green <<  8) | 
     721                (p_line->i_blue       ), 
     722                &i_y, &i_u, &i_v); 
    720723    i_alpha = p_line->i_alpha; 
    721724 
     
    808811            { 
    809812                /* Every glyph can (and in fact must) have its own color */ 
    810                 int i_red   = ( p_line->p_rgb[ i ] & 0x00ff0000 ) >> 16; 
    811                 int i_green = ( p_line->p_rgb[ i ] & 0x0000ff00 ) >>  8; 
    812                 int i_blue  = ( p_line->p_rgb[ i ] & 0x000000ff ); 
    813  
    814                 i_y = (uint8_t)__MIN(abs( 2104 * i_red  + 4130 * i_green + 
    815                                   802 * i_blue + 4096 + 131072 ) >> 13, 235); 
    816                 i_u = (uint8_t)__MIN(abs( -1214 * i_red  + -2384 * i_green + 
    817                                  3598 * i_blue + 4096 + 1048576) >> 13, 240); 
    818                 i_v = (uint8_t)__MIN(abs( 3598 * i_red + -3013 * i_green + 
    819                                   -585 * i_blue + 4096 + 1048576) >> 13, 240); 
     813                YUVFromRGB( p_line->p_fg_rgb[ i ], &i_y, &i_u, &i_v ); 
    820814            } 
    821815 
     
    824818                for( x = 0; x < p_glyph->bitmap.width; x++, i_bitmap_offset++ ) 
    825819                { 
     820                    uint8_t i_y_local = i_y; 
     821                    uint8_t i_u_local = i_u; 
     822                    uint8_t i_v_local = i_v; 
     823 
     824                    if( p_line->p_fg_bg_ratio != 0x00 ) 
     825                    { 
     826                        int i_split = p_glyph->bitmap.width * 
     827                                      p_line->p_fg_bg_ratio[ i ] / 0x7f; 
     828 
     829                        if( x > i_split ) 
     830                        { 
     831                            YUVFromRGB( p_line->p_bg_rgb[ i ], 
     832                                        &i_y_local, &i_u_local, &i_v_local ); 
     833                        } 
     834                    } 
     835 
    826836                    if( p_glyph->bitmap.buffer[i_bitmap_offset] ) 
    827837                    { 
     
    11551165#ifdef HAVE_FONTCONFIG 
    11561166static ft_style_t *CreateStyle( char *psz_fontname, int i_font_size, 
    1157         int i_font_color, int i_font_alpha, vlc_bool_t b_bold, 
     1167        uint32_t i_font_color, uint32_t i_karaoke_bg_color, vlc_bool_t b_bold, 
    11581168        vlc_bool_t b_italic, vlc_bool_t b_uline ) 
    11591169{ 
     
    11621172    if( p_style ) 
    11631173    { 
    1164         p_style->i_font_size  = i_font_size; 
    1165         p_style->i_font_color = ( i_font_color & 0x00ffffff ) 
    1166                                 | (( i_font_alpha & 0xff ) << 24 ); 
    1167         p_style->b_italic     = b_italic; 
    1168         p_style->b_bold       = b_bold; 
    1169         p_style->b_underline  = b_uline; 
    1170         /* p_style has just been malloc'ed in this function - 
    1171          * it CAN'T have a previous assignment, and hence we 
    1172          * don't need to do a free() for any previous value - 
    1173          * which will in fact be undefined. */ 
     1174        p_style->i_font_size        = i_font_size; 
     1175        p_style->i_font_color       = i_font_color; 
     1176        p_style->i_karaoke_bg_color = i_karaoke_bg_color; 
     1177        p_style->b_italic           = b_italic; 
     1178        p_style->b_bold             = b_bold; 
     1179        p_style->b_underline        = b_uline; 
     1180 
    11741181        p_style->psz_fontname = strdup( psz_fontname ); 
    11751182    } 
     
    12071214 
    12081215static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size, 
    1209                      int i_color, int i_alpha
     1216                     uint32_t i_color, uint32_t i_karaoke_bg_color
    12101217{ 
    12111218    font_stack_t *p_new; 
     
    12251232        p_new->psz_name = NULL; 
    12261233 
    1227     p_new->i_size   = i_size; 
    1228     p_new->i_color  = i_color; 
    1229     p_new->i_alpha  = i_alpha
     1234    p_new->i_size              = i_size; 
     1235    p_new->i_color             = i_color; 
     1236    p_new->i_karaoke_bg_color  = i_karaoke_bg_color
    12301237 
    12311238    if( !*p_font ) 
     
    12741281 
    12751282static int PeekFont( font_stack_t **p_font, char **psz_name, int *i_size, 
    1276                      int *i_color, int *i_alpha
     1283                     uint32_t *i_color, uint32_t *i_karaoke_bg_color
    12771284{ 
    12781285    font_stack_t *p_last; 
     
    12861293    ; 
    12871294 
    1288     *psz_name = p_last->psz_name; 
    1289     *i_size   = p_last->i_size; 
    1290     *i_color  = p_last->i_color; 
    1291     *i_alpha  = p_last->i_alpha
     1295    *psz_name            = p_last->psz_name; 
     1296    *i_size              = p_last->i_size; 
     1297    *i_color             = p_last->i_color; 
     1298    *i_karaoke_bg_color  = p_last->i_karaoke_bg_color
    12921299 
    12931300    return VLC_SUCCESS; 
     
    13551362    ft_style_t   *p_style = NULL; 
    13561363 
    1357     char  *psz_fontname = NULL; 
    1358     int    i_font_color = p_sys->i_font_color
    1359     int    i_font_alpha = 0
    1360     int    i_font_size  = p_sys->i_font_size; 
     1364    char       *psz_fontname = NULL; 
     1365    uint32_t    i_font_color = p_sys->i_font_color & 0x00ffffff
     1366    uint32_t    i_karaoke_bg_color = i_font_color
     1367    int         i_font_size  = p_sys->i_font_size; 
    13611368 
    13621369    if( VLC_SUCCESS == PeekFont( p_fonts, &psz_fontname, &i_font_size, 
    1363                                  &i_font_color, &i_font_alpha )
     1370                                 &i_font_color, &i_karaoke_bg_color )
    13641371    { 
    13651372        p_style = CreateStyle( psz_fontname, i_font_size, i_font_color, 
    1366                 i_font_alpha, b_bold, b_italic, b_uline ); 
     1373                i_karaoke_bg_color, b_bold, b_italic, b_uline ); 
    13671374    } 
    13681375    return p_style; 
     
    13701377 
    13711378static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, 
    1372                       vlc_bool_t b_uline, line_desc_t *p_line, 
    1373                       uint32_t *psz_unicode, int *pi_pen_x, int i_pen_y, 
    1374                       int *pi_start, FT_Vector *p_result ) 
     1379                      vlc_bool_t b_uline, int i_karaoke_bgcolor, 
     1380                      line_desc_t *p_line, uint32_t *psz_unicode, 
     1381                      int *pi_pen_x, int i_pen_y, int *pi_start, 
     1382                      FT_Vector *p_result ) 
    13751383{ 
    13761384    FT_BBox      line; 
     
    14591467        } 
    14601468        p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph; 
    1461         p_line->p_rgb[ i ] = i_font_color & 0x00ffffff; 
     1469        p_line->p_fg_rgb[ i ] = i_font_color & 0x00ffffff; 
     1470        p_line->p_bg_rgb[ i ] = i_karaoke_bgcolor & 0x00ffffff; 
     1471        p_line->p_fg_bg_ratio[ i ] = 0x00; 
    14621472 
    14631473        line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - 
     
    15481558                                  font_stack_t **p_fonts ) 
    15491559{ 
    1550     int   rv; 
    1551     char *psz_fontname = NULL; 
    1552     int   i_font_color = 0xffffff; 
    1553     int   i_font_alpha = 0; 
    1554     int   i_font_size  = 24; 
     1560    int        rv; 
     1561    char      *psz_fontname = NULL; 
     1562    uint32_t   i_font_color = 0xffffff; 
     1563    int        i_font_alpha = 0; 
     1564    uint32_t   i_karaoke_bg_color = 0x00ffffff; 
     1565    int        i_font_size  = 24; 
    15551566 
    15561567    /* Default all attributes to the top font in the stack -- in case not 
     
    15611572                                 &i_font_size, 
    15621573                                 &i_font_color, 
    1563                                  &i_font_alpha )) 
     1574                                 &i_karaoke_bg_color )) 
    15641575    { 
    15651576        psz_fontname = strdup( psz_fontname ); 
    15661577    } 
     1578    i_font_alpha = (i_font_color >> 24) & 0xff; 
     1579    i_font_color &= 0x00ffffff; 
    15671580 
    15681581    while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) 
    15691582    { 
    1570         char *psz_name = xml_ReaderName ( p_xml_reader ); 
    1571         char *psz_value = xml_ReaderValue ( p_xml_reader ); 
     1583        char *psz_name = xml_ReaderName( p_xml_reader ); 
     1584        char *psz_value = xml_ReaderValue( p_xml_reader ); 
    15721585 
    15731586        if( psz_name && psz_value ) 
     
    16131626                   psz_fontname, 
    16141627                   i_font_size, 
    1615                    i_font_color
    1616                    i_font_alpha ); 
     1628                   (i_font_color & 0xffffff) | ((i_font_alpha & 0xff) << 24)
     1629                   i_karaoke_bg_color ); 
    16171630 
    16181631    free( psz_fontname ); 
     
    16771690} 
    16781691 
    1679 static int ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, 
    1680                          text_style_t *p_font_style, uint32_t *psz_text, 
    1681                          int *pi_len, uint32_t *pi_runs, 
    1682                          uint32_t **ppi_run_lengths, ft_style_t ***ppp_styles) 
     1692static void SetKaraokeLen( uint32_t i_runs, uint32_t *pi_run_lengths, 
     1693                           uint32_t i_k_runs, uint32_t *pi_k_run_lengths ) 
     1694
     1695    /* Karaoke tags _PRECEDE_ the text they specify a duration 
     1696     * for, therefore we are working out the length for the 
     1697     * previous tag, and first time through we have nothing 
     1698     */ 
     1699    if( pi_k_run_lengths ) 
     1700    { 
     1701        int i_chars = 0; 
     1702        uint32_t i; 
     1703 
     1704        /* Work out how many characters are presently in the string 
     1705         */ 
     1706        for( i = 0; i < i_runs; i++ ) 
     1707            i_chars += pi_run_lengths[ i ]; 
     1708 
     1709        /* Subtract away those we've already allocated to other 
     1710         * karaoke tags 
     1711         */ 
     1712        for( i = 0; i < i_k_runs; i++ ) 
     1713            i_chars -= pi_k_run_lengths[ i ]; 
     1714 
     1715        pi_k_run_lengths[ i_k_runs - 1 ] = i_chars; 
     1716    } 
     1717
     1718 
     1719static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs, 
     1720                          uint32_t **ppi_k_run_lengths, 
     1721                          uint32_t **ppi_k_durations ) 
     1722
     1723    while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) 
     1724    { 
     1725        char *psz_name = xml_ReaderName( p_xml_reader ); 
     1726        char *psz_value = xml_ReaderValue( p_xml_reader ); 
     1727 
     1728        if( psz_name && psz_value && 
     1729            !strcasecmp( "t", psz_name ) ) 
     1730        { 
     1731            if( ppi_k_durations && ppi_k_run_lengths ) 
     1732            { 
     1733                (*pi_k_runs)++; 
     1734 
     1735                if( *ppi_k_durations ) 
     1736                { 
     1737                    *ppi_k_durations = (uint32_t *) 
     1738                        realloc( *ppi_k_durations, 
     1739                                 *pi_k_runs * sizeof( uint32_t ) ); 
     1740                } 
     1741                else if( *pi_k_runs == 1 ) 
     1742                { 
     1743                    *ppi_k_durations = (uint32_t *) 
     1744                        malloc( *pi_k_runs * sizeof( uint32_t ) ); 
     1745                } 
     1746 
     1747                if( *ppi_k_run_lengths ) 
     1748                { 
     1749                    *ppi_k_run_lengths = (uint32_t *) 
     1750                        realloc( *ppi_k_run_lengths, 
     1751                                 *pi_k_runs * sizeof( uint32_t ) ); 
     1752                } 
     1753                else if( *pi_k_runs == 1 ) 
     1754                { 
     1755                    *ppi_k_run_lengths = (uint32_t *) 
     1756                        malloc( *pi_k_runs * sizeof( uint32_t ) ); 
     1757                } 
     1758                if( *ppi_k_durations ) 
     1759                    (*ppi_k_durations)[ *pi_k_runs - 1 ] = atoi( psz_value ); 
     1760                 
     1761                if( *ppi_k_run_lengths ) 
     1762                    (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0; 
     1763            } 
     1764        } 
     1765        if( psz_name )  free( psz_name ); 
     1766        if( psz_value ) free( psz_value ); 
     1767    } 
     1768
     1769 
     1770static int ProcessNodes( filter_t *p_filter, 
     1771                         xml_reader_t *p_xml_reader, 
     1772                         text_style_t *p_font_style, 
     1773                         uint32_t *psz_text, 
     1774                         int *pi_len, 
     1775 
     1776                         uint32_t *pi_runs, 
     1777                         uint32_t **ppi_run_lengths, 
     1778                         ft_style_t ***ppp_styles, 
     1779 
     1780                         vlc_bool_t b_karaoke, 
     1781                         uint32_t *pi_k_runs, 
     1782                         uint32_t **ppi_k_run_lengths, 
     1783                         uint32_t **ppi_k_durations ) 
    16831784{ 
    16841785    int           rv             = VLC_SUCCESS; 
     
    16961797    { 
    16971798        rv = PushFont( &p_fonts, 
    1698                        p_font_style->psz_fontname, 
    1699                        p_font_style->i_font_size, 
    1700                        p_font_style->i_font_color, 
    1701                        p_font_style->i_font_alpha ); 
     1799               p_font_style->psz_fontname, 
     1800               p_font_style->i_font_size, 
     1801               (p_font_style->i_font_color & 0xffffff) | 
     1802                   ((p_font_style->i_font_alpha & 0xff) << 24), 
     1803               (p_font_style->i_karaoke_background_color & 0xffffff) | 
     1804                   ((p_font_style->i_karaoke_background_alpha & 0xff) << 24)); 
    17021805 
    17031806        if( p_font_style->i_style_flags & STYLE_BOLD ) 
     
    17131816                       FC_DEFAULT_FONT, 
    17141817                       p_sys->i_font_size, 
    1715                        0xffffff, 
    1716                        0 ); 
     1818                       0x00ffffff, 
     1819                       0x00ffffff ); 
    17171820    } 
    17181821    if( rv != VLC_SUCCESS ) 
     
    17641867                                                          b_uline ) ); 
    17651868                    } 
     1869                    else if( !strcasecmp( "k", psz_node ) ) 
     1870                    { 
     1871                        /* Only valid in karaoke */ 
     1872                        if( b_karaoke ) 
     1873                        { 
     1874                            if( *pi_k_runs > 0 ) 
     1875                            { 
     1876                                SetKaraokeLen( *pi_runs, *ppi_run_lengths, 
     1877                                               *pi_k_runs, *ppi_k_run_lengths ); 
     1878                            } 
     1879                            SetupKaraoke( p_xml_reader, pi_k_runs, 
     1880                                          ppi_k_run_lengths, ppi_k_durations ); 
     1881                        } 
     1882                    } 
    17661883 
    17671884                    free( psz_node ); 
     
    18031920        } 
    18041921    } 
     1922    if( b_karaoke ) 
     1923    { 
     1924        SetKaraokeLen( *pi_runs, *ppi_run_lengths, 
     1925                       *pi_k_runs, *ppi_k_run_lengths ); 
     1926    } 
    18051927 
    18061928    *pi_len = psz_text - psz_text_orig; 
     
    18111933} 
    18121934 
    1813 static int ProcessLines( filter_t *p_filter, uint32_t *psz_text, 
    1814                          int i_len, uint32_t i_runs, 
    1815                          uint32_t *pi_run_lengths, ft_style_t **pp_styles, 
    1816                          line_desc_t **pp_lines, FT_Vector *p_result ) 
     1935static int ProcessLines( filter_t *p_filter, 
     1936                         uint32_t *psz_text, 
     1937                         int i_len, 
     1938 
     1939                         uint32_t i_runs, 
     1940                         uint32_t *pi_run_lengths, 
     1941                         ft_style_t **pp_styles, 
     1942                         line_desc_t **pp_lines, 
     1943                          
     1944                         FT_Vector *p_result, 
     1945 
     1946                         vlc_bool_t b_karaoke, 
     1947                         uint32_t i_k_runs, 
     1948                         uint32_t *pi_k_run_lengths, 
     1949                         uint32_t *pi_k_durations )  
    18171950{ 
    18181951    filter_sys_t   *p_sys = p_filter->p_sys; 
    1819     ft_style_t     **pp_char_styles; 
     1952    ft_style_t    **pp_char_styles; 
     1953    int            *p_new_positions = NULL; 
     1954    int8_t         *p_levels = NULL; 
     1955    uint8_t        *pi_karaoke_bar = NULL; 
    18201956    uint32_t        i, j, k; 
    18211957    int             i_prev; 
     
    18291965        return VLC_ENOMEM; 
    18301966 
     1967    if( b_karaoke ) 
     1968    { 
     1969        pi_karaoke_bar = (uint8_t *) malloc( i_len * sizeof( uint8_t )); 
     1970        /* If we can't allocate sufficient memory for karaoke, continue anyway - 
     1971         * we just won't be able to display the progress bar; at least we'll 
     1972         * get the text. 
     1973         */ 
     1974    } 
     1975 
    18311976    i = 0; 
    18321977    for( j = 0; j < i_runs; j++ ) 
     
    18371982    { 
    18381983        ft_style_t  **pp_char_styles_new; 
    1839         int         *p_positions; 
     1984        int         *p_old_positions; 
    18401985        uint32_t    *p_fribidi_string; 
    18411986        int start_pos, pos = 0; 
    18421987 
    1843         p_fribidi_string = malloc( (i_len + 1) * sizeof(uint32_t) ); 
    1844         if(! p_fribidi_string ) 
     1988        pp_char_styles_new  = (ft_style_t **) 
     1989            malloc( i_len * sizeof( ft_style_t * )); 
     1990 
     1991        p_fribidi_string = (uint32_t *) 
     1992            malloc( (i_len + 1) * sizeof(uint32_t) ); 
     1993        p_old_positions = (int *) 
     1994            malloc( (i_len + 1) * sizeof( int ) ); 
     1995        p_new_positions = (int *) 
     1996            malloc( (i_len + 1) * sizeof( int ) ); 
     1997        p_levels = (int8_t *) 
     1998            malloc( (i_len + 1) * sizeof( int8_t ) ); 
     1999 
     2000        if( ! pp_char_styles_new || 
     2001            ! p_fribidi_string || 
     2002            ! p_old_positions || 
     2003            ! p_new_positions || 
     2004            ! p_levels ) 
    18452005        { 
    18462006            msg_Err( p_filter, "out of memory" ); 
    1847             free( pp_char_styles ); 
    1848             return VLC_ENOMEM; 
    1849         } 
    1850         pp_char_styles_new  = (ft_style_t **) 
    1851                                        malloc( i_len * sizeof( ft_style_t * )); 
    1852         if(! pp_char_styles_new ) 
    1853         { 
    1854             msg_Err( p_filter, "out of memory" ); 
    1855             free( p_fribidi_string ); 
    1856             free( pp_char_styles ); 
    1857             return VLC_ENOMEM; 
    1858         } 
    1859         p_positions = (int *) malloc( (i_len + 1) * sizeof( int ) ); 
    1860         if(! p_positions ) 
    1861         { 
    1862             msg_Err( p_filter, "out of memory" ); 
    1863             free( pp_char_styles_new ); 
    1864             free( p_fribidi_string ); 
     2007            if( p_levels )           free( p_levels ); 
     2008            if( p_old_positions )    free( p_old_positions ); 
     2009            if( p_new_positions )    free( p_new_positions ); 
     2010            if( p_fribidi_string )   free( p_fribidi_string ); 
     2011            if( pp_char_styles_new ) free( pp_char_styles_new ); 
     2012            if( pi_karaoke_bar )     free( pi_karaoke_bar ); 
     2013 
    18652014            free( pp_char_styles ); 
    18662015            return VLC_ENOMEM; 
     
    18752024                p_fribidi_string[pos] = psz_text[pos]; 
    18762025                pp_char_styles_new[pos] = pp_char_styles[pos]; 
     2026                p_new_positions[pos] = pos; 
     2027                p_levels[pos] = 0; 
    18772028                ++pos; 
    18782029            } 
     
    18892040                        pos - start_pos, &base_dir, 
    18902041                        (FriBidiChar*)p_fribidi_string + start_pos, 
    1891                         0
    1892                         p_positions, 0); 
    1893  
     2042                        p_new_positions + start_pos
     2043                        p_old_positions, 
     2044                        p_levels + start_pos ); 
    18942045                for( j = (uint32_t) start_pos; j < (uint32_t) pos; j++ ) 
    18952046                { 
    18962047                    pp_char_styles_new[ j ] = pp_char_styles[ start_pos + 
    1897                                                 p_positions[ j - start_pos ] ]; 
     2048                                                p_old_positions[ j - start_pos ] ]; 
     2049                    p_new_positions[ j ] += start_pos; 
    18982050                } 
    18992051            } 
    19002052        } 
    1901         free( p_positions ); 
     2053        free( p_old_positions ); 
    19022054        free( pp_char_styles ); 
    19032055        pp_char_styles = pp_char_styles_new; 
     
    19062058    } 
    19072059#endif 
     2060    /* Work out the karaoke */ 
     2061    if( pi_karaoke_bar ) 
     2062    { 
     2063        int64_t i_last_duration = 0; 
     2064        int64_t i_duration = 0; 
     2065        int64_t i_start_pos = 0; 
     2066        int64_t i_elapsed  = var_GetTime( p_filter, "spu-elapsed" ) / 1000; 
     2067         
     2068        for( k = 0; k< i_k_runs; k++ ) 
     2069        { 
     2070             double fraction = 0.0; 
     2071 
     2072             i_duration += pi_k_durations[ k ]; 
     2073 
     2074             if( i_duration < i_elapsed ) 
     2075             { 
     2076                 /* Completely finished this run-length - 
     2077                  * let it render normally */ 
     2078 
     2079                 fraction = 1.0; 
     2080             } 
     2081             else if( i_elapsed < i_last_duration ) 
     2082             { 
     2083                 /* Haven't got up to this segment yet - 
     2084                  * render it completely in karaoke BG mode */ 
     2085 
     2086                 fraction = 0.0; 
     2087             } 
     2088             else 
     2089             { 
     2090                 /* Partway through this run */ 
     2091 
     2092                 fraction = (double)(i_elapsed - i_last_duration) / 
     2093                            (double)pi_k_durations[ k ]; 
     2094             } 
     2095             for( i = 0; i < pi_k_run_lengths[ k ]; i++ ) 
     2096             { 
     2097                 double shade = pi_k_run_lengths[ k ] * fraction; 
     2098 
     2099                 if( p_new_positions ) 
     2100                     j = p_new_positions[ i_start_pos + i ]; 
     2101                 else 
     2102                     j = i_start_pos + i; 
     2103 
     2104                 if( i < (uint32_t)shade ) 
     2105                     pi_karaoke_bar[ j ] = 0xff; 
     2106                 else if( (double)i > shade ) 
     2107                     pi_karaoke_bar[ j ] = 0x00; 
     2108                 else 
     2109                 { 
     2110                     shade -= (int)shade; 
     2111                     pi_karaoke_bar[ j ] = ((int)(shade * 128.0) & 0x7f) | 
     2112                                   ((p_levels ? (p_levels[ j ] % 2) : 0 ) << 7); 
     2113                 } 
     2114             } 
     2115              
     2116             i_last_duration = i_duration; 
     2117             i_start_pos += pi_k_run_lengths[ k ]; 
     2118        } 
     2119    } 
     2120    if( p_levels )         free( p_levels ); 
     2121    if( p_new_positions )  free( p_new_positions ); 
     2122 
    19082123    FT_Vector tmp_result; 
    19092124 
     
    19452160                    free( psz_text ); 
    19462161#endif 
     2162                    if( pi_karaoke_bar ) 
     2163                        free( pi_karaoke_bar ); 
    19472164                    return VLC_EGENERIC; 
    19482165                } 
     
    19602177                free( psz_text ); 
    19612178#endif 
     2179                if( pi_karaoke_bar ) 
     2180                    free( pi_karaoke_bar ); 
    19622181                return VLC_EGENERIC; 
    19632182            } 
     
    19772196                free( psz_text ); 
    19782197#endif 
     2198                if( pi_karaoke_bar ) 
     2199                    free( pi_karaoke_bar ); 
    19792200                return VLC_ENOMEM; 
    19802201            } 
     
    19952216                        free( psz_text ); 
    19962217#endif 
     2218                        if( pi_karaoke_bar ) 
     2219                            free( pi_karaoke_bar ); 
    19972220                        return VLC_ENOMEM; 
    19982221                    } 
     
    20152238                    else *pp_lines = p_line; 
    20162239                } 
     2240 
    20172241                if( RenderTag( p_filter, p_face ? p_face : p_sys->p_face, 
    20182242                               p_style->i_font_color, p_style->b_underline, 
     2243                               p_style->i_karaoke_bg_color, 
    20192244                               p_line, psz_unicode, &i_pen_x, i_pen_y, &i_posn, 
    20202245                               &tmp_result ) != VLC_SUCCESS ) 
     
    20262251                    free( psz_text ); 
    20272252#endif 
     2253                    if( pi_karaoke_bar ) 
     2254                        free( pi_karaoke_bar ); 
    20282255                    return VLC_EGENERIC; 
    20292256                } 
     2257 
    20302258                if( *psz_unicode ) 
    20312259                { 
     
    20462274    free( psz_text ); 
    20472275#endif 
    2048  
    20492276    if( p_line ) 
    20502277    { 
     
    20522279        p_result->y += tmp_result.y; 
    20532280    } 
     2281 
     2282    if( pi_karaoke_bar ) 
     2283    { 
     2284        int i = 0; 
     2285        for( p_line = *pp_lines; p_line; p_line=p_line->p_next ) 
     2286        { 
     2287            for( k = 0; p_line->pp_glyphs[ k ]; k++, i++ ) 
     2288            { 
     2289                if( (pi_karaoke_bar[ i ] & 0x7f) == 0x7f) 
     2290                { 
     2291                    /* do nothing */ 
     2292                } 
     2293                else if( (pi_karaoke_bar[ i ] & 0x7f) == 0x00) 
     2294                { 
     2295                    /* 100% BG colour will render faster if we 
     2296                     * instead make it 100% FG colour, so leave 
     2297                     * the ratio alone and copy the value across 
     2298                     */ 
     2299                    p_line->p_fg_rgb[ k ] = p_line->p_bg_rgb[ k ]; 
     2300                } 
     2301                else 
     2302                { 
     2303                    if( pi_karaoke_bar[ i ] & 0x80 ) 
     2304                    { 
     2305                        /* Swap Left and Right sides over for Right aligned 
     2306                         * language text (eg. Arabic, Hebrew) 
     2307                         */ 
     2308                        uint32_t i_tmp = p_line->p_fg_rgb[ k ]; 
     2309 
     2310                        p_line->p_fg_rgb[ k ] = p_line->p_bg_rgb[ k ]; 
     2311                        p_line->p_bg_rgb[ k ] = i_tmp; 
     2312                    } 
     2313                    p_line->p_fg_bg_ratio[ k ] = (pi_karaoke_bar[ i ] & 0x7f); 
     2314                } 
     2315            } 
     2316            /* Jump over the '\n' at the line-end */ 
     2317            i++; 
     2318        } 
     2319        free( pi_karaoke_bar ); 
     2320    } 
     2321 
    20542322    return VLC_SUCCESS; 
    20552323} 
     
    20752343        if( p_xml ) 
    20762344        { 
     2345            vlc_bool_t b_karaoke = VLC_FALSE; 
     2346 
    20772347            p_xml_reader = xml_ReaderCreate( p_xml, p_sub ); 
     2348            if( p_xml_reader ) 
     2349            { 
     2350                /* Look for Root Node */ 
     2351                if( xml_ReaderRead( p_xml_reader ) == 1 ) 
     2352                { 
     2353                    char *psz_node = xml_ReaderName( p_xml_reader ); 
     2354 
     2355                    if( !strcasecmp( "karaoke", psz_node ) ) 
     2356                    { 
     2357                        /* We're going to have to render the text a number 
     2358                         * of times to show the progress marker on the text. 
     2359                         */ 
     2360                        var_SetBool( p_filter, "text-rerender", VLC_TRUE ); 
     2361                        b_karaoke = VLC_TRUE; 
     2362                    } 
     2363                    else if( !strcasecmp( "text", psz_node ) ) 
     2364                    { 
     2365                        b_karaoke = VLC_FALSE; 
     2366                    } 
     2367                    else 
     2368                    { 
     2369                        /* Only text and karaoke tags are supported */ 
     2370                        xml_ReaderDelete( p_xml, p_xml_reader ); 
     2371                        p_xml_reader = NULL; 
     2372                        rv = VLC_EGENERIC; 
     2373                    } 
     2374 
     2375                    free( psz_node ); 
     2376                } 
     2377            } 
     2378 
    20782379            if( p_xml_reader ) 
    20792380            { 
     
    20812382                int         i_len; 
    20822383                uint32_t    i_runs = 0; 
     2384                uint32_t    i_k_runs = 0; 
    20832385                uint32_t   *pi_run_lengths = NULL; 
     2386                uint32_t   *pi_k_run_lengths = NULL; 
     2387                uint32_t   *pi_k_durations = NULL; 
    20842388                ft_style_t  **pp_styles = NULL; 
    20852389                FT_Vector    result; 
     
    20942398                    rv = ProcessNodes( p_filter, p_xml_reader, 
    20952399                                  p_region_in->p_style, psz_text, &i_len, 
    2096                                   &i_runs, &pi_run_lengths, &pp_styles ); 
     2400                                  &i_runs, &pi_run_lengths, &pp_styles, 
     2401                                  b_karaoke, &i_k_runs, &pi_k_run_lengths, 
     2402                                  &pi_k_durations ); 
    20972403 
    20982404                    p_region_out->i_x = p_region_in->i_x; 
     
    21022408                    { 
    21032409                        rv = ProcessLines( p_filter, psz_text, i_len, i_runs, 
    2104                                 pi_run_lengths, pp_styles, &p_lines, &result ); 
     2410                                pi_run_lengths, pp_styles, &p_lines, &result, 
     2411                                b_karaoke, i_k_runs, pi_k_run_lengths, 
     2412                                pi_k_durations ); 
    21052413                    } 
    21062414 
     
    22122520    free( p_line->pp_glyphs ); 
    22132521    free( p_line->p_glyph_pos ); 
    2214     free( p_line->p_rgb ); 
     2522    free( p_line->p_fg_rgb ); 
     2523    free( p_line->p_bg_rgb ); 
     2524    free( p_line->p_fg_bg_ratio ); 
    22152525    free( p_line->pi_underline_offset ); 
    22162526    free( p_line->pi_underline_thickness ); 
     
    22422552    p_line->pp_glyphs = malloc( sizeof(FT_BitmapGlyph) * ( i_count + 1 ) ); 
    22432553    p_line->p_glyph_pos = malloc( sizeof( FT_Vector ) * ( i_count + 1 ) ); 
    2244     p_line->p_rgb = malloc( sizeof( uint32_t ) * ( i_count + 1 ) ); 
     2554    p_line->p_fg_rgb = malloc( sizeof( uint32_t ) * ( i_count + 1 ) ); 
     2555    p_line->p_bg_rgb = malloc( sizeof( uint32_t ) * ( i_count + 1 ) ); 
     2556    p_line->p_fg_bg_ratio = calloc( i_count + 1, sizeof( uint8_t ) ); 
    22452557    p_line->pi_underline_offset = calloc( i_count + 1, sizeof( uint16_t ) ); 
    22462558    p_line->pi_underline_thickness = calloc( i_count + 1, sizeof( uint16_t ) ); 
    22472559    if( ( p_line->pp_glyphs == NULL ) || 
    22482560        ( p_line->p_glyph_pos == NULL ) || 
    2249         ( p_line->p_rgb == NULL ) || 
     2561        ( p_line->p_fg_rgb == NULL ) || 
     2562        ( p_line->p_bg_rgb == NULL ) || 
     2563        ( p_line->p_fg_bg_ratio == NULL ) || 
    22502564        ( p_line->pi_underline_offset == NULL ) || 
    22512565        ( p_line->pi_underline_thickness == NULL ) ) 
     
    22542568            free( p_line->pi_underline_thickness ); 
    22552569        if( p_line->pi_underline_offset ) free( p_line->pi_underline_offset ); 
    2256         if( p_line->p_rgb ) free( p_line->p_rgb ); 
     2570        if( p_line->p_fg_rgb ) free( p_line->p_fg_rgb ); 
     2571        if( p_line->p_bg_rgb ) free( p_line->p_bg_rgb ); 
     2572        if( p_line->p_fg_bg_ratio ) free( p_line->p_fg_bg_ratio ); 
    22572573        if( p_line->p_glyph_pos ) free( p_line->p_glyph_pos ); 
    22582574        if( p_line->pp_glyphs ) free( p_line->pp_glyphs ); 
     
    23102626    return VLC_SUCCESS; 
    23112627} 
     2628 
     2629static void YUVFromRGB( uint32_t i_argb, 
     2630                    uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ) 
     2631{ 
     2632    int i_red   = ( i_argb & 0x00ff0000 ) >> 16; 
     2633    int i_green = ( i_argb & 0x0000ff00 ) >>  8; 
     2634    int i_blue  = ( i_argb & 0x000000ff ); 
     2635 
     2636    *pi_y = (uint8_t)__MIN(abs( 2104 * i_red  + 4130 * i_green + 
     2637                      802 * i_blue + 4096 + 131072 ) >> 13, 235); 
     2638    *pi_u = (uint8_t)__MIN(abs( -1214 * i_red  + -2384 * i_green + 
     2639                     3598 * i_blue + 4096 + 1048576) >> 13, 240); 
     2640    *pi_v = (uint8_t)__MIN(abs( 3598 * i_red + -3013 * i_green + 
     2641                      -585 * i_blue + 4096 + 1048576) >> 13, 240); 
     2642}