精华内容
下载资源
问答
  • 怎么实现时钟同步
    千次阅读
    2022-02-09 22:22:23


    前言

    录制视频的时候,需要保证视频的声音和画面同步,通常是记录视频和音频的时间戳,让它们时间关系匹配上。而h264和aac本身不包含时间戳,只有写入mp4时才需要时间戳,本文将通过使用mp4v2作为mp4的封装工具,来说明如何实现时钟同步。


    一、使用外部时钟

    1.设置起始点

    在录制开始时记录起始时间点,以音频起始为准。
    定义时钟方法

    int64_t getClock() {
    	return clock();
    }
    

    设置起始点

    //记录起始时间
    timestamp = getClock();
    //视频录制启动
    videoStream.Start();
    //音频录制启动
    audioStream.Start();
    

    2.音频固定时间戳

    音频写入的时候不能使用当前的时间戳,因为音频是按比特播放的,音频帧的播放速度是均匀的,使用当前时间戳会导致播放速度产生波动,出现声音卡顿现象。所以一般情况下应该直接使用固定的时间戳,在mp4中是duration。
    添加音频流时,设置其duration即可。需要注意的是duration的值要计算正确,如果以下列的方式则非常简单,timescale设置为采样率,则一帧duration就是1024,1024不需要改变,只需要根据不同声音的采样率设置即可。

    audioId=MP4AddAudioTrack(pHandle, 44100, 1024, MP4_MPEG4_AUDIO_TYPE);
    

    写入aac的时候则不设置duration,参数设为MP4_INVALID_DURATION。

    MP4WriteSample(pHandle, audioId, frame->data, frame->dataLength, MP4_INVALID_DURATION, 0, 1);
    

    3.视频记录时间戳

    在视频采集处记录时间戳,此时还未编码。

    frame->timestamp=getClock();
    

    编码后写入mp4时计算时间戳

    //计算与上一帧的时间差
    auto duration = frame->timestamp - _timestamp;
    //计算当前帧的时间戳,用于下次计算
    timestamp = frame->timestamp;
    MP4WriteSample(pHandle, videoId, pNalu, len + 4, duration * timeScale / 1000, 0, frame->isIdr);
    

    完整流程(C++示例)

    int64_t getClock() {
    	return clock();
    }
    void main() {
    	int timestamp = 0;
    	MP4FileHandle pHandle = MP4Create("test.mp4", 0);
    	auto  videoId = MP4AddH264VideoTrack(/*略*/);
    	//设置音频的固定帧时长
    	auto  audioId = MP4AddAudioTrack(pHandle, 44100, 1024, MP4_MPEG4_AUDIO_TYPE);
    	//音频编码事件
    	audioStream.encode = [&](auto frame) {
    	    //使用固定帧时长(时间戳)MP4_INVALID_DURATION
    		MP4WriteSample(pHandle, audioId, frame->data, frame->dataLength, MP4_INVALID_DURATION, 0, 1);
    	};
    	//视频采集事件
    	videoStream.capture = [&](auto frame) {
    	    //记录时间戳
    		frame.timestamp = getClock();
    	};
    	//视频编码事件
    	videoStream.encode = [&](auto frame) {
    		//计算与上一帧的时间差
    		auto duration = frame->timestamp - _timestamp;
    		//记录当前帧的时间戳,用于下次计算
    		timestamp = frame->timestamp;
    		MP4WriteSample(pHandle, videoId, pNalu, len + 4, duration * timeScale / 1000, 0, frame->isIdr);
    	};
    	//记录起始时间
    	timestamp = getClock();
    	//视频录制启动
    	videoStream.Start();
    	//音频录制启动
    	audioStream.Start();
    	//下面略
        ....
    	MP4Close(pHandle, 0);
    }
    

    二、使用音频时钟

    在一的基础上实现下列2点即可。

    1.设置音频时钟

    在录制开始时记录起始时间点,以音频起始为准,由于基于音频时钟所以起始点为0。

    //atime作为音频时钟,必须使用double保留精度
    double atime=0;
    double getClock() {
    	return atime;
    }
    

    2.计算音频时钟

    在音频的采集处,计算音频的时长,累加即是音频时钟,计算公式为:
    时长(单位:s)=数据长度(单位:bytes)/(采样率(单位:hz)x(位深/8)x声道)
    注:音频的采集频率需要大于等于视频帧率,否则时钟灵敏度不够。

    //计算音频时钟
    atime += frame.dataLength * 1000.0 / (44100 * 16 / 8 * 2);
    

    完整流程(C++示例)

    double atime=0;
    double getClock() {
    	return atime;
    }
    void main() {
    	int timestamp = 0;
    	MP4FileHandle pHandle = MP4Create("test.mp4", 0);
    	auto  videoId = MP4AddH264VideoTrack(/*略*/);
    	//设置音频的固定帧时长
    	auto  audioId = MP4AddAudioTrack(pHandle, 44100, 1024, MP4_MPEG4_AUDIO_TYPE);	
        //音频采集事件
    	audioStream.capture= [&](auto frame) {
    	    //计算时钟
    		atime += frame.dataLength * 1000.0 / (44100 * 16 / 8 * 2);
    	};	
    	//音频编码事件
    	audioStream.encode = [&](auto frame) {
    	    //使用固定帧时长(时间戳)MP4_INVALID_DURATION
    		MP4WriteSample(pHandle, audioId, frame->data, frame->dataLength, MP4_INVALID_DURATION, 0, 1);
    	};
    	//视频采集事件
    	videoStream.capture = [&](auto frame) {
    	    //记录时间戳
    		frame.timestamp = getClock();
    	};
    	//视频编码事件
    	videoStream.encode = [&](auto frame) {
    		//计算与上一帧的时间差
    		auto duration = frame->timestamp - _timestamp;
    		//记录当前帧的时间戳,用于下次计算
    		timestamp = frame->timestamp;
    		MP4WriteSample(pHandle, videoId, pNalu, len + 4, duration * timeScale / 1000, 0, frame->isIdr);
    	};
    	//记录起始时间
    	timestamp = getClock();
    	//视频录制启动
    	videoStream.Start();
    	//音频录制启动
    	audioStream.Start();
    	//下面略
        ....
    	MP4Close(pHandle, 0);
    }
    

    总结

    以上就是今天要讲的内容,时钟同步的内容在网上查到的是理论居多,但是音视频开发中很多情况都需要依赖实践,知道理论未必能做。比如今天的音视频同步就是,需要直接代码调试才能真正确定是如何实现的,本文给出的代码示例,是通过实际调试得出的方案。

    更多相关内容
  • 如何使用GPS PPS实现时钟同步采集系统
  • 如何使用GPSPPS实现时钟同步采集系统
  • 倍福使用2个EL6688实现时钟同步
  • 这是一种通过分布式线性迭代实现时钟同步的算法,来自 IEEE 出版物“无线传感器网络中时钟同步的分布式共识协议”
  • 网络游戏-MPLS-TP网络实现时钟同步的方法及装置.zip
  • 分布式网络共识关俊杰在第46届IEEE决策与控制会议上由Luca Schenato和Giovanni Gamba提出的IEEE出版物“无线传感器网络中的时钟同步的分布式共识协议”,通过分布式线性迭代实现时钟同步的算法“ Average TimeSync ...
  • java实现时钟同步程序

    热门讨论 2011-01-27 16:58:27
    时间同步 linux NTP 时钟同步 同步 最近做一个项目,发现几台Linux服务器的时间都有严重偏差,本想启用NTP时间同步服务,但是想到自己是个程序员,这些事情自己写程序来实现倒是蛮有趣,所以就有了这个小程序. 将这个...
  • 伯克利使用Berkeley算法的逻辑时钟同步的基本实现
  • 时钟同步MATLAB实现

    2018-04-10 09:38:25
    主要通过MATLAB实现时钟同步,进行仿真分析。本系统采用前导符号作为定时同步符号,前导符号采用CAZAC序列。
  •  Network Time Protocol(NTP)是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒)...
  • 在介绍IEEE1588时钟协议基本原理的基础上,提出了使用具有IEEE1588协议硬件支持功能的DP83640以太网物理层收发器在基于ARM-WinCE的嵌入式系统平台上实现时钟同步的设计方案,给出了硬件设计的接口电路和软件设计框架...
  • IEEE1588时钟同步实现方式研究,对于RTP协议的研究非常有帮助,可以精确到微妙级别,欢迎研发人员借鉴
  • 分布式系统 同步化 时钟同步 物理时钟 Lamport时间戳 逻辑时钟

    1、概述

    同步化是分布式系统中的一个重要概念,同步化主要解决的是排序问题。例如:多个线程不能同时操作一个变量,而是将多个线程使用锁或无锁结构进行同步,同步的目的就是将多个线程排序为一个操作时序对这个变量进行操作。

    在单个计算机中,时间是明确的。当进程想要获取时间时,进程就进行一次系统调用,然后操作系统内核就会返回时间给这个进程。
    但是在分布式系统中,每台计算机的时钟可能是一致的也可能是不一致的。即使分布式系统中的每台计算机中的时钟是一致的,那么对于这个分布式系统而言这个时钟也不是全局的。不是全局的时钟那么在分布式系统中可能会产生问题。

    注意

    分布式系统中,一般用进程来抽象整个系统中的节点,一般理解为一个进程为一台计算机。

    2、物理时钟

    计算机中的时钟是一个物理硬件通常称为计时器,计算机的计时器通常是一个石英晶体管。石英晶体管以一定的频率振荡。然后有两个寄存器与每个石英晶体相联,一个是计数器,另一个是保持寄存器。石英晶体振荡使得计数器减1。当计数器为0时产生一个中断,然后计数器从保持寄存器中重新装入初始值。计数器产生的中断称为时钟滴答。当产生一个中断时,操作系统就会响应中断并调用中断处理程序将时钟存储器中的值加1。

    时钟中断示意图(图片来源于网络-示意图显示的是增1):
    在这里插入图片描述

    2.1、物理时钟的问题

    一句话总结:单台计算使用物理使用没有问题,分布式系统中各个进程使用物理时钟大概率不准确从而造成问题。
    计算中物理时钟的的主要问题是时钟偏移(clock skew)。通俗点描述时钟偏移就是钟摆摆动的偏移变慢或者变快或者时快时慢导致时钟不同步。

    时间偏移对同一台计算机的进程的时间获取基本上没有影响,因为即使出现了时间偏移,不同进程的在不同时刻得到的时间还是不一样的,但是在分布式系统就会有问题。

    在分布式系统中,进程分布在不同的计算机上,这时每台计算机的时钟都发生了偏移,那么整个分布式系统中的时钟就是不同步的。整个分布式系统中的时钟不同步的话会导致依赖时钟同步的程序有问题。

    解决物理时钟不同步的方式主要是时钟同步算法。这些算法包括但不限于:网络时间协议、Berkeley算法、Critian算法。

    注意:物理时钟同步有一个很重要的点就是即使当前计算机时钟大于标准时间或UTC时间,那么这台计算机的物理时钟也是不会回退的,因为回退会造成很多问题,甚至是致命的问题。通常的解决方式是如果物理时钟过快就增加保持寄存器的值从而增加了时钟的振荡周期;如果物理时钟国漫就减少保持寄存器的值从而减少了时钟的振荡周期;以上都是通过一个过渡期来慢慢调整物理时钟从而达到与标准时间或UTC时间一致的结果。

    2.2、物理时钟同步-网络时间协议(NTP)

    网络时间协议就是使用计算机与时间服务器进行计算机的时钟同步以达到高精准度的时间校正。

    2.3、物理时钟同步-Berkeley算法

    Berkeley 算法 适用于无线电时钟(radio clock)不可用的分布式系统,此类系统无法得知真实时间,只能通过维护一个全局的平均时间作为标准时间。一台时间服务器会周期性地获取各个客户端上的时间,将其平均处理后,回传每个客户端的时间与平均时间的偏移,以达到统一使用此平均时间的目的。此算法适用于不仅时间可能不一致,时钟速率也可能不一致的系统。如果一个客户端的时间偏移过大,超出了容忍值,则通常不会参与平均时间的计算。如此可以防止系统的时间被单个异常的时钟过度影响。

    Berkeley时钟同步算法图:
    在这里插入图片描述

    2.4、物理时钟同步-Cristian 算法

    3、逻辑时钟

    逻辑时钟关注点在顺序一致,这个时间不一定与实际时间相同。
    这里面关键点是时钟完全一致实在是太复杂了,所以人们才提出了逻辑时钟;如果物理时钟能够完全一致,那么就不需要逻辑时钟了。

    3.1、Lamport逻辑时钟

    Lamport逻辑时钟是一个happens-before关系,happens-before的意思是先发生(happens-before在Java/go内存模型也在使用)。happens-before关系使用表达式:a->b表示读作“a在b之前发生”,意思是所有进程一致认为事件a先发生,然后事件b才发生。
    Lamport提出逻辑时钟就是为了解决分布式系统中的时序问题,即如何定义a在b之前发生。

    逻辑时钟定义

    1. 如果a和b是同一进程中的两个事件,且a在b之前发生,则a->b为真。
    2. 如果a是一个进程发送消息的事件,而b为另一个进程接受这个消息的事件,则a->b为真。

    先发生关系是一种传递关系,所以若a->b且b->c则a->c。如果时间x和y发生在两个互不交换消息的进程中,那么x->y不为真,y->x也不为真,我们就称这两个事件是并发的;按照这样理解,happen-before关系是一个偏序关系,分布式系统中的一主多备之间的时间关系是全序关系。

    3.2 Lamport逻辑时钟实现

    实现Lamport逻辑时钟,每个时钟进程Pi维护一个局部计数器Ci,计数器按照如下步骤进行更新:

    1. 执行一个事件之前,P执行Ci=Ci+1;
    2. 当进程Pi发送一个消息m给Pj,在执行1的步骤后,把m的时间戳ts(m)设置为Ci;
    3. 在接收到消息m时,进程Pj调整自己的局部计数器为Cj=max(Cj, ts(m)),然后执行第一步,并把消息传送给应用程序。

    Lamport逻辑时钟有一个重要前提是:两个事件不会完全同时发生。

    3.3 Lamport时钟校正

    在这里插入图片描述

    3.4 时钟校正说明

    图a和图b说明:

    1. 图a和图b都有3个进程;
    2. 图a说明了使用物理时钟得到的时间分配;
    3. 图b说明了使用Lamport逻辑时钟得到的时间分配。

    3.4.1 图a-物理时钟

    图a中的三个进程P1、P2和P3各自运行在不同的计算机上,每台计算机都有自己的时钟,每台物理时钟都以不同的速率工作从而得到了不同的时间。

    在时刻6,进程P1将消息m1发送给进程P2,当m1消息到达进程P2时,进程P2的时时钟值是16;进程P2发送消息m2和进程P3发送消息m3发送时间及时钟值都还在合理的时钟值范围内;但是在进程P3发送m3到进程P2并达到P2的时钟值就出现了问题,因为消息发送的时刻应该小于消息达到的时刻,而Lamport逻辑时钟就解决了这个问题(看图b)。

    3.4.2 图b-Lamport逻辑时钟

    Lamport逻辑时钟就是让事件遵循happen-before关系。因为消息m3在时刻60离开P2,那么消息m3到达进程P1的时刻应该在61时刻或者更晚。所以每个消息应该根据发送者时钟的发送时间来调整自己的时钟值。图b中进程P3在收到m3消息后发现自己的时钟小于m3消息的时钟,进程P2根据消息m3的时钟调整了自己的时钟为61,进程P1也做了同样的时钟值调整。

    3.4.3 Lamport逻辑时钟在复制服务的应用

    复制是提升可靠性和性能的重要手段,复制面临的主要问题就是一致性问题,所有副本要完全相同,一般利用全序多播来实现。全序多播就是一次将所有消息以同样的顺序传送给每个接收者的多播。全序多播是实现状态机复制的重要工具,一致性乱了天下大乱。

    3.4.4 Lamport逻辑时钟集群复制

    在这里插入图片描述

    5、参考

    1. 分布式系统原理与范型(第2版)
    2. 时钟同步
    3. 分布式系统:Lamport 逻辑时钟
    4. 时钟同步
    5. 分布式系统(6) - 同步化
    展开全文
  • 可以采用同步以太网、IEEE 1588v2、网络时间协议(NTP)等多种技术实现时钟同步。同步以太网标准的同步状态信息(SSM)算法存在时钟成环,以及难以对节点跟踪统计的问题。中兴通讯提出了一种扩展SSM算法可以改进时钟...
  • 教你实现局域网内时钟同步.pdf
  •  时钟同步是分布式系统的核心技术之一,其目的是维护一个全局一致的物理或逻辑时钟,以使系统中的消息、事件及各节点与时间有关的行为有一个全局一致的解释,以确保节点发送和接收消息在时间逻辑上是完全正确的。...
  • 然后通过建立协议的有色Petri 网模型, 利用状态方程等工具针对不安全状态的可达性进行判断分析, 从而实现时钟同步协议的安全性分析; 最后具体分析了一种基于精密时钟同步协议(PTP) 的时钟同步协议以及针对该协议的...
  • uwb 定位时钟同步源码
  • 可以采用同步以太网、IEEE 1588v2、网络时间协议(NTP)等多种技术实现时钟同步。同步以太网标准的同步状态信息(SSM)算法存在时钟成环,以及难以对节点跟踪统计的问题。中兴通讯提出了一种扩展SSM算法可以改进时钟同步...
  • 摘 要:本文介绍了一种基于嵌入式微控制器MSP430构建的嵌入式同步时钟系统的设计与实现方案,在实现了网络时钟同步的基础上又提供了方便易用的网络管理接口。关键词:同步时钟;MSP430单片机;数字锁相环;CPLD ...
  • 采用STM32F407+DP83848及PTPd协议栈实现支持IEEE1588V2协议的采集节点,通过井下工业环网将北斗的绝对时钟同步到各采集节点;本地后备时钟采用STM32F407内部RTC(实时时钟)实现,给各采集节点提供秒级精度的时间戳...
  • 同步时钟信号不仅用于监测输入码元信号,确保收发同步,而且在获取祯同步、群同步及对接收的数字码元进行各种处理的过程中,也为系统提供了一个基准的同步时钟。  随着可编程器件容量的增加,设计师倾向于把位...
  • 可以使用时间戳交换来实现具有独立时钟的节点之间的时钟同步。 此外,可以利用无线环境的广播特性来提高同步精度。 在这个工具箱中,我们提供了 Matlab 脚本来估计时钟参数和范围估计。 更多详情我们参考: SP ...
  • 可以采用同步以太网、IEEE 1588v2、网络时间协议(NTP)等多种技术实现时钟同步。同步以太网标准的同步状态信息(SSM)算法存在时钟成环,以及难以对节点跟踪统计的问题。中兴通讯提出了一种扩展SSM算法可以改进时钟...
  • 利用IEEE 1588和 Blackfin 嵌入式处理器实现设备时钟同步

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 106,426
精华内容 42,570
关键字:

怎么实现时钟同步