Search code examples
ffmpeg

Remove a section from the middle of a video without concat


How do I cut a section out of a video with ffmpeg?

Imagine I have a 60 second mp4 A.

I want to remove all the stuff from 0:15 to 0:45.

The result should be a 30-second mp4, which is composed of the first 15 seconds of A directly followed by the last 15 seconds of A.

How can I do this without using concat?

I know how I could do it by creating two intermediary files and then using ffmpeg to concat them. I don't want to have to perform so much manual work for this (simple?) operation.

I have also seen the trim filder used for removing multiple parts from a video. All the usages I've found show that it seems to be very verbose, and I haven't found an example for a case as simple as I would like (just a single section removed).

Do I have to use trim for this operation? Or are there other less verbose solutions?

The ideal would of course be something at least simple as -ss 0:15 -to 0:45 which removes the ends of a video (-cut 0:15-0:45 for example).


Solution

  • I started from https://stackoverflow.com/a/54192662/3499840 (currently the only answer to "FFmpeg remove 2 sec from middle of video and concat the parts. Single line solution").

    Working from that example, the following works for me:

        # In order to keep <start-15s> and <45s-end>, you need to 
        # keep all the frames which are "not between 15s and 45s":
    
        ffmpeg -i input.mp4 \
          -vf  "select='not(between(t,15,45))',  setpts=N/FRAME_RATE/TB" \
          -af "aselect='not(between(t,15,45))', asetpts=N/SR/TB" \
          output.mp4
    

    This is a one-line linux command, but I've used the bash line-continuation character ('\') so that I can vertically align the equals-signs as this helps me to understand what is going on.

    I had never seen ffmpeg's not and between operators before, but I found their documentation here.

    Regarding the usual ffmpeg "copy vs re-encode" dichotomy, I was hoping to be able to use ffmpeg's "copy" "codec" (yeah, I know that it's not really a codec) so that ffmpeg would not re-encode my video, but if I specify "copy", then ffmpeg starts and stops at the nearest keyframes which are not sufficiently close to my desired start and stop points. (I want to remove a piece of video that is approximately 20 seconds long, but my source video only has one keyframe every 45 seconds!). Hence I am obliged to re-encode. See https://trac.ffmpeg.org/wiki/Seeking#Seekingwhiledoingacodeccopy for more info.

    The setpts/asetpts filters set the timestamps on each frame to the correct values so that your media player will play each frame at the correct time.

    HTH.