Commit 9b8c543c authored by Laurent Aimar's avatar Laurent Aimar

Improved subtitle rendering accuracy and fixed pause on dynamic subtitles.

Dynamic subtitles are used by ssa and kate.
This commit breaks the API for 2 functions used by the transcode module.
parent 6456512f
...@@ -115,7 +115,7 @@ VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) ); ...@@ -115,7 +115,7 @@ VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) );
* *
* The returned list can only be used by spu_RenderSubpictures. * The returned list can only be used by spu_RenderSubpictures.
*/ */
VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t display_date, bool b_paused, bool b_subtitle_only ) ); VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t render_date, bool b_subtitle_only ) );
/** /**
* This function renders a list of subpicture_t on the provided picture. * This function renders a list of subpicture_t on the provided picture.
...@@ -123,7 +123,7 @@ VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t display_date ...@@ -123,7 +123,7 @@ VLC_EXPORT( subpicture_t *, spu_SortSubpictures, ( spu_t *, mtime_t display_date
* \param p_fmt_dst is the format of the destination 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.
*/ */
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, bool b_paused ) ); 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_date ) );
/** @}*/ /** @}*/
......
...@@ -1910,8 +1910,7 @@ static int transcode_video_process( sout_stream_t *p_stream, ...@@ -1910,8 +1910,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
/* 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, p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false );
false /* Fixme: check if stream is paused */, false );
/* TODO: get another pic */ /* TODO: get another pic */
} }
...@@ -1941,8 +1940,9 @@ static int transcode_video_process( sout_stream_t *p_stream, ...@@ -1941,8 +1940,9 @@ static int transcode_video_process( sout_stream_t *p_stream,
fmt.i_sar_num = fmt.i_aspect * fmt.i_height / fmt.i_width; fmt.i_sar_num = fmt.i_aspect * fmt.i_height / fmt.i_width;
fmt.i_sar_den = VOUT_ASPECT_FACTOR; fmt.i_sar_den = VOUT_ASPECT_FACTOR;
/* FIXME the mdate() seems highly suspicious */
spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt, spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt,
p_subpic, &id->p_decoder->fmt_out.video, false ); p_subpic, &id->p_decoder->fmt_out.video, mdate() );
} }
/* Run user specified filter chain */ /* Run user specified filter chain */
...@@ -2334,7 +2334,7 @@ static int transcode_osd_process( sout_stream_t *p_stream, ...@@ -2334,7 +2334,7 @@ static int transcode_osd_process( sout_stream_t *p_stream,
/* Check if we have a subpicture to send */ /* Check if we have a subpicture to send */
if( p_sys->p_spu && in->i_dts > 0) if( p_sys->p_spu && in->i_dts > 0)
{ {
p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts, false, false ); p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts, false );
} }
else else
{ {
......
...@@ -1177,17 +1177,24 @@ static void* RunThread( void *p_this ) ...@@ -1177,17 +1177,24 @@ static void* RunThread( void *p_this )
/* /*
* Check for subpictures to display * Check for subpictures to display
*/ */
mtime_t spu_render_time;
if( p_vout->p->b_paused )
spu_render_time = p_vout->p->i_pause_date;
else
spu_render_time = p_picture ? p_picture->date : mdate();
subpicture_t *p_subpic = NULL; subpicture_t *p_subpic = NULL;
if( display_date > 0 ) if( spu_render_time > 1 )
p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date, p_subpic = spu_SortSubpictures( p_vout->p_spu,
p_vout->p->b_paused, b_snapshot ); spu_render_time, b_snapshot );
/* /*
* Perform rendering * Perform rendering
*/ */
p_vout->p->i_picture_displayed++; p_vout->p->i_picture_displayed++;
p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture, p_directbuffer = vout_RenderPicture( p_vout,
p_subpic, p_vout->p->b_paused ); p_filtered_picture, p_subpic,
spu_render_time );
/* /*
* Take a snapshot if requested * Take a snapshot if requested
......
...@@ -107,7 +107,8 @@ struct vout_thread_sys_t ...@@ -107,7 +107,8 @@ struct vout_thread_sys_t
/* DO NOT use vout_RenderPicture unless you are in src/video_ouput */ /* DO NOT use vout_RenderPicture unless you are in src/video_ouput */
picture_t *vout_RenderPicture( vout_thread_t *, picture_t *, picture_t *vout_RenderPicture( vout_thread_t *, picture_t *,
subpicture_t *, bool b_paused ); subpicture_t *,
mtime_t render_date );
/* DO NOT use vout_UsePictureLocked unless you are in src/video_ouput /* DO NOT use vout_UsePictureLocked unless you are in src/video_ouput
* *
......
...@@ -335,7 +335,7 @@ static void vout_UnlockPicture( vout_thread_t *p_vout, picture_t *p_picture ) ...@@ -335,7 +335,7 @@ static void vout_UnlockPicture( vout_thread_t *p_vout, picture_t *p_picture )
* thread which direct buffer needs to be displayed. * thread which direct buffer needs to be displayed.
*/ */
picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
subpicture_t *p_subpic, bool b_paused ) subpicture_t *p_subpic, mtime_t render_date )
{ {
if( p_pic == NULL ) if( p_pic == NULL )
return NULL; return NULL;
...@@ -356,7 +356,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -356,7 +356,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
spu_RenderSubpictures( p_vout->p_spu, spu_RenderSubpictures( p_vout->p_spu,
PP_OUTPUTPICTURE[0], &p_vout->fmt_out, PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
p_subpic, &p_vout->fmt_in, b_paused ); p_subpic, &p_vout->fmt_in, render_date );
vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] ); vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
...@@ -383,7 +383,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -383,7 +383,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
picture_Copy( PP_OUTPUTPICTURE[0], p_pic ); picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
spu_RenderSubpictures( p_vout->p_spu, spu_RenderSubpictures( p_vout->p_spu,
PP_OUTPUTPICTURE[0], &p_vout->fmt_out, PP_OUTPUTPICTURE[0], &p_vout->fmt_out,
p_subpic, &p_vout->fmt_in, b_paused ); p_subpic, &p_vout->fmt_in, render_date );
vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] ); vout_UnlockPicture( p_vout, PP_OUTPUTPICTURE[0] );
...@@ -419,7 +419,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -419,7 +419,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
/* Render subpictures on the first direct buffer */ /* Render subpictures on the first direct buffer */
spu_RenderSubpictures( p_vout->p_spu, spu_RenderSubpictures( p_vout->p_spu,
p_tmp_pic, &p_vout->fmt_out, p_tmp_pic, &p_vout->fmt_out,
p_subpic, &p_vout->fmt_in, b_paused ); p_subpic, &p_vout->fmt_in, render_date );
if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) ) if( vout_LockPicture( p_vout, &p_vout->p_picture[0] ) )
return NULL; return NULL;
...@@ -438,7 +438,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, ...@@ -438,7 +438,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
/* Render subpictures on the first direct buffer */ /* Render subpictures on the first direct buffer */
spu_RenderSubpictures( p_vout->p_spu, spu_RenderSubpictures( p_vout->p_spu,
&p_vout->p_picture[0], &p_vout->fmt_out, &p_vout->p_picture[0], &p_vout->fmt_out,
p_subpic, &p_vout->fmt_in, b_paused ); p_subpic, &p_vout->fmt_in, render_date );
} }
vout_UnlockPicture( p_vout, &p_vout->p_picture[0] ); vout_UnlockPicture( p_vout, &p_vout->p_picture[0] );
......
...@@ -149,7 +149,8 @@ static void SpuRenderRegion( spu_t *, ...@@ -149,7 +149,8 @@ static void SpuRenderRegion( spu_t *,
subpicture_t *, subpicture_region_t *, subpicture_t *, subpicture_region_t *,
const spu_scale_t scale_size, const spu_scale_t scale_size,
const video_format_t *p_fmt, const video_format_t *p_fmt,
const spu_area_t *p_subtitle_area, int i_subtitle_area ); const spu_area_t *p_subtitle_area, int i_subtitle_area,
mtime_t render_date );
static void UpdateSPU ( spu_t *, vlc_object_t * ); static void UpdateSPU ( spu_t *, vlc_object_t * );
static int CropCallback( vlc_object_t *, char const *, static int CropCallback( vlc_object_t *, char const *,
...@@ -350,13 +351,15 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic ) ...@@ -350,13 +351,15 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
void spu_RenderSubpictures( spu_t *p_spu, void spu_RenderSubpictures( spu_t *p_spu,
picture_t *p_pic_dst, const video_format_t *p_fmt_dst, picture_t *p_pic_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, bool b_paused ) const video_format_t *p_fmt_src,
mtime_t render_date )
{ {
spu_private_t *p_sys = p_spu->p; spu_private_t *p_sys = p_spu->p;
const mtime_t system_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;
const mtime_t i_current_date = mdate();
unsigned int i_subpicture; unsigned int i_subpicture;
subpicture_t *pp_subpicture[VOUT_MAX_SUBPICTURES]; subpicture_t *pp_subpicture[VOUT_MAX_SUBPICTURES];
...@@ -375,11 +378,11 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -375,11 +378,11 @@ void spu_RenderSubpictures( spu_t *p_spu,
p_subpic != NULL; p_subpic != NULL;
p_subpic = p_subpic->p_next ) p_subpic = p_subpic->p_next )
{ {
/* */ /* TODO remove pre-render */
if( !b_paused && p_subpic->pf_pre_render ) if( p_subpic->pf_pre_render )
p_subpic->pf_pre_render( p_spu, p_subpic, p_fmt_dst ); p_subpic->pf_pre_render( p_spu, p_subpic, p_fmt_dst );
if( !b_paused && p_subpic->pf_update_regions ) if( p_subpic->pf_update_regions )
{ {
video_format_t fmt_org = *p_fmt_dst; video_format_t fmt_org = *p_fmt_dst;
fmt_org.i_width = fmt_org.i_width =
...@@ -387,7 +390,8 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -387,7 +390,8 @@ void spu_RenderSubpictures( spu_t *p_spu,
fmt_org.i_height = fmt_org.i_height =
fmt_org.i_visible_height = i_source_video_height; fmt_org.i_visible_height = i_source_video_height;
p_subpic->pf_update_regions( p_spu, p_subpic, &fmt_org, i_current_date ); p_subpic->pf_update_regions( p_spu, p_subpic, &fmt_org,
p_subpic->b_subtitle ? render_date : system_date );
} }
/* */ /* */
...@@ -505,7 +509,8 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -505,7 +509,8 @@ void spu_RenderSubpictures( spu_t *p_spu,
/* */ /* */
SpuRenderRegion( p_spu, p_pic_dst, &area, SpuRenderRegion( p_spu, p_pic_dst, &area,
p_subpic, p_region, scale, p_fmt_dst, p_subpic, p_region, scale, p_fmt_dst,
p_subtitle_area, i_subtitle_area ); p_subtitle_area, i_subtitle_area,
p_subpic->b_subtitle ? render_date : system_date );
if( p_subpic->b_subtitle ) if( p_subpic->b_subtitle )
{ {
...@@ -540,12 +545,13 @@ void spu_RenderSubpictures( spu_t *p_spu, ...@@ -540,12 +545,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 display_date, subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_date,
bool b_paused, bool b_subtitle_only ) bool b_subtitle_only )
{ {
spu_private_t *p_sys = p_spu->p; spu_private_t *p_sys = p_spu->p;
int i_channel; int i_channel;
subpicture_t *p_subpic = NULL; subpicture_t *p_subpic = NULL;
const mtime_t system_date = mdate();
/* Update sub-filter chain */ /* Update sub-filter chain */
vlc_mutex_lock( &p_sys->lock ); vlc_mutex_lock( &p_sys->lock );
...@@ -563,7 +569,7 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date, ...@@ -563,7 +569,7 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
} }
/* Run subpicture filters */ /* Run subpicture filters */
filter_chain_SubFilter( p_sys->p_chain, display_date ); filter_chain_SubFilter( p_sys->p_chain, render_date );
vlc_mutex_lock( &p_sys->lock ); vlc_mutex_lock( &p_sys->lock );
...@@ -575,8 +581,9 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date, ...@@ -575,8 +581,9 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
bool pb_available_late[VOUT_MAX_SUBPICTURES]; bool pb_available_late[VOUT_MAX_SUBPICTURES];
int i_available = 0; int i_available = 0;
mtime_t start_date = display_date; mtime_t start_date = render_date;
mtime_t ephemer_date = 0; mtime_t ephemer_subtitle_date = 0;
mtime_t ephemer_system_date = 0;
int i_index; int i_index;
/* Select available pictures */ /* Select available pictures */
...@@ -599,25 +606,25 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date, ...@@ -599,25 +606,25 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
{ {
continue; continue;
} }
if( display_date && if( render_date &&
display_date < p_current->i_start ) render_date < p_current->i_start )
{ {
/* Too early, come back next monday */ /* Too early, come back next monday */
continue; continue;
} }
if( p_current->i_start > ephemer_date ) mtime_t *pi_ephemer_date = p_current->b_subtitle ? &ephemer_subtitle_date : &ephemer_system_date;
ephemer_date = p_current->i_start; if( p_current->i_start > *pi_ephemer_date )
*pi_ephemer_date = p_current->i_start;
b_stop_valid = ( !p_current->b_ephemer || p_current->i_stop > p_current->i_start ) && b_stop_valid = !p_current->b_ephemer || p_current->i_stop > p_current->i_start;
( !p_current->b_subtitle || !b_paused ); /* XXX Assume that subtitle are pausable */
b_late = b_stop_valid && p_current->i_stop <= display_date; b_late = b_stop_valid && p_current->i_stop <= p_current->b_subtitle ? render_date : system_date;
/* start_date will be used for correct automatic overlap support /* start_date will be used for correct automatic overlap support
* in case picture that should not be displayed anymore (display_time) * in case picture that should not be displayed anymore (display_time)
* overlap with a picture to be displayed (p_current->i_start) */ * overlap with a picture to be displayed (p_current->i_start) */
if( !b_late && !p_current->b_ephemer ) if( p_current->b_subtitle && !b_late && !p_current->b_ephemer )
start_date = p_current->i_start; start_date = p_current->i_start;
/* */ /* */
...@@ -638,7 +645,10 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date, ...@@ -638,7 +645,10 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
subpicture_t *p_current = p_available_subpic[i_index]; subpicture_t *p_current = p_available_subpic[i_index];
bool b_late = pb_available_late[i_index]; bool b_late = pb_available_late[i_index];
if( ( b_late && p_current->i_stop <= __MAX( start_date, p_sys->i_last_sort_date ) ) || const mtime_t stop_date = p_current->b_subtitle ? __MAX( start_date, p_sys->i_last_sort_date ) : system_date;
const mtime_t ephemer_date = p_current->b_subtitle ? ephemer_subtitle_date : ephemer_system_date;
if( ( b_late && p_current->i_stop <= stop_date ) ||
( p_current->b_ephemer && p_current->i_start < ephemer_date ) ) ( p_current->b_ephemer && p_current->i_start < ephemer_date ) )
{ {
/* Destroy late and obsolete ephemer subpictures */ /* Destroy late and obsolete ephemer subpictures */
...@@ -651,7 +661,7 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date, ...@@ -651,7 +661,7 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
} }
} }
p_sys->i_last_sort_date = display_date; p_sys->i_last_sort_date = render_date;
vlc_mutex_unlock( &p_sys->lock ); vlc_mutex_unlock( &p_sys->lock );
return p_subpic; return p_subpic;
...@@ -1034,7 +1044,7 @@ static void SpuRenderCreateAndLoadScale( spu_t *p_spu ) ...@@ -1034,7 +1044,7 @@ static void SpuRenderCreateAndLoadScale( spu_t *p_spu )
static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text, static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
subpicture_t *p_subpic, subpicture_region_t *p_region, subpicture_t *p_subpic, subpicture_region_t *p_region,
int i_min_scale_ratio ) int i_min_scale_ratio, mtime_t render_date )
{ {
filter_t *p_text = p_spu->p->p_text; filter_t *p_text = p_spu->p->p_text;
...@@ -1063,7 +1073,7 @@ static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text, ...@@ -1063,7 +1073,7 @@ static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
* the text over time. * the text over time.
*/ */
var_SetTime( p_text, "spu-duration", p_subpic->i_stop - p_subpic->i_start ); var_SetTime( p_text, "spu-duration", p_subpic->i_stop - p_subpic->i_start );
var_SetTime( p_text, "spu-elapsed", mdate() - p_subpic->i_start ); var_SetTime( p_text, "spu-elapsed", render_date );
var_SetBool( p_text, "text-rerender", false ); var_SetBool( p_text, "text-rerender", false );
var_SetInteger( p_text, "scale", i_min_scale_ratio ); var_SetInteger( p_text, "scale", i_min_scale_ratio );
...@@ -1326,7 +1336,8 @@ static void SpuRenderRegion( spu_t *p_spu, ...@@ -1326,7 +1336,8 @@ static void SpuRenderRegion( spu_t *p_spu,
subpicture_t *p_subpic, subpicture_region_t *p_region, subpicture_t *p_subpic, subpicture_region_t *p_region,
const spu_scale_t scale_size, const spu_scale_t scale_size,
const video_format_t *p_fmt, const video_format_t *p_fmt,
const spu_area_t *p_subtitle_area, int i_subtitle_area ) const spu_area_t *p_subtitle_area, int i_subtitle_area,
mtime_t render_date )
{ {
spu_private_t *p_sys = p_spu->p; spu_private_t *p_sys = p_spu->p;
...@@ -1346,7 +1357,8 @@ static void SpuRenderRegion( spu_t *p_spu, ...@@ -1346,7 +1357,8 @@ static void SpuRenderRegion( spu_t *p_spu,
if( p_region->fmt.i_chroma == VLC_CODEC_TEXT ) if( p_region->fmt.i_chroma == VLC_CODEC_TEXT )
{ {
const int i_min_scale_ratio = SCALE_UNIT; /* FIXME what is the right value? (scale_size is not) */ const int i_min_scale_ratio = SCALE_UNIT; /* FIXME what is the right value? (scale_size is not) */
SpuRenderText( p_spu, &b_rerender_text, p_subpic, p_region, i_min_scale_ratio ); SpuRenderText( p_spu, &b_rerender_text, p_subpic, p_region,
i_min_scale_ratio, render_date );
b_restore_format = b_rerender_text; b_restore_format = b_rerender_text;
/* Check if the rendering has failed ... */ /* Check if the rendering has failed ... */
......
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