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,,因此,发送出去的时间戳意义是从本机开机到当前的时间累加值,单位为毫秒.
但是很少人提及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,,因此,发送出去的时间戳意义是从本机开机到当前的时间累加值,单位为毫秒.
相关文章推荐
- ASP.NET MVC使用Bootstrap系列(4)——使用JavaScript插件
- 实例讲解Java设计模式编程中如何运用代理模式
- 使用容联云通讯实现电话云呼叫功能
- Android向通讯录添加联系人的一般方法
- eclipse 常用快捷键
- 拖拽Imformatica Repository Navigator
- hibernate 一对一关联关系 及其懒加载,总结
- Selectable的Navigation用法
- Powershell 更新 Nagios Windows客户端
- java中注解的使用与实例
- 编码规范系列(二):Eclipse Checkstyle配置
- 虚拟化的组件的学习
- 云计算中虚拟化的意义
- MySQL Connector C
- Tab Control控件简单使用
- 写在参加工作后-记录
- ASP.NET MVC使用Bootstrap系列(1)——开始使用Bootstrap
- 有的事情是无可奈何的,有的事情是能够改变的……
- 使用 Apache Commons CLI 开发命令行工具
- 什么是J2EE