使用 FFMPEG,如何将视频分成相等长度的片段那可能会或者可能不会从 KeyFrames 开始?
假设你熟悉部分格式和打破非关键帧选项,FFMPEG 会不是似乎做了我期望的事情(从我读到的内容来看......再也找不到链接了)。
ffmpeg -i ... -f segment -break_non_keyframes 1 -segment_time 2 -c copy 2secs%03d.ts
即,创建一个实际上可能比所需段更长的段,必要时包括整个 GOP。
例如,假设一个 3 帧 GOP,其愚蠢的帧速率为 1 FPS,并具有以下愚蠢的 IBP 节奏:
01 02 03 11 12 13 21 22 23 31 32 33
I B P I B P I B P I B P
如果我想将其分成 2 秒的片段,则应该会看到以下生成的片段(括号内的帧不会显示在该片段中):
01 02 03 (03 not displayed in this segment, only used for decoding)
01 02 03 11 (... 01 and 02)
11 12 13 (... 11 )
21 22 23 (... 23)
21 22 23 31 (...21 22)
31 32 33 (... 31)
如您所见,每个片段都会有额外的帧,但给定起始 PTS 和结束 PTS,您始终可以单独播放/转码该片段。
这确实浪费了空间(片段的总和将比原始资产大得多),但这不是这里的重点。重点是拥有独立的片段而无需转码。
答案1
很遗憾,目前的片段复用器无法实现这一点。该break_non_keyframes
选项针对的是 HLS 等情况,其中许多播放器将片段视为连续的数据包流,因此将参考数据拆分到多个文件中不是问题。
我很好奇你在这里的实际用例是什么。你在哪里需要固定长度的片段,每个片段都必须可以解码为完全独立的文件?我怀疑大多数播放器会按照你希望的方式处理这个问题;在没有参考图片的情况下,播放器通常会显示绿色或灰色伪影,而不是丢帧。
另外,您的 IBP 节奏有点误导。假设您的帧编号是显示顺序,则您的帧在流中的顺序实际上是 IPB/IPB/IPB/IPB。
如果您确实需要此功能,则可以(但并非完全不重要)在段复用器中实现。您需要缓冲每个传入的数据包,每次命中 IDR 帧时丢弃缓冲区,并将缓冲区写入您开始写入的下一个文件。
引用:我实现了该break_non_keyframes
设置。
答案2
当我跑步时
ffmpeg -i input.mp4 -f segment -c copy -reset_timestamps 1 -segment_time 2 -break_non_keyframes 1 a%02d.mp4
然后使用 ffplay 播放输出的 MP4 片段,尽管出现许多错误消息,但其中许多片段播放正常。仅播放了 2 秒的部分。少数片段播放时有瑕疵,即关键帧尚未解码。但是,如果我将片段时间设置为更高的值,例如 11,则所有片段都可以通过 ffplay 按照您希望的方式播放。TS 输出并非如此。此外,在 VLC 等常规播放器中播放效果不佳。
或者,如果我使用下面的模板创建一个片段
ffmpeg -ss N -t 2 -i input.mp4 -c copy aN.ts
Potplayer 播放得很好 - 只有 2 秒部分,没有错误。ffplay 播放所有混合帧,没有错误。VLC 只播放了 2 秒部分,但有故障。在我的测试中,30 fps 视频的 229 帧被混合到输出中。
tl;dr 不同的播放器对包含负 DTS/PTS 帧的文件的处理方式不同。您的用例是什么?