【问题标题】:Cutting the videos based on start and end time using ffmpeg使用 ffmpeg 根据开始和结束时间剪切视频
【发布时间】:2013-08-28 22:43:17
【问题描述】:

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

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

通过使用上述命令,我想将视频从00:00:03 剪切到00: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

现在一切正常。

【问题讨论】:

  • 您完整的、未删减的 ffmpeg 控制台输出丢失。请在询问时始终包含此内容。谢谢。
  • 你从哪里得到-strict 2?只是好奇,因为它不在文档中:ffmpeg.org/ffmpeg.html
  • 安装ffmpeg后为了质量,在ffmpeg帮助中可以找到这个选项
  • 您应该使用-t 00:00:05 或-to 00:00:08 将视频从00:00:03 剪切到00:00:08。查看文档。
  • 我认为这里的问题实际上只是您将 from 和 to 放在 -i movie.mp4 之前的事实。该流的参数在它之后,对吗?这就是为什么另一种方式奏效的原因。 =/

标签: video ffmpeg video-editing


【解决方案1】:

尝试使用它。这是我发现的最快和最好的 ffmpeg 方式:

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

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

命令说明:

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

计时格式为:hh:mm:ss

请注意,当前高度赞成的答案已经过时,并且修剪会非常缓慢。更多信息请看这个官方的ffmpegarticle。

【讨论】:

  • 你可能仍然会因为缺少关键帧而苦恼。我采用了你的方法进行剪切,然后根据接受的答案重新编码,以确保我最大限度地减少重新编码所需的时间。
  • 正如@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。但是,现在跳过已损坏,结束时间不正确(在我的情况下)。
  • 根据FFmpeg,输入搜索现在既快速又准确,您使用输出搜索而不是输入搜索有什么具体原因吗?
  • 如果您不需要精确到毫秒的修剪,您应该使用此答案,因此它将选择最接近的可用关键帧。这就是为什么它如此之快,它选择最近的关键帧并取出 sn-p 而无需重新编码。但是,如果您确实需要一个精确的时间,那么采用最近的关键帧是不够的,因为它肯定不会完全匹配。唯一可用的解决方案是重新编码视频,这就是它如此慢的原因。但是,如果您确实需要,这是唯一的解决方案。这就是为什么另一个答案应该被接受的原因,因为这就是 OP 的问题所在。
  • 您可能需要-ss 和 -to 在-i 之前,例如:ffmpeg -ss aa:bb:cc -to xx:yy:zz -i input.mp4 -c copy output.mp4。否则,-to 值最终会成为持续时间,而不是原始视频的结束时间。省略-c copy 将通过重新编码使其更慢和更准确,但仍然比在-i 之后指定-ss 和-to 更快,因为这种情况意味着在必须处理整个输入后进行修剪文件。
【解决方案2】:

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

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

如果您使用来自 git master 的 latest ffmpeg,它将在使用您提供的命令调用时使用编辑列表执行此操作。如果这对您不起作用,那么您可能正在使用旧版本的 ffmpeg,或者您的播放器不支持编辑列表。有些播放器会忽略编辑列表,总是从头到尾播放文件中的所有媒体。

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

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

在重新编码时,您可能还希望包含其他与质量相关的选项或特定的 AAC 编码器。详情请看ffmpeg的x264 Encoding Guide视频和AAC Encoding Guide音频。

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

【讨论】:

  • 是否有快捷方式可以指定到视频结束?
  • @JikkuJose:省略-t/-to 及其参数以继续到最后。
  • 注意:在输入文件之前(-i之前)提供-ss会更快,因为这样ffmpeg会直接跳到该位置。但是,这也会将时间“零”设置为该位置,这意味着-to 将指向错误的时间。来源:trac.ffmpeg.org/wiki/Seeking
  • 使用ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4后出现音视频同步问题,但原文件没有这个问题。
  • @user2002522:尝试不使用-async 1。
【解决方案3】:
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 

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

【讨论】:

  • of -c copy 效果很好,但前提是我删除 -async 1
  • 在不同的输入和输出容器的情况下,由于标头无效,最终导致写入失败,例如.mkv 输入和 .mp4 输出。
  • 好吧,要将 .mkv 转换为 .mp4,您必须使用另一个命令:ffmpeg -i movie.mkv -vcodec copy -acodec copy converted_movie.mp4 反之亦然
  • 重新编码有什么好处?如果我们只想要相同格式的较小视频,它有什么用吗?
  • 我和@Harsha 有同样的问题。 -c 通俗地说是复制什么?
【解决方案4】:

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

ffmpeg -i input.mp4 -ss 01:19:27 -to 02:18:51 -c:v copy -c:a copy output.mp4

参考:Trim video files using FFmpeg by Alexander Refsum Jensenius。


生成的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()


def 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()
        print(output)


if __name__ == "__main__":
    main()

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


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

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

【讨论】:

  • 这不能只使用“-c”和“复制”而不是分开 -c:v 和 -c:a 吗?
  • 我不知道为什么,但是这段代码出错了
  • 这很慢。输入文件没有被寻找,它正在被处理和丢弃。 -ss 作为输出选项 = 慢。查看我的更新答案。
  • 我正在剪辑视频,但第一秒帧只是冻结
  • @PabloDíaz 您使用的视频可能有问题。您可以尝试使用其他视频取消注释# times = [["00:00:00", get_duration(name)]] 并查看生成的output.mp4 文件是否正常
【解决方案5】:
    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

除了从第 3 秒到第 8 秒之外的所有内容。

【讨论】:

  • 我得到了前 8 秒,前 3 秒冻结在第一帧。通过在修剪过滤器之后链接 setpts=PTS-STARTPTS 过滤器来修复。
  • 这表示“编码器'aac'是实验性的,但实验性编解码器未启用,如果你想使用它,请添加'-strict -2'。”添加 -strict -2 没有帮助。结果是一个零长度文件。
  • @Ivan,您是否尝试在cut.mp4 之前添加-strict -2(而不是在命令行末尾)?
  • 这超级慢
【解决方案6】:

新答案(快速)

您可以让 bash 为您计算,它可以在毫秒内运行。

toSeconds() {
    awk -F: 'NF==3 { print ($1 * 3600) + ($2 * 60) + $3 } NF==2 { print ($1 * 60) + $2 } NF==1 { print 0 + $1 }' <<< $1
}

StartSeconds=$(toSeconds "45.5")
EndSeconds=$(toSeconds "1:00.5")
Duration=$(bc <<< "(${EndSeconds} + 0.01) - ${StartSeconds}" | awk '{ printf "%.4f", $0 }')
ffmpeg -ss $StartSeconds -i input.mpg -t $Duration output.mpg

与旧答案一样,这将产生 15 秒的剪辑。即使从大文件的深处进行剪辑,此方法也是理想的,因为与旧答案不同,不会禁用搜索。是的,我已经验证了它的框架完美。

注意:开始时间是INCLUSIVE,结束时间通常是EXCLUSIVE,因此+0.01,使它包括在内。

如果您使用mpv,您可以使用--osd-fractions 在 OSD 中启用毫秒时间码


带有解释的旧答案(慢)

要根据源视频的开始和结束时间进行剪辑并避免进行数学运算,将结束时间指定为输入选项,将开始时间指定为输出选项。

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

这将产生从 0:45 到 1:00 的 15 秒剪辑。

这是因为当-ss 作为输出选项给出时,丢弃的时间仍然包含在从输入读取的总时间中,-t 用它来知道何时停止。而如果-ss 是作为输入 选项给出的,则会寻找开始时间并且不计算,这就是混淆的来源。

它比查找要慢,因为省略的段在被丢弃之前仍会被处理,但据我所知,这是唯一的方法。如果您要从大文件的深处进行剪辑,则更谨慎的做法是进行数学运算并使用 -ss 作为输入。

【讨论】:

  • 慢,但唯一对我有用(不会丢失其他答案的帧)
  • 优秀。唯一不计算持续时间但为 ffmpeg 提供开始和结束的解决方案
【解决方案7】:

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

【解决方案8】:

随意使用这个工具https://github.com/rooty0/ffmpeg_video_cutter我前段时间写的 这几乎是 ffmpeg 的 cli 前端......你只需要创建一个 yaml 你想要删除的东西......像这样

cut_method: delete  # we're going to delete following video fragments from a video
timeframe:
  - from: start   # waiting for people to join the conference
    to: 4m
  - from: 10m11s  # awkward silence
    to: 15m50s
  - from: 30m5s   # Off-Topic Discussion
    to: end

然后只需运行一个工具即可获得结果

【讨论】:

  • 通过 GitHub 帐户配置文件,看起来这可能是您自己创建的工具。如果是这种情况,you must disclose this in your answer,否则这可以被视为垃圾邮件。
【解决方案9】:

我的设置:

$ ffmpeg
ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 12.0.5 (clang-1205.0.22.9)

我发现开关的顺序很重要。 如果-i 不在-ss 和-t 之间,那么结果中的前导空白大约为3 秒。

所以无论你使用什么额外的开关,确保你按正确的顺序得到这三个开关,像这样

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

【讨论】:

    【解决方案10】:

    即使我迟到了 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_time和end_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 音频文件,而不是一个视频。
    • 我想您可以更新脚本以输出视频格式而不是音频。如果我没记错的话,大约 3 年前我只是为了音频。
    猜你喜欢
    • 2013-12-16
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    • 2023-02-20
    • 2013-09-17
    • 2020-09-21
    相关资源
    最近更新 更多