vlc_filter: return a non-text subpicture region when rendering text regions

We no longer need to ugly hack that marks the output region as marked
and we don't mix the input and output regions.
This commit is contained in:
Steve Lhomme 2023-10-24 11:13:47 +02:00
parent 569c1d039a
commit fe415420f3
8 changed files with 94 additions and 91 deletions

View File

@ -100,8 +100,11 @@ struct vlc_filter_operations
/** Filter a subpicture (sub filter) */
subpicture_t *(*filter_sub)(filter_t *, subpicture_t *);
/** Render text (text renderer) */
int (*render)(filter_t *, subpicture_region_t *,
/** Render text (text renderer)
*
* \return a picture-based region or NULL
*/
subpicture_region_t * (*render)(filter_t *,
const subpicture_region_t *, const vlc_fourcc_t *);
};

View File

@ -342,8 +342,7 @@ error:
*****************************************************************************
* This function merges the previously rendered freetype glyphs into a picture
*****************************************************************************/
static int RenderYUVP( const subpicture_region_t *p_region_in,
subpicture_region_t *p_region,
static subpicture_region_t *RenderYUVP( const subpicture_region_t *p_region_in,
const line_desc_t *p_line,
const FT_BBox *p_regionbbox,
const FT_BBox *p_bbox )
@ -372,20 +371,16 @@ static int RenderYUVP( const subpicture_region_t *p_region_in,
fmt.p_palette = p_region_in->fmt.p_palette ? p_region_in->fmt.p_palette : malloc(sizeof(*fmt.p_palette));
assert( !p_region->p_picture );
p_region->p_picture = picture_NewFromFormat( &fmt );
if( !p_region->p_picture )
subpicture_region_t *p_region = subpicture_region_New(&fmt);
if (unlikely(p_region == NULL))
{
if (p_region_in->fmt.p_palette == NULL)
free(fmt.p_palette);
return VLC_EGENERIC;
return NULL;
}
const unsigned regionnum = p_region_in->fmt.i_sar_num;
const unsigned regionden = p_region_in->fmt.i_sar_den;
p_region->fmt = fmt;
p_region->fmt.i_sar_num = regionnum;
p_region->fmt.i_sar_den = regionden;
p_region->fmt.i_sar_num = p_region_in->fmt.i_sar_num;
p_region->fmt.i_sar_den = p_region_in->fmt.i_sar_den;
/* Calculate text color components
* Only use the first color */
@ -463,7 +458,7 @@ static int RenderYUVP( const subpicture_region_t *p_region_in,
memset( p_top, 0, fmt.i_width );
}
return VLC_SUCCESS;
return p_region;
}
/*****************************************************************************
@ -641,9 +636,8 @@ static void RenderCharAXYZ( filter_t *p_filter,
}
}
static inline int RenderAXYZ( filter_t *p_filter,
static inline subpicture_region_t *RenderAXYZ( filter_t *p_filter,
const subpicture_region_t *p_region_in,
subpicture_region_t *p_region,
const line_desc_t *p_line_head,
const FT_BBox *p_regionbbox,
const FT_BBox *p_paddedtextbbox,
@ -666,15 +660,14 @@ static inline int RenderAXYZ( filter_t *p_filter,
fmt.space = p_region_in->fmt.space;
fmt.mastering = p_region_in->fmt.mastering;
picture_t *p_picture = p_region->p_picture = picture_NewFromFormat( &fmt );
if( !p_region->p_picture )
return VLC_EGENERIC;
subpicture_region_t *p_region = subpicture_region_New(&fmt);
if (unlikely(p_region == NULL))
return NULL;
const unsigned regionnum = p_region_in->fmt.i_sar_num;
const unsigned regionden = p_region_in->fmt.i_sar_den;
p_region->fmt = fmt;
p_region->fmt.i_sar_num = regionnum;
p_region->fmt.i_sar_den = regionden;
picture_t *p_picture = p_region->p_picture;
p_region->fmt.i_sar_num = p_region_in->fmt.i_sar_num;
p_region->fmt.i_sar_den = p_region_in->fmt.i_sar_den;
/* Initialize the picture background */
const text_style_t *p_style = p_sys->p_default_style;
@ -713,7 +706,7 @@ static inline int RenderAXYZ( filter_t *p_filter,
}
}
return VLC_SUCCESS;
return p_region;
}
static void UpdateDefaultLiveStyles( filter_t *p_filter )
@ -980,14 +973,15 @@ static size_t SegmentsToTextAndStyles( filter_t *p_filter, const text_segment_t
* needed glyphs into memory. It is used as pf_add_string callback in
* the vout method by this module
*/
static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
static subpicture_region_t *Render( filter_t *p_filter,
const subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
if( !p_region_in || !p_region_in->p_text )
return VLC_EGENERIC;
return NULL;
filter_sys_t *p_sys = p_filter->p_sys;
subpicture_region_t *region = NULL;
bool b_grid = (p_region_in->text_flags & VLC_SUBPIC_TEXT_FLAG_GRID_MODE) != 0;
p_sys->i_scale = ( b_grid ) ? 100 : var_InheritInteger( p_filter, "sub-text-scale");
@ -1001,7 +995,7 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
if( !p_sys->p_faceid )
{
msg_Err( p_filter, "Render(): Error loading default face" );
return VLC_EGENERIC;
return NULL;
}
p_sys->i_font_default_size = i_font_default_size;
}
@ -1015,7 +1009,7 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
{
free( text_block.pp_styles );
free( text_block.p_uchars );
return VLC_EGENERIC;
return NULL;
}
/* */
@ -1125,12 +1119,11 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
regionbbox = paddedbbox;
}
rv = VLC_EGENERIC;
for( const vlc_fourcc_t *p_chroma = p_chroma_list; *p_chroma != 0; p_chroma++ )
{
if( *p_chroma == VLC_CODEC_YUVP )
rv = RenderYUVP( p_region_in, p_region_out, text_block.p_laid,
&regionbbox, &bbox );
region = RenderYUVP( p_region_in, text_block.p_laid,
&regionbbox, &bbox );
else
{
const ft_drawing_functions *func;
@ -1163,29 +1156,29 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
else
continue;
rv = RenderAXYZ( p_filter, p_region_in, p_region_out, text_block.p_laid,
&regionbbox, &paddedbbox, &bbox,
*p_chroma,
func );
region = RenderAXYZ( p_filter, p_region_in, text_block.p_laid,
&regionbbox, &paddedbbox, &bbox,
*p_chroma,
func );
}
if( rv == VLC_SUCCESS )
if( region != NULL )
{
subpicture_region_TextMarkRendered( p_region_out );
/* Avoid useless pixels:
* reshrink/trim Region Box to padded text one,
* but update offsets to keep position and have same rendering */
// if( (bboxcolor & 0xFF) == 0 )
{
p_region_out->i_x = (paddedbbox.xMin - regionbbox.xMin) + p_region_in->i_x;
p_region_out->i_y = (regionbbox.yMax - paddedbbox.yMax) + p_region_in->i_y;
region->i_x = (paddedbbox.xMin - regionbbox.xMin) + p_region_in->i_x;
region->i_y = (regionbbox.yMax - paddedbbox.yMax) + p_region_in->i_y;
}
// else /* case where the bounding box is larger and visible */
// {
// p_region_out->i_x = p_region_in->i_x;
// p_region_out->i_y = p_region_in->i_y;
// region->i_x = p_region_in->i_x;
// region->i_y = p_region_in->i_y;
// }
region->i_alpha = p_region_in->i_alpha;
region->i_align = p_region_in->i_align;
break;
}
}
@ -1198,7 +1191,7 @@ done:
if( text_block.pp_ruby )
FreeRubyBlockArray( text_block.pp_ruby, text_block.i_count );
return rv;
return region;
}
static const struct vlc_filter_operations filter_ops =

View File

@ -37,8 +37,7 @@
static int Create (filter_t *);
static void Destroy(filter_t *);
static int RenderText(filter_t *,
subpicture_region_t *,
static subpicture_region_t *RenderText(filter_t *,
const subpicture_region_t *,
const vlc_fourcc_t *);
@ -97,8 +96,7 @@ static NSString * languageCodeForString(NSString *string) {
return (NSString *)CFStringTokenizerCopyBestStringLanguage((CFStringRef)string, CFRangeMake(0, [string length]));
}
static int RenderText(filter_t *p_filter,
subpicture_region_t *p_region_out,
static subpicture_region_t *RenderText(filter_t *p_filter,
const subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list)
{
@ -107,7 +105,7 @@ static int RenderText(filter_t *p_filter,
const text_segment_t *p_segment = p_region_in->p_text;
if (!p_segment)
return VLC_EGENERIC;
return NULL;
for ( const text_segment_t *s = p_segment; s != NULL; s = s->p_next ) {
if ( !s->psz_text )
@ -155,6 +153,6 @@ static int RenderText(filter_t *p_filter,
[p_sys->speechSynthesizer startSpeakingString:stringToSpeech];
}
return VLC_SUCCESS;
return NULL;
}
}

View File

@ -56,8 +56,7 @@ DEFINE_GUID(CLSID_SpObjectTokenCategory, 0xa910187f, 0x0c7a, 0x45ac, 0x92,0xcc,
extern "C" {
static int Create (filter_t *);
static void Destroy(filter_t *);
static int RenderText(filter_t *,
subpicture_region_t *,
static subpicture_region_t *RenderText(filter_t *,
const subpicture_region_t *,
const vlc_fourcc_t *);
}
@ -213,8 +212,7 @@ error:
return -ENOENT;
}
static int RenderText(filter_t *p_filter,
subpicture_region_t *,
static subpicture_region_t *RenderText(filter_t *p_filter,
const subpicture_region_t *region_in,
const vlc_fourcc_t *)
{
@ -223,7 +221,7 @@ static int RenderText(filter_t *p_filter,
sys->cmd.render_text.region = region_in;
sys->cmd_available.post();
sys->cmd_ready.wait();
return VLC_EGENERIC; /* We don't generate output region. */
return NULL; /* We don't generate output region. */
}
static const struct vlc_filter_operations filter_ops = []{

View File

@ -49,7 +49,7 @@
*****************************************************************************/
static int Create ( filter_t * );
static void Destroy ( filter_t * );
static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
static subpicture_region_t *RenderText( filter_t *p_filter,
const subpicture_region_t *p_region_in,
const vlc_fourcc_t * );
@ -328,25 +328,22 @@ static char * SegmentsToSVG( text_segment_t *p_segment, int i_height, int *pi_to
return psz_result;
}
static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
static subpicture_region_t *RenderText( filter_t *p_filter,
const subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
/* Sanity check */
if( !p_region_in || !p_region_out || !p_region_in->p_text )
return VLC_EGENERIC;
if( !p_region_in || !p_region_in->p_text )
return NULL;
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;
return NULL;
}
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_in->i_x <= i_width )
i_width -= p_region_in->i_x;
@ -356,7 +353,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
i_height -= p_region_in->i_y;
if( i_height == 0 || i_width == 0 )
return VLC_EGENERIC;
return NULL;
char *psz_svg;
/* Check if the data is SVG or pure text. In the latter case,
@ -379,19 +376,23 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
}
if( !psz_svg )
return VLC_EGENERIC;
return NULL;
picture_t *p_picture = svg_RenderPicture( p_filter, psz_svg );
free( psz_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 );
subpicture_region_TextMarkRendered(p_region_out);
return VLC_SUCCESS;
}
return VLC_EGENERIC;
if (p_picture == NULL)
return NULL;
subpicture_region_t *p_region_out = subpicture_region_ForPicture(&p_picture->format, 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;
return p_region_out;
}

View File

@ -37,13 +37,13 @@ vlc_module_begin ()
vlc_module_end ()
static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
static subpicture_region_t *RenderText( filter_t *p_filter,
const subpicture_region_t *p_region_in,
const vlc_fourcc_t *p_chroma_list )
{
VLC_UNUSED(p_filter); VLC_UNUSED(p_region_out); VLC_UNUSED(p_region_in);
VLC_UNUSED(p_filter); VLC_UNUSED(p_region_in);
VLC_UNUSED(p_chroma_list);
return VLC_EGENERIC;
return NULL;
}
static const struct vlc_filter_operations filter_ops = {

View File

@ -313,7 +313,7 @@ static filter_t *SpuRenderCreateAndLoadScale(vlc_object_t *object,
return scale;
}
static int SpuRenderText(spu_t *spu,
static subpicture_region_t *SpuRenderText(spu_t *spu,
subpicture_region_t *region,
unsigned i_original_width,
unsigned i_original_height,
@ -327,7 +327,7 @@ static int SpuRenderText(spu_t *spu,
if(unlikely(text == NULL))
{
vlc_mutex_unlock(&sys->textlock);
return VLC_EGENERIC;
return NULL;
}
// assume rendered text is in sRGB if nothing is set
@ -347,10 +347,11 @@ static int SpuRenderText(spu_t *spu,
text->fmt_out.video.i_height =
text->fmt_out.video.i_visible_height = i_original_height;
int i_ret = text->ops->render(text, region, region, chroma_list);
subpicture_region_t *rendered_region = text->ops->render(text, region, chroma_list);
assert(rendered_region == NULL || !subpicture_region_IsText(rendered_region));
vlc_mutex_unlock(&sys->textlock);
return i_ret;
return rendered_region;
}
/**
@ -808,13 +809,15 @@ static subpicture_region_t *SpuRenderRegion(spu_t *spu,
/* Render text region */
if (subpicture_region_IsText( region ))
{
if(SpuRenderText(spu, region,
subpicture_region_t *rendered_text =
SpuRenderText(spu, region,
i_original_width, i_original_height,
chroma_list) != VLC_SUCCESS)
return NULL;
if(subpicture_region_IsText( region ))
chroma_list);
if ( rendered_text == NULL)
// not a rendering error for Text-To-Speech
return NULL;
// FIXME notify the caller it is allocated
region = rendered_text;
}
video_format_AdjustColorSpace(&region->fmt);
@ -1530,9 +1533,16 @@ static void spu_PrerenderText(spu_t *spu, subpicture_t *p_subpic,
{
if(!subpicture_region_IsText( region ))
continue;
SpuRenderText(spu, region,
i_original_picture_width, i_original_picture_height,
chroma_list);
subpicture_region_t *rendered_text =
SpuRenderText(spu, region,
i_original_picture_width, i_original_picture_height,
chroma_list);
if (rendered_text == NULL)
vlc_spu_regions_remove(&p_subpic->regions, region);
else
// replace the text region with the rendered region
vlc_list_replace(&region->node, &rendered_text->node);
subpicture_region_Delete(region);
}
}

View File

@ -255,15 +255,15 @@ static int OpenWindow(vlc_window_t *wnd)
return VLC_SUCCESS;
}
static int TextRendererRender(filter_t *filter, subpicture_region_t *region_out,
static subpicture_region_t *TextRendererRender(filter_t *filter,
const subpicture_region_t *region_in,
const vlc_fourcc_t *chroma_list)
{
(void) region_out; (void) chroma_list;
(void) chroma_list;
struct input_decoder_scenario *scenario = &input_decoder_scenarios[current_scenario];
if (scenario->text_renderer_render != NULL)
scenario->text_renderer_render(filter, region_in);
return VLC_EGENERIC;
return NULL;
}
static int OpenTextRenderer(filter_t *filter)