MPEG2传输流PCR计算问询:基于PTS/DTS的推导与实现问题
关于MPEG-TS中PCR的计算与推导方案
核心认知:PCR与PTS/DTS的本质区别
PCR(Program Clock Reference)是用于同步解码器系统时钟(STC)的基准信号,它对应的是TS包到达解码器的时间点,时钟基准为90kHz(扩展部分为27MHz);而PTS/DTS是帧的显示/解码时间,属于媒体内容的时间戳。两者没有固定的推导公式,PCR的计算需要结合传输码率和解码器缓冲需求两个核心因素。
对现有两种计算方式的分析
基于包数量与码率的计算
你提到的这段代码:(int64_t) ((8.0 * (packetsWritten * TS_PACKET_LENGTH + offset) / tsMuxrate) * TS_CLOCK + 0.5) + pcrStart逻辑上是正确的——通过已发送的字节数、码率计算对应传输时间,再转换为90kHz的PCR值。但和ffmpeg输出不符的原因大概率是细节误差:
tsMuxrate需精确到bps(如10Mbps要写10000000而非10);offset必须指向PCR字段在TS包中的具体字节位置(PCR是指该字节到达解码器的时间,不是包起始位置);pcrStart的初始值未和ffmpeg的起始PCR对齐。
硬编码100ms延迟的方法
base = (int64_t) packet->dts - (int64_t) (SYSTEM_CLOCK_FREQ_90kHz * 0.1);这种方式能快速跑通,但100ms是经验值,无法适配不同码率、不同解码器的缓冲需求,属于临时方案。
合理的PCR计算实现方案
方案1:结合传输时间与媒体时间戳约束
PCR的计算需要满足两个核心规则:
- PCR的增长速率严格匹配90kHz时钟,且和TS流码率对应(每个TS包的发送间隔对应固定的PCR增量);
- 对于承载视频PES的TS包,PCR必须早于该PES中首帧的DTS(提前几十到几百ms,保证解码器STC在帧到达时已准备好解码)。
具体实现步骤:
- 初始化全局PCR计数器:取第一个视频帧的DTS,减去一个可配置的缓冲时间(如50-200ms,对应90kHz时钟周期为
缓冲时间(ms)*90),作为初始PCR值; - 每发送一个TS包,计算该包对应的PCR增量:
// 避免浮点运算误差,用整数计算:增量 = (包字节数*8*90000)/码率 int64_t pcr_increment = (TS_PACKET_LENGTH * 8LL * 90000) / tsMuxrate; current_pcr += pcr_increment; - 当发送包含视频PES头的TS包时,检查当前PCR是否小于
当前帧DTS - 缓冲时间,如果是则将PCR调整到该值,避免PCR落后于解码时间。
方案2:对齐ffmpeg的实现逻辑
ffmpeg在libavformat/mpegtsenc.c中的PCR计算逻辑可参考:
- 维护
last_pcr变量记录上一次写入的PCR值; - 通过已发送字节数计算传输时间对应的PCR:
current_pcr = start_pcr + (bytes_written * 8LL * 90000) / bit_rate; - 对视频流强制保证PCR至少比当前帧DTS提前
pcr_delay(默认100ms,对应9000个90kHz时钟周期),若计算出的current_pcr小于DTS - pcr_delay,则用后者作为当前PCR。
额外注意事项
- PCR的插入间隔:MPEG标准要求每100ms至少插入一次PCR,通常在视频PES的适配字段中插入;
- 精度要求:PCR包含33位的90kHz基准和9位的27MHz扩展部分,若追求严格标准,需完整计算扩展部分(将90kHz基准乘以300,加上对应27MHz的增量)。
内容的提问来源于stack exchange,提问作者Tomislav Timic
相关产品推荐
相关产品推荐

