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

Kal*_*lai 457 linux video ffmpeg video-editing

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

ffmpeg -ss 00:00:03 -t 00:00:08 -i movie.mp4 -acodec copy -vcodec copy -async 1 cut.mp4
Run Code Online (Sandbox Code Playgroud)

通过使用上面的命令,我想将视频剪切00:00:0300:00:08.但它并没有在这些时间之间切断视频,而是在前11秒内切断视频.任何人都可以帮我解决这个问题吗?

编辑1:

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

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4
Run Code Online (Sandbox Code Playgroud)

但它显示以下错误.

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

所以我添加-strict -2到命令,即,

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -strict -2 cut.mp4
Run Code Online (Sandbox Code Playgroud)

现在工作正常.

mar*_*k4o 507

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

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

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

如果你想精确地从非关键帧开始剪切并希望它从不支持编辑列表的播放器上的所需点开始播放,或者想要确保剪切部分实际上不在输出文件中(例如如果它包含机密信息),那么你可以通过重新编码来做到这一点,以便在所需的开始时间精确地存在一个关键帧.如果未指定,则重新编码是默认值copy.例如:

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4
Run Code Online (Sandbox Code Playgroud)

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

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

  • 注意:在输入文件之前(在`-i`之前)提供`-ss`会更快,因为这样ffmpeg将直接跳到该位置.但是,这也会将时间设置为"零"到该位置,这意味着`-to`将指向错误的时间.来源:https://trac.ffmpeg.org/wiki/Seeking (29认同)
  • @JikkuJose:忽略`-t` /`-to`及其参数继续结束. (16认同)
  • @ user2002522:尝试没有`-async 1`. (6认同)
  • 使用这个```ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4```后我得到音频和视频同步问题,虽然原始文件没有这样的问题. (4认同)
  • 是否有快捷方式指定直到视频结束? (3认同)
  • 这个答案,http://stackoverflow.com/a/14013439/1170023是您想要使用-c复制来查找关键帧时间以避免音频同步的原因 (2认同)
  • 有没有办法只重新编码直到下一个关键帧的部分,然后复制其他所有内容? (2认同)

Geo*_*oub 341

试试这个.这是我发现的最快,最好的方式:

 ffmpeg -ss 00:01:00 -i input.mp4 -to 00:02:00 -c copy output.mp4
Run Code Online (Sandbox Code Playgroud)

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

我在我的博客上解释:

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

时间格式为:hh:mm:ss

请注意,目前高度响应的答案已经过时,修剪速度非常慢.有关更多信息,请查看此官方ffmpeg 文章.

  • 这在3s内处理了我的45分钟720p文件.这应该是正确的答案. (9认同)
  • 尽管如此,你可能仍然会遇到缺少关键帧的问题.我采用你的切割方法,然后根据接受的答案重新编码,以确保我最大限度地减少了重新编码所需的时间. (6认同)
  • 正如@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`.但是,现在,跳过被破坏,结束时间不正确(在我的情况下). (5认同)
  • 不确定为什么,但这似乎不比接受的答案更正确,因为这会导致丢失关键帧的问题.对于短视频剪辑,效果是不可接受的.在这种情况下,缓慢的reencode似乎是唯一的解决方案. (4认同)
  • 如果您不需要精确修剪毫秒,则应使用此答案,因此它将选择最接近的关键帧.这就是为什么它如此之快,它选择最接近的关键帧并将片段取出而无需重新编码.但是,如果你确实需要一个精确的时间,那么取最近的关键帧是不够的,因为它肯定不会完全匹配.唯一可用的解决方案是对视频进行重新编码,这就是它如此缓慢的原因.但是,这是唯一的解决方案,如果你确实需要这个.这就是为什么另一个答案应该是被接受的答案,因为这就是OP的问题. (3认同)
  • 您可能需要在 `-i` 之前使用 `-ss` * 和* `-to`,例如:`ffmpeg -ss aa:bb:cc -to xx:yy:zz -i input.mp4 -c copy output.mp4` . 否则,`-to` 值最终会成为原始视频的持续时间而不是结束时间。省略 `-c copy` 将通过重新编码使其更慢和更准确,但仍然比在 `-i` 之后指定 `-ss` 和 `-to` 时更快,因为这种情况意味着在有处理整个输入文件。 (3认同)
  • 对于我的Linux机器(Ubuntu 16.04,ffplay版本2.8.14),此命令行以某种方式损坏了输出视频. (2认同)
  • @Yamaneko如果您需要精确到毫秒进行剪切,但又不想浪费时间重新编码文件的很大一部分,我发现从所需的开始时间剪切到下一个时间范围(通常是 2 秒的倍数)很有用),然后将其与从关键帧剪切到所需结束时间的第二个视频文件相结合。您可以将这两个文件转码为 TS 格式,然后简单地附加它们以合并两个剪辑,如果需要不同的输出格式,则使用 ffmpeg 重新混合。 (2认同)

Vla*_*sky 82

ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 
Run Code Online (Sandbox Code Playgroud)

立即使用-c copy for make.在这种情况下,ffmpeg不会重新编码视频,只会根据大小进行切割.

  • -c复制的效果很好,但仅当我删除-async 1时 (2认同)
  • 在不同的输入和输出容器(例如 .mkv 输入和 .mp4 输出)的情况​​下,由于标头无效,这最终会导致写入失败。 (2认同)

小智 27

    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4
Run Code Online (Sandbox Code Playgroud)

删除除第二个3到第二个8之外的所有内容.

  • @Ivan,您是否尝试在`cut.mp4`之前添加`-strict -2`(而不是命令行的结尾)? (4认同)
  • 我得到了前8秒,第一帧冻结了前3秒.通过在修剪过滤器之后链接`setpts = PTS-STARTPTS`过滤器来修复. (3认同)
  • 这太慢了 (2认同)

alp*_*per 24

这是我使用的,只需几秒钟即可运行:

ffmpeg -i input.mp4 -ss 01:19:27 -to 02:18:51 -c:v copy -c:a copy output.mp4
Run Code Online (Sandbox Code Playgroud)

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


生成的mp4文件也可以在iMovie. 有关使用get_duration(input_video)模型获取完整持续时间的更多信息。


如果要连接多个过场动画,可以使用以下 Python 脚本:

#!/usr/bin/env python3

import subprocess


def get_duration(input_video):
    cmd = ["ffprobe", "-i", input_video, "-show_entries", "format=duration",
           "-v", "quiet", "-sexagesimal", "-of", "csv=p=0"]
    return subprocess.check_output(cmd).decode("utf-8").strip()


if __name__ == "__main__":
    name = "input.mkv"

    times = []
    times.append(["00:00:00", "00:00:10"])
    times.append(["00:06:00", "00:07:00"])

    # times = [["00:00:00", get_duration(name)]]

    if len(times) == 1:
        time = times[0]
        cmd = ["ffmpeg", "-i", name, "-ss", time[0], "-to", time[1], "-c:v", "copy", "-c:a", "copy", "output.mp4"]
        subprocess.check_output(cmd)
    else:
        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", "output.mp4"]
        output = subprocess.check_output(cmd).decode("utf-8").strip()

Run Code Online (Sandbox Code Playgroud)

示例脚本将剪切和合并00:00:00 - 00:00:10和之间的场景00:06:00 - 00:07:00


如果您想剪切完整的视频(如果您想将mkv格式转换为mp4),只需取消注释以下行:

# times = [["00:00:00", get_duration(name)]]
Run Code Online (Sandbox Code Playgroud)

  • 这是这里唯一对我从大视频中剪切小剪辑有用的答案。这有效而且快!!!谢谢 (2认同)
  • 不客气,我很高兴能提供帮助。在尝试了多种方法后,我找到了这个答案。他们中的大多数人都非常慢。@lacostenycoder (2认同)

Rya*_*efi 16

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

ffmpeg -t 1:00 -i input.mpg -ss 45 output.mpg
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 速度很慢,但对我来说唯一有效(不会因其他答案而丢失帧) (2认同)
  • 非常好。不计算持续时间但提供 ffmpeg 开始和结束的唯一解决方案 (2认同)

dyn*_*ael 6

使用-to代替-t:-to指定结束时间,-t指定持续时间