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

Laurent Aimar fenrir at elivagar.org
Sat Sep 17 23:07:33 CEST 2011


On Sat, Sep 17, 2011 at 04:43:35AM +0900, Naohiro KORIYAMA wrote:
> Previous patch has a little bug (use break, but should use return ),
> so please forget previous patch.

> +    /* to determine length and time */
> +    int         i_pid_first_pcr;
> +    mtime_t     i_first_pcr;
> +    mtime_t     i_current_pcr;
> +    mtime_t     i_last_pcr;
> +    mtime_t     i_time;
 I don't think you need i_time (it will simplify a bit without).
> +    int         i_mux_rate;

> @@ -788,6 +800,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" );
>  
> +    bool can_seek = false;
> +    stream_Control( p_demux->s, STREAM_CAN_SEEK, &can_seek );
> +    if( can_seek )
> +    {
> +        GetFirstPCR( p_demux );
> +        GetLastPCR( p_demux );
> +        if( p_sys->i_last_pcr - p_sys->i_first_pcr > 0 )
> +        {
> +            p_sys->i_mux_rate = (stream_Size( p_demux->s )) * INT64_C(1000000) / ((p_sys->i_last_pcr - p_sys->i_first_pcr) * 100 / 9);
 After looking at the full patch, I don't think i_mux_rate is usefull:
GET_TIME/POSITION/LENGTH can be computed from i_first_pcr/i_last_pcr and it
will be more precise than using the byte position I think (it will prevents
having weird results with VBR streams).

> @@ -1219,41 +1195,38 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
>              return VLC_EGENERIC;
>  
>          return VLC_SUCCESS;
> -#if 0
>  
>      case DEMUX_GET_TIME:
>          pi64 = (int64_t*)va_arg( args, int64_t * );
> -        if( p_sys->i_time < 0 )
> +        if( (p_sys->b_dvb_meta && p_sys->b_access_control) || p_sys->i_time <= 0 )
 You should check last_pcr - first_pcr and not current_pcr - first_pcr.

>          {
> -            *pi64 = 0;
> -            return VLC_EGENERIC;
> +            if( DVBEventInformation( p_demux, pi64, NULL ) )
> +            {
> +                *pi64 = 0;
> +            }
> +        }
> +        else
> +        {
> +            *pi64 = p_sys->i_time;
>          }
> -        *pi64 = p_sys->i_time;
>          return VLC_SUCCESS;
 Also, bonus points ;) if you fix DEMUX_GET_POSITION to use 
(current_pcr - first_pcr) / (last_pcr - first_pcr)
when possible (but it's not mandatory to get the patch applied).

>      case DEMUX_GET_LENGTH:
>          pi64 = (int64_t*)va_arg( args, int64_t * );
> -        if( p_sys->i_mux_rate > 0 )
> +        if( (p_sys->b_dvb_meta && p_sys->b_access_control) || p_sys->i_mux_rate <= 0 )
> +        {
> +            if( DVBEventInformation( p_demux, NULL, pi64 ) )
> +            {
> +                *pi64 = 0;
> +            }
> +        }
> +        else
>          {
> -            *pi64 = INT64_C(1000000) * ( stream_Size( p_demux->s ) / 50 ) /
> +            *pi64 = INT64_C(1000000) * ( stream_Size( p_demux->s ) ) /
>                      p_sys->i_mux_rate;
> -            return VLC_SUCCESS;
 I think using last_pcr - first_pcr would be better, no ?
>          }
> -        *pi64 = 0;
> -        return VLC_EGENERIC;

> +static void GetPCR( block_t *p_pkt, mtime_t *p_pcr )
> +{
> +    const uint8_t *p = p_pkt->p_buffer;
> +
> +    *p_pcr = 0;
>  
>      if( ( p[3]&0x20 ) && /* adaptation */
>          ( p[5]&0x10 ) &&
>          ( p[4] >= 7 ) )
>      {
>          /* PCR is 33 bits */
> -        const mtime_t i_pcr = ( (mtime_t)p[6] << 25 ) |
> -                              ( (mtime_t)p[7] << 17 ) |
> -                              ( (mtime_t)p[8] << 9 ) |
> -                              ( (mtime_t)p[9] << 1 ) |
> -                              ( (mtime_t)p[10] >> 7 );
> +        *p_pcr = ( (mtime_t)p[6] << 25 ) |
> +                 ( (mtime_t)p[7] << 17 ) |
> +                 ( (mtime_t)p[8] << 9 ) |
> +                 ( (mtime_t)p[9] << 1 ) |
> +                 ( (mtime_t)p[10] >> 7 );
> +    }
> +}
A PCR of 0 is perfectly valid.
static mtime_t GetPCR(block_t *p_pkt) returning -1 on error would fix that
and be easier to use IMHO.

> +static void GetFirstPCR( demux_t *p_demux )
> +{
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +
> +    int64_t i_current_pos = stream_Tell( p_demux->s );
> +
> +    while( vlc_object_alive (p_demux) )
> +    {
> +        block_t     *p_pkt;
> +        if( !(p_pkt = ReadTSPacket( p_demux )) )
> +        {
> +            break;
> +        }
> +
> +        /* Parse the TS packet */
> +        ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
> +
> +        bool b_pcr = false;
> +        if( p_pid->b_valid )
> +        {
> +            if( p_pid->psi )
> +            {
> +                if( p_pid->i_pid == 0 || ( p_sys->b_dvb_meta && ( p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 || p_pid->i_pid == 0x14 ) ) )
> +                {
> +                    dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
> +                }
> +                else
> +                {
> +                    for( int i_prg = 0; i_prg < p_pid->psi->i_prg; i_prg++ )
> +                    {
> +                        dvbpsi_PushPacket( p_pid->psi->prg[i_prg]->handle,
> +                                           p_pkt->p_buffer );
> +                    }
> +                }
> +            }
> +            else
> +            {
> +                b_pcr = true;
> +            }
> +        }
> +        else
> +        {
> +            b_pcr = true;
> +        }
> +        if( !b_pcr )
> +        {
> +            block_Release( p_pkt );
> +            continue;
> +        }
> +
> +        if( p_sys->i_pmt_es > 0 )
> +        {
> +            if( p_sys->i_pid_first_pcr == 0  )
> +            {
> +                mtime_t i_pcr;
> +                GetPCR( p_pkt, &i_pcr );
> +                if( i_pcr > 0 )
> +                {
> +                    p_sys->i_pid_first_pcr = p_pid->i_pid;
> +                    p_sys->i_first_pcr = i_pcr;
> +                }
> +            }
> +        }
> +        block_Release( p_pkt );
 I think that simply calling GetPCR() on every packet until you actually get
a PCR would achieve the same thing and be simpler.
> +        
> +        if( p_sys->i_first_pcr > 0 )
> +            break;
> +    }
> +
> +    stream_Seek( p_demux->s, i_current_pos );
> +}
> +
> +static void GetLastPCR( demux_t *p_demux )
> +{
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +
> +    int64_t i_current_pos = stream_Tell( p_demux->s );
> +    int64_t i_last_pos = stream_Size( p_demux->s ) - p_sys->i_packet_size;
> +    int64_t i_pos = i_last_pos - p_sys->i_packet_size * 1000; /* FIXME how many packets to get last pcr? */
> +    if( i_pos < 0 )
> +        return;
 The specs says that a PCR should be found every 100ms at most (some streams
goes a bit beyong that).
 If you plan for 62 mbit/s (DVB-S I think), you need 4122 so ~4500 with a
margin.
 When STREAM_CAN_FASTSEEK is true, it might be better to look at the end with
a slower value, and if nothing is found, going back a bit further. But I am
not sure it's worthwhile, and it can always be added later.

> +    if( stream_Seek( p_demux->s, i_pos ) )
> +        return;
> +
> +    while( vlc_object_alive( p_demux ) )
> +    {
> +        block_t     *p_pkt;
> +        if( !(p_pkt = ReadTSPacket( p_demux )) )
> +        {
> +            break;
> +        }
> +
> +        ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
> +        if( p_sys->i_pmt_es > 0 )
> +        {
> +            if( p_sys->i_pid_first_pcr ==  p_pid->i_pid )
 You can simply test PIDGet( p_pkt ) == p_sys->i_pid_first_pcr and if true,
then call GetPCR();
> +            {
> +                mtime_t i_pcr;
> +                GetPCR( p_pkt, &i_pcr );
> +                if( i_pcr > 0 )
> +                {
> +                    p_sys->i_last_pcr = i_pcr;
> +                }
> +            }
> +        }
> +        block_Release( p_pkt );
> +        if( stream_Tell( p_demux->s ) >= i_last_pos )
> +            break;
> +    }
> +
> +    stream_Seek( p_demux->s, i_current_pos );
> +}

Thanks for your works,

Regards,

-- 
fenrir



More information about the vlc-devel mailing list