[vlc-devel] [PATCH] TS demux: get time and length

Laurent Aimar fenrir at elivagar.org
Wed Oct 5 21:48:20 CEST 2011


Sorry for the delay.

On Fri, Sep 30, 2011 at 12:20:37AM +0900, Naohiro KORIYAMA wrote:
> 2011/9/25 Laurent Aimar <fenrir at elivagar.org>:
> > On Fri, Sep 23, 2011 at 11:17:57AM +0900, Naohiro KORIYAMA wrote:
> > There are two differents issues:
> > 1. Handle files that have PCR restarting without it being due to a PCR wrap.
> > 2. Handle files longer than 1 PCR wraps (more than ~ 26 hours).
> 
> I added a table for checking PCR wrap around.
> This modification solved the issues and made a little bit improvement
> for Seek().


> @@ -336,6 +343,14 @@ struct demux_sys_t
>      /* how many TS packet we read at once */
>      int         i_ts_read;
>  
> +    /* to determine length and time */
> +    int         i_pid_ref_pcr;
> +    mtime_t     i_first_pcr;
> +    mtime_t     i_current_pcr;
> +    mtime_t     i_last_pcr;
> +    bool        b_force_seek_per_percent;
> +    mtime_t     i_pcrs[10];
 You could also store and use the exact position to:
 - improve the precision of the seek, and maybe (I am unsure) to avoid
 failling seeking in case the PCR was not too close of the byte position.
 - prepare for support when the file size change while playing. I know it
 won't work as is yet (and not needed in this patch).

 If you prefer to do that in another patch later, I am fine with it.

> @@ -788,6 +810,18 @@ static int Open( vlc_object_t *p_this )
>      p_sys->b_silent = var_CreateGetBool( p_demux, "ts-silent" );
>      p_sys->b_split_es = var_InheritBool( p_demux, "ts-split-es" );
>  
> +    p_sys->i_first_pcr = -1;
> +    p_sys->i_last_pcr = -1;
> +    p_sys->b_force_seek_per_percent = false;
 It would be simpler to initialize it with var_InheritBool("ts-seek-percent")
and it would avoid to call it at each seek.

> +    bool can_seek = false;
> +    stream_Control( p_demux->s, STREAM_CAN_SEEK, &can_seek );
> +    if( can_seek  )
> +    {
> +        GetFirstPCR( p_demux );
> +        CheckPCRWrapAround( p_demux );
> +        GetLastPCR( p_demux );
You could also set b_force_seek_per_percent to true here if
i_first_pcr/i_last_pcr are not valid (will simplify later code).

>      case DEMUX_SET_POSITION:
>          f = (double) va_arg( args, double );
> -        i64 = stream_Size( p_demux->s );
>  
> -        if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) )
> +        if( f < 0.0  || f > 1.0 )
> +        {
>              return VLC_EGENERIC;
> +        }
 You don't need to check the value of f, it is guaranted to be valid.

> +static void GetFirstPCR( demux_t *p_demux )
> +{
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +
> +    p_sys->i_pid_ref_pcr = -1;
> +    p_sys->i_first_pcr = -1;
> +
> +    int64_t i_initial_pos = stream_Tell( p_demux->s );
> +
> +    if( stream_Seek( p_demux->s, 0 ) )
> +        return;
> +
> +    while( vlc_object_alive (p_demux) )
> +    {
> +        block_t     *p_pkt;
> +        if( !( p_pkt = ReadTSPacket( p_demux ) ) )
> +        {
> +            break;
> +        }
> +        mtime_t i_pcr = GetPCR( p_pkt );
> +        if( i_pcr >= 0 )
> +        {
> +            p_sys->i_pid_ref_pcr = PIDGet( p_pkt );
> +            p_sys->i_first_pcr = i_pcr;
 Setting i_current_pcr here will avoid having GET_TIME failing
at the beginning.

> +        }
> +        block_Release( p_pkt );
> +        if( p_sys->i_first_pcr >= 0 )
> +            break;
> +    }
> +    stream_Seek( p_demux->s, i_initial_pos );
> +}

> +static void CheckPCRWrapAround( demux_t *p_demux )
> +{
> +    demux_sys_t   *p_sys = p_demux->p_sys;
> +
> +    int64_t i_initial_pos = stream_Tell( p_demux->s );
> +
> +    p_sys->b_force_seek_per_percent = false;
> +
> +    int i = 0;
> +    p_sys->i_pcrs[0] = p_sys->i_first_pcr;
> +
> +    for(int i = 1; i < 10 && vlc_object_alive( p_demux ); ++i )
> +    {
> +        int64_t i_pos = stream_Size( p_demux->s ) * 0.1 * i;
> +        if( SeekToPCR( p_demux, i_pos ) )
> +        {
> +            p_sys->b_force_seek_per_percent = true;
> +            break;
> +        }
> +        p_sys->i_pcrs[i] = p_sys->i_current_pcr;
> +        if( p_sys->i_pcrs[i-1] > p_sys->i_pcrs[i] )
> +        {
> +            msg_Dbg( p_demux, "PCR Wrap Around found between %d%% and %d%% (pcr:%lld(%09llx) pcr:%lld(%09llx))",
> +                    (i-1)*10, i*10, p_sys->i_pcrs[i-1], p_sys->i_pcrs[i-1], p_sys->i_pcrs[i], p_sys->i_pcrs[i] );
> +        }
> +    }
> +
> +    stream_Seek( p_demux->s, i_initial_pos );
> +}
 I think that it might be worth to reject (ie b_force_seek_per_percent = true)
when they are too much PCR wraps. It will catch most of the file that have
arbitrary PCR reset.
 Again, that can be added later, as you prefer.

Regards,

-- 
fenrir




More information about the vlc-devel mailing list