FFmpeg: How to split video efficiently?
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
Related videos on Youtube
Antony
Updated on April 27, 2022Comments
-
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 about 12 yearswhen using the "-vcodec copy -acodec copy" it is very fast:))
-
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. almost 11 yearsThe 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 over 9 yearsThis 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 over 9 years
-
Dr.jacky almost 9 yearsIf 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 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 almost 4 yearsUsing
--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 over 3 yearsIs there any reason the second video output is also
-t 00:30:00
?
-
-
Mladen B. almost 11 yearsSame 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 almost 9 yearsIf 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 over 7 yearsThis 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 over 7 yearsNice script. Did you write it? Is it on GitHub? I'd like to make some suggestions :)
-
utdev over 7 yearsI 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 about 7 yearsThe 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 over 6 yearsfor mp4, scenes are damaged. better replace copy with: -vcodec libx264 -acodec aac
-
Majid Abdolhosseini over 5 yearshow 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 over 5 yearsWhy 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 over 5 yearsThis 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 over 5 yearsThe 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 withffmpeg
is more efficient. -
vmassuchetto over 5 yearsAnd is much easier to use
EndTime
than-t
. -
sapatelbaps over 3 yearsThe best and quick solution than vlc or ffmpeg. Thanks
-
Felix Jassler almost 3 yearsThe link is broken
-
Rublacava over 2 yearsMP4Box 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 over 2 yearsThis 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 over 2 yearsbetter 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 about 2 yearsHuge 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.