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 22nd January 2021, 06:28   #4161  |  Link
foxyshadis
ангел смерти
 
foxyshadis's Avatar
 
Join Date: Nov 2004
Location: Lost
Posts: 9,558
Quote:
Originally Posted by feisty2 View Post
it's nobody's problem, msvc is well known to be slow on supporting new C++ features (it's also not the worst tho, apple clang is far worse than msvc in terms of C++20 support). things will get there eventually. the main problem with msvc currently is that it does not provide complete support for concepts, a major C++20 feature that the wrapper relies on heavily.
You have to be kidding me, right? This is a bleeding edge GCC 10 feature. You need an Ubuntu line less than six months old to be able to use that, no 20.04 or LTS for you. There's still no RHEL/CentOS that has gcc10. You literally have to reinstall your entire OS to be able to build this, or have a dev environment just for it.

You're intentionally cutting your userbase off in order to experiment with bleeding edge features, which is fine in the abstract, but marks the project as unsuitable for anyone else.
foxyshadis is offline   Reply With Quote
Old 22nd January 2021, 11:22   #4162  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
the latest version of all 3 mainstream compilers (GCC, Clang, MSVC) have supported many C++20 features, both GCC and Clang have implemented full support for concepts, and MSVC has partial support for it. I can imagine that MSVC should be able to catch up in the following months and my project should work with all mainstream compilers by the time I finish writing the documentation. CentOS is dead so not supporting it is no big deal, regardless of that, GCC is capable of bootstrapping, just download the source code of the latest version and build it with whatever version you already have, you certainly don't need to reinstall your OS to run the latest version of GCC. what's the point really to use Linux if you can't even compile GCC from scratch...

concepts is a must-have in order to design a flexible interface in C++, it is by far the only facility to express type-level equivariance in C++, take the following polymorphic function f() for example:
Code:
auto f(auto&& x) {
    if constexpr (requires { { x.g() }->Iterable; })
        if constexpr (requires { { *x.g().begin() }->SubtypeOf<VideoInfo>; })
            return std::vector<VideoNode>{};
        else if constexpr (requires { { *x.g().begin() }->SubtypeOf<AudioInfo>; })
            return std::vector<AudioNode>{};
        else
            static_assert(AlwaysFalse<decltype(x)>, "Type Error!");
    else if constexpr (requires { { x.g() }->SubtypeOf<VideoInfo>; })
        return VideoNode{};
    else if constexpr (requires { { x.g() }->SubtypeOf<AudioInfo>; })
        return AudioNode{};
    else
        static_assert(AlwaysFalse<decltype(x)>, "Type Error!");
}
the "if constexpr (requires { ... })" construct defines an equivariant map from the return type of x.g() to the return type of f(), and therefore extends polymorphism to the type level for f(). As a result, the user defined function x.g() no longer needs to be constrained by an invariant interface. the user is allowed to define g() however he/she likes at the type level, whatever works the best for his/her particular use case, and the framework function f() always self-adapts to whatever the user wants.

you simply cannot write such f() without concepts. you can try mimicking it using SFINAE in older versions of C++ and I guarantee that your code will be an unreadable and unmaintainable mess in no time. therefore concepts is absolutely essential if you agree that the user's freewill matters.

edit: simple proof that shows f() is indeed equivariant at the type level for types that it can handle.
let F() denote f() at the type level, [] denote a type operator that transforms any type T to std::vector<T>.

we have that:
F([VideoInfo]) = [VideoNode]
[F(VideoInfo)] = [VideoNode]
F([AudioInfo]) = [AudioNode]
[F(AudioInfo)] = [AudioNode]

therefore F() satisfies F(G∙T) = G∙F(T), where G = [], T = VideoInfo, AudioInfo.

Last edited by feisty2; 22nd January 2021 at 13:47.
feisty2 is offline   Reply With Quote
Old 22nd January 2021, 20:09   #4163  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
Not that is important, but tried to subclass videonode, if for example could use custom attributes like clip.rgb, clip.isError etc:
Code:
class My_videonode(vs.VideoNode):
    def __init__(self, clip, *args, **kwargs):
        super(My_videonode, self).__init__(*args,**kwargs)

my_videonode = My_videonode(clip1)
got error, vapoursynth.Error: Class cannot be instantiated directly,
from here:
https://github.com/vapoursynth/vapou...synth.pyx#L954

is it possible, or is it stupid idea, it could be done differently sure, or forget it?
_Al_ is offline   Reply With Quote
Old 22nd January 2021, 20:13   #4164  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
use VaporMagik, it allows you to do dangerous things to native extensions, not just VideoNode, you can even modify the behavior of built-in types like list or int
feisty2 is offline   Reply With Quote
Old 22nd January 2021, 21:41   #4165  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
thank you,
I think I saw it before, really advanced script for me, thinking what it would be good for :-) . I tried to butcher it a bit and came up with this, which works. So I might use it. Interesting. I realized also I could also use collections.namedtuple lib, not sure how I would implement it yet. But your VaporMagik seams to be fun:
Code:
import ctypes
import builtins

class PyObject(ctypes.Structure):
    pass

PyObject._fields_ = [
    ('ob_refcnt', ctypes.c_ssize_t),
    ('ob_type', ctypes.POINTER(PyObject)),
]

class NativeMappingProxy(PyObject):
    _fields_ = [('UnderlyingDictionary', ctypes.POINTER(PyObject))]

def Dereference(Pointer):
    ObjectHolder = []
    ctypes.pythonapi.PyList_Append(ctypes.py_object(ObjectHolder), Pointer)
    return ObjectHolder[0]
    
def ExposeAttributeDictionary(Type):
    AttributeMaps = Type.__dict__
    TransparentAttributeMaps = NativeMappingProxy.from_address(id(AttributeMaps))
    return Dereference(TransparentAttributeMaps.UnderlyingDictionary)

def SetTypeAttribute(Type, Name, Attribute):
    AttributeDictionary = ExposeAttributeDictionary(Type)
    AttributeDictionary[Name] = Attribute
    ctypes.pythonapi.PyType_Modified(ctypes.py_object(Type))

@property
def rgb(self):
    return self.resize.Bicubic(format=vs.RGB24)

SetTypeAttribute(vs.VideoNode, 'rgb', rgb)


clip = core.avisource.AVISource(file.avi)
print(clip)
print(clip.rgb)

Last edited by _Al_; 22nd January 2021 at 21:45.
_Al_ is offline   Reply With Quote
Old 22nd January 2021, 22:15   #4166  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
is it possible using VaporMagik to do get things out of tuple to atribute:
Code:
@property
def rgb(self):
    #action of converting
    return rgb_clip, isError, log  #returned is vs.VideoNode, bool and string

#something:
SetTypeAttribute(vs.VideoNode, 'rgb', rgb)

clip = core.avisource.AVISource(file.avi)
print(clip)
print(clip.rgb)
print(clip.isError)
print(clip.log)
#or maybe better
print(clip.rgb)
print(clip.rgb.isError)
print(clip.rgb.log)
#or
print(clip.rgb[0], clip.rgb[1], clip.rgb[2])
_Al_ is offline   Reply With Quote
Old 23rd January 2021, 07:20   #4167  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
I don't see why you'd think that you cannot do that, although what you're trying to do doesn't seem elegant to me.
feisty2 is offline   Reply With Quote
Old 23rd January 2021, 09:00   #4168  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
ok, I got that, thanks, but then I could not figure out how to have array/list of clips done by that, that code is too much for me, I settled with something like this at the end:
Code:
import vapoursynth as vs
from vapoursynth import core
import collections

class Clips(list):    
    def __init__(self, inputs):
        list.__init__(self,[])
        
        self.Clip_data = collections.namedtuple('Clip_data', ['clip','rgb','isError','log','output_index'])

        if isinstance(inputs, type(vs.get_outputs())):
            inputs = [ (clip, output_index) for output_index, clip in inputs.items()]
                                         
        elif isinstance(inputs, list):
            inputs = [ (clip, None) for clip in inputs]
        else:
            raise ValueError('wrong input')
        for clip, output_index in inputs:
            self.append(self.set(clip, output_index))
 
    def set(self, clip, output_index=None):
        rgb, isError, log = self.toRGB(clip)
        #other work
        return self.Clip_data(clip=clip, rgb=rgb, isError=isError, log=log, output_index=output_index)
        
    def replace(self, index, clip, output_index=None):
        self[index] = self.set(clip, output_index)

    def appending(self, clip, output_index=None):
        self.append(self.set(clip, output_index))
        
    def toRGB(self, c):
        #conversion to rgb, mocking a return for show
        return core.resize.Bicubic(c, matrix_in_s='170m',format=vs.RGB24), False, 'this is a conversion log'
    
vs.clear_outputs()
clip = core.std.BlankClip(format=vs.YUV420P8)
clip.set_output(0)

bright = clip.std.Expr(['x 40 +','',''])
bright.set_output(1)

clips = Clips([clip, bright])
##clips = Clips(vs.get_outputs())

print(clips[0].clip)
print(clips[0].rgb)
print(clips[0].log)
print(clips[1].clip)
#...

#replacing clip on index 1
brightest = clip.std.Expr(['x 100 +','',''])
clips.replace(1, brightest)

#apending clip
clip = core.std.BlankClip(color=(255,0,0)).resize.Point(matrix_s='170m',format=vs.YUV420P8)
clips.appending(clip)
_Al_ is offline   Reply With Quote
Old 23rd January 2021, 12:39   #4169  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
Quote:
Originally Posted by _Al_ View Post
but then I could not figure out how to have array/list of clips done by that
obviously, you need to inject your custom attributes into the built-in list type. use the @Inject decorator provided by VaporMagik

Code:
@Inject
def f(self: list):
    for x in self:
        print(x)

[1, 2, 3, 4].f() # prints "1 2 3 4"

Last edited by feisty2; 23rd January 2021 at 12:42.
feisty2 is offline   Reply With Quote
Old 25th January 2021, 23:20   #4170  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
ok thanks, I used dataclass at the end, same syntax as namedtuple, I understand it, and it can assign and change attributes directly (namedtuple has awkward syntax). Not saying that VaporMagik cannot do that, most likely yes.
_Al_ is offline   Reply With Quote
Old 27th January 2021, 07:12   #4171  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
@Myrsloik
could you explain how getFrame() is invoked with different activation reasons, particularly the case involving arAllFramesReady && !*frameData? it seems getFrame() might be invoked twice with the same activation reason, what happens after getFrame() exits from the arAllFramesReady && !*frameData branch and before it gets invoked again? if several frames (either from the same node or from several nodes) are requested in the arAllFramesReady && !*frameData branch, is it guaranteed that all requested frames are ready before the next call to getFrame()?

there seems to be 4 types of filters with different getFrame() skeletons:

standard filters
arInitial -> RequestReferenceFrames()
arAllFramesReady -> DrawFrame()

source filters
arInitial -> DrawFrame()

special filters (e.g. std.FrameEval)
arInitial -> RequestReferenceFrames()
arAllFramesReady && !*frameData -> RequestSpecialResources()
arAllFramesReady -> DrawFrame()

special(or weird?) source filters
arInitial && !*frameData -> RequestSpecialResources()
arInitial -> DrawFrame()

any other possibilities? also is it possible to get a concrete error message if the arError branch is activated?
feisty2 is offline   Reply With Quote
Old 27th January 2021, 11:09   #4172  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,548
Quote:
Originally Posted by feisty2 View Post
@Myrsloik
could you explain how getFrame() is invoked with different activation reasons, particularly the case involving arAllFramesReady && !*frameData? it seems getFrame() might be invoked twice with the same activation reason, what happens after getFrame() exits from the arAllFramesReady && !*frameData branch and before it gets invoked again? if several frames (either from the same node or from several nodes) are requested in the arAllFramesReady && !*frameData branch, is it guaranteed that all requested frames are ready before the next call to getFrame()?

there seems to be 4 types of filters with different getFrame() skeletons:

standard filters
arInitial -> RequestReferenceFrames()
arAllFramesReady -> DrawFrame()

source filters
arInitial -> DrawFrame()

special filters (e.g. std.FrameEval)
arInitial -> RequestReferenceFrames()
arAllFramesReady && !*frameData -> RequestSpecialResources()
arAllFramesReady -> DrawFrame()

special(or weird?) source filters
arInitial && !*frameData -> RequestSpecialResources()
arInitial -> DrawFrame()

any other possibilities? also is it possible to get a concrete error message if the arError branch is activated?
That's more or less the existing cases. Rule is very simple (ignore arFrameReady since it's effectively deprecated):

At the end of each invocation either an output frame must be returned OR there must be outstanding frame requests (requestFrameFilter).

First call is always arInitial to make things clear.
Once all requested frames are available arAllFramesReady is called.
You're allowed to request additional frames in arAllFramesReady which will then result in getting called with arAllFramesReady again and you can repeat this as many times as you like.
Errors may be propagated from other filters at any time after the arInitial call and then it's not the filter's job to handle it, only to clean up any allocated resources and return nothing. The error message is always propagated to the original requester to display. (As in whoever called getFrame/getFrameAsync)

Your last weird example is obviously invalid since it'll have outstanding frame requests when returning an output frame.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is online now   Reply With Quote
Old 27th January 2021, 12:51   #4173  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
Quote:
Your last weird example is obviously invalid since it'll have outstanding frame requests when returning an output frame.
that's good to know. then apparently the last weird case and the standard case could be unified by generalizing RequestReferenceFrames() to RequestResources()

Code:
if (activationReason == arInitial)
    if constexpr (requires { { filter->RequestResources() }->AnyBut<void>; })
        *frameData = new auto{ filter->RequestResources() };
    else if constexpr (requires { filter->RequestResources(); }) // fails to satisfy AnyBut<void>, therefore returns void, equivalent to RequestReferenceFrames()
        filter->RequestResources();
    else if constexpr (requires { { filter->DrawFrame() }->SubtypeOf<FrameReference>; }) // source filter
        return filter->DrawFrame().Leak();
    else
        static_assert(AlwaysFalse<decltype(filter)>, "missing attribute!");
feisty2 is offline   Reply With Quote
Old 28th January 2021, 07:49   #4174  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
what happens if there's no frame requested or generated in the arInitial branch (empty branch)? it might happen in rare cases like the following
Code:
if (activationReason == arInitial)
    for (auto& node : inputs) // inputs might be an empty container depending on the user input
        node.RequestFrame(n, FrameContext);
will getFrame() still be invoked with arAllFramesReady later on?
feisty2 is offline   Reply With Quote
Old 28th January 2021, 09:59   #4175  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,548
Quote:
Originally Posted by feisty2 View Post
what happens if there's no frame requested or generated in the arInitial branch (empty branch)? it might happen in rare cases like the following
Code:
if (activationReason == arInitial)
    for (auto& node : inputs) // inputs might be an empty container depending on the user input
        node.RequestFrame(n, FrameContext);
will getFrame() still be invoked with arAllFramesReady later on?
That's a fatal error since you either must have outstanding requests or return a frame.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is online now   Reply With Quote
Old 1st February 2021, 04:39   #4176  |  Link
lansing
Registered User
 
Join Date: Sep 2006
Posts: 1,657
How does the api getCoreInfo2() function works? It asks for the core and VSCoreInfo as parameters. But the only way to get the VSCoreInfo from the document is by using api->getCoreInfo(), but it also said that this function was deprecated.
lansing is offline   Reply With Quote
Old 1st February 2021, 06:15   #4177  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
Quote:
Originally Posted by lansing View Post
How does the api getCoreInfo2() function works? It asks for the core and VSCoreInfo as parameters. But the only way to get the VSCoreInfo from the document is by using api->getCoreInfo(), but it also said that this function was deprecated.
https://github.com/IFeelBloated/vsFi...de/Core.vxx#L9
feisty2 is offline   Reply With Quote
Old 1st February 2021, 06:43   #4178  |  Link
lansing
Registered User
 
Join Date: Sep 2006
Posts: 1,657
Quote:
Originally Posted by feisty2 View Post
Thanks I got it working. The naming is confusing, this is more like setCoreInfo rather than getCoreInfo
lansing is offline   Reply With Quote
Old 1st February 2021, 08:09   #4179  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
it's a common practice in C to return something via side effects (by manipulating global variables or modifying something from a foreign scope via pointers)
feisty2 is offline   Reply With Quote
Old 2nd February 2021, 01:46   #4180  |  Link
lansing
Registered User
 
Join Date: Sep 2006
Posts: 1,657
Can I retrieve the paths for the vs plugin folder and script folder through the api?
lansing is offline   Reply With Quote
Reply

Tags
speed, vaporware, vapoursynth

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 14:11.


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