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

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 -i input.mp4 -ss 01:19:27 -to 02:18:51 -c:v copy -c:a copy output.mp4

参考:使用FFmpeg由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)]]

其他回答

使用ffmpeg-python库,我这样做了。但是在安装ffmpeg-library之前,必须先卸载ffmpeg。详见我的github。 https://github.com/johntsunami/ffmpeg-python-video-trimmer/blob/main/trimmer.py

sys.path.append(r"C:\Users\johnc\Desktop\ffmpeg\bin")
stream = ffmpeg.input(r"C:/Users/johnc/Desktop/krystal.mp4",ss=57, t=55)  # ss is start time,  t IS DURATION

## SEPARATES AUDIO AND VIDEO INDEPENDENTLY BECAUSE SOMETIMES IT DOESNT HAVE AUDIO UNLESS YOU DO THIS>

audio = stream.audio 
video = stream.video   #.trim(start=60,end=115).filter('setpts','PTS-STARTPTS') ## CURRENTLY IS GOOD BUT DOESNT CUT DURATION AFTER 55 seconds

#overwrite_output overwrites it automatically if i dont want it just use output
stream = ffmpeg.output(audio, video, r'C:\Users\johnc\Desktop\output.mp4')


ffmpeg.run(stream)

你可能在3秒时没有关键帧。因为非关键帧编码与其他帧不同,所以它们需要从前一个关键帧开始的所有数据。

使用mp4容器,可以在不使用编辑列表重新编码的情况下切割非关键帧。换句话说,如果3s之前最接近的关键帧是0s,那么它将从0s开始复制视频,并使用编辑列表告诉玩家开始播放3秒。

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

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

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

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

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

我感兴趣的是基于毫秒的切割时间,并注意到秒(以及它们的分数)可以被指定为切割如下:

ffmpeg -i input.mp4 -ss 17.5 -to 20.5 output.mp4

对于持续时间而不是结束时间,使用-t而不是-to:

ffmpeg -i input.mp4 -ss 17.5 -t 3 output.mp4

虽然我迟到了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支持的文件,计算开始时间和结束时间之间的持续时间并将其传递给ffmpeg,因为-t实际上是持续时间,而不是真正的结束时间

如果你有任何问题就找我。

    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;

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