FFmpeg: How to split video efficiently?

156,669

Solution 1

The ffmpeg wiki links back to this page in reference to "How to split video efficiently". I'm not convinced this page answers that question, so I did as @AlcubierreDrive suggested…

echo "Two commands" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 -sn test1.mkv
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test2.mkv
echo "One command" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 \
  -sn test3.mkv -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test4.mkv

Which outputs...

Two commands
real    0m16.201s
user    0m1.830s
sys 0m1.301s

real    0m43.621s
user    0m4.943s
sys 0m2.908s

One command
real    0m59.410s
user    0m5.577s
sys 0m3.939s

I tested a SD & HD file, after a few runs & a little maths.

Two commands SD 0m53.94 #2 wins  
One command  SD 0m49.63  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.60 #2 wins  
One command  SD 0m58.61 

Two commands SD 0m54.60  
One command  SD 0m50.51 #1 wins 

Two commands SD 0m53.94  
One command  SD 0m49.63 #1 wins  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.71  
One command  SD 0m58.61 #1 wins

Two commands SD 0m54.63  
One command  SD 0m50.51 #1 wins  

Two commands SD 1m6.67s #2 wins  
One command  SD 1m20.18  

Two commands SD 1m7.67  
One command  SD 1m6.72 #1 wins

Two commands SD 1m4.92  
One command  SD 1m2.24 #1 wins

Two commands SD 1m1.73  
One command  SD 0m59.72 #1 wins

Two commands HD 4m23.20  
One command  HD 3m40.02 #1 wins

Two commands SD 1m1.30  
One command  SD 0m59.59 #1 wins  

Two commands HD 3m47.89  
One command  HD 3m29.59 #1 wins  

Two commands SD 0m59.82  
One command  SD 0m59.41 #1 wins  

Two commands HD 3m51.18  
One command  HD 3m30.79 #1 wins  

SD file = 1.35GB DVB transport stream
HD file = 3.14GB DVB transport stream

Conclusion

The single command is better if you are handling HD, it agrees with the manuals comments on using -ss after the input file to do a 'slow seek'. SD files have a negligible difference.

The two command version should be quicker by adding another -ss before the input file for the a 'fast seek' followed by the more accurate slow seek.

Solution 2

Here's a useful script, it helps you split automatically: A script for splitting videos using ffmpeg

#!/bin/bash
 
# Written by Alexis Bezverkhyy <[email protected]> in 2011
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
 
function usage {
        echo "Usage : ffsplit.sh input.file chunk-duration [output-filename-format]"
        echo -e "\t - input file may be any kind of file reconginzed by ffmpeg"
        echo -e "\t - chunk duration must be in seconds"
        echo -e "\t - output filename format must be printf-like, for example myvideo-part-%04d.avi"
        echo -e "\t - if no output filename format is given, it will be computed\
 automatically from input filename"
}
 
IN_FILE="$1"
OUT_FILE_FORMAT="$3"
typeset -i CHUNK_LEN
CHUNK_LEN="$2"
 
DURATION_HMS=$(ffmpeg -i "$IN_FILE" 2>&1 | grep Duration | cut -f 4 -d ' ')
DURATION_H=$(echo "$DURATION_HMS" | cut -d ':' -f 1)
DURATION_M=$(echo "$DURATION_HMS" | cut -d ':' -f 2)
DURATION_S=$(echo "$DURATION_HMS" | cut -d ':' -f 3 | cut -d '.' -f 1)
let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S"
 
if [ "$DURATION" = '0' ] ; then
        echo "Invalid input video"
        usage
        exit 1
fi
 
if [ "$CHUNK_LEN" = "0" ] ; then
        echo "Invalid chunk size"
        usage
        exit 2
fi
 
if [ -z "$OUT_FILE_FORMAT" ] ; then
        FILE_EXT=$(echo "$IN_FILE" | sed 's/^.*\.\([a-zA-Z0-9]\+\)$/\1/')
        FILE_NAME=$(echo "$IN_FILE" | sed 's/^\(.*\)\.[a-zA-Z0-9]\+$/\1/')
        OUT_FILE_FORMAT="${FILE_NAME}-%03d.${FILE_EXT}"
        echo "Using default output file format : $OUT_FILE_FORMAT"
fi
 
N='1'
OFFSET='0'
let 'N_FILES = DURATION / CHUNK_LEN + 1'
 
while [ "$OFFSET" -lt "$DURATION" ] ; do
        OUT_FILE=$(printf "$OUT_FILE_FORMAT" "$N")
        echo "writing $OUT_FILE ($N/$N_FILES)..."
        ffmpeg -i "$IN_FILE" -vcodec copy -acodec copy -ss "$OFFSET" -t "$CHUNK_LEN" "$OUT_FILE"
        let "N = N + 1"
        let "OFFSET = OFFSET + CHUNK_LEN"
done

Solution 3

In my experience, don't use ffmpeg for splitting/join. MP4Box, is faster and light than ffmpeg. Please tryit. Eg if you want to split a 1400mb MP4 file into two parts a 700mb you can use the following cmdl: MP4Box -splits 716800 input.mp4 eg for concatenating two files you can use:

MP4Box -cat file1.mp4 -cat file2.mp4 output.mp4

Or if you need split by time, use -splitx StartTime:EndTime:

MP4Box -add input.mp4 -splitx 0:15 -new split.mp4

Solution 4

http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg may also be useful to you. Also ffmpeg has a segment muxer that might work.

Anyway my guess is that combining them into one command would save time.

Solution 5

Here is a simple Windows bat file to split incoming file into 50 parts. Each part has length 1 minute. Sorry for such dumb script. I hope it is better to have a dumb windows script instead of do not have it at all. Perhaps it help someone. (Based on "bat file for loop" from this site.)

set var=0
@echo off
:start
set lz=
if %var% EQU 50 goto end
if %var% LEQ 9 set lz=0
echo part %lz%%var%
ffmpeg -ss 00:%lz%%var%:00 -t 00:01:00 -i %1 -acodec copy -vcodec copy %2_%lz%%var%.mp4
set /a var+=1
goto start

:end
echo var has reached %var%.
exit
Share:
156,669

Related videos on Youtube

Antony
Author by

Antony

Updated on April 27, 2022

Comments

  • Antony
    Antony about 2 years

    I wish to split a large avi video into two smaller consecutive videos. I am using ffmpeg.

    One way is to run ffmpeg two times:

    ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi
    ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi
    

    But according to manpage of ffmpeg, I can make more than one ouput file from one input file using just one line:

    ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi \
       -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi
    

    My question is, does the later approach save computation time and memory?

    • Savas Adar
      Savas Adar about 12 years
      when using the "-vcodec copy -acodec copy" it is very fast:))
    • AlcubierreDrive
      AlcubierreDrive almost 11 years
      @Antony, Why don't you time both versions (and look at the memory monitor such as htop), and tell us what the answer is?
    • Mladen B.
      Mladen B. almost 11 years
      The first example does it sequentially, while the second example uses threads. Both will do the same thing, no noticeable speedups should occur. But to simplify things, you might use ffmpeg stream segmenter muxer: ffmpeg.org/…
    • Lucian Wischik
      Lucian Wischik over 9 years
      This example looks badly wrong! The ffmpeg documentation says about the -ss option: "When used as an input option (before -i), seeks in this input file to position. When used as an output option (before an output filename), decodes but discards input until the timestamps reach position." You are using it in the output position, so your second line wastes effort decoding and discarding the first 30 minutes.
    • Philip Bulley
      Philip Bulley over 9 years
      If using MP4, consider MP4Box -split MP4Box -split 5 input.mp4 to split every 5 secs. Options also available to split every x bytes.
    • Dr.jacky
      Dr.jacky almost 9 years
      If TS contain multiple program (TV programs that captured by DVB-T), how can split it? For example I have a TS file that contain football + cooking + cartoon .How can i split this TS file to 3 mpg files?
    • jiggunjer
      jiggunjer over 8 years
      @LucianWischik but using -ss as input option in the second split might not be accurate, so you might not get a clean split. IMO the example by OP is more correct.
    • luckydonald
      luckydonald almost 4 years
      Using --ss 00:00:00 might actually result in the first key frame being skipped, so best to simply leave that out, to start at the start.
    • StickySli
      StickySli over 3 years
      Is there any reason the second video output is also -t 00:30:00?
  • Mladen B.
    Mladen B. almost 11 years
    Same comment goes for you as for SEARAS. Writing batch files is useful when absolutely needed and when you have no other option available, because it is not portable. You won't be able to run the same script on Windows, for example. When there are more generic/portable ways, batch scripts should be avoided, to save the time needed to port them. Since ffmpeg has multiple ways to solve this issue, the proper way would be to use ffmpeg alone, without the help of scripts.
  • Dr.jacky
    Dr.jacky almost 9 years
    If TS contain multiple program (TV programs that captured by DVB-T), how can split it? For example I have a TS file that contain football + cooking + cartoon .How can i split this TS file to 3 mpg files?
  • matt
    matt over 7 years
    This was exactly what I needed! When I was cutting with ffmpeg, the clips didn't start on keyframes and had weird freezes at the ends. Using MP4Box -splitz did the trick!
  • voices
    voices over 7 years
    Nice script. Did you write it? Is it on GitHub? I'd like to make some suggestions :)
  • utdev
    utdev over 7 years
    I used your answer in my question here (stackoverflow.com/questions/41983940/…) but it did not work, what do you think I am doing wrong?
  • oklas
    oklas about 7 years
    The result file was with no video (only audio) in my case. After some experiments I found soultion. It need to specify key for "do not modify quality" like this -q:v 0.
  • kishu
    kishu over 6 years
    for mp4, scenes are damaged. better replace copy with: -vcodec libx264 -acodec aac
  • Majid Abdolhosseini
    Majid Abdolhosseini over 5 years
    how can I trim the video using Mp4Box with multiple numbers? for example I need to have sub clips in seconds are : 5 - 8 , 21 - 30 , 12 - 18 so I need three output video file.
  • Lance U. Matthews
    Lance U. Matthews over 5 years
    Why is this the "perfect way" to split the video? Like the command line in the question, you're passing -i followed by -ss and -t. The question is about how to efficiently extract multiple segments from the same input file, though, whereas you are only extracting a single segment. I don't see how this answers the question.
  • Lance U. Matthews
    Lance U. Matthews over 5 years
    This is essentially the first code snippet in the question (consecutive ffmpeg commands) rewritten as a loop. This doesn't answer the question of whether that approach or a single command will "save computation time and memory".
  • Lance U. Matthews
    Lance U. Matthews over 5 years
    The question is asking which is more efficient of two approaches to extracting multiple segments from an input file with ffmpeg. Unless you have a really, really fast internet connection, I think having to upload the entire video to a cloud service and then download the results is going to increase processing time significantly. Even so, this still doesn't answer the question of which approach with ffmpeg is more efficient.
  • vmassuchetto
    vmassuchetto over 5 years
    And is much easier to use EndTime than -t.
  • sapatelbaps
    sapatelbaps over 3 years
    The best and quick solution than vlc or ffmpeg. Thanks
  • Felix Jassler
    Felix Jassler almost 3 years
    The link is broken
  • Rublacava
    Rublacava over 2 years
    MP4Box only worked slightly better. I don't recommend it. A user wrote: "When I was cutting with ffmpeg, the clips didn't start on keyframes". This may be due to using -c copy. If you want a video to start on the right frame, it may be necessary to re-encode it. So no -c copy or -vcodec copy in the OP. E.g.: ffmpeg -i in.mp4 -ss 00:00:00.46 out.mp4 -y. stackoverflow.com/questions/49846095 points out this which may be relevant: "None of these methods will be perfectly accurate due to the very mechanics of how video compression works (P and B frames can not stand on their own)".
  • Jonathan Hartley
    Jonathan Hartley over 2 years
    This worked for me when splitting out a chunk from the start of my input .mp4, but when splitting a chunk starting at 6.5 seconds into the input, the result is a few seconds of all green with a few "delta artifacts" overlaid. I wonder if this might be because, from man MP4Box: "the input file must have enough random access points in order to be split. This may not be the case with some video files where only the very first sample of the video track is a key frame. In order to split such files you will have to use a real video editor and re-encode the content."
  • pavlovma007
    pavlovma007 over 2 years
    better fix one line here: > #let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S" > DURATION=$( echo "($DURATION_H * 60 + $DURATION_M ) * 60 + $DURATION_S" | bc) i have an error here and this a better to method compute it
  • NeuroXc
    NeuroXc about 2 years
    Huge caveat: This only works with mp4 files. Even the question itself doesn't use an mp4 file, so this would not work with the OP's example.