mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.14k stars 2.88k forks source link

How is vf=vapoursynth so fast? #12853

Closed NotMithical closed 11 months ago

NotMithical commented 11 months ago

I've been using a vapoursynth script to descale poorly upscaled sources before scaling in MPV, and I noticed a strange inconsistency. When I benchmark the same vapoursynth script in vsedit, or encode with it through FFMPEG or MPV, it runs at ~210fps using nearly 100% of my CPU. Enabling the same vapoursynth in MPV at runtime or in my mpv.conf as a vf, I get the same result visually but with the below profile I see I get around 1600fps with my CPU at about 44% usage.

[benchmark]
audio=no
untimed=yes
video-sync=display-desync
vulkan-swap-mode=immediate
opengl-swapinterval=0
d3d11-sync-interval=0
osd-msg1="FPS: ${estimated-display-fps}"

I'm confident this isn't due to encoding overhead or a GPU bottleneck as benchmarking the vpy script in vsedit doesn't appear to have any more than around 5% GPU usage and zero hardware encoder usage.

Everything is functioning properly, I'm just curious as to why there's such a big gap in performance between these implementations.

Log file

From playing a video with --no-config and --vf=vapoursynth="descale.vpy"

log.txt

Andarwinux commented 11 months ago

If the benchmark profile is used to measure de/en/transcoding performance, display-fps-overrideshould be made equal to the source video frame rate to avoid any interpolation.

NotMithical commented 11 months ago

Oh of course. Well that does give me more realistic results, more like 240fps now. I'm still curious about the difference in resource usage as it's still a far cry from 100% like it is when encoding or benchmarking with vsedit.

NotMithical commented 11 months ago

Actually, hang on. That fps value I just gave is almost exactly 10x what I set display-fps-override to. The ~1600 and ~3400 I got before are almost exactly 10x and 20x my display's reported refresh rate. Is setting that option actually an entirely reliable way to ensure no interpolation is happening?

Andarwinux commented 11 months ago

Oh of course. Well that does give me more realistic results, more like 240fps now. I'm still curious about the difference in resource usage as it's still a far cry from 100% like it is when encoding or benchmarking with vsedit.

Maybe because of the different de/encoders used? I don't know.

Is setting that option actually an entirely reliable way to ensure no interpolation is happening?

Yes, estimated-display-fps exceeds display-fps-override because the performance far exceeds the realtime processing requirements, and also disabled vsync, so that should be the expected behavior.

hooke007 commented 11 months ago

I do not think you will make mpv+vs as fast as vs only. Here is another example. https://github.com/vapoursynth/vapoursynth/issues/720#issuecomment-896479833

kasper93 commented 11 months ago

estimated-display-fps is telling you the presentation speed. It is not suitable to profile if decoding/filtering is slower than you display rate or target frequency. In short you are not profiling it correctly and the number you are seeing is multiplied by your vsync rate.

It is explained here https://haasn.dev/posts/2017-10-05-how-to-benchmark-mpvs-raw-throughput.html in caveats section.

In short to profile, you need to know what part you are interested in. This profiling you are using is mostly suited for GPU rendering and presentation speed.

NotMithical commented 11 months ago

Ok, I think I've got it now. Still some things I'm curious about with vapoursynth's performance but this definitely answers my question for the time being, plus I see where I went wrong trying to profile things. Thank you!

erickyun commented 10 months ago

is it possible if you could you please share your descale.vpy script?

NotMithical commented 10 months ago

is it possible if you could you please share your descale.vpy script?

Sure, it's a basic one but here you go:

from vapoursynth import core
import vapoursynth as vs

video_in = core.descale.Debilinear(video_in, 1280, 720)
video_in.set_output()
erickyun commented 10 months ago

is it possible if you could you please share your descale.vpy script?

Sure, it's a basic one but here you go:

from vapoursynth import core
import vapoursynth as vs

video_in = core.descale.Debilinear(video_in, 1280, 720)
video_in.set_output()

Thank you very much. I sincerely appreciate it.