View Single Post
Old 16th June 2008, 18:36   #1  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
(Bug) Run-time functions can produce wrong results

I have discovered a subtle and potentially nasty bug in the operation of the run-time (aka conditional) environment. Under certain circumstances, a run-time function can produce the wrong result because it is looking at the wrong frame of its input clip.

Specifically, if:
  1. The input clip to a run-time filter is derived from an earlier run-time filter, and
  2. There is an intervening filter in the chain that changes frame numbers (eg Trim), and
  3. The (later) run-time script makes more than one run-time function call
then all its calls to run-time functions after the first one will operate on the wrong frame.

As you can see, a combination of factors need to be present. However, the bug is potentially nasty because when it bites, you get no error or any indication that something has gone wrong; the script runs apparently OK but produces erroneous results. And it can appear or disappear depending on statements in a completely different part of the script.

Here's an example reduced to its simplest form:
Code:
# 100 frames black + 100 white, to give predictable luma
BlankClip(100, pixel_type="YV12")+BlankClip(100, pixel_type="YV12", color=color_white)
FrameEvaluate("#anything you like, even nothing")
  # ... <- arbitrary filters can appear here...
Trim(50, 149)
  # ... <- ... and again here
ScriptClip("""
  a1 = AverageLuma() # OK
  a2 = AverageLuma() # gives wrong value
  Subtitle("a1="+string(a1)+" a2="+string(a2)) # shows a1 != a2
""")
Analysis: The source of the problem is that the evaluation of the first run-time function causes the variable current_frame to be overwritten by its value from the earlier script. You can see this in action if you change the example to do
Code:
ScriptClip("""
  f1 = current_frame
  a1 = AverageLuma()
  f2 = current_frame # now wrong, = f1+50
  Subtitle("f1="+string(f1)+" f2="+string(f2))
""")
What happens is:
  1. When the ScriptClip's GetFrame is called for frame n, it sets current_frame to n, then evaluates its associated script.
  2. This causes the first run-time function call to be evaluated, which in turn requires frame n of its input to be fetched. This passes up the filter chain in the usual way, but because of the Trim, will request a different frame number (in this case n+50) from the earlier run-time filter (here FrameEvaluate).
  3. In a similar way to step 1, FrameEvaluate's GetFrame sets current_frame to n+50, and carries on with its business. Ultimately the correct frame is fetched from the source clip and we unwind back to step 2 whereupon the run-time function correctly calculates its result.
  4. However, current_frame now has the value n+50, so any subsequent run-time function calls in the run-time script will be evaluated using the wrong frame number.
Solution: The correct solution is for the GetFrame of each run-time filter to save any existing value of current_frame before assigning to it, and then restore the initial value when it exits (just like it does with last, and for the same reason). That way the correct value is preserved when returning to an enclosing GetFrame as in the example given.

(If some aspects of this seem strangely familiar, you may have seen the recent thread about problems using run-time functions inside user-defined functions. Thinking further about that problem led me to deduce the existence of this bug, which I was then able to reproduce.)
Gavino is offline   Reply With Quote