Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
28th March 2020, 15:26 | #1 | Link |
Registered User
Join Date: Apr 2010
Posts: 16
|
Presenting VapourSynth.nim
I have wrapped VapourSynth in Nim programming language. Nim is to C like CoffeScript is to JavaScript.
The main advantages I see are: 1. Writting a pipeline is very easy. It feels even easier than python. For instance, reading the first 100 frames, transposing and piping to stdout: Code:
import vapoursynth Source("video.mkv")[0..100].Transpose.Pipey4m 3. It should be as fast as C. (But I haven't performed any serious benchmark yet) 4. You can even perform filters like in C. mycrop.nim is an implementation similar (not complete) to vapoursynth's simplefilter.c version. 5. Nim has metaprogramming superpowers. I have created a macro to make easier the development of filters. This way, the creation of a filter becomes: Code:
import ../vapoursynth import mymacro import options import strformat newFilter("MyCropRel"): parameters: inClip clip # Input video (mandatory) optional: left Natural right Natural top Natural bottom Natural validation: # We assign the destination's frame size data.width = data.vi.width.Natural - data.left - data.right data.height = data.vi.height.Natural - data.top - data.bottom # Avoid too much cropping assert( (data.top + data.bottom) < data.vi.height, "vertical cropping too big" ) assert( (data.left + data.right) < data.vi.width, "horizontal cropping too big" ) # make sure the given values will work with subSampling assert( (data.left mod divHorizontal) == 0, &"subSampling: \"left\"={data.left} not divisible by {divHorizontal}" ) assert( (data.top mod divVertical) == 0, &"subSampling: \"top\"={data.top} not divisible by {divVertical}" ) assert( (data.width mod divHorizontal) == 0, &"subSampling: new \"width\"={data.width} not divisible by {divHorizontal}" ) assert( (data.height mod divVertical) == 0, &"subSampling: new \"height\"={data.height} not divisible by {divVertical}") if (data.left == 0 and data.right == 0 and data.top == 0 and data.bottom == 0): passTrough() processing: let dst = src.newVideoFrame(data.width, data.height) #echo "Frame: ", n for i in 0..<srcNumPlanes: var srcPlane = src.getPlane(i) var dstPlane = dst.getPlane(i) srcPlane.goto(row=data.top, col=data.left) if data.height > 0: srcPlane.copy(dstPlane, rows=data.height, cols=data.width) - parameters: The function parameters, where left, right, top, bottom has Natural type (>=0) - validation: contains all the checks needed for the inputs - processing: which is pretty human friendly code. Creates a new frame, iterates over the planes, goes to a position in the plane and copiesss a number of rows up to certain column. It does so bearing in mind the subsampling. This is about 40 lines for a working filter. You can find it here. In order to use this filter you would do: Code:
import ../vapoursynth import options import croprel # Reads the file, applies the Simple filter and saves the result in a file Source("../../test/2sec.mkv").MyCropRel(top=some(150.Natural),bottom=some(150.Natural)).Savey4m("original.y4m") Code:
$ time nim c modifyframe real 0m1,284s user 0m1,361s sys 0m0,136s Code:
$ time ./modifyframe real 0m0,176s user 0m0,141s sys 0m0,038s Code:
$ time ./modifyframe2 real 0m0,186s user 0m0,148s sys 0m0,037s I hope you find it useful. There is lot of work to do ahead nonetheless. I am not a pro-developer, so my code is pretty ugly. Bear in mind that this has been my toy project to learn Nim. |
|
|