v0.96g "Terrible No Matter How Much You Struggle"
Pre-releaseNote: this is still experimental. The prerelease is to gather comments on the API.
This release introduces two new filters (Select
to replace some common use cases of std.FrameEval
and PropExpr
to replace some common use cases of std.ModifyFrame
), along with some enhancements and bugfixes to existing filters.
The most notable enhancement is the removal of 26 input clips limitation across all Expr filters (Expr
, Select
and PropEdit
). Use srcN
to access the N
-th clip (For example, src0
is x
, src25
is w
.) There is no hardcoded limitation on how many inputs you can pass, but using too many might have VS performance implications. I have tested up to 255 input clips and all seem fine.
New Feature: Select
filter
This release introduces a Select
filter that aims to replace common uses of std.FrameEval
when you just need to select one clip from multiple using the frame properties of another set of clips (e.g. mvsfunc.FilterIf
)
Unlike std.FrameEval
, the Select
filter doesn't rely on Python, so it's unaffected by GIL and is fully parallelized. It also supports most of the operators supported by Expr
(except those that access pixel values).
akarin.Select(clip[] clip_src, clip[] prop_src, string[] expr)
For each frame n
, expr
computes an index (idx
) using frame properties for frame n
of all clips in prop_src
clips and then the n-th frame of clip_src[idx]
will be returned.
As all the clips in prop_src
are always requested for each frame, you should aim to minimize the cost for those clips. For each frame, only one clip from clip_src
will be requested, so those clips should be the heavyweight in terms of computation cost.
If you specify multiple expressions for expr
, then they will be used to select each planes of the output (the last specified expression will be repeated as necessary). But note that each output plane always comes from the corresponding plane of one of the clip_src
input. That is, you can select different input clips for different planes, but you can't use the input's U plane as the output's V plane.
A simple example:
mvsfunc.FilterIf(src, flt, '_Combed', prop_clip) # is equivalent to:
core.akarin.Select([src, flt], prop_clip, 'x._Combed 1 0 ?') # when x._Combed is set and True, then pick the 2nd clip (flt) otherwise use src
The expression is still evaluated in 32-bit floating point and the final result will be rounded to nearest integer and then clamped to be within [0, len(clip_src)-1]
before used as an index into clip_src
.
Three new operators are introduced to simplify the common case of ranking some property and then pick the best clip:
argminN
andargmaxN
: consume N elements from the stack, find the index for the max/min value in those N values. e.g.2 1 0 3 100 argmin5
should push2
on the stack (as the minimum value0
is the 3rd value [index starts from 0, as in Python]).argsortN
: in case you want a rank other than the minimum or maximum, we haveargsortN
which will sort the top N values and return the indices. e.g.9 5 1 2 8 4 0 3 6 7 argsort10
should put0 4 9 8 1 5 7 3 2 6
(top is on the right) onto the stack. If you want the index for I-th smallest value, thendupI idx! drop10 idx@
should do. Please beware the difference betweensortN
andargsortN
.
Notes:
- Unlike
Expr
, the expressions are interpreted, not JIT'ed. This shouldn't pose a big issue as it's still 10x faster than Python's interpreter.
New Feature: PropExpr
filter
akarin.PropExpr(clip[] clips, dict=lambda: dict(key=val))
PropExpr
is a filter to programmatically compute numeric frame properties. Given a list of clips, it will return the first clip after modifying its frame properties as specified by the dict argument. The expressions have access to the frame property of all the clips.
dict
is a Python lambda that returns a Python dict, where each key specifies the expression that evaluates to the new value for the frame property of the same name. The expression supports all operators supported by Select
(i.e. no support for pixel access operators.)
For each val
, there are three cases:
- an integer, or a float: the property
key
will be set to that value. - an empty string: the property
key
will be removed. - an expression string: the result of evaluating the expression specifies the value of property
key
. If the result is an integer, then it will be set as an integer frame property, otherwise, a floating point frame property. (Please beware that some special properties do need to be integer, e.g._ChromaLocation
,_ColorRange
, etc.)
Additionally, in v0.96e or above, val
could also be an array of numbers, and each output frame will use subsequent element of the array (wrap around to the first.)
Some examples:
PropExpr(c, lambda: dict(_FrameNumber='N'))
: this set the_FrameNumber
frame property to the current frame number.PropExpr(c, lambda: dict(A=1, B=2.1, C="x.Prop 2 *"))
: this set propertyA
to constant 1,B
to 2.1 andC
to be the value returned by the expressionx.Prop 2 *
, which is two times the value of the existingProp
property.PropExpr(c, lambda: dict(ToBeDeleted=''))
: this deletes the frame propertyToBeDeleted
(no error if it does not exist.)PropExpr(c, lambda: dict(A='x.B', B='x.A'))
: this swaps the value of propertyA
andB
as all frame property updates are performed atomically.PropExpr(c, lambda: dict(C=[0, 1, 2]))
: output framei
will have frame propertyC
set toi%3
. A common idiom of generating strength clip for specified value given a list of values (values
) in Python isstrength = core.std.BlankClip(format=vs.GRAYS, width=1, height=1, length=len(values)).akarin.PropExpr(lambda:dict(_val=values)).akarin.Expr('x._val')
, then thei
-th frame ofstrength
clip will havevalues[i]
as its uniform pixel values.
Notes:
- This peculiar form of specifying the properties is to workaround a limitation of the VS API. (I know api4 can use
any
, but unfortunately, this plugin has to support api3 as well. It's a trivial matter to write a nicer Python wrapper for this interface, so I don't think it matters much.) - Unlike
Expr
, the expressions are interpreted, not JIT'ed. This shouldn't pose a big issue as it's still 10x faster than Python's interpreter.
New Feature: Text
filter (v0.96b)
The v0.96b release also introduces an enhanced text.Text
filter.
New Feature: Tmpl
filter (v0.96c)
If you want a Text filter on steroid ...
New Feature: PickFrames
filter (v0.96g)
akarin.PickFrames(clip clip, int[] indices)
Return a new clip with frames picked from input clip
from the indices
array.
PickFrames(c, indices)
is functionally equivalent to c[indices[0]] + c[indices[1]] + ... + c[indices[-1]]
, only more efficient as you only need to create one filter instance, especially when len(indices)
is very large. As long as all indices are within range [0, c.num_frames-1]
, there is no limit on the the indices.
New Feature: ExprTest
filter (v0.96g2)
....
Enhancements
- Issue #18:
DLVFX
now takes amodel_dir
parameter and it overrides theMODEL_DIR
environment variable and the builtin hardcoded pathC:\Program Files\NVIDIA Corporation\NVIDIA Video Effects\models
. - Issue #19: fixed compatibility with newer VFX version (
Invalid strengh parameter
error forOP_SUPERRES
.) - Issue #19: DLVFX
OP_DENOISE
is NOT working. - Issue #17: All expr filters now allow arbitrary number of input clips. Use
srcN
to access theN
-th input. e.g.src0
isx
, andsrc25
isw
. - Issue #22: allow reading the first byte of bytes-typed frame properties (v0.96b).
- Issue #15: support for LLVM 14/15 added. (v0.96d)
Expr
now fully supports 16-bit floating point formats, even when the underlying architecture doesn't support the f16c instruction set extension (std.Expr
only supports 16-bit floating point formats when f16c is present.) (v0.96d)- Now you can put
akarin.dlisr.dll
asakarin\dlisr.dll
to avoid getting warnings during VS plugin autoload. (v0.96d2) - Support arrays in
PropExpr
(e.g.PropExpr(c, lambda: dict(C=[0, 1, 2]))
: output framei
will have frame propertyC
set toi%3
.) (v0.96e) - Fixes #14, logical operators with mixed int/float operands in certain rare cases (v0.96f)
- Add
lerp
andpolyval
/polyeval
operators (v0.96g3).