mirror of
https://github.com/videolan/vlc.git
synced 2024-12-04 15:26:23 +08:00
codec: add tx3g spu
This commit is contained in:
parent
2a60d695e5
commit
6a63bcae63
1
NEWS
1
NEWS
@ -25,6 +25,7 @@ Decoder:
|
||||
* OpenMax IL improvements, notably for RaspberryPi
|
||||
* Fix channel ordering of LPCM codec in m2ts files
|
||||
* New jpeg image decoder
|
||||
* Add tx3g subtitles decoder
|
||||
|
||||
Encoder:
|
||||
* Support for MPEG-2 encoding using x262
|
||||
|
@ -416,6 +416,7 @@
|
||||
#define VLC_CODEC_USF VLC_FOURCC('u','s','f',' ')
|
||||
#define VLC_CODEC_OGT VLC_FOURCC('o','g','t',' ')
|
||||
#define VLC_CODEC_CVD VLC_FOURCC('c','v','d',' ')
|
||||
#define VLC_CODEC_TX3G VLC_FOURCC('t','x','3','g')
|
||||
/* Blu-ray Presentation Graphics */
|
||||
#define VLC_CODEC_BD_PG VLC_FOURCC('b','d','p','g')
|
||||
/* EBU STL (TECH. 3264-E) */
|
||||
|
@ -344,6 +344,7 @@ $Id$
|
||||
* stream_out_transcode: audio & video transcoder
|
||||
* subsdec: a codec to output textual subtitles
|
||||
* subsdelay: subtitles delay filter
|
||||
* substx3g: tx3g styled subtitles decoder
|
||||
* subsusf: a demuxer for USF subtitles
|
||||
* subtitle: a demuxer for subtitle files
|
||||
* svcdsub: SVCD subtitles decoder
|
||||
|
@ -183,6 +183,8 @@ endif
|
||||
EXTRA_LTLIBRARIES += libzvbi_plugin.la
|
||||
codec_LTLIBRARIES += $(LTLIBzvbi)
|
||||
|
||||
libsubstx3g_plugin_la_SOURCES = codec/substx3g.c codec/substext.h
|
||||
codec_LTLIBRARIES += libsubstx3g_plugin.la
|
||||
|
||||
### Xiph ###
|
||||
|
||||
|
@ -1,18 +1,164 @@
|
||||
#include <vlc_strings.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool b_set;
|
||||
unsigned int i_value;
|
||||
} subpicture_updater_sys_option_t;
|
||||
|
||||
typedef struct segment_t segment_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t i_fontsize;
|
||||
uint32_t i_color; //ARGB
|
||||
uint8_t i_flags;
|
||||
} segment_style_t;
|
||||
|
||||
struct segment_t
|
||||
{
|
||||
char *psz_string;
|
||||
unsigned int i_size;
|
||||
segment_t *p_next;
|
||||
/* styles applied to that segment */
|
||||
segment_style_t styles;
|
||||
};
|
||||
|
||||
struct subpicture_updater_sys_t {
|
||||
char *text;
|
||||
char *html;
|
||||
segment_t *p_htmlsegments;
|
||||
|
||||
int align;
|
||||
int x;
|
||||
int y;
|
||||
int i_font_height_percent;
|
||||
int i_font_height_abs_to_src;
|
||||
|
||||
bool is_fixed;
|
||||
int fixed_width;
|
||||
int fixed_height;
|
||||
bool renderbg;
|
||||
|
||||
/* styling */
|
||||
subpicture_updater_sys_option_t style_flags;
|
||||
subpicture_updater_sys_option_t font_color;
|
||||
subpicture_updater_sys_option_t background_color;
|
||||
int16_t i_alpha;
|
||||
int16_t i_drop_shadow;
|
||||
int16_t i_drop_shadow_alpha;
|
||||
};
|
||||
|
||||
static void SegmentFree( segment_t *p_segment )
|
||||
{
|
||||
if ( p_segment )
|
||||
{
|
||||
free( p_segment->psz_string );
|
||||
free( p_segment );
|
||||
}
|
||||
}
|
||||
|
||||
static void MakeHtmlNewLines( char **ppsz_src )
|
||||
{
|
||||
unsigned int i_nlcount = 0;
|
||||
unsigned i_len = strlen( *ppsz_src );
|
||||
if ( i_len == 0 ) return;
|
||||
for ( unsigned i=0; i<i_len; i++ )
|
||||
if ( (*ppsz_src)[i] == '\n' )
|
||||
i_nlcount++;
|
||||
if ( !i_nlcount ) return;
|
||||
|
||||
char *psz_dst = malloc( i_len + 1 + (i_nlcount * 4) );
|
||||
char *ptr = psz_dst;
|
||||
for ( unsigned i=0; i<i_len; i++ )
|
||||
{
|
||||
if ( (*ppsz_src)[i] == '\n' )
|
||||
{
|
||||
strcpy( ptr, "<br/>" );
|
||||
ptr += 5;
|
||||
} else {
|
||||
*ptr++ = (*ppsz_src)[i];
|
||||
}
|
||||
}
|
||||
*ptr = 0;
|
||||
free( *ppsz_src );
|
||||
*ppsz_src = psz_dst;
|
||||
}
|
||||
|
||||
static void HtmlAppend( char **ppsz_dst, const char *psz_src,
|
||||
const segment_style_t *p_styles, const float f_scale )
|
||||
{
|
||||
if ( !ppsz_dst ) return;
|
||||
int i_ignore; VLC_UNUSED(i_ignore);
|
||||
char *psz_subtext = NULL;
|
||||
char *psz_text = NULL;
|
||||
char *psz_fontsize = NULL;
|
||||
char *psz_color = NULL;
|
||||
char *psz_encoded = convert_xml_special_chars( psz_src );
|
||||
if ( !psz_encoded ) return;
|
||||
|
||||
MakeHtmlNewLines( &psz_encoded );
|
||||
|
||||
if ( p_styles->i_color & 0xFF000000 ) //ARGB
|
||||
i_ignore = asprintf( &psz_color, " color=\"#%6x\"",
|
||||
p_styles->i_color & 0x00FFFFFF );
|
||||
|
||||
if ( p_styles->i_fontsize > 0 && f_scale > 0 )
|
||||
i_ignore = asprintf( &psz_fontsize, " size=\"%u\"",
|
||||
(unsigned) (f_scale * p_styles->i_fontsize) );
|
||||
|
||||
i_ignore = asprintf( &psz_subtext, "%s%s%s%s%s%s%s",
|
||||
( p_styles->i_flags & STYLE_UNDERLINE ) ? "<u>" : "",
|
||||
( p_styles->i_flags & STYLE_BOLD ) ? "<b>" : "",
|
||||
( p_styles->i_flags & STYLE_ITALIC ) ? "<i>" : "",
|
||||
psz_encoded,
|
||||
( p_styles->i_flags & STYLE_ITALIC ) ? "</i>" : "",
|
||||
( p_styles->i_flags & STYLE_BOLD ) ? "</b>" : "",
|
||||
( p_styles->i_flags & STYLE_UNDERLINE ) ? "</u>" : ""
|
||||
);
|
||||
|
||||
if ( psz_color || psz_fontsize )
|
||||
{
|
||||
i_ignore = asprintf( &psz_text, "<font%s%s>%s</font>",
|
||||
psz_color ? psz_color : "",
|
||||
psz_fontsize ? psz_fontsize : "",
|
||||
psz_subtext );
|
||||
free( psz_subtext );
|
||||
}
|
||||
else
|
||||
{
|
||||
psz_text = psz_subtext;
|
||||
}
|
||||
|
||||
free( psz_fontsize );
|
||||
free( psz_color );
|
||||
|
||||
if ( *ppsz_dst )
|
||||
{
|
||||
char *psz_dst = *ppsz_dst;
|
||||
i_ignore = asprintf( ppsz_dst, "%s%s", psz_dst, psz_text );
|
||||
free( psz_dst );
|
||||
free( psz_text );
|
||||
}
|
||||
else
|
||||
*ppsz_dst = psz_text;
|
||||
}
|
||||
|
||||
static char *SegmentsToHtml( segment_t *p_head, const float f_scale )
|
||||
{
|
||||
char *psz_dst = NULL;
|
||||
char *psz_ret = NULL;
|
||||
while( p_head )
|
||||
{
|
||||
HtmlAppend( &psz_dst, p_head->psz_string, &p_head->styles, f_scale );
|
||||
p_head = p_head->p_next;
|
||||
}
|
||||
int i_ignore = asprintf( &psz_ret, "<text>%s</text>", psz_dst );
|
||||
VLC_UNUSED( i_ignore );
|
||||
free( psz_dst );
|
||||
return psz_ret;
|
||||
}
|
||||
|
||||
static int SubpictureTextValidate(subpicture_t *subpic,
|
||||
bool has_src_changed, const video_format_t *fmt_src,
|
||||
bool has_dst_changed, const video_format_t *fmt_dst,
|
||||
@ -59,7 +205,13 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
|
||||
return;
|
||||
|
||||
r->psz_text = sys->text ? strdup(sys->text) : NULL;
|
||||
r->psz_html = sys->html ? strdup(sys->html) : NULL;
|
||||
if ( sys->p_htmlsegments )
|
||||
r->psz_html = SegmentsToHtml( sys->p_htmlsegments,
|
||||
(float) fmt_dst->i_height / fmt_src->i_height );
|
||||
else if ( sys->html )
|
||||
r->psz_html = strdup(sys->html);
|
||||
else
|
||||
r->psz_html = NULL;
|
||||
r->i_align = sys->align;
|
||||
r->b_renderbg = sys->renderbg;
|
||||
if (!sys->is_fixed) {
|
||||
@ -84,16 +236,38 @@ static void SubpictureTextUpdate(subpicture_t *subpic,
|
||||
r->i_y = sys->y * fmt_dst->i_height / sys->fixed_height;
|
||||
}
|
||||
|
||||
if (sys->i_font_height_percent != 0)
|
||||
if (sys->i_font_height_percent || sys->i_alpha ||
|
||||
sys->style_flags.b_set ||
|
||||
sys->font_color.b_set ||
|
||||
sys->background_color.b_set )
|
||||
{
|
||||
r->p_style = text_style_New();
|
||||
if (r->p_style)
|
||||
if (!r->p_style) return;
|
||||
|
||||
if (sys->i_font_height_abs_to_src)
|
||||
sys->i_font_height_percent = sys->i_font_height_abs_to_src * 100 /
|
||||
fmt_src->i_visible_height;
|
||||
|
||||
if (sys->i_font_height_percent)
|
||||
{
|
||||
r->p_style->i_font_size = sys->i_font_height_percent *
|
||||
subpic->i_original_picture_height / 100;
|
||||
r->p_style->i_font_size = sys->i_font_height_percent *
|
||||
subpic->i_original_picture_height / 100;
|
||||
r->p_style->i_font_color = 0xffffff;
|
||||
r->p_style->i_font_alpha = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
if (sys->style_flags.b_set)
|
||||
r->p_style->i_style_flags = sys->style_flags.i_value;
|
||||
if (sys->font_color.b_set)
|
||||
r->p_style->i_font_color = sys->font_color.i_value;
|
||||
if (sys->background_color.b_set)
|
||||
r->p_style->i_background_color = sys->background_color.i_value;
|
||||
if (sys->i_alpha)
|
||||
r->p_style->i_font_alpha = sys->i_alpha;
|
||||
if (sys->i_drop_shadow)
|
||||
r->p_style->i_shadow_width = sys->i_drop_shadow;
|
||||
if (sys->i_drop_shadow_alpha)
|
||||
r->p_style->i_shadow_alpha = sys->i_drop_shadow_alpha;
|
||||
}
|
||||
}
|
||||
static void SubpictureTextDestroy(subpicture_t *subpic)
|
||||
@ -102,6 +276,12 @@ static void SubpictureTextDestroy(subpicture_t *subpic)
|
||||
|
||||
free(sys->text);
|
||||
free(sys->html);
|
||||
while( sys->p_htmlsegments )
|
||||
{
|
||||
segment_t *p_segment = sys->p_htmlsegments;
|
||||
sys->p_htmlsegments = sys->p_htmlsegments->p_next;
|
||||
SegmentFree( p_segment );
|
||||
}
|
||||
free(sys);
|
||||
}
|
||||
|
||||
|
346
modules/codec/substx3g.c
Normal file
346
modules/codec/substx3g.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*****************************************************************************
|
||||
* substx3gsub.c : MP4 tx3g subtitles decoder
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2014 VLC authors and VideoLAN
|
||||
*
|
||||
* 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.,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <vlc_common.h>
|
||||
#include <vlc_plugin.h>
|
||||
#include <vlc_codec.h>
|
||||
#include <vlc_sout.h>
|
||||
|
||||
#include "substext.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Module descriptor.
|
||||
*****************************************************************************/
|
||||
static int Open ( vlc_object_t * );
|
||||
static subpicture_t *Decode( decoder_t *, block_t ** );
|
||||
|
||||
vlc_module_begin ()
|
||||
set_description( N_("tx3g subtitles decoder") )
|
||||
set_shortname( N_("tx3g subtitles") )
|
||||
set_capability( "decoder", 100 )
|
||||
set_category( CAT_INPUT )
|
||||
set_subcategory( SUBCAT_INPUT_SCODEC )
|
||||
set_callbacks( Open, NULL )
|
||||
vlc_module_end ()
|
||||
|
||||
/****************************************************************************
|
||||
* Local structs
|
||||
****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Open: probe the decoder and return score
|
||||
*****************************************************************************/
|
||||
static int Open( vlc_object_t *p_this )
|
||||
{
|
||||
decoder_t *p_dec = (decoder_t *) p_this;
|
||||
|
||||
if( p_dec->fmt_in.i_codec != VLC_CODEC_TX3G )
|
||||
return VLC_EGENERIC;
|
||||
|
||||
p_dec->pf_decode_sub = Decode;
|
||||
|
||||
p_dec->fmt_out.i_cat = SPU_ES;
|
||||
p_dec->fmt_out.i_codec = 0;
|
||||
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Local:
|
||||
*****************************************************************************/
|
||||
|
||||
#define FONT_FACE_BOLD 0x1
|
||||
#define FONT_FACE_ITALIC 0x2
|
||||
#define FONT_FACE_UNDERLINE 0x4
|
||||
|
||||
static int ConvertFlags( int i_atomflags )
|
||||
{
|
||||
int i_vlcstyles_flags = 0;
|
||||
if ( i_atomflags & FONT_FACE_BOLD )
|
||||
i_vlcstyles_flags |= STYLE_BOLD;
|
||||
else if ( i_atomflags & FONT_FACE_ITALIC )
|
||||
i_vlcstyles_flags |= STYLE_ITALIC;
|
||||
else if ( i_atomflags & FONT_FACE_UNDERLINE )
|
||||
i_vlcstyles_flags |= STYLE_UNDERLINE;
|
||||
return i_vlcstyles_flags;
|
||||
}
|
||||
|
||||
static void SegmentDoSplit( segment_t *p_segment, uint16_t i_start, uint16_t i_end,
|
||||
segment_t **pp_segment_left,
|
||||
segment_t **pp_segment_middle,
|
||||
segment_t **pp_segment_right )
|
||||
{
|
||||
segment_t *p_segment_left = *pp_segment_left;
|
||||
segment_t *p_segment_right = *pp_segment_right;
|
||||
segment_t *p_segment_middle = *pp_segment_middle;
|
||||
p_segment_left = p_segment_middle = p_segment_right = NULL;
|
||||
|
||||
if ( (p_segment->i_size - i_start < 1) || (p_segment->i_size - i_end < 1) )
|
||||
return;
|
||||
|
||||
if ( i_start > 0 )
|
||||
{
|
||||
p_segment_left = calloc( 1, sizeof(segment_t) );
|
||||
if ( !p_segment_left ) goto error;
|
||||
memcpy( &p_segment_left->styles, &p_segment->styles, sizeof(segment_style_t) );
|
||||
p_segment_left->psz_string = strndup( p_segment->psz_string, i_start );
|
||||
p_segment_left->i_size = strlen( p_segment_left->psz_string );
|
||||
}
|
||||
|
||||
p_segment_middle = calloc( 1, sizeof(segment_t) );
|
||||
if ( !p_segment_middle ) goto error;
|
||||
memcpy( &p_segment_middle->styles, &p_segment->styles, sizeof(segment_style_t) );
|
||||
p_segment_middle->psz_string = strndup( p_segment->psz_string + i_start, i_end - i_start + 1 );
|
||||
p_segment_middle->i_size = strlen( p_segment_middle->psz_string );
|
||||
|
||||
if ( i_end < (p_segment->i_size - 1) )
|
||||
{
|
||||
p_segment_right = calloc( 1, sizeof(segment_t) );
|
||||
if ( !p_segment_right ) goto error;
|
||||
memcpy( &p_segment_right->styles, &p_segment->styles, sizeof(segment_style_t) );
|
||||
p_segment_right->psz_string = strndup( p_segment->psz_string + i_end + 1, p_segment->i_size - i_end - 1 );
|
||||
p_segment_right->i_size = strlen( p_segment_right->psz_string );
|
||||
}
|
||||
|
||||
if ( p_segment_left ) p_segment_left->p_next = p_segment_middle;
|
||||
if ( p_segment_right ) p_segment_middle->p_next = p_segment_right;
|
||||
|
||||
*pp_segment_left = p_segment_left;
|
||||
*pp_segment_middle = p_segment_middle;
|
||||
*pp_segment_right = p_segment_right;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
SegmentFree( p_segment_left );
|
||||
SegmentFree( p_segment_middle );
|
||||
SegmentFree( p_segment_right );
|
||||
}
|
||||
|
||||
static bool SegmentSplit( segment_t *p_prev, segment_t **pp_segment,
|
||||
const uint16_t i_start, const uint16_t i_end,
|
||||
const segment_style_t *p_styles )
|
||||
{
|
||||
segment_t *p_segment_left = NULL, *p_segment_middle = NULL, *p_segment_right = NULL;
|
||||
|
||||
if ( (*pp_segment)->i_size == 0 ) return false;
|
||||
if ( i_start > i_end ) return false;
|
||||
if ( (size_t)(i_end - i_start) > (*pp_segment)->i_size - 1 ) return false;
|
||||
if ( i_end > (*pp_segment)->i_size - 1 ) return false;
|
||||
|
||||
SegmentDoSplit( *pp_segment, i_start, i_end, &p_segment_left, &p_segment_middle, &p_segment_right );
|
||||
if ( !p_segment_middle )
|
||||
{
|
||||
/* Failed */
|
||||
SegmentFree( p_segment_left );
|
||||
SegmentFree( p_segment_right );
|
||||
return false;
|
||||
}
|
||||
|
||||
segment_t *p_next = (*pp_segment)->p_next;
|
||||
SegmentFree( *pp_segment );
|
||||
*pp_segment = ( p_segment_left ) ? p_segment_left : p_segment_middle ;
|
||||
if ( p_prev ) p_prev->p_next = *pp_segment;
|
||||
|
||||
if ( p_segment_right )
|
||||
p_segment_right->p_next = p_next;
|
||||
else
|
||||
p_segment_middle->p_next = p_next;
|
||||
|
||||
p_segment_middle->styles = *p_styles;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Creates a new segment using the given style and split existing ones according
|
||||
to the start & end offsets */
|
||||
static void ApplySegmentStyle( segment_t **pp_segment, const uint16_t i_absstart,
|
||||
const uint16_t i_absend, const segment_style_t *p_styles )
|
||||
{
|
||||
/* find the matching segment */
|
||||
uint16_t i_curstart = 0;
|
||||
segment_t *p_prev = NULL;
|
||||
segment_t *p_cur = *pp_segment;
|
||||
while ( p_cur )
|
||||
{
|
||||
uint16_t i_curend = i_curstart + p_cur->i_size - 1;
|
||||
if ( (i_absstart >= i_curstart) && (i_absend <= i_curend) )
|
||||
{
|
||||
/* segment found */
|
||||
if ( !SegmentSplit( p_prev, &p_cur, i_absstart - i_curstart,
|
||||
i_absend - i_curstart, p_styles ) )
|
||||
return;
|
||||
if ( !p_prev ) *pp_segment = p_cur;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
i_curstart += p_cur->i_size;
|
||||
p_prev = p_cur;
|
||||
p_cur = p_cur->p_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Decode:
|
||||
*****************************************************************************/
|
||||
static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
|
||||
{
|
||||
block_t *p_block;
|
||||
subpicture_t *p_spu = NULL;
|
||||
|
||||
if( ( pp_block == NULL ) || ( *pp_block == NULL ) ) return NULL;
|
||||
p_block = *pp_block;
|
||||
*pp_block = NULL;
|
||||
|
||||
if( ( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) ||
|
||||
p_block->i_buffer < sizeof(uint16_t) )
|
||||
{
|
||||
block_Release( p_block );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *p_buf = p_block->p_buffer;
|
||||
|
||||
/* Read our raw string and create the styled segment for HTML */
|
||||
uint16_t i_psz_length = GetWBE( p_buf );
|
||||
char *psz_subtitle = malloc( i_psz_length + 1 );
|
||||
if ( !psz_subtitle ) return NULL;
|
||||
memcpy( psz_subtitle, p_block->p_buffer + sizeof(uint16_t), i_psz_length );
|
||||
psz_subtitle[ i_psz_length ] = '\0';
|
||||
p_buf += i_psz_length + sizeof(uint16_t);
|
||||
|
||||
for( uint16_t i=0; i < i_psz_length; i++ )
|
||||
if ( psz_subtitle[i] == '\r' ) psz_subtitle[i] = '\n';
|
||||
|
||||
segment_t *p_segment = calloc( 1, sizeof(segment_t) );
|
||||
if ( !p_segment )
|
||||
{
|
||||
free( psz_subtitle );
|
||||
return NULL;
|
||||
}
|
||||
p_segment->psz_string = strdup( psz_subtitle );
|
||||
p_segment->i_size = strlen( psz_subtitle );
|
||||
if ( p_dec->fmt_in.subs.p_style )
|
||||
{
|
||||
p_segment->styles.i_color = p_dec->fmt_in.subs.p_style->i_font_color;
|
||||
p_segment->styles.i_color |= p_dec->fmt_in.subs.p_style->i_font_alpha << 24;
|
||||
if ( p_dec->fmt_in.subs.p_style->i_style_flags )
|
||||
p_segment->styles.i_flags = p_dec->fmt_in.subs.p_style->i_style_flags;
|
||||
p_segment->styles.i_fontsize = p_dec->fmt_in.subs.p_style->i_font_size;
|
||||
}
|
||||
|
||||
if ( !p_segment->psz_string )
|
||||
{
|
||||
SegmentFree( p_segment );
|
||||
free( psz_subtitle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the subpicture unit */
|
||||
p_spu = decoder_NewSubpictureText( p_dec );
|
||||
if( !p_spu )
|
||||
{
|
||||
free( psz_subtitle );
|
||||
SegmentFree( p_segment );
|
||||
return NULL;
|
||||
}
|
||||
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
|
||||
|
||||
/* Parse our styles */
|
||||
while( (size_t)(p_buf - p_block->p_buffer) + 8 < p_block->i_buffer )
|
||||
{
|
||||
uint32_t i_atomsize = GetDWBE( p_buf );
|
||||
vlc_fourcc_t i_atomtype = VLC_FOURCC(p_buf[4],p_buf[5],p_buf[6],p_buf[7]);
|
||||
p_buf += 8;
|
||||
switch( i_atomtype )
|
||||
{
|
||||
|
||||
case VLC_FOURCC('s','t','y','l'):
|
||||
{
|
||||
if ( (size_t)(p_buf - p_block->p_buffer) < 14 ) break;
|
||||
uint16_t i_nbrecords = GetWBE(p_buf);
|
||||
uint16_t i_cur_record = 0;
|
||||
p_buf += 2;
|
||||
while( i_cur_record++ < i_nbrecords )
|
||||
{
|
||||
if ( (size_t)(p_buf - p_block->p_buffer) < 12 ) break;
|
||||
uint16_t i_start = __MIN( GetWBE(p_buf), i_psz_length - 1 );
|
||||
uint16_t i_end = __MIN( GetWBE(p_buf + 2), i_psz_length - 1 );
|
||||
|
||||
segment_style_t style;
|
||||
style.i_flags = ConvertFlags( p_buf[6] );
|
||||
style.i_fontsize = p_buf[7];
|
||||
style.i_color = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB
|
||||
style.i_color |= (GetDWBE(p_buf+8) & 0xFF) << 24;
|
||||
ApplySegmentStyle( &p_segment, i_start, i_end, &style );
|
||||
|
||||
if ( i_nbrecords == 1 )
|
||||
{
|
||||
if ( p_buf[6] )
|
||||
{
|
||||
p_spu_sys->style_flags.i_value = ConvertFlags( p_buf[6] );
|
||||
p_spu_sys->style_flags.b_set = true;
|
||||
}
|
||||
p_spu_sys->i_font_height_abs_to_src = p_buf[7];
|
||||
p_spu_sys->font_color.i_value = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB
|
||||
p_spu_sys->font_color.i_value |= (GetDWBE(p_buf+8) & 0xFF) << 24;
|
||||
p_spu_sys->font_color.b_set = true;
|
||||
}
|
||||
|
||||
p_buf += 12;
|
||||
}
|
||||
} break;
|
||||
|
||||
case VLC_FOURCC('d','r','p','o'):
|
||||
if ( (size_t)(p_buf - p_block->p_buffer) < 4 ) break;
|
||||
p_spu_sys->i_drop_shadow = __MAX( GetWBE(p_buf), GetWBE(p_buf+2) );
|
||||
break;
|
||||
|
||||
case VLC_FOURCC('d','r','p','t'):
|
||||
if ( (size_t)(p_buf - p_block->p_buffer) < 2 ) break;
|
||||
p_spu_sys->i_drop_shadow_alpha = GetWBE(p_buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
p_buf += i_atomsize;
|
||||
}
|
||||
|
||||
p_spu->i_start = p_block->i_pts;
|
||||
p_spu->i_stop = p_block->i_pts + p_block->i_length;
|
||||
p_spu->b_ephemer = (p_block->i_length == 0);
|
||||
p_spu->b_absolute = false;
|
||||
|
||||
p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM;
|
||||
p_spu_sys->text = psz_subtitle;
|
||||
p_spu_sys->p_htmlsegments = p_segment;
|
||||
|
||||
block_Release( p_block );
|
||||
|
||||
return p_spu;
|
||||
}
|
@ -399,6 +399,7 @@ modules/codec/spudec/spudec.h
|
||||
modules/codec/stl.c
|
||||
modules/codec/subsdec.c
|
||||
modules/codec/subsusf.c
|
||||
modules/codec/substx3g.c
|
||||
modules/codec/svcdsub.c
|
||||
modules/codec/t140.c
|
||||
modules/codec/telx.c
|
||||
|
Loading…
Reference in New Issue
Block a user