View Full Version : DirectShow filter as Avisynth source (other than ffdshow)?
CrendKing
25th February 2020, 03:50
I might be asking a dumb question since I'm very new to Avisynth world. I'm trying to use Avisynth to load some frame manipulation script in MPC-HC / MPC-BE, which allows me to add subtitle or change FPS. I'd done a lot of searches, but AFAIK ffdshow is the only DirectShow filter that can provide the video being played as an Avisynth clip (ffdshow_source), am I correct? One alternative is Daum PotPlayer, which basically has the ffdshow's Avisynth (AND VapourSynth, good job!) built in. Unfortunately it is closed source. All other Avisynth source filters requires a filename as parameter.
I'm asking because ffdshow has stopped development for years, and VapourSynth is not supported (by briefly looking at it (https://forum.doom9.org/showthread.php?p=1697685#post1697685)).
-----
Update: wrote my own filter at https://github.com/CrendKing/avisynth_filter. See this post (https://forum.doom9.org/showthread.php?p=1903403#post1903403).
Asmodian
25th February 2020, 16:11
What is wrong with using a filename?
PotPlayer is closed source while also using open source code... :devil:
CrendKing
25th February 2020, 18:26
Well, it is a tad more inconvenient to have to edit a text file every time watching a video than just double clicking or passing an argument to the executable from a batch. Well, technically I would write a simpler filter that automatically generate an avs script and feed to the player, but I just feel so dumb if I have to do that. It does not feel right.
I'm experimenting on implementing just the Avisynth loading logic from ffdshow on a filter. It seems pretty straight forward. If nobody has ever done this before, I guess there must be a good reason.
That's also why I refuse to use PotPlayer.
hello_hello
1st March 2020, 07:07
You can install just the ffdshow raw video filter and audio processor, At least the custom installer options suggest you can. I've never installed them without the rest of ffdshow, but it's worth a look. They can be added to MPC-HC as external filters.
To configure them, you can double click on each in MPC-HC's external filters section.
Or.... someone told me how to create shortcuts for opening the configurations as it's more convenient. They work on XP.
C:\WINDOWS\system32\rundll32.exe "C:\Program Files\ffdshow\ffdshow.ax",configureRaw
C:\WINDOWS\system32\rundll32.exe "C:\Program Files\ffdshow\ffdshow.ax",configureAudioRaw
Does ffdshow's Avisynth filter allow you to change the frame rate? I'm reasonably sure frame rate stuff in a script is ignored. Probably because it could mess with the audio sync.I tried AssumeFPS(50) in ffdshow but it had no effect.
CrendKing
9th March 2020, 21:06
Anyways, I wrote a filter to replace ffdshow. The project is at https://github.com/CrendKing/avisynth_filter . Comparing to ffdshow, I put NV12, P010 and P016 into support since they are more popular 4:2:0 formats than YV12. I've never seen 4:2:2 or 4:4:4 video, so I did not put effort into writing those transform code, yet.
I understand AviSynth has large amount of internal functions and plugins, 99% of which I have no idea what they do. I just tested against my own use cases and some simple internal functions. I've been running it for like a week without major problem.
If you are interested, feel free to give it a try, or fork it. Just remember, if you ever publish your own version, release it under GPL (since AviSynth is under GPL). Don't be another PotPlayer.
I've briefly studied VapourSynth C API. It largely resembles AviSynth+'s API. So with a few changes, I should be able to migrate the logic to VapourSynth.
CrendKing
9th March 2020, 21:14
Does ffdshow's Avisynth filter allow you to change the frame rate? I'm reasonably sure frame rate stuff in a script is ignored. Probably because it could mess with the audio sync.I tried AssumeFPS(50) in ffdshow but it had no effect.
Just tested it for you. You seems to be correct. With ffdshow, even though a following Info() shows the FPS of the clip is indeed changed, the play rate remains the same.
Well, my filter does not have this problem. If you put AssumeFPS(50) on a 25fps video, every other frame will be a duplicate frame. If you put AssumeFPS(15) on a 30fps video, every other frame will be skipped. Maybe you could give it a try.
Milardo
10th March 2020, 02:57
Hi, i just tested your filter. Not sure if there is a problem with my system, but the audio is not in sync with video. Tried this with mpc-hc. Used something simple like ChangeFPS(23.976)
I did see that the player rate changed in mpc-hc.
By the way, as far as i know in ffdshow avisynth filters changing frame rate do work like the ChangeFPS() for example. But the buffer back/ahead sometimes have to be adjusted sometimes for it to work. However ffdshow reports in the info section the source's original frame rate. however whatever player i might be using reports the changed frame rate.
Also is there a buffer back/ahead option in your filter? Like the one in ffdshow or is this even needed? Does the filter work with capture cards as a source? It just crashed with an error when i tried that.
CrendKing
10th March 2020, 20:03
I tried AssumeFPS, ChangeFPS and ConvertFPS in MPC-HC. Did not see audio sync problem. I did mess up with the x64 release though (it had a wrong old version). I reuploaded the archive.
-------------
About ffdshow's buffer option. According to their wiki (http://ffdshow-tryout.sourceforge.net/wiki/video:avisynth#buffer_back_ahead), it is used to allow filters to access a configurable range of frame within the current position. I implemented a similar buffer in the filter. Here's the detail.
In DirectShow, the upstream filters usually process a few frames ahead of time (like prefetch), and send them down to the renderer with a "render timestamp". The renderer (e.g. madVR) caches whatever it receives and presents them when the time comes. The heavier the system is under load, the shorter the prefetch becomes (could even lag behind, where it starts to drop frames). This filter just saves all frames between the tip of the prefetch and the current play timestamp. Once a frame is "out of sight", it is discarded from buffer. Like ffdshow, if any frame is requested outside of the buffer range, the nearest one is returned.
Whenever a seeking happens, I just flush the buffer to avoid the "ghost frame" problem I had with ffdshow.
Because this mechanism totally relies on the upstream (or more specifically splitter), I do not provide any option for it. If anyone finds a use case where "out of sight" frames are needed, I could provide option to save those extra frames.
-------------
About the crash, first please try the current archive. If it still crashes, I need more information (e.g. frame rate, color format, duration, etc). I can upload a debug version if you'd like to help, because I do not have a capture card.
Milardo
11th March 2020, 02:45
It must be my computer that's having issues, tried a different pc and there was no audio sync problem.
However mpc-hc crashed again as soon as i tried to use a capture card.
I uploaded a screenshot of the error message. Let me know if you need more info and i would be glad to test a debug version thanks in advance.
Frame rate is at 29.97 original, YUY2 color format.
CrendKing
12th March 2020, 04:37
I did not have YUY2 video, so I did not implement that as input format. But if you use LAV Filters, they should convert it into some 4:2:0 format such as NV12. Should not be a crash. Unless something else is in the filter graph?
The attachment is still pending, so I can't tell for sure.
If there is not private in the video, I wonder if you could send me a sample for test?
Milardo
12th March 2020, 05:25
Actually the YUY2 format is the capture card itself-raw video.
That's where i get the crash and error message.
CrendKing
1st May 2020, 10:18
I've worked with Milardo to hunt down bugs and bring improvements. I released version 0.3 (https://github.com/CrendKing/avisynth_filter/releases/tag/0.3) a while ago and haven't found any problem with it. If you are interested in using AviSynth in a video player with DirectShow support (e.g. MPC-HC/BE), please give it a try.
Sparktank
6th June 2020, 06:06
Would this work in something like SVP?
Say, I threw in a hi10p encode to interpolate. This would accept P010 without reducing the quality in the flow chain to allow it to be interpolated, as if it were using FFDShow?
SVP requires FFDShow and its limited support of formats.
I can use the Vapoursynth port to get it to play back 10bit with SVP's modified MPV player.
But, say, I want to use MPC-HC (madvr, et al) instead. Without having to reduce to 8bits.
Would this be the tool for me?
CrendKing
9th June 2020, 16:04
My filter is pretty much a replacement of ffdshow (regarding the AviSynth part). So if there is anything ffdshow can but my filter can't do, let me know.
More specifically, the filter should work with SVP. Also individually the filter supports P010 format. However, I remember SVP only works on YV12 input, so you need to either put something like ConvertBits(8) in your script to convert that 10 bit video to 8 bit, or simply uncheck P010 in the setting page (in this case, LAV Video Decoder will do the conversion, which could be more efficient).
Here is a simple script to use SVP (doubling framerate):
AvsFilterSource()
LoadPlugin("plugins\SysInfo\SysInfo64.dll")
LoadPlugin("plugins\SVPflow\windows\x64\svpflow1.dll")
LoadPlugin("plugins\SVPflow\windows\x64\svpflow2.dll")
super = SVSuper("{gpu: 1}")
vectors = SVAnalyse(super, "{}")
SVSmoothFps(super, vectors, "{rate: {num: 2"}}", mt=SI_LogicalCores())
Prefetch(SI_LogicalCores())
StainlessS
9th June 2020, 16:49
Prefetch(SI_LogicalCores())
It is my understanding that Prefetch(SI_PhysicalCores()) would be favourite.
Groucho2004
9th June 2020, 17:10
It is my understanding that Prefetch(SI_PhysicalCores()) would be favourite.Is it? Why?
StainlessS
9th June 2020, 17:17
Well I cant test, (I dont have hyperthreading), just 4 physical. [but for me Prefetch(4) or 3 or 2 near same when encoding, I now use 4, just recently started using Prefetch].
But has been suggested as best by Atak_Snajpera (I think) and others as performant, especially when also encoding, encode needs some CPU too.
Groucho2004
9th June 2020, 17:20
Well I cant test, (I dont have hyperthreading), just 4 physical.
But has been suggested as best by Atak_Snajpera (I think) and others as performant, especially when also encoding, encode need some CPU too.I see. I suppose that makes sense. :)
manolito
9th June 2020, 23:01
The following follows a recommendation from Myrsloik a while ago:
Prefetch(Min(Int(Value(GetSystemEnv("NUMBER_OF_PROCESSORS"))),8))
It basically uses the physical + virtual cores, but with a ceiling of 8.
For my CORE i5 (two physical cores plus HyperThreading) this means a prefetch value of 4, and this really works best for me - I did make extensive speed and stability tests.
Sparktank
10th June 2020, 02:25
I remember SVP only works on YV12 input
It works with YV12 because it depends on FFDShow which only has YV12. They'd use something else if it was available.
I'll let them know you made this and show this to them.
I'd rather not depend on MPV for 10bit SVP.
I'm looking for fidelity in the workflow and still keep MadVR.
CrendKing
10th June 2020, 07:46
It is my understanding that Prefetch(SI_PhysicalCores()) would be favourite.
According to https://superuser.com/a/740616/495087, hyperthreading provides 20%-40% improvement over physical cores, so yeah, using SI_LogicalCores() is a bit too optimistic. However, it would be nice if someone can do a benchmark on AviSynth use case specifically though. Who knows if HT is extremely beneficial here and making Prefetch(SI_LogicalCores()) the optimal choice.
It works with YV12 because it depends on FFDShow which only has YV12. They'd use something else if it was available.
I didn't know, because when I tried to load SVP I get error like in attachment. It makes sense because mvtools2 can operate on 10-bit content, and SVP is based on mvtools. Why does SVP self-restrict itself? If I'm the SVP developer, I wouldn't assume the only thing that can load my filter is something that has ceased development years ago. I have faith in humanity :)
StainlessS
10th June 2020, 11:40
Prefetch(Min(Int(Value(GetSystemEnv("NUMBER_OF_PROCESSORS"))),8))
Above GetSystemEnv("NUMBER_OF_PROCESSORS") can be used on XP for logical processor count [W2K unklnown],
and is same as Groucho2004 SystemInfo SI_LogicalCores().
There is no equivalent in system environment (at least on XP/W7) for physical processor count but SystemInfo SI_PhysicalCoress() does that.
[Just for anyone not aware of G2K4 SystemInfo plug, and to save people looking in system environment for something that dont exist]
Groucho2004
10th June 2020, 12:36
There is no equivalent in system environment (at least on XP/W7) for physical processor count but SystemInfo SI_PhysicalCoress() does that.The physical processor count is actually "SI_NumberOfCPUs()". The physical core count (number of CPUs * Physical cores/CPU) is "SI_PhysicalCores()".
StainlessS
10th June 2020, 14:14
Oops, thats what I mean't.
Boulder
10th June 2020, 15:59
According to https://superuser.com/a/740616/495087, hyperthreading provides 20%-40% improvement over physical cores, so yeah, using SI_LogicalCores() is a bit too optimistic. However, it would be nice if someone can do a benchmark on AviSynth use case specifically though. Who knows if HT is extremely beneficial here and making Prefetch(SI_LogicalCores()) the optimal choice.
I did some tests quite recently with Avs+ v3.6 on my 3900X which has 12 cores and 24 threads. The script is my basic process:
1) Source decoding with DGSource
2) Motion-compensated denoising (some preprocessing + MAnalyse + MRecalculate n times depending on the source resolution + MDegrain)
3) Converting to RGB in linear light (32bit float precision), downscaling, converting back to YV12 in high bitdepth
4) Debanding with neo_f3kdb
Then encoded with x265 at Main10 profile, --preset slower and slight tweaks. These were the results:
threads=24, frames default 2.53 fps
threads=24, frames 12 2.57 fps
threads=24, frames 24 2.51 fps
threads=24, frames 8 2.56 fps
threads=24, frames 10 2.57 fps
threads=24, frames 16 2.55 fps
threads=22, frames 16 2.55 fps
threads=20, frames 12 2.58 fps
threads=16, frames 12 2.57 fps
threads=12, frames 12 2.55 fps
So not so much of a difference, the number of prefetched frames played a bigger part. I'm now using threads=24, frames=12 as my default settings.
Groucho2004
10th June 2020, 19:12
Then encoded with x265 at Main10 profile, --preset slower and slight tweaks. These were the results:
threads=24, frames default 2.53 fps
threads=24, frames 12 2.57 fps
threads=24, frames 24 2.51 fps
threads=24, frames 8 2.56 fps
threads=24, frames 10 2.57 fps
threads=24, frames 16 2.55 fps
threads=22, frames 16 2.55 fps
threads=20, frames 12 2.58 fps
threads=16, frames 12 2.57 fps
threads=12, frames 12 2.55 fps
So not so much of a difference, the number of prefetched frames played a bigger part. I'm now using threads=24, frames=12 as my default settings.
It looks like the encoder is the main bottleneck in this case. Can you run just the script with AVSMeter and the same parameters?
Boulder
11th June 2020, 06:01
Here are some test results (threads, frames, fps, cpu%)
24, 48 - 13.94 / 80,8%
24, 28 - 15.82 / 82,9%
24, 24 - 15.97 / 82,7%
24, 20 - 15.42 / 69,9%
24, 16 - 14.41 / 56,0%
24, 12 - 13.08 / 43,9%
20, 40 - 12.75 / 66,1%
20, 24 - 15.46 / 70,7%
20, 20 - 15.34 / 69,9%
18, 22 - 15.22 / 63,8%
16, 20 - 14.72 / 56,4%
I've noticed that a high prefetched frames amount causes occasional stalls in the process, maybe the GPU decoder gets overwhelmed there. I have a 1050Ti GTX which is not the fastest card around.
Groucho2004
11th June 2020, 07:57
Here are some test results (threads, frames, fps, cpu%)
24, 48 - 13.94 / 80,8%
24, 28 - 15.82 / 82,9%
24, 24 - 15.97 / 82,7%
24, 20 - 15.42 / 69,9%
24, 16 - 14.41 / 56,0%
24, 12 - 13.08 / 43,9%
20, 40 - 12.75 / 66,1%
20, 24 - 15.46 / 70,7%
20, 20 - 15.34 / 69,9%
18, 22 - 15.22 / 63,8%
16, 20 - 14.72 / 56,4%
I've noticed that a high prefetched frames amount causes occasional stalls in the process, maybe the GPU decoder gets overwhelmed there. I have a 1050Ti GTX which is not the fastest card around.Oddly similar results, it looks as if your CPU is already saturated at 16 threads. Do you have avstp.dll in your plugin directory? Also, can you post your complete script?
Boulder
11th June 2020, 09:07
Oddly similar results, it looks as if your CPU is already saturated at 16 threads. Do you have avstp.dll in your plugin directory? Also, can you post your complete script?
In my opinion, 20 and 24 threads are quite close to each other which is probably due to the logical cores making the mark there. The big difference comes from the amount of prefetched frames -- I don't know if the script "startup" time is what skews the results a bit. In this test, I had 2000 frames output to compensate.
I don't have avstp.dll and all the internal multithreading settings in filters are disabled. I can post the script, but my internal functions are messy :D
Groucho2004
11th June 2020, 09:13
I can post the script, but my internal functions are messy :DNever mind, I only have 4 cores (no HT) so I can't really test under similar conditions.
CrendKing
9th July 2020, 21:13
Came across a post about physical cores vs logical cores: https://medium.com/data-design/destroying-the-myth-of-number-of-threads-number-of-physical-cores-762ad3919880 . According to the result, on average scaling the number of threads to the logical core number is the best. Of course, actual performance is dependent on specific workload and the program's ability to scale.
chainik_svp
6th August 2020, 11:00
Any chance adding a remote control to make this filter usable as a ffdshow replacement for SVP?
> If I'm the SVP developer, I wouldn't assume the only thing that can load my filter is something that has ceased development years ago. I have faith in humanity
- it is a good thing as we don't have to test every new build of ffdshow if it breaks something (which is the common case for open-source projects :D). It just works.
- we always have Vapoursynth/mpv as a backup ;)
BTW, what about passing HDR meta-data between LAV and madVR? is it possible?
----
Doesn't work correctly when the frame size is changed by the script (resize / crop). The frame size in the video player remains the same.
butterw2
6th August 2020, 13:29
@CrendKing
I'm currently looking at Avisynth+ to play video files with .avs processing. cpu usage is bit high but it can still be useful in some cases. It's simple enough, but you need a video file path in the avs file and you need a source plugin to load the video/audio.
My understanding is that your DS filter takes the frame at the video player input and allows you to process it with a specified external avs script.
Can you provide a .ax x64 build for trying it out ?
CrendKing
9th August 2020, 05:57
Any chance adding a remote control to make this filter usable as a ffdshow replacement for SVP?
> If I'm the SVP developer, I wouldn't assume the only thing that can load my filter is something that has ceased development years ago. I have faith in humanity
- it is a good thing as we don't have to test every new build of ffdshow if it breaks something (which is the common case for open-source projects :D). It just works.
- we always have Vapoursynth/mpv as a backup ;)
BTW, what about passing HDR meta-data between LAV and madVR? is it possible?
----
Doesn't work correctly when the frame size is changed by the script (resize / crop). The frame size in the video player remains the same.
I'm not sure what kind of remote control you need/ffdshow provides. Is it like API to change the script file path or reload script? Just FYI, the .avs file path is stored in registry, so you can change it and next time it will load that file. However, currently there is no way to instantly reload that file when there is playback in process (other than go into the settings page and click the button). It is easy to add some form of trigger for that, but I need to know what kind of trigger you need. For example, some Windows message? IPC? Named event?
Again FYI, as I mentioned very early in this thread, I'm working on a VapourSynth version of the filter, so you can load VS scripts into any DirectShow player. Currently the basic frame processing is working, but I need to figure out how to flush cache and fixup environment for seeking to work.
As you mention, this is a WIP, so expect bugs (and fixes).
@CrendKing
I'm currently looking at Avisynth+ to play video files with .avs processing. cpu usage is bit high but it can still be useful in some cases. It's simple enough, but you need a video file path in the avs file and you need a source plugin to load the video/audio.
My understanding is that your DS filter takes the frame at the video player input and allows you to process it with a specified external avs script.
Can you provide a .ax x64 build for trying it out ?
You can go to https://github.com/CrendKing/avisynth_filter. Download and instructions are all there.
chainik_svp
9th August 2020, 10:49
> Is it like API to change the script file path or reload script?
- set script path
- turn processing on / off
- get various info: media path, basic media info (frame size, frame rate, color format), real-time source frame rate, playback state (playing / paused)
> For example, some Windows message? IPC? Named event?
Doesn't matter, which way is simplest... ffdshow and PotPlayer work via windows messages, mpv and VLC via named pipes. IMO Windows messages are much easier to implement.
butterw2
9th August 2020, 20:58
@CrendKing
I'm currently looking at Avisynth+ to play video files with .avs processing. cpu usage is bit high but it can still be useful in some cases. It's simple enough, but you need a video file path in the avs file and you need a source plugin to load the video/audio.
My understanding is that your DS filter takes the frame at the video player input and allows you to process it with a specified external avs script.
Can you provide a .ax x64 build for trying it out ?
https://github.com/CrendKing/avisynth_filter/releases
You need to run install.bat as Admin.
For me: Works good for mp4/x264.
Some sluggishness with larger mkv after seeking.
tested on win10 with mpc-hc + evr-cp
limitation: the avs receives the frame from Lav Video Decoder. It cannot resize the frame displayed by the player.
If there is syntax error in the script, it displays the error msg (instead of just: "cannot render the frame").
CrendKing
10th August 2020, 02:08
> Is it like API to change the script file path or reload script?
- set script path
- turn processing on / off
- get various info: media path, basic media info (frame size, frame rate, color format), real-time source frame rate, playback state (playing / paused)
The first two are doable. The third one, are you talking about something like image below? It does not sound to me specific to the avs filter. For example, media path is something only a source filter can provide, rather than a transformation filter. Other media info could change between filters. Do you need pre-transform info or post-transform or both? Should we isolate into a separate filter (like the ol' deprecated ISampleGrabber)?
Also, for HDR passthrough, I need to read about it. Never done anything like that before.
https://i.imgur.com/NALncgn.jpg
https://github.com/CrendKing/avisynth_filter/releases
You need to run install.bat as Admin.
For me: Works good for mp4/x264.
Some sluggishness with larger mkv after seeking.
tested on win10 with mpc-hc + evr-cp
limitation: the avs receives the frame from Lav Video Decoder. It cannot resize the frame displayed by the player.
If there is syntax error in the script, it displays the error msg (instead of just: "cannot render the frame").
> Some sluggishness with larger mkv after seeking.
It is because after each seeking, the filter has to recreate the whole AviSynth environment just to flush stale cache. DirectShow requires filters to flush cache after seeking, and there is no API from AviSynth to do so. AviSynth is not designed to handle "seeking", but rather process the whole source in streamline fashion. I have an issue at https://github.com/AviSynth/AviSynthPlus/issues/180, but I doubt the dev would care to cater for a non-intended use case.
I could disable the cache flushing logic, but then you will get some ghost frames every time you seek.
> It cannot resize the frame displayed by the player.
You are correct. I have not implemented video dimension change from avs script. I believe it is doable.
> If there is syntax error in the script, it displays the error msg
Is this bad or you are saying it should be like this?
butterw2
10th August 2020, 09:20
> It cannot resize the frame displayed by the player.
You are correct. I have not implemented video dimension change from avs script. I believe it is doable.
It would be a nice feature to have (use fullscreen black bars space, resizers)
> If there is syntax error in the script, it displays the error msg
Is this bad or you are saying it should be like this?
It very much is a good thing.
Mpc-hc/be gives you no info about the problem when you open .avs with a syntax error.
chainik_svp
10th August 2020, 11:29
> are you talking about something like image below?
Yep
> It does not sound to me specific to the avs filter. For example, media path is something only a source filter can provide, rather than a transformation filter.
And yet SVP need to know these values somehow, and ffdshow transform filter is able to provide them
> Do you need pre-transform info or post-transform or both?
Pre-transform only
> Should we isolate into a separate filter (like the ol' deprecated ISampleGrabber)?
I don't think so...
> I have not implemented video dimension change from avs script.
BTW there's another side of this - _source_ frame size may change in runtime too. As an example - BD3D playback in MPC-BE.
clsid
10th August 2020, 13:49
You can get filename yourself.
Enumerate filters in the graph, until you find first one that implements IFileSourceFilter interface. Then use that to query filename.
https://docs.microsoft.com/en-us/windows/win32/api/strmif/nn-strmif-ifilesourcefilter
CrendKing
13th August 2020, 07:53
It would be a nice feature to have (use fullscreen black bars space, resizers)
It very much is a good thing.
Mpc-hc/be gives you no info about the problem when you open .avs with a syntax error.
Just added the support for size change. https://github.com/CrendKing/avisynth_filter/releases/tag/0.5.2.
In order to correctly recognize the size change, you need to put the new AvsFilterSizeChanged() in the script. Please read the Readme and check the example. Let me know if there's problem.
chainik_svp
13th August 2020, 11:00
> AvsFilterSizeChanged()
why? o_O can you imagine the situation when you should ignore the output clip dimensions?
CrendKing
13th August 2020, 11:34
Just added the support for size change. https://github.com/CrendKing/avisynth_filter/releases/tag/0.5.2.
In order to correctly recognize the size change, you need to put the new AvsFilterSizeChanged() in the script. Please read the Readme and check the example. Let me know if there's problem.
Just made an automatic size change detection, so no need for AvsFilterSizeChanged(). Try https://github.com/CrendKing/avisynth_filter/releases/tag/0.5.3.
> AvsFilterSizeChanged()
why? o_O can you imagine the situation when you should ignore the output clip dimensions?
There are two sources of size change, one from the avs script, and one from DirectShow upstream. If I don't make it unambiguous, the filter wouldn't know which size to use for the output pin if both sources are changing.
In the filter, there are two phases that output pin type could change. One is during type negotiation. The other is during transform. For type negotiation, the filter used to simply copy the input dimension to generate the output type. For the dynamic type change during transform, it was also copied.
In 0.5.2, AvsFilterSizeChanged() determines if upstream input or avs output dimension is used for both phases.
In 0.5.3, the filter detects if the upstream input dimension equals the avs output dimension in negotiation phase. If changed, it will use avs output dimension from then on. If not, it will use upstream input dimension from then on (which means if the dynamic change happens during transform, it will correctly update).
Note the detection does not happen in transform phase. So it is not supported to load a non-size-changing script at beginning, change the script to size changing then click the "Reload" button and expect the whole player window change. It is probably possible with some dynamic renegotiation logic, but I feel overengineering to support such a rare case.
chainik_svp
13th August 2020, 11:55
> if the dynamic change happens during transform, it will correctly update
in my understanding:
1. the filter must always use AVS output clip dimensions
2. "if the dynamic change happens during transform" the filter MUST reload AVS script and update the output dimensions according to the updated AVS output clip
in any case the situation when filter's output dimension is different from AVS output dimension is _wrong_
CrendKing
13th August 2020, 13:59
> if the dynamic change happens during transform, it will correctly update
in my understanding:
1. the filter must always use AVS output clip dimensions
2. "if the dynamic change happens during transform" the filter MUST reload AVS script and update the output dimensions according to the updated AVS output clip
in any case the situation when filter's output dimension is different from AVS output dimension is _wrong_
You are correct. FYI, currently the filter does reload avs if dynamic type change happens. I did not put any extra logic around that code block because I assumed most size changing logic from avs script should be unconditional towards the "upstream size changing". What I mean is, remember there is already a detection at negotiation phase. If the script replaces the clip with a ColorBars(), the changing is already picked. The output type is already guaranteed to be the same as avs from then on (thanks to the mark I mentioned). The only thing there would be an off is when the avs script would conditionally replaces the clip with ColorBars() if the input video size does not match the original size but matches the dynamically changed one.
For example, suppose I'm playing a 640x480 video. There is dynamic change during transform to 630x470. The following avs script should work correctly:
return ColorBars(320, 240, "YV12")
This script would fail with 0.5.3:
AvsFilterSource()
if (Width == 630) {
return ColorBars(320, 240, "YV12")
}
return last
Your suggestion should work in both cases, so I probably should use that instead.
Hmm, when trying the example, I noticed that the filter does not handle pixel type change either (the "YV12" is necessary). I should fix that too.
chainik_svp
13th August 2020, 14:08
> The following avs script should work correctly:
replace ColorBars() with Crop() and even the simple "return Crop(...)" will fail with the current approach
so you definitely have to reload script and re-init the output in case the input was changed
CrendKing
14th August 2020, 07:11
Can you post the full script? I tried this and seems OK:
AvsFilterSource()
return Crop(10, 20, 320, 240)
I ask because ColorBars() is a source function but Crop() is a transformation function. Simply replacing one with the other will not work.
I'm gonna rework the code anyways. Just want more test cases to verify once done. Thanks.
CrendKing
15th August 2020, 18:50
Release https://github.com/CrendKing/avisynth_filter/releases/tag/0.5.4 for better handling of the format change. Please read the note and test. Thanks.
chainik_svp
15th August 2020, 20:34
I'd also expect it to update the output format after changing the script and pressing "reload".
---
Doesn't work correctly when input format changed in runtime.
Easy (well, probably not that "easy" :D) way to reproduce: MPC-BE + any BD3D ISO + Intel's MVC decoder.
Start playback, switch modes in View -> Stereo 3D modes between "Mono" (1920*1080) and "OverUnder" (1920*2160).
mono -> overunder = crash
overunder -> mono = image distortion
CrendKing
15th August 2020, 23:36
It is expected because currently all format change is dynamic changes, as explained in https://docs.microsoft.com/en-us/windows/win32/directshow/queryaccept--downstream, you can't "drastic changes to the format, such as changing the bit depth". The downstream filter may not be able to handle the format change without completely stopping the stream and reconnect the pins with new media type. Some filters/renderers support "dynamic pin reconnection", but not all of them. My thought process was "these players already have a key bind or button for reopening the current file, which does exactly the stop-reload-play thing. Why should I repeat the whole process in a transform filter?"
If anyone has code that can make what you described work and easy to implement (in case I'm missing some obvious tricks), I'm all ears as long as their license allows me to copy of course. I just don't want to put 1000 lines of code to a piece of software that is 1500 lines in total for maybe less than 1% of usage.
chainik_svp
16th August 2020, 10:40
what I personally know at this point is it works in ffdshow
and it definitely will be necessary for SVP to work correctly
+++
ConvertToYUV420()
ConvertBits(10)
doesn't work - the filter won't attach to the graph
only works with ConvertBits(16)
CrendKing
17th August 2020, 07:28
I'll try the dynamic format change in ffdshow see how's it work.
About the ConvertBits(10) issue, I actually have a discussion with AviSynthPlus guys at https://github.com/AviSynth/AviSynthPlus/issues/146. Basically, both the P010 and P016 types are internally represented as CS_YUV420P16 in AviSynth. Therefore the filter only supports converting CS_YUV420P16 back to P010.
ConvertBits(10) converts the format to CS_YUV420P10. Because there is no format for it to convert to, the filter disconnects from the graph. However, since P010 is basically P016 with 6 bits padded as 0, there is no downside of always using ConvertBits(16).
ffdshow only supports limited number of output types, and 10 bits and 16 bits compressed formats are not among them. All these are converted to NV12, which cause the picture to have green artifacts.
My reasoning of only supporting the few popular AviSynth formats is that AviSynth already has a excellent set of convert functions (http://avisynth.nl/index.php/Convert). It is much easier for user to add a line of ConvertXXX() at the end of the script, than reimplement those convert functions in the filter again. Plus the mapping between DirectShow media types and AviSynth formats are not one-to-one mapping. Here's some examples:
AviSynth CS_YV12 can be losslessly converted to NV12, YV12, I420 or IYUV. Which one should be right output type?
Both P010 and P016 are represented as AviSynth CS_YUV420P16.
How to convert CS_YUV9 to a reasonable DirectShow type? Do we choose a 4:1:1 format such as NV11 or a 4:2:0 format such as NV12? What if NV11 is less lossy but the renderer does not support it?
chainik_svp
17th August 2020, 08:47
> It is much easier for user to add a line of ConvertXXX()
still P010 is the most popular format for high bit depth video, e.g. 4K/HDR, why adding _unnecessary_ conversion P010->P016?
besides, EVR renderer doesn't seems to work with P016 o_O
> Plus the mapping between DirectShow media types and AviSynth formats are not one-to-one mapping. Here's some examples:
> Which one should be right output type?
the one that needs less work
===
re-read that "Does AviSynth+ internally support P010?" conversation... :)
so the problem is the filter gets left-shifted pixels from a decoder? in this case doing a conversion to "true" P010 would be an extra step, I agree
I was just confused because in mpv and VLC, P010 is "true" P010, w/o this "microsoft-specific"...
+++
when working in P010, EVR renderer won't load for some reason
CrendKing
17th August 2020, 19:42
> still P010 is the most popular format for high bit depth video, e.g. 4K/HDR, why adding _unnecessary_ conversion P010->P016?
> I was just confused because in mpv and VLC, P010 is "true" P010, w/o this "microsoft-specific"...
Basically it is a incompatibility between AviSynth and Microsoft. AviSynth treats CS_YUV420P10 as little-endian P010, where Microsoft treats as big-endian. You can imagine that we can write some function to traverse every 16 bits of the buffer and flip the endian to truly support the P010 in AviSynth, but is it really worth the effort and performance cost? P010 is P016 with 6 bits of zero. There is no conversion.
> besides, EVR renderer doesn't seems to work with P016 o_O
It shouldn't be a problem. Here is how my filter works with formats. Basically there are sets of mappings from {DS input type} -> {AviSynth format} -> {DS output type}. During pin connection, the filter will supply all compatible pairs of mappings that shares the same intermediate AviSynth format to upstream and downstream. And upstream/downstream can choose whichever they support/prefer to complete the connection.
Take CS_YUV420P16 as example. In DS side, it can be either P010 or P016. So if upstream wants to connect with P016 but downstream wants P010, that's completely fine. P010 -> CS_YUV420P16 -> P016 also works. The only thing it does not work out of the box is something like NV12 -> ??? -> P016. In this case, I'll have to ask the user to put a ConvertP016() at the end of their script.
BTW, I just make quite some changes for the dynamic format thingy. Could you try https://github.com/CrendKing/avisynth_filter/releases/tag/0.5.5? I verified the MVC scenario you mentioned should be working now.
chainik_svp
17th August 2020, 20:58
Regarding EVR - no idea why it won't attach to the graph when avisynth_filter is enabled. It definitely works with simple P010 source -> EVR config, but doesn't like P010 source -> avs (P010) -> EVR. Basic VMR is selected instead, and it doesn't work either, producing corrupted image.
> I verified the MVC scenario you mentioned should be working now.
Seems to work when switching from double frame to mono, but still crashes switching from 1920*1080 to 1920*2160
clsid
17th August 2020, 23:36
P010/P016 does not work well with EVR/VMR renderers. Use NV12 instead. You should output P010/P016 only when connecting to madVR or MPCVR.
Example code from LAV:
https://github.com/clsid2/LAVFilters/blob/master/decoder/LAVVideo/LAVVideo.cpp#L1064
CrendKing
18th August 2020, 00:01
About the EVR issue:
https://i.imgur.com/7Y5rQTU.jpg
About mono to double:
https://streamable.com/crghkh
Used script:
AvsFilterSource()
return Info()
CrendKing
18th August 2020, 00:02
P010/P016 does not work well with EVR/VMR renderers. Use NV12 instead. You should output P010/P016 only when connecting to madVR or MPCVR.
If needed, user can always tick off the P010 and P016 formats in the option page if they use EVR/VMR. It will automatically fallback to NV12.
chainik_svp
18th August 2020, 10:24
regarding MVC:
doesn't crash with
AvsFilterSource()
return Info()
crashes with
AvsFilterSource()
crop(8,8,-8,-8)
return Info()
regarding EVR: dunno, I can't make it work o_O MPC-HC 1.9.6 if it matters...
+++
upd: EVR-CP works in MPC-BE, doesn't work in MPC-HC
+++
const REFERENCE_TIME frameTime = frameNb * llMulDiv(_videoInfo.fps_denominator, UNITS, _videoInfo.fps_numerator, 0);
return _frameHandler.GetNearestFrame(frameTime);
not sure it will work for variable frame rate videos
CrendKing
18th August 2020, 21:38
Crash: Just updated the repo. Should be working now. Let me know if you want to test it out. I can send you compiled files.
EVR: In my end, with MPC-HC, the pin just connects with NV12 format, no crash. Could it be related to video? Here's some log for pin connection:
MPC-BE
T 6324 @ 0: CAviSynthFilter::CAviSynthFilter()
T 6324 @ 6: Add acceptable input definition: 0
T 6324 @ 6: Add acceptable output definition: 0
T 6324 @ 6: Add compatible definitions: input 0 output 0
T 6324 @ 6: Add acceptable output definition: 1
T 6324 @ 6: Add compatible definitions: input 0 output 1
T 6324 @ 6: Add acceptable output definition: 2
T 6324 @ 6: Add compatible definitions: input 0 output 2
T 6324 @ 6: Add acceptable output definition: 3
T 6324 @ 6: Add compatible definitions: input 0 output 3
T 6324 @ 6: Reject input definition due to settings: 6
T 6324 @ 6: Reject input definition due to settings: 9
T 6324 @ 8: Add acceptable input definition: 4
T 6324 @ 8: Add acceptable output definition: 4
T 6324 @ 8: Add compatible definitions: input 4 output 4
T 6324 @ 8: Add acceptable output definition: 5
T 6324 @ 8: Add compatible definitions: input 4 output 5
T 6324 @ 8: Reject input definition due to settings: 5
T 6324 @ 8: Accept input definition: 0
T 6324 @ 8: Accept input definition: 0
T 6324 @ 8: Connected input pin with definition: 0
T 6324 @ 8: Offer output definition: 0
T 6324 @ 8: Offer output definition: 1
T 6324 @ 8: Offer output definition: 2
T 6324 @ 8: Offer output definition: 3
T 6324 @ 8: Offer output definition: 4
T 6324 @ 8: Offer output definition: 5
T 6324 @ 8: Offer output definition: 0
T 6324 @ 8: Offer output definition: 1
T 6324 @ 8: Offer output definition: 2
T 6324 @ 8: Offer output definition: 3
T 6324 @ 8: Offer output definition: 4
T 6324 @ 9: Offer output definition: 5
T 6324 @ 9: CAviSynthFilter::CAviSynthFilter()
T 6324 @ 14: Offer output definition: 0
T 6324 @ 14: Accept transform: out 0
T 6324 @ 14: Accept transform: out 0
T 6324 @ 18: Offer output definition: 1
T 6324 @ 18: Accept transform: out 1
T 6324 @ 18: Accept transform: out 1
T 6324 @ 18: Offer output definition: 2
T 6324 @ 18: Accept transform: out 2
T 6324 @ 18: Accept transform: out 2
T 6324 @ 18: Offer output definition: 3
T 6324 @ 18: Accept transform: out 3
T 6324 @ 18: Accept transform: out 3
T 6324 @ 18: Offer output definition: 4
T 6324 @ 18: Accept transform: out 4
T 6324 @ 18: Accept transform: out 4
T 6324 @ 18: Offer output definition: 5
T 6324 @ 18: Accept transform: out 5
T 6324 @ 18: Accept transform: out 5
T 6324 @ 99: Offer output definition: 0
T 6324 @ 99: Accept transform: out 0
T 6324 @ 99: Accept transform: out 0
T 6324 @ 99: Accept transform: out 0
T 6324 @ 109: Connected with types: in 0 out 0
MPC-HC
T 16700 @ 1: CAviSynthFilter::CAviSynthFilter()
T 16700 @ 19: Add acceptable input definition: 4
T 16700 @ 19: Add acceptable output definition: 4
T 16700 @ 19: Add compatible definitions: input 4 output 4
T 16700 @ 19: Add acceptable output definition: 5
T 16700 @ 19: Add compatible definitions: input 4 output 5
T 16700 @ 19: Reject input definition due to settings: 5
T 16700 @ 19: Reject input definition due to settings: 5
T 16700 @ 23: Add acceptable input definition: 0
T 16700 @ 23: Add acceptable output definition: 0
T 16700 @ 23: Add compatible definitions: input 0 output 0
T 16700 @ 23: Add acceptable output definition: 1
T 16700 @ 23: Add compatible definitions: input 0 output 1
T 16700 @ 23: Add acceptable output definition: 2
T 16700 @ 23: Add compatible definitions: input 0 output 2
T 16700 @ 23: Add acceptable output definition: 3
T 16700 @ 23: Add compatible definitions: input 0 output 3
T 16700 @ 23: Reject input definition due to settings: 6
T 16700 @ 23: Reject input definition due to settings: 6
T 16700 @ 23: Reject input definition due to settings: 7
T 16700 @ 23: Reject input definition due to settings: 7
T 16700 @ 23: Reject input definition due to settings: 9
T 16700 @ 23: Reject input definition due to settings: 9
T 16700 @ 23: Reject input definition due to settings: 8
T 16700 @ 23: Reject input definition due to settings: 8
T 16700 @ 23: Reject input definition due to settings: 10
T 16700 @ 23: Reject input definition due to settings: 10
T 16700 @ 23: Accept input definition: 4
T 16700 @ 23: Accept input definition: 4
T 16700 @ 23: Connected input pin with definition: 4
T 16700 @ 24: Offer output definition: 4
T 16700 @ 24: Offer output definition: 5
T 16700 @ 24: Offer output definition: 0
T 16700 @ 24: Offer output definition: 1
T 16700 @ 24: Offer output definition: 2
T 16700 @ 24: Offer output definition: 3
T 16700 @ 24: CAviSynthFilter::CAviSynthFilter()
T 16700 @ 192: Offer output definition: 4
T 16700 @ 192: Accept transform: out 4
T 16700 @ 192: Accept transform: out 4
T 16700 @ 192: Offer output definition: 5
T 16700 @ 192: Accept transform: out 5
T 16700 @ 192: Accept transform: out 5
T 16700 @ 192: Offer output definition: 0
T 16700 @ 192: Accept transform: out 0
T 16700 @ 192: Accept transform: out 0
T 16700 @ 209: Offer output definition: 4
T 16700 @ 209: Offer output definition: 5
T 16700 @ 209: Offer output definition: 0
T 16700 @ 209: Offer output definition: 1
T 16700 @ 209: Offer output definition: 2
T 16700 @ 209: Offer output definition: 3
T 16700 @ 209: Reconnect with types: old in 4 new in 0 out 0
T 16700 @ 209: Accept transform: out 0
T 16700 @ 209: Accept transform: out 0
T 16700 @ 209: Reject input definition due to settings: 5
T 16700 @ 209: Reject input definition due to settings: 5
T 16700 @ 210: Reject input definition due to settings: 6
T 16700 @ 210: Reject input definition due to settings: 6
T 16700 @ 210: Reject input definition due to settings: 7
T 16700 @ 210: Reject input definition due to settings: 7
T 16700 @ 210: Reject input definition due to settings: 9
T 16700 @ 210: Reject input definition due to settings: 9
T 16700 @ 210: Reject input definition due to settings: 8
T 16700 @ 210: Reject input definition due to settings: 8
T 16700 @ 210: Reject input definition due to settings: 10
T 16700 @ 210: Reject input definition due to settings: 10
T 16700 @ 210: Accept input definition: 0
T 16700 @ 210: Accept transform: out 0
T 16700 @ 210: Accept input definition: 0
T 16700 @ 210: Connected with types: in 0 out 0
Notice for MPC-HC, there is the "Reconnect with types: old in 4 new in 0 out 0". Format 4 is P010. 0 is NV12. As to why such different behavior, maybe clsid has some idea?
Variable frame rate video: I don't have any experience about this. Do you have any sample video? How does ffdshow behave? Does it treat like dynamic format change?
###################
By the way, since you know about SVP, I have a question. When I put SVSmoothFps_NVOF() in script, and NOT recreate the avs environment every time I connect pin or seek, the filter just freezes. If I do recreate, everything works line. I have a little comment about it in filter.cpp. However, the SVSuper() -> SVAnalyse() -> SVSmoothFps() triplet works regardless of recreating or not. Does SVSmoothFps_NVOF() internally have some sort of restriction that it can be only eval'd once? Like there's some singleton predicate?
clsid
18th August 2020, 21:38
MPC-HC/LAV has a workaround to disable use of P010/P016 when it is (potentially) unsupported. It only allows P010 on recent versions of Windows 10.
chainik_svp
18th August 2020, 22:09
> Variable frame rate video: I don't have any experience about this.
You'll have different frame durations for different frames :)
So your method of getting frame time from frame number, based on a fixed frame duration, will fail - it'll return wrong frames.
You need to count input frames, and return the exact frame (by number) when it's requested.
> Do you have any sample video?
Basically any anime video out there is VFR in some parts.
> How does ffdshow behave? Does it treat like dynamic format change?
It's not a format change. Since ffdshow works with frame numbers it doesn't have any problems here.
> When I put SVSmoothFps_NVOF() in script, and NOT recreate the avs environment every time I connect pin or seek, the filter just freezes.
I'll take a look...
chainik_svp
19th August 2020, 14:18
I wonder if it's really necessary to reload script so many times?
Considering the simple YV12 playback, it's reloaded:
- 4 times in CheckConnect
- 1 time in HandleInputFormatChange
- 1 time in TransformAndDeliver
total of six (6) times just to start the playback, plus one time for every set on pause (why??).
And each time SVSmoothFps have to init and destroy OpenCL context, queues, build shader programs etc., plus init/destoy CUDA context for NVOF.
I'd at least remove Reset() from pause handler... 5 times re-init is better than 6 :D
===
The "NVOF problem" - my guess is it arises from the fact that when reloading script w/o deleting the environment, the "new" filters initialization might occur before destruction of "old" filters.
chainik_svp
19th August 2020, 21:17
Regarding VFR. Just played with an anime file where frame rate is constantly floating between 24 and 30 fps, and found that IMediaSample::GetTime() is returning incorrect end-time - it's always equal to start-time plus average-time-per-frame defined in VIDEOINFOHEADER. However subtracting previous frame's start-time from the current frame's start-time gives correct value.
CrendKing
20th August 2020, 06:38
clsid: Thanks for info. However I tested in the latest Windows 10 (ver 2004) though. My MPC-HC version is 1.9.4.21 (daeb8bf8d).
VFR: "You need to count input frames, and return the exact frame (by number) when it's requested." But you are assuming the samples we receive are ordered and continuous. Upstream can give us frame #X then #X + 2 in case of frame drop. And if seek happens, all we know is the time of that frame. Why does avs take frame number instead of frame time? Does that mean avs only support CFR?
I also played a VFR video (where ffmpeg vfrdet reports "VFR:0.501632 (1076/1069) min: 3753 max: 15015 avg: 3777"). I don't see any problem during playback.
Reload: You can read my comment in filter.cpp. I hate reloading. It destroys performance. But I think every single one of them is necessary.
CheckConnect: Reason why reload is to feed the script new input format. Each time the upstream gives me a new media type. I need to run through the script to get the corresponding output format, then feed it to downstream. Good news is these reload only reload the script, not the whole avs environment (because there is no frame generated yet).
HandleInputFormatChange: Same reason as above. New input media type, thus reload. Bad news, since the playback is already started, there could be frames inside avs. To flush the cache, we need to reload the whole thing. Maybe one day we will get some answer from https://github.com/AviSynth/AviSynthPlus/issues/180.
TransformAndDeliver: This is for Pause(). As you may know, the DirectShow document (https://docs.microsoft.com/en-us/windows/win32/directshow/flushing) specifically requires filters to "discard any samples that were created before the seek command". We could flush cached frames in our filter, but we can't control any caching in avs. Thus a full reload is done every time user seeks. You could argue that it is not strictly "necessary", but then you will encounter the same ghost frame problem as in ffdshow, that after seeking you still see a bunch of frames around the time before seeking. I'd rather the seek taking a bit of time than seeing wrong frames.
NVOF: You are correct full reload works. The first 5 reloads (being full or not) are not the concern because they are generally not user visible (usually one time per playback). However, if every time we completely reload the environment there is no problem. But doing full reload in Pause() will impose unbearable latency for seeking. So either AviSynth gives us proper flushing method, NVOF somehow can do without full reload, or use NVOF with ghost frame.
chainik_svp
20th August 2020, 08:34
> Thus a full reload is done every time user seeks.
seek != pause
> I don't see any problem during playback.
and still you
1. fetch the wrong frames using fixed frameTime value while converting requested frame number to timestamp
2. pass a cfr sequence to downstream
CrendKing
20th August 2020, 11:03
> Thus a full reload is done every time user seeks.
seek != pause
Fixed and pushed.
> I don't see any problem during playback.
and still you
1. fetch the wrong frames using fixed frameTime value while converting requested frame number to timestamp
2. pass a cfr sequence to downstream
I get what you are saying, but I don't understand how to reconcile between DS and AVS. From what I see (http://avisynth.nl/index.php/VFR), AVS only supports CFR, otherwise it would not use frame number to getFrame(). So feeding any VFR to AVS would only get out CFR. Am I wrong?
chainik_svp
20th August 2020, 13:40
> So feeding any VFR to AVS would only get out CFR. Am I wrong?
you feed AVS with a frame sequence and you get another frame sequence back, it's up to you how to set timestamps
what I know is ffdshow somehow managed to deal with VFR input/output
https://github.com/jeeb/ffdshow-tryouts/blob/422a13650bb3d3c986e21e3abad210e7d815ebdf/src/imgFilters/avisynth/TimgFilterAvisynth.cpp#L975
CrendKing
20th August 2020, 23:01
I get it now. Basically we need to calculate the output frame duration ourselves, by applying the avs scaling (where the scaling itself is fixed at e.g. 2x, 1.5x, etc) to the source frame duration. And to get the frame number, we need to count from start or last seek point, instead of relying on the average frame duration, which is just a statistic number and rather meaningless. And for seeking, I don't need to care about anything before seeking. Just rebuild the frame queue from anew.
edcrfv94
28th November 2020, 13:03
VapourSynth multithreading stable than AviSynth, maybe supporting VapourSynth is a better idea.
real.finder
28th November 2020, 16:42
VapourSynth multithreading stable than AviSynth, maybe supporting VapourSynth is a better idea.
not anymore, I don't see any problem in multithreading stablety in AviSynth+ 3.6.2-test4 20201112
CrendKing
29th November 2020, 14:45
VapourSynth multithreading stable than AviSynth, maybe supporting VapourSynth is a better idea.
Do you mean AviSynth is not stable in general, or specifically in this filter's use case? If latter, can you open an issue in the repo so I can understand the problem.
Technically I could create a version of this filter that uses VapourSynth instead of AviSynth as the frame server (I have a working internal version but extremely buggy, not actively working on it), but since it pulls in Python in runtime thus way heavier in footprint, I need some good use case and incentive to do that work.
edcrfv94
2nd December 2020, 04:27
Do you mean AviSynth is not stable in general, or specifically in this filter's use case? If latter, can you open an issue in the repo so I can understand the problem.
Technically I could create a version of this filter that uses VapourSynth instead of AviSynth as the frame server (I have a working internal version but extremely buggy, not actively working on it), but since it pulls in Python in runtime thus way heavier in footprint, I need some good use case and incentive to do that work.
My computer is currently unavailable.
Currently, VapourSynth HDB support and multithreading are much better than AviSynth+.
You can try some complex script with multithreading e.g: QTGMC + fslg_quick_denoise + mcDAA3.
real.finder
2nd December 2020, 07:02
My computer is currently unavailable.
Currently, VapourSynth HDB support and multithreading are much better than AviSynth+.
You can try some complex script with multithreading e.g: QTGMC + fslg_quick_denoise + mcDAA3.
I do use complex scripts (using QTGMC, mcDAA3 and others) most of times and I can say that there are no problem these days in avs+ mt
HDB support maybe not as the vs one since there are few plugins need to add HBD in avs+, but again it's way better than 2019, since https://github.com/Asd-g?tab=repositories did added a lot since then
CrendKing
3rd December 2020, 19:49
Also remember that since the use case here is real-time video playing, having complex script that requires significant CPU time would jeopardize your experience. For instance, playing a 60 fps video means you can't spend more than 16.6ms per frame on both decoding, avs and rendering, or you will start to drop frames. So essentially we only need to concern about a very subset of functionality. As long as this subset is stable, it's fine.
cork_OS
5th December 2020, 14:10
Hello.
I've faced several problems with AVSF, not sure where to report it.
1. On the new PC manually installed AVSF didn't appear in the player's filters list (and don't work) until activate_remote_control.reg is applied. Is it a bug or a feature?
2. Player hangs on start if this script is loaded:
AvsFilterSource()
TDecimate(mode=2, rate=23.976)
prefetch()
If TDecimate string is commented on player start and uncommented after playback starts, the video with script reloaded in real-time runs ok (audio sync not tested).
3. QTGMC and ApparentFPS work great individually, but not in one script.
This script plays choppy, but seeking works:
AvsFilterSource()
QTGMC()
ApparentFPS()
prefetch()
This script plays smoothly, but player hangs on seek:
AvsFilterSource()
QTGMC()
prefetch()
ApparentFPS()
AVS+ 3.6.1, AVSF 0.8.2. TDecimate problem tested on two PCs with different players/renderers (MPC-HC+madVR/MPC-BE+EVR-CP).
StainlessS
5th December 2020, 17:36
I cant remember what AvsFilterSource() is, but suggest RequestFramesLinear() [with appropriate cache args] inserted after AvsFilterSource.
Before and After cache args might best be at least the framerate of the source clip. [maybe]
EDIT: or maybe if still probs, try at least the framerate of the source clip * Prefetch.
EDIT: Note, ApparentFPS() has to access 2*FrameRate [by default] frames everytime you jump about, hence hang
especially due to QTGMC doing its stuff for each of those.
EDIT: ApparentFPS() wil need linear access, need set as such in your SetMTMode.avs thing. [MT_SERIALIZED]
so probably best placed AFTER Prefetch().
CrendKing
6th December 2020, 11:05
Hello.
I've faced several problems with AVSF, not sure where to report it.
Please report to https://github.com/CrendKing/avisynth_filter/issues/new/choose. There is bug report template to ask you information I need.
1. On the new PC manually installed AVSF didn't appear in the player's filters list (and don't work) until activate_remote_control.reg is applied. Is it a bug or a feature?
There are other people report installation not working. Some were due to lack of Visual C++ runtime. activate_remote_control.reg should have nothing to do with it. If it's true, it's bug. Please report and we track there.
2. Player hangs on start if this script is loaded:
I thought "Prefetch" has required thread number argument. Have you tried adding it?
I've tested FDecimate2 before, but never tested TDecimate. Please report on separate issue.
However, we should first solve the installation issue. I'm not even sure you are actually loaded the filter in its expected state.
This script plays smoothly, but player hangs on seek:
I thought "prefetch" must be the last statement in a script. Am I wrong? Reference: http://avisynth.nl/index.php/AviSynth%2B:
You enable MT by placing a single call to Prefetch(X) at the end of your script, where X is the number of threads to use.
I cant remember what AvsFilterSource() is
It is the source function added by this filter: https://github.com/CrendKing/avisynth_filter#avsfiltersource. It feeds source samples from upstream DirectShow filter to AviSynth engine.
StainlessS
6th December 2020, 17:04
I thought "Prefetch" has required thread number argument. Have you tried adding it?
Prefetch has a default value, which is number of Physical CPUs + 1.
NOTE, I think 'Physical CPUs' is meaning 'Physical Cores'.
Eg, a machine might have 2 physical Xeon CPUs, each with 6 physical cores and 6 logical cores, 12 physical [EDIT: total] cores per CPU, or
24 threads/cores total machine.
Dont know if Physical_CPUs means physical_cores in single CPU, or eg total number of physical cores in multi CPU Xeon system.
From Avisynth.cpp
size_t __stdcall ScriptEnvironment::GetProperty(AvsEnvProperty prop)
{
switch(prop)
{
case AEP_FILTERCHAIN_THREADS:
return (prefetcher != NULL) ? prefetcher->NumPrefetchThreads()+1 : 1;
case AEP_PHYSICAL_CPUS:
return GetNumPhysicalCPUs();
case AEP_LOGICAL_CPUS:
return std::thread::hardware_concurrency();
case AEP_THREAD_ID:
return 0;
case AEP_THREADPOOL_THREADS:
return thread_pool->NumThreads();
case AEP_VERSION:
return AVS_SEQREV;
default:
this->ThrowError("Invalid property request.");
return std::numeric_limits<size_t>::max();
}
assert(0);
}
Also see GetProperty in avisynth.h
EDIT: Not available for Avs Standard v2.60 (dont know about v2.61).
I thought "prefetch" must be the last statement in a script.
Prefetch() is just an pretty standard filter which takes as its first argument a video clip,
it is more usually called with implicit Last clip, it also returns a video clip, and has never had to be final filter in script,
although that has been its usual use in the past.
I'm pretty sure that there was a Pinterf post [which I did not find] that showed multiple use of Prefetch in single script,
multi-use was quite recent mod to avs+. [EDIT: I only searched Devs forum, maybe was in Usage]
Quote by Pinterf, [cant directly quote a closed thread any more ???]:- https://forum.doom9.org/showthread.php?p=1904672#post1904672
Prefetch (clip c, int threads, int "frames")
In the original Plus, you could use only one Prefetch, but you can use any number of CUDA versions.
Also, an argument has been added to specify the number of frames to prefetch.
Prefetch (1,4) # Make 1 thread stand and prefetch 4 frames
By doing so, flexible parallelization configuration is possible, such as pipeline parallelization.
threads
Number of threads. If it is 0, it passes without doing anything.
frames
Number of frames to prefetch.
Again, if it is 0, it passes without doing anything.
Note above clip c,
and threads default = physical cores + 1, frames default is presumably 1 [although defaults tend not to be shown]
EDIT: Threads is Optional, should be enclosed in double quotes.
Prefetch (clip c, int "threads"=Physical_cores+1, int "frames"=1) # returning video clip
EDIT: I'm guessin that Physical_Cores might mean physical cores in a single CPU.
It is the source function added by this filter
Thanks.
clsid
6th December 2020, 18:00
There are other people report installation not working. Some were due to lack of Visual C++ runtime.I really recommend to use static linking. Pretty much every DirectShow filter uses static linking. Requiring runtimes is really annoying for distribution and also a support nightmare.
CrendKing
6th December 2020, 19:01
I really recommend to use static linking. Pretty much every DirectShow filter uses static linking. Requiring runtimes is really annoying for distribution and also a support nightmare.
Good suggestion. I didn't bother to change the default from Visual Studio. Now you mention it, next version will be statically linked.
CrendKing
7th December 2020, 05:06
2. Player hangs on start if this script is loaded:
The reason why it hangs is because the plugin tries to get frame on it own whenever the script is imported. However, the filter needs to import script during initialization phase to determine video info, when the source samples are not yet available. It becomes a chicken egg problem.
I could make it not hang by providing fake empty frame during initialization, and switch to real frame after, but I think you might be better just use FDecimate2 instead, if that's an option. I can give you a test build if you want.
cork_OS
7th December 2020, 14:55
I could make it not hang by providing fake empty frame during initialization, and switch to real frame after, but I think you might be better just use FDecimate2 instead, if that's an option. I can give you a test build if you want.
Unfortunately, FDecimate2 fails in my very simple 1-in-5 case where TDecimate instead works perfectly with default settings. Additionally, TDecimate has a very informative display (debug) mode. So it would be great to make AVSF TDecimate compatible. However, if requesting a frame on filter initialization is bad practice, maybe it's better to ask pinterf to fix TDecimate instead?
EDIT: ApparentFPS() wil need linear access, need set as such in your SetMTMode.avs thing. [MT_SERIALIZED]
so probably best placed AFTER Prefetch().
I've added SetFilterMTMode("ApparentFPS", MT_SERIALIZED) string to script, nothing changed.
CrendKing
7th December 2020, 18:04
requesting a frame on filter initialization is bad practice
It's not necessarily bad practice, because for conventional avs usage the source video file is probably always available. It is just not very compatible with the video playing use case.
You can try https://github.com/CrendKing/avisynth_filter/files/5653636/AviSynthFilter.zip if that fixes the TDecimate problem. It shouldn't hang, and I can see FPS change to 24, but I can't guarantee if every part of TDecimate is working properly.
I'll tend to the other one later. Maybe you can submit an issue for tracking purpose?
cork_OS
7th December 2020, 20:53
You can try https://github.com/CrendKing/avisynth_filter/files/5653636/AviSynthFilter.zip if that fixes the TDecimate problem. It shouldn't hang, and I can see FPS change to 24, but I can't guarantee if every part of TDecimate is working properly.
Thanks, it works.
Interestingly, TDecimate injected into SVP generated script doesn't hang with the previous AVSF version.
I'll tend to the other one later. Maybe you can submit an issue for tracking purpose?
Sure, I'll do it now.
StainlessS
7th December 2020, 23:15
I've added SetFilterMTMode("ApparentFPS", MT_SERIALIZED) string to script, nothing changed.
Yeh, and how bout RequestFramesLinear() ?
sappyyy
16th October 2021, 10:26
Here's autohotkey code to control - switch on/off - avisynthfilter from the player. PotPlayer taken as an example, replace with your .avs path,
remote control should be enabled
StrPutVar(string, ByRef var, encoding)
{
; Ensure capacity.
VarSetCapacity( var, StrPut(string, encoding)
; StrPut returns char count, but VarSetCapacity needs bytes.
* ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
; Copy or convert the string.
return StrPut(string, &var, encoding)
}
;-------------------------------------------------------------------------------
send_WM_COPYDATA(Code, Str, WinId) { ; send string via WM_COPYDATA
;-------------------------------------------------------------------------------
DetectHiddenWindows, On
avsfilter := WinExist(WinId)
VarSetCapacity(COPYDATASTRUCT, A_PtrSize * 3, 0)
NumPut(Code, COPYDATASTRUCT)
if Str > 0
{
Numput(StrPutVar(Str, Str, "cp0"), COPYDATASTRUCT, A_PtrSize)
NumPut(&Str, COPYDATASTRUCT, A_PtrSize * 2)
SendMessage, 0x4a, A_ScriptHwnd, ©DATASTRUCT,, ahk_id %avsfilter%
}
else
SendMessage, 0x4a, A_ScriptHwnd, ©DATASTRUCT,, ahk_id %avsfilter%
}
#IfWinActive, ahk_exe potplayermini64.exe
Q::
DetectHiddenWindows, On
potavsfilter := WinExist("ahk_class AvsFilterRemoteControlClass ahk_exe potplayermini64.exe")
if potavsstate != %potavsfilter%
{
potavstoggle = 0
Send_WM_COPYDATA(403,"C:\Progs\PotPlayer\AviSynth\work\pot.avs","ahk_class AvsFilterRemoteControlClass ahk_exe potplayermini64.exe")
potavsstate = %potavsfilter%
}
else
if potavstoggle = 1
{
potavstoggle = 0
Send_WM_COPYDATA(403,"C:\Progs\PotPlayer\AviSynth\work\pot.avs","ahk_class AvsFilterRemoteControlClass ahk_exe potplayermini64.exe")
potavsstate = %potavsfilter%
}
else
{
potavstoggle = 1
Send_WM_COPYDATA(403,0,"ahk_class AvsFilterRemoteControlClass ahk_exe potplayermini64.exe")
}
return
flossy_cake
3rd November 2022, 03:50
Is it possible to get the filepath of the video being played so that we can apply per-file/folder processing? I saw this question was asked earlier by chainik_svp but didn't see to have an answer, only this:
You can get filename yourself.
Enumerate filters in the graph, until you find first one that implements IFileSourceFilter interface. Then use that to query filename.
https://docs.microsoft.com/en-us/windows/win32/api/strmif/nn-strmif-ifilesourcefilter
Also here (https://drive.google.com/file/d/1WfW3yXmGhIvUCiexQGYD18gSiXRe2bze/view?usp=share_link) is a test clip 720x576 square pixels 1.25:1 according to MediaInfo and MadVR, but running it through CrendKing's Avisynth filter results in slightly squished 1.22:1 aspect & MadVR reporting 1.22:1 also.
edit: how it should look:
https://i.ibb.co/ckGsCqs/1.png
After Avisynth plugin with propShow():
https://i.ibb.co/zNLwTxL/2.png
https://i.ibb.co/TWTGRjf/3.png
CrendKing
10th November 2022, 03:16
Handled in GitHub. Should be fixed in v1.4.6.
flossy_cake
10th November 2022, 14:05
Thanks a lot. Looks like I'll be migrating all my scripts across and using Avisynth this way from now on :)
Here is a template for noobs like myself
# main.avs
AvsFilterSource() # replaces DirectShowSource() etc.
if (FindStr(AvsFilterGetSourcePath(), "Series\Comedy\(2001-2003) The Office") != 0){
Import("The Office.avs")
}
else if (FindStr(AvsFilterGetSourcePath(), "Series\Comedy\(2005-2007) Extras") != 0){
Import("Extras.avs")
}
else {
AvsFilterDisconnect()
}
# FindStr() is case-sensitive.
# The Office.avs
Subtitle("Now playing: The Office", last_frame=int(5*last.FrameRate)) # show for 5 seconds
# Extras.avs
Subtitle("Now playing: Extras", last_frame=int(5*last.FrameRate))
Then in CrendKing's Avisynth filter GUI point it to main.avs.
Note that resizing works differently now since the filter passes on aspect ratio metadata to the renderer. eg. no need to scale NTSC 4:3 720x480 to 720x540, but there may be an upcoming override for that to force square pixels for backwards compatibility with existing scripts (link (https://github.com/CrendKing/avisynth_filter/issues/81))
flossy_cake
11th November 2022, 09:27
Note that resizing works differently now since the filter passes on aspect ratio metadata to the renderer. eg. no need to scale NTSC 4:3 720x480 to 720x540, but there may be an upcoming override for that to force square pixels for backwards compatibility with existing scripts (link (https://github.com/CrendKing/avisynth_filter/issues/81))
Actually letting the renderer perform the DAR correction has an added benefit in that it allows deinterlacing to be performed by the renderer (eg. MadVR's film mode and DXVA deint). Whereas if the renderer already receives the aspect-corrected 720x540 from Avisynth, the field alignment is ruined and deinterlacing cannot be done after this point.
Although it would be possible to workaround it by instead performing the DAR correction manually in MadVR using its "screen config" setting, but this is a bit convoluted and would require making multiple "screen config" profiles in MadVR.
flossy_cake
11th November 2022, 10:17
Spoke too soon.
It seems the Avisynth frame counter resets to 0 every time we seek. This breaks a lot of things.
*sigh*
Hoping it can be fixed, but I'm not gonna get my hopes up.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.