Commit 8e47c597 authored by Laurent Aimar's avatar Laurent Aimar

Reworked the way subtitles are rendered on video.

I have merged spu_RenderSubpictures and spu_SortSubpictures and removed the
blending from spu_RenderSubpictures. No functionnal changes except maybe
a bit for the transcode plugin.
parent 784b3717
......@@ -71,19 +71,15 @@ VLC_EXPORT( void, spu_Destroy, ( spu_t * ) );
VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) );
/**
* This function asks the spu_t core a list of subpictures to display.
* This function will return an unique subpicture containing the OSD and
* subtitles visibles at the requested date.
*
* The returned list can only be used by spu_RenderSubpictures.
*/
VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t render_subtitle_date, bool b_subtitle_only ) );
/**
* This function renders a list of subpicture_t on the provided picture.
*
* \param p_fmt_dst is the format of the destination picture.
* \param p_fmt_dst is the format of the picture on which the return subpicture will be rendered.
* \param p_fmt_src is the format of the original(source) video.
*
* The returned value if non NULL must be released by subpicture_Delete().
*/
VLC_EXPORT( void, spu_RenderSubpictures, ( spu_t *, picture_t *, const video_format_t *p_fmt_dst, subpicture_t *p_list, const video_format_t *p_fmt_src, mtime_t render_subtitle_date ) );
VLC_EXPORT( subpicture_t *, spu_Render, ( spu_t *, const video_format_t *p_fmt_dst, const video_format_t *p_fmt_src, mtime_t render_subtitle_date, mtime_t render_osd_date, bool b_subtitle_only ) );
/**
* It registers a new SPU channel.
......
......@@ -119,7 +119,10 @@ int transcode_osd_process( sout_stream_t *p_stream, sout_stream_id_t *id,
/* Check if we have a subpicture to send */
if( p_sys->p_spu && in->i_dts > VLC_TS_INVALID )
{
p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts, false );
video_format_t fmt;
video_format_Init( &fmt, 0 );
video_format_Setup( &fmt, 0, 720, 576, 1, 1 );
p_subpic = spu_Render( p_sys->p_spu, &fmt, &fmt, in->i_dts, in->i_dts, false );
}
else
{
......
......@@ -397,6 +397,7 @@ static int Open( vlc_object_t *p_this )
/* Subpictures transcoding parameters */
p_sys->p_spu = NULL;
p_sys->p_spu_blend = NULL;
p_sys->psz_senc = NULL;
p_sys->p_spu_cfg = NULL;
p_sys->i_scodec = 0;
......@@ -504,6 +505,7 @@ static void Close( vlc_object_t * p_this )
free( p_sys->psz_senc );
if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
if( p_sys->p_spu_blend ) filter_DeleteBlend( p_sys->p_spu_blend );
config_ChainDestroy( p_sys->p_osd_cfg );
free( p_sys->psz_osdenc );
......
......@@ -62,6 +62,7 @@ struct sout_stream_sys_t
bool b_soverlay;
config_chain_t *p_spu_cfg;
spu_t *p_spu;
filter_t *p_spu_blend;
/* OSD Menu */
vlc_fourcc_t i_osdcodec; /* codec osd menu (0 if not transcode) */
......
......@@ -626,7 +626,6 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id,
while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) )
{
subpicture_t *p_subpic = NULL;
sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_VIDEO, 1 );
......@@ -706,35 +705,36 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id,
/* Check if we have a subpicture to overlay */
if( p_sys->p_spu )
{
p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false );
/* TODO: get another pic */
}
/* Overlay subpicture */
if( p_subpic )
{
video_format_t fmt;
if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
{
/* We can't modify the picture, we need to duplicate it */
picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder );
if( p_tmp )
{
picture_Copy( p_tmp, p_pic );
picture_Release( p_pic );
p_pic = p_tmp;
}
}
if( filter_chain_GetLength( id->p_f_chain ) > 0 )
fmt = filter_chain_GetFmtOut( id->p_f_chain )->video;
else
fmt = id->p_decoder->fmt_out.video;
spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt,
p_subpic, &id->p_decoder->fmt_out.video, p_pic->date );
subpicture_t *p_subpic = spu_Render( p_sys->p_spu, &fmt, &fmt,
p_pic->date, p_pic->date, false );
/* Overlay subpicture */
if( p_subpic )
{
if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
{
/* We can't modify the picture, we need to duplicate it */
picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder );
if( p_tmp )
{
picture_Copy( p_tmp, p_pic );
picture_Release( p_pic );
p_pic = p_tmp;
}
}
if( !p_sys->p_spu_blend )
p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt );
if( p_sys->p_spu_blend )
picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic );
subpicture_Delete( p_subpic );
}
}
/* Run user specified filter chain */
......
......@@ -403,8 +403,7 @@ spu_Create
spu_Destroy
spu_DisplaySubpicture
spu_ChangeFilters
spu_RenderSubpictures
spu_SortSubpictures
spu_Render
spu_RegisterChannel
spu_ClearChannel
sql_Create
......
......@@ -890,18 +890,20 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
msg_Warn(vout, "Unsupported timestamp modifications done by chain_interactive");
/*
* Check for subpictures to display
* Get the subpicture to be displayed
*/
const bool do_snapshot = vout_snapshot_IsRequested(&vout->p->snapshot);
mtime_t spu_render_time;
mtime_t render_subtitle_date;
if (vout->p->pause.is_on)
spu_render_time = vout->p->pause.date;
render_subtitle_date = vout->p->pause.date;
else
spu_render_time = filtered->date > 1 ? filtered->date : mdate();
render_subtitle_date = filtered->date > 1 ? filtered->date : mdate();
mtime_t render_osd_date = mdate(); /* FIXME wrong */
subpicture_t *subpic = spu_Render(vout->p->spu, &vd->source, &vd->source,
render_subtitle_date, render_osd_date,
do_snapshot);
subpicture_t *subpic = spu_SortSubpictures(vout->p->spu,
spu_render_time,
do_snapshot);
/*
* Perform rendering
*
......@@ -923,9 +925,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
if (render) {
picture_Copy(render, filtered);
spu_RenderSubpictures(vout->p->spu,
render, &vd->source,
subpic, &vd->source, spu_render_time);
if (vout->p->spu_blend && subpic)
picture_BlendSubpicture(render, vout->p->spu_blend, subpic);
}
if (vout->p->is_decoder_pool_slow) {
direct = picture_pool_Get(vout->p->display_pool);
......@@ -942,6 +943,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
} else {
direct = filtered;
}
if (subpic)
subpicture_Delete(subpic);
if (!direct)
return VLC_EGENERIC;
......@@ -1289,12 +1292,20 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
vout->p->step.last = VLC_TS_INVALID;
vout->p->step.timestamp = VLC_TS_INVALID;
vout->p->spu_blend = filter_NewBlend(VLC_OBJECT(vout), &vout->p->original);
if (!vout->p->spu_blend)
msg_Err(vout, "Failed to create blending filter, OSD/Subtitles will not work");
video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original);
return VLC_SUCCESS;
}
static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state)
{
if (vout->p->spu_blend)
filter_DeleteBlend(vout->p->spu_blend);
/* Destroy translation tables */
if (vout->p->display.vd) {
if (vout->p->decoder_pool) {
......
......@@ -65,6 +65,7 @@ struct vout_thread_sys_t
/* Subpicture unit */
vlc_mutex_t spu_lock;
spu_t *spu;
filter_t *spu_blend;
/* Video output window */
struct {
......
......@@ -79,7 +79,6 @@ struct spu_private_t
spu_heap_t heap;
int i_channel; /**< number of subpicture channels registered */
filter_t *p_blend; /**< alpha blending module */
filter_t *p_text; /**< text renderer module */
filter_t *p_scale_yuvp; /**< scaling module for YUVP */
filter_t *p_scale; /**< scaling module (all but YUVP) */
......@@ -202,7 +201,6 @@ spu_t *spu_Create( vlc_object_t *p_this )
SpuHeapInit( &p_sys->heap );
p_sys->p_blend = NULL;
p_sys->p_text = NULL;
p_sys->p_scale = NULL;
p_sys->p_scale_yuvp = NULL;
......@@ -238,9 +236,6 @@ void spu_Destroy( spu_t *p_spu )
{
spu_private_t *p_sys = p_spu->p;
if( p_sys->p_blend )
filter_DeleteBlend( p_sys->p_blend );
if( p_sys->p_text )
FilterRelease( p_sys->p_text );
......@@ -348,16 +343,15 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
/**
* This function renders all sub picture units in the list.
*/
void spu_RenderSubpictures( spu_t *p_spu,
picture_t *p_pic_dst, const video_format_t *p_fmt_dst,
subpicture_t *p_subpic_list,
const video_format_t *p_fmt_src,
mtime_t render_subtitle_date )
static subpicture_t *SpuRenderSubpictures( spu_t *p_spu,
const video_format_t *p_fmt_dst,
subpicture_t *p_subpic_list,
const video_format_t *p_fmt_src,
mtime_t render_subtitle_date,
mtime_t render_osd_date )
{
spu_private_t *p_sys = p_spu->p;
const mtime_t render_osd_date = mdate();
const int i_source_video_width = p_fmt_src->i_width;
const int i_source_video_height = p_fmt_src->i_height;
......@@ -369,8 +363,6 @@ void spu_RenderSubpictures( spu_t *p_spu,
spu_area_t *p_subtitle_area;
int i_subtitle_area;
vlc_mutex_lock( &p_sys->lock );
/* Preprocess subpictures */
i_subpicture = 0;
i_subtitle_region_count = 0;
......@@ -395,10 +387,8 @@ void spu_RenderSubpictures( spu_t *p_spu,
/* Be sure we have at least 1 picture to process */
if( i_subpicture <= 0 )
{
vlc_mutex_unlock( &p_sys->lock );
return;
}
return NULL;
subpicture_t *p_output = subpicture_New( NULL );
/* Now order subpicture array
......@@ -517,24 +507,11 @@ void spu_RenderSubpictures( spu_t *p_spu,
if( p_subtitle_area != p_subtitle_area_buffer )
free( p_subtitle_area );
if( p_output )
{
/* Create the blending module */
if( !p_sys->p_blend )
p_spu->p->p_blend = filter_NewBlend( VLC_OBJECT(p_spu), p_fmt_dst );
/* Do the blending */
if( p_spu->p->p_blend )
picture_BlendSubpicture( p_pic_dst, p_spu->p->p_blend, p_output );
subpicture_Delete( p_output );
}
vlc_mutex_unlock( &p_sys->lock );
return p_output;
}
/*****************************************************************************
* spu_SortSubpictures: find the subpictures to display
* SpuSortSubpictures: find the subpictures to display
*****************************************************************************
* This function parses all subpictures and decides which ones need to be
* displayed. If no picture has been selected, display_date will depend on
......@@ -543,33 +520,13 @@ void spu_RenderSubpictures( spu_t *p_spu,
* to be removed if a newer one is available), which makes it a lot
* more difficult to guess if a subpicture has to be rendered or not.
*****************************************************************************/
subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_subtitle_date,
bool b_subtitle_only )
static subpicture_t *SpuSortSubpictures( spu_t *p_spu,
mtime_t render_subtitle_date,
mtime_t render_osd_date,
bool b_subtitle_only )
{
spu_private_t *p_sys = p_spu->p;
subpicture_t *p_subpic = NULL;
const mtime_t render_osd_date = mdate();
/* Update sub-filter chain */
vlc_mutex_lock( &p_sys->lock );
char *psz_chain_update = p_sys->psz_chain_update;
p_sys->psz_chain_update = NULL;
vlc_mutex_unlock( &p_sys->lock );
vlc_mutex_lock( &p_sys->chain_lock );
if( psz_chain_update )
{
filter_chain_Reset( p_sys->p_chain, NULL, NULL );
filter_chain_AppendFromString( p_spu->p->p_chain, psz_chain_update );
free( psz_chain_update );
}
/* Run subpicture filters */
filter_chain_SubFilter( p_sys->p_chain, render_osd_date );
vlc_mutex_unlock( &p_sys->chain_lock );
vlc_mutex_lock( &p_sys->lock );
/* Create a list of channels */
int pi_channel[VOUT_MAX_SUBPICTURES];
......@@ -695,11 +652,63 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_subtitle_date,
}
p_sys->i_last_sort_date = render_subtitle_date;
vlc_mutex_unlock( &p_sys->lock );
return p_subpic;
}
subpicture_t *spu_Render( spu_t *p_spu,
const video_format_t *p_fmt_dst,
const video_format_t *p_fmt_src,
mtime_t render_subtitle_date,
mtime_t render_osd_date,
bool b_subtitle_only )
{
spu_private_t *p_sys = p_spu->p;
/* Update sub-filter chain */
vlc_mutex_lock( &p_sys->lock );
char *psz_chain_update = p_sys->psz_chain_update;
p_sys->psz_chain_update = NULL;
vlc_mutex_unlock( &p_sys->lock );
vlc_mutex_lock( &p_sys->chain_lock );
if( psz_chain_update )
{
filter_chain_Reset( p_sys->p_chain, NULL, NULL );
filter_chain_AppendFromString( p_spu->p->p_chain, psz_chain_update );
free( psz_chain_update );
}
/* Run subpicture filters */
filter_chain_SubFilter( p_sys->p_chain, render_osd_date );
vlc_mutex_unlock( &p_sys->chain_lock );
/* Get the sorted list of subpicture to render */
vlc_mutex_lock( &p_sys->lock );
subpicture_t *p_list = SpuSortSubpictures( p_spu,
render_subtitle_date,
render_osd_date,
b_subtitle_only );
if( !p_list )
{
vlc_mutex_unlock( &p_sys->lock );
return NULL;
}
/* Render the current list of subpictures */
subpicture_t *p_render = SpuRenderSubpictures( p_spu,
p_fmt_dst,
p_list,
p_fmt_src,
render_subtitle_date,
render_osd_date );
vlc_mutex_unlock( &p_sys->lock );
return p_render;
}
void spu_OffsetSubtitleDate( spu_t *p_spu, mtime_t i_duration )
{
spu_private_t *p_sys = p_spu->p;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment