[vlc-commits] text_renderer: svg: rework

Francois Cartegnie git at videolan.org
Thu Dec 29 20:41:46 CET 2016


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Dec 29 15:55:20 2016 +0100| [ad76af9b57ac6e9ab1cf9354b67cb7ca6c7377d3] | committer: Francois Cartegnie

text_renderer: svg: rework

Drops legacy code, local chroma conversion.
Shrinks regions instead of fixed size/viewport.
Allows multiline.
Fixes unsafe template.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ad76af9b57ac6e9ab1cf9354b67cb7ca6c7377d3
---

 modules/text_renderer/svg.c | 569 ++++++++++++++++++--------------------------
 1 file changed, 227 insertions(+), 342 deletions(-)

diff --git a/modules/text_renderer/svg.c b/modules/text_renderer/svg.c
index 3e96891..71fe7e5 100644
--- a/modules/text_renderer/svg.c
+++ b/modules/text_renderer/svg.c
@@ -34,6 +34,7 @@
 #include <vlc_fs.h>
 #include <vlc_filter.h>
 #include <vlc_subpicture.h>
+#include <vlc_strings.h>
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -42,8 +43,7 @@
 #include <glib/gstdio.h>
 #include <glib-object.h>                                  /* g_object_unref( ) */
 #include <librsvg/rsvg.h>
-
-typedef struct svg_rendition_t svg_rendition_t;
+#include <cairo/cairo.h>
 
 /*****************************************************************************
  * Local prototypes
@@ -53,12 +53,20 @@ static void Destroy   ( vlc_object_t * );
 static int  RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
                         subpicture_region_t *p_region_in,
                         const vlc_fourcc_t * );
-static char *svg_GetTemplate( vlc_object_t *p_this );
+
+struct filter_sys_t
+{
+    char *psz_file_template;
+    const char *psz_token;
+};
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 
+#define SVG_TEMPLATE_BODY_TOKEN   "<!--$SVGBODY$-->"
+#define SVG_TEMPLATE_BODY_TOKEN_L 16
+
 #define TEMPLATE_TEXT N_( "SVG template file" )
 #define TEMPLATE_LONGTEXT N_( "Location of a file holding a SVG template "\
         "for automatic string conversion" )
@@ -72,441 +80,318 @@ vlc_module_begin ()
     set_callbacks( Create, Destroy )
 vlc_module_end ()
 
-/**
-   Describes a SVG string to be displayed on the video
-*/
-struct svg_rendition_t
-{
-    int            i_width;
-    int            i_height;
-    int            i_chroma;
-    /** The SVG source associated with this subpicture */
-    char           *psz_text;
-    /* The rendered SVG, as a GdkPixbuf */
-    GdkPixbuf      *p_rendition;
-};
-
-static int Render( filter_t *, subpicture_region_t *, svg_rendition_t *, int, int);
-static char *svg_GetTemplate ();
-static void svg_set_size( filter_t *p_filter, int width, int height );
-static void svg_SizeCallback  ( int *width, int *height, gpointer data );
-static void svg_RenderPicture ( filter_t *p_filter,
-                                svg_rendition_t *p_svg );
-static void FreeString( svg_rendition_t * );
-
-/*****************************************************************************
- * filter_sys_t: svg local data
- *****************************************************************************
- * This structure is part of the filter thread descriptor.
- * It describes the svg specific properties of an output thread.
- *****************************************************************************/
-struct filter_sys_t
-{
-    /* The SVG template used to convert strings */
-    char          *psz_template;
-    /* Default size for rendering. Initialized to the output size. */
-    int            i_width;
-    int            i_height;
-};
-
-/*****************************************************************************
- * Create: allocates svg video thread output method
- *****************************************************************************
- * This function allocates and initializes a  vout method.
- *****************************************************************************/
-static int Create( vlc_object_t *p_this )
-{
-    filter_t *p_filter = ( filter_t * )p_this;
-    filter_sys_t *p_sys;
-
-    /* Allocate structure */
-    p_sys = malloc( sizeof( filter_sys_t ) );
-    if( !p_sys )
-        return VLC_ENOMEM;
-
-    /* Initialize psz_template */
-    p_sys->psz_template = svg_GetTemplate( p_this );
-    if( !p_sys->psz_template )
-    {
-        free( p_sys );
-        return VLC_ENOMEM;
-    }
-
-    p_sys->i_width = p_filter->fmt_out.video.i_width;
-    p_sys->i_height = p_filter->fmt_out.video.i_height;
-
-    p_filter->pf_render = RenderText;
-    p_filter->p_sys = p_sys;
-
-    /* MUST call this before any RSVG funcs */
-    rsvg_init( );
-
-    return VLC_SUCCESS;
-}
+static void svg_RescaletoFit  ( filter_t *, int *width, int *height, float * );
+static picture_t * svg_RenderPicture ( filter_t *p_filter, const char * );
 
-static char *svg_GetTemplate( vlc_object_t *p_this )
+static void svg_LoadTemplate( filter_t *p_filter )
 {
-    filter_t *p_filter = ( filter_t * )p_this;
-    char *psz_filename;
-    char *psz_template;
-    FILE *file;
-
-    psz_filename = var_InheritString( p_filter, "svg-template-file" );
-    if( !psz_filename || (psz_filename[0] == 0) )
-    {
-        /* No filename. Use a default value. */
-        psz_template = NULL;
-    }
-    else
+    filter_sys_t *p_sys = p_filter->p_sys;
+    char *psz_template = NULL;
+    char *psz_filename = var_InheritString( p_filter, "svg-template-file" );
+    if( psz_filename && psz_filename[0] )
     {
         /* Read the template */
-        file = vlc_fopen( psz_filename, "rt" );
+        FILE *file = vlc_fopen( psz_filename, "rt" );
         if( !file )
         {
-            msg_Warn( p_this, "SVG template file %s does not exist.",
+            msg_Warn( p_filter, "SVG template file %s does not exist.",
                                          psz_filename );
-            psz_template = NULL;
         }
         else
         {
             struct stat s;
-
-            if( fstat( fileno( file ), &s ) )
-            {
-                /* Problem accessing file information. Should not
-                   happen as we could open it. */
-                psz_template = NULL;
-            }
-            else
-            if( ((signed)s.st_size) < 0 )
+            if( fstat( fileno( file ), &s ) || ((signed)s.st_size) < 0 )
             {
-                msg_Err( p_this, "SVG template too big" );
-                psz_template = NULL;
+                msg_Err( p_filter, "SVG template invalid" );
             }
             else
             {
-                msg_Dbg( p_this, "reading %ld bytes from template %s",
+                msg_Dbg( p_filter, "reading %ld bytes from template %s",
                          (unsigned long)s.st_size, psz_filename );
 
-                psz_template = calloc( 1, s.st_size + 42 );
-                if( !psz_template )
-                {
-                    fclose( file );
-                    free( psz_filename );
-                    return NULL;
-                }
-                if(! fread( psz_template, s.st_size, 1, file ) )
+                psz_template = malloc( s.st_size + 1 );
+                if( psz_template )
                 {
-                    msg_Dbg( p_this, "No data read from template." );
+                    psz_template[ s.st_size ] = 0;
+                    ssize_t i_read = fread( psz_template, s.st_size, 1, file );
+                    if( i_read != 1 )
+                    {
+                        free( psz_template );
+                        psz_template = NULL;
+                    }
                 }
             }
             fclose( file );
         }
     }
     free( psz_filename );
-    if( !psz_template )
+
+    if( psz_template )
     {
-        /* Either there was no file, or there was an error.
-           Use the default value */
-        psz_template = strdup( "<?xml version='1.0' encoding='UTF-8' standalone='no'?> \
-<svg version='1' preserveAspectRatio='xMinYMin meet' viewBox='0 0 800 600'> \
-  <text x='10' y='560' fill='white' font-size='32'  \
-        font-family='sans-serif'>%s</text></svg>" );
+        p_sys->psz_token = strstr( psz_template, SVG_TEMPLATE_BODY_TOKEN );
+        if( !p_sys->psz_token )
+        {
+            msg_Err( p_filter, "'%s' not found in SVG template", SVG_TEMPLATE_BODY_TOKEN );
+            free( psz_template );
+        }
+        else *((char*)p_sys->psz_token) = 0;
     }
 
-    return psz_template;
+    p_sys->psz_file_template = psz_template;
 }
 
-/*****************************************************************************
- * Destroy: destroy Clone video thread output method
- *****************************************************************************
- * Clean up all data and library connections
- *****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
+static char *svg_GetDocument( filter_t *p_filter, int i_width, int i_height, const char *psz_body )
 {
-    filter_t *p_filter = ( filter_t * )p_this;
     filter_sys_t *p_sys = p_filter->p_sys;
+    char *psz_result;
+    VLC_UNUSED(i_width);VLC_UNUSED(i_height);
 
-    free( p_sys->psz_template );
-    free( p_sys );
-    rsvg_term( );
-}
-
-/*****************************************************************************
- * Render: render SVG in picture
- *****************************************************************************/
-static int Render( filter_t *p_filter, subpicture_region_t *p_region,
-                   svg_rendition_t *p_svg, int i_width, int i_height )
-{
-    video_format_t fmt;
-    uint8_t *p_y, *p_u, *p_v, *p_a;
-    int x, y, i_pitch, i_u_pitch;
-    guchar *pixels_in = NULL;
-    int rowstride_in;
-    int channels_in;
-    int alpha;
-    picture_t *p_pic;
-
-    if ( p_filter->p_sys->i_width != i_width ||
-         p_filter->p_sys->i_height != i_height )
+    if( p_sys->psz_file_template )
     {
-        svg_set_size( p_filter, i_width, i_height );
-        p_svg->p_rendition = NULL;
-    }
-
-    if( p_svg->p_rendition == NULL ) {
-        svg_RenderPicture( p_filter, p_svg );
-        if( ! p_svg->p_rendition )
-        {
-            msg_Err( p_filter, "Cannot render SVG" );
-            return VLC_EGENERIC;
-        }
-    }
-    i_width = gdk_pixbuf_get_width( p_svg->p_rendition );
-    i_height = gdk_pixbuf_get_height( p_svg->p_rendition );
-
-    if( gdk_pixbuf_get_colorspace( p_svg->p_rendition ) != GDK_COLORSPACE_RGB ||
-        gdk_pixbuf_get_has_alpha( p_svg->p_rendition ) != TRUE ||
-        gdk_pixbuf_get_bits_per_sample( p_svg->p_rendition ) != 8 )
-    {
-        g_object_unref( p_svg->p_rendition );
-        p_svg->p_rendition = NULL;
-        msg_Err( p_filter, "Unsupported colorspace" );
-        return VLC_EGENERIC;
+        if( asprintf( &psz_result, "%s%s%s",
+                      p_sys->psz_file_template,
+                      psz_body,
+                      &p_sys->psz_token[SVG_TEMPLATE_BODY_TOKEN_L] ) < 0 )
+            psz_result = NULL;
     }
-
-    /* Create a new subpicture region */
-    video_format_Init( &fmt, VLC_CODEC_YUVA );
-    fmt.i_width = fmt.i_visible_width = i_width;
-    fmt.i_height = fmt.i_visible_height = i_height;
-
-    p_region->p_picture = picture_NewFromFormat( &fmt );
-    if( !p_region->p_picture )
+    else
     {
-        video_format_Clean( &fmt );
-        return VLC_EGENERIC;
+        /* Either there was no file, or there was an error.
+           Use the default value */
+        const char *psz_temp = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>"
+                    "<svg preserveAspectRatio='xMinYMin meet'>" // viewBox='0 0 %d %d'>"
+                    "<rect fill='none' width='100%%' height='100%%'></rect>"
+                    "<text fill='white' font-family='sans-serif' font-size='32px'>%s</text>"
+                    "</svg>";
+        if( asprintf( &psz_result, psz_temp, /*i_width, i_height,*/ psz_body ) < 0 )
+            psz_result = NULL;
     }
-    video_format_Clean( &p_region->fmt );
-    video_format_Init( &p_region->fmt, 0 );
-    video_format_Copy( &p_region->fmt, &fmt );
-
-    p_region->i_x = p_region->i_y = 0;
-    p_y = p_region->p_picture->Y_PIXELS;
-    p_u = p_region->p_picture->U_PIXELS;
-    p_v = p_region->p_picture->V_PIXELS;
-    p_a = p_region->p_picture->A_PIXELS;
-
-    i_pitch = p_region->p_picture->Y_PITCH;
-    i_u_pitch = p_region->p_picture->U_PITCH;
 
-    /* Initialize the region pixels (only the alpha will be changed later) */
-    memset( p_y, 0x00, i_pitch * p_region->fmt.i_height );
-    memset( p_u, 0x80, i_u_pitch * p_region->fmt.i_height );
-    memset( p_v, 0x80, i_u_pitch * p_region->fmt.i_height );
-
-    p_pic = p_region->p_picture;
-
-    /* Copy the data */
-
-    /* This rendering code is in no way optimized. If someone has some time to
-       make it work faster or better, please do.
-    */
-
-    /*
-      p_pixbuf->get_rowstride() is the number of bytes in a line.
-      p_pixbuf->get_height() is the number of lines.
-
-      The number of bytes of p_pixbuf->p_pixels is get_rowstride * get_height
-
-      if( has_alpha() ) {
-      alpha = pixels [ n_channels * ( y*rowstride + x ) + 3 ];
-      }
-      red   = pixels [ n_channels * ( y*rowstride ) + x ) ];
-      green = pixels [ n_channels * ( y*rowstride ) + x ) + 1 ];
-      blue  = pixels [ n_channels * ( y*rowstride ) + x ) + 2 ];
-    */
-
-    pixels_in = gdk_pixbuf_get_pixels( p_svg->p_rendition );
-    rowstride_in = gdk_pixbuf_get_rowstride( p_svg->p_rendition );
-    channels_in = gdk_pixbuf_get_n_channels( p_svg->p_rendition );
-    alpha = gdk_pixbuf_get_has_alpha( p_svg->p_rendition );
-
-    /*
-      This crashes the plugin (if !alpha). As there is always an alpha value,
-      it does not matter for the moment :
-
-    if( !alpha )
-      memset( p_a, 0xFF, i_pitch * p_region->fmt.i_height );
-    */
-
-#define INDEX_IN( x, y ) ( y * rowstride_in + x * channels_in )
-#define INDEX_OUT( x, y ) ( y * i_pitch + x * p_pic->p[Y_PLANE].i_pixel_pitch )
-
-    for( y = 0; y < i_height; y++ )
-    {
-        for( x = 0; x < i_width; x++ )
-        {
-            guchar *p_in;
-            int i_out;
-
-            p_in = &pixels_in[INDEX_IN( x, y )];
+    return psz_result;
+}
 
-#define R( pixel ) *pixel
-#define G( pixel ) *( pixel+1 )
-#define B( pixel ) *( pixel+2 )
-#define ALPHA( pixel ) *( pixel+3 )
+/*****************************************************************************
+ * Create: allocates svg video thread output method
+ *****************************************************************************
+ * This function allocates and initializes a  vout method.
+ *****************************************************************************/
 
-            /* From http://www.geocrawler.com/archives/3/8263/2001/6/0/6020594/ :
-               Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
-               U = -0.1687 * r  - 0.3313 * g + 0.5 * b + 128
-               V = 0.5   * r - 0.4187 * g - 0.0813 * b + 128
-            */
-            if ( alpha ) {
-                i_out = INDEX_OUT( x, y );
+static int Create( vlc_object_t *p_this )
+{
+    filter_t *p_filter = ( filter_t * )p_this;
 
-                p_pic->Y_PIXELS[i_out] = .299 * R( p_in ) + .587 * G( p_in ) + .114 * B( p_in );
+    p_filter->p_sys = calloc( 1, sizeof(*p_filter->p_sys) );
+    if( !p_filter->p_sys )
+        return VLC_ENOMEM;
 
-                p_pic->U_PIXELS[i_out] = -.1687 * R( p_in ) - .3313 * G( p_in ) + .5 * B( p_in ) + 128;
-                p_pic->V_PIXELS[i_out] = .5 * R( p_in ) - .4187 * G( p_in ) - .0813 * B( p_in ) + 128;
+    p_filter->pf_render = RenderText;
+    svg_LoadTemplate( p_filter );
 
-                p_pic->A_PIXELS[i_out] = ALPHA( p_in );
-            }
-        }
-    }
+#if (GLIB_MAJOR_VERSION < 2 || GLIB_MINOR_VERSION < 36)
+    g_type_init( );
+#endif
 
     return VLC_SUCCESS;
 }
 
-static void svg_set_size( filter_t *p_filter, int width, int height )
+/*****************************************************************************
+ * Destroy: destroy Clone video thread output method
+ *****************************************************************************
+ * Clean up all data and library connections
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
 {
-  p_filter->p_sys->i_width = width;
-  p_filter->p_sys->i_height = height;
+    filter_t *p_filter = ( filter_t * )p_this;
+#if (GLIB_MAJOR_VERSION < 2 || GLIB_MINOR_VERSION < 36)
+    rsvg_term();
+#endif
+    free( p_filter->p_sys->psz_file_template );
+    free( p_filter->p_sys );
 }
 
-static void svg_SizeCallback( int *width, int *height, gpointer data )
+static void svg_RescaletoFit( filter_t *p_filter, int *width, int *height, float *scale )
 {
-    filter_t *p_filter = data;
+    *scale = 1.0;
+
+    if( *width > 0 && *height > 0 )
+    {
+        if( (unsigned)*width > p_filter->fmt_out.video.i_visible_width )
+            *scale = (1.0 * p_filter->fmt_out.video.i_visible_width / *width);
 
-    *width = p_filter->p_sys->i_width;
-    *height = p_filter->p_sys->i_height;
-    return;
+        if( (unsigned)*height > p_filter->fmt_out.video.i_visible_height )
+        {
+            float y_scale = (1.0 * p_filter->fmt_out.video.i_visible_height / *height);
+            if( y_scale < *scale )
+                *scale = y_scale;
+        }
+
+        *width *= *scale;
+        *height *= *scale;
+    }
 }
 
-static void svg_RenderPicture( filter_t *p_filter,
-                               svg_rendition_t *p_svg )
+static picture_t * svg_RenderPicture( filter_t *p_filter,
+                                      const char *psz_svgdata )
 {
-    /* Render the SVG string p_string->psz_text into a new picture_t
-       p_string->p_rendition with dimensions ( ->i_width, ->i_height ) */
     RsvgHandle *p_handle;
     GError *error = NULL;
 
-    p_svg->p_rendition = NULL;
-
-    p_handle = rsvg_handle_new();
-
+    p_handle = rsvg_handle_new_from_data( (const guint8 *)psz_svgdata,
+                                          strlen( psz_svgdata ), &error );
     if( !p_handle )
     {
-        msg_Err( p_filter, "Error creating SVG reader" );
-        return;
+        msg_Err( p_filter, "error while rendering SVG: %s", error->message );
+        return NULL;
     }
 
-    rsvg_handle_set_size_callback( p_handle, svg_SizeCallback, p_filter, NULL );
+    RsvgDimensionData dim;
+    rsvg_handle_get_dimensions( p_handle, &dim );
+    float scale;
+    svg_RescaletoFit( p_filter, &dim.width, &dim.height, &scale );
 
-    if( ! rsvg_handle_write( p_handle,
-                 ( guchar* )p_svg->psz_text, strlen( p_svg->psz_text ),
-                 &error ) )
+    /* Create a new subpicture region */
+    video_format_t fmt;
+    video_format_Init( &fmt, VLC_CODEC_BGRA ); /* CAIRO_FORMAT_ARGB32 == VLC_CODEC_BGRA, go figure */
+    fmt.i_bits_per_pixel = 32;
+    fmt.i_chroma = VLC_CODEC_BGRA;
+    fmt.i_width = fmt.i_visible_width = dim.width;
+    fmt.i_height = fmt.i_visible_height = dim.height;
+
+    picture_t *p_picture = picture_NewFromFormat( &fmt );
+    if( !p_picture )
+    {
+        video_format_Clean( &fmt );
+        g_object_unref( G_OBJECT( p_handle ) );
+        return NULL;
+    }
+    memset( p_picture->p[0].p_pixels, 0x00, p_picture->p[0].i_pitch * p_picture->p[0].i_lines );
+
+    cairo_surface_t* surface = cairo_image_surface_create_for_data( p_picture->p->p_pixels,
+                                                                    CAIRO_FORMAT_ARGB32,
+                                                                    fmt.i_width, fmt.i_height,
+                                                                    p_picture->p[0].i_pitch );
+    if( !surface )
     {
-        msg_Err( p_filter, "error while rendering SVG: %s", error->message );
         g_object_unref( G_OBJECT( p_handle ) );
-        return;
+        picture_Release( p_picture );
+        return NULL;
     }
 
-    if( ! rsvg_handle_close( p_handle, &error ) )
+    cairo_t *cr = cairo_create( surface );
+    if( !cr )
     {
-        msg_Err( p_filter, "error while rendering SVG (close): %s", error->message );
+        msg_Err( p_filter, "error while creating cairo surface" );
+        cairo_surface_destroy( surface );
         g_object_unref( G_OBJECT( p_handle ) );
-        return;
+        picture_Release( p_picture );
+        return NULL;
     }
 
-    p_svg->p_rendition = rsvg_handle_get_pixbuf( p_handle );
+    if( ! rsvg_handle_render_cairo( p_handle, cr ) )
+    {
+        msg_Err( p_filter, "error while rendering SVG" );
+        cairo_destroy( cr );
+        cairo_surface_destroy( surface );
+        g_object_unref( G_OBJECT( p_handle ) );
+        picture_Release( p_picture );
+        return NULL;
+    }
 
+    cairo_destroy( cr );
+    cairo_surface_destroy( surface );
     g_object_unref( G_OBJECT( p_handle ) );
+
+    return p_picture;
 }
 
+static char * SegmentsToSVG( text_segment_t *p_segment, int i_height, int *pi_total_size )
+{
+    char *psz_result = NULL;
+
+    i_height = 6 * i_height / 100;
+    *pi_total_size = 0;
+
+    for( ; p_segment; p_segment = p_segment->p_next )
+    {
+        char *psz_prev = psz_result;
+        char *psz_encoded = vlc_xml_encode( p_segment->psz_text );
+        if( asprintf( &psz_result, "%s<tspan x='0' dy='%upx'>%s</tspan>\n",
+                                   (psz_prev) ? psz_prev : "",
+                                    i_height,
+                                    psz_encoded ) < 0 )
+            psz_result = NULL;
+        free( psz_prev );
+        free( psz_encoded );
+
+        *pi_total_size += i_height;
+    }
+
+    return psz_result;
+}
 
 static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
                        subpicture_region_t *p_region_in,
                        const vlc_fourcc_t *p_chroma_list )
 {
-    VLC_UNUSED(p_chroma_list);
-
-    filter_sys_t *p_sys = p_filter->p_sys;
-    svg_rendition_t *p_svg = NULL;
-    char *psz_string;
-
     /* Sanity check */
-    if( !p_region_in || !p_region_out ) return VLC_EGENERIC;
-    if( !p_region_in->p_text ) return VLC_EGENERIC;
-    //FIXME: What should we do when there's more than a single segment?
-    //Is this refused at codec level?
-    psz_string = p_region_in->p_text->psz_text;
-    if( !psz_string || !*psz_string ) return VLC_EGENERIC;
-
-    p_svg = malloc( sizeof( svg_rendition_t ) );
-    if( !p_svg )
-        return VLC_ENOMEM;
+    if( !p_region_in || !p_region_out || !p_region_in->p_text )
+        return VLC_EGENERIC;
+
+    for( size_t i=0; p_chroma_list[i]; i++ )
+    {
+        if( p_chroma_list[i] == VLC_CODEC_BGRA )
+            break;
+        if( p_chroma_list[i] == 0 )
+            return VLC_EGENERIC;
+    }
 
     p_region_out->i_x = p_region_in->i_x;
     p_region_out->i_y = p_region_in->i_y;
 
+    unsigned i_width = p_filter->fmt_out.video.i_visible_width;
+    if( (unsigned) p_region_out->i_x <= i_width )
+        i_width -= p_region_out->i_x;
+
+    unsigned i_height = p_filter->fmt_out.video.i_visible_height;
+    if( (unsigned) p_region_out->i_y <= i_height )
+        i_height -= p_region_out->i_y;
+
+    if( i_height == 0 || i_width == 0 )
+        return VLC_EGENERIC;
+
+    char *psz_svg;
     /* Check if the data is SVG or pure text. In the latter case,
        convert the text to SVG. FIXME: find a better test */
-    if( strstr( psz_string, "<svg" ))
+    if( p_region_in->p_text && strstr( p_region_in->p_text->psz_text, "<svg" ) )
     {
-        /* Data is SVG: duplicate */
-        p_svg->psz_text = strdup( psz_string );
-        if( !p_svg->psz_text )
-        {
-            free( p_svg );
-            return VLC_ENOMEM;
-        }
+        psz_svg = strdup( p_region_in->p_text->psz_text );
     }
     else
     {
         /* Data is text. Convert to SVG */
-        /* FIXME: handle p_style attributes */
-        int length;
-        char* psz_template = p_sys->psz_template;
-        length = strlen( psz_string ) + strlen( psz_template ) + 42;
-        p_svg->psz_text = calloc( 1, length + 1 );
-        if( !p_svg->psz_text )
+        int i_total;
+        psz_svg = SegmentsToSVG( p_region_in->p_text, i_height, &i_total );
+        if( psz_svg )
         {
-            free( p_svg );
-            return VLC_ENOMEM;
+            char *psz_doc = svg_GetDocument( p_filter, i_width, i_total, psz_svg );
+            free( psz_svg );
+            psz_svg = psz_doc;
         }
-        snprintf( p_svg->psz_text, length, psz_template, psz_string );
     }
-    p_svg->i_width = p_sys->i_width = p_filter->fmt_out.video.i_width;
-    p_svg->i_height = p_sys->i_height = p_filter->fmt_out.video.i_height;
-    p_svg->i_chroma = VLC_CODEC_YUVA;
 
-    /* Render the SVG.
-       The input data is stored in the p_string structure,
-       and the function updates the p_rendition attribute. */
-    svg_RenderPicture( p_filter, p_svg );
+    if( !psz_svg )
+        return VLC_EGENERIC;
 
-    Render( p_filter, p_region_out, p_svg, p_svg->i_width, p_svg->i_height );
-    FreeString( p_svg );
+    picture_t *p_picture = svg_RenderPicture( p_filter, psz_svg );
 
-    return VLC_SUCCESS;
-}
+    free( psz_svg );
 
-static void FreeString( svg_rendition_t *p_svg )
-{
-    free( p_svg->psz_text );
-    /* p_svg->p_rendition is a GdkPixbuf, and its allocation is
-       managed through ref. counting */
-    if( p_svg->p_rendition )
-        g_object_unref( p_svg->p_rendition );
-    free( p_svg );
+    if (p_picture)
+    {
+        p_region_out->p_picture = p_picture;
+        video_format_Clean( &p_region_out->fmt );
+        video_format_Copy( &p_region_out->fmt, &p_picture->format );
+        return VLC_SUCCESS;
+    }
+    return VLC_EGENERIC;
 }



More information about the vlc-commits mailing list