summary refs log tree commit diff
path: root/.config/mpv/vapoursynth/interpolate.vpy
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2026-04-08 13:26:13 +0900
committerRobert Günzler <r@gnzler.io>2026-04-08 13:26:13 +0900
commit4e34cbf9673aeaba252e01df554a0d204e83c5e2 (patch)
treef3eea07d0e2bf1628ce19987c5164577f63ac614 /.config/mpv/vapoursynth/interpolate.vpy
parent28db7c76e26c312918959384e02e433f8858de49 (diff)
Automated-commit-by: dots
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to '')
-rw-r--r--.config/mpv/vapoursynth/interpolate.vpy84
1 files changed, 84 insertions, 0 deletions
diff --git a/.config/mpv/vapoursynth/interpolate.vpy b/.config/mpv/vapoursynth/interpolate.vpy
new file mode 100644
index 0000000..414aa4d
--- /dev/null
+++ b/.config/mpv/vapoursynth/interpolate.vpy
@@ -0,0 +1,84 @@
+# vim: set ft=python:
+
+# see the README at https://gist.github.com/phiresky/4bfcfbbd05b3c2ed8645
+# source: https://github.com/mpv-player/mpv/issues/2149
+# source: https://github.com/mpv-player/mpv/issues/566
+# source: https://github.com/haasn/gentoo-conf/blob/nanodesu/home/nand/.mpv/filters/mvtools.vpy
+
+from vapoursynth import core
+
+# ref: http://avisynth.org.ru/mvtools/mvtools2.html#functions
+# default is 400, less means interpolation will only happen when it will work well
+ignore_threshold = 140
+# if n% of blocks change more than threshold then don't interpolate at all (default is 51%)
+scene_change_percentage = 15
+# default to 60fps
+dst_fps = 60
+realtime = True
+
+if "video_in" in globals():
+    # realtime (mpv)
+    clip = video_in
+    # Needed because clip FPS is missing
+    src_fps_num = int(container_fps * 1e8)
+    src_fps_den = int(1e8)
+    clip = core.std.AssumeFPS(clip, fpsnum=src_fps_num, fpsden=src_fps_den)
+    dst_fps = display_fps
+    # Interpolating to fps higher than 60 is too CPU-expensive, smoothmotion can handle the rest.
+    while (dst_fps > 60):
+        dst_fps /= 2
+else:
+    realtime = False
+    core.std.LoadPlugin('/usr/lib64/libffms2.so')
+    # run with vspipe
+    clip = core.ffms2.Source(source=video_in_path)
+    if "output_fps" in globals():
+        dst_fps = float(output_fps)
+
+# resolution in megapixels. 1080p ≈ 2MP, 720p ≈ 1MP
+mpix = clip.width * clip.height / 1000000
+
+# Skip interpolation for >1080p or 60 Hz content due to performance
+if not (realtime and (mpix > 2.5 or clip.fps_num / clip.fps_den > 59)):
+    analParams = {
+        'overlap': 0,
+        'search': 3,
+        'truemotion': True,
+        #'chrome': True,
+        #'blksize':16,
+        #'searchparam':1
+    }
+    blockParams = {
+        'thscd1': ignore_threshold,
+        'thscd2': int(scene_change_percentage * 255 / 100),
+        'mode': 3,
+    }
+
+    if realtime and mpix > 1.5:
+        # can't handle these on Full HD with Intel i5-2500k
+        # see the description of these parameters in http://avisynth.org.ru/mvtools/mvtools2.html#functions
+        analParams['search'] = 0
+        blockParams['mode'] = 0
+        quality = 'low'
+    else:
+        quality = 'high'
+
+    dst_fps_num = int(dst_fps * 1e4)
+    dst_fps_den = int(1e4)
+    print("Reflowing from {} fps to {} fps (quality={})".format(
+        clip.fps_num / clip.fps_den, dst_fps_num / dst_fps_den, quality))
+
+    sup = core.mv.Super(clip, pel=2)
+    bvec = core.mv.Analyse(sup, isb=True, **analParams)
+    fvec = core.mv.Analyse(sup, isb=False, **analParams)
+    clip = core.mv.BlockFPS(clip,
+                            sup,
+                            bvec,
+                            fvec,
+                            num=dst_fps_num,
+                            den=dst_fps_den,
+                            **blockParams)
+else:
+    print("Skipping interpolation")
+
+clip.set_output()