Open FredMSloniker opened 2 years ago
Two things could be happening, depending on how the graph is being constructed: A) DirectShowSource opens LAVFilters to open the script with AviSynth, LAVFilters is set to output pcm_s16le. B) DirectShowSource is directly re-accessing AviSynth to chainload itself, and some of the particular global options meant for working with VfW or DirectShow are getting in the way before it realizes it's talking to ffprobe and not something like VirtualDub.
That said, for the task of
I'm combining the output of several .avs files into a master .avs file
that would probably be better handled by Import
, not one of the source filters.
For one, Import
is portable across OSes, AVISource
and DirectShowSource
are Windows-only (and quite possibly x86(-64) Windows-only at that, either because Windows on ARM doesn't include VfW or DirectShow or because even if it does, no one will bother porting the relevant VfW/DS codecs to WoA).
There's also the risk that trying to essentially chainload AviSynth.dll through itself on multiple invocations of DirectShowSource
could interact strangely with anything like DLL reentrancy or memory and cache operations or who-knows-what. It may not show itself with only a few, but if the master file is supposed to end up doing this dozens or hundreds of times...
Thanks for the tip. Switching to Import()
caused some glitches, though, which I narrowed down to the .avs files I'm importing defining variables and changing last
and so on. What kind of insulation do I have to wrap around Import()
to only return the clip I'd get if I opened it directly?
Ah, yeah, the documentation seems to mention something like that.
I don't know if it'd work, but if you wrap the contents of the child script into a function, I would think it would preserve the state of the child script when imported and then invoked by calling the function in the master script. It'd just be woefully inefficient if most of the child scripts use the same or very similar filtering.
To illustrate (and somewhat for the benefit of anyone stumbling onto this through Google), test.avs
Version()
And test2.avs
Version().Invert()
And import.avs
a=Import("test.avs")
b=Import("test2.avs")
a+b
import.avs plays back the regular Version info for 10 seconds, then a negative of it for 10 seconds. But we can do something like this in test2.avs instead (the indentation is just for readability):
function loadsomething()
{
a=Version()
b=a.Invert()
return b
}
And then in import.avs
a=Import("test.avs")
b=Import("test2.avs")
a+loadsomething()
And it outputs exactly the same thing as the first import.avs example, except that test2.avs was changed into a function, and you call the function.
So would this function do what I think it'll do, i.e. isolate the imported .avs and supply only its video output?
function Wrap(string name)
{
return Import(name)
}
If you're defining it as a function, it should be done in the child script, not the master script, and so Import
shouldn't be happening there. The master script Import
s the child script, and then loads it in using the function name.
If you can provide a more concrete example where the variable(s) in the scripts aren't honored when using Import
, it'd be easier to troubleshoot this.
The issue is rather the opposite. I'm trying to keep the .avs I'm importing from, for instance, overwriting last
; I want adding it to the master .avs to be just like adding a clip with AVISource
or DirectShowSource
, i.e. only returning a video clip and not making any other changes to the master .avs's environment.
e: here's a test case. I created t1.avs:
DirectShowSource("test.mkv")
z = Import("t2.avs")
last
And t2.avs:
BlankClip()
Info()
I would expect, on loading t1.avs, to see the contents of test.mkv. Instead, bizarrely, I see a blank clip without the info, meaning I'm getting neither the expected result nor the glitch I expected to get, i.e. the contents of t2.avs! However, if I change t1.avs to:
DirectShowSource("test.mkv")
function Wrap(string name)
{
return Import(name)
}
z = Wrap("t2.avs")
last
...then I get test.mkv as intended.
Okay, I see more of what's going on now. Let me see.
Import("t2.avs")
Version()
last
You get Version, same as you would if you were using the implicit last.
Version()
Import("t2.avs")
last
You get the contents of t2.avs, same as if you were using the implicit last.
z=Import("t2.avs")
Version()
last
You get Version(). Same with the implicit last.
Version()
z=Import("t2.avs")
last
You get t2.avs. But the implicit last,
Version()
z=Import("t2.avs")
is now broken. This seems like it might be a bug, because (as far as I know) variables other than last should not be considered implicit, and last shouldn't be equivocating itself to a declared variable (that part may be up for debate, but if the user explicitly calls last you might be able to make an argument for why it should equivocate; I'd argue that it would make sense for implicit last to ignore declared variables, though). But the more concerning thing is that it breaks at all. Basically, the skip does seem to be functioning, in that it refuses to load z into last without the user having invoked either z or last explicitly, but under other circumstances it should have fallen back to the non-variable-invoked Version() instead.
[ffmpeg/demuxer] avisynth: AviSynth script did not return a clip
[lavf] avformat_open_input() failed
Failed to recognize file format.
Which implies that it's mangling the script being imported.
Changing t2.avs to
function here() {
a=BlankClip()
a.Info
}
t1.avs's implicit last is still broken, but explicit last returns Version(), and
Version()
z=Import("test2.avs")
here
returns t2.avs. Although to be fair, the z= declaration is meaningless here, because Import is importing the function, not the source (per ce), and something like z=here fails the exact same way the implicit last does above. To make that work, you actually need to do something like:
Version()
Import("test2.avs")
z=here
z
Honestly, my gut feeling is that a lot of this might simply be undocumented edge case behaviors with an actual explanation, it just rarely occurs because script writing tutorials try to avoid writing scripts with unclear variable usage that end up conflicting this way.
For instance, I would never try to Import
a script containing a source filter mid-way through the script, after the parent script has already declared its source. All Import
usage should ideally be done at the top of the script, along with whatever global options and other script control functions (SetMemoryMax, SetFilterMTMode, etc.) you might be using. And if I declare more than one source in a script, no source is going to be under an ambiguous last
: every source is getting its own distinct variable. And when I go to actually output in that circumstance, unless I'm using a filter that takes variables (AudioDub and Overlay come to mind here), I'll be explicitly declaring the source's variable that I want to output instead of relying on the implicit or explicit last
behavior and just hoping it understands what I want.
At this point I'll say that maybe @pinterf or @magiblot or one of the other contributors might have a much better explanation/take on what it's actually doing here, and so I'll just hand it off to them.
So the other part of the t2.avs weirdness:
Instead, bizarrely, I see a blank clip without the info, meaning I'm getting neither the expected result nor the glitch I expected to get, i.e. the contents of t2.avs!
ffplay displays the alpha channel as a black screen. mpv displays it as the typical transparency checkerboard. The output of Info() is there, but because BlankClip creates an RGBA clip by default, it's being obscured by how libavformat-based players display the alpha channel. If you open it in VirtualDub, it'd display the Info() readout. Similarly, if you either use RemoveAlphaPlane()
after BlankClip()
, or use BlankClip
's pixel_type= parameter to select a pixel format that lacks an alpha channel (there's ton of them in AviSynth+), then ffplay and mpv show the Info() readout.
I have a file,
t1.avs
, that's simplyConvertAudioToFloat(BlankClip())
. Running ffprobe on it gives me this:I have a second file,
t2.avs
, that's simplyDirectShowSource("t1.avs")
. Running ffprobe on it gives me this:Changing
DirectShowSource()
toAVISource()
doesn't help. I'm combining the output of several .avs files into a master .avs file, and I don't know if this counts as a bug or if I'm doing something wrong...