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.

 

Go Back   Doom9's Forum > Capturing and Editing Video > VapourSynth

Reply
 
Thread Tools Search this Thread Display Modes
Old 1st June 2018, 01:53   #1  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
View VapourSynth Output in .NET

Is there a way to display the output of a VapourSynth script in a .NET application? What kind of API does VapourSynth expose?
MysteryX is offline   Reply With Quote
Old 1st June 2018, 03:48   #2  |  Link
TheFluff
Excessively jovial fellow
 
Join Date: Jun 2004
Location: rude
Posts: 1,073
read the fucking manual, 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.

Last edited by TheFluff; 1st June 2018 at 03:52.
TheFluff is offline   Reply With Quote
Old 1st June 2018, 16:41   #3  |  Link
amichaelt
Registered User
 
Join Date: Apr 2018
Posts: 63
Quote:
Originally Posted by MysteryX View Post
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.
__________________
My project BDSup2Sub++: https://github.com/amichaeltm/BDSup2SubPlusPlus
amichaelt is offline   Reply With Quote
Old 1st June 2018, 18:13   #4  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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.
MysteryX is offline   Reply With Quote
Old 1st June 2018, 18:20   #5  |  Link
amichaelt
Registered User
 
Join Date: Apr 2018
Posts: 63
Quote:
Originally Posted by MysteryX View Post
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...-using-pinvoke

Since you're dealing with a sane, C API it should be pretty straightforward.
__________________
My project BDSup2Sub++: https://github.com/amichaeltm/BDSup2SubPlusPlus
amichaelt is offline   Reply With Quote
Old 1st June 2018, 20:55   #6  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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?
MysteryX is offline   Reply With Quote
Old 1st June 2018, 21:43   #7  |  Link
amichaelt
Registered User
 
Join Date: Apr 2018
Posts: 63
Quote:
Originally Posted by MysteryX View Post
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:

Quote:
if you want to evaluate .vpy scripts, there's a separate api for that.
__________________
My project BDSup2Sub++: https://github.com/amichaeltm/BDSup2SubPlusPlus
amichaelt is offline   Reply With Quote
Old 2nd June 2018, 00:45   #8  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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
Quote:
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
Quote:
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.
MysteryX is offline   Reply With Quote
Old 2nd June 2018, 01:19   #9  |  Link
amichaelt
Registered User
 
Join Date: Apr 2018
Posts: 63
So then you have to use the core API as well:

Quote:
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:

Quote:
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:

Quote:
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.
__________________
My project BDSup2Sub++: https://github.com/amichaeltm/BDSup2SubPlusPlus

Last edited by amichaelt; 2nd June 2018 at 01:46.
amichaelt is offline   Reply With Quote
Old 2nd June 2018, 03:03   #10  |  Link
videoh
Registered User
 
Join Date: Jul 2014
Posts: 840
Quote:
Originally Posted by MysteryX View Post
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/vapou...ript_example.c
videoh is offline   Reply With Quote
Old 2nd June 2018, 03:14   #11  |  Link
amayra
Quality Checker
 
amayra's Avatar
 
Join Date: Aug 2013
Posts: 227
Quote:
Originally Posted by MysteryX View Post
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
__________________
I love Doom9
amayra is offline   Reply With Quote
Old 2nd June 2018, 03:56   #12  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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.
MysteryX is offline   Reply With Quote
Old 2nd June 2018, 07:47   #13  |  Link
TheFluff
Excessively jovial fellow
 
Join Date: Jun 2004
Location: rude
Posts: 1,073
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.
TheFluff is offline   Reply With Quote
Old 3rd June 2018, 19:57   #14  |  Link
foxyshadis
ангел смерти
 
foxyshadis's Avatar
 
Join Date: Nov 2004
Location: Lost
Posts: 9,413
Quote:
Originally Posted by TheFluff View Post
read the fucking manual, 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.
Hey, this isn't lkml, you know the minimal level of decorum we expect here. No need to spell out the abbreviation anyway.
__________________
There are four boxes to be used in defense of liberty: soap, ballot, jury, and ammo. Please use in that order.
foxyshadis is offline   Reply With Quote
Old 6th June 2018, 23:32   #15  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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/vapou...VSScript.h#L75

It returns a pointer to an object of type VSAPI. Which is a very complex object.
https://github.com/vapoursynth/vapou...urSynth.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
Code:
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
Code:
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!

Last edited by MysteryX; 7th June 2018 at 00:09.
MysteryX is offline   Reply With Quote
Old 7th June 2018, 00:02   #16  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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 is offline   Reply With Quote
Old 7th June 2018, 17:55   #17  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
OK. Several bad advice were given; and I'm encountering some issues.

Quote:
Originally Posted by TheFluff
read the fucking manual, it's a plain c api
It's not that simple.

Quote:
Originally Posted by amayra View Post
At least someone try to do it here
Yes thank you! Some great information in there.

Quote:
Originally Posted by captainadamo View Post
Or you could use a tool 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.

Quote:
Originally Posted by amichaelt View Post
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
Code:
[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?
Code:
[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.
Quote:
Originally Posted by jackoneill View Post
2. Everything's supposed to be UTF8, so that's how you should save your scripts too. It Just Works.

Last edited by MysteryX; 7th June 2018 at 19:33.
MysteryX is offline   Reply With Quote
Old 7th June 2018, 19:06   #18  |  Link
jackoneill
unsigned int
 
jackoneill's Avatar
 
Join Date: Oct 2012
Location: 🇪🇺
Posts: 723
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).
__________________
Buy me a "coffee" and/or hire me to write code!
jackoneill is offline   Reply With Quote
Old 7th June 2018, 19:36   #19  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
Quote:
Originally Posted by jackoneill View Post
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/marsh...-it-ought.html
MysteryX is offline   Reply With Quote
Old 7th June 2018, 20:04   #20  |  Link
MysteryX
Soul Architect
 
MysteryX's Avatar
 
Join Date: Apr 2014
Posts: 2,170
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.
Code:
[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 is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 22:42.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.