学习使用 ffprobe 分析视频是否正常

梦康 2023-06-07 09:09:49 1690

输入图片说明

场景

经常有运营反馈视频上传到系统之后,视频时长变短了。原版视频200分钟上传转码之后,只有40分钟了。下面学习下使用 ffprobe 来分析确认这种问题。

安装 ffmpeg

mac 系统可以先配置清华大学的镜像,然后执行 brew install ffmpeg

Debian / Ubuntu 系统:sudo apt-get install ffmpeg

Windows 系统:下载 ffmpeg 并将其添加到环境变量中。

使用 ffprobe 分析

查询视频帧率

ffprobe 工具可以用来分析视频文件,可以得到视频的信息,包括视频时长、码率、分辨率等。
可以简单的理解视频是一帧一帧的图片组成,一帧就是这个视频最小切割单元,也可以叫一个数据包。

ffprobe -i '/Users/zhoumengkang/Documents/normal_video.mp4'
...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/zhoumengkang/Documents/normal_video.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: isommp41mp42
    creation_time   : 2022-11-04T09:46:54.000000Z
  Duration: 00:01:12.64, start: 0.000000, bitrate: 2164 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, unknown/bt470bg/iec61966-2-1, progressive), 960x544, 2095 kb/s, SAR 1:1 DAR 30:17, 28 fps, 28 tbr, 600 tbn (default)
    Metadata:
      creation_time   : 2022-11-04T09:46:54.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 62 kb/s (default)
    Metadata:
      creation_time   : 2022-11-04T09:46:54.000000Z
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]

可以看到视频文件有两个StreamStream #0:0是视频;Stream #0:1是音频。我主要是关注视频的帧率28 fps,也就是说一帧的时长大概是是1/28秒,也就是0.035714秒。

逐帧分析视频

ffprobe -select_streams v -show_entries packet=pts_time,duration_time '/Users/zhoumengkang/Documents/normal_video.mp4'

-select_streams v:选择视频流进行分析,v 表示视频流。如果视频文件中包含多个视频流,则需要根据实际情况进行调整。
-show_entries packet=pts_time,duration_time:输出视频数据包的 PTS 时间戳和时长信息。

[PACKET]
pts_time=0.000000
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.071667
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.035000
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.143333
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.106667
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.215000
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.178333
duration_time=0.035000
[/PACKET]
[PACKET]
pts_time=0.285000
duration_time=0.035000
[/PACKET]
...

可以再增加一个参数输出位 csv 格式,方便后续分析

ffprobe -select_streams v -show_entries packet=pts_time,duration_time -of csv '/Users/zhoumengkang/Documents/normal_video.mp4'|head -n 10
...
packet,0.000000,0.035000
packet,0.071667,0.035000
packet,0.035000,0.035000
packet,0.143333,0.035000
packet,0.106667,0.035000
packet,0.215000,0.035000
packet,0.178333,0.035000
packet,0.285000,0.035000

第二列是时间戳,第三列是这一帧的时长。

可以发现时间戳不是完全顺序的,这就是视频有问题的么?

这样的结果并不一定说明时间戳是乱序的。每个视频数据包的 pts_time 属性表示该数据包的显示时间,而 duration_time 属性表示该数据包的显示时长,这两个属性并不依赖于视频数据包的先后顺序。因此,这些数据包的先后顺序并不一定是乱序的,可能是正常的时间顺序。

另外,对于视频数据包的时间戳顺序,需要根据实际情况进行分析。有时候,由于视频的编码方式或其他因素,视频数据包的时间戳可能会存在跳跃或非线性变化的情况。这种情况下,需要特别注意分析视频数据包的时间戳和时长信息,以确保分析结果的正确性。

我理解可能算法上有一些优化,我可以粗估如果前后两个数据包时间差距不大于5帧秒就是正常的。(我的外行理解)

5*0.035=0.175

下面的命令的意思就是上下两帧时间戳差距了0.175了,就输出timestamps error:xxx,xxx

下面是完整的 awk 命令:

ffprobe -select_streams v -show_entries packet=pts_time,duration_time -of csv '/Users/zhoumengkang/Documents/normal_video.mp4'|awk -F ',' '{print $2}'| awk '{if ($1-p>0.175 || p-$1>0.175) {print "timestamps error:" p,$1} p=$1}'

分析视频是否有错

有时候视频文件问题可能更严重,也有可能文件是一个远程文件,有时候几十G,我们不需要将视频完整的下载下来,ffprobe 可以直接分析远程视频文件

比如下面的截图

输入图片说明

"Invalid NAL unit size" 是在 H.264 视频编码中常见的错误提示,表示解码器在解码过程中遇到了不符合规范的 NAL 单元大小,无法正确解码视频数据。

"missing picture in access unit with size 8637" 是 H.264 编码中常见的错误提示,表示解码器在解码过程中遇到了大小为 8637 字节的访问单元(access unit)中缺失了部分图像数据,导致无法正确解码视频数据。

基本可以确定视频文件的数据损坏,需要重新输出。