最近使用 YaoFANGUK/video-subtitle-remover 这个项目来移除视频中的硬字幕,遇到了一个问题:

这个错误提示 TypeError: 'NoneType' object is not subscriptable 通常是因为代码试图访问一个为 None 的对象的元素或属性。
好在这是个已知问题,已经有大佬在 GitHub 上提交了 issue,并且提供了解决方案。
解决办法就是把视频修改为 固定帧率 。
VFR 和 CFR
在视频处理中,VFR(Variable Frame Rate)和 CFR(Constant Frame Rate)是两种不同的帧率处理方式。
VFR(可变帧率)指的是视频的帧率在不同时间段内可以变化,这种方式通常用于节省存储空间或适应不同的播放需求。而 CFR(固定帧率)则是指视频在整个播放过程中保持恒定的帧率,这样可以确保视频的流畅性和同步性。
虽然 VFR(可变帧率)是一种非常高效的录制方法,但某些视频编辑程序(例如 Adobe Premiere)无法正确支持以 VFR(可变帧率)保存的视频文件,因此在这种情况下,必须使用 CFR(恒定帧率)。
FFmpeg + DeepSeek
说到视频格式转换,我很自然就想到了FFmpeg。FFmpeg 是一个强大的多媒体处理工具,可以用来转换视频格式、调整帧率等。
同时,我也想到了DeepSeek。我让DeepSeek来帮我写一个FFmpeg命令,将一个可变帧率(VFR)的MKV视频转换为固定帧率(CFR)的MP4视频。
我先后问了DeepSeek三次:
第一次:ffmpeg将一个mkv视频转化为25帧每秒的固定帧率。
|
|
第二次:ffmpeg 把视频 从vfr 转成 cfr
|
|
第三次:ffmpeg把一个vfr的mkv视频转化成一个24f/s的mp4视频。
|
|
为什么问了三次?很明显,前面两次的回答都没有解决我的问题。当然,并不是DeepSeek不行,而是我问的问题不够具体。
正好,可以通过这三次的回答,来学习FFmpeg VFR 转 CFR 的关键参数。
相关参数
- 输入文件:
-i input.mkv指定输入文件。 - 视频过滤器:
-vf "fps=24,format=yuv420p"设置输出视频的帧率为 24 帧每秒,并将像素格式转换为 YUV 4:2:0,这是一种常见的压缩格式,兼容性较好。 - 视频编解码器:
-c:v libx264使用 H.264 编解码器进行视频编码。 - CRF 值:
-crf 23设置恒定质量的编码参数,数值越低,质量越高,文件大小也越大。23 是一个常用的平衡点。 - 预设:
-preset medium设置编码速度和压缩率的平衡点,medium 是一个常用的预设值。 - 同步模式:
-vsync cfr强制使用固定帧率输出。-vsync表示视频帧同步的⽅法:cfr或1:复制或丢弃从输⼊视频中选定的帧,以维持恒定的输出帧率;vfr或2:把选定的输⼊帧连同时间戳传递给输出⽂件,但丢弃时间戳重复的帧。 - 输出帧率:
-r 24设置输出视频的帧率为 24 帧每秒。 - 音频编解码器:
-c:a aac -b:a 192k使用 AAC 编解码器进行音频编码,设置比特率为 192 kbps。 - 快速启动标志:
-movflags +faststart使 MP4 文件在网络传输时可以更快地开始播放,这对于在线流媒体非常有用。 - 输出文件:
output.mp4指定输出文件名。
第三次命令的成功在于它同时解决了视频流处理、容器格式兼容性、音频转码和网络优化四大关键点。以下是详细对比分析:
第一次命令的问题
|
|
- 未指定输出帧率 (
-r)
fps=25滤镜会丢弃/复制帧以达到目标帧率,但未用-r显式声明输出流帧率,可能导致元数据仍标记为 VFR。 - 音频直接复制 (
-c:a copy)
若源音频是 MKV 特有的格式(如 FLAC),复制到 MP4 会失败(MP4 不支持 FLAC)。
第二次命令的改进与遗留问题
|
|
- 关键改进
- 添加
-r 25明确输出帧率 - 用
-vsync cfr强制 CFR 同步 format=yuv420p确保兼容播放器(H.264 要求 YUV 4:2:0)
- 添加
- 仍存在的缺陷
- 音频仍直接复制 (
-c:a copy),MP4 容器可能不兼容 - 输出格式仍是 MKV(非 MP4)
- 音频仍直接复制 (
第三次命令的成功要素
|
|
-
完整的帧率控制组合拳
1 2 3-vf "fps=24" # 滤镜层:重采样到24帧 -r 24 # 输出流层:标记帧率为24 -vsync cfr # 同步模式:强制CFR三位一体确保输出为真 CFR。
-
像素格式兼容性
format=yuv420p规避了 H.264 播放的色彩空间问题。 -
音频转码适配 MP4
-c:a aac -b:a 192k主动将音频转为 MP4 广泛支持的 AAC 格式,避免复制导致的兼容性错误。 -
容器格式优化
- 输出为
.mp4后缀 -movflags +faststart:将元数据移到文件头,实现网络视频秒开。
- 输出为
总结:成功命令的核心逻辑
| 组件 | 处理方案 | 作用 |
|---|---|---|
| 视频流 | -vf "fps=24" |
帧重采样 |
-r 24 |
设置输出帧率元数据 | |
-vsync cfr |
强制CFR同步模式 | |
| 像素格式 | format=yuv420p |
确保播放兼容性 |
| 音频流 | -c:a aac -b:a 192k |
转码为MP4兼容的AAC |
| 容器 | .mp4后缀 |
目标容器格式 |
| 网络优化 | -movflags +faststart |
优化MP4网络加载速度 |
总结
- 明确容器格式
当需要 MP4 时,务必在命令中显式指定后缀,并主动转码音频(如 AAC)。 - 帧率控制三位一体
同时使用fps滤镜 +-r+-vsync cfr可彻底确保 CFR。 - 像素格式保险
对 H.264/H.265 输出,始终添加format=yuv420p(或yuv420p10le支持 10bit)。 - 网络发布优化
-movflags +faststart对 MP4 网页播放至关重要。

当然,还有更简单也更复杂的方式来实现 VFR 转 CFR,就是用视频编辑软件来处理,比如 Adobe Premiere、Final Cut Pro 等。把视频导入软件中,设置帧率为固定帧率,然后导出即可。
附:moov(⾳视频⽂件的媒体信息头结构)
⾳视频⽂件的媒体信息头结构包含了⾳频⽂件和视频⽂件的总体描述信息,以及⾳视频流的播放控制信息等。
moov 是⼀个复合结构,其本身不包含实际的有效数据,⽽是作为其他结构的容器存在。由于其内部的多个⼦Box中包含多种重要结构,因此moov⾄关重要。
moov可能位于⽂件的头部或尾部。位于⽂件尾部的moov更适⽤于视频⽂件编码与压制系统,它可以在压制完成后直接将参数写⼊媒体信息头结构中,并写⼊输出⽂件,实现简单且效率更⾼。⽽在在线视频点播等流媒体应⽤场景中,当 moov 位于⽂件头部时,媒体的解码和播放会更加⾼效。
moov 对于MP4格式的解码和播放⾄关重要,解码器必须获取moov 的全部信息,才能在成功解析后获取其中每⼀个码流包的位置和时间戳。当使⽤ffmpeg的默认参数输出为MP4格式时,moov会在所有数据转封装完成后⽣成,然后添加在⽂件的末尾。由于获取moov相对较为复杂,因此MP4格式对流媒体播放等场景并不友好。为了解决该问题,在使⽤ffmpeg进⾏转封装操作时,可以在选项-movflags 中加⼊参数faststart。