[vlc-devel] [PATCH] Add support for rendering EIA-608 captions with a black background

Devin Heitmueller dheitmueller at kernellabs.com
Wed Jan 2 17:45:11 CET 2013


Place a black background behind caption text.  We cannot use the
existing "background" feature for subdecoders because it fills the
entire subpicture block, and in the case of the EIA-608 decoder
would result in a large square (since we send all lines to
the subpicture decoder even if they are blank).  This approach
allows for rendering of the background even in such cases, while
preserving proper layout of the captions.
---
 include/vlc_subpicture.h         |    1 +
 modules/codec/cc.c               |    1 +
 modules/codec/substext.h         |    2 +
 modules/text_renderer/freetype.c |   96 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 100 insertions(+)

diff --git a/include/vlc_subpicture.h b/include/vlc_subpicture.h
index d98e043..6bfede1 100644
--- a/include/vlc_subpicture.h
+++ b/include/vlc_subpicture.h
@@ -67,6 +67,7 @@ struct subpicture_region_t
     char            *psz_text;       /**< text string comprising this region */
     char            *psz_html;       /**< HTML version of subtitle (NULL = use psz_text) */
     text_style_t    *p_style;        /**< a description of the text style formatting */
+    bool            b_renderbg;      /**< render black background under text */
 
     subpicture_region_t *p_next;                /**< next region in the list */
     subpicture_region_private_t *p_private;  /**< Private data for spu_t *only* */
diff --git a/modules/codec/cc.c b/modules/codec/cc.c
index 75dae6b..0d9edd4 100644
--- a/modules/codec/cc.c
+++ b/modules/codec/cc.c
@@ -333,6 +333,7 @@ static subpicture_t *Subtitle( decoder_t *p_dec, char *psz_subtitle, char *psz_h
     p_spu_sys->text  = psz_subtitle;
     p_spu_sys->html  = psz_html;
     p_spu_sys->i_font_height_percent = 5;
+    p_spu_sys->renderbg = 1;
 
     return p_spu;
 }
diff --git a/modules/codec/substext.h b/modules/codec/substext.h
index 68e6c61..fe5df95 100644
--- a/modules/codec/substext.h
+++ b/modules/codec/substext.h
@@ -10,6 +10,7 @@ struct subpicture_updater_sys_t {
     bool is_fixed;
     int  fixed_width;
     int  fixed_height;
+    bool renderbg;
 };
 
 static int SubpictureTextValidate(subpicture_t *subpic,
@@ -60,6 +61,7 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
     r->psz_text = sys->text ? strdup(sys->text) : NULL;
     r->psz_html = sys->html ? strdup(sys->html) : NULL;
     r->i_align  = sys->align;
+    r->b_renderbg = sys->renderbg;
     if (!sys->is_fixed) {
         const float margin_ratio = 0.04;
         const int   margin_h     = margin_ratio * fmt_dst->i_visible_width;
diff --git a/modules/text_renderer/freetype.c b/modules/text_renderer/freetype.c
index d5864e3..a828a81 100644
--- a/modules/text_renderer/freetype.c
+++ b/modules/text_renderer/freetype.c
@@ -301,6 +301,7 @@ struct line_desc_t
     line_desc_t      *p_next;
 
     int              i_width;
+    int              i_height;
     int              i_base_line;
     int              i_character_count;
     line_character_t *p_character;
@@ -1059,6 +1060,95 @@ static inline void BlendAXYZLine( picture_t *p_picture,
     }
 }
 
+static inline void RenderBackground( filter_t *p_filter,
+                                     subpicture_region_t *p_region,
+                                     line_desc_t *p_line_head,
+                                     FT_BBox *p_bbox,
+                                     int i_margin,
+                                     picture_t *p_picture,
+                                     int i_text_width,
+                                     void (*ExtractComponents)( uint32_t, uint8_t *, uint8_t *, uint8_t * ),
+                                     void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) )
+{
+    uint8_t i_x, i_y, i_z;
+    
+    for( line_desc_t *p_line = p_line_head; p_line != NULL; p_line = p_line->p_next )
+    {
+        int i_align_left = i_margin;
+        int i_align_top = i_margin;
+        int line_start = 0;
+        int line_end = 0;
+        int line_top = 0;
+        int line_bottom = 0;
+        int max_height = 0;
+            
+        if( p_line->i_width < i_text_width )
+        {
+            /* Left offset to take into account alignment */
+            if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT )
+                i_align_left += ( i_text_width - p_line->i_width );
+            else if( (p_region->i_align & 0x10) == SUBPICTURE_ALIGN_LEAVETEXT)
+                i_align_left = i_margin; /* Keep it the way it is */
+            else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT )
+                i_align_left += ( i_text_width - p_line->i_width ) / 2;
+        }
+
+        /* Find the tallest character in the line */
+        for( int i = 0; i < p_line->i_character_count; i++ ) {
+            const line_character_t *ch = &p_line->p_character[i];
+            FT_BitmapGlyph p_glyph = ch->p_outline ? ch->p_outline : ch->p_glyph;
+            if (p_glyph->top > max_height)
+                max_height = p_glyph->top;
+        }
+        
+        /* Compute the background for the line (identify leading/trailing space) */
+        for( int i = 0; i < p_line->i_character_count; i++ ) {
+            const line_character_t *ch = &p_line->p_character[i];
+            FT_BitmapGlyph p_glyph = ch->p_outline ? ch->p_outline : ch->p_glyph;
+            if (p_glyph && p_glyph->bitmap.rows > 0) {
+                // Found a non-whitespace character
+                line_start = i_align_left + p_glyph->left - p_bbox->xMin;
+                break;
+            }
+        }
+
+        /* Fudge factor to make sure caption background edges are left aligned
+           despite variable font width */
+        if (line_start < 12)
+            line_start = 0;
+
+        /* Find right boundary for bounding box for background */
+        for( int i = p_line->i_character_count; i > 0; i-- ) {
+            const line_character_t *ch = &p_line->p_character[i - 1];
+            FT_BitmapGlyph p_glyph = ch->p_shadow ? ch->p_shadow : ch->p_glyph;
+            if (p_glyph && p_glyph->bitmap.rows > 0) {
+                // Found a non-whitespace character
+                line_end = i_align_left + p_glyph->left - p_bbox->xMin + p_glyph->bitmap.width;
+                break;
+            }
+        }
+
+        /* Setup color for the background */
+        ExtractComponents( 0x000000, &i_x, &i_y, &i_z );
+
+        /* Compute the upper boundary for the background */
+        if ((i_align_top + p_line->i_base_line - max_height) < 0)
+            line_top = i_align_top + p_line->i_base_line;
+        else
+            line_top = i_align_top + p_line->i_base_line - max_height;
+
+        /* Compute lower boundary for the background */
+        line_bottom =  __MIN(line_top + p_line->i_height, p_region->fmt.i_visible_height);
+
+        /* Render the actual background */
+        for( int dy = line_top; dy < line_bottom; dy++ )
+        {
+            for( int dx = line_start; dx < line_end; dx++ )
+                BlendPixel( p_picture, dx, dy, 0xff, i_x, i_y, i_z, 0xff );
+        }
+    }
+}
+
 static inline int RenderAXYZ( filter_t *p_filter,
                               subpicture_region_t *p_region,
                               line_desc_t *p_line_head,
@@ -1093,6 +1183,11 @@ static inline int RenderAXYZ( filter_t *p_filter,
 
     FillPicture( p_picture, i_a, i_x, i_y, i_z );
 
+    if (p_region->b_renderbg) {
+        RenderBackground(p_filter, p_region, p_line_head, p_bbox, i_margin, p_picture, i_text_width,
+                         ExtractComponents, BlendPixel);
+    }
+    
     /* Render shadow then outline and then normal glyphs */
     for( int g = 0; g < 3; g++ )
     {
@@ -2411,6 +2506,7 @@ static int ProcessLines( filter_t *p_filter,
         {
             p_line->i_width  = __MAX(line_bbox.xMax - line_bbox.xMin, 0);
             p_line->i_base_line = i_base_line;
+            p_line->i_height = __MAX(i_face_height, i_face_height_previous);
             if( i_ul_thickness > 0 )
             {
                 for( int i = 0; i < p_line->i_character_count; i++ )
-- 
1.7.9.5




More information about the vlc-devel mailing list