View Full Version : SelectOdd - SelectEven question
jollye
10th December 2008, 16:15
Hi,
I've got a small question to AviSynth experts. It's about SelectOdd or SelectEven. My script looks like the following:
clip=AviSource("mysource.avi")
clip=MyFilter(clip)
clip=SelectOdd(clip)
return clip
This works fine. However, the filter I've developped (MyFilter) will work fine only if all the consecutive frames are asked to it. But at the output, I only want to see the odd frames. What I see is that AviSynth doesn't drop the frames at the output but seems to ask MyFilter only for odd frames.
Is there any means to change this behaviour without writing my own custom version of SelectOdd (that would ask the preceding filter in the chain for odd and even frames even if it returns only odd frames to the filter after itself).
Thanks in advance for your advices.
Gavino
10th December 2008, 16:47
Avisynth is designed to work this way. As a frame server, it delivers frames on request. To meet that request, each filter requests whatever frames it needs from its predecessor in the filter chain.
The question is, why is your filter written the way it is?
If it needs more frames than it delivers, it can always request them itself.
However, if there are good reasons for it, there is a trick that can be used to force more frames to be fetched, by adding
ChangeFPS(Framerate(), linear=true)
after your filter.
Guest
10th December 2008, 17:01
If it needs more frames than it delivers, it can always request them itself. Exactly. You can implement your filter like Decimate(2). Decimate fetches all the frames from the previous filter in order to examine them, but it does not return all the frames. You can look at the source code for Decimate() in the Decomb package. If you do it this way, you won't need the SelectOdd() call.
jollye
10th December 2008, 18:50
Gavino's trick ChangeFPS(Framerate(), linear=true) is working very well and I thank your for your answers.
If it needs more frames than it delivers, it can always request them itself.
Actually there are good reasons for it. Depending on the filter after MyFilter, sometimes I need all frames, sometimes 1 out of 2. In the example I've shown in my first message, I have no filter after the script but I want to see only one frame out of two. That's why Gavino's trick is nice because it can do what I need just by adding one simple line in my script.
Thanks again
jollye
kemuri-_9
10th December 2008, 19:10
as a good programming principle,
you should not have your filter crash/fail under certain conditions,
especially when they're likely to occur.
Gavino
10th December 2008, 21:59
Gavino's trick is working very well
I'm glad to hear that, but remember it is just a trick and not a general solution. It works by buffering up to 10 frames, but if the downstream filter skips more than that (eg SelectEvery(20)) then your filter will not see a request for every frame.
Unless your filter is just a one-off for a specific personal use, I recommend you rewrite it as suggested by neuron2.
IanB
10th December 2008, 22:42
When using Gavino's trick, it would be better to use the copy FPS from clip version of ChangeFPS. This will avoid any risk from floating point rounding of the framerate.ChangeFPS(Last, linear=true)
And as kemuri-_9 points out filters must not assume anything about the incoming frame request order. If you need to reference a range of frames to generate your output frame then you should child->GetFrame() all the need frames each time. Requesting frames multiple times is normal behaviour for filters with any temporal sense, this is what the cache is for. For filters that just want some form of metric per frame then you can internally save the metrics in a FrameCount element table. If you do keep linear state in your filter then you must compare the incoming requested frame number, N, with your current state and take remedial action when N is not as expected. Keeping linear state is not a good way to write Avisynth filters.
Also note the client application may not request frames from Avisynth in a linear order. i.e. At least 1 very popular Mpeg2 encoder requests frames in Mpeg stream order, e.g. 0, 3, 1, 2, 6, 4, 5, 9, 7, 8, ... (IPBBPBBPBB...)
Gavino
11th December 2008, 14:23
When using Gavino's trick, it would be better to use the copy FPS from clip version of ChangeFPS.
Quite right. In fact, the trick is not really mine, I was just (mis-)remembering what Ian himself posted on other occasion.
Keeping linear state is not a good way to write Avisynth filters.
And by extension the same applies to script functions, although some well-known (and loved) functions do break this rule for performance reasons.
At least 1 very popular Mpeg2 encoder requests frames in Mpeg stream order, e.g. 0, 3, 1, 2, 6, 4, 5, 9, 7, 8, ... (IPBBPBBPBB...)
Interesting, I wonder how that affects the afore-mentioned functions.
jollye
11th December 2008, 14:58
And as kemuri-_9 points out filters must not assume anything about the incoming frame request order. If you need to reference a range of frames to generate your output frame then you should child->GetFrame() all the need frames each time. Requesting frames multiple times is normal behaviour for filters with any temporal sense, this is what the cache is for.
Thanks for your very detailed explanation. The problem in the case of my filter is a bit complicated. For the sake of the discussion I can explain a bit further my problem even though the given trick is perfect for my problem.
Actually the filter I've written outputs a video at twice the rate as the input video. According to what I want to do with its output, the following lines in the scripts may include a SelectOdd instruction. The second constraint is that as my filter has a temporal loop inside it, to get a correct result, I need the GetFrame function of my filter to be called linearly (I mean 0,1,2,...) which was not the case with the script I've presented above.
You are all right when you say that my filter could have taken this problem into account itself by, for example, testing if the calls to the GetFrame are continuous and if not, forcing the "not called" parts of my internal loop to be called. However the trick given is, in my opinion better for the following reasons (theoretical example):
- There may be reasons for which I'm interested by seing only 1 frame out of 10 from the output of my filter but I need it not to skip the intermediate calls (even if there results don't interest me).
- There may be reasons for which I'm interested by seing only 1 frame out of 10 from the output of my filter and I need also the intermediate calls to be skipped. In the case where the filter itself detects if the GetFrame are (or aren't) related to consecutive frames, this would not be possible anymore.
Also the code inside the filter is much simpler. Just process one GetFrame without testing if the calls are linear or not.
For those reasons, I prefer the script function in my case.
Thanks for all your careful replies and advices.
Gavino
11th December 2008, 19:10
Also the code inside the filter is much simpler. Just process one GetFrame without testing if the calls are linear or not.
Is it really simpler? Presumably you are also having to maintain an internal data structure as each frame is processed (otherwise why insist on linear access?).
Can you explain for us what processing your filter does to derive the contents of each frame it delivers?
Normally, a filter produces frames based on the contents of a small number of frames of its input clip(s), often just one. So a filter that doubles the frame rate, when asked for frame n, might return frame 2*n of its input. Or to give another example, a temporal smoothing filter might derive frame n from frames n-1, n and n+1. Only if output frame n depends on all frames before it should it be necessary to require linear access and retain information from one frame to the next.
It might be you are thinking about the task wrongly, the simplest way is usually to start with the question: "What input does my filter need in order to produce frame n of its output?". Think of how to design a single GetFrame rather than a sequence of GetFrame calls, which can come in any order.
jollye
12th December 2008, 11:28
Hi Gavino,
Thanks for your questions.
The problem may of course be related to the architecture of my filter. This filter was made from an old code (CLI application).
I didn't want to rewrite everything as it is a rather complicated code which has been written by several people I tried to put it in an AviSynth filter and at that time I was just starting using AviSynth. Maybe I could have implemented it differently...
As you suppose, there is an internal data structure maintained inside the filter.
Can you explain for us what processing your filter does to derive the contents of each frame it delivers?
At the company I'm working in, we are prototyping some image processing algorithms in hardware (FPGA's). Sometimes (and it's the case here) we also need a software model of the same functions. I decided to try using AviSynth some time ago because I thought it would allow more flexibility and it's really the case.
My filter uses the input video plus its own last output to derive a new output. It memorizes internally its last output (for historical reasons in the CLI application and I didn't want to change that part of the code).
Regards
Gavino
12th December 2008, 13:18
Thanks for your explanation, jollye.
I see now why you took the approach you did, wanting to use some existing CLI-driven code. The issues are similar to those that arise when converting a CLI application to an event-driven (Windows/GUI) one.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.