乐趣区

私有流媒体服务器录制的mpegts文件medieinfo解析播放时长偏小的问题

1 问题描述

  最近碰到一个问题,流媒体服务器写出来的 TS 文件用 ffmpeg、potplayer 播放时长是正确的,但是使用 mediainfo 和 windows 自带的系统播放器播放,就会出现播放时长偏小的问题。而 mediainfo 中音视频播放时长却是正确值。如下图所示:

  如上图所示,该 MPEG-TS 文件的播放总时长为 9.268 秒,视频播放时长为 10.865 秒,音频播放时长为 10.755 秒。而该视频在 ffmpeg 中显示播放时长为 10.865 秒。

2 问题原因

  针对以上问题,笔者下载了 mediainfo 的源码编译调试发现,mediainfo 解析 MPEG-TS 的播放时长来自于 TS 包中的 PCR(即 program_clock_reference/ 节目时钟参考)。而音视频播放时长来自于 PES 中时间戳。说到这里,我估计有些不熟悉 MPEG-TS 格式的小伙伴已经开始晕了。

3.MPEG2 系统音视频同步方式

  MPEG-TS 文件结构分三个层面:

3.1.TS 层

  使用固定包大小对数据进行打包,TS 包大小固定为 188 字节(M2TS/ 蓝光高清为 192 字节)。它包括 TS 头数据、有效载荷数据和填充数据三部分。

3.1.1 TS 包头

  TS 包头为 4 字节固定大小包头标识,定义如下
typedef struct TS_packet_header
{

unsigned sync_byte                        : 8; // 同步字节, 固定为 0x47, 表示后面的是一个 TS 分组
unsigned transport_error_indicator        : 1; // 传输误码指示符
unsigned payload_unit_start_indicator    : 1; // 有效荷载单元起始指示符
unsigned transport_priority              : 1; // 传输优先, 1 表示高优先级, 传输机制可能用到,解码用不着
unsigned PID                            : 13; //PID
unsigned transport_scrambling_control    : 2; // 传输加扰控制 
unsigned adaption_field_control            : 2; // 自适应控制 01 仅含有效负载,10 仅含调整字段,11 含有调整字段和有效负载。为 00 解码器不进行处理
unsigned continuity_counter                : 4; // 连续计数器 一个 4bit 的计数器,范围 0 -15

} TS_packet_header; // 总共 32 位,4 个字节
当 adaption_field_control=10 或 11 时:
包头后面紧跟者调整字段,PCR 则是在这个字段中,如下

…]

3.1.2 有效载荷数据

  有效载荷数据一般为音视频数据包的 PES 数据包,或是节目映射表 PMT 和节目访问表 PAT 等 TS 节目信息。

3.1.3 填充部分

  当 TS 包头和有效载荷数据不总 188 字节时,将会使用 0xff 填充,直到 TS 包满足 188 字节为止。

3.2 PES(Packetize Elementary Stream)

  经过打包的基本码流,一般以数据帧为单位对音视频数据进行打包,同时会携带有该数据帧的时间戳和一些其他标志位信息。

3.3 ES(Elementary Stream)

  视频基本码流数据。

4 PCR

  PCR(Program Clock Reference/ 节目时钟参考)用于恢复出与编码端一致的系统时序时钟(STC/System Time Clock)。MPEG2 系统层标准规定,PTS 的时间间隔不能超过 0.7S,出现在 TS 包头的 PCR 间隔不能超过 0.1S,PCR 最大值位 26:30:43。在 TS 传输过程中,一般 DTS 和 PCR 差值会在一个合适的范围,这个差值就是要设置的音视频 buffer 的大小。一般情况下视频 DTS 和 PCR 的差值在 700ms-1200ms 之间,音频差值在 200ms-700ms 之间。

5 解决方案

  现在终于明白了,mediainfo 和系统播放器获取时间是根据 PCR/ 节目时钟参考来计算的,而 ffmpeg 和 potplayer 之类的播放器时使用 PTS 来计算时间戳的。而 PCR 的时间间隔最大不能超过 0.1s,即 100ms,而这个 TS 文件的 PCR 时间间隔明显就大于 1 秒,才会导致这个问题的出现。想要解决这个问题,在每间隔 100ms 插入一个 PCR 就 OK 了。

退出移动版