Evaluation of runtime scripts starts, as already stated, at the frame serving phase of the main script's execution. At that point frames of the final output clip are requested by the host video application. This triggers a sequence of successive calls to the GetFrame / GetAudio methods of all filters along the filter graph. Whenever one of those filters is a runtime filter, the following three-phase sequence of events happens in every frame:
The following paragraphs examine each phase in more detail.
The runtime filter code sets (at the top-level script local scope) its special variables for the runtime script. These at the minimum include last, which is set to the filter's source clip and current_frame, which is set to the frame number requested by the filter from the AviSynth code.
As a consequence, those special variables cannot be passed between runtime scripts; whatever value the passing script will set, it will be overwritten by the receiving filter's frame initialisation code.
The runtime script is parsed, as a regular script would be parsed if loaded in AviSynth. The parsing mechanism is the same. Thus everything allowed to a regular script is allowed to a runtime script; what changes is the context of execution. For example, you can:
Of course, some of the above are not advisable, because the different execution context poses different constrains regarding performance and resource usage. The main rule of thumb here is: Parsing occurs in every frame requested. Therefore, computationally expensive actions should be avoided. More on the performance considerations section.
The runtime filter code receives the result of script parsing and evaluation. If all went well, the result will be a valid filter graph (the runtime filter graph) from which the runtime filter requests to fetch the needed frame. If not, the filter will propagate the error to the caller. When the filter's code will return the final video frame, the runtime filter graph will be destroyed. As part of the cleanup the runtime filter code also restores the last special variable to its previous value.
Despite the very thin layer of added features (just a handful of variables and functions) the runtime environment is much more dynamic that the normal (main) script environment. The key-difference is the event-driven model of runtime script execution as opposed to the linear flow of the main script's execution. Execution of a runtime script occurs only in the event of a frame request. In addition, since intermediate filters in the chain may shuffle and combine frames in an arbitrary fashion, the requested frame's number may be different than the final clip's frame number.
At any time during the frame serving phase, the elements of the runtime environment are the following:
An interesting feature of runtime functions is that they consult the value of the current_frame special variable in order to determine what frame of their input clip(s) to inspect for extracting information. This provides the ability inside a runtime script to easily request information for any frame of a clip by changing before the call to the function the current_frame variable.
As explained above, setting the current_frame variable has no effect on other runtime scripts in the filter chain because the runtime filters' initialisation code resets current_frame to the proper value before executing the runtime script. It also has no effect on subsequent filter calls in the runtime script. But it does have on runtime functions and anywhere the value of current_frame is used. Therefore, after such a usage it is good practice to restore the variable to its initial value before issuing other script commands.
A skeleton example of a runtime script that computes a weighted second order luma interpolation value (the actions after the computation are ommited) follows:
...previous processing ommited... ScriptClip(""" # this is a multiline string n = current_frame lm_k = AverageLuma() current_frame = n - 1 lm_km1 = AverageLuma() current_frame = n + 1 lm_kp1 = AverageLuma() dvg = (lm_km1 - 2 * lm_k + lm_kp1) / 2 lm_ipl = lm_k + Sign(dvg) * Sqrt(Abs(dvg)) current_frame = n # remember to reset current_frame ...rest of script ommited... """) ...subsequent processing ommited...
Despite the dynamic nature of the runtime environment, creating runtime scripts is relatively easy if you follow a simple set of rules:
Back to the script execution model.
$Date: 2008/04/20 19:07:33 $