Cutting the videos based on start and end time using ffmpeg

707,800

Solution 1

You probably do not have a keyframe at the 3 second mark. Because non-keyframes encode differences from other frames, they require all of the data starting with the previous keyframe.

With the mp4 container it is possible to cut at a non-keyframe without re-encoding using an edit list. In other words, if the closest keyframe before 3s is at 0s then it will copy the video starting at 0s and use an edit list to tell the player to start playing 3 seconds in.

If you are using the latest ffmpeg from git master it will do this using an edit list when invoked using the command that you provided. If this is not working for you then you are probably either using an older version of ffmpeg, or your player does not support edit lists. Some players will ignore the edit list and always play all of the media in the file from beginning to end.

If you want to cut precisely starting at a non-keyframe and want it to play starting at the desired point on a player that does not support edit lists, or want to ensure that the cut portion is not actually in the output file (for example if it contains confidential information), then you can do that by re-encoding so that there will be a keyframe precisely at the desired start time. Re-encoding is the default if you do not specify copy. For example:

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

When re-encoding you may also wish to include additional quality-related options or a particular AAC encoder. For details, see ffmpeg's x264 Encoding Guide for video and AAC Encoding Guide for audio.

Also, the -t option specifies a duration, not an end time. The above command will encode 8s of video starting at 3s. To start at 3s and end at 8s use -t 5. If you are using a current version of ffmpeg you can also replace -t with -to in the above command to end at the specified time.

Solution 2

Try using this. It is the fastest and best ffmpeg-way I have figure it out:

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

This command trims your video in seconds!

Explanation of the command:

-i: This specifies the input file. In that case, it is (input.mp4).
-ss: Used with -i, this seeks in the input file (input.mp4) to position.
00:01:00: This is the time your trimmed video will start with.
-to: This specifies duration from start (00:01:40) to end (00:02:12).
00:02:00: This is the time your trimmed video will end with.
-c copy: This is an option to trim via stream copy. (NB: Very fast)

The timing format is: hh:mm:ss

Please note that the current highly upvoted answer is outdated and the trim would be extremely slow. For more information, look at this official ffmpeg article.

Solution 3

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

Use -c copy for make in instantly. In that case ffmpeg will not re-encode video, just will cut to according size.

Solution 4

Here's what I use and will only take a few seconds to run:

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

Reference: Trim video files using FFmpeg by Alexander Refsum Jensenius.


Generated mp4 files could also be used in iMovie. More info related to get the full duration using get_duration(input_video) model.

If you want to concatenate multiple cut scenes you can use following Python script:

#!/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()

Example script will cut and merge scenes in between 00:00:00 - 00:00:10 and 00:06:00 - 00:07:00.


If you want to cut the complete video (in case if you want to convert mkv format into mp4) just uncomment the following line:

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

Solution 5

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

Drop everything except from second 3 to second 8.

Share:
707,800
Kalaiyarasan
Author by

Kalaiyarasan

Web developer having experience in Angular Ionic Html css Javascript and Jquery Laravel PHP Mysql Wordpress Redis Codeigniter MVC framework Mediawiki Wowza media server Amazon EC2 Amazon S3 Smarty Media temple server Customising Flex video applications using AS3 Kaltura video editor installation and usage CS Cart with good problem-solving skills.

Updated on January 15, 2022

Comments

  • Kalaiyarasan
    Kalaiyarasan over 2 years

    I tried to cut the video using the start and end time of the video by using the following command

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

    By using the above command i want to cut the video from 00:00:03 to 00:00:08. But it is not cutting the video between those times instead of that it is cutting the video with first 11 seconds. can anyone help me how resolve this?

    Edit 1:

    I have tried to cut by using the following command which is suggested by mark4o

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

    But it was shown the following error.

    the encoder 'aac' is experimental but experimental codecs are not enabled

    so i added the -strict -2 into the command i.e.,

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

    Now it is working fine.

  • Jikku Jose
    Jikku Jose over 9 years
    Is there a shortcut to specify till the end of the video?
  • mark4o
    mark4o over 9 years
    @JikkuJose: Omit the -t/-to and its argument to continue to the end.
  • Denilson Sá Maia
    Denilson Sá Maia almost 9 years
    Note: it is faster to supply -ss BEFORE the input file (before -i), because that way ffmpeg will skip directly to the location. However, that will also set the time "zero" to that location, meaning that -to will point to the wrong time. Source: trac.ffmpeg.org/wiki/Seeking
  • user2002522
    user2002522 almost 9 years
    I get audio and video sync issue after using this ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4 , though the original file has no such issue.
  • mark4o
    mark4o almost 9 years
    @user2002522: Try without the -async 1.
  • jiggunjer
    jiggunjer over 8 years
    I get the first 8 seconds with this, with the first 3 seconds frozen on the first frame. Fixed by chaining setpts=PTS-STARTPTS filter after the trim filter.
  • Ivan
    Ivan over 8 years
    This says "The encoder 'aac' is experimental but experimental codecs are not enabled, add '-strict -2' if you want to use it." Adding -strict -2 does not help. The result is a zero length file.
  • Jan Gondol
    Jan Gondol over 8 years
    @Ivan, did you try adding -strict -2 before cut.mp4 (as opposed to the end of the command line)?
  • Kevin
    Kevin about 7 years
    this answer, stackoverflow.com/a/14013439/1170023 is what you want for finding the keyframe times with -c copy to avoid audio sync
  • dorien
    dorien almost 7 years
    of -c copy works great, but only if I remove -async 1
  • pelson
    pelson almost 7 years
    You may still suffer from a lack of keyframes with this though. I took your approach to cutting, then re-encoded as per the accepted answer to make sure I minimised the amount of time I needed to spend re-encoding.
  • Assil Ksiksi
    Assil Ksiksi over 6 years
    This ends up failing on write due to invalid headers in the case of different input and output containers e.g. .mkv input and .mp4 output.
  • Vlad Hudnitsky
    Vlad Hudnitsky over 6 years
    Alright, to convert .mkv to .mp4 you have to use another command: ffmpeg -i movie.mkv -vcodec copy -acodec copy converted_movie.mp4 and vise versa
  • Raphael
    Raphael over 6 years
    As @pelson says, this will cut off key frames and leave the first few seconds blank (if the cutting time is between key frames). Interestingly, changing the parameter order solves the problem: ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -ss 00:01:00 -to 00:02:00 -c copy output.mp4. Now, however, skipping is broken and the end time is not correct (in my case).
  • vxh.viet
    vxh.viet over 6 years
    According to FFmpeg, input seeking is now both fast and accurate, is there any specific reason you use output seeking instead of input seeking?
  • Ryan
    Ryan over 6 years
    Nice! What worked for me was ffmpeg -i origin.mp4 -ss 02:51:14 -c copy destination.mp4 (I guess -to is optional and unnecessary if you want the end point to be the absolute end of the video.)
  • duplex143
    duplex143 almost 6 years
    For me also, the output was corrupted and with no sound. IINA player is crashing whenever I'm trying to open the video. I'm on macOS 10.13.5 and ffmpeg is 3.4
  • Yamaneko
    Yamaneko over 5 years
    You should use this answer if you don't need to trim at an exact milisecond, thus it will select the closest keyframe available. That's why it's so fast, it selects the closest keyframes and takes the snippet out without the need of reencoding. However, if you do need a precise time, taking the nearest keyframe isn't enough, because it certainly won't match exactly. The only solution available is to reencode the video, and that's why it's so slow. That's the only solution, though, if you do need this. That's why the other answer should be the accepted one, as that's what was OP's issue about.
  • theferrit32
    theferrit32 over 5 years
    You probably want -ss and -to before -i, example: ffmpeg -ss aa:bb:cc -to xx:yy:zz -i input.mp4 -c copy output.mp4. Otherwise the -to value ends up being a duration instead of the end time from the original video. Omitting the -c copy will make it slower and more accurate by re-encoding, but still faster than if the -ss and -to are specified after -i, since that case means to trim after having to process the whole input file.
  • Shayan
    Shayan about 5 years
    Remember to put both -ss and -t before -i to avoid black screen for few seconds at the beginning and don't use -to because it will produce a file with incorrect duration.
  • techkuz
    techkuz about 5 years
    @theferrit32 it gives Option to (record or transcode stop time) cannot be applied to input url file.mp4 -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to.
  • techkuz
    techkuz about 5 years
    slow, but the only thing worked for me (without loosing frames from other answers)
  • Trect
    Trect over 4 years
    THis is super slow
  • Bugs Happen
    Bugs Happen over 4 years
    Note that if you specify -ss before -i only, the timestamps will be reset to zero, so -t and -to have not the same effect. If you want to keep the original timestamps, add the -copyts option. Reference
  • Harsha
    Harsha over 4 years
    What are the advantages of re-encoding? Is it of any use if we just want smaller video in the same format?
  • vdegenne
    vdegenne over 4 years
    -to is not the duration, -t is !
  • lacostenycoder
    lacostenycoder over 4 years
    This outputs only an mp3 audio file and NOT a video.
  • ceremcem
    ceremcem about 4 years
  • nstenz
    nstenz about 4 years
    Couldn't this just use "-c" with "copy" instead of splitting out -c:v and -c:a?
  • Yaniv Levi
    Yaniv Levi about 4 years
    I also experienced sync issues. i tried the solution provided by George Chalhoub (below) and the sync issue was fixed
  • Piotr Majek
    Piotr Majek almost 4 years
    Excelent. The only solution to not calculate duration but provide start and end to the ffmpeg
  • Pablo Díaz
    Pablo Díaz almost 4 years
    I don't know why but I'm getting error with this code
  • Hoppeduppeanut
    Hoppeduppeanut almost 4 years
    Going by the GitHub account profile, it looks like this might be a tool that you've created yourself. If this is the case, you must disclose this in your answer, otherwise this can be considered spam.
  • Muhammed Yalçın Kuru
    Muhammed Yalçın Kuru almost 4 years
    i am getting quality issue. Is there anyone getting same issue ?
  • mark4o
    mark4o almost 4 years
    @MuhammedYalçınKuru: To control the quality see trac.ffmpeg.org/wiki/Encode/H.264
  • Muhammed Yalçın Kuru
    Muhammed Yalçın Kuru almost 4 years
    @mark4o i have tried with my lack of info. Didn't find fit one. while cutting passed this one ` -c:v libx264 -preset ultrafast -crf 0 `
  • y o
    y o almost 4 years
    this is slow. the input file isn't being seeked, it's being processed and discarded. -ss as an output option = slow. see my updated answer.
  • Pablo Díaz
    Pablo Díaz almost 4 years
    I'm getting the video cutted but for first seconds the frames just freeze
  • alper
    alper almost 4 years
    @PabloDíaz The video you are using might be faulty. Can you give it a try with a different video uncommenting # times = [["00:00:00", get_duration(name)]] and see if the generated output.mp4 file is fine
  • Franva
    Franva over 3 years
    I can confirm that with the -c copy the speed is more than 300 times of normal playing speed whereas without the -c copy the speed is only 4 times of the normal playing speed. As typing the comment, the "with c " command has finished, and the "without c " is still running....
  • JasonXA
    JasonXA over 3 years
    This one is outdated, unless there are differences between the win and linux builds, or the answer was made with an old version of ffmpeg, but placing -to after the input file, for my recent win build, it creates an unwanted output, as in it resets timestamps with -ss to 0 and -to won't actually end with the desired timestamp from the input file. The -ss and -to options need to be placed before the input... for new versions of ffmpeg. Otherwise, -ss -i input should be followed by -t, i.e. total duration of the clip, to achieve the right duration for the cut.
  • Ale
    Ale over 3 years
    Is there any way to re-encode only the part up to next keyframe, then copy everything else over?
  • Sudhir Singh Khanger
    Sudhir Singh Khanger over 3 years
    In layman's terms what does now deprecated async 1 does?
  • Sudhir Singh Khanger
    Sudhir Singh Khanger over 3 years
    I have same question as @Harsha. What does -c copy in layman's terms?
  • Harsha
    Harsha over 3 years
    @SudhirSinghKhanger Just found a free GUI interface to Ffmpeg, check out the program LosslessCut
  • kiltek
    kiltek about 3 years
    -t is not picked up and the command ends up cutting from -ss to and of file
  • EmBeCoRau
    EmBeCoRau almost 3 years
    Hi guys, I've implement it on my Android app, but it seem have a bit inaccuracy. I used this command ffmpeg -y -i movie.mp4 -ss 00:00:00.400 -to 00:00:47 -preset ultrafast -c:v copy -c:a copy cut.mp4 the result always have the duration 46s, that mean it always cut 1s instead of 400ms as the params above. It can work well on my iOS app. Someone can help me in this case?
  • mark4o
    mark4o almost 3 years
    @EmBeCoRau If you want to re-encode the video in order to create a new keyframe at a precise time, remove the -c:v copy option.
  • Sayyor Y
    Sayyor Y almost 3 years
    I would advise to put the from time and to time together, otherwise they might not cut properly. So it should be: ffmpeg -ss 00:01:00 -to 00:02:00 -i input.mp4 -c copy output.mp4
  • alper
    alper almost 3 years
    @yo It shouldn't be slow. What do you mean by input file isn't being seeked? Instead of input.mp4 provide the path of the movie you want to convert. I have tried to convert 6.7 GB BlueRay movie by the script I provided, which only took 3.56 seconds.
  • rolodex
    rolodex almost 3 years
    I suppose you can update the script to output video format instead of audio. If I remember correctly, about 3 years ago I did it just for audio.
  • greenoldman
    greenoldman over 2 years
    IMHO you should fix your answer and put the start/to options on one side of the input -- either left or right. Splitting them gives very counter-intuitive behavior because as you put it "-to" behaves like "-t" (because it counts output time). I just learned about it from superuser.com/a/670574/43045
  • Nitin Ashutosh
    Nitin Ashutosh over 2 years
    if we use -t it will clip the video till the end of the video. Try -to instead of -t
  • Trung0246
    Trung0246 over 2 years
    Adding -c copy apparently make the first few frames corrupted, so I removed that and it fixed the issue
  • Sunwoo Yang
    Sunwoo Yang about 2 years
    This is so fast! I'm never gonna use the regular windows photo editor
  • Ax_
    Ax_ about 2 years
    in batches for f in *.mp4; do ffmpeg -ss 00:00:00 -to 00:00:30 -i "$f" -c copy "$f".mp4 ; done
  • Ax_
    Ax_ about 2 years
    and optimize compression H265 for f in *.mp4 ; do ffmpeg -ss 00:00:00 -to 00:00:30 -i "$f" -c:v libx265 -preset fast -crf 28 -tag:v hvc1 -c:a eac3 -b:a 224k "$f".mp4 ; done