48

这不是一个特别新的问题领域,但我已经尝试了那里的建议,但运气不佳。所以,我的故事:

我有一大块 15 秒的直接 from-the-camera.mov 视频,我想从中提取一个特定的块,我可以通过开始时间和停止时间来识别它,以秒为单位。我首先尝试做我称之为“复制提取”的事情:获得 9 到 12 秒,

ffmpeg -i test.mov -vcodec copy -acodec copy -ss 9 -to 12 test-copy.mov

这是一个不错的开始,但是剪辑的开头和结尾有一些黑框,这是我无法做到的——它必须是对原始版本的干净剪辑。所以,我尝试将原件重新编码成一个新的、修剪过的剪辑:

ffmpeg -i test.mov -ss 00:00:09 -t 00:00:03 test-out.mov

这更好,但不完全是:剪辑的开头不再有任何黑框,但它们仍然存在。

经过更多的浏览和阅读,我怀疑问题是由于原始视频中缺少关键帧,ffmpeg 无法找到合适的点。所以我重新编码了原始视频以(大概)以几种不同的方式添加关键帧。因为我希望能够在一秒的边界(“从 9 秒到 12 秒”)选择视频,所以我尝试在网络上复制各种建议,

ffmpeg -i test.mov -force_key_frames "expr:gte(t, n_forced)" test-forced.mp4

ffmpeg -i test.mov -g 1 test-g-inserted.mp4

(我根据一些关于需要 mp4 容器来支持关键帧搜索的评论将这些构建为 mp4,但老实说,我只是在这里破解。)然后我像以前一样尝试提取,但是在这些可能现在有关键帧的新视频上在他们中。不走运——两者似乎差不多;开始是好的,但最后仍然有黑框。(FWIW,test-forced.mp4 和 test-g-inserted.mp4 也有尾随黑框。)

所以:我仍然被困住,并且不想被困住。关于我做错了什么的任何见解?我觉得我很接近了,但我真的需要摆脱那些拖尾的黑框......

4

6 回答 6

49

好的,首先假设您知道开始和停止的持续时间;我们将在该持续时间内添加关键帧。

ffmpeg -i a.mp4 -force_key_frames 00:00:09,00:00:12 out.mp4

大多数情况下,您可以直接完美地剪切视频,但在您的情况下它对您没有帮助;所以我们已经通过上面的命令处理了它。此处请注意不要添加太多关键帧,因为在按照Ffmpeg Docs进行编码时可能会出现问题。

现在您可以再次尝试从特定时间剪切视频。

ffmpeg -ss 00:00:09 -i out.mp4 -t 00:00:03 -vcodec copy -acodec copy -y final.mp4

这将解决问题,因为我们在剪切的起点和终点手动添加了关键帧。它对我有用。

干杯。:)

于 2014-01-29T05:22:45.953 回答
13

我认为问题和其他答案的问题是它们-ss用作输出文件的选项,而不是输入文件。大多数 ffmpeg 选项不是全局的,而是仅适用于它们之前的文件。选项需要去哪里通常并不明显,因此有时需要反复试验。

在它们要应用于的输入文件之前正确使用,-ss并且-t对我来说工作得很好。在输出中包含音频时,我必须将其-shortest用作输出文件的选项,否则我会得到 2 分钟的音频和 2 秒的视频。

ffmpeg 版本 N-67413-g2a88c74(基本上是 2014 年 12 月 14 日的 git 源)

这是我最近用来制作剪辑的命令行。(实际上调整为一个更好的例子,因为我为此留下了音频,并没有慢动作。)

ffmpeg -ss 120.2 -t 0.75 -i ../mcdeint.60p.lossless264.slow.mkv -c:a libopus -shortest -aspect 16:9 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -movflags +faststart clip2.mkv

使用-c:a copy(源具有 AC3 音频),播放开始时 mplayer 不稳定。它可能从包含开头的音频帧的开头抓取音频,然后必须在容器中使用 aa/v 偏移量。在启动时,音频需要几分之一秒的时间才能领先于视频该偏移量,在此之前视频以非常低的 FPS 播放。所以我对音频进行了编码。opus 和 pcm_s16le 都不能进入 mp4,所以我在这个例子中使用了一个 mkv 容器。

源是来自非常慢的 yadif=3:1,mcdeint=3:1:10 输出的无损 x264 编码 ( -qp 0)(来自 NTSC DVD 的一些 BFF 隔行扫描视频,可能来自 DV 摄像机)。不是所有I帧,而是P具有正常关键帧间隔的帧。

将 -ss 调整 0.2 秒正是我希望的,所以 ffmpeg 必须处理解码到所需的点。这不仅仅是我想要的 I 框架的巧合。也许-accurate_seek是默认值?当我使用 ffvhuff 无损源作为输入时,我也得到了相同的结果(逐字节相同的 gif 输出)。(但它运行得更快,因为它不必解码到请求的点。)

另一个可能相关的选项是-seek2any,但它说“在解复用器级别寻找非关键帧”,听起来它会让您以会产生乱码输出的方式寻找。(即开始解码而不实际生成当前帧所需的引用,只使用全灰色?)

我没有尝试使用-c:v copy,因为我要剪出一个非常短的剪辑来循环播放,所以我知道不会有I我需要它们的帧。

这是我实际使用的命令行,用于制作没有声音的短慢动作剪辑。

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -c:v libx264 -preset veryslow -x264-params nr=250:ref=6 -crf 22 -filter:v "setpts=3.0*PTS" -movflags +faststart -r 20 clip.mp4

请注意,这-r 20很重要,因为与 mkv 不同,ffmpeg 的 MP4 输出仅是恒定帧率(编辑:因为-vsync vfr不是 mp4 多路复用器的默认设置)。没有告诉它不同,它会设置输出 FPS = 输入 FPS,并在需要时复制帧以实现这一点。x264 和动画 gif(具有透明度)都可以非常有效地对重复帧进行编码,但它仍然很傻。

在将其作为示例进行编写之前,我分两步完成,一个输出到 mkv,然后输出ffmpeg -i clip.mkv -c:v copy -movflags +faststart -r 20 clip.mp4到 remux。顺便说一句,可以在重新混合时更改视频的 fps,无需 xcoding,而不能使用 ffmpeg。 https://superuser.com/questions/740196/reducing-video-size-with-avconv-why-does-the-size-increase。但无论如何,ffmpeg 在制作 mkv 时只向 libx264 发送了 45 帧,尽管它认为它正在以 60fps 的速度制作 2.2 秒的视频。不要将 ffmpeg 与 mp4 一起使用来处理可变的 FPS 内容。

编辑:原来ffmpeg默认-vsync vfr为mkv输出,但不是mp4。使用-vsync vfr,ffmpeg 可以将 VFR 写入 mp4 输出就好了。

再次用于 gif 输出,以防我决定不使用 HTML5 视频 ( <video controls autoplay loop> <source src="clip.mp4" type="video/mp4"> </video>)

ffmpeg -ss 120.2 -t 0.75 -i ../vid.yadif3.1,mcdeint3.1.10.ffvhuff.mkv -an -shortest -aspect 16:9 -filter:v "setpts=3.0*PTS,scale=854x480" -r 20 clip.gif

我不得不使用scale=,因为 gif 容器不存储纵横比,所以它不能在播放时自动缩放。(我的 720x480 像素 16:9 视频在播放时被缩放到 854x480。实际上应该是 853.333,但是会四舍五入,然后 ffmpeg 将 853x480 存储在 mkv 容器中,因此一直使用 -aspect 16:9,所以我的 mp4 会存储正确的纵横比[SAR 32:27 DAR 16:9],而不是[SAR 186:157 DAR 279:157])

于 2015-01-05T16:00:32.157 回答
6

在树林里戳睡熊 ‍♂️。我没有看到任何提及-to该线程中提到的标志,我发现它比-t标志更有用。一个对我很有效的示例命令,

ffmpeg -y -i [INPUT.file] -ss 00:42:42 -to 00:84:84 -codec copy [OUTPUT.file]
于 2019-03-14T17:17:03.753 回答
5

[更新:这个答案可能不正确 - 请参阅评论]

无需添加关键帧;正如彼得所说,这只是一个以正确顺序获得选项的问题。但是,请参阅https://trac.ffmpeg.org/wiki/Seeking以获取有关如何正确操作的权威官方指南。

于 2015-01-14T12:20:37.930 回答
0

我也想知道。到目前为止,我已经无损地转换了我的视频,提取了一个片段并在编辑后对其重新编码:

ffmpeg -i input -ss 9.48 -t 3.52 -c:v libx264 -crf 0 -g 1 -c:a copy TempIframe.mp4

但这是一个耗时且有损的过程......

我尝试了以下但没有成功:

ffmpeg -i source.mp4 -ss 1 -c:v copy -seek2any 1 -avoid_negative_ts 1 -safe 1 -c:a copy segment.mp4
于 2014-01-29T01:53:34.850 回答
0

我在上面的例子中并不是很成功,因为每次结果都是视频与音频未正确同步。

解决方案是使用trimandatrim过滤器,其时间戳以秒为单位,因为[-][<HH>:]<MM>:<SS>[.<m>...]格式不起作用,所以我不得不使用[-]<S>+[.<m>...]格式,如man ffmpeg-utils.

mpv --osd-fractions首先,我使用我的视频提取要剪切的确切时间戳,然后将其转换为秒格式:

start 00:11:59.560
end 00:14:31.080

start 719.56
end 871.08

最后一步,运行

ffmpeg -i in.mp4 -vf "trim=start=719.56:end=871.08,setpts=PTS-STARTPTS" -af "atrim=start=719.56:end=871.08,asetpts=PTS-STARTPTS" out.mp4

请注意,您需要为trimatrim过滤器指定两次时间戳,但是,生成的视频会正确同步。

于 2021-11-14T02:45:32.100 回答