[vlc-devel] [PATCH] Subtitles fps support

Yuval Tze yuvaltze at gmail.com
Sat Apr 30 16:27:18 CEST 2011


add DEMUX_SET_FPS demux command
handle fps in the subtitle demux
add INPUT_CONTROL_SET_SUB_FPS event
monitor sub-fps variable changes
---
 include/vlc_demux.h               |    1 +
 include/vlc_input.h               |    2 +
 modules/demux/subtitle.c          |   72 +++++++++++++++++++++++++++++++++---
 modules/gui/qt4/input_manager.cpp |    1 +
 src/input/event.c                 |   10 +++++
 src/input/event.h                 |    1 +
 src/input/input.c                 |   26 ++++++++++----
 src/input/input_internal.h        |    1 +
 src/input/var.c                   |   16 ++++++++
 9 files changed, 117 insertions(+), 13 deletions(-)

diff --git a/include/vlc_demux.h b/include/vlc_demux.h
index c3f32e5..12991b9 100644
--- a/include/vlc_demux.h
+++ b/include/vlc_demux.h
@@ -124,6 +124,7 @@ enum demux_query_e
     DEMUX_SET_NEXT_DEMUX_TIME,  /* arg1= int64_t *      can fail */
     /* FPS for correct subtitles handling */
     DEMUX_GET_FPS,              /* arg1= double *       res=can fail    */
+    DEMUX_SET_FPS,              /* arg1= double         res=can fail    */
 
     /* Meta data */
     DEMUX_GET_META,             /* arg1= vlc_meta_t **  res=can fail    */
diff --git a/include/vlc_input.h b/include/vlc_input.h
index afa7a81..872b318 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -427,6 +427,8 @@ typedef enum input_event_type_e
     INPUT_EVENT_AUDIO_DELAY,
     /* "spu-delay" has changed */
     INPUT_EVENT_SUBTITLE_DELAY,
+    /* "sub-fps" has changed */
+    INPUT_EVENT_SUBTITLE_FPS,
 
     /* "bookmark" has changed */
     INPUT_EVENT_BOOKMARK,
diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c
index 7fcd8d6..cf0044f 100644
--- a/modules/demux/subtitle.c
+++ b/modules/demux/subtitle.c
@@ -154,6 +154,11 @@ struct demux_sys_t
 
     int64_t     i_length;
 
+    double      f_original_fps;
+    double      f_requested_fps;
+    double      f_fps_ratio;
+    bool        b_fps_updated;
+
     /* */
     struct
     {
@@ -228,6 +233,21 @@ static int Control( demux_t *, int, va_list );
 
 static void Fix( demux_t * );
 
+/*
+ * Internal timestamp is the time used by the demux source (the time it got from
+ * the subtitles files).
+ * External timestamp is the time used by the demux controller (as it seen outside
+ * of the demux).
+ *
+ * the input of the control function is external time and should be translated
+ * to internal time before using it.
+ * the output of the control and the demux functions is internal time and should
+ * be translated to external time before returning it.
+ */
+
+#define ToInternalTs( p_sys, t ) ( ( t ) * ( p_sys )->f_fps_ratio )
+#define ToExternalTs( p_sys, t ) ( ( t ) / ( p_sys )->f_fps_ratio )
+
 /*****************************************************************************
  * Module initializer
  *****************************************************************************/
@@ -262,10 +282,18 @@ static int Open ( vlc_object_t *p_this )
     p_sys->jss.b_inited       = false;
     p_sys->mpsub.b_inited     = false;
 
+    p_sys->f_original_fps     = 1.0;
+    p_sys->f_requested_fps    = 1.0;
+    p_sys->f_fps_ratio        = 1.0;
+    p_sys->b_fps_updated      = false;
+
     /* Get the FPS */
     f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" ); /* FIXME */
     if( f_fps >= 1.0 )
+    {
         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
+        p_sys->f_original_fps = f_fps;
+    }
 
     msg_Dbg( p_demux, "Movie fps: %f", f_fps );
 
@@ -275,6 +303,8 @@ static int Open ( vlc_object_t *p_this )
     {
         p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
         msg_Dbg( p_demux, "Override subtitle fps %f", f_fps );
+        p_sys->f_requested_fps = f_fps;
+        p_sys->f_fps_ratio = p_sys->f_requested_fps / p_sys->f_original_fps;
     }
 
     /* Get or probe the type */
@@ -570,20 +600,20 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
     {
         case DEMUX_GET_LENGTH:
             pi64 = (int64_t*)va_arg( args, int64_t * );
-            *pi64 = p_sys->i_length;
+            *pi64 = ToExternalTs( p_sys, p_sys->i_length );
             return VLC_SUCCESS;
 
         case DEMUX_GET_TIME:
             pi64 = (int64_t*)va_arg( args, int64_t * );
             if( p_sys->i_subtitle < p_sys->i_subtitles )
             {
-                *pi64 = p_sys->subtitle[p_sys->i_subtitle].i_start;
+                *pi64 = ToExternalTs( p_sys, p_sys->subtitle[p_sys->i_subtitle].i_start );
                 return VLC_SUCCESS;
             }
             return VLC_EGENERIC;
 
         case DEMUX_SET_TIME:
-            i64 = (int64_t)va_arg( args, int64_t );
+            i64 = ToInternalTs( p_sys, (int64_t)va_arg( args, int64_t ) );
             p_sys->i_subtitle = 0;
             while( p_sys->i_subtitle < p_sys->i_subtitles )
             {
@@ -633,7 +663,36 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             return VLC_SUCCESS;
 
         case DEMUX_SET_NEXT_DEMUX_TIME:
-            p_sys->i_next_demux_date = (int64_t)va_arg( args, int64_t );
+            p_sys->i_next_demux_date = ToInternalTs( p_sys, (int64_t)va_arg( args, int64_t ) );
+
+            if( p_sys->b_fps_updated )
+            {
+                p_sys->i_subtitle = 0;
+                while( p_sys->i_subtitle < p_sys->i_subtitles &&
+                       p_sys->subtitle[p_sys->i_subtitle].i_start < p_sys->i_next_demux_date )
+                {
+                    p_sys->i_subtitle++;
+                }
+
+                p_sys->b_fps_updated = false;
+            }
+            return VLC_SUCCESS;
+
+        case DEMUX_SET_FPS:
+            f = (double)va_arg( args, double );
+            if ( f >= 1.0 )
+            {
+                /* Get current demux date */
+                i64 = ToExternalTs( p_sys, p_sys->i_next_demux_date );
+
+                p_sys->f_requested_fps = f;
+                p_sys->f_fps_ratio = p_sys->f_requested_fps / p_sys->f_original_fps;
+                p_sys->b_fps_updated = true;
+
+                /* Set new demux date */
+                p_sys->i_next_demux_date = ToInternalTs( p_sys, i64 );
+            }
+
             return VLC_SUCCESS;
 
         case DEMUX_GET_PTS_DELAY:
@@ -690,9 +749,10 @@ static int Demux( demux_t *p_demux )
         }
 
         p_block->i_dts =
-        p_block->i_pts = VLC_TS_0 + p_subtitle->i_start;
+        p_block->i_pts = ToExternalTs( p_sys, VLC_TS_0 + 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;
+            p_block->i_length = ToExternalTs( p_sys, p_subtitle->i_stop ) -
+                                ToExternalTs( p_sys, p_subtitle->i_start );
 
         memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
 
diff --git a/modules/gui/qt4/input_manager.cpp b/modules/gui/qt4/input_manager.cpp
index 6acb687..606eb17 100644
--- a/modules/gui/qt4/input_manager.cpp
+++ b/modules/gui/qt4/input_manager.cpp
@@ -347,6 +347,7 @@ static int InputEvent( vlc_object_t *p_this, const char *,
 
     case INPUT_EVENT_AUDIO_DELAY:
     case INPUT_EVENT_SUBTITLE_DELAY:
+    case INPUT_EVENT_SUBTITLE_FPS:
         event = new IMEvent( SynchroChanged_Type );
         break;
 
diff --git a/src/input/event.c b/src/input/event.c
index f0a4205..f91cc95 100644
--- a/src/input/event.c
+++ b/src/input/event.c
@@ -122,6 +122,16 @@ void input_SendEventSubtitleDelay( input_thread_t *p_input, mtime_t i_delay )
     Trigger( p_input, INPUT_EVENT_SUBTITLE_DELAY );
 }
 
+void input_SendEventSubtitleFps( input_thread_t *p_input, double f_fps )
+{
+    vlc_value_t val;
+
+    val.f_float = f_fps;
+    var_Change( p_input, "sub-fps", VLC_VAR_SETVALUE, &val, NULL );
+
+    Trigger( p_input, INPUT_EVENT_SUBTITLE_FPS );
+}
+
 /* TODO and file name ? */
 void input_SendEventRecord( input_thread_t *p_input, bool b_recording )
 {
diff --git a/src/input/event.h b/src/input/event.h
index 31eea4d..7507486 100644
--- a/src/input/event.h
+++ b/src/input/event.h
@@ -37,6 +37,7 @@ void input_SendEventStatistics( input_thread_t *p_input );
 void input_SendEventRate( input_thread_t *p_input, int i_rate );
 void input_SendEventAudioDelay( input_thread_t *p_input, mtime_t i_delay );
 void input_SendEventSubtitleDelay( input_thread_t *p_input, mtime_t i_delay );
+void input_SendEventSubtitleFps( input_thread_t *p_input, double f_fps );
 void input_SendEventRecord( input_thread_t *p_input, bool b_recording );
 void input_SendEventTitle( input_thread_t *p_input, int i_title );
 void input_SendEventSeekpoint( input_thread_t *p_input, int i_title, int i_seekpoint );
diff --git a/src/input/input.c b/src/input/input.c
index 63a1480..fcc12bc 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -1000,13 +1000,7 @@ static void LoadSubtitles( input_thread_t *p_input )
         var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
         var_SetFloat( p_input, "sub-original-fps", f_fps );
 
-        f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
-        if( f_requested_fps != f_fps )
-        {
-            var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
-                                            VLC_VAR_DOINHERIT );
-            var_SetFloat( p_input, "sub-fps", f_requested_fps );
-        }
+        var_SetFloat( p_input, "sub-fps", f_fps );
     }
 
     const int i_delay = var_CreateGetInteger( p_input, "sub-delay" );
@@ -1149,6 +1143,19 @@ static void UpdatePtsDelay( input_thread_t *p_input )
     es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, 0, i_cr_average );
 }
 
+static void UpdateSubFps( input_thread_t *p_input )
+{
+    input_thread_private_t *p_sys = p_input->p;
+
+    double f_fps = var_GetFloat( p_input, "sub-fps" );
+
+    for( int i = 0; i < p_sys->i_slave; i++ )
+    {
+        /* TODO: notify subtitles demuxes only */
+        demux_Control( p_sys->slave[i]->p_demux, DEMUX_SET_FPS, f_fps );
+    }
+}
+
 static void InitPrograms( input_thread_t * p_input )
 {
     int i_es_out_mode;
@@ -1898,6 +1905,11 @@ static bool Control( input_thread_t *p_input,
             UpdatePtsDelay( p_input );
             break;
 
+        case INPUT_CONTROL_SET_SUB_FPS:
+            input_SendEventSubtitleFps( p_input, val.f_float );
+            UpdateSubFps( p_input );
+            break;
+
         case INPUT_CONTROL_SET_TITLE:
         case INPUT_CONTROL_SET_TITLE_NEXT:
         case INPUT_CONTROL_SET_TITLE_PREV:
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index beaa856..d2bbb08 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -198,6 +198,7 @@ enum input_control_e
 
     INPUT_CONTROL_SET_AUDIO_DELAY,
     INPUT_CONTROL_SET_SPU_DELAY,
+    INPUT_CONTROL_SET_SUB_FPS,
 
     INPUT_CONTROL_ADD_SLAVE,
 
diff --git a/src/input/var.c b/src/input/var.c
index b516ffb..ec786ff 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -59,6 +59,8 @@ static int ESCallback      ( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
 static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
+static int EsFpsCallback   ( vlc_object_t *p_this, char const *psz_cmd,
+                             vlc_value_t oldval, vlc_value_t newval, void * );
 
 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval, void * );
@@ -98,6 +100,7 @@ static const vlc_input_callback_t p_input_callbacks[] =
     CALLBACK( "chapter", SeekpointCallback ),
     CALLBACK( "audio-delay", EsDelayCallback ),
     CALLBACK( "spu-delay", EsDelayCallback ),
+    CALLBACK( "sub-fps", EsFpsCallback ),
     CALLBACK( "video-es", ESCallback ),
     CALLBACK( "audio-es", ESCallback ),
     CALLBACK( "spu-es", ESCallback ),
@@ -197,6 +200,8 @@ void input_ControlVarInit ( input_thread_t *p_input )
     val.i_time = 0;
     var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
 
+    var_Create( p_input, "sub-fps", VLC_VAR_FLOAT );
+
     /* Video ES */
     var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
     text.psz_string = _("Video Track");
@@ -787,6 +792,17 @@ static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
     return VLC_SUCCESS;
 }
 
+static int EsFpsCallback ( vlc_object_t *p_this, char const *psz_cmd,
+                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    input_thread_t *p_input = (input_thread_t*)p_this;
+    VLC_UNUSED(oldval); VLC_UNUSED(p_data);
+
+    input_ControlPush( p_input, INPUT_CONTROL_SET_SUB_FPS, &newval );
+
+    return VLC_SUCCESS;
+}
+
 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
                              vlc_value_t oldval, vlc_value_t newval,
                              void *p_data )
-- 
1.7.1




More information about the vlc-devel mailing list