Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  svg.c   Sprache: C

 

/*****************************************************************************
 * svg.c : Put SVG on the video
 *****************************************************************************
 * Copyright (C) 2002, 2003 VLC authors and VideoLAN
 *
 * Authors: Olivier Aubert <oaubert@lisi.univ-lyon1.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option ) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_fs.h>
#include <vlc_filter.h>
#include <vlc_subpicture.h>
#include <vlc_strings.h>

#include <sys/types.h>
#include <math.h>
#include <unistd.h>

#include <glib.h>
#include <glib/gstdio.h>
#include <glib-object.h>                                  /* g_object_unref( ) */
#include <vlc_memstream.h>
#include <librsvg/rsvg.h>
#include <cairo.h>

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

static int  Create    ( filter_t * );
static void Destroy   ( filter_t * );
static subpicture_region_t *RenderText( filter_t *p_filter,
                        const subpicture_region_t *p_region_in,
                        const vlc_fourcc_t * );

typedef struct
{
    char *psz_file_template;
    const char *psz_token;
} filter_sys_t;

/*****************************************************************************
 * 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" )

vlc_module_begin ()
    set_subcategory( SUBCAT_INPUT_SCODEC )
    add_shortcut( "svg" )
    add_string( "svg-template-file", "", TEMPLATE_TEXT, TEMPLATE_LONGTEXT )
    set_callback_text_renderer( Create, 99 )
vlc_module_end ()

static void svg_RescaletoFit (filter_t *, double *width, double *height);
static picture_t * svg_RenderPicture ( filter_t *p_filter, const char * );

static void svg_LoadTemplate( filter_t *p_filter )
{
    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 *file = vlc_fopen( psz_filename, "rt" );
        if( !file )
        {
            msg_Warn( p_filter, "SVG template file %s does not exist.",
                                         psz_filename );
        }
        else
        {
            struct stat s;
            if( fstat( fileno( file ), &s ) || ((signed)s.st_size) < 0 )
            {
                msg_Err( p_filter, "SVG template invalid" );
            }
            else
            {
                msg_Dbg( p_filter, "reading %ld bytes from template %s",
                         (unsigned long)s.st_size, psz_filename );

                psz_template = malloc( s.st_size + 1 );
                if( psz_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 )
    {
        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 );
     psz_template = NULL;
        }
        else *((char*)p_sys->psz_token) = 0;
    }

    p_sys->psz_file_template = psz_template;
}

static char *svg_GetDocument( filter_t *p_filter, int i_width, int i_height, const char *psz_body )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    char *psz_result;
    VLC_UNUSED(i_width);VLC_UNUSED(i_height);

    if( p_sys->psz_file_template )
    {
        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;
    }
    else
    {
        /* 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;
    }

    return psz_result;
}

static const struct vlc_filter_operations filter_ops = {
    .render = RenderText, .close = Destroy,
};

/*****************************************************************************
 * Create: allocates svg video thread output method
 *****************************************************************************
 * This function allocates and initializes a  vout method.
 *****************************************************************************/


static int Create( filter_t *p_filter )
{
    filter_sys_t *p_sys = calloc( 1, sizeof(*p_sys) );
    if( !p_sys )
        return VLC_ENOMEM;
    p_filter->p_sys = p_sys;

    p_filter->ops = &filter_ops;
    svg_LoadTemplate( p_filter );

#if (GLIB_MAJOR_VERSION < 2 || GLIB_MINOR_VERSION < 36)
    g_type_init( );
#endif

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Destroy: destroy Clone video thread output method
 *****************************************************************************
 * Clean up all data and library connections
 *****************************************************************************/

static void Destroy( filter_t *p_filter )
{
    filter_sys_t *p_sys = p_filter->p_sys;
#if (GLIB_MAJOR_VERSION < 2 || GLIB_MINOR_VERSION < 36)
    rsvg_term();
#endif
    free( p_sys->psz_file_template );
    free( p_sys );
}

static void svg_RescaletoFit(filter_t *p_filter, double *width, double *height)
{
    double scale = 1.0;

    if( *width > 0 && *height > 0 )
    {
        if( (unsigned)*width > p_filter->fmt_out.video.i_visible_width )
            scale = ((double)p_filter->fmt_out.video.i_visible_width / *width);

        if( (unsigned)*height > p_filter->fmt_out.video.i_visible_height )
        {
            double y_scale = ((double)p_filter->fmt_out.video.i_visible_height / *height);
            if( y_scale < scale )
                scale = y_scale;
        }

        *width *= scale;
        *height *= scale;
    }
}

static bool svg_GetDimensionsInPixels( RsvgHandle *handle, double *width, double *height )
{
#if LIBRSVG_CHECK_VERSION(2, 52, 0)
    RsvgRectangle outRect;
    if (!rsvg_handle_get_geometry_for_element( handle, NULL, &outRect, NULL, NULL ))
        return false;

    *width = outRect.width;
    *height = outRect.height;
    return true;
#else
    RsvgDimensionData dim;
    rsvg_handle_get_dimensions( handle, &dim );
    *width = dim.width;
    *height = dim.height;
    return true;
#endif
}

static picture_t * svg_RenderPicture( filter_t *p_filter,
                                      const char *psz_svgdata )
{
    RsvgHandle *p_handle;
    GError *error = NULL;

    p_handle = rsvg_handle_new_from_data( (const guint8 *)psz_svgdata,
                                          strlen( psz_svgdata ), &error );
    if( !p_handle )
    {
        msg_Err( p_filter, "error while rendering SVG: %s", error->message );
        return NULL;
    }

    double width, height;
    if (!svg_GetDimensionsInPixels( p_handle, &width, &height )) {
        msg_Err( p_filter, "Unable to obtain SVG dimensions for rendering" );
        g_object_unref(G_OBJECT(p_handle));
        return NULL;
    }
    svg_RescaletoFit(p_filter, &width, &height);

    /* 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_chroma = VLC_CODEC_BGRA;
    fmt.i_width = fmt.i_visible_width = ceil(width);
    fmt.i_height = fmt.i_visible_height = height;
    fmt.transfer = TRANSFER_FUNC_SRGB;
    fmt.primaries = COLOR_PRIMARIES_SRGB;
    fmt.space = COLOR_SPACE_SRGB;
    fmt.color_range = COLOR_RANGE_FULL;

    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 )
    {
        g_object_unref( G_OBJECT( p_handle ) );
        picture_Release( p_picture );
        return NULL;
    }

    cairo_t *cr = cairo_create( surface );
    if( !cr )
    {
        msg_Err( p_filter, "error while creating cairo surface" );
        cairo_surface_destroy( surface );
        g_object_unref( G_OBJECT( p_handle ) );
        picture_Release( p_picture );
        return NULL;
    }

#if LIBRSVG_CHECK_VERSION(2, 46, 0)
    if ( ! rsvg_handle_render_document( p_handle, cr, &(RsvgRectangle){ .height = height, .width = width }, NULL ) )
#else
    if( ! rsvg_handle_render_cairo( p_handle, cr ) )
#endif
    {
        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 )
{
    struct vlc_memstream stream;
    vlc_memstream_open(&stream);

    i_height = 6 * i_height / 100;
    *pi_total_size = 0;

    for( ; p_segment; p_segment = p_segment->p_next )
    {
        char *psz_encoded = vlc_xml_encode( p_segment->psz_text );
        if ( !psz_encoded )
            continue;

        vlc_memstream_printf( &stream, "<tspan x='0' dy='%upx'>%s</tspan>\n",
                              i_height, psz_encoded );
        free( psz_encoded );

        *pi_total_size += i_height;
    }

    if (vlc_memstream_close( &stream ))
        return NULL;

    return stream.ptr;
}

static subpicture_region_t *RenderText( filter_t *p_filter,
                       const subpicture_region_t *p_region_in,
                       const vlc_fourcc_t *p_chroma_list )
{
    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 )
        {
            msg_Warn( p_filter, "no output chroma supported for rendering" );
            return NULL;
        }
    }

    unsigned i_width = p_filter->fmt_out.video.i_visible_width;
    if( (unsigned) p_region_in->i_x <= i_width )
        i_width -= p_region_in->i_x;

    unsigned i_height = p_filter->fmt_out.video.i_visible_height;
    if( (unsigned) p_region_in->i_y <= i_height )
        i_height -= p_region_in->i_y;

    if( i_height == 0 || i_width == 0 )
        return NULL;

    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( p_region_in->p_text->psz_text, "<svg" ) )
    {
        psz_svg = strdup( p_region_in->p_text->psz_text );
    }
    else
    {
        /* Data is text. Convert to SVG */
        int i_total;
        psz_svg = SegmentsToSVG( p_region_in->p_text, i_height, &i_total );
        if( psz_svg )
        {
            char *psz_doc = svg_GetDocument( p_filter, i_width, i_total, psz_svg );
            free( psz_svg );
            psz_svg = psz_doc;
        }
    }

    if( !psz_svg )
        return NULL;

    picture_t *p_picture = svg_RenderPicture( p_filter, psz_svg );

    free( psz_svg );

    if (p_picture == NULL)
        return NULL;

    subpicture_region_t *p_region_out = subpicture_region_ForPicture(p_picture);
    picture_Release(p_picture);
    if (unlikely(p_region_out == NULL))
        return NULL;
    p_region_out->i_x     = p_region_in->i_x;
    p_region_out->i_y     = p_region_in->i_y;
    p_region_out->i_alpha = p_region_in->i_alpha;
    p_region_out->i_align = p_region_in->i_align;
    p_region_out->b_absolute = p_region_in->b_absolute;
    p_region_out->b_in_window= p_region_in->b_in_window;

    return p_region_out;
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416964