]> git.sesse.net Git - vlc/commitdiff
Add support for rendering EIA-608 captions with a black background
authorDevin Heitmueller <dheitmueller@kernellabs.com>
Wed, 2 Jan 2013 16:45:11 +0000 (11:45 -0500)
committerRafaël Carré <funman@videolan.org>
Thu, 10 Jan 2013 20:58:13 +0000 (21:58 +0100)
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.

Signed-off-by: Rafaël Carré <funman@videolan.org>
include/vlc_subpicture.h
modules/codec/cc.c
modules/codec/substext.h
modules/text_renderer/freetype.c

index d98e043f6eb90623944ec0cba840cc74a061d23d..6bfede171002b78b80c7635e87fdd51ea7d15ea4 100644 (file)
@@ -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* */
index 75dae6b5305df9d65ca4cb313e2859206c1fe249..8863f1c6f5aa40afc37aa01b45729bc9251ab96c 100644 (file)
@@ -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 = true;
 
     return p_spu;
 }
index 68e6c6139c9e17864b5b57e01f19e64d0576de0d..fe5df95350e3ac0cb4ccdbb4d5aa2dcd17939026 100644 (file)
@@ -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;
index d5864e373edc9bb20582ed91aa8d98ed0ef482da..5070462038b5bca88b7160497ee7ee7ec8cfa772 100644 (file)
@@ -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,93 @@ static inline void BlendAXYZLine( picture_t *p_picture,
     }
 }
 
+static inline void RenderBackground( 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) )
+{
+    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;
+        unsigned 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 */
+        uint8_t i_x, i_y, i_z;
+        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 +1181,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_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++ )
     {
@@ -1105,7 +1198,7 @@ static inline int RenderAXYZ( filter_t *p_filter,
                 /* 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)
+                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;
@@ -2411,6 +2504,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++ )