title: Retime Video aka Change Framerate tags: ffmpeg The aim here is to take e.g. a 25fps video, change it so that it becomes 24fps using the same frames (so is slightly longer), and also stretch the audio to fit the new length. To take a 24fps video and make it 30fps (same frames, sped up, shorter duration): (from [this stackoverflow](https://stackoverflow.com/questions/45462731/using-ffmpeg-to-change-framerate) # With re-encoding Note that you have to compute the `1.25` passed to `setpts`. ```bash ffmpeg -y -i in.mp4 -vf "setpts=1.25*PTS" -r 24 out.mp4 ``` # Without re-encoding This is useful since there is no need to compute the fraction of input-fps/output-fps. First step - extract video to raw bitstream ``` ffmpeg -y -i in.mp4 -c copy -f h264 in.h264 ``` Remux with new framerate ``` ffmpeg -y -r 24 -i in.h264 -c copy out.mp4 ``` # Stretching Audio You could use a DAW like Reaper, or a command line app like [rubber band](https://breakfastquay.com/news/20241025.html). # Combined script This is something rough cobbled together. I think it works, but haven't properly tested it, and it's not robust. The `getvdur` script returns the duration of a media file in the format: `filename.mp4: 3661 1h1m1s`. Something more robust could be written in Python. ```bash #!/bin/bash # usage: # retime OFR file1 [file2...] # where OFR is TARGET frame rate. chk() { for s; do which "$s" >& /dev/null || { echo "no $s"; exit 1; } done } chk ffprobe ffmpeg rubberband-r3 getvdur ofrate="$1" shift # temporary filenames wav="tmp_audio.wav" rwav="tmp_raudio.wav" h264="tmp_video.h264" tmp4="tmp_video.mp4" for ifn; do if ! rm -f "$wav" "$rwav" "$h264" "$tmp4"; then echo "Failed to delete temporary files" exit 1 fi ofn="rt_$ifn" if [ -e "$ofn" ]; then echo "$ofn exists already" continue fi # must h264 to mp4 to get resulting dur for rubber band ffmpeg -y -i "$ifn" "$wav" if [ ! -e "$wav" ]; then echo "Failed to extract audio" exit 1 fi ffmpeg -y -i "$ifn" -an -c:v copy -f h264 "$h264" if [ ! -e "$h264" ]; then echo "Failed to extract h264 video" exit 1 fi VIDCODEC="-c:v h264_nvenc -b:v 8M" # full hd with nvidia gpu VIDCODEC="-b:v 8M" # full hd using cpu ffmpeg -y -r "$ofrate" -i "$h264" -an $VIDCODEC "$tmp4" if [ ! -e "$tmp4" ]; then echo "Failed to convert frame rate to $tmp4" exit 1 fi d="$(getvdur "$tmp4" | cut -f2 -d: | awk '{ print $1 }')" rubberband-r3 -D$d "$wav" "$rwav" if [ ! -e "$rwav" ]; then echo "Failed to stretch audio" exit 1 fi ffmpeg -i "$tmp4" -i "$rwav" -c:v copy -map 0:0 -map 1:0 -b:a 160k "$ofn" if [ ! -e "$ofn" ]; then echo "Failed to combine to output file" exit 1 fi done ```