[vlc-devel] [PATCH 1/5] Subtitle delay : fixed sync problem that breaks audio under linux
Rémi Denis-Courmont
remi at remlab.net
Mon Jun 9 21:26:09 CEST 2014
Le lundi 9 juin 2014, 21:00:23 Pascal Thomet a écrit :
> @@ -1067,7 +1011,30 @@ static int ActionEvent( vlc_object_t *libvlc, char
> const *psz_var, (void)psz_var;
> (void)oldval;
>
> - return PutAction( p_intf, newval.i_int );
> + if ( strcmp( psz_var, "key-osdmessage") == 0)
> + {
> + if ( strlen(newval.psz_string) > 0 )
> + {
> + playlist_t *p_playlist = pl_Get( p_intf );
> + input_thread_t *p_input = playlist_CurrentInput( p_playlist );
> + if (p_input)
> + {
> + vout_thread_t *p_vout = p_input ? input_GetVout( p_input )
> : NULL;// XXXXDZFEEGVDS
> + if( p_vout )
> + {
> + DisplayMessage(p_vout, "%s", newval.psz_string);
> + vlc_object_release( p_vout );
> + }
> + vlc_object_release(p_input);
> + }
> +
> + }
> + return VLC_SUCCESS;
> + }
> + else
> + {
> + return PutAction( p_intf, newval.i_int );
> + }
Seriously, WTH is this? That seems completely out of place.
> }
>
> static void PlayBookmark( intf_thread_t *p_intf, int i_num )
> diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c
> index 29922cc..81d0a76 100644
> --- a/modules/demux/subtitle.c
> +++ b/modules/demux/subtitle.c
> @@ -35,6 +35,7 @@
> #include <vlc_plugin.h>
> #include <vlc_input.h>
> #include <vlc_memory.h>
> +#include <vlc_interface.h>
>
> #include <ctype.h>
>
> @@ -127,6 +128,16 @@ static void TextUnload( text_t * );
>
> typedef struct
> {
> + /*
> + * i_start and i_stop are the original subtitle timestamps.
> + *
> + * In order to take into account the subtitle delay (spu-delay),
> + * please use
> + * adjust_subtitle_time(p_demux, my_subtitle_t.i_start)
> + * instead of
> + * my_subtitle_t.i_start
> + * (same goes for i_stop)
> + */
> int64_t i_start;
> int64_t i_stop;
>
> @@ -141,6 +152,7 @@ struct demux_sys_t
> es_out_id_t *es;
>
> int64_t i_next_demux_date;
> + int64_t i_last_demux_date;
> int64_t i_microsecperframe;
>
> char *psz_header;
> @@ -166,6 +178,14 @@ struct demux_sys_t
> float f_total;
> float f_factor;
> } mpsub;
> +
> + /*subtitle_delaybookmarks: placeholder for storing subtitle sync
> timestamps*/ + struct
> + {
> + int64_t i_time_subtitle;
> + int64_t i_time_audio;
> + } subtitle_delaybookmarks;
> +
> };
>
> static int ParseMicroDvd ( demux_t *, subtitle_t *, int );
> @@ -224,6 +244,76 @@ 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 int set_current_subtitle_by_time(demux_t *p_demux, int64_t
> i64_when); +
> +
> +/**************************************************************************
> *** + * external callbacks
> +
> ***************************************************************************
> **/ +int subtitle_external_callback ( vlc_object_t * ,char const *,
> vlc_value_t old_value, vlc_value_t new_value, void * callback_data); +int
> subtitle_external_callback (
> + vlc_object_t * object,
> + char const * variable_name,
> + vlc_value_t old_value,
> + vlc_value_t new_value,
> + void * callback_data_p_demux)
> +{
> + demux_t *p_demux = (demux_t*)callback_data_p_demux;
> + (void)object;
> + (void)old_value;
> + (void)new_value;
> +
> + demux_sys_t *p_sys = p_demux->p_sys;
> +
> + if ( ! strcmp(variable_name, "sub-bookmarkaudio") )
> + {
> + p_sys->subtitle_delaybookmarks.i_time_audio =
> p_sys->i_last_demux_date;
> + var_SetString(p_demux->p_libvlc,
> "key-osdmessage", _("Sub sync: bookmarked audio time"));
> + }
> + if ( ! strcmp(variable_name, "sub-bookmarksubtitle") )
> + {
> + p_sys->subtitle_delaybookmarks.i_time_subtitle =
> p_sys->i_last_demux_date; + var_SetString(p_demux->p_libvlc,
> "key-osdmessage", _("Sub sync: bookmarked subtitle time")); + }
> + if ( ! strcmp(variable_name, "sub-syncbookmarks") )
> + {
> + if ( (p_sys->subtitle_delaybookmarks.i_time_audio == 0) ||
> (p_sys->subtitle_delaybookmarks.i_time_subtitle == 0) ) + {
> + var_SetString(p_demux->p_libvlc, "key-osdmessage", _("Sub sync:
> set bookmarks first!")); + }
> + else
> + {
> + int64_t i_current_subdelay = var_GetTime( p_demux->p_parent,
> "spu-delay" ); + int64_t i_additional_subdelay =
> p_sys->subtitle_delaybookmarks.i_time_audio -
> p_sys->subtitle_delaybookmarks.i_time_subtitle; + int64_t
> i_total_subdelay = i_current_subdelay + i_additional_subdelay; +
> var_SetTime( p_demux->p_parent, "spu-delay", i_total_subdelay); +
> char message[150];
> + snprintf(message, 150,
> + _( "Sub sync: corrected %i ms (total delay = %i ms)" ),
> + (int)(i_additional_subdelay / 1000), +
> (int)(i_total_subdelay / 1000) ); +
> var_SetString(p_demux->p_libvlc, "key-osdmessage", message); +
> p_sys->subtitle_delaybookmarks.i_time_audio = 0;
> + p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
> + }
> + }
> + if ( ! strcmp(variable_name, "sub-syncreset") )
> + {
> + var_SetTime( p_demux->p_parent, "spu-delay", 0);
> + p_sys->subtitle_delaybookmarks.i_time_audio = 0;
> + p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
> + var_SetString(p_demux->p_libvlc, "key-osdmessage", _("Sub sync:
> delay reset")); + return VLC_SUCCESS;
> + }
> + if ( ! strcmp(variable_name, "spu-delau") )
> + {
> + set_current_subtitle_by_time(p_demux, p_sys->i_last_demux_date);
> + }
> + return VLC_SUCCESS;
> +}
> +
> +
Demuxer accessing libvlc cannot be right. Also memory accesses seem to violate
the concurrency model.
>
> /**************************************************************************
> *** * Module initializer
> @@ -249,7 +339,29 @@ static int Open ( vlc_object_t *p_this )
> p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
> if( p_sys == NULL )
> return VLC_ENOMEM;
> -
> +
> + /* reset spu-delay at Open*/
> + var_SetTime( p_demux->p_parent, "spu-delay", 0 );
> + /* this is a file subtitle*/
> + var_SetInteger(p_demux->p_parent, "sub-isfilesub", 1);
> +
> +
> + p_sys->subtitle_delaybookmarks.i_time_audio = 0;
> + p_sys->subtitle_delaybookmarks.i_time_subtitle = 0;
> +
> +
> + /* Add callbacks*/
> + var_Create(p_demux->p_parent, "sub-bookmarkaudio", VLC_VAR_INTEGER);
> + var_Create(p_demux->p_parent, "sub-bookmarksubtitle", VLC_VAR_INTEGER);
> + var_Create(p_demux->p_parent, "sub-syncbookmarks", VLC_VAR_INTEGER); +
> var_Create(p_demux->p_parent, "sub-syncreset", VLC_VAR_INTEGER); +
> var_AddCallback( p_demux->p_parent, "sub-bookmarkaudio",
> &subtitle_external_callback, p_this );
> + var_AddCallback(
> p_demux->p_parent, "sub-bookmarksubtitle", &subtitle_external_callback,
> p_this );
> + var_AddCallback( p_demux->p_parent, "sub-syncbookmarks",
> &subtitle_external_callback, p_this );
> + var_AddCallback(
> p_demux->p_parent, "sub-syncreset", &subtitle_external_callback, p_this );
> + var_AddCallback( p_demux->p_parent, "spu-delay",
> &subtitle_external_callback, p_this );
> +
> +
Hell no. That's not how the demuxer interface works.
> p_sys->psz_header = NULL;
> p_sys->i_subtitle = 0;
> p_sys->i_subtitles = 0;
> @@ -579,8 +691,23 @@ static void Close( vlc_object_t *p_this )
> {
> demux_t *p_demux = (demux_t*)p_this;
> demux_sys_t *p_sys = p_demux->p_sys;
> - int i;
>
> + var_SetInteger(p_demux->p_parent, "sub-isfilesub", 0);
> +
> + /* Remove callbacks*/
> + var_DelCallback( p_demux->p_parent, "sub-bookmarkaudio",
> &subtitle_external_callback, p_this ); + var_DelCallback(
> p_demux->p_parent, "sub-bookmarksubtitle", &subtitle_external_callback,
> p_this ); + var_DelCallback( p_demux->p_parent, "sub-syncbookmarks",
> &subtitle_external_callback, p_this ); + var_DelCallback(
> p_demux->p_parent, "sub-syncreset", &subtitle_external_callback, p_this );
> +
> + var_DelCallback( p_demux->p_parent, "spu-delay",
> &subtitle_external_callback, p_this ); + var_Destroy(p_demux->p_parent,
> "sub-bookmarkaudio");
> + var_Destroy(p_demux->p_parent, "sub-bookmarksubtitle");
> + var_Destroy(p_demux->p_parent, "sub-syncbookmarks");
> + var_Destroy(p_demux->p_parent, "sub-syncreset");
> +
> +
> + int i;
> for( i = 0; i < p_sys->i_subtitles; i++ )
> free( p_sys->subtitle[i].psz_text );
> free( p_sys->subtitle );
> @@ -591,6 +718,31 @@ static void Close( vlc_object_t *p_this )
> /**************************************************************************
> *** * Control:
>
> ***************************************************************************
> **/ +
> +/* Utlity function : sets the current subtitle index (p_sys->i_subtitle)
> + * based on the time
> + */
> +static int set_current_subtitle_by_time(demux_t *p_demux, int64_t i64_when)
> +{
> + demux_sys_t *p_sys = p_demux->p_sys;
> +
> + p_sys->i_subtitle = 0;
> + while( p_sys->i_subtitle < p_sys->i_subtitles )
> + {
> + const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
> + 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;
> +
> + p_sys->i_subtitle++;
> + }
> +
> + if( p_sys->i_subtitle >= p_sys->i_subtitles )
> + return VLC_EGENERIC;
> + return VLC_SUCCESS;
> +}
> +
> static int Control( demux_t *p_demux, int i_query, va_list args )
> {
> demux_sys_t *p_sys = p_demux->p_sys;
> @@ -608,29 +760,14 @@ static int Control( demux_t *p_demux, int i_query,
> va_list args ) 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 = adjust_subtitle_time(p_demux,
> 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 );
> - p_sys->i_subtitle = 0;
> - while( p_sys->i_subtitle < p_sys->i_subtitles )
> - {
> - const subtitle_t *p_subtitle =
> &p_sys->subtitle[p_sys->i_subtitle]; -
> - if( p_subtitle->i_start > i64 )
> - break;
> - if( p_subtitle->i_stop > p_subtitle->i_start &&
> p_subtitle->i_stop > i64 ) - break;
> -
> - p_sys->i_subtitle++;
> - }
> -
> - if( p_sys->i_subtitle >= p_sys->i_subtitles )
> - return VLC_EGENERIC;
> - return VLC_SUCCESS;
> + return set_current_subtitle_by_time(p_demux, i64);
>
> case DEMUX_GET_POSITION:
> pf = (double*)va_arg( args, double * );
> @@ -640,7 +777,8 @@ static int Control( demux_t *p_demux, int i_query,
> va_list args ) }
> else if( p_sys->i_subtitles > 0 )
> {
> - *pf = (double)p_sys->subtitle[p_sys->i_subtitle].i_start /
> + int64_t i_start_adjust = adjust_subtitle_time(p_demux,
> p_sys->subtitle[p_sys->i_subtitle].i_start); + *pf =
> (double) ( i_start_adjust ) /
> (double)p_sys->i_length;
> }
> else
> @@ -655,7 +793,7 @@ static int Control( demux_t *p_demux, int i_query,
> va_list args )
>
> p_sys->i_subtitle = 0;
> while( p_sys->i_subtitle < p_sys->i_subtitles &&
> - p_sys->subtitle[p_sys->i_subtitle].i_start < i64 )
> + adjust_subtitle_time(p_demux,
> p_sys->subtitle[p_sys->i_subtitle].i_start) < i64 ) {
> p_sys->i_subtitle++;
> }
> @@ -693,15 +831,15 @@ static int Demux( demux_t *p_demux )
> if( p_sys->i_subtitle >= p_sys->i_subtitles )
> return 0;
>
> - i_maxdate = p_sys->i_next_demux_date - var_GetTime( p_demux->p_parent,
> "spu-delay" );; + i_maxdate = p_sys->i_next_demux_date;
> if( i_maxdate <= 0 && p_sys->i_subtitle < p_sys->i_subtitles )
> {
> /* Should not happen */
> - i_maxdate = p_sys->subtitle[p_sys->i_subtitle].i_start + 1;
> + i_maxdate = adjust_subtitle_time(p_demux,
> p_sys->subtitle[p_sys->i_subtitle].i_start) + 1; }
> -
> +
> while( p_sys->i_subtitle < p_sys->i_subtitles &&
> - p_sys->subtitle[p_sys->i_subtitle].i_start < i_maxdate )
> + adjust_subtitle_time(p_demux,
> p_sys->subtitle[p_sys->i_subtitle].i_start) < i_maxdate ) {
> const subtitle_t *p_subtitle = &p_sys->subtitle[p_sys->i_subtitle];
>
> @@ -721,9 +859,9 @@ 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 = 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; + p_block->i_length =
> adjust_subtitle_time(p_demux, p_subtitle->i_stop) -
> adjust_subtitle_time(p_demux, p_subtitle->i_start);
>
> memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
>
> @@ -733,11 +871,28 @@ static int Demux( demux_t *p_demux )
> }
>
> /* */
> + p_sys->i_last_demux_date = p_sys->i_next_demux_date;
> p_sys->i_next_demux_date = 0;
>
> return 1;
> }
>
> +
> +/**************************************************************************
> *** + * adjust_subtitle_time : receives a subtitle timestamp as input
> + * (p_subtitle->i_start or p_subtitle->i_stop)
> + * and returns that timestamp corrected
> + * by spu-delay
> +
> ***************************************************************************
> **/ +static int64_t adjust_subtitle_time( demux_t * p_demux, int64_t
> i64_when) +{
> + int64_t spu_delay = var_GetTime( p_demux->p_parent, "spu-delay" );
> + int64_t i64_adjust = i64_when + spu_delay;
> + return i64_adjust;
> +}
> +
> +
> +
> /**************************************************************************
> *** * Fix: fix time stamp and order of subtitle
>
> ***************************************************************************
> **/ diff --git a/src/input/input.c b/src/input/input.c
> index 7e71d4e..ab34401 100644
> --- a/src/input/input.c
> +++ b/src/input/input.c
> @@ -1103,7 +1103,14 @@ static void UpdatePtsDelay( input_thread_t *p_input )
> /* Take care of audio/spu delay */
> const mtime_t i_audio_delay = var_GetTime( p_input, "audio-delay" );
> const mtime_t i_spu_delay = var_GetTime( p_input, "spu-delay" );
> - const mtime_t i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
> + int isfilesub =var_GetInteger(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;
>
> diff --git a/src/input/var.c b/src/input/var.c
> index 3e722f4..be3ef2a 100644
> --- a/src/input/var.c
> +++ b/src/input/var.c
> @@ -195,6 +195,14 @@ void input_ControlVarInit ( input_thread_t *p_input )
> val.i_time = 0;
> var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
>
> + /*sub-isfilesub will be
> + * - equal to 1 when the subtitle is read from a file (for example a
> .srt file), + * - equal to 0 otherwise (for example dvd subtitles)*/
> + var_Create( p_input, "sub-isfilesub", VLC_VAR_INTEGER );
> + val.i_int = 0;
> + var_Change( p_input, "sub-isfilesub", VLC_VAR_SETVALUE, &val, 0 );
> +
> +
> /* Video ES */
> var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
> text.psz_string = _("Video Track");
> @@ -789,7 +797,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 );
> + int isfilesub = var_GetInteger(p_input, "sub-isfilesub"); +
> if ( ! isfilesub )
> + input_ControlPush( p_input, INPUT_CONTROL_SET_SPU_DELAY,
> &newval ); }
> return VLC_SUCCESS;
> }
--
Rémi Denis-Courmont
http://www.remlab.net/
More information about the vlc-devel
mailing list