/*****************************************************************************
* vout_subpictures.c : subpicture management functions
*****************************************************************************
- * Copyright (C) 2000-2005 the VideoLAN team
+ * Copyright (C) 2000-2007 the VideoLAN team
* $Id$
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
p_spu->pp_filter[p_spu->i_filter]->p_cfg = p_cfg;
p_spu->pp_filter[p_spu->i_filter]->p_module =
module_Need( p_spu->pp_filter[p_spu->i_filter],
- "sub filter", psz_name, 0 );
+ "sub filter", psz_name, VLC_TRUE );
if( p_spu->pp_filter[p_spu->i_filter]->p_module )
{
filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) );
video_format_t *p_fmt )
{
subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
+ if( !p_region ) return NULL;
+
memset( p_region, 0, sizeof(subpicture_region_t) );
p_region->p_next = 0;
p_region->p_cache = 0;
if( !p_region->picture.i_planes )
{
free( p_region );
- free( p_fmt->p_palette );
+ if( p_fmt->p_palette ) free( p_fmt->p_palette );
return NULL;
}
picture_t *p_pic )
{
subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
+ (void)p_this;
memset( p_region, 0, sizeof(subpicture_region_t) );
p_region->p_next = 0;
p_region->p_cache = 0;
if( p_region->psz_text )
free( p_region->psz_text );
+ if( p_region->psz_html )
+ free( p_region->psz_html );
//free( p_region->p_style ); FIXME --fenrir plugin does not allocate the memory for it. I think it might lead to segfault, video renderer can live longer than the decoder
free( p_region );
}
if( psz_modulename && *psz_modulename )
{
p_spu->p_text->p_module =
- module_Need( p_spu->p_text, "text renderer", psz_modulename, VLC_TRUE );
+ module_Need( p_spu->p_text, "text renderer",
+ psz_modulename, VLC_TRUE );
}
if( !p_spu->p_text->p_module )
{
}
if( p_spu->p_text )
{
- if( p_subpic->i_original_picture_height > 0 &&
- p_subpic->i_original_picture_width > 0 )
+ if( (p_subpic->i_original_picture_height > 0) &&
+ (p_subpic->i_original_picture_width > 0) )
{
p_spu->p_text->fmt_out.video.i_width =
p_spu->p_text->fmt_out.video.i_visible_width =
i_scale_width = i_scale_width_orig;
i_scale_height = i_scale_height_orig;
- if( p_subpic->i_original_picture_height > 0 &&
- p_subpic->i_original_picture_width > 0 )
+ if( (p_subpic->i_original_picture_height > 0) &&
+ (p_subpic->i_original_picture_width > 0) )
{
i_scale_width = i_scale_width * p_fmt->i_width /
p_subpic->i_original_picture_width;
}
/* Load the scaling module */
- if( !p_spu->p_scale && (i_scale_width != 1000 ||
- i_scale_height != 1000) )
+ if( !p_spu->p_scale &&
+ ((i_scale_width > 0) || (i_scale_height > 0)) &&
+ ((i_scale_width != 1000) || (i_scale_height != 1000)) )
{
p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
vlc_object_attach( p_spu->p_scale, p_spu );
while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend )
{
+ video_format_t orig_fmt = p_region->fmt;
+ vlc_bool_t b_rerender_text = VLC_FALSE;
int i_fade_alpha = 255;
int i_x_offset = p_region->i_x + i_subpic_x;
int i_y_offset = p_region->i_y + p_subpic->i_y;
{
if( p_spu->p_text && p_spu->p_text->p_module )
{
- p_region->i_align = p_subpic->i_flags;
+ vlc_value_t val;
+
+ /* Setup 3 variables which can be used to render time-dependent
+ * text (and effects). The first indicates the total amount of
+ * time the text will be on screen, the second the amount of time
+ * it has already been on screen (can be a negative value as text
+ * is layed out before it is rendered) and the third is a feedback
+ * variable from the renderer - if the renderer sets it then this
+ * particular text is time-dependent, eg. the visual progress bar
+ * inside the text in karaoke and the text needs to be rendered
+ * multiple times in order for the effect to work - we therefore
+ * need to return the region to its original state at the end of
+ * the loop, instead of leaving it in YUVA or YUVP
+ * Any renderer which is unaware of how to render time-dependent
+ * text can happily ignore the variables and render the text the
+ * same as usual - it should at least show up on screen, but the
+ * effect won't change the text over time.
+ */
+
+ var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME );
+ val.i_time = p_subpic->i_stop - p_subpic->i_start;
+ var_Set( p_spu->p_text, "spu-duration", val );
+
+ var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME );
+ val.i_time = mdate() - p_subpic->i_start;
+ var_Set( p_spu->p_text, "spu-elapsed", val );
+
+ var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL );
+ var_SetBool( p_spu->p_text, "text-rerender", VLC_FALSE );
if( p_spu->p_text->pf_render_html && p_region->psz_html )
{
p_spu->p_text->pf_render_text( p_spu->p_text,
p_region, p_region );
}
+ b_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" );
+
+ var_Destroy( p_spu->p_text, "spu-duration" );
+ var_Destroy( p_spu->p_text, "spu-elapsed" );
+ var_Destroy( p_spu->p_text, "text-rerender" );
+
}
}
/* Force palette if requested */
- if( p_spu->b_force_palette && VLC_FOURCC('Y','U','V','P') ==
- p_region->fmt.i_chroma )
+ if( p_spu->b_force_palette &&
+ (VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma) )
{
memcpy( p_region->fmt.p_palette->palette,
p_spu->palette, 16 );
}
}
- if( (i_scale_width != 1000 || i_scale_height != 1000) &&
+ if( ((i_scale_width != 1000) || (i_scale_height != 1000)) &&
+ ((i_scale_width > 0) || (i_scale_height > 0)) &&
p_spu->p_scale && !p_region->p_cache )
{
picture_t *p_pic;
p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
p_region->p_cache->i_x = p_region->i_x * i_scale_width / 1000;
p_region->p_cache->i_y = p_region->i_y * i_scale_height / 1000;
+ p_region->p_cache->i_align = p_region->i_align;
p_pic = p_spu->p_scale->pf_video_filter(
p_spu->p_scale, &p_region->p_cache->picture );
free( p_pic );
}
}
- if( (i_scale_width != 1000 || i_scale_height != 1000) &&
+ if( ((i_scale_width != 1000) || (i_scale_height != 1000)) &&
+ ((i_scale_width > 0) || (i_scale_height > 0)) &&
p_spu->p_scale && p_region->p_cache )
{
p_region = p_region->p_cache;
}
- if( p_subpic->i_flags & SUBPICTURE_ALIGN_BOTTOM )
+ if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM )
{
i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
- p_subpic->i_y;
+ p_subpic->i_y - p_region->i_y;
}
- else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_TOP) )
+ else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) )
{
i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
}
- if( p_subpic->i_flags & SUBPICTURE_ALIGN_RIGHT )
+ if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT )
{
i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
- i_subpic_x;
+ i_subpic_x - p_region->i_x;
}
- else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_LEFT) )
+ else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) )
{
i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
}
p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
i_fade_alpha * p_subpic->i_alpha / 255 );
+ if( b_rerender_text )
+ {
+ /* Some forms of subtitles need to be re-rendered more than once,
+ * eg. karaoke. We therefore restore the region to its pre-rendered
+ * state, so the next time through everything is calculated again.
+ */
+ p_region->picture.pf_release( &p_region->picture );
+ memset( &p_region->picture, 0, sizeof( picture_t ) );
+ p_region->fmt = orig_fmt;
+ }
p_region = p_region->p_next;
}
static int CropCallback( vlc_object_t *p_object, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
+ (void)psz_var; (void)oldval; (void)newval;
UpdateSPU( (spu_t *)p_data, p_object );
return VLC_SUCCESS;
}
static subpicture_t *spu_new_buffer( filter_t *p_filter )
{
subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
+ (void)p_filter;
memset( p_subpic, 0, sizeof(subpicture_t) );
p_subpic->b_absolute = VLC_TRUE;
static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic )
{
+ (void)p_filter;
if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
if( p_pic ) free( p_pic );
}
static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
+ (void)p_object; (void)oldval; (void)newval;
+
if( !strcmp( psz_var, "sub-filter" ) )
{
spu_t *p_spu = (spu_t *)p_data;