Skip to content

Instantly share code, notes, and snippets.

@Fire-
Created June 11, 2016 06:06
Show Gist options
  • Save Fire-/2c3472619202cf6ae29dd26a8e0aa0d7 to your computer and use it in GitHub Desktop.
Save Fire-/2c3472619202cf6ae29dd26a8e0aa0d7 to your computer and use it in GitHub Desktop.
fps reflow alteration
### 0
## Uses motion vectors to change the framerate of a file with motion blur instead of standard duplication or decimation
## Requires:
# ffmpeg
# vapoursynth http://www.vapoursynth.com/
# ffms2 vs plugin https://github.com/FFMS/ffms2/blob/master/doc/ffms2-vapoursynth.md
# mvtools vs plugin https://github.com/dubhater/vapoursynth-mvtools
### 1
## Snip the part you want, or use the whole file, either way
## if you do not need to snip, or to re-encode, omit this step.
# ffmpeg -ss 1 -i INPUT_FILE -ss 1 -force_key_frames "expr:gte(t,n_forced*2)" -c:a copy -c:v libx264 -preset ultrafast -qp 10 OUTPUT_FILE
### 2
## get the duration of this file, you'll need it later
# ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 INPUT_FILE
# 28.775000
## ^ = END_TIMESTAMP
### 3
## replace file variable string with your output filename
## run this to generate your output file, replacing INPUT_FILE, END_TIMESTAMP, and FINAL_OUTPUT with tthe first file ( for audio ), the first file's duration ( from ffprobe ), and your designated output filename, respectively
# vspipe -p -y reflow.vpy - | ffmpeg -thread_queue_size 8192 -y -i pipe: -i INPUT_FILE -map 0:v:0 -map 1:a:0 -c:a copy -c:v libx264 -preset slow -crf 18 -force_key_frames "expr:gte(t,n_forced*2)" -to END_TIMESTAMP FINAL_OUTPUT.mp4
###
import vapoursynth as vs
core = vs.get_core()
file = r'OUTPUT_FILE.mp4' # change this
destination_framerate = 40 # 40 for twitter
input_framerate = 60 # whatever your input framerate is supposed to be
source_framerate_numerator = int(input_framerate * 1e8)
source_framerate_denominator = int(1e8)
destination_framerate_numerator = int(destination_framerate * 1e4)
destination_framerate_denominator = int(1e4)
#TODO: feed from input argument if possible ( not possible with vspipe? )
clip = core.ffms2.Source(source=file, seekmode=0)
# resize to 1080p because twitter can't consume 1440p
#TODO: only downscale if greater than 1080
clip = core.resize.Lanczos(clip=clip, width=1920, height=1080)
# append 10s blank clip because of some dumb bug that stalls video track several seconds before end
#TODO: solve this a better way
clip = clip + core.std.BlankClip(clip)
# Needed because clip FPS is missing and assuming on the import screws the export framerate
clip = core.std.AssumeFPS(clip, fpsnum = source_framerate_numerator, fpsden = source_framerate_denominator)
print("Reflowing from ",source_framerate_numerator/source_framerate_denominator," fps to ",destination_framerate_numerator/destination_framerate_denominator," fps.")
# prepare mvtools "super" clip
sup = core.mv.Super(clip, pel=1, hpad=8, vpad=8)
# forward motion vector analysis
bvec = core.mv.Analyse(sup, blksize=4, isb=True , chroma=True, search=3, searchparam=1, truemotion=True)
# backward motion vector analysis
fvec = core.mv.Analyse(sup, blksize=4, isb=False, chroma=True, search=3, searchparam=1, truemotion=True)
# motion vector blurring
clip = core.mv.FlowBlur(clip, sup, bvec, fvec, blur=100, thscd2=12)
# motion vector reflow fps decimation
clip = core.mv.FlowFPS(clip, sup, bvec, fvec, num=destination_framerate_numerator, den=destination_framerate_denominator, thscd2=12, blend=False)
# block based fps decimation, if desired instead. Comment ^ if uncommented.
#clip = core.mv.BlockFPS(clip, sup, bvec, fvec, num=destination_framerate_numerator, den=destination_framerate_denominator, mode=3, thscd2=12)
# set the clip as ready to output for the receiving application.
clip.set_output()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment