您的位置:首页 > 其它

vlc发送的时间戳分析

2016-02-04 10:02 337 查看
很多人发送流媒体习惯于使用VLC, 很方便也很好用, 功能很强大.

但是很少人提及VLC 发出的帧的时间戳是什么意义,是如何计算得来的. 本人最近分析了VLC的源代码, 分析了时间戳形成机制, 不敢独享,拿出来与大家共享.

VLC发送实时流的命令一般如下:

vlc -vvv localFile --sout udp://ip:port

-vvv是输出调试信息的选项

--sout是输出流到某个地址的选项.

在VLC中时间戳的调用栈如下:

1. decoder.c:decoder_New()-->vlc_clone( &p_dec->p_owner->thread, DecoderThread, p_dec, i_priority )

启动线程,回调函数DecoderThread

2. decoder.c:DecoderThread()-->DecoderProcess( p_dec, p_block )

3. decoder.c:DecoderProcess-->DecoderProcessSout( p_dec, p_block )

4. decoder.c:DecoderProcessSout-->DecoderPlaySout( p_dec, p_sout_block )

5. decoder.c:DecoderPlaySout-->DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,

&p_sout_block->i_length, NULL, INT64_MAX )

可以看到该函数的第二第三个参数为引用,也就是在该函数中赋值

6. decoder.c:DecoderFixTs()-->input_clock_ConvertTS( p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound )

7. decoder.c:input_clock_ConvertTS()-->*pi_ts0 = ClockStreamToSystem( cl, *pi_ts0 + AvgGet( &cl->drift ) )

在该函数中进行时间戳转换,将原视频的时间戳转换为VLC系统的时间戳,发送出去,转换公式如下:

return ( i_stream - cl->ref.i_stream ) * cl->i_rate / INPUT_RATE_DEFAULT +

cl->ref.i_system;

用到的ref的i_stream和i_system是系统时间,那时如何得到的呢?

在thread.c的mdate()函数中, 得到系统时钟:

/**

* Precision monotonic clock.

*

* In principles, the clock has a precision of 1 MHz. But the actual resolution

* may be much lower, especially when it comes to sleeping with mwait() or

* msleep(). Most general-purpose operating systems provide a resolution of

* only 100 to 1000 Hz.

*

* @warning The origin date (time value "zero") is not specified. It is

* typically the time the kernel started, but this is platform-dependent.

* If you need wall clock time, use gettimeofday() instead.

*

* @return a timestamp in microseconds.

*/

mtime_t mdate (void)

{

#if (_POSIX_TIMERS > 0)

struct timespec ts;

vlc_clock_setup ();

if (unlikely(clock_gettime (vlc_clock_id, &ts) != 0))//qpx

abort ();

return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000);

#else

struct timeval tv;

if (unlikely(gettimeofday (&tv, NULL) != 0))

abort ();

return (INT64_C(1000000) * tv.tv_sec) + tv.tv_usec;

#endif

}

该函数中, _POSIX_TIMERS的值大于0,因此走第一个分支.也就是通过clock_gettime得到系统时钟.

第一个参数为系统时钟ID:

clk_id : 检索和设置的clk_id指定的时钟时间。
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,
中间时刻如果系统时间被用户改成其他,则对应的时间相应改变

  CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响

  CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间

  CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间
在vlc的代码中,

#if (_POSIX_TIMERS > 0)

static unsigned vlc_clock_prec;

# if (_POSIX_MONOTONIC_CLOCK > 0) && (_POSIX_CLOCK_SELECTION > 0)

/* Compile-time POSIX monotonic clock support */

# define vlc_clock_id (CLOCK_MONOTONIC)

# elif (_POSIX_MONOTONIC_CLOCK == 0) && (_POSIX_CLOCK_SELECTION > 0)

/* Run-time POSIX monotonic clock support (see clock_setup() below) */

static clockid_t vlc_clock_id;

# else

/* No POSIX monotonic clock support */

# define vlc_clock_id (CLOCK_REALTIME)

# warning Monotonic clock not available. Expect timing issues.

# endif /* _POSIX_MONOTONIC_CLOKC */

显然,在VLC中, vlc_clock_id的值为CLOCK_MONOTONIC,,因此,发送出去的时间戳意义是从本机开机到当前的时间累加值,单位为毫秒.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: