【VLC核心二】clock管理流程

简介: 一、前言 clock管理是vlc播放音视频的重要部分,从live555收流到decoder解码到render渲染,整个播放过程中均需依赖clock机制。

一、前言

clock管理是vlc播放音视频的重要部分,从live555收流到decoder解码到render渲染,整个播放过程中均需依赖clock机制。

二、涉及的类文件

src\input\input.c

modules\access\live555.cpp

src\input\es_out.c

src\input\decoder.c

src\input\clock.c

三、clock核心点备注

1、live555::CmdExecuteControl(ES_OUT_SET_PCR,p_sys->i_pcr+1)

注:p_sys->i_pcr+1作为input_clock_Update的i_ck_stream参数传入。p_sys->i_pcr在live555的StreamRead函数中赋值

2、clock中i_cr_average值的来源

clock中i_cr_average=配置文件中读取默认40ms * i_pts_delay / DEFAULT_PTS_DELAY;
DEFAULT_PTS_DELAY = 3*CLOCK_FREQ/10

3、当准备收流或回放拖动时,会触发设置PCR动作,对应ES_OUT_SET_PCR,继而调用clock::input_clock_Update(i_pcr, mdate()),更新clock机制,其核心处理如下

a、判断当前流时戳与上一帧时戳差值是否大于MAX_GAP,如果大于MAX_GAP,说明收到的帧已经跳变过大,则重置clock值ResetClock。(MAX_GAP宏的值为60s,可以调整宏代码,此值过大,应该调整为1s以内,否则在回放拖动时有bug,后续文章详解);

b、每隔20ms调用AvgUpdate计算一次 stream clock 和system clock间的漂移;

typedef struct
{
    mtime_t i_value;
    int     i_residue; //残余

    int     i_count;	
    int     i_divider; // 分割;分配
} average_t;

AvgUpdate详解:
//将当前mdate时间转换为流时戳
const mtime_t i_converted = ClockSystemToStream( cl, i_ck_system );
//用转换的流时戳-真实流时戳作为ivalue
AvgUpdate( &cl->drift, i_converted - i_ck_stream );

static void AvgUpdate( average_t *p_avg, mtime_t i_value )
{
    const int i_f0 = __MIN( p_avg->i_divider - 1, p_avg->i_count );//i_f0记录当前已存值的个数
    const int i_f1 = p_avg->i_divider - i_f0;//剩余个数
	//统计总值=已存个数*平均value + 剩余个数*新来i_value + 余数
	// 好处是:未存满值的时候,剩余个数均使用新的i_value填充
    const mtime_t i_tmp = i_f0 * p_avg->i_value + i_f1 * i_value + p_avg->i_residue;
	// 计算新平均值和余数
    p_avg->i_value   = i_tmp / p_avg->i_divider;
    p_avg->i_residue = i_tmp % p_avg->i_divider;

    p_avg->i_count++;
}

c、计算当前帧是否来晚了

当前系统时戳即mdate的当前时间- (当前系统时戳将流时戳+平均偏移,转换为系统时戳)。如果大于零,说明改帧比期望它到的时间来晚了。来晚了就更新到数组里。VLC缓存了三个late的值,为后续GetJitter获取的时候可以计算平均的late值。

摘录:如果late,存储到数组中
if( i_late > 0 )
    {
        cl->late.pi_value[cl->late.i_index] = i_late;
        cl->late.i_index = ( cl->late.i_index + 1 ) % INPUT_CLOCK_LATE_COUNT;
    }

摘录:input_clock_GetJitter
寻找中间的late值,这种方法可以规避掉bad values
const mtime_t *p = cl->late.pi_value;
    mtime_t i_late_median = p[0] + p[1] + p[2] - __MIN(__MIN(p[0],p[1]),p[2]) - __MAX(__MAX(p[0],p[1]),p[2]);
    mtime_t i_pts_delay = cl->i_pts_delay ;

d、如果晚了,在es_out.c中,调用clock::input_clock_GetJitter统计抖动,并调用clock:: input_clock_Reset和input_clock_SetJitter重置clock,重新调节计算漂移的参数。这样就可以重新缓存待解码的数据。


4、缓存数据的核心流程

a、每次es_out.c中SET_PCR中调用EsOutDecodersStopBuffering 如果是缓冲状态, 判断是否缓冲完?

1)计算流缓存时间:调用input_clock_GetState检查i_stream_duration值得到流缓存的时间
2)计算预设缓存时间:
const mtime_t i_buffering_duration = p_sys->i_pts_delay + i_preroll_duration + p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
实测中i_buffering_duration  = p_sys->i_pts_delay = 1000;其它值为0,待研究什么情况下其它值不为零。
3)如果i_stream_duration<i_buffering_duration,则继续缓冲,否则已缓冲满。

b、input_DecoderWaitBuffering缓冲完通知decoder模块。解码模块队列中循环解码,可参考文章《【VLC核心一】播放流程梳理


5、clock在live555收流拼帧部分相关工作

a、拼帧完成后送SteamRead,SteamRead中的处理

int64_t i_pts = (int64_t)pts.tv_sec * INT64_C(1000000) +(int64_t)pts.tv_usec;
i_pts &= INT64_C(0x00ffffffffffffff);

if( p_sys->i_pcr < i_pts )
{
    p_sys->i_pcr = i_pts;
}

四、核心流程时序图


目录
相关文章
|
1月前
|
Linux C++ iOS开发
VLC源码解析:视频播放速度控制背后的技术
VLC源码解析:视频播放速度控制背后的技术
82 0
|
3月前
|
存储 芯片 C++
STM32启动详细流程分析(一)
STM32启动详细流程分析(一)
77 0
|
7月前
|
传感器 存储 物联网
STM32F103产品级开源项目:iLook.Time设计解读
STM32F103产品级开源项目:iLook.Time设计解读
93 0
|
7月前
|
API 芯片
STM32 使用HAL库调试内部RTC经验总结
STM32 使用HAL库调试内部RTC经验总结
281 1
|
7月前
|
传感器 物联网 芯片
超轻量级网红软件定时器multi_timer(51+stm32双平台实战)
超轻量级网红软件定时器multi_timer(51+stm32双平台实战)
248 0
|
8月前
|
编解码
播放器实战--音视频同步方案
播放器实战--音视频同步方案
110 0
|
11月前
|
数据可视化
ARM-CPU150FPS | PicoDet助力移动端达到超实时检测(强烈建议工程人员学习)(二)
ARM-CPU150FPS | PicoDet助力移动端达到超实时检测(强烈建议工程人员学习)(二)
41 0
|
11月前
|
机器学习/深度学习 存储 固态存储
ARM-CPU150FPS | PicoDet助力移动端达到超实时检测(强烈建议工程人员学习)(一)
ARM-CPU150FPS | PicoDet助力移动端达到超实时检测(强烈建议工程人员学习)(一)
129 0
|
11月前
|
Linux API 开发者
Linux驱动分析之RTC框架
当Linux内核启动时,它会从RTC中读取时间与日期,作为基准值。然后通过软件来维护系统时间和日期。Linux系统中提供了RTC核心层,对于驱动开发者而言,操作起来就变得很简单了。我们来看看整体框架。
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的。为了更好的表述封装设计过程,本文描述了CH340G和MAX232芯片封装创建(SOP-16),并将原理图的元器件关联引脚封装。
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件

热门文章

最新文章