View Full Version : 3.0 strikes back
Bidoche
5th November 2003, 17:35
After a while without committing anything, sourceforge has finally heard from me again.
So, what's up :
- Smart pointers are now defined in term of the boost::shared_ptr template.
It loses a bit speed-wise and memory-wise, but has other advantages like implicit upcasting, downcasting using a free method, and possibility to use the sister class boost::weak_ptr to break references cycles.
If you don't understand what I am talking about, don't worry those will be hidden behind the usual typedefs and you don't really need to know about. (But up/down casting abilities are nice to have)
- Worked on the Cache system : Cache are now embedded into clips, but only those that DO need to cache.
Proxies filter (like Trim) or minor adjustement filter (like AssumeFPS) don't need a Cache, so the point is to save those unneeded Caches.
This is achieved using Multiple Inheritance and a special clip base class named CachingClip, who is the only one to be able to have a Cache.
The only difference for filters implementers is that they have to choose between GenericVideoFilter and a couple others I made to derive from, and that they must override MakeFrame and not GetFrame if the superclass is actually caching.
(There are still issues to solve how Cache handles cache hints (now named CacheRequest and obligatory))
- Added a Simplify method to Clip whose aim is to simplify the filter chain.
Exemple, if you have this avs script : Avisource("toto.avi')
Trim(1, 10)
Trim(2, 5)You could have the same effect of the 2 Trims with only one : Trim(3, 6)
This method aims to do that kind of simplification on the fly on the filter chain.
I think it could help some huge/recursive scripts to avoid overflow and the like.
- I started converting filters, I have made Splice and UnalignedSplice (both absorbing childs of same type into their own child list), Trim is in progress... (not so simple due to Simplify method)
But there is so many of them and only one of me, so I could use some help on them.
Many are relatively easy to do, it's just takes time.
So, if you are interested, make yourself known.
That's all for now (will commit VideoFrame stuff soon).
mf
5th November 2003, 22:03
The simplify thing could be interesting for the huge scripted functions (littered with conditionals, intermediate clips and setting-checking output clip queues) that are getting more popular nowadays, if it could be made more advanced in a way. Maybe I can think of something. :)
Bidoche
5th November 2003, 23:40
Feel free to do so.
But you know, I think with the 3 simplications :
Trim(Trim(c)) -> Trim(c)
Splice(Splice(a, b), c) -> Splice(a, b, c)
Trim(Splice(a, b, c)) -> Splice(Trim(a), b, Trim(c))
We cover 90% of the actual cases. (Which doesn't mean we must overlook others)
Bidoche
6th November 2003, 14:23
Another possible application, which I didn't think about firsthand, of this Simplify method may to introduce instances folding for appropriate filters.
Example to explain what is instances folding with KillAudio :
Considering the following pseudo-codea = ... //a clip
b = FreezeFrame(a) //resolves as Splice(Trim(a), Trim(a))
c = KillAudio(b)Assuming KillAudio simplications are: (which I am not sure are the right ones to do)
KillAudio(Trim(a)) -> Trim(KillAudio(a))
KillAudio(Splice(a,b)) -> Splice(KillAudio(a), KillAudio(b))You will end with this :
Splice(Trim(KillAudio(a)), Trim(KillAudio(a))
Where the two KillAudio, while having same child and rendering the same are different instances.
That's where instances folding may kick in, recognize 2nd instance as a dupe of 1st and do the proper replacement.
The Simplify method might be the right place to do so (the alternative being factory method with private constructor, but it may prove less flexible in some cases), and I can probably come up with a (templated) clip superclass to automatize that.
That would be neat, no ?
Si
6th November 2003, 21:08
Is this simplifying really important/useful:)
Should it not be up to script writers to do the simplifing :)
regards
Simon
Bidoche
6th November 2003, 21:40
Simplifications are not often possible by script writers when functions, filters implemented in term of others come into play.
That's the same thing about the C++ optimizer, who knows better than you what is really happening.
The filter chain knows better about itself than the script writer will ever do.
As for usefulness, consider the case (from the Usage forum of a few days ago) of this guy who had many frames to replace by the next (because original damaged)
He was doing this using a DeleteFrame/DuplicateFrame combo.
Imagine there are 50 frames to fix that way.
Without simplification, DeleteFrame and DuplicateFrame both being implemented as Splice(Trim, Trim).
You end with a filter chain containing 300 filters and of depth 200
With simplification, all that is reduced to an unique Splice containing 101 Trims (50 of 1 frame, 51 others)
So a filter chain of 102 filters of depth 3.
And I am sure script writers can come up with more agressive case than that, especially when using recursivity.
There was some case of stack overflow in heavy recursive scripts, I think this may reduce them.
Si
6th November 2003, 22:42
Fair enough - looks well worth doing then :)
regards
Simon
Kurosu
7th November 2003, 08:30
Useless post ahead...
I won't be of much help here, both for time and ability reasons, but I'd like to cheer Bidoche on his work, as he got little support from us plugin writers.
Doing such an optimization is very usefull: check the .avs files produced by a tool like Yatta. In the end, some users could come up with dozens of trims...
mf
8th November 2003, 14:28
Originally posted by Bidoche
As for usefulness, consider the case (from the Usage forum of a few days ago) of this guy who had many frames to replace by the next (because original damaged)
He was doing this using a DeleteFrame/DuplicateFrame combo.
Imagine there are 50 frames to fix that way.
wc -l tells me I now have 273 replace with next / replace with previous lines. :D And I'm not done.
Bidoche
11th November 2003, 10:49
I came up with a generic Simplify framework for all filters with one child.
I made a generic clip superclass for instance folding too.
This will greatly speed up the writing of those methods.
That would make Trim is complete once this design decision is answered :
Should it fill up audio to A/V synch when audio samples lack, or just let it be ?
stickboy
11th November 2003, 11:50
Isn't that the responsibility of AlignedSplice?
If Trim filled up missing audio samples, would UnalignedSplice still work?
Bidoche
11th November 2003, 12:01
AlignedSplice does that, yes.
UnalignedSplice would have same effect as Splice if childs are Trims.
But you are right, this could be done by Splice(clip) (Yes you can have a Splice with only one child (even 0 :p))
vion11
11th November 2003, 12:47
I anticipate an intelligent method to simplify the filter chain.
Will it have impact on functions like this:
Function BlurMore (clip c , int nTimes )
{return ( nTimes == 0 ? c : BlurMore (Blur(c, 1), nTimes - 1))}
Otherwise It would help developers to save memory and time,
if the chain complexity is perceivable in a readable style.
For example something like this:
  avisource       avisource
     |               |
ConverttoRGB32 ConverttoRGB32
     |               |
     -----------------
         Layer
           |
       KillAudio
           |
        Output
If I would get in touch with the chain, without learning c,
I'd like to think about a basic chain2html renderer
Bidoche
11th November 2003, 19:04
If there is a simplification for Blur(Blur(clip, a), b), then the whole will collapse... But is there ?
All the filters I made so far (and future ones will have too) have methods so their childs can be examined.
But that won't help getting their names... :/
vion11
12th November 2003, 11:55
It seams there is no simple solution available. I'll throw some facts
intended to get falsified to engross my understanding.
There is no meta-object controlling the chain and
knows about amount of input filter, count of filters,
performance of filters, errors happen and useless filter.
The chain engine was latest touched from BRG.
The filters in a chain don't know their names.
The filters don't know their successors and predecessors.
If the same filter is twice or more one after the other (has Childs)
it is up to the filter to recognize and optimize.
It is hard to explain, whats missing. Actually I'm dreaming
to mix the advantages of two applications, Avisynth and Visualjockey.
VisualJockey has a great interface but lacks scripting.
Avisynth has perfect scripting solution but lacks the interface.
Both manipulate Pixel and generate Avis.
Unfortunately vJo is commercial so code exchange is not an option.
But may be a look at the interface will explain what I'm trying
to suggest.Screenshot (http://www.visualjockey.com/software/software_description.page.php)
What must be done to get a Chain2Html renderer running?
Bidoche
12th November 2003, 12:28
There is no meta-object controlling the chain and
knows about amount of input filter, count of filters,
performance of filters, errors happen and useless filter.
Right, there is no such thing.
But if you have ideas to develop further, I am listening.
The chain engine was latest touched from BRG.Depends what you call the chain engine.
The filters in a chain don't know their names.There is no reflexivity in C++, so classes don't know about themselves.
But maybe I spoke too fast, RTTI (Real Time Type Id) may be able to get the filter names.
The filters don't know their successors and predecessors.They know their childs, which in my mind would be their predecessors (created before).
If the same filter is twice or more one after the other (has Childs) !?? I don't understand.
What must be done to get a Chain2Html renderer running?
- Interface natively with avisynth
- try casting clips to the different possibilities in childs
- Maybe unrealistic for 2.5 since there is many many cases, the simpler would be to add a GetChilds() method to IClip..
- Not a problem for 3.0 : only 4 cases so far
- 0 child : inherits SourceClip
- 1 child : inherits ChildClip
- 2 childs : inherits TwoChildsClip
- many : only AbstractSplice
- use keyword typeof and type_info to get classes names
- think to use operator== to recognize identical clips
- make the html
vion11
12th November 2003, 18:07
OK, very slowly I get a clue. Lets define some things.
Filter: a piece of software, moves frames to other filter on request,
knows about output and input format (width/height/Colors),
current frame number, has access to all and only frames of his
predecessors, can manipulate frames.
Questions: Who tolds the filter current frame number? Are filter objects with methods?
Chain engine: Reads the script, evaluates the math and string stuff,
builds the graph of filters, is connected to windows to answer requests on frames,
is defined from output to input, so AviSource cannot have childs.
Questions: If I write a script like:
Version(1)
Lanczosresize(100,100)
Who puts the error message in?
Why LanczosResize doesn't work on this error clip?
Whats happening with conditional filters?
-------
Isn't a high level (COM) interface possible?
Set mySynthesizer = CreateObject("AVISynth")
ErrorCount = mySynthesizer.Load("c:\test.avs")
Filter = mySynthesizer.Root
With a set of methods like:
   FirstChild, Parent, Next -> return filterObjects
   FilterName (r/w), params (r/w), CountChildren (r)
a lot of things can be done easily
and keeps door open to manipulate
filterchain on the fly inside applications.
With mySynthesizer.Bitblt (framenum, hDestDC, x, y.......)
video editing would be a pleasure.
How many lines of code are between native and COM?
Bidoche
12th November 2003, 19:35
Two (connected) definitions of Filter actually cohabits :
It can be the avisynth command you call, or the C++ class who do the field job.
Here is the (relevant part of) definition of the 3.0 Clip class :class Clip
{
public: //clip general interface
//get info about the clip
virtual const VideoInfo& GetVideoInfo() const = 0;
//get the frame n
//undefined behavior if frame n don't exist
virtual CPVideoFrame GetFrame(int n, const CachingClip& client) const = 0;
//fill the passed buffer with audio samples
//out of bounds values are allowed, the excess is filled with blank noise
virtual void GetAudio(BYTE * buf, __int64 start, __int64 count) const = 0;
};All filters are Clip subclasses, having (eventually) its own childs, processing data it gets from them, or just forwarding it...
Each filter works only on request from its successor, until it comes from the final renderer.
Chain engine: Reads the script, evaluates the math and string stuff,
builds the graph of filtersOn 2.5, this is done by an interpreter.
On 3.0, I intend to have the script compiled into an expression graph whose evaluates into the filter chain.
is connected to windows to answer requests on framesThe connection to Windows is done by an implementation of the VFW IAVIFile COM interface who translates VFW requests to the root Clip.
Version(1)
Lanczosresize(100,100)
Who puts the error message in? [quote]On 2.X, I am not sure, it may be the interpreter or Version::Create.
On 3.0, the compiler would complain it cannot find a Version(int) function.
[quote]Why LanczosResize doesn't work on this error clip?Evaluation is stopped by the error, it switchs to render to error msg.
Isn't a high level (COM) interface possible?It is possible, but I am not the one writing it... (not before a long time...)
How many lines of code are between native and COM?Probably too much, but it all depends on all close you want to be of filters.
It shouldn't be too much to make wrappers for base classes, but for all...
vion11
12th November 2003, 21:04
I've opend avisynth.dll in depedency walker.
As far I understand it exports some functions like
  avs_create_script_environment
  avs_release_clip
  avs_check_version
Can I do something useful with this functions like I do with:
  Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA"
  (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
If yes, should I go deeper into 2.5 or better wait for 3.0?
If no, can useful functions be added before a long time ;-)
Bidoche
12th November 2003, 21:49
You can do (almost) everything once you get one script_environment, it has methods to parse a script, build a chain filter by filter...
Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA"
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongAnd now that's me who don't understand. Is that some king of IDL ?
If yes, should I go deeper into 2.5 or better wait for 3.0?3.0 is not coming soon, but in the other hand 2.5 code is ugly...
If no, can useful functions be added before a long time ;-)I won't touch on 2.5, but if it's just add "virtual vector<PClip> GetChilds() const" on each filter, you can probably do it yourself.
vion11
12th November 2003, 23:03
Can you explain the following line in simple words, please.
  AVS_ScriptEnvironment * avs_create_script_environment(int version);
What kind of data structure is AVS_ScriptEnvironment?
Where is it defined?
What does that "*" means?
Why version informations is needed to create an environment?
Is it correct, the stuff defined in avisynth_c.h helps me
to create my own filter chains, but does not allow to connect
to an existing/runing ones?
If yes, how an enviroment can be used from a player or VDub?
The "Private Declare Function SendMessage...." statement
is the way you can use functions in external DLLs from Visual Basic
and other languages. Kind of wrapper for Windows API. What is IDL?
I'm sorry, next language to learn on my never ending
list is french. C is nearly at the end.
I'm sure, I'll need years to install a compiler.
When I think of compiler options and read the posts
starting with "Help, XXX will not compile" I feel respect
for people dealing with.
Adding "virtual vector<PClip> GetChilds() const"
sounds like kisuaheli for me. ;-)
Bidoche
13th November 2003, 14:45
AVS_ScriptEnvironment * avs_create_script_environment(int version);declares a (free) function named avs_create_script_environment taking an int arg and returning a AVS_ScriptEnvironment *
What kind of data structure is AVS_ScriptEnvironment?It is some kind of C wrapper around the C++ ScriptEnvironment class.
Where is it defined?Somewhere in the C plugin package i guess.
What does that "*" means?It means pointer (address in memory).
Instead of manipulating the whole data structure whose copying may be expensive, you just returns its address (whose copy is cheap).
C and C++ exposes them when other languages do the same behind the scenes. You may not see them, but there are always pointers :p.
Is it correct, the stuff defined in avisynth_c.h helps me
to create my own filter chains, but does not allow to connect
to an existing/runing ones?It may be possible to extract the underlying clip from the IAVIFile created by avisynth...
The "Private Declare Function SendMessage...." statement
is the way you can use functions in external DLLs from Visual Basic
and other languages. Kind of wrapper for Windows API. What is IDL?IDL = Interface Definition Language.
COM interfaces are defined using MIDL (Microsoft ...)
I'm sorry, next language to learn on my never ending
list is french. C is nearly at the end. DO you learn languages so fast you have a list for that !?
Anyway any computer language is definitely easier to learn than an human one.
I'm sure, I'll need years to install a compiler.Installing the compiler is easy, it's just the further layers who are annoying...
Adding "virtual vector<PClip> GetChilds() const"
sounds like kisuaheli for me.It declares a metod named GetChilds who returns a vector<PClip>, ie a dynamic array of PClip.
PClip itself being a customised pointer to a Clip.
sh0dan
13th November 2003, 15:04
To sum up:
AVS_ScriptEnvironment * avs_create_script_environment(int version);
This function returns a script-env for you application to use. It is an env. as described in avisynth.h, and it basicly provides access to all avisynth functionality without having to use the VFW-framework.
Version must correspond with the avisynth version. Version == 1 is AviSynth 1.0 and 2.0. Version == 2 is AviSynth 2.5. Use env->CheckVersion(int v) to get exact version.
You have access to all functions in AviSynth - Invoke most importantly. You can use it to load an external script or simply Invoke internal functions or plugins. (More on Invoke (http://www.avisynth.org/index.php?page=EnvInvoke)). Basicly you can Invoke 'Import("Filename")' to open an external AviSynth script.
You get a PClip back, and can use this to get video info, extract frames and audio.
You also have access to all other functions, like Variables, BitBlt, AddFunction, etc.
So basicly this is a hook into AviSynth that allows you to easily access AviSynth frames. You must do this in MSVC++, otherwise it'll be an almost impossible task.
vion11
13th November 2003, 18:11
Many thanks for all your answers and knowledge.
I'm sure now, all functionality needed is available.
It is looking in my eyes and otherwise.
If someone reading these lines, can talk c, or knows somebody with
a pictures of somebody codes c, a wrapper guru, you can stop me
performing endless what sh0dan names an almost impossible task.
Just pm me!
Bidoche
15th November 2003, 11:32
I just converted my first non trivial filter to 3.0 : SpatialSoften.
If some of you wants to take a peek at the code, the files are /filters/focus/spatialsoften.h/cpp.
While doing that, I imagined that a Threshold helper class may come in handy in a couple of places.
But since I am not the one who used those threasholds everywhere, I'd like some input as if I got the right semantics.
class Threshold
{
int threshold_; //underlying threshold value
public: //constructors
Threshold(int threshold) : threshold_( threshold )
{
if ( threshold < 0 )
throw ....
}
Threshold(const Threshold& other) : threshold_( other.threshold_ ) { }
public: //Threshold methods
bool IsReached(int value) const { return value >= threshold_; }
bool IsBelow(int value) const { return value < threshold_; }
bool IsAbsReached(int value) const { return IsReached(std::abs(value)); }
bool IsAbsBelow(int value) const { return IsBelow(std::abs(value)); }
bool AreClose(int a, int b) const { return IsAbsBelow(a - b); }
};
Bidoche
20th November 2003, 12:29
i have started converting to 3.0 style the resizing functions, and then I have come to this function :
int* GetResamplingPatternYUV( int original_width, double subrange_start, double subrange_width, int target_width, ResamplingFunction* func, bool luma, BYTE *temp )whose logic I have trouble to understand.
If somebody had some insight into it, I would like some answers :
- The temp parameter is only used to take addresses into the array it represents :*(cur[ii]) = luma ?
(int)(temp + (start_pos & -2) * 2) : //start_pos is int
(int)(temp + start_pos * 8);Why bother with it and not simply code the offsets...
Bidoche
24th November 2003, 22:20
I finally changed the resampling patterns production code, to an easier to read version I think.
I now only have two cases only :
- ResamplingPattern::Straight (it's an object) creates exactly the same data layout than the old GetRGBPattern did, eventually longer for alignement issues.
- ResamplingPattern::MMXInterleave creates almost the same data as GetYUVPattern in luma case, but instead of directly coding an adress in the temp buffer, it codes its offset.
That done, I made ResizeHorizontal on RGB24, RGB32 and YV12.
The two RGB were easy, just copy and paste the assembly and updating it with proper var names.
But I had to make some modification to the code for the YV12 case (adding the temp bufer base adsress)
@sh0dan
If you're the original coder, could you take a look at my mods (you may want to make it differently).
And I'll probably need your help for YUY2 case which is more complex.
Code is in : filters/resample/resizehorizontal.cpp
Bidoche
25th November 2003, 18:08
- added a new requirement for one child filter, they must provide an implementation for :virtual Clip * clone(PClip child) const = 0; //child changing clone
If you are wondering why I am not simply going for a SetChild method, two reasons dictated this decision :
It's easier this way, you can just a constructor rather having to alter potentially complex internal data.
It's more flexible, changing the child may require using a different class.
Exemple: Colorspace specific implementations like Tweak::YUY2 and Tweak::YV12. Changing ones child may require to pass hand to the other.
- added a method in the env for acquisition of a punctual temporary buffer (of requested size/align)
The point is to save filters from allocation costs (if allocates each time) and/or memory cost (if allocated once and for all)
NB: 2.X could use that scheme too
NB2: SMP could make that quite complex...
- finally completed some 3.0 filters, the winners are Trim and KillAudio.
Bidoche
9th December 2003, 19:31
I have continued conversion of filters to 3.0 style, making the count of converted (sometimes partially) filters to around 20.
Doing that, I became quite fond of inner subclassing, finding it an elegant way to clean up the mess of many multi path filters.
Let me explain with the example of ResizeHorizontal:
//before
class ResizeHorizontal
{
//common stuff
//YUV stuff
//planar stuff
//...
virtual PVideoFrame GetFrame( ...
{
//...
if ( IsYUY2() )
//YUY2 path
else if ( IsYV12()
//YV12 path
else if ( IsRGB24() )
//RGB24 path
else //RGB32 path
}
};
//after
class ResizeHorizontal
{
//common stuff
static Create(PClip child, //other params
{
//...
if ( IsYUY2() ) return new YUY2( child, ..
if ( IsYV12() ) return new YV12(..
if ( IsRGB24() ) return new RGB24(..
if ( IsRGB32() ) return new RGB32(...
//exception
}
private: //colorspace specific inner subclasses
class RGB24;
class RGB32;
class YUY2;
class YV12;
};//ResizeHorizontal
class ResizeHorizontal::RGB24 : public ResizeHorizontal
{
//RGB24 specific stuff
virtual PVideoFrame GetFrame(...) { //RGB24 path }
};
//same for RGB32, YUY2, YV12By doing that, you save some run time (no need to choose path) and some space (planar stuff and the like only in planar case), but the whole point is essentially that it is much cleaner.
Bidoche
11th December 2003, 00:12
Just committed Turn::Left and Turn::Right. (More inner subclassing :p )
The Turn code is not done though, I am just trivially calling the VideoFrame methods of the same name.
If anybody could volunteer to fill up those, it would help.
Edit: FlipHorizontal and FlipVertical committed too.
Bidoche
11th December 2003, 14:22
What's nice with this topic is that I can easily break the record of consecutive posts...
And without cheating too.
That is to say I'd appreciate a bit more feedback here.
I know sometimes (often ?) I am cryptic and you don't understand me.
But don't tell it was the case when I was asking if my threashold operations were the ones you expected.
And now the advanced problem for which I need input, it's just about algorithm so you should be able to follow me.
It's about cache (again).
The current mechanism use cache hints, but I now think it's too much rigid and deterministic to adapt to unpredictably complex filter graphs.
I think we should look at an adaptive approach :
After all, no one but the concerned cache knows better about the caching opportunities it may have missed, and so may decide to cache more.
So here is my current proposal (incomplete) :
Cache :
- keeps a list of past requested frames (10, more, adaptive ?)
- keeps count of misses/hits
- keeps a (float) target cache size
- keeps a minimum effective cache size (no need to cache 1 if you're always requested the 2nd last)
- somehow adjusts target cache size when cache miss
- somehow adjusts target cache size when env request to drop frames (too much memory used)
RuntimeEnvironment (3.0 runtime spawn of ScriptEnvironment)
- keeps a list of Cache depending of him
- when too much memory used, ask Caches to drop until ok again.
- makes these drop requests choosing Caches in a relevant order to determine (The point is that Caches with high miss cost are asked less often)
geoffwa
11th December 2003, 15:57
Holy cow, you reverse engineered the GetResamplePattern functions? I had to borrow Graphic Gems III from my uni library in order to figure that out (and I never got around to finishing that project).
Shouldn't the cache take into acccount the speed of the filter(s) it is caching? (easier said than done :D)
Surely the majority of frame requests be linear?
Bidoche
11th December 2003, 21:23
Holy cow, you reverse engineered the GetResamplePattern functions? I had to borrow Graphic Gems III from my uni library in order to figure that out (and I never got around to finishing that project). Yes, I did that. It was hard and it took a long time, that's why I requested some help at that time.
But now, I am pretty sure that my code produces the same output as before and it happens to be far more readable :p.
Shouldn't the cache take into acccount the speed of the filter(s) it is caching? (easier said than done ) A filter speed only has a sense when comparing to others, and so of little use for a Cache logic.
That's why it's the env who deals with that...
Unless you meant when the filter is so fast caching is irrelevant, when it does not really do any processing like Trim, or just affects audio.
It may be an issue for 2.X, but in 3.0 only filters who actually do something gets a Cache, Trim and the like don't.
Surely the majority of frame requests be linear?
True, and as long as it is the case, there is no need to cache anything.
But as soon as a clip has two (or more) clients or a temporal filter as client, there are potential cache opportunity.
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.