4

I want to cut a video into about 10 minute parts like this.

ffmpeg -i video.mp4 -ss 00:00:00 -t 00:10:00 -c copy 01.mp4
ffmpeg -i video.mp4 -ss 00:10:00 -t 00:10:00 -c copy 02.mp4
ffmpeg -i video.mp4 -ss 00:20:00 -t 00:10:00 -c copy 03.mp4

With for it will be like this.

for i in `seq 10`; do ffmpeg -i video.mp4 -ss 00:${i}0:00 -t 00:10:00 -c copy ${i].mp4; done;

But it works only if duration is under a hour. How can I convert number to time format in bash shell?

2
  • I would say this is already complex enough to handle using a script language say python.
    – zinking
    Oct 6, 2013 at 3:09
  • ok, then I'll use ruby for this. Thanks!
    – ironsand
    Oct 6, 2013 at 3:32

4 Answers 4

7

BASH isn't that bad for this problem. You just need to use the very powerful, but underused date command.

for i in {1..10}; do
  hrmin=$(date -u -d@$(($i * 10 * 60)) +"%H:%M")
  outfile=${hrmin/:/-}.mp4
  ffmpeg -i video.mp4 -ss ${hrmin}:00 -t 00:10:00 -c copy ${outfile}
done

date Command Explained

date with a -d flags allows you to set which date you want displayed (instead of the current date and time, which is the default). In this case, I am setting it to a UNIX time by prepending the @ symbol before an integer. The integer in this case is the time in ten minute increments (calculated by the BASH built-in calculator: $((...))).

The + symbol tells date that you would like to specify a format for displaying the results. In our case, we care only about the hour (%H) and the minutes (%M).

And finally, the -u is to display as UTC time instead of local. This is important in this case because we specified the time as UTC when we gave it the UNIX time (UNIX time is always as UTC). The numbers would most likely not start from 0 if you didn't specify -u.

BASH Variable Substitution Explained

The date command gave us just what we needed. But colons in a file name might be problematic/non-standard. So, we substitute the ':' for a '-'. This can be done by the sed or cut or tr command, but because this is such a simple task, why spawn a new subshell when BASH can do it?

Here we use BASH's simple expression substitution. To do this, the variable must be contained within curly braces (${hrmin}) and then use the standard forward slash notation. The first string after the first slash is the search pattern. The second string after the second slash is the substitution.

BASH variable substitution and more can be found at http://tldp.org/LDP/abs/html/parameter-substitution.html.

1
  • The macos version of date does not support this syntax. But it works with the GNU flavour of date for mac which can be installed with brew install coreutils and which will be exposed as gdate.
    – ccpizza
    Mar 22, 2021 at 12:29
2

It's slightly more complicated but you can do it in bash easily enough. The example below is for a 2h video, you can set the limits (n<=11) accordingly:

k=0; 
i=00;
for ((n=0;n<=11;n++)); do
  if [ $i -ge 60 ]; then 
    let k++; i=00; 
  fi; 
  ffmpeg -i video.mp4 -ss 0$k:$i:00 -t 00:10:00 -c copy $k$i.mp4; 
  let i+=10; 
done

You can see what this does by adding an echo to the ffmpeg line:

echo "ffmpeg -i video.mp4 -ss 0$k:$i:00 -t 00:10:00 -c copy $k$i.mp4";

which will print:

ffmpeg -i video.mp4 -ss 00:00:00 -t 00:10:00 -c copy 000.mp4
ffmpeg -i video.mp4 -ss 00:10:00 -t 00:10:00 -c copy 010.mp4
ffmpeg -i video.mp4 -ss 00:20:00 -t 00:10:00 -c copy 020.mp4
ffmpeg -i video.mp4 -ss 00:30:00 -t 00:10:00 -c copy 030.mp4
ffmpeg -i video.mp4 -ss 00:40:00 -t 00:10:00 -c copy 040.mp4
ffmpeg -i video.mp4 -ss 00:50:00 -t 00:10:00 -c copy 050.mp4
ffmpeg -i video.mp4 -ss 01:00:00 -t 00:10:00 -c copy 100.mp4
ffmpeg -i video.mp4 -ss 01:10:00 -t 00:10:00 -c copy 110.mp4
ffmpeg -i video.mp4 -ss 01:20:00 -t 00:10:00 -c copy 120.mp4
ffmpeg -i video.mp4 -ss 01:30:00 -t 00:10:00 -c copy 130.mp4
ffmpeg -i video.mp4 -ss 01:40:00 -t 00:10:00 -c copy 140.mp4
ffmpeg -i video.mp4 -ss 01:50:00 -t 00:10:00 -c copy 150.mp4
1
  • Not sure if this comment is relevant, but it seems like it might be .... "Beware: According to the man page [ linux.die.net/man/1/ffmpeg ] this results in unnatural, overlapping cuts. For instance, the second command starts at 00:30:00 but goes on for an hour; i.e., up to 01:30:00, so the third command, which starts at 01:00:00, will yield an overlapping cut. It may be the goal, but it wouldn't be very natural." ... askubuntu.com/a/56044/17531
    – slm
    Oct 6, 2013 at 15:16
2

It's simple math: the hour figure is $((i%3600), the minutes are $((i/60%60)), the seconds are $((i%60)). To add a leading zero where needed, a simple trick is to add 100, then strip the leading 1. Do the same with the file name if you want to avoid leading zeroes.

for i in $(seq 10); do
  minutes=$((i / 60 % 60 + 100)); minutes=${minutes#1}
  seconds=$((i%60)); seconds=${seconds#1}
  i=$((i+100)); i=${i#1}
  ffmpeg -i video.mp4 -ss $((i%3600):$minutes:$seconds -t 00:10:00 -c copy ${i}.mp4
done
2
  • As far as I know ffmpeg timestamp should not like 0:10:0, it must be 2 digits. But what show me very good example.
    – ironsand
    Oct 7, 2013 at 7:15
  • @Tetsu Oh, it does? See my updated answer. Oct 7, 2013 at 7:43
0

I found that ffmpeg accept as a timestamp format not only [HH:MM:SS], but also simple seconds.

https://trac.ffmpeg.org/wiki/Seeking%20with%20FFmpeg

So I can write like this.

for i in `seq 10`; do ffmpeg -i video.mp4 -ss $((i*10*60)) -t 00:10:00 -c copy ${i].mp4; done;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .