我一直找不到一款能够拍摄视频文件(最好是 avi、mkv 和 mp4)并精确剪辑出非常短的片段(2-6 秒)的 cli 应用程序。我试过ffmpeg,门编码器,艾维德姆, 和mp4盒但它们都在关键帧上进行剪切,从而创建了 6 秒以上的剪辑。是否有工具可以重新编码输入文件并剪切准确的时间或不准确地剪切,重新编码,然后准确剪切?
答案1
使用剪辑视频ffmpeg
你能使用 FFmpeg 精确剪切视频。从 2.5 版开始就变得非常容易。
例如,这将从 0 分 3 秒 123 毫秒开始缩短 10 秒。
ffmpeg -ss 00:00:03.123 -i input.mp4 -t 10 -c:v libx264 -c:a copy out.mp4
位置和时间可以以秒为单位,也可以以hh:mm:ss[.xxx]
形式为单位。
请注意,在这些示例中,视频将使用x264编码器;音频被复制过来。
您还可以使用-to
而不是-t
来指定结束点而不是持续时间。但是,在这种情况下,-to
相当于-t
,因为通过将 放在-ss
前面-i
,ffmpeg 将首先寻找该点,然后开始输出。
如果输出似乎没有被正确剪切,则添加-fflags +genpts
命令可能会有所帮助。
另请参阅寻求维基百科条目。
答案2
到目前为止我发现的唯一一个可以按精确帧(或按帧精度)进行剪切的 Linux 命令行工具是melt
( sudo apt-get install melt
)。
假设你有一个inputvid.mp4
- 首先使用 say 检查它的编码设置ffmpeg
(这里,我只是说我想再次将它编码为-f mp4
,但是作为文件,/dev/null
所以输出被丢弃;我重定向 stderr 以便我可以通过它进行 grep - 注意在中间,命令提示符,你应该y
用 ENTER 回答,所以过程继续并转储有用的信息;这是在 Ubuntu 14 上使用 ffmpeg 3.3.3):
ffmpeg -i inputvid.mp4 -f mp4 /dev/null 2>&1 | grep 'Stream\|encoder'
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709), 640x360 [SAR 1:1 DAR 16:9], 389 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 95 kb/s (default)
y
File '/dev/null' already exists. Overwrite ? [y/N] Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #0:1 (aac (native) -> aac (native))
encoder : Lavf57.71.100
Stream #0:0(und): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p(progressive), 640x360 [SAR 1:1 DAR 16:9], q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
encoder : Lavc57.89.100 libx264
Stream #0:1(und): Audio: aac (LC) ([64][0][0][0] / 0x0040), 44100 Hz, stereo, fltp, 128 kb/s (default)
encoder : Lavc57.89.100 aac
好的,我们可以看到此视频的ffmpeg
选择libx264
和aac
编码器;然后我们可以输入这个melt
:
melt inputvid.mp4 in=7235 out=7349 -consumer avformat:cut.mp4 acodec=aac vcodec=libx264
.... 并将melt
帧 7235 和 7349 之间的片段剪切到新文件中。cut.mp4
然后检查cut.mp4
循环是否正确,使用melt
again 播放两次 - 并将其播放到 SDL 窗口:
melt cut.mp4 cut.mp4 -consumer sdl
... 以下是ffmpeg
此文件的内容:
ffmpeg -i cut.mp4 -f mp4 /dev/null 2>&1 | grep 'Stream\|encoder' encoder : Lavf54.20.4
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x360 [SAR 1:1 DAR 16:9], 526 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 182 kb/s (default)
y
File '/dev/null' already exists. Overwrite ? [y/N] Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #0:1 (aac (native) -> aac (native))
encoder : Lavf57.71.100
Stream #0:0(und): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 640x360 [SAR 1:1 DAR 16:9], q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
encoder : Lavc57.89.100 libx264
Stream #0:1(und): Audio: aac (LC) ([64][0][0][0] / 0x0040), 48000 Hz, stereo, fltp, 128 kb/s (default)
encoder : Lavc57.89.100 aac
视频编码设置cut.mp4
似乎与相同,inputvid.mp4
只是视频比特率从 389 kb/s 变为 526 kb/s,音频编码设置也几乎相同,只是采样率从 44100 变为 48000 Hz;不过可以通过以下方式进行调节:
melt inputvid.mp4 in=7235 out=7349 -consumer avformat:cut.mp4 acodec=aac ar=44100 ab=95k vcodec=libx264 vb=389k
... 但是,即使这样,最终的视频比特率对我来说也只有 337 kb/s。不过,当循环播放时,剪辑片段(包括音频)可以很好地循环播放,所以我猜这确实是帧精确的...
答案3
就像 Baodad 在评论中所说的那样(我发布是因为如果你快速阅读的话不容易找到),更好的方法是通过 ffmpeg 自动检测音频/视频编码器,所以:
ffmpeg -ss 00:05:17.18 -i in.mp4 -t 00:06:29.10 -acodec copy -vcodec copy out.mp4
- 开始于 00:05:17.18
- 输入 = in.mp4
- 停止于 00:06:29.10
- 输出 = out.mp4
答案4
在对类似问题的回答中,提到了早期版本中使用 -ss 会导致不可靠的结果。但在新版本中似乎也一样。总结一下,如果在 -i 之前使用 ss/to/t,它会在 i 帧处剪切,在 -i 之后,它会在指定时间剪切并使用下一个 i 帧,直到达到该帧,即您会得到到那时为止的静止图像。如果不是巧合的话,在 -to 时它可能会按要求剪切。我以为您可以通过编码 i 帧之前的部分并复制之后的部分来获得准确的剪切,但显然您无法合并生成的文件。我们可以安全地得出结论,如果不编码整个视频,就不可能准确切断 i 帧吗?