Improved subtitle rendering accuracy and fixed pause on dynamic subtitles.
authorLaurent Aimar <fenrir@videolan.org>
Sun, 26 Jul 2009 21:59:53 +0000 (23:59 +0200)
committerLaurent Aimar <fenrir@videolan.org>
Mon, 27 Jul 2009 19:27:25 +0000 (21:27 +0200)
Dynamic subtitles are used by ssa and kate.
This commit breaks the API for 2 functions used by the transcode module.

include/vlc_osd.h
modules/stream_out/transcode.c
src/video_output/video_output.c
src/video_output/vout_internal.h
src/video_output/vout_pictures.c
src/video_output/vout_subpictures.c

index 310b6f0..baae6f3 100644 (file)
@@ -115,7 +115,7 @@ VLC_EXPORT( void, spu_DisplaySubpicture, ( spu_t *, subpicture_t * ) );
  *
  * 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.
@@ -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_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 ) );
 
 /** @}*/
 
index 79013d4..b0b1126 100644 (file)
@@ -1910,8 +1910,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
         /* 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 /* Fixme: check if stream is paused */, false );
+            p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false );
             /* TODO: get another pic */
         }
 
@@ -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_den = VOUT_ASPECT_FACTOR;
 
+            /* FIXME the mdate() seems highly suspicious */
             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 */
@@ -2334,7 +2334,7 @@ static int transcode_osd_process( sout_stream_t *p_stream,
     /* Check if we have a subpicture to send */
     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
     {
index 5b9e730..280d0be 100644 (file)
@@ -1177,17 +1177,24 @@ static void* RunThread( void *p_this )
         /*
          * 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;
-        if( display_date > 0 )
-            p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
-                                            p_vout->p->b_paused, b_snapshot );
+        if( spu_render_time > 1 )
+            p_subpic = spu_SortSubpictures( p_vout->p_spu,
+                                            spu_render_time, b_snapshot );
 
         /*
          * Perform rendering
          */
         p_vout->p->i_picture_displayed++;
-        p_directbuffer = vout_RenderPicture( p_vout, p_filtered_picture,
-                                             p_subpic, p_vout->p->b_paused );
+        p_directbuffer = vout_RenderPicture( p_vout,
+                                             p_filtered_picture, p_subpic,
+                                             spu_render_time );
 
         /*
          * Take a snapshot if requested
index eb9fd17..773008e 100644 (file)
@@ -107,7 +107,8 @@ struct vout_thread_sys_t
 
 /* DO NOT use vout_RenderPicture unless you are in src/video_ouput */
 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
  *
index 48238aa..e639353 100644 (file)
@@ -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.
  */
 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 )
         return NULL;
@@ -356,7 +356,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
 
             spu_RenderSubpictures( p_vout->p_spu,
                                    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] );
 
@@ -383,7 +383,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         picture_Copy( PP_OUTPUTPICTURE[0], p_pic );
         spu_RenderSubpictures( p_vout->p_spu,
                                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] );
 
@@ -419,7 +419,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         /* Render subpictures on the first direct buffer */
         spu_RenderSubpictures( p_vout->p_spu,
                                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] ) )
             return NULL;
@@ -438,7 +438,7 @@ picture_t *vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
         /* Render subpictures on the first direct buffer */
         spu_RenderSubpictures( p_vout->p_spu,
                                &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] );
index 4b4afd1..5ee652f 100644 (file)
@@ -149,7 +149,8 @@ static void SpuRenderRegion( spu_t *,
                              subpicture_t *, subpicture_region_t *,
                              const spu_scale_t scale_size,
                              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 int  CropCallback( vlc_object_t *, char const *,
@@ -350,13 +351,15 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
 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, bool b_paused )
+                            const video_format_t *p_fmt_src,
+                            mtime_t render_date )
 {
     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_height = p_fmt_src->i_height;
-    const mtime_t i_current_date = mdate();
 
     unsigned int i_subpicture;
     subpicture_t *pp_subpicture[VOUT_MAX_SUBPICTURES];
@@ -375,11 +378,11 @@ void spu_RenderSubpictures( spu_t *p_spu,
             p_subpic != NULL;
                 p_subpic = p_subpic->p_next )
     {
-        /* */
-        if( !b_paused && p_subpic->pf_pre_render )
+        /* TODO remove pre-render */
+        if( p_subpic->pf_pre_render )
             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;
             fmt_org.i_width =
@@ -387,7 +390,8 @@ void spu_RenderSubpictures( spu_t *p_spu,
             fmt_org.i_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,
             /* */
             SpuRenderRegion( p_spu, p_pic_dst, &area,
                              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 )
             {
@@ -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
  * 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,
-                                   bool b_paused, bool b_subtitle_only )
+subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t render_date,
+                                   bool b_subtitle_only )
 {
     spu_private_t *p_sys = p_spu->p;
     int i_channel;
     subpicture_t *p_subpic = NULL;
+    const mtime_t system_date = mdate();
 
     /* Update sub-filter chain */
     vlc_mutex_lock( &p_sys->lock );
@@ -563,7 +569,7 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
     }
 
     /* 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 );
 
@@ -575,8 +581,9 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
         bool         pb_available_late[VOUT_MAX_SUBPICTURES];
         int          i_available = 0;
 
-        mtime_t      start_date = display_date;
-        mtime_t      ephemer_date = 0;
+        mtime_t      start_date = render_date;
+        mtime_t      ephemer_subtitle_date = 0;
+        mtime_t      ephemer_system_date = 0;
         int i_index;
 
         /* Select available pictures */
@@ -599,25 +606,25 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
             {
                 continue;
             }
-            if( display_date &&
-                display_date < p_current->i_start )
+            if( render_date &&
+                render_date < p_current->i_start )
             {
                 /* Too early, come back next monday */
                 continue;
             }
 
-            if( p_current->i_start > ephemer_date )
-                ephemer_date = p_current->i_start;
+            mtime_t *pi_ephemer_date = p_current->b_subtitle ? &ephemer_subtitle_date : &ephemer_system_date;
+            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 ) &&
-                           ( !p_current->b_subtitle || !b_paused ); /* XXX Assume that subtitle are pausable */
+            b_stop_valid = !p_current->b_ephemer || p_current->i_stop > p_current->i_start;
 
-            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
              * in case picture that should not be displayed anymore (display_time)
              * 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;
 
             /* */
@@ -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];
             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 ) )
             {
                 /* Destroy late and obsolete ephemer subpictures */
@@ -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 );
 
     return p_subpic;
@@ -1034,7 +1044,7 @@ static void SpuRenderCreateAndLoadScale( spu_t *p_spu )
 
 static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
                            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;
 
@@ -1063,7 +1073,7 @@ static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
      * the text over time.
      */
     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_SetInteger( p_text, "scale", i_min_scale_ratio );
 
@@ -1326,7 +1336,8 @@ static void SpuRenderRegion( spu_t *p_spu,
                              subpicture_t *p_subpic, subpicture_region_t *p_region,
                              const spu_scale_t scale_size,
                              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;
 
@@ -1346,7 +1357,8 @@ static void SpuRenderRegion( spu_t *p_spu,
     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) */
-        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;
 
         /* Check if the rendering has failed ... */