[vlc-devel] [PATCH] This patch improves the support for the USF subtitle format.

Christopher Gundler c.gundler at mail.de
Tue May 2 14:10:39 CEST 2017


Hello Jean-Baptiste,

actually, this patch was developed by Julius Schöning in the context of 
his research. As his student assistant it is my task to be the contact 
for you and try to push his patch into the main code base.

Best,
Christopher

Am 02.05.2017 um 10:34 schrieb Jean-Baptiste Kempf:
> Hello Christopher,
>
> Who is the author of this patch then? You or Julius?
>
> Best,
>
> On Thu, 20 Apr 2017, at 17:14, Christopher Gundler wrote:
>> This patch introduces the support for parsing rects, circles, and
>> polygons from this type of subtitle format and was developed in the
>> context of research ("Providing Video Annotations in Multimedia
>> Containers for Visualization and Research.") by Julius Schoening,
>> University of Osnabrueck, Germany.
>> ---
>>   modules/codec/subsusf.c | 322
>>   ++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 322 insertions(+)
>>
>> diff --git a/modules/codec/subsusf.c b/modules/codec/subsusf.c
>> index 1a94b6b4fd..14acc884ad 100644
>> --- a/modules/codec/subsusf.c
>> +++ b/modules/codec/subsusf.c
>> @@ -821,7 +821,147 @@ static void ParseUSFHeaderTags( decoder_t *p_dec,
>> xml_reader_t *p_xml_reader )
>>       free( p_ssa_style );
>>   }
>>   
>> +/**
>> + * Create a region with a white transparent picture.
>> + */
>> +static subpicture_region_t *newPaintRegion( int x, int y, int width, int
>> height )
>> +{
>> +    video_palette_t palette = {
>> +        .i_entries = 2,
>> +        .palette = {
>> +            [0] = { 0xff, 0x80, 0x80, 0x00 },
>> +            [1] = { 0xff, 0x80, 0x80, 0xff },
>> +        },
>> +    };
>> +
>> +    video_format_t fmt;
>> +    video_format_Init( &fmt, VLC_CODEC_YUVP );
>> +    fmt.i_width          =
>> +    fmt.i_visible_width  = width;
>> +    fmt.i_height         =
>> +    fmt.i_visible_height = height;
>> +    fmt.i_sar_num        = 1;
>> +    fmt.i_sar_den        = 1;
>> +    fmt.p_palette        = &palette;
>> +
>> +    subpicture_region_t *r = subpicture_region_New( &fmt );
>> +    if ( !r )
>> +        return NULL;
>> +    r->i_x = x;
>> +    r->i_y = y;
>> +    memset( r->p_picture->p->p_pixels, 0, r->p_picture->p->i_pitch *
>> height );
>> +
>> +    return r;
>> +}
>> +
>> +/**
>> + * Draw a rectangle into a paint region
>> + */
>> +static void DrawRect( subpicture_region_t *r,
>> +                     int x1, int y1, int x2, int y2 )
>> +{
>> +    uint8_t *p    = r->p_picture->p->p_pixels;
>> +    int     pitch = r->p_picture->p->i_pitch;
>> +
>> +    for ( int y = y1; y <= y2; y++ )
>> +    {
>> +        p[x1 + pitch * y] = 1;
>> +        p[x2 + pitch * y] = 1;
>> +    }
>> +
>> +    for ( int x = x1; x <= x2; x++ ) {
>> +        p[x + pitch * y1] = 1;
>> +        p[x + pitch * y2] = 1;
>> +    }
>> +}
>> +
>> +struct polydata {
>> +    int x;
>> +    int y;
>> +    struct polydata *next;
>> +};
>> +typedef struct polydata polydata;
>> +
>> +static void DrawPoly( subpicture_region_t *r, polydata *root )
>> +{
>> +    uint8_t *pY    = r->p_picture->p[Y_PLANE].p_pixels;
>> +    int     pitchY = r->p_picture->p[Y_PLANE].i_pitch;
>> +
>> +    polydata *curr = root;
>> +
>> +    do
>> +    {
>> +        // if end of list, set next to root for closed polygon
>> +        polydata *next = curr->next == NULL ? root : curr->next;
>> +
>> +        int x0 = curr->x;
>> +        int y0 = curr->y;
>> +        int x1 = next->x;
>> +        int y1 = next->y;
>> +
>> +        // bresenham's line algorithm
>> +        // from
>> http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
>> +        int dx = abs( x1 - x0 ), sx = x0 < x1 ? 1 : -1;
>> +        int dy = abs( y1 - y0 ), sy = y0 < y1 ? 1 : -1;
>> +        int err = ( dx > dy ? dx : -dy ) / 2, e2;
>> +
>> +        for( ; ; )
>> +        {
>> +            pY[ x0 + pitchY * y0 ] = 1;
>> +            if ( x0 == x1 && y0 == y1 )
>> +              break;
>> +
>> +            e2 = err;
>> +
>> +            if ( e2 >- dx )
>> +            {
>> +                err -= dy;
>> +                x0 += sx;
>> +            }
>> +
>> +            if ( e2 < dy )
>> +            {
>> +                err += dx;
>> +                y0 += sy;
>> +            }
>> +        }
>> +    }
>> +    while( ( curr = curr->next ) != NULL );
>> +}
>> +
>> +static void DrawCircle( subpicture_region_t *r, int x0, int y0, int
>> diameter )
>> +{
>> +    uint8_t *pY    = r->p_picture->p[Y_PLANE].p_pixels;
>> +    int     pitchY = r->p_picture->p[Y_PLANE].i_pitch;
>>   
>> +    // bresenham's circle algorithm
>> +    // slightly optimized from
>> https://de.wikipedia.org/wiki/Bresenham-Algorithmus#Kreisvariante_des_Algorithmus
>> +    int x = diameter / 2;
>> +    int y = 0;
>> +    int err = x;
>> +
>> +    while( y <= x )
>> +    {
>> +        pY[ ( x0 + x ) + pitchY * ( y0 + y ) ] = 1;
>> +        pY[ ( x0 - x ) + pitchY * ( y0 + y ) ] = 1;
>> +        pY[ ( x0 + x ) + pitchY * ( y0 - y ) ] = 1;
>> +        pY[ ( x0 - x ) + pitchY * ( y0 - y ) ] = 1;
>> +        pY[ ( x0 + y ) + pitchY * ( y0 + x ) ] = 1;
>> +        pY[ ( x0 - y ) + pitchY * ( y0 + x ) ] = 1;
>> +        pY[ ( x0 + y ) + pitchY * ( y0 - x ) ] = 1;
>> +        pY[ ( x0 - y ) + pitchY * ( y0 - x ) ] = 1;
>> +        err -= 2 * y;
>> +        err++;
>> +        y++;
>> +
>> +        if(err < 0)
>> +        {
>> +            err--;
>> +            err += 2*x;
>> +            x--;
>> +        }
>> +    }
>> +}
>>   
>>   static subpicture_region_t *ParseUSFString( decoder_t *p_dec,
>>                                               char *psz_subtitle )
>> @@ -917,6 +1057,188 @@ static subpicture_region_t *ParseUSFString(
>> decoder_t *p_dec,
>>                       p_region_upto = p_region_upto->p_next;
>>                   }
>>               }
>> +            else if(( !strncasecmp( psz_subtitle, "<polygon ", 9 )) ||
>> +                    ( !strncasecmp( psz_subtitle, "<polygon>", 9 )))
>> +            {
>> +                // get the end of the current polygon
>> +                psz_end = strstr ( psz_subtitle, "</polygon>" );
>> +
>> +                // initialize stuff
>> +                polydata *p_root = NULL;
>> +                polydata **pp_next = &p_root;
>> +
>> +                // starting position of next point
>> +                char *psz_point_start, *psz_point_end = NULL;
>> +
>> +                // check if next point is found and in current polygon
>> +                for ( psz_point_start = strstr( psz_subtitle, "<point "
>> );
>> +                      pp_next &&
>> +                      psz_point_start && psz_point_start < psz_end ;
>> +                      psz_point_start = psz_point_end
>> +                        ? strstr( psz_point_end, "<point " ) : NULL )
>> +                {
>> +                    // read attributes of points
>> +                    char *psz_point_x = GrabAttributeValue( "posx",
>> psz_point_start );
>> +                    char *psz_point_y = GrabAttributeValue( "posy",
>> psz_point_start );
>> +
>> +                    if ( psz_point_x && psz_point_y &&
>> +                       ( ( *pp_next = calloc( 1, sizeof( polydata ) ) )
>> != NULL ) )
>> +                    {
>> +                        ( *pp_next )->x = (int)( strtol( psz_point_x,
>> NULL, 10 ) );
>> +                        ( *pp_next )->y = (int)( strtol( psz_point_y,
>> NULL, 10 ) );
>> +                        pp_next = &( ( *pp_next )->next );
>> +                    }
>> +                    else
>> +                    {
>> +                        pp_next = NULL;
>> +                    }
>> +
>> +                    if ( psz_point_x ) free( psz_point_x );
>> +                    if ( psz_point_y ) free( psz_point_y );
>> +
>> +                    // get end of point and continue the search from
>> there on
>> +                    psz_point_end = strstr(psz_point_start, "/>") + 2;
>> +                }
>> +
>> +                if ( pp_next )
>> +                {
>> +                    // create and draw picture region
>> +                    subpicture_region_t *p_paint_region;
>> +                    int video_width = p_sys->i_original_width;
>> +                    int video_height = p_sys->i_original_height;
>> +                    p_paint_region = newPaintRegion( 0, 0, video_width +
>> 1, video_height + 1 );
>> +                    DrawPoly( p_paint_region, p_root );
>> +
>> +                    // save picture region in list
>> +                    if( !p_region_first )
>> +                    {
>> +                        p_region_first = p_region_upto = p_paint_region;
>> +                    }
>> +                    else if( p_paint_region )
>> +                    {
>> +                        p_region_upto->p_next = p_paint_region;
>> +                        p_region_upto = p_region_upto->p_next;
>> +                    }
>> +                }
>> +
>> +                // free linked list
>> +                while( p_root )
>> +                {
>> +                    polydata *p_tmp = p_root;
>> +                    p_root = p_root->next;
>> +                    free(p_tmp);
>> +                }
>> +            }
>> +            else if ( !strncasecmp( psz_subtitle, "<rectangle ", 11 ))
>> +            {
>> +                // get the end of the rectangle
>> +                psz_end = strstr ( psz_subtitle,"/>" );
>> +
>> +                // read attributes of rectangle
>> +                char *psz_rec_x = GrabAttributeValue( "posx",
>> psz_subtitle );
>> +                char *psz_rec_y = GrabAttributeValue( "posy",
>> psz_subtitle );
>> +                char *psz_rec_width = GrabAttributeValue( "width",
>> psz_subtitle );
>> +                char *psz_rec_height = GrabAttributeValue( "height",
>> psz_subtitle );
>> +
>> +                if ( psz_rec_x && psz_rec_y && psz_rec_width &&
>> psz_rec_height )
>> +                {
>> +                    // create and draw picture region
>> +                    subpicture_region_t *p_paint_region;
>> +                    int video_width = p_sys->i_original_width;
>> +                    int video_height = p_sys->i_original_height;
>> +                    p_paint_region = newPaintRegion( 0, 0, video_width +
>> 1, video_height + 1 );
>> +
>> +                    // convert to int
>> +                    int x = (int)( strtol( psz_rec_x, NULL, 10 ) );
>> +                    int y = (int)( strtol( psz_rec_y, NULL, 10 ) );
>> +                    int w = (int)( strtol( psz_rec_width, NULL, 10 ) );
>> +                    int h = (int)( strtol( psz_rec_height, NULL, 10 ) );
>> +
>> +                    DrawRect( p_paint_region, x, y, x + w, y + h );
>> +
>> +                    // save picture region in list
>> +                    if( !p_region_first )
>> +                    {
>> +                        p_region_first = p_region_upto = p_paint_region;
>> +                    }
>> +                    else if( p_paint_region )
>> +                    {
>> +                        p_region_upto->p_next = p_paint_region;
>> +                        p_region_upto = p_region_upto->p_next;
>> +                    }
>> +                }
>> +
>> +                if ( psz_rec_x ) free( psz_rec_x );
>> +                if ( psz_rec_y ) free( psz_rec_y );
>> +                if ( psz_rec_width ) free( psz_rec_width );
>> +                if ( psz_rec_height ) free( psz_rec_height );
>> +            }
>> +            else if ( !strncasecmp( psz_subtitle, "<point ", 7 ) )
>> +            {
>> +                // get the end of the point
>> +                psz_end = strstr ( psz_subtitle, "/>" );
>> +
>> +                // read attributes of point
>> +                char *psz_point_x = GrabAttributeValue( "posx",
>> psz_subtitle );
>> +                char *psz_point_y = GrabAttributeValue( "posy",
>> psz_subtitle );
>> +                char *psz_point_d = GrabAttributeValue( "diameter",
>> psz_subtitle );
>> +
>> +                if ( psz_point_x && psz_point_y && psz_point_d )
>> +                {
>> +                     // create and draw picture region
>> +                    subpicture_region_t *p_paint_region;
>> +                    int video_width = p_sys->i_original_width;
>> +                    int video_height = p_sys->i_original_height;
>> +                    p_paint_region = newPaintRegion( 0, 0, video_width +
>> 1, video_height + 1 );
>> +
>> +                    // convert to int
>> +                    int x = (int)( strtol( psz_point_x, NULL, 10 ) );
>> +                    int y = (int)( strtol( psz_point_y, NULL, 10 ) );
>> +                    int d = (int)( strtol( psz_point_d, NULL, 10 ) );
>> +
>> +                    DrawCircle( p_paint_region, x, y, d );
>> +
>> +                    // save picture region in list
>> +                    if( !p_region_first )
>> +                    {
>> +                        p_region_first = p_region_upto = p_paint_region;
>> +                    }
>> +                    else if( p_paint_region )
>> +                    {
>> +                        p_region_upto->p_next = p_paint_region;
>> +                        p_region_upto = p_region_upto->p_next;
>> +                    }
>> +                }
>> +
>> +                if ( psz_point_x ) free( psz_point_x );
>> +                if ( psz_point_y ) free( psz_point_y );
>> +                if ( psz_point_d ) free( psz_point_d );
>> +            }
>> +            else if(( !strncasecmp( psz_subtitle, "<text ", 6 )) ||
>> +                    ( !strncasecmp( psz_subtitle, "<text>", 6 )))
>> +            {
>> +                subpicture_region_t  *p_text_region;
>> +                psz_end = strstr( psz_subtitle, "</text>" );
>> +                p_text_region = CreateTextRegion( p_dec,
>> +                                                  psz_subtitle,
>> +                                                  p_sys->i_align );
>> +
>> +                if( p_text_region )
>> +                {
>> +                    free( p_text_region->p_text->psz_text );
>> +                    p_text_region->p_text->psz_text = CreatePlainText(
>> psz_subtitle );
>> +                }
>> +
>> +                if( !p_region_first )
>> +                {
>> +                    p_region_first = p_region_upto = p_text_region;
>> +                }
>> +                else if( p_text_region )
>> +                {
>> +                    p_region_upto->p_next = p_text_region;
>> +                    p_region_upto = p_region_upto->p_next;
>> +                }
>> +            }
>>               else
>>               {
>>                   subpicture_region_t  *p_text_region;
>> -- 
>> 2.12.2
>>
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel



More information about the vlc-devel mailing list