[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