Skip to content

v0.96g "Terrible No Matter How Much You Struggle"

Pre-release
Pre-release
Compare
Choose a tag to compare
@AkarinVS AkarinVS released this 20 Nov 10:48
· 14 commits to master since this release

Note: 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 and argmaxN: 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 push 2 on the stack (as the minimum value 0 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 have argsortN 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 put 0 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, then dupI idx! drop10 idx@ should do. Please beware the difference between sortN and argsortN.

Notes:

  1. 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 property A to constant 1, B to 2.1 and C to be the value returned by the expression x.Prop 2 *, which is two times the value of the existing Prop property.
  • PropExpr(c, lambda: dict(ToBeDeleted='')): this deletes the frame property ToBeDeleted (no error if it does not exist.)
  • PropExpr(c, lambda: dict(A='x.B', B='x.A')): this swaps the value of property A and B as all frame property updates are performed atomically.
  • PropExpr(c, lambda: dict(C=[0, 1, 2])): output frame i will have frame property C set to i%3. A common idiom of generating strength clip for specified value given a list of values (values) in Python is strength = core.std.BlankClip(format=vs.GRAYS, width=1, height=1, length=len(values)).akarin.PropExpr(lambda:dict(_val=values)).akarin.Expr('x._val'), then the i-th frame of strength clip will have values[i] as its uniform pixel values.

Notes:

  1. 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.)
  2. 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 a model_dir parameter and it overrides the MODEL_DIR environment variable and the builtin hardcoded path C:\Program Files\NVIDIA Corporation\NVIDIA Video Effects\models.
  • Issue #19: fixed compatibility with newer VFX version (Invalid strengh parameter error for OP_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 the N-th input. e.g. src0 is x, and src25 is w.
  • 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 as akarin\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 frame i will have frame property C set to i%3.) (v0.96e)
  • Fixes #14, logical operators with mixed int/float operands in certain rare cases (v0.96f)
  • Add lerp and polyval/polyeval operators (v0.96g3).