使用ffmpeg根据开始和结束时间剪切视频


510

我尝试通过使用以下命令使用视频的开始和结束时间剪切视频

ffmpeg -ss 00:00:03 -t 00:00:08 -i movie.mp4 -acodec copy -vcodec copy -async 1 cut.mp4

通过使用上述命令,我想将视频从剪切00:00:0300:00:08。但是,这并不是在这段时间之间剪切视频,而是在前11秒内剪切视频。谁能帮我解决这个问题?

编辑1:

我试图通过使用mark4o建议的以下命令进行剪切

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

但是显示以下错误。

编码器“ aac”是实验性的,但未启用实验性编解码器

所以我-strict -2在命令中添加了

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -strict -2 cut.mp4

现在工作正常。


3
您完整的,未剪辑的ffmpeg控制台输出丢失。询问时请始终包括此内容。谢谢。
slhck

3
您从哪里获得-strict 2?只是好奇,因为它不在文档中:ffmpeg.org/ffmpeg.html
StackOverflowed

在安装ffmpeg后提高质量,在ffmpeg帮助中您可以找到此选项
Kalai


1
我认为这里的问题实际上只是您在-i movie.mp4之前和之后放置了一个事实。该流之后的参数在它之后,对吗?这就是为什么其他方法起作用的原因。= /
布伦特·里滕豪斯

Answers:


572

您可能在3秒标记处没有关键帧。由于非关键帧编码与其他帧的差异,因此它们需要从前一个关键帧开始的所有数据。

使用mp4容器,可以在非关键帧处进行剪切,而无需使用编辑列表进行重新编码。换句话说,如果最接近3s的关键帧位于0s,则它将复制从0s开始的视频,并使用编辑列表告诉播放器开始播放3秒。

如果您使用的是git master中的最新ffmpeg,则在使用提供的命令调用该列表时,将使用编辑列表来执行此操作。如果这不适合您,则可能是您使用的是较旧版本的ffmpeg,或者您的播放器不支持编辑列表。一些播放器将忽略编辑列表,并始终从头到尾播放文件中的所有媒体。

如果要从非关键帧开始精确剪切,并且希望它在不支持编辑列表的播放器上从所需点开始播放,或者要确保剪切部分实际上不在输出文件中(例如, (如果其中包含机密信息),则可以通过重新编码来实现,这样就可以在所需的开始时间准确显示关键帧。如果未指定,则默认为重新编码copy。例如:

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4

重新编码时,您可能还希望包括其他与质量相关的选项或特定的AAC编码器。有关详细信息,请参阅ffmpeg的x264视频编码指南AAC音频编码指南

另外,该-t选项指定持续时间,而不是结束时间。上面的命令将从3s开始对8s的视频进行编码。要从3s开始并在8s结束,请使用-t 5。如果您使用的是ffmpeg的当前版本,也可以在上述命令中将替换-t-to在指定时间结束。


4
在影片结束前是否有指定捷径?
Jikku Jose

20
@JikkuJose:省略-t/ -to及其参数继续到结尾。
mark4o

41
注意:-ss在输入文件之前(之前-i)提供文件的速度更快,因为ffmpeg会直接跳到该位置。但是,这还将把时间设置为该位置的“零”,这意味着-to将指向错误的时间。资料来源:trac.ffmpeg.org/wiki/Seeking
DenilsonSáMaia

4
使用此工具后出现音频和视频同步问题ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4,尽管原始文件没有此类问题。
user2002522

6
@ user2002522:尝试不使用-async 1
mark4o 2015年

429

尝试使用这个。这是我弄清楚的最快最好的ffmpeg方式:

 ffmpeg -ss 00:01:00 -i input.mp4 -to 00:02:00 -c copy output.mp4

此命令可在几秒钟内修剪您的视频!

我已经解释它在我的博客在这里

-i:这指定输入文件。在这种情况下,它是(input.mp4)。
-ss:与-i一起使用,它在输入文件(input.mp4)中查找位置。
00:01:00:这是您修剪的视频开始的时间。
-至:这指定从开始(00:01:40)到结束(00:02:12)的持续时间。
00:02:00:这是您修剪的视频结束的时间。
-c复制:这是通过流复制修剪的选项。(注:非常快)

计时格式为:hh:mm:ss

请注意,当前高度评价的答案已过时,修剪将非常慢。有关更多信息,请参见ffmpeg官方文章


9
这在3秒钟内处理了我的45分钟720p文件。这应该是正确的答案。
Dheeraj Bhaskar

7
但是,您可能仍然缺少关键帧。我采用您的方法进行剪切,然后根据公认的答案进行重新编码,以确保将重新编码所需的时间减至最少。
pelson

7
如@pelson所说,这将切断关键帧并保留前几秒为空白(如果剪切时间在关键帧之间)。有趣的是,更改参数顺序可以解决以下问题:ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -ss 00:01:00 -to 00:02:00 -c copy output.mp4。但是,现在跳过被打破了,结束时间不正确(在我的情况下)。
拉斐尔

6
如果您不需要精确地修剪,则应使用此答案,这样它将选择最接近的关键帧。这就是为什么它是如此之快,它选择最接近的关键帧并不需要重新编码就可以摘录片段。但是,如果您确实需要精确的时间,则仅取最接近的关键帧是不够的,因为它肯定不完全匹配。唯一可用的解决方案是对视频进行重新编码,这就是为什么它这么慢。但是,如果您确实需要这样做,那是唯一的解决方案。这就是为什么另一个答案应该被接受的原因,这就是OP的问题所在。
Yamaneko,

4
不知道为什么,但是这似乎比接受的答案更正确,因为这会导致缺少关键帧的问题。对于短视频剪辑,效果不可接受。在这种情况下,慢速重新编码似乎是唯一的解决方案。
icarus74 '18

91
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 

使用-c复制即可即时制作。在这种情况下,ffmpeg不会重新编码视频,只会切成适当的大小。


2
-c复制的效果很好,但前提是我删除了-async 1
dorien

2
在不同的输入和输出容器(例如.mkv输入和.mp4输出)的情况​​下,由于无效的标头而导致写入失败。
阿西尔·基西

1
好了,要将.mkv转换为.mp4,您必须使用另一个命令:ffmpeg -i movie.mkv -vcodec copy -acodec copy converted_movie.mp4反之亦然
Vlad Hudnitsky

重新编码有什么优势?如果我们只想要相同格式的较小视频,有什么用吗?
哈莎

29
    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

将所有内容从秒3减至秒8。


4
我得到了前8秒,而前3秒冻结在第一帧上。setpts=PTS-STARTPTS在修整滤镜之后通过链接滤镜固定。
jiggunjer 2015年

这表示“编码器'aac'是实验性的,但实验性编解码器未启用,如果要使用它,请添加'-strict -2'。” 添加-strict -2没有帮助。结果是零长度的文件。
伊万

4
@Ivan,您尝试添加-strict -2之前cut.mp4(而不是命令行末尾)吗?
Jan Gondol '16

嘿,您能告诉我是否只需要3到8秒的视频吗?
Parth Solanki

1
这太慢了
Tessaracter19年

21

要基于源视频的开始时间和结束时间进行剪切并避免进行数学运算,请指定结束时间作为输入选项,并指定开始时间作为输出选项。

ffmpeg -t 1:00 -i input.mpg -ss 45 output.mpg

这将在0:45到1:00之间产生15秒的切换。

这是因为将when -ss用作输出选项时,丢弃的时间仍包含在从输入读取的总时间中,该时间-t用来知道何时停止。而如果-ss将其作为输入选项,则会寻找开始时间而不是开始时间,这是造成混乱的原因。

这比查找要慢,因为省略的段在丢弃之前仍会进行处理,但是据我所知,这是唯一的方法。如果要从一个大文件中深切,则最好进行数学运算并将其-ss用于输入。


4
速度很慢,但对我来说唯一有效(不会丢失其他答案的帧)
techkuz19年

8

这是我使用的:

ffmpeg -i input.mkv -ss 00:01:00 -to 00:02:00 -c:v copy -c:a copy output.mp4

生成的mp4文件也可以在中使用iMovie

参考:https : //www.arj.no/2018/05/18/trimvideo


如果要串联多个剪切场景,可以使用以下脚本:

#!/usr/bin/env python3

import subprocess

name = "batman.mp4"

times = []
times.append(["01:06:00", "01:07:00"])
times.append(["01:08:00", "01:09:00"])

open('concatenate.txt', 'w').close()
for idx, time in enumerate(times):
    output_filename = f"output{idx}.mp4"
    cmd = ["ffmpeg", "-i", name, "-ss", time[0], "-to", time[1], "-c:v", "copy", "-c:a", "copy", output_filename]
    subprocess.check_output(cmd)
    with open("concatenate.txt", "a") as myfile:
        myfile.write(f"file {output_filename}\n")

cmd = ["ffmpeg", "-f", "concat", "-i", "concatenate.txt", "-c", "copy", "final.mp4"]
output = subprocess.check_output(cmd).decode("utf-8").strip()

不过,这已经得到了解答
Tessaracter19年

1
我的方法不同于公认的答案。我尝试过那些时间较长的文件来构建mp4文件。@Tessaracter
alper

1
这是我从大型视频中剪下一个小片段的唯一答案。这有效并且快速!!!谢谢
lacostenycoder

1
不客气,我很高兴能为您提供帮助。在尝试了许多方法之后,我能够找到这个答案。他们中的大多数人都很慢。@lacostenycoder
日晚

这难道不是只将“ -c”与“ copy”一起使用,而不是将-c:v和-c:a分开吗?
nstenz


-3

尽管我迟到了6年,但我认为以上所有答案都无法正确解决@kalai提出的问题。下面的bash脚本将处理以下格式的文本文件:

URL | start_time | end_time | filename

例如

https://www.youtube.com/watch?v=iUDURCrvrMI|00:02:02|00:03:41|1

并遍历文件,下载文件是youtube-dl支持的,计算之间的持续时间start_timeend_time并将它传递给ffmpeg,因为-t实际上是时间,而不是真正的end_time

如有任何问题请打我。

    for i in $(<video.txt);
    do
        URL=`echo $i | cut -d "|" -f 1`;
        START=`echo $i | cut -d "|" -f 2`;
        END=`echo $i | cut -d "|" -f 3`;
        FILE=`echo $i | cut -d "|" -f 4`;

        SEC1=`echo $START | sed 's/^/((/; s/:/)*60+/g' | bc`
        SEC2=`echo $END | sed 's/^/((/; s/:/)*60+/g' | bc`

        DIFFSEC=`expr ${SEC2} - ${SEC1}`

        ffmpeg $(youtube-dl -g $URL | sed "s/.*/-ss $START -i &/") -t $DIFFSEC -c copy $FILE".mkv";
        ffmpeg -i $FILE".mkv" -f mp3 -ab 192000 -vn $FILE".mp3";
        rm $FILE".mkv";
    done;

这仅输出mp3音频文件,而不输出视频。
lacostenycoder

是的...只需更改输出格式。
rolodex
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.