繁体   English   中英

如何使用ffmpeg提取时间准确的视频片段?

[英]How to extract time-accurate video segments with ffmpeg?

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

我有一大块 15 秒的直接来自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 也有尾随黑框。)

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

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

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

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

干杯。:)

我认为问题和其他答案存在的问题是他们使用-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 必须将解码处理到所需的点。 不仅仅是我想要的框架的巧合。 也许-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 -vsync vfr器的默认设置)。 没有告诉它不同,它会设置输出 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] )

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

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

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

ffmpeg -y -i [INPUT.file] -ss 00:42:42 -to 00:84:84 -codec copy [OUTPUT.file]

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

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

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

解决方案是使用带有以秒为单位给出atrimtrimatrim过滤器,因为[-][<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过滤器指定两次时间戳,但是,生成的视频已正确同步。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM