Nuihc88 / SVPlite

SVPlite - Realtime-Optimized AviSynth+ Script-Templates for the SmoothVideo Project's SVPflow filters. Portable Low-Resource Motion Interpolation.
The Unlicense
37 stars 4 forks source link

Open Discussion About Future Direction: Suggestions? Collaboration? #3

Closed Nuihc88 closed 1 year ago

Nuihc88 commented 2 years ago

I have more or less finished refining these scripts now, but am thinking of taking the project into new directions...

Here are some of my current ideas for possible future improvements:

Use ChangeFPS to create duplicate frames to later be replaced by DupeInterpolator ScriptClip.

   FramerateTargetingMode=1                # 0 = None    - Don't use ChangeFPS to add extra duplicates to interpolate.
   TargetFPS=59.94              Num=2      # 1 = Dynamic - Uses highest integer multiplier below TargetFPS.

global Stats=false Den=1 # 2 = Set FPS - Creates duplicate frames to reach all the way up to TargetFPS. global DupeThreshold=.618034 # 3 = Static - Uses Num / Den values from above to set framerate manually. if (FramerateTargetingMode==1) {Num=1 while(FrameRate()(Num+1)<TargetFPS){Num=Num+1} ChangeFPS(FrameRate()Num)} else if (FramerateTargetingMode==2) {ChangeFPS(TargetFPS)} else if (FramerateTargetingMode==3) {ChangeFPS(Num, Den)}

DupeInterpolator = """Difference=YDifferenceFromPrevious() FrameNumber=current_frame global DupeFactor=0 global DupeCounter=0 if(Framecount()>current_frame && DupeThreshold>=Difference) {current_frame=current_frame+1 DupeFactor=DupeFactor+1 DupeCounter=DupeCounter+1 while(Framecount()>current_frame && DupeThreshold>=YDifferenceFromPrevious() ) {current_frame=current_frame+1}

trim(FrameNumber-1,-1)+trim(current_frame,-1)
  super=SVSuper(last,super_params)      vectors=SVAnalyse(super,analyse_params,src=last)
  SVSmoothFps(super,vectors,"{rate:{num:"+string(DupeFactor+1)+",den:1"+smoothfps_params,mt=1)
trim(1,DupeFactor) Stats ? Subtitle("Dupe-Pass: Interpolated") : last}

else{DupeFactor=0 Stats ? Subtitle("Dupe-Pass: Original") : last} Stats ? Subtitle("Threshold = "+string(DupeThreshold) +" Difference = "+string(Difference)+" DupeFactor = "+String(DupeFactor)+\ " Duplicates= "+String(DupeCounter)+ " Originals = "+string(FrameNumber-DupeCounter)+" Total = "+string(FrameNumber), align=8) : last""" ScriptClip(DupeInterpolator)


Although the output from the above script is looking amazingly smooth, it's currently only getting ~20 fps, due to not being thread safe.
couleurm commented 2 years ago

Hey, I've been lurking on this repo for a while, but haven't got the occasion to spend some time messing with trying to use these settings on VapourSynth (if that's even possible) to make use in my project, I've also made a post on doom9 explaining my objective on a larger scale if you're curious

I'm interested in learning C/C++ to make VapourSynth plugins but I really don't know where to start, the only thing I found is this

Nuihc88 commented 2 years ago

Importing the settings is certainly possible... If it helps, here's my half-finished VapourSynth Test Script with UltraLight Animated Preset's settings enabled:

import vapoursynth as vs
from vapoursynth import core
import math
core.num_threads=4 #8 #16
core.add_cache=True
core.max_cache_size=4000

last = VpsFilterSource #.resize.Point(format=vs.YUV420P8)

super_params="{pel:1,gpu:1,full:false}"
analyse_params="{block:{w:32,h:32,overlap:0},main:{\
search:{distance:-0 ,type:4,satd:false,sort:false,\
coarse:{distance:-21,type:2,satd:false,trymany:false,\
width:241,bad:{range:0}}},levels:3,penalty:{lambda:3.3,\
plevel:1.25,pnew:44,pglobal:104,pzero:240,pnbour:74,prev:-1}}}"
smoothfps_params="},mask:{cover:99},algo:2,cubic:1,linear:false,scene:{\
mode:0,blend:false,limits:{scene:2220,zero:4,blocks:42},luma:1}}"

  Num="2";  Den="1";    Abs="false"
super = core.svp1.Super(last,super_params)
vectors = core.svp1.Analyse(super["clip"],super["data"],last,analyse_params)
smooth = core.svp2.SmoothFps(last,super["clip"],super["data"],vectors["clip"],vectors["data"],"{rate:{num:"+str(Num)+",den:"+str(Den)+",Abs:"+str(Abs)+smoothfps_params,src=last,fps=VpsFilterSource.fps)
#"{rate:{num:"+String(Num)+",den:"+String(Den)+",abs:"+String(abs)+smoothfps_params,src=last,fps=VpsFilterSource.fps)
smooth = core.std.AssumeFPS(smooth,fpsnum=smooth.fps_num,fpsden=smooth.fps_den)
smooth.set_output()

For some reason it's performing far worse than the AviSynth+ version, but at least it runs and has fairly readable formatting.

couleurm commented 2 years ago

I think a function to convert multi-line string that removes spaces and new-lines into a single line string would be great to improve readability, so we can use JSON-like indentation/spacing and pass that thru a def

couleurm commented 2 years ago

This isn't working code at all, just an idea of how it could work:


AnalyseParams = helpers.Wrap('''
{
    block:{
        w:32,
        h:32,
        overlap:0
    },
    main:{
        search:{
            distance:-0,
            type:4,
            satd:false,
            sort:false,
            coarse:{
                distance:-21,
                type:2,
                satd:false,
                trymany:false,
                width:241,
                bad:{
                    range:0
                }
            }
        },
        levels:3,
        penalty:{
            lambda:3.3,
            plevel:1.25,
            pnew:44,
            pglobal:104,
            pzero:240,
            pnbour:74,
            prev:-1
        }
    }
}
''')

SmoothFPSParams = helpers.Wrap('''
{
    rate:{
        num:"2",
        den:"1",
        Abs:"false"
    },
    mask:{
        cover:99
    },
    algo:2,
    cubic:1,
    linear:false,
    scene:{
        mode:0,
        blend:false,
        limits:{
            scene:2220,
            zero:4,
            blocks:42
        },
    luma:1
    }
}
''')

or in a less verbose-y way:


AnalyseParams = helpers.Wrap('''
{
    block:{w:32,h:32,overlap:0},
    main:{
        search:{
            distance:-0,type:4,satd:false,sort:false,
            coarse:{
                distance:-21,type:2,satd:false,
                trymany:false,width:241,
                bad:{range:0}
            }
        },
        levels:3,
        penalty:{
            lambda:3.3,plevel:1.25,pnew:44,
            pglobal:104,pzero:240,pnbour:74,prev:-1
        }
    }
}
''')

SmoothFPSParams = helpers.Wrap('''
{
    rate:{
        num:"2",den:"1",Abs:"false"
    },
    mask:{cover:99},
    algo:2,cubic:1,linear:false,
    scene:{
        mode:0,blend:false,
        limits:{
            scene:2220,zero:4,blocks:42
        },
    luma:1
    }
}
''')
Nuihc88 commented 2 years ago

Personally i prefer keeping the configurations in just a few densely populated lines grouped into repeating patterns; that way it's quick and easy to review various versions and revisions in WinMerge's 3-way compare mode without needing to scroll around.

One of the reasons i'm rethinking readability in the first place has to do with my plans to make a simple GUI configuration tool later on. For example, i have following considerations for editing parameters:

  1. There are 2(+) 'distance', 'type' and 'satd' parameters, plus other similarly named parameters that must be kept differentiable based on context, otherwise it would have to cache and rewrite the whole file, which would wipe out comments and any experimental edits. Thus '{' can't be used as a simple separator, which effectively means having to insert whitespace characters and use those instead.
  2. Preventing whitespace drift while repeatedly applying RegEx to strings. Thus the code will need to be padding aware and possibly able to differentiate space, tab & linebreak characters.
  3. Then there is also the problem of where and how to insert sad, lsad & refine, which are currently not used by my scripts, but could be added through the GUI.

Currently i'm thinking of using something like this as a template:

super_params="{pel: 1, gpu: 1, full:false , scale:{ up: 2 , down: 4 } }"
analyse_params="{ block:{ w:32 , h:32 , overlap: 0 },   main:{          \
levels: 3 ,  search:{ distance: -0 , type: 4 ,    sort:false , satd:false   ,   \
coarse:{ width: 241 , distance:-21 , type: 2 , trymany:false , satd:false   ,   \
   bad:{ range:   0 , sad: 1000 }}}, penalty:{    lsad: 8000 , lambda: 3.3  ,   \
prev: -1 , pnew: 44 , pzero: 240 , pnbour: 74 , pglobal: 104 , plevel: 1.25 }}  \
,refine:[\
{thsad:65000, penalty:{pnew:44}, search:{ distance:-6 , type:2 , satd:false } },\
{thsad:65000, penalty:{pnew:44}, search:{ distance:-3 , type:4 , satd:false } }]\
}"
smoothfps_params="}, algo: 2 , linear:false , cubic: 1 , block:false , gpuid: 0,\
mask:{ cover: 88 , area: 0 , area_sharp:1.00 } , scene:{ mode: 0 , blend:false ,\
limits:{ m1:1800 , m2:3600 , scene:2220 , zero:  4 , blocks: 42 }, luma: 1.00 }}"

...that way i can find & replace almost anything using spaces (e.g. ' sort:false ' -> ' sort: true ') as separators and the remaining ones i could differentiate using Regular Expression wildcards and look-behind assertions (e.g. satd:.....(?<=.search:{ ) )

Moving Num, Den & Abs outside the smoothfps_params-string is another future proofing step required for more advanced motion interpolation scripts like the one in the first post, but i won't add those changes to my current scripts until i have something more usable.

couleurm commented 2 years ago

What is your opinion on using mvtools with VapourSynth?

Nuihc88 commented 2 years ago

What is your opinion on using mvtools with VapourSynth?

I read somewhere that mvtools is slow and CPU only, which means it might not be suitable for realtime use or at least may require 16+ core CPU. However i don't really have enough experience with it to have an opinion one way or another.