4

I have a large video file (large.mp4) and a corresponding subtitle file (large.srt).

What is the best way to split both the files into n equal parts?

This will produce large-1.mp4, ... , large-n.mp4 and large-1.srt, ..., large-n.srt. And all these files will be of equal size (except the last ones).

What is the best way to split both the files into parts of a specific duration, say, 15 mins?

The output will be similar to the one indicated above.

I would like to use a command line tool, preferably ffmpeg and preferably the direct command, without a script.

  • Am I understanding you right you want to split the files into a number n of (not necessarily corresponding!) files as well as a number of (more or less corresponding) files of n minutes duration each? Or do they have to correspond in either way? – dessert Apr 5 '18 at 8:29
  • Now that I read your question again after answering I stumbled across all these files will be of equal size vs. split (…) into parts of a specific duration – those two statements contradict each other and need different approaches. My answer covers the specific duration and I think this is what you wanted, if I'm wrong please mention me and let me adjust my answer – split comes to mind. – dessert Apr 13 '18 at 19:06
  • @dessert Either of the two things would work. Either split into n parts or parts of n sec each. It only means I will need to manually do one calculation. :) – deshmukh Apr 18 '18 at 12:51
3

A task as complex like this (to my knowledge) can't be done with ffmpeg alone and in one single call, but I'll add a oneline version below. Here's the script version:

#!/bin/bash
in=$1
dur=$2
totaldur=$(ffprobe -v -8 -show_entries format=duration -of flat large.mp4 | sed -r 's/.*"([0-9]+).*/\1/')
i=0

while (( i * dur < totaldur) )
do
  ffmpeg -i $in -i ${in%%.*}.srt \
    -ss $((i*dur)) -t $dur -c copy -sn ${in%%.*}-$((i+1)).${in#*.} \
    -ss $((i*dur)) -t $dur -an -vn ${in%%.*}-$((i+1)).srt
  ((i++))
done

This script takes two arguments, the first one being the video's filename and the second being the duration in seconds, see the example run below. It first pipes the output of ffprobe to sed to get the video's total duration in seconds, this value is used to build a while loop for the parts. Inside the loop ffmpeg is called to create the parts, both the .mp4 and .srt in one call.

Example run

$ tree # the directory contains large.mp4 and large.srt
.
├── large.mp4
└── large.srt
$ ffmpeg -i large.mp4 |& awk '/Duration/' # large.mp4 has a duration of 00:02:30.07
  Duration: 00:02:30.07, start: 0.000000, bitrate: 1283 kb/s
$ /path/to/above/script large.mp4 60 # let's split it after every 60 seconds
$ tree
.
├── large-1.mp4
├── large-1.srt
├── large-2.mp4
├── large-2.srt
├── large-3.mp4
├── large-3.srt
├── large.mp4
└── large.srt

Oneline version

The first two variables hold the filename and the duration in seconds, adjust those two to your needs.

in=large.mp4;dur=60;i=0;while ((i*dur<$(ffprobe -v -8 -show_entries format=duration -of flat large.mp4|sed -r 's/.*"([0-9]+).*/\1/')));do ffmpeg -y -i $in -i ${in%%.*}.srt -ss $((i*dur)) -t $dur -c copy -sn ${in%%.*}-$((i+1)).${in#*.} -ss $((i*dur)) -t $dur -an -vn ${in%%.*}-$((i+1)).srt;((i++));done

Links

Here are some links I found on the way:

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.