[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