Log in

View Full Version : View VapourSynth Output in .NET


Pages : [1] 2

MysteryX
1st June 2018, 01:53
Is there a way to display the output of a VapourSynth script in a .NET application? What kind of API does VapourSynth expose?

TheFluff
1st June 2018, 03:48
read the fucking manual (http://www.vapoursynth.com/doc/api/vapoursynth.h.html), it's a plain c api. there's a c++ wrapper if you prefer that, and someone also made a rust wrapper, but I don't think I've seen a C# wrapper

if you want to evaluate .vpy scripts, there's a separate api for that (http://www.vapoursynth.com/doc/api/vsscript.h.html).

amichaelt
1st June 2018, 16:41
Is there a way to display the output of a VapourSynth script in a .NET application? What kind of API does VapourSynth expose?

Yes, just create a PInvoke wrapper to the C API or create a C++/CLI wrapper if you prefer that route. There's no mystical ritual involved. ;)

MysteryX
1st June 2018, 18:13
Creating a C# wrapper around raw C API is something I've never done and would be way too much work; was hoping someone might have done it.

I'm better to open it in a MPlayer control, which does have a .NET wrapper around its console interface.

amichaelt
1st June 2018, 18:20
Creating a C# wrapper around raw C API is something I've never done and would be way too much work; was hoping someone might have done it.

I'm better to open it in a MPlayer control, which does have a .NET wrapper around its console interface.

Here's a good reference on PInvoke in case no one else is willing to do it:

https://docs.microsoft.com/en-us/cpp/dotnet/how-to-call-native-dlls-from-managed-code-using-pinvoke

Since you're dealing with a sane, C API it should be pretty straightforward.

MysteryX
1st June 2018, 20:55
This API is for plugin development. If I want to initialize a VapourSynth instance, load a script and return the first frame, which functions do I call?

amichaelt
1st June 2018, 21:43
This API is for plugin development. If I want to initialize a VapourSynth instance, load a script and return the first frame, which functions do I call?

TheFluff already told you:

if you want to evaluate .vpy scripts, there's a separate api for that (http://www.vapoursynth.com/doc/api/vsscript.h.html).

MysteryX
2nd June 2018, 00:45
ok this look quite straightforward; except that it uses a lot of C objects that would make it difficult to invoke via .NET

Function GetOutput is what looks relevant
VSNodeRef * vsscript_getOutput(VSScript *handle, int index)

Retrieves a node from the script environment. A node in the script must have been marked for output with the requested index.

Ownership of the node is transferred to the caller.

Returns NULL if there is no node at the requested index.


It returns a VSNodeRef, and that's all there is about VSNodeRef
struct VSNodeRef

A reference to a node in the constructed filter graph. Its primary use is as an argument to other filter or to request frames from.

Now what do I do with it?

Basically what I want to know is how to read a frame at designed position, and parse it as a RGB displayable image. Is there anything to help convert the output for display?

This really does look like a complex path.

amichaelt
2nd June 2018, 01:19
So then you have to use the core API as well:

const VSFrameRef *getFrame(int n, VSNodeRef *node, char *errorMsg, int bufSize)
Generates a frame directly. The frame is available when the function returns.
This function is meant for external applications using the core as a library, or if frame requests are necessary during a filter’s initialization.
Thread-safe.
n
The frame number. Negative values will cause an error.
node
The node from which the frame is requested.
errorMsg
Pointer to a buffer of bufSize bytes to store a possible error message. Can be NULL if no error message is wanted.
bufSize
Maximum length for the error message, in bytes (including the trailing ‘0’). Can be 0 if no error message is wanted.
Returns a reference to the generated frame, or NULL in case of failure. The ownership of the frame is transferred to the caller.
Warning
Never use inside a filter’s “getframe” function.

Followed by:

const uint8_t *getReadPtr(const VSFrameRef *f, int plane)
Returns a read-only pointer to a plane of a frame.
Passing an invalid plane number will cause a fatal error.
Note
Don’t assume all three planes of a frame are allocated in one contiguous chunk (they’re not).

And then from there you convert the plane data to an RGB image.

Once your done free the frame:

void freeFrame(const VSFrameRef *f)
Deletes a frame reference, releasing the caller’s ownership of the frame.
It is safe to pass NULL.
Don’t try to use the frame once the reference has been deleted.

videoh
2nd June 2018, 03:03
It returns a VSNodeRef, and that's all there is about VSNodeRef

Now what do I do with it? Look at the sample code here:

https://github.com/vapoursynth/vapoursynth/blob/master/sdk/vsscript_example.c

amayra
2nd June 2018, 03:14
Creating a C# wrapper around raw C API is something I've never done and would be way too much work; was hoping someone might have done it.

I'm better to open it in a MPlayer control, which does have a .NET wrapper around its console interface.

At least someone try to do it here (https://forum.doom9.org/showthread.php?t=172244)

MysteryX
2nd June 2018, 03:56
OK getting closer; would be lots of work but it's doable.

For YV12 to RGB32 conversion for display, what other option do I have besides appending a conversion at the end of the script file? Even there, VapourSynth doesn't support any stacked format.

TheFluff
2nd June 2018, 07:47
For display purposes, you can tack on a conversion to COMPATBGR32 at the end of the script. That’s packed RGB32 compatible with Windows bitmaps etc.

foxyshadis
3rd June 2018, 19:57
read the fucking manual (http://www.vapoursynth.com/doc/api/vapoursynth.h.html), it's a plain c api. there's a c++ wrapper if you prefer that, and someone also made a rust wrapper, but I don't think I've seen a C# wrapper

if you want to evaluate .vpy scripts, there's a separate api for that (http://www.vapoursynth.com/doc/api/vsscript.h.html).

Hey, this isn't lkml, you know the minimal level of decorum we expect here. No need to spell out the abbreviation anyway.

MysteryX
6th June 2018, 23:32
SWIG generates a whole lot of classes to manage the interface. Does it have to be so complex or can the C interface be called in a simple way?

I'm looking at the first function vsscript_getVSApi2
https://github.com/vapoursynth/vapoursynth/blob/master/include/VSScript.h#L75

It returns a pointer to an object of type VSAPI. Which is a very complex object.
https://github.com/vapoursynth/vapoursynth/blob/master/include/VapourSynth.h#L242

What's the best way of handling it? Use the SWIG complex code or do it otherwise?

Furthermore, SWIG on VapourSynth.h returns these errors

swig -csharp -module VsApi _\VapourSynth.h
_\VapourSynth.h(193) : Warning 451: Setting a const char * variable may leak memory.
Unable to open file _\SWIGTYPE_p_f_p_q_const__struct_VSMap_p_struct_VSMap_p_q_const__char_p_f_p_struct_VSMap_p_struct_VSMap_p_p_void_p_struct_VSNode_p_struct_VSCore_p_q_const__struct_VSAPI__void_
p_f_int_int_p_p_void_p_p_void_p_struct_VSFrameContext_p_struct_VSCore_p_q_const__struct_VSAPI__p_q_const__struct_VSFrameRef_p_f_p_void_p_struct_VSCore_p_q_const__struct_VSAPI__void_int_int_p_void_p_
struct_VSCore__void.cs: No such file or directory

Furthermore, it fails on VSScript.h

swig -csharp -module VsApi -lvapoursynth.h VSScript.h

VSScript.h(39) : Error: Syntax error in input(1).


And looking at the generated code for VapourSynth.h, the returned VSAPI object doesn't expose any API at all!

MysteryX
7th June 2018, 00:02
VFW avifile API could be a simpler option, but then it requires VapourSynth to be properly installed on the machine so that the codec is recognized. The advantage of using the VapourSynth API directly is that I can deploy VapourSynth.dll and don't need it to be installed on the machine; I don't rely on codec configuration.

MysteryX
7th June 2018, 17:55
OK. Several bad advice were given; and I'm encountering some issues.

read the fucking manual, it's a plain c api
It's not that simple.

At least someone try to do it here (https://forum.doom9.org/showthread.php?t=172244)
Yes thank you! Some great information in there.

Or you could use a tool (http://www.swig.org/index.php) to do the work for you.
SWIG generates a HUGE amount of unnecessary code, linking to an intermediate C library, and even fails to generate for VsScript. It's a pure waste of time here.

So then you have to use the core API as well (GetFrame)
Calling the C++ API within VapourSynth.h is very complex. VsScript exposes a plain C interface to simplify that, and I should stick to it. I believe vsscript_getOutput is what I need to call GetFrame. Knowing what to do with VSNodeRef, however, may be more complex.

Now if I do just this it works

[DllImport(VsScriptDll, CallingConvention=CallingConvention.Cdecl)]
public static extern int vsscript_getApiVersion();


As for strings, how am I supposed to handle them? Someone mentioned they are in UTF8 format. Normally I could call it like this, but only ASCI and UNICODE are supported. What exact format is being used in VapourSynth? Is it a null-terminated UTF8 string?

[DllImport(VsScriptDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int vsscript_evaluateScript(ref IntPtr handle, [MarshalAs(UnmanagedType.LPStr)]string script, [MarshalAs(UnmanagedType.LPStr)]string scriptFileName, int flags);


Edit: As I'm trying to open up a script in VirtualDub, it's showing an error clearly saying it's supposed to be Unicode. The UTF8 information was inaccurate.
2. Everything's supposed to be UTF8, so that's how you should save your scripts too. It Just Works.

jackoneill
7th June 2018, 19:06
UTF8 is a type of Unicode...

Yes, everything in VapourSynth expects char* to contain null-terminated UTF8.

The calling convention in VapourSynth is stdcall (see the VS_CC macro in VapourSynth.h).

MysteryX
7th June 2018, 19:36
UTF8 is a type of Unicode...
Unicode is 2-byte per char, UTF8 is either 1 or 2 bytes per char. Completely different encoding.

I did find some information about how to do it here but I have to do the work manually; automatic marshal won't help me here.
http://blog.kutulu.org/2012/04/marshaling-utf-8-harder-than-it-ought.html

MysteryX
7th June 2018, 20:04
OK I have successfully handled the functions in VsScript, in a nice managed class that handles all allocations and deallocations and UTF8 pointer conversions.

vsscript_getOutput returns VSNodeRef. Now what do I do with it?

It looks like I'll have to dive into VapourSynth.h too for the rest.

For VsScript functions, this is working fine.

[DllImport(VsScriptDll)]
public static extern int vsscript_evaluateFile(ref IntPtr handle, IntPtr scriptFilename, int flags);


In VapourSynth.h, however, the functions are within struct VSAPI. How does this change the declaration?

I see GetFrame takes the VSNodeRef as input parameter and gives VSFrameRef as output. From there, I suppose the other relevant functions are getReadPtr(plane) and getVideoInfo. What else do I need?

MysteryX
7th June 2018, 20:09
According to here this is not possible; which would make that work all for nothing. Unless writing a wrapper in C++.
https://stackoverflow.com/questions/16956820/how-to-call-a-function-in-struct-from-c-dll-by-c-sharp

So far I get the VSFrameNode like this, and the rest is done automatically -- what I'd expect from a managed API

VapourSynthApi Api = VapourSynthApi.LoadFile("test.vpy", true);
string E = Api.GetError();
IntPtr F = Api.GetFrame(0);

Groucho2004
7th June 2018, 21:06
Again, your strong dislike of reading documentation and doing some research is blatantly obvious.

UTF-8, UTF-16, and UTF-32 (among others) are all Unicode encodings.
UTF8 is either 1 or 2 bytes per char.
A UTF-8 character can occupy up to 4 bytes.

Unicode is 2-byte per char
UTF-32 for example occupies 4 bytes.

MysteryX
7th June 2018, 21:16
UTF-8, UTF-16, and UTF-32 (among others) are all Unicode encodings.
According to Wikipedia, you are technically right.

In practice, C# and C++ consider Unicode as UTF-16 specifically.
https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding

So I guess we're both right, depending how we look at it.

Groucho2004
7th June 2018, 21:22
According to Wikipedia, you are technically right.

In practice, C# and C++ consider Unicode as UTF-16 specifically.
https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding

So I guess we're both right, depending how we look at it.
What? C++ doesn't "consider" Unicode. I think you're talking about some .NET stuff that makes it easier to handle character encodings which has nothing to do with the Unicode standard itself.

MysteryX
7th June 2018, 21:28
I'm talking about practical programming on non-compliant MS stuff; you're talking about theoretical standards. But that's irrelevant here.

If you want to be useful, got any idea how to call methods within VSAPI struct in C#? It looks like the only way is to create a C++ wrapper, either a full wrapper, or maybe just simple C-style methods that take VSAPI* as the first parameter and then redirect the call. The downside is that this would make my library unportable, would require a separate compilation depending on the environment (x86, x64, Linux, iOS), otherwise it would work anywhere.

Groucho2004
7th June 2018, 21:52
I'm talking about practical programming on non-compliant MS stuff; you're talking about theoretical standards. But that's irrelevant here.
This was your statement which is simply wrong, there's no dancing around it:
Unicode is 2-byte per char, UTF8 is either 1 or 2 bytes per char.


As for a wrapper - Megui has a C# wrapper around the Avisynth C API. Not sure if it's useful but have a look:
https://sourceforge.net/p/megui/code/?source=navbar

MysteryX
7th June 2018, 23:03
I think the simplest method is to create a C++ project with a single file that looks like this and repeat for every function.

It looks good or anything I'm missing?

#include <VapourSynth.h>

VS_API(VSCore*) vsapi_createCore(VSAPI* api, int threads) VS_NOEXCEPT;
VSCore* VS_CC vsapi_createCore(VSAPI* api, int threads) VS_NOEXCEPT {
return api->createCore(threads);
}

VS_API(void) vsapi_freeCore(VSAPI* api, VSCore *core) VS_NOEXCEPT;
void VS_CC vsapi_freeCore(VSAPI* api, VSCore *core) VS_NOEXCEPT {
return api->freeCore(core);
}


It compiles but gives a warning for each: "inconsistent dll linkage"

foxyshadis
8th June 2018, 04:40
I think the simplest method is to create a C++ project with a single file that looks like this and repeat for every function.

It looks good or anything I'm missing?

#include <VapourSynth.h>

VS_API(VSCore*) vsapi_createCore(VSAPI* api, int threads) VS_NOEXCEPT;
VSCore* VS_CC vsapi_createCore(VSAPI* api, int threads) VS_NOEXCEPT {
return api->createCore(threads);
}

VS_API(void) vsapi_freeCore(VSAPI* api, VSCore *core) VS_NOEXCEPT;
void VS_CC vsapi_freeCore(VSAPI* api, VSCore *core) VS_NOEXCEPT {
return api->freeCore(core);
}


It compiles but gives a warning for each: "inconsistent dll linkage"

My psychic senses tell me you're compiling 32-bit. In 64-bit, VS_CC means nothing, but in 32-bit, it means __stdcall. (Where default is usually __cdecl unless you explicitly change it in the project settings.) Just add VS_CC to both halves if you want it and need the definition, like in a header.

In other news: Sheesh, is everyone really this grumpy that someone wants to make a C# binding library and wants help with the C/C++ side?

MysteryX
8th June 2018, 06:07
Because the signature is inconsistent between your function declaration and function definition. I think the function declarations are quite redundant here. You could simply define the functions without the declarations existing. And you should use VS_EXTERNAL_API instead of VS_API to export your wrapper functions.
Changing VS_API to VS_EXTERNAL_API removed all warnings.

It's now working :D In x64. If I compile in x86 I still get a whole bunch of compilation errors.

Question: what is a node, exactly?

According to the documentation

struct VSNode
Not really interesting.


The errors I get in x86

VS_EXTERNAL_API (const VSCoreInfo*) vsapi_getCoreInfo(VSAPI* api, VSCore *core) VS_NOEXCEPT;
const VS_CC VSCoreInfo* vsapi_getCoreInfo(VSAPI* api, VSCore *core) VS_NOEXCEPT {
return api->getCoreInfo(core);
}

Error: variable "VSCoreInfo" is not a type name
Error: explicit type is missing ('int' assumed)
Error: expected a ';'

MysteryX
8th June 2018, 06:28
Ah this is beautiful, can access output data with this using this wrapper, and it handles errors correctly. I love simple code.

try {
// Initialize script.
VsScriptApi.SetDllPath(@"C:\Program Files (x86)\VapourSynth\core64");
VsScriptApi ScriptApi = VsScriptApi.LoadFile(@"C:\GitHub\VapourSynth Viewer .NET\test.vpy", true);
VsOutput Api = ScriptApi.GetOutput(0);
VsVideoInfo Vi = Api.GetVideoInfo();
VsFormat Format = Vi.Format;

// Get all frames.
for (int i = 0; i < Vi.NumFrames; i++) {
VsFrame Frame = Api.GetFrame(i);

for (int p = 0; p < Format.NumPlanes; p++) {
VsPlane Plane = Frame.GetPlane(p);
int RowSize = Plane.Width * Format.BytesPerSample;
int Stride = Plane.Stride;

for (int y = 0; y < Plane.Height; y++) {
// ...
}
}
}
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}

TheFluff
8th June 2018, 11:23
I really don't think you need a C++ wrapper to get at the functions inside struct VSAPI. The StackOverflow question you linked deals with C++ code where struct is actually a class in disguise. If you do want a C++ wrapper that is actually idiomatic C++, twc's vsxx (https://github.com/sekrit-twc/vsxx/blob/master/VapourSynth%2B%2B.hpp) wrapper is that, but in this case I don't think it's that useful.

What you have in struct VSAPI is a bunch of function pointers, and I'm certain you can call those from C#. Without knowing more than a few minutes of Googling gave me, I think what you need to do is first retrieve the struct itself, and then handle the function pointers with delegation or marshaling or something. This stackoverflow question (https://stackoverflow.com/questions/1969049/c-sharp-p-invoke-marshalling-structures-containing-function-pointers) seems to have decent example code that does something very similar to what's going on in the VS API.

Question: what is a node, exactly?

It's the equivalent of a clip in Avisynth parlance. It represents the end of a chain of filter functions. Pass it to the various getFrame functions to get VS to deliver frames from that filter chain to you.

In other news: Sheesh, is everyone really this grumpy that someone wants to make a C# binding library and wants help with the C/C++ side?

Asking good questions goes a long way towards getting good answers. We've made progress though, now we're actually getting practical questions rather than ones like "what is the VS API like".

MysteryX
8th June 2018, 16:26
I really don't think you need a C++ wrapper to get at the functions inside struct VSAPI. The StackOverflow question you linked deals with C++ code where struct is actually a class in disguise. If you do want a C++ wrapper that is actually idiomatic C++, twc's vsxx (https://github.com/sekrit-twc/vsxx/blob/master/VapourSynth%2B%2B.hpp) wrapper is that, but in this case I don't think it's that useful.
Great it's working now, without a C++ wrapper. Thanks.

What you have in struct VSAPI is a bunch of function pointers
I'm learning something new, I was wondering why all the functions started with *

I could try to guess this one but would rather get a clear answer. When getting and releasing nodes, what is index for? Is it always 0, or if I load several scripts within the same process, do I need to assign this manually to unique numbers? Can I specify any number as long as I release that same index later?

MysteryX
8th June 2018, 18:24
I'm successfully displaying a black/white clip of a script in .NET :D

The next part is how to reliably convert it to RGB format.

video.resize.Bicubic(format=vs.COMPATBGR32)

If I insert that at the end of the script, I have no way of knowing the right syntax to use as both vs and video can be not defined.

Also if I insert that line in the script it throws this error:

Resize error: Resize error 3074: no path between colorspaces (2/2/2 => 0/2/2). May need to specify additional colorspace parameters.

jackoneill
8th June 2018, 19:01
The "index" parameter passed to set_output() and get_output() can be used to export multiple video nodes from one script. If you're only dealing with scripts written by other people, you only need to retrieve index=0. Assuming they're scripts meant to be passed to vspipe eventually.

(As an example of using indexes other than 0, in Wobbly I use index=1 to store the source filter's node, to avoid recreating it when the user changes something in the filter chain. The user doesn't directly write the Python script. The script is assembled by my program.)

You can append the conversion to any random script like this:

import vapoursynth as mystery_vs # You can import it again

mystery_node = mystery_vs.get_output(index=0)

mystery_format = mystery_node.format

mystery_params = { "format": mystery_vs.COMPATBGR32 }

if mystery_format is None or (mystery_format.color_family != mystery_vs.RGB and mystery_format.id != mystery_vs.COMPATBGR32)
mystery_params["matrix_in_s"] = "709"

mystery_node = mystery_node.resize.Bicubic(mystery_params)
mystery_node.set_output()

100% untested code.

MysteryX
8th June 2018, 19:28
I still haven't written any script and don't know much of the synatx at all.

The "if" line is missing ':' at the end and there's some other syntax error in it. Then it also gives error "Python exception: invalid literal for int() with base 10: 'format'"

TheFluff
8th June 2018, 21:52
Second to last line should probably be
mystery_node.resize.Bicubic(**mystery_params)

The double splat operator, **, lets you take a dictionary and pass its contents as named arguments to a function - the keys in the dict become argument names and the values become the actual arguments. The single splat, *, does the same thing for lists and positional arguments. So, for example


named_params = {
"arg1": False,
"arg2": 5,
}
ret = func(**named_params) # same thing as func(arg1=False, arg2=5)

positional_params = [True, 10]
ret2 = func2(*positional_params) # same thing as func2(True, 10)

MysteryX
8th June 2018, 21:55
This line works to convert but displays up-side-down, so I also need to flip vertically.

video = video.resize.Bicubic(format=vs.COMPATBGR32, matrix_in_s="709")


I can generate additional script programmatically so the conditions and check will be done my side before generating the script.

What happens if I specify matrix_in_s and it is already specified on the clip? Do I have to check it's not specified before specifying it?

And I suppose I should use 603 when height <= 480 and 709 when height > 709, or there's a better standard to determine the default?

What I don't like about this extra script is that it's a bit hacky, and can potentially fail if the chosen names are already used in the script.

MysteryX
8th June 2018, 22:39
oh you're right the conditions need to be set in the script because I append this before even loading the script. Only condition missing is checking for 609 or 703 as defaults.

MysteryX
8th June 2018, 22:55
Appending this at the end works and seems good enough; with the option of specifying the matrix manually.

import vapoursynth as viewernet_vs
viewernet_node = viewernet_vs.get_output(index=0)
viewernet_format = viewernet_node.format
viewernet_params = { "format": viewernet_vs.COMPATBGR32 }
if viewernet_node.height <= 480:
viewernet_matrix = "603"
else:
viewernet_matrix = "709"
if viewernet_format is None or (viewernet_format.color_family != viewernet_vs.RGB and viewernet_format.id != viewernet_vs.COMPATBGR32):
viewernet_params["matrix_in_s"] = viewernet_matrix
viewernet_node = viewernet_node.resize.Bicubic(**viewernet_params)
viewernet_node = viewernet_node.std.FlipVertical()
viewernet_node.set_output()

Next thing I notice is that the script runs slowly and is only using 35% of the CPU. Do I have to turn on multithreading manually? I tried calling setThreadCount(8) and it doesn't seem to be working. Note that I have only ffm2 source in the script.

TheFluff
9th June 2018, 01:02
Unlike in Avisynth, the VS getFrame is asynchronous (well, there's a synchronous version in the API too but it's async internally). That is, you call getFrameAsync multiple times, it'll return immediately each time and then call your code back later when the frame is ready. You can therefore have multiple frame requests in flight at the same time. To take advantage of the VS multithreading as an API user, you need to exploit this and set up a frame request queue or something like that. Keep in mind though that if you do this you need to be thread-safe on the receiving end and that frames may arrive out of order. You can check what VSPipe does (https://github.com/vapoursynth/vapoursynth/blob/master/src/vspipe/vspipe.cpp) if you want somewhere to start - it takes care of all of this for normal end-users.

In Avisynth Prefetch kinda accomplishes the same thing as an async frame request queue, but in a far clumsier and less efficient way because it has to be shoehorned into the synchronous API.

MysteryX
9th June 2018, 02:21
Thanks, very useful explanation. Should be easy enough to implement in .NET, it makes multi-threading very easy.

MysteryX
9th June 2018, 06:58
Now it's working in MT ... BUT, it takes a ridiculous amount of memory and fills up 8GB within seconds.

After calling getFrameAsync, are there other functions to call to release resources while processing?

jackoneill
9th June 2018, 11:39
I guess you're not freeing the frames after you're done using them.

MysteryX
9th June 2018, 17:52
I guess you're not freeing the frames after you're done using them.
Was searching "release" in the API and couldn't find anything but freeFrame does the job thanks.

MT is working. I'm calling SetThreadCount(8) send 8 frame requests, and each time a frame is done I add a new one into the queue. Now the CPU still runs only at 40%.

When I call GetFrameAsync on my class, it returns the frames in the same order they were requested so that's working very well.

jackoneill
9th June 2018, 21:40
Is your script complex enough to fully use the CPU?

There is no guarantee you will receive the frames in order. You have to handle reordering them.

MysteryX
10th June 2018, 00:57
Code is already written to reorder them. My VsOutput class raises 2 events: FrameDone (when frame is processed, to insert new request into the queue) and FrameReady (for display, guaranteed to be in right order). That's working well.

I see that if I skip display code, it runs MUCH faster; but still, it only runs at 40% CPU. There's only FFM2 in the script so far, maybe it's not designed to run faster than that.

foxyshadis
10th June 2018, 05:39
With only reading or writing plugins, you're probably I/O bound more than anything.

amayra
12th June 2018, 04:21
just out of curiosity what is your goals with this ?

MysteryX
12th June 2018, 20:42
Looking to replace Avisynth with VapourSynth in my Yin Media Encoder that goes with the Natural Grounding Player for video processing, and use Avisynth only for audio processing.

Could also add nice features like previewing various versions of a script side-by-side by switching tabs, zooming in, and seeking/scrolling simultaneously in all tabs. This would be better than simply opening up a script in MPC-HC.

I'm also switching into using MPV via dll instead of Windows Media Player for audio and video playback; working on an UI right now because all these alternative media players have no decent UI.

foxyshadis
13th June 2018, 07:46
What holds you back from VS audio processing?