3

I've been trying to figure out how to write a filter for ffmpeg to take a set of videos and make them all the same time length.

For example I have a video that is 35 seconds and a video 15 seconds, but I want both the 2 videos to be 30seconds long.

I know i can use the setpts filter to speed up or slow down a video, but truthfully I don't understand filter. I know setpts is "Change the PTS (presentation timestamp) of the input frames." Though I don't think this correct filter to use as I think it applies to the time length of the frame and nothing to do with the time length of the video.

3
  • Filters don't have information on stream duration, so that has to be separately found out and then setpts invoked with an expression that uses that info.
    – Gyan
    Sep 25, 2018 at 18:21
  • So use ffprobe -v error -show_format -show_streams XXXX.mp4 Get the duration of the video stream. Divide the target time by duration of the existing video Which should go like this then: ffmpeg -i XXXX.mp4 -filter:v "setpts=(30/$SOURCEDURATION)*PTS" output.mp4 I had hoped to be able to do it in a 1 shot line a batch file.
    – Pyromanci
    Sep 25, 2018 at 18:49
  • Not possible to do it in one command; you have to do some scripting. If your code answers your question, please use the button below to post your own answer.
    – slhck
    Sep 26, 2018 at 7:49

1 Answer 1

2

Say your input file is input.mp4 and output is output.mp4. You want output.mp4 to be approximately 30 seconds long.

Here's a one-liner:

ffmpeg -i input.mp4 -filter:v "setpts=PTS/$(($(ffprobe -v error -show_format -show_streams -i input.mp4 | grep 'duration=' | head -n 1 | sed 's/duration=//')/30))" output.mp4

Let's break it down. First, we find the file duration with:

ffprobe -v error -show_format -show_streams -i input.mp4 | grep 'duration=' | head -n 1 | sed 's/duration=//'

We are getting the duration with ffprobe, then extracting the information with grep, head, and sed.

Next, we divide this quantity by 30 using:

$(( $(ffprobe -v error -show_format -show_streams -i input.mp4 | grep 'duration=' | head -n 1 | sed 's/duration=//') / 30 ))

We plug this into the -filter:v "setpts=PTS/..." to give us the correct ratio for speedup or slowdown.


Generic way

Now, assuming we define the input file as INPUT_FILE, the output file as OUTPUT_FILE, and the required duration as OUTPUT_DURATION, here's the generic way to write this:

ffmpeg -i $INPUT_FILE -filter:v "setpts=PTS/$(($(ffprobe -v error -show_format -show_streams -i $INPUT_FILE | grep 'duration=' | head -n 1 | sed 's/duration=//')/$OUTPUT_DURATION))" $OUTPUT_FILE

Interpretable way

Lastly, here's the more interpretable way to write all of this:

INPUT_FILE=input.mp4
OUTPUT_FILE=output.mp4
OUTPUT_DURATION=30

CURRENT_DURATION=$(ffprobe -v error -show_format -show_streams -i $INPUT_FILE | grep 'duration=' | head -n 1 | sed 's/duration=//')

SPEEDUP=$(( $CURRENT_DURATION / $OUTPUT_DURATION ))

ffmpeg -i $INPUT_FILE -filter:v "setpts=PTS/$SPEEDUP" $OUTPUT_FILE
1
  • thanks for the clear answer! I tried this but it seems that the audio track is not changed so no longer matches the video. How can this be modified so the audio is also sped up? thanks!
    – dan
    Jun 1 at 12:33

You must log in to answer this question.

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