108

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?

9
  • 4
    when using the "-vcodec copy -acodec copy" it is very fast:))
    – Savas Adar
    May 2 '12 at 20:39
  • @Antony, Why don't you time both versions (and look at the memory monitor such as htop), and tell us what the answer is? Jul 3 '13 at 19:01
  • 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/…
    – Mladen B.
    Aug 24 '13 at 10:04
  • 1
    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. Feb 22 '15 at 20:51
  • 1
    @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.
    – jiggunjer
    Dec 8 '15 at 7:10
87

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.

3
  • 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?
    – Dr.jacky
    Jul 20 '15 at 12:35
  • 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?
    – utdev
    Feb 1 '17 at 15:58
  • 2
    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.
    – oklas
    Apr 25 '17 at 6:39
21

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

#!/bin/bash
 
# Written by Alexis Bezverkhyy <alexis@grapsus.net> 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
4
  • 3
    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.
    – Mladen B.
    Aug 24 '13 at 10:00
  • Nice script. Did you write it? Is it on GitHub? I'd like to make some suggestions :)
    – voices
    Jan 21 '17 at 4:41
  • for mp4, scenes are damaged. better replace copy with: -vcodec libx264 -acodec aac
    – kishu
    Feb 28 '18 at 15:26
  • The link is broken Sep 13 at 9:51
9

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

5
  • 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!
    – matt
    Dec 12 '16 at 0:12
  • 1
    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.
    – mhndev
    Dec 1 '18 at 11:39
  • And is much easier to use EndTime than -t. Dec 31 '18 at 11:48
  • The best and quick solution than vlc or ffmpeg. Thanks Dec 21 '20 at 7:32
  • 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)".
    – Rublacava
    1 min ago
6

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.

2

does the later approach save computation time and memory?

There is no big difference between those two examples that you provided. The first example cuts the video sequentially, in 2 steps, while the second example does it at the same time (using threads). No particular speed-up will be noticeable. You can read more about creating multiple outputs with FFmpeg

Further more, what you can use (in recent FFmpeg) is the stream segmenter muxer which can:

output streams to a number of separate files of nearly fixed duration. Output filename pattern can be set in a fashion similar to image2.

2

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
1
  • 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". Dec 4 '18 at 3:34
1

Didn't test ist, but this looks promising:

Basic stream segmenter

It is obviously splitting AVI into segments of same size, which implies these chunks don't loose quality or increase memory or must be recalculated.

It also uses the codec copy - does that mean it can handle very large streams ? Because this is my problem, i want to break down my avi so i could use a filter to get rid of the distorsion. But a whole avi runs for hours.

-1

Here is a perfect way to split the video. I have done it previously, and it's working well for me.

ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4 (For cmd). shell_exec('ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4') (for php).

Please follow this and I am sure it will work perfectly.

1
  • 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. Dec 4 '18 at 3:31
-2

one simple way is to use trim option with publitio url-based api.

once you get your video uploaded, just set start offset and end offset in url (so_2,eo_2) like so:

    https://media.publit.io/file/so_2,eo_2/tummy.mp4

this will create instantly new videos starting from 2nd second and 2 seconds in length. you can split videos this way anyway you like.

1
  • 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. Dec 4 '18 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.