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 > Avisynth Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 23rd August 2013, 02:42   #161  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Tried as in my previous post with additional #define AVISYNTH_CORE,

and with

static const AVS_Linkage avs_linkage;
const AVS_Linkage* AVS_linkage = &avs_linkage;

in InvertNeg (removing the ptr),

both compile and link OK (thought the static forward decalre would fail, but did not) but
provided an access violation error in v2.5.

You are such a tease.

EDIT:
Quote:
works after building and testing in both 2.6 and 2.5.8
, maybe I did something wrong.

EDIT: Would this not create a second avs_linkage, static in InvertNeg module (whereas the initialized one is static
in Interface module) rather than combining into a single static AVS_Linkage.

Code:
static const AVS_Linkage avs_linkage;
const AVS_Linkage *AVS_linkage = &avs_linkage;
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 23rd August 2013 at 02:53.
StainlessS is offline   Reply With Quote
Old 23rd August 2013, 03:12   #162  |  Link
Robert Martens
Registered User
 
Join Date: Feb 2010
Location: New York
Posts: 116
Quote:
Originally Posted by StainlessS View Post
Would this not create a second avs_linkage, static in InvertNeg module (whereas the initialized one is static
in Interface module) rather than combining into a single static AVS_Linkage.

Code:
static const AVS_Linkage avs_linkage;
const AVS_Linkage *AVS_linkage = &avs_linkage;
Yes, I'd think it would; I made the mistake of using "static" when I'd meant "extern", but correcting my code I see that introduces a new set of errors.

Using the approach I rather irresponsibly suggested, though, still seems to work for my own plugin, if only I could decipher why. I can't successfully use InvertNeg, though, so obviously something's wrong with my idea.

I should probably learn C++ one of these days.
Robert Martens is offline   Reply With Quote
Old 23rd August 2013, 03:17   #163  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Quote:
I should probably learn C++ one of these days.
Me too.

Strange but if I try to debug, it does not crash (although output video is weird, with some kind of temporal chroma lead/lag).

EDIT:
Wilbert,
Code:
	int planes[] = {PLANAR_Y, PLANAR_V, PLANAR_U};
PLANAR_U(1) and PLANAR_V(2) transposed (should not cause problems though).

EDIT: and
Code:
++x;
produces better code than
Code:
x++;
although not much in it.

EDIT: The above x++; ++x;
The first one 'x++;' implies for a stack variable, that the variable x is gotten off stack , incremented and then updated
on-stack afterwards. The 2nd '++x;' can increment variable directly on-stack (if possible in assembler instruction set),
rather than doing it post increment.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 25th August 2013 at 16:53.
StainlessS is offline   Reply With Quote
Old 23rd August 2013, 06:24   #164  |  Link
Robert Martens
Registered User
 
Join Date: Feb 2010
Location: New York
Posts: 116
I think I've managed to work this out; my plugin, TurnsTile, was working because I use my own computed tile width and height, and the input videoinfo's width and height members, but never call GetRowSize or GetHeight. It seems that in the 2.58 code those follow the old fashioned approach of assuming U/V pitch and height are equal to half the Y plane pitch and height, respectively. The 2.6 code for both of those functions relies upon the VideoFrame members row_sizeUV and heightUV, which go uninitialized in 2.58 since they don't actually exist in that version. They end up with insane values, which then affect InvertNeg's loop count, leading to access violations.

I came to the conclusion by first following Ian's instructions as he provided them, then doing what I mentioned earlier and adding #define AVISYNTH_CORE before all includes of the header. Next, in the copy of interface.cpp that I swiped from Avisynth, I removed the static and const keywords from AVS_Linkage; apparently each of those implies, among other things, internal linkage, so the object in question won't be visible outside that source file. If this is a bad idea, please do let me know, I suppose in that case we can put the keywords back and just combine interface.cpp with our own code into one source file.

Over in my other source file, where I define the plugininit functions, I did the same as I did a few posts up but with the proper keyword this time:

Code:
...
extern AVS_Linkage avs_linkage;
const AVS_Linkage* AVS_linkage = &avs_linkage;

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(
    IScriptEnvironment* env, const AVS_Linkage* const vectors) {
...
This lets the project build properly, but it still doesn't work, so I just threw a little something into the logic of the filter for testing purposes:

Code:
...
row_size = dst->GetRowSize(planes[p]);
height = dst->GetHeight(planes[p]);
if (p == 1 || p == 2) {
    row_size = child->GetVideoInfo().width / 2;
    height = child->GetVideoInfo().height / 2;
}

for (y = 0; y < height; y++) {
    for (x = 0; x < row_size; x++) {
...
The plugin then loads (in 2.58; comment out the blue section for 2.60), and YV12 video is processed as expected. As for the proper way to modify the local copy of interface.cpp to handle this, assuming there is one, I'm still working my way through that.

Last edited by Robert Martens; 23rd August 2013 at 06:27.
Robert Martens is offline   Reply With Quote
Old 23rd August 2013, 07:54   #165  |  Link
TurboPascal7
Registered User
 
TurboPascal7's Avatar
 
Join Date: Jan 2010
Posts: 270
I'm not sure if someone asked this already, but is there any reason why we can't remove unaligned crop or at least make it optional? I believe it's the only function that might produce unaligned results in 2.6 and I really don't see any reasons to keep it this way. Am I missing something?

Also, any plans on making frames 32-bytes aligned for AVX?
TurboPascal7 is offline   Reply With Quote
Old 23rd August 2013, 13:00   #166  |  Link
ultim
AVS+ Dev
 
ultim's Avatar
 
Join Date: Aug 2013
Posts: 359
I'm hacking around in the AviSynth code, currently mainly familiarizing myself with it, but with ambitious goals. I've already made some progress, and I will probably open a thread for my efforts once I feel confident enough, but now I just have a general question. Given that the "standard/official" AviSynth is single-threaded by nature, why is it littered full with atomic increments and critical sections? Is there some aspect I missed that these are needed?
ultim is offline   Reply With Quote
Old 23rd August 2013, 14:40   #167  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 890
Quote:
Originally Posted by IanB View Post
The brief was 2.6 would load and support 2.5 plugins, period!
For me I do not want to meddle with Avisynth core. The alternatives suggested possibly produce in one package two plugins one for each version. It will double the size.
I will stick to the mandate and have a cpp file as suggested by stainless in his earlier post.
__________________
mohan
my plugins are now hosted here

Last edited by tebasuna51; 23rd August 2013 at 21:53.
vcmohan is offline   Reply With Quote
Old 24th August 2013, 00:40   #168  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
I did say
Quote:
Just needs a little imagination .....
so the hacking of Interface.cpp was obviously going to need a little thought and effort apart from the obvious #include's at the top and the extern __declspec at the bottom. All the old 2.5 code is still there in the comments.

In terms of size most plugin code is tiny. Things like fancy tables and runtime libraries usually make up most of the .dll size and these would occur only once. So I would not expect most dual mode plugins to be very much bigger.


@TurboPascal7,

Aligned crop costs an unaligned bitblt, i.e. unaligned read with aligned write in a loop.

For a plugin that does not have an unaligned path and crashes on unaligned reads, then you have no choice.

But for code with a usable unaligned path you are comparing [unaligned read + aligned write + aligned read] with [unaligned read] clearly the second case is faster.

So why do some filters suffer so badly with the unaligned case. Maybe they revert from a fast SSE path to a slow C++ code path, yes that's a bit slack, but maybe an unaligned SSE path won't go fast. More insidious is needing to read the input multiple times then the comparing becomes [1 *unaligned read + 1 * aligned write + N * aligned read] with [N *unaligned read], here the first case pulls ahead as N increases.

As for 32 byte alignment it may become the default in the future, but you have always been able to ask for extra alignment on the env->NewVideoFrame call.
IanB is offline   Reply With Quote
Old 24th August 2013, 02:13   #169  |  Link
TurboPascal7
Registered User
 
TurboPascal7's Avatar
 
Join Date: Jan 2010
Posts: 270
@IanB,

The problem is added complexity. By having unaligned crop in the core, you essentially destroy all alignment guarantees said core might provide, asking all developers to add multiple code paths to handle unaligned case, thus making implementation harder (and helping introducing template/macro hell), always using slow unaligned loads or simply break with or without error message. Is marginal performance difference in one filter in some cases worth it? You might make unaligned crop optional so people who think it matters for them could still shoot in their feet, but I don't think it's reasonable.

Strict alignment (16 or even better - 32) guarantee would IMHO simplify a lot of things for developers, especially when plugin is using the same codebase for avisynth and vapoursynth versions (vsynth guarantees 32-bytes alignment). It might be even better to completely ignore alignment parameter in env->NewVideoFrame or make 32 the minimum accepted value, but I'm not sure how many (broken) filters that might break.
TurboPascal7 is offline   Reply With Quote
Old 24th August 2013, 02:41   #170  |  Link
Groucho2004
 
Join Date: Mar 2006
Location: Barcelona
Posts: 5,034
@IanB

I have a question about AVS_Linkage. In the following code, my program crashes (exactly here: "~AVSValue() AVS_BakedCode( AVS_LinkCall(AVSValue_DESTRUCTOR)() )") if the script (test.avs) does not return a clip. However, if I uncomment the line "AVS_linkage = 0" (bold and red in the code) it seems to work OK. Just wondering if setting "AVS_linkage" to 0 is correct in this context.

Or maybe I should just use "ThrowError()" and let Avisynth clean up by itself.


Code:
#include "avisynth.h"

const AVS_Linkage *AVS_linkage = 0;

int main()
{
 HINSTANCE hDLL = ::LoadLibrary("avisynth");
 if (!hDLL)
  return -1;

 try 
 {
  IScriptEnvironment *(__stdcall *CreateEnvironment)(int) = (IScriptEnvironment *(__stdcall *)(int))::GetProcAddress(hDLL, "CreateScriptEnvironment");
  if (!CreateEnvironment)
  {
   ::FreeLibrary(hDLL);
   return -1;
  }
 
  IScriptEnvironment *AVS_env = CreateEnvironment(AVISYNTH_INTERFACE_VERSION);
  if (!AVS_env)
  {
   ::FreeLibrary(hDLL);
   return -1;
  }

  AVS_linkage = AVS_env->GetAVSLinkage();
  AVSValue AVSV_main;
  AVSV_main = AVS_env->Invoke("Import", "test.avs");

  if (!AVSV_main.IsClip()) //not a clip
  {
   //AVS_linkage = 0; 
   AVSV_main = 0;
   AVS_env->DeleteScriptEnvironment();
   ::FreeLibrary(hDLL);
   return -1;
  }
 }
 catch(AvisynthError err) 
 {
 }

 ::FreeLibrary(hDLL);

 return 0;
}
__________________
Groucho's Avisynth Stuff

Last edited by Groucho2004; 24th August 2013 at 09:21.
Groucho2004 is offline   Reply With Quote
Old 25th August 2013, 00:09   #171  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
If we look under the covers of the baked macros :-
Code:
# define AVS_BakedCode(arg) { arg ; } 
# define AVS_LinkCall(arg) !AVS_linkage || offsetof(AVS_Linkage, arg) >= AVS_linkage->Size ? 0 : (this->*(AVS_linkage->arg))

We see :-
Code:
~AVSValue() AVS_BakedCode( AVS_LinkCall(AVSValue_DESTRUCTOR)() )
which becomes after we unwrap AVS_BakedCode :-
Code:
~AVSValue() { AVS_LinkCall(AVSValue_DESTRUCTOR)() ; }
and finally becomes :-
Code:
~AVSValue() {
  !AVS_linkage
   || 
  offsetof(AVS_Linkage, AVSValue_DESTRUCTOR)()) >= AVS_linkage->Size
   ?
  0
   :
  (this->*(AVS_linkage->AVSValue_DESTRUCTOR)()));
}
and if we follow the function pointer :-
Code:
void AVSValue::DESTRUCTOR() { if (IsClip() && clip) clip->Release(); }
So I find it a little strange the crash report is on the link call itself rather than in the actual code, but that may be a lack of symbols thing with the debugger.

Of course setting AVS_linkage = 0 cause the code to be skipped, so what ever is wrong is ignored.

I suspect your problem may be earlier with AVSV_main not being constructed correctly :-
Code:
  AVS_linkage = AVS_env->GetAVSLinkage();
  AVSValue AVSV_main;
  AVSV_main = AVS_env->Invoke("Import", "test.avs");
it depends on the order the compiler does things, but I suspect AVSV_main tries to get made with AVSValue::CONSTRUCTOR0() before AVS_linkage gets assigned.

So setting AVS_linkage back to zero before the ::FreeLibrary is the right thing to do, but setting it to zero before all the classes are finished is not right. Just like trying to start classes is not right before you initially set AVS_linkage.

I think we need some notes about lifetime and scope of things needing a valid AVS_linkage.
IanB is offline   Reply With Quote
Old 25th August 2013, 00:30   #172  |  Link
Groucho2004
 
Join Date: Mar 2006
Location: Barcelona
Posts: 5,034
Quote:
Originally Posted by IanB View Post
So setting AVS_linkage back to zero before the ::FreeLibrary is the right thing to do, but setting it to zero before all the classes are finished is not right.
Thanks Ian. I now tested these 2 options:
Code:
if (!AVSV_main.IsClip()) //not a clip
{
 AVSV_main = 0;
 AVS_env->DeleteScriptEnvironment();
 AVS_linkage = 0;
 ::FreeLibrary(hDLL);
 return -1;
}
Code:
if (!AVSV_main.IsClip()) //not a clip
 AVS_env->ThrowError("Script did not return a video clip");
Both let the program (a function actually) exit without crashing. I guess I'll use the former.

Edit: Static linking with avisynth.lib also works fine.
__________________
Groucho's Avisynth Stuff

Last edited by Groucho2004; 25th August 2013 at 12:27.
Groucho2004 is offline   Reply With Quote
Old 28th August 2013, 14:10   #173  |  Link
vcmohan
Registered User
 
Join Date: Jul 2003
Location: India
Posts: 890
The windows 32 bit dll is dated jan 2013. Since then a number of changes/ corrections were done. Will it be possible to update the dll and make available for down load?
__________________
mohan
my plugins are now hosted here
vcmohan is offline   Reply With Quote
Old 28th August 2013, 20:16   #174  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
vcmohan,
See Grouch02004 ICL compiler version v2.6a4 with updates, current April 25 2013, works great.
You just need install v2.6a4 and overwrite dll in system32 (SysWOW64 64bit) with the new dll.

http://forum.doom9.org/showthread.php?t=167358
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 28th August 2013 at 20:18.
StainlessS is offline   Reply With Quote
Old 29th August 2013, 01:03   #175  |  Link
Robert Martens
Registered User
 
Join Date: Feb 2010
Location: New York
Posts: 116
Ian, I wonder if you'd be so kind as to offer a little more help regarding your idea for the dual-host plugin as described here:

Quote:
Originally Posted by IanB View Post
Initialise AVS_linkage to the local copy and set it to the core value in the AvisynthPluginInit3 entry code.
Code:
....
const AVS_Linkage *AVS_linkage = &avs_linkage;

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(
        IScriptEnvironment* env,
        const AVS_Linkage* const vectors) {

    AVS_linkage = vectors;
    env->AddFunction("InvertNeg", "c", Create_InvertNeg, 0);
    return "`InvertNeg' sample plugin";
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(
        IScriptEnvironment* env) {
    env->AddFunction("InvertNeg", "c", Create_InvertNeg, 0);
    return "`InvertNeg' sample plugin";
}
I've spent the past few days going over C++ books, websites, Stack Overflow posts, basically all the reference material I could get my hands on, digging further into function pointers than I ever thought I would, along with inheritance and a variety of other related topics, but I feel like I'm going around in circles.

Including the Avisynth header with AVISYNTH_CORE defined means the linkage macros evaluate to nothing, so all the header contains are function declarations. I'm then free to implement them as I see fit in interface.cpp. That's great for 2.5, but loading the plugin in 2.6 shows that it uses those same local implementations, since the various methods aren't defined to call AVS_linkage and get the appropriate function pointers from the core.

Trying to include the header twice (once in interface.cpp with AVISYNTH_CORE defined, and once in invertneg.cpp without it) just ends up defining the functions twice, which won't work, and I spun my wheels in the mud playing around with derived classes, friend functions, and function pointer casts only to find myself back where I started.

The only answer I could come up with involves initializing AVS_linkage to zero, and then making every function in my copy of interface.cpp look like this (after copying some of the macro code into the file so it'll evaluate to code calling the function pointer):

Code:
bool VideoInfo::HasVideo() const
{

  if (AVS_linkage) {
    return AVS_LinkCall(HasVideo)();
  } else {
    return (width!=0);
  }

}
As seen above, however, you suggested initializing AVS_linkage differently, so I'm fairly sure this isn't what you had in mind. Would you by any chance be able to give me a hint where I should go next? I don't expect you to teach me remedial C++, or walk me through the intricacies of the Avisynth codebase, but a nudge in the right direction would be a big help; maybe just the names of the C++ or general programming concepts I'd need to study to solve the problem the way you intended?
Robert Martens is offline   Reply With Quote
Old 29th August 2013, 02:12   #176  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Mucho admiration that you seem to be pursuing this, thought it might better be in the domain of a CPP progger, (me given up),
Hope Mr B gives you an audience.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 29th August 2013, 06:31   #177  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
A solution to the functions defining twice is to wrap one instance in a namespace, then they become distinct. This is pretty much how the first brute solution gets around the same problem of duplicate names.

I did warn that some imagination would be required.
Code:
namespace Interface {
/* Modified Interface.cpp */
....
// 50 #include "stdafx.h"
#include <windows.h>

#define AVISYNTH_CORE // pretend we are avisynth.dll
#include "avisynth.h"

....

// Old 2.5 version of code
int VideoFrame::GetHeight(int plane) const {
  switch (plane) {
  case PLANAR_U:
  case PLANAR_V:
    if (pitchUV)
      return height>>1;
    return 0;
  }
  return height;
}
/* int VideoFrame::GetHeight(int plane) const {
  switch (plane) {
  case PLANAR_U:
  case PLANAR_V:
    if (pitchUV)
      return heightUV;
    return 0;
  }
  return height;
}*/

....

// 746 extern __declspec(dllexport) const AVS_Linkage* const AVS_linkage = &avs_linkage;
....
}
And of course you need to reference the namespace version of thing in Interface.cpp
Code:
...
const AVS_Linkage* AVS_linkage = &Interface::avs_linkage;
...

Last edited by IanB; 29th August 2013 at 06:35.
IanB is offline   Reply With Quote
Old 29th August 2013, 15:40   #178  |  Link
ultim
AVS+ Dev
 
ultim's Avatar
 
Join Date: Aug 2013
Posts: 359
In the definition of the ScriptEnvironment::NewPlanarVideoFrame method, what is the point of letting plugins force a smaller alignment than the default? Anything else than those very few bytes of memory savings?
ultim is offline   Reply With Quote
Old 29th August 2013, 22:44   #179  |  Link
Chikuzen
typo lover
 
Chikuzen's Avatar
 
Join Date: May 2009
Posts: 595
From core/parser/script.cpp
Code:
AVSValue Import(AVSValue args, void*, IScriptEnvironment* env) 
{
...
    TCHAR full_path[MAX_PATH];
    TCHAR* file_part;
    if (strchr(script_name, '\\') || strchr(script_name, '/')) {
      DWORD len = GetFullPathName(script_name, MAX_PATH, full_path, &file_part);
      if (len == 0 || len > MAX_PATH)
        env->ThrowError("Import: unable to open \"%s\" (path invalid?)", script_name);
    } else {
      DWORD len = SearchPath(NULL, script_name, NULL, MAX_PATH, full_path, &file_part);
      if (len == 0 || len > MAX_PATH)
        env->ThrowError("Import: unable to locate \"%s\" (try specifying a path)", script_name);
    }
...
Although Windows API can handle MAX_PATH(260) characters(not bytes) as filepath, 'Import' causes an error by about 130 non-ASCII characters by shortage of a buffer.
(Generally, non-ASCII characters require 2bytes on ACP.)
I think that 'TCHAR full_path[MAX_PATH]' should be changed into 'TCHAR full_path[MAX_PATH * 2]'.
__________________
my repositories
Chikuzen is offline   Reply With Quote
Old 29th August 2013, 22:58   #180  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
@ultim,

Forcing alignment is generally for setting a PVideoFrame to describe an existing foreign video buffer layout. This can avoid an unnecessary copy of the data. e.g. a source filter to match the memory layout delivered by a codec, or matching the memory layout of a hardware device.

Setting some pointers and a few describing numbers is of order a million times faster than actually copying the data bytes. TurboPascal7 above was advocating always making Crop that million times slower for the sake of always maintaining memory alignment.
IanB 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 11:34.


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