786

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

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

现在它工作正常。

4

10 回答 10

911

尝试使用这个。这是我发现的最快和最好的 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

请注意,当前高度赞成的答案已经过时,并且修剪会非常缓慢。有关更多信息,请查看此官方 ffmpeg文章

于 2017-03-16T06:46:29.370 回答
779

您可能在 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 的视频。要从 3 秒开始并在 8 秒结束,请使用-t 5. 如果您使用的是当前版本的 ffmpeg,您也可以在上述命令中替换为在指定时间结束-t-to

于 2013-08-26T17:27:05.167 回答
114
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4 

使用-c copy立即制作。在这种情况下,ffmpeg 不会重新编码视频,只会削减到相应的大小。

于 2016-10-25T15:42:00.800 回答
45

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

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

参考:Alexander Refsum Jensenius使用 FFmpeg 修剪视频文件


生成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)]]
于 2019-09-23T09:11:48.307 回答
35
    ffmpeg -i movie.mp4 -vf trim=3:8 cut.mp4

丢弃除第 3 秒到第 8 秒之外的所有内容。

于 2015-02-23T22:31:41.563 回答
28

新答案(快速)

你可以让 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 中启用毫秒时间码--osd-fractions


带有解释的旧答案(慢)

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

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

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

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

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

于 2018-10-21T14:45:53.587 回答
7

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

于 2019-11-30T13:21:48.907 回答
0

随意使用这个工具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

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

于 2020-09-03T23:34:22.000 回答
0

我的设置:

$ 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
于 2021-10-24T23:17:33.433 回答
-5

即使我迟到了 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;
于 2019-11-18T15:47:53.680 回答