[vlc-devel] [PATCH] Fix https://trac.videolan.org/vlc/ticket/10749 Video was getting stuck while using subtitle delay option when setting a negative subtitle delay.

Pascal Thomet pthomet at gmail.com
Sat Sep 30 19:16:35 CEST 2017


Steps to reproduce the problem:
* load a video + srt sub
* open the "Track synchro" window
* enter -10s or +10s in the subtitle delay => video will be frozen for 10 seconds

Modifications:
**************

Note : you can see this patch online at https://github.com/pthom/vlc/commit/33742f3e76f7930e85506c23848975f2156427ea

modules/demux/subtitle.c:
* Added adjust_subtitle_time : adjust_subtitle_time returns a timestamp corrected by spu-delay
* Added set_current_subtitle_by_time: sets the current subtitle index, returns true if index changed,
  i.e a new subtitle should be displayed

Note : the code was using var_GetInteger (add thus could not see the correct spu-delay). This was corrected by using var_InheritInteger

src/input/var.c:
* Added var "sub-isfilesub" : will be set to true if the sub is a file sub

src/input/input.c:
* UpdatePtsDelay now only applies a delay if var "sub-isfilesub" is false.
* Init resets the var "spu-delay" (when loading a new movie)
* Set var "sub-isfilesub" to false by default, then sets it to true inside input_SlaveSourceAdd
  (if  i_type == SLAVE_TYPE_SPU )
---
 modules/control/hotkeys.c |  10 -----
 modules/demux/subtitle.c  | 108 +++++++++++++++++++++++++++++++---------------
 src/input/input.c         |  17 +++++++-
 src/input/var.c           |   9 +++-
 4 files changed, 97 insertions(+), 47 deletions(-)

diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c
index 690a4e5e6c..1f2f4a8a80 100644
--- a/modules/control/hotkeys.c
+++ b/modules/control/hotkeys.c
@@ -630,16 +630,6 @@ static int PutAction( intf_thread_t *p_intf, input_thread_t *p_input,
             break;
         case ACTIONID_SUBSYNC_APPLY:
         {
-            /* Warning! Can yield a pause in the playback.
-             * For example, the following succession of actions will yield a 5 second delay :
-             * - Pressing Shift-H (ACTIONID_SUBSYNC_MARKAUDIO)
-             * - wait 5 second
-             * - Press Shift-J (ACTIONID_SUBSYNC_MARKSUB)
-             * - Press Shift-K (ACTIONID_SUBSYNC_APPLY)
-             * --> 5 seconds pause
-             * This is due to var_SetTime() (and ultimately UpdatePtsDelay())
-             * which causes the video to pause for an equivalent duration
-             * (This problem is also present in the "Track synchronization" window) */
             if ( p_input )
             {
                 if ( (p_sys->subtitle_delaybookmarks.i_time_audio == 0) || (p_sys->subtitle_delaybookmarks.i_time_subtitle == 0) )
diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c
index 89f1198114..bbf7e1bcab 100644
--- a/modules/demux/subtitle.c
+++ b/modules/demux/subtitle.c
@@ -131,6 +131,7 @@ static void TextUnload( text_t * );
 
 typedef struct
 {
+    /* subtitle timestamps : use with adjust_subtitle_time() to include spu-delay */
     int64_t i_start;
     int64_t i_stop;
 
@@ -175,6 +176,7 @@ struct demux_sys_t
     bool        b_first_time;
 
     int64_t     i_next_demux_date;
+    int64_t     i_last_spu_delay;
 
     struct
     {
@@ -250,6 +252,8 @@ static int Control( demux_t *, int, va_list );
 
 static void Fix( demux_t * );
 static char * get_language_from_filename( const char * );
+static int64_t adjust_subtitle_time( demux_t *, int64_t);
+static bool set_current_subtitle_by_time(demux_t *p_demux, int64_t i64_when);
 
 /*****************************************************************************
  * Decoder format output function
@@ -324,6 +328,7 @@ static int Open ( vlc_object_t *p_this )
     p_sys->b_slave = false;
     p_sys->b_first_time = true;
     p_sys->i_next_demux_date = 0;
+    p_sys->i_last_spu_delay = 0;
 
     p_sys->pf_convert = ToTextBlock;
 
@@ -798,24 +803,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
 
         case DEMUX_GET_TIME:
             pi64 = va_arg( args, int64_t * );
-            *pi64 = p_sys->i_next_demux_date - var_GetInteger( p_demux->obj.parent, "spu-delay" );
-            if( *pi64 < 0 )
-               *pi64 = p_sys->i_next_demux_date;
+            *pi64 = adjust_subtitle_time(p_demux, p_sys->subtitles.p_array[p_sys->subtitles.i_current].i_start);
             return VLC_SUCCESS;
 
         case DEMUX_SET_TIME:
             i64 = va_arg( args, int64_t );
-            for( size_t i = 0; i + 1< p_sys->subtitles.i_count; i++ )
-            {
-                if( p_sys->subtitles.p_array[i + 1].i_start >= i64 )
-                {
-                    p_sys->subtitles.i_current = i;
-                    p_sys->i_next_demux_date = i64;
-                    p_sys->b_first_time = true;
-                    return VLC_SUCCESS;
-                }
-            }
-            break;
+            set_current_subtitle_by_time(p_demux, i64);
+            return VLC_SUCCESS;
 
         case DEMUX_GET_POSITION:
             pf = va_arg( args, double * );
@@ -825,10 +819,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             }
             else if( p_sys->subtitles.i_count > 0 && p_sys->i_length )
             {
-                *pf = p_sys->i_next_demux_date - var_GetInteger( p_demux->obj.parent, "spu-delay" );
-                if( *pf < 0 )
-                    *pf = p_sys->i_next_demux_date;
-                *pf /= p_sys->i_length;
+                int64_t i_start_adjust = adjust_subtitle_time(p_demux, p_sys->i_next_demux_date);
+                *pf = (double)i_start_adjust / (double)p_sys->i_length;
             }
             else
             {
@@ -871,41 +863,45 @@ static int Demux( demux_t *p_demux )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
 
-    int64_t i_barrier = p_sys->i_next_demux_date - var_GetInteger( p_demux->obj.parent, "spu-delay" );
-    if( i_barrier < 0 )
-        i_barrier = p_sys->i_next_demux_date;
-
-    while( p_sys->subtitles.i_current < p_sys->subtitles.i_count &&
-           p_sys->subtitles.p_array[p_sys->subtitles.i_current].i_start <= i_barrier )
+    int64_t i_adjusted_next_demux_date = adjust_subtitle_time(p_demux, p_sys->i_next_demux_date);
+    if ( !p_sys->b_slave && p_sys->b_first_time )
     {
-        const subtitle_t *p_subtitle = &p_sys->subtitles.p_array[p_sys->subtitles.i_current];
+        es_out_SetPCR( p_demux->out, VLC_TS_0 + i_adjusted_next_demux_date );
+        p_sys->b_first_time = false;
+    }
 
-        if ( !p_sys->b_slave && p_sys->b_first_time )
-        {
-            es_out_SetPCR( p_demux->out, VLC_TS_0 + i_barrier );
-            p_sys->b_first_time = false;
-        }
+    /* log if detected spu-delay changes */
+    int64_t spu_delay = var_InheritInteger(p_demux->obj.parent, "spu-delay");
+    if (spu_delay != p_sys->i_last_spu_delay)
+    {
+        msg_Info( p_demux->obj.parent,
+                 "Detected spu-delay change from %lld to %lld",
+                 p_sys->i_last_spu_delay / 1000, spu_delay / 1000);
+        p_sys->i_last_spu_delay = spu_delay;
+    }
 
-        if( p_subtitle->i_start >= 0 )
+    bool b_is_new_subtitle = set_current_subtitle_by_time(p_demux, p_sys->i_next_demux_date);
+    if ( b_is_new_subtitle )
+    {
+        const subtitle_t *p_subtitle = &p_sys->subtitles.p_array[p_sys->subtitles.i_current];
+        if ( p_subtitle->i_start >= 0 )
         {
             block_t *p_block = p_sys->pf_convert( p_subtitle );
             if( p_block )
             {
                 p_block->i_dts =
-                p_block->i_pts = VLC_TS_0 + p_subtitle->i_start;
+                p_block->i_pts = VLC_TS_0 + adjust_subtitle_time(p_demux, p_subtitle->i_start);
                 if( p_subtitle->i_stop >= 0 && p_subtitle->i_stop >= p_subtitle->i_start )
                     p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
 
                 es_out_Send( p_demux->out, p_sys->es, p_block );
             }
         }
-
-        p_sys->subtitles.i_current++;
     }
 
     if ( !p_sys->b_slave )
     {
-        es_out_SetPCR( p_demux->out, VLC_TS_0 + i_barrier );
+        es_out_SetPCR( p_demux->out, VLC_TS_0 + i_adjusted_next_demux_date );
         p_sys->i_next_demux_date += CLOCK_FREQ / 8;
     }
 
@@ -916,6 +912,48 @@ static int Demux( demux_t *p_demux )
 }
 
 
+/*****************************************************************************
+ * adjust_subtitle_time & set_current_subtitle_by_time : handle the spu-delay
+ *
+ * - adjust_subtitle_time : return a timestamp corrected by spu-delay
+ * - set_current_subtitle_by_time : sets the current subtitle index
+ *     returns true if index changed, i.e a new subtitle should be displayed
+ *****************************************************************************/
+static int64_t adjust_subtitle_time( demux_t * p_demux, int64_t i64_when)
+{
+    int64_t spu_delay = var_InheritInteger(p_demux->obj.parent, "spu-delay");
+    int64_t i64_adjust = i64_when + spu_delay;
+    if (i64_adjust < 0)
+        i64_adjust = 0;
+    return i64_adjust;
+}
+
+static bool set_current_subtitle_by_time(demux_t *p_demux, int64_t i64_when)
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    size_t i_new_current_sub = 0;
+    while( i_new_current_sub < p_sys->subtitles.i_count )
+    {
+        const subtitle_t *p_subtitle = &p_sys->subtitles.p_array[i_new_current_sub];
+        if( adjust_subtitle_time(p_demux, p_subtitle->i_start) > i64_when )
+            break;
+        if(    ( p_subtitle->i_stop > p_subtitle->i_start )
+            && ( adjust_subtitle_time(p_demux, p_subtitle->i_stop) > i64_when ) )
+            break;
+
+        i_new_current_sub++;
+    }
+    if( i_new_current_sub >= p_sys->subtitles.i_count )
+    {
+        p_sys->subtitles.i_current = p_sys->subtitles.i_count - 1;
+    }
+
+    bool b_changed = ( p_sys->subtitles.i_current != i_new_current_sub);
+    p_sys->subtitles.i_current = i_new_current_sub;
+    return b_changed;
+}
+
 static int subtitle_cmp( const void *first, const void *second )
 {
     int64_t result = ((subtitle_t *)(first))->i_start - ((subtitle_t *)(second))->i_start;
diff --git a/src/input/input.c b/src/input/input.c
index 9d8f145777..1e7dcf8f8e 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -1066,6 +1066,9 @@ static void LoadSlaves( input_thread_t *p_input )
     int i_slaves;
     TAB_INIT( i_slaves, pp_slaves );
 
+    /* sub-isfilesub will be set to true inside input_SlaveSourceAdd (if needed)*/
+    var_SetBool(p_input, "sub-isfilesub", false);
+
     /* Look for and add slaves */
 
     char *psz_subtitle = var_GetNonEmptyString( p_input, "sub-file" );
@@ -1221,7 +1224,14 @@ static void UpdatePtsDelay( input_thread_t *p_input )
     /* Take care of audio/spu delay */
     const mtime_t i_audio_delay = var_GetInteger( p_input, "audio-delay" );
     const mtime_t i_spu_delay   = var_GetInteger( p_input, "spu-delay" );
-    const mtime_t i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
+    bool isfilesub = var_GetBool(p_input, "sub-isfilesub");
+
+    mtime_t i_extra_delay;
+    if ( isfilesub )
+        i_extra_delay = i_audio_delay;
+    else
+        i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
+
     if( i_extra_delay < 0 )
         i_pts_delay -= i_extra_delay;
 
@@ -1308,6 +1318,9 @@ static int Init( input_thread_t * p_input )
         var_SetBool( p_input, "sub-autodetect-file", false );
     }
 
+    /* reset spu-delay on Init */
+    var_SetInteger(p_input, "spu-delay", 0);
+
     InitStatistics( p_input );
 #ifdef ENABLE_SOUT
     if( InitSout( p_input ) )
@@ -3317,6 +3330,8 @@ static int input_SlaveSourceAdd( input_thread_t *p_input,
         return VLC_EGENERIC;
     }
 
+    if ( i_type == SLAVE_TYPE_SPU )
+        var_SetBool(p_input, "sub-isfilesub", true);
     if( i_type == SLAVE_TYPE_AUDIO )
     {
         if( b_set_time )
diff --git a/src/input/var.c b/src/input/var.c
index f41dac5e9e..949190c156 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -188,6 +188,11 @@ void input_ControlVarInit ( input_thread_t *p_input )
                     1000 * var_GetInteger( p_input, "audio-desync" ) );
     var_Create( p_input, "spu-delay", VLC_VAR_INTEGER );
 
+    /* sub-isfilesub : true for *.srt & the like, false otherwise (for example dvd subtitles) */
+    var_Create( p_input, "sub-isfilesub", VLC_VAR_BOOL );
+    val.b_bool = false;
+    var_Change( p_input, "sub-isfilesub", VLC_VAR_SETVALUE, &val, 0 );
+
     val.i_int = -1;
     /* Video ES */
     var_Create( p_input, "video-es", VLC_VAR_INTEGER );
@@ -819,7 +824,9 @@ static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
     }
     else if( !strcmp( psz_cmd, "spu-delay" ) )
     {
-        input_ControlPush( p_input, INPUT_CONTROL_SET_SPU_DELAY, &newval );
+        bool isfilesub = var_GetBool(p_input, "sub-isfilesub");
+        if ( ! isfilesub )
+            input_ControlPush( p_input, INPUT_CONTROL_SET_SPU_DELAY, &newval );
     }
     return VLC_SUCCESS;
 }
-- 
2.12.2



More information about the vlc-devel mailing list