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 * ) ); ...@@ -71,19 +71,15 @@ VLC_EXPORT( void, spu_Destroy, ( spu_t * ) );
VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_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. * \param p_fmt_dst is the format of the picture on which the return subpicture will be rendered.
*/
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_src is the format of the original(source) video. * \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. * It registers a new SPU channel.
......
...@@ -119,7 +119,10 @@ int transcode_osd_process( sout_stream_t *p_stream, sout_stream_id_t *id, ...@@ -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 */ /* Check if we have a subpicture to send */
if( p_sys->p_spu && in->i_dts > VLC_TS_INVALID ) 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 else
{ {
......
...@@ -397,6 +397,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -397,6 +397,7 @@ static int Open( vlc_object_t *p_this )
/* Subpictures transcoding parameters */ /* Subpictures transcoding parameters */
p_sys->p_spu = NULL; p_sys->p_spu = NULL;
p_sys->p_spu_blend = NULL;
p_sys->psz_senc = NULL; p_sys->psz_senc = NULL;
p_sys->p_spu_cfg = NULL; p_sys->p_spu_cfg = NULL;
p_sys->i_scodec = 0; p_sys->i_scodec = 0;
...@@ -504,6 +505,7 @@ static void Close( vlc_object_t * p_this ) ...@@ -504,6 +505,7 @@ static void Close( vlc_object_t * p_this )
free( p_sys->psz_senc ); free( p_sys->psz_senc );
if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu ); 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 ); config_ChainDestroy( p_sys->p_osd_cfg );
free( p_sys->psz_osdenc ); free( p_sys->psz_osdenc );
......
...@@ -62,6 +62,7 @@ struct sout_stream_sys_t ...@@ -62,6 +62,7 @@ struct sout_stream_sys_t
bool b_soverlay; bool b_soverlay;
config_chain_t *p_spu_cfg; config_chain_t *p_spu_cfg;
spu_t *p_spu; spu_t *p_spu;
filter_t *p_spu_blend;
/* OSD Menu */ /* OSD Menu */
vlc_fourcc_t i_osdcodec; /* codec osd menu (0 if not transcode) */ 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, ...@@ -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 )) ) 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 ); 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, ...@@ -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 */ /* Check if we have a subpicture to overlay */
if( p_sys->p_spu ) 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; 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 ) if( filter_chain_GetLength( id->p_f_chain ) > 0 )
fmt = filter_chain_GetFmtOut( id->p_f_chain )->video; fmt = filter_chain_GetFmtOut( id->p_f_chain )->video;
else else
fmt = id->p_decoder->fmt_out.video; fmt = id->p_decoder->fmt_out.video;
spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt, subpicture_t *p_subpic = spu_Render( p_sys->p_spu, &fmt, &fmt,
p_subpic, &id->p_decoder->fmt_out.video, p_pic->date ); 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 */ /* Run user specified filter chain */
......
...@@ -403,8 +403,7 @@ spu_Create ...@@ -403,8 +403,7 @@ spu_Create
spu_Destroy spu_Destroy
spu_DisplaySubpicture spu_DisplaySubpicture
spu_ChangeFilters spu_ChangeFilters
spu_RenderSubpictures spu_Render
spu_SortSubpictures
spu_RegisterChannel spu_RegisterChannel
spu_ClearChannel spu_ClearChannel
sql_Create sql_Create
......
...@@ -890,18 +890,20 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) ...@@ -890,18 +890,20 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
msg_Warn(vout, "Unsupported timestamp modifications done by chain_interactive"); 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); 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) if (vout->p->pause.is_on)
spu_render_time = vout->p->pause.date; render_subtitle_date = vout->p->pause.date;
else 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 * Perform rendering
* *
...@@ -923,9 +925,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) ...@@ -923,9 +925,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
if (render) { if (render) {
picture_Copy(render, filtered); picture_Copy(render, filtered);
spu_RenderSubpictures(vout->p->spu, if (vout->p->spu_blend && subpic)
render, &vd->source, picture_BlendSubpicture(render, vout->p->spu_blend, subpic);
subpic, &vd->source, spu_render_time);
} }
if (vout->p->is_decoder_pool_slow) { if (vout->p->is_decoder_pool_slow) {
direct = picture_pool_Get(vout->p->display_pool); direct = picture_pool_Get(vout->p->display_pool);
...@@ -942,6 +943,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) ...@@ -942,6 +943,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
} else { } else {
direct = filtered; direct = filtered;
} }
if (subpic)
subpicture_Delete(subpic);
if (!direct) if (!direct)
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -1289,12 +1292,20 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state) ...@@ -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.last = VLC_TS_INVALID;
vout->p->step.timestamp = 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); video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state) 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 */ /* Destroy translation tables */
if (vout->p->display.vd) { if (vout->p->display.vd) {
if (vout->p->decoder_pool) { if (vout->p->decoder_pool) {
......
...@@ -65,6 +65,7 @@ struct vout_thread_sys_t ...@@ -65,6 +65,7 @@ struct vout_thread_sys_t
/* Subpicture unit */ /* Subpicture unit */
vlc_mutex_t spu_lock; vlc_mutex_t spu_lock;
spu_t *spu; spu_t *spu;
filter_t *spu_blend;
/* Video output window */ /* Video output window */
struct { struct {
......
...@@ -79,7 +79,6 @@ struct spu_private_t ...@@ -79,7 +79,6 @@ struct spu_private_t
spu_heap_t heap; spu_heap_t heap;
int i_channel; /**< number of subpicture channels registered */ 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_text; /**< text renderer module */
filter_t *p_scale_yuvp; /**< scaling module for YUVP */ filter_t *p_scale_yuvp; /**< scaling module for YUVP */
filter_t *p_scale; /**< scaling module (all but YUVP) */ filter_t *p_scale; /**< scaling module (all but YUVP) */
...@@ -202,7 +201,6 @@ spu_t *spu_Create( vlc_object_t *p_this ) ...@@ -202,7 +201,6 @@ spu_t *spu_Create( vlc_object_t *p_this )
SpuHeapInit( &p_sys->heap ); SpuHeapInit( &p_sys->heap );
p_sys->p_blend = NULL;
p_sys->p_text = NULL; p_sys->p_text = NULL;
p_sys->p_scale = NULL; p_sys->p_scale = NULL;
p_sys->p_scale_yuvp = NULL; p_sys->p_scale_yuvp = NULL;
...@@ -238,9 +236,6 @@ void spu_Destroy( spu_t *p_spu ) ...@@ -238,9 +236,6 @@ void spu_Destroy( spu_t *p_spu )
{ {
spu_private_t *p_sys = p_spu->p; spu_private_t *p_sys = p_spu->p;
if( p_sys->p_blend )
filter_DeleteBlend( p_sys->p_blend );
if( p_sys->p_text ) if( p_sys->p_text )
FilterRelease( p_sys->p_text ); FilterRelease( p_sys->p_text );
...@@ -348,16 +343,15 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic ) ...@@ -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. * This function renders all sub picture units in the list.
*/ */
void spu_RenderSubpictures( spu_t *p_spu, static subpicture_t *SpuRenderSubpictures( spu_t *p_spu,
picture_t *p_pic_dst, const video_format_t *p_fmt_dst, const video_format_t *p_fmt_dst,
subpicture_t *p_subpic_list, subpicture_t *p_subpic_list,
const video_format_t *p_fmt_src, const video_format_t *p_fmt_src,
mtime_t render_subtitle_date ) mtime_t render_subtitle_date,
mtime_t render_osd_date )
{ {
spu_private_t *p_sys = p_spu->p; 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_width = p_fmt_src->i_width;
const int i_source_video_height = p_fmt_src->i_height; const int i_source_video_height = p_fmt_src->i_height;
...@@ -369,8 +363,6 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -369,8 +363,6 @@ void spu_RenderSubpictures( spu_t *p_spu,
spu_area_t *p_subtitle_area; spu_area_t *p_subtitle_area;
int i_subtitle_area; int i_subtitle_area;
vlc_mutex_lock( &p_sys->lock );
/* Preprocess subpictures */ /* Preprocess subpictures */
i_subpicture = 0; i_subpicture = 0;
i_subtitle_region_count = 0; i_subtitle_region_count = 0;
...@@ -395,10 +387,8 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -395,10 +387,8 @@ void spu_RenderSubpictures( spu_t *p_spu,
/* Be sure we have at least 1 picture to process */ /* Be sure we have at least 1 picture to process */
if( i_subpicture <= 0 ) if( i_subpicture <= 0 )
{ return NULL;
vlc_mutex_unlock( &p_sys->lock );
return;
}
subpicture_t *p_output = subpicture_New( NULL ); subpicture_t *p_output = subpicture_New( NULL );
/* Now order subpicture array /* Now order subpicture array
...@@ -517,24 +507,11 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -517,24 +507,11 @@ void spu_RenderSubpictures( spu_t *p_spu,
if( p_subtitle_area != p_subtitle_area_buffer ) if( p_subtitle_area != p_subtitle_area_buffer )
free( p_subtitle_area ); free( p_subtitle_area );
if( p_output ) return 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 );
} }
/***************************************************************************** /*****************************************************************************
* 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 * This function parses all subpictures and decides which ones need to be
* displayed. If no picture has been selected, display_date will depend on * displayed. If no picture has been selected, display_date will depend on
...@@ -543,33 +520,13 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -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 * 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. * 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, static subpicture_t *SpuSortSubpictures( spu_t *p_spu,
bool b_subtitle_only ) mtime_t render_subtitle_date,
mtime_t render_osd_date,
bool b_subtitle_only )
{ {
spu_private_t *p_sys = p_spu->p; spu_private_t *p_sys = p_spu->p;
subpicture_t *p_subpic = NULL; 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 */ /* Create a list of channels */
int pi_channel[VOUT_MAX_SUBPICTURES]; int pi_channel[VOUT_MAX_SUBPICTURES];
...@@ -695,11 +652,63 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_subtitle_date, ...@@ -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; p_sys->i_last_sort_date = render_subtitle_date;
vlc_mutex_unlock( &p_sys->lock );
return p_subpic; 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 ) void spu_OffsetSubtitleDate( spu_t *p_spu, mtime_t i_duration )
{ {
spu_private_t *p_sys = p_spu->p; 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