[yv12][yuy2]

ConditionalFilter

ConditionalFilter(clip testclip, clip source1, clip source2, string function, string operator, string value, bool "show")


testclip: klip służący do przetestowania filtrowania warunkowego

source1: pierwszy klip; jest zwracany gdy wyrażenie warunkowe jest spełnione

source2: drugi klip; jest zwracany gdy wyrażenie warunkowe nie jest spełnione

function: filtr wewnętrzny (lub predefiniowana funkcja), który będzie użyta w wyrażeniu warunkowym

operator: ten parametr określa relację ("=", ">", "<") pomiędzy argumentami function i value

value: wartość porównywana z wynikiem uzyskanym dla filtru określonego parametrem function

show: gdy równy true to wyświetlane są informacje o bieżącej wartości zwracanej przez funkcję użytą w wyrażeniu warunkowym


ConditionalFilter zwraca klip source1 gdy jest spełniony warunek utworzony poprzez zestawienie filter+operator+value, w przeciwnym wypadku zwracany jest klip source2. Jeżeli function nie jest zastosowany w sposób bezpośredni na klipie to będzie on zastosowany na klipie testclip. Strumień audio jest pobierany z klipu source1
Parametr function może być dowolnym filtrem wewnętrznym, a także jednym z filtrów zdefiniowanych w części "Funkcje wewnętrzne dla filtrów warunkowych" . Parametr operator może przyjąć wartości: "equals", "graterthan" lub "lessthan" co jest równoważne z użyciem operatorów "=", ">" lub "<".


Przykład:

vid = AviSource("file")
vid_blur = vid.Blur(1.5)
ConditionalFilter(vid, vid_blur, vid, "AverageLuma()", "lessthan", "20")

#

zwróci klatki z klipu vid_blur gdy średnia wartość luminancji klatki będzie mniejsza od 20. W przeciwnym wypadku zostaną zwrócone klatki z klipu vid. Dodanie na końcu argumentu show=true umożliwi wyświetlenie na ekranie bieżącej średniej wartości luminancji


[yv12] [yuy2]

ScriptClip

ScriptClip(clip, string function[, bool show, bool after_frame])


function: funkcja, która operuje na klipie (musi być podana w cudzysłowach)

show: ten parametr umożliwia wyświetlenie na ekranie tekstu z informacją o użytej funkcji

after_frame: ta opcja została dodana w wersji 2.55. Opcja ta umożliwia określenie czy skrypt powinien zostać zastosowany na klipie przed (ustawienie domyślne tzn. after_frame=false) czy po tym jak klatka została zwrócona przez funkcję określoną parametrem function


ScriptClip zwraca klip, który jest zwracany przez funkcję operującą na każdej z klatek. 
Wynikiem działa poniższego skryptu będzie czasowe wygładzenie scen statycznych i zastosowanie zmiennego rozmycia dla scen dynamicznych. Rozmycie w poniższym przykładzie jest realizowane w prawidłowy sposób. W tym skrypcie została dodana także zmienna (diff) i dlatego też należało umieścić przejście do nowej linii poprzez dodanie chr(13):

function fmin(float f1, float f2) {return (f1<f2) ? f1 : f2}
clip = AviSource("c:\file.avi")
ScriptClip(clip, "diff = YDifferenceToNext()"+chr(13)+"diff > / 2.5 ? Blur(fmin(diff/20,1.5)) : TemporalSoften(2,7,7,3,2)")

Klip na wyjściu skryptu MUSI mieć dokładnie takie same parametry jak klip wyjściowy (ta sama rozdzielczość i przestrzeń kolorów). Zwracany klip może mieć inną długość - lecz i tak zostanie użyta długość klipu wejściowego. Ścieżka dźwiękowa klipu wejściowego nie jest modyfikowana. Dla różnych filtrów źródłowych (MPEG2DEC3 i AviSource) możliwe jest uzyskanie niezgodności pomiędzy przestrzeniami kolorów. Jest to znane udziwnienie.


Przykłady:

clip = AviSource("c:\file.avi")
ScriptClip(clip, "Subtitle(String(YDifferenceFromPrevious))")

#

zostanie wyświetlona (na bieżącej klatce) różnica w luminancji pomiędzy poprzednią a bieżącą klatką

 

clip = AviSource("c:\file.avi")
ScriptClip(clip, "Blur(YDifferenceFromPrevious/20.0)")

#

rozmycie każdej klatki w zależności od różnicy luminancji pomiędzy bieżącą, a poprzednią klatką

 

ScriptClip("subtitle(string(current_frame))")

#

wyświetlenie numeru bieżącej klatki w klipie

 

AviSource("C:\file.avi").trim(100,124)
ScriptClip("""subtitle("frame = " + string(current_frame))""")

#

wyświetlenie tekstu 'frame = numer_bieżącej_klatki':


[yv12] [yuy2]

FrameEvaluate

FrameEvaluate(clip, string function[, bool after_frame])


function: funkcja, która operuje na klipie ( musi być podana w cudzysłowach)

after_frame: ta opcja została dodana w wersji 2.53. Umożliwia określenie czy skrypt powinien zostać zastosowany na klipie przed (ustawienie domyślne tzn. after_frame=false) czy po tym jak klatka została zwrócona przez funkcję określoną parametrem function


Działanie tego filtra jest podobne do sposobu działania filtru ScriptClip z tą różnicą, że klip zwracany przez ten filtr jest ignorowany. Może być to przydatne do określania zmiennych, itp. Klatki z klipu są dostarczane w sposób bezpośredni (bez wykonywania na nich jakichkolwiek działań).


[yv12] [yuy2]

ConditionalReader

ConditionalReader(clip, string filename, string variablename[, bool show])


filename: nazwa pliku tekstowego (w cudzysłowach) z wartościami, które będą przypisane pod zmienną określoną parametrem variablename

variablename: zmienna, do której zostaną przypisane wartości znajdujące się w pliku filename

show
: gdy ten parametr jest równy true to wartość przypisana dla tej klatki zostanie nałożona na klip; domyślnie show=false


ConditionalReader umożliwia pobranie wartości dla każdej z klatek lub dla przedziału klatek z pliku tekstowego.


Wstęp do zaawansowanego filtrowania warunkowego

Format pliku
Plik zawiera sam tekst. Rozdzielenia wartości dokonuje się za pomocą odstępów. Każda nowa linia oznacza oddzielny zbiór danych. Wielkość liter w tekście nie jest brana pod uwagę.

TYPE (int|float|bool)

W pojedynczym pliku dane mogą być tylko jednego typu. Obecnie można używać danych typu float (wartości zmiennopozycyjne), int (wartości całkowite) oraz bool (wartości logiczne). Typ danych określany jest poprzez słowo kluczowe TYPE. Tworząc plik z danymi zawsze trzeba najpierw określić ich typ, ponieważ dane, które były umieszczone przed słowem TYPE NIE ZOSTANĄ przypisane pod zmienną variable. Wyklucza się zmianę typu danych gdy już raz został on określony (przyp. początek akapitu).

DEFAULT <wartość>

To słowo kluczowe określa wartość domyślną dla wszystkich klatek. Słowo to należy umieścić tuż po TYPE, ponieważ ustawienie wartości domyślnej powoduje utratę wcześniej przypisanych wartości dla klatek. Słowo to można pominąć o ile ma się pewność, że wszystkim klatkom zostały przypisane wartości. W przeciwnym wypadku może to doprowadzić do uzyskania niezamierzonego rezultatu.

<numer_klatki> <wartość>

Umożliwi to przypisanie wartości pojedynczej klatce o numerze numer_klatki.

R <klatka_początkowa> <klatka_końcowa> <wartość>

Komenda ta przypisze wartość dla przedziału klatek. Klatki o numerach klatka_początkowa i klatka_końcowa zalicza się także do tego przedziału.

I <klatka_początkowa> <klatka_końcowa> <wartość_początkowa> <wartość_końcowa>

Ten zapis spowoduje przypisanie przedziałowi klatek wartości zmieniającej się w sposób liniowy od wartość_początkowa do wartość_końcowa. Dla tej komendy nie można stosować wartości logicznych, ponieważ nie można ich zmieniać w sposób liniowy. Klatki o numerach klatka_początkowa i klatka_końcowa także są zaliczane do przedziału.

Typy wartości
Tak jak wspomniano wcześniej można stosować typy int, float i bool
Wartości typu int mogą być ujemne. Typ float jest liczbą dziesiętną zawierającą kropkę. Podobnie jak int może też być liczbą ujemną oraz zawierać literę e lub E (symbol wykładnika potęgi dziesiętnej) i po nim liczbę całkowitą np. -32.52521E2 = -3252.521, -32.52521e-2 = -0.3252521. Typ bool może mieć dwie wartości tj. true (prawda) lub false (fałsz).

Przykłady

Zastosowanie podstawowe

file.txt:
Type float
Default 3.45567

R 45 300 76.5654
2 -671.454
72 -671.454

Powyższy plik zwróci wartości zmiennopozycyjne. Domyślną wartością dla klatek będzie 3.45567. Jednakże klatkom z przedziału od 45 do 300 zostanie przypisana wartość 76.5654, a klatkom 2 i 72 wartość -671.454.

Jak można zauważyć późniejsze zmiany unieważniają wcześniejsze przypisane wartości. Ta zasada jest dobrze widoczna dla klatki o numerze 72. Pomimo tego, że była ona zawarta w przedziale 45-300 i jej wartość wynosiła 76.5654, to w ostatniej linijce została przypisana jej nowa wartość równa -671.454. Z drugiej strony gdyby określenie przedziału klatek nastąpiło po linii "72 -671.454", to klatce 72 zostałaby przyporządkowana wartość 76.5654.

Poniżej jest umieszczony skrypt, który wykorzystuje wcześniej stworzony plik z danymi:

colorbars(512,512)
trim(0,500)
ScriptClip("subtitle(string(myvar))")
ConditionalReader("file.txt", "myvar", false)

Wywołanie tego skryptu spowoduje przypisanie danych zawartych w pliku "file.txt" zmiennej o nazwie "myvar", która będzie wykorzystana przez filtr Subtitle wywołany przez ScriptClip w celu wyświetlenia zmiennej "myvar".

Zmiana parametrów nakładania klipów

skrypt Avisynth:
colorbars(512,256)
a1 = trim(0,600)
a2 = MessageClip("Text clip")
overlay(a1,a2, y = 100, x = 110, mode="subtract", opacity=0, pc_range=true)
ConditionalReader("opacity.txt", "ol_opacity_offset", false)
ConditionalReader("xoffset.txt", "ol_x_offset", false)

xoffset.txt:
Type int
Default -50
I 25 50 -50 100
R 50 250 100
I 250 275 100 250

opacity.txt:
Type float
Default 0.0
I 25 50 0.0 1.0
R 50 250 1.0
I 250 275 1.0 0.0

W dwóch plikach tekstowych zostały ustalone wartości odpowiednio dla parametru x (plik "xoffset.txt") i opacity (plik "opacity.txt"). Dla klatek 25->50 parametr opacity zmienia się od 0.0 do 1.0, podczas gdy tekst przemieszcza się z lewej na prawą stronę. Tekst jest nieruchomy dla przedziału 50->250. Dla klatek z przedziału 250->275 następuje dalsze przemieszczanie się tekstu na prawo z jednoczesnym zanikaniem.

Funkcje wewnętrzne dla filtrów warunkowych
Poniżej są umieszczone wewnętrzne funkcje, których wartość jest obliczana dla każdej klatki. Funkcje te zwrócą średnią wartość piksela dla płaszczyzny (wymagana przestrzeń to YV12 oraz procesor zawierający zestaw instrukcji ISSE):

AverageLuma(clip)
AverageChromaU(clip)
AverageChromaV(clip)

Poniższe funkcje zwrócą wartość ułamkową z przedziału [0, 255] bezwzględnej różnicy pomiędzy dwiema płaszczyznami (wymagana przestrzeń to YV12 oraz procesor zawierający zestaw instrukcji ISSE):

RGBDifference(clip1, clip2)
LumaDifference(clip1, clip2)
ChromaUDifference(clip1, clip2)
ChromaVDifference(clip1, clip2)

W powyższych funkcjach możliwie jet pominięcie pierwszego parametru. Gdy zostaje on pominięty to wtedy parametr clip jest zastąpiony klipem testowym.

Poniższe funkcje powinny być przydatne do wykrywania zmiany ujęcia:

RGBDifferenceFromPrevious(clip)
YDifferenceFromPrevious(clip)
UDifferenceFromPrevious(clip)
VDifferenceFromPrevious(clip)
RGBDifferenceToNext(clip)
YDifferenceToNext(clip)
UDifferenceToNext(clip)
VDifferenceToNext(clip)

W poniższym przykładzie ostatnia klatka przed zmianą ujęcia zostanie zastąpiona pierwszą klatką po zmianie ujęcia:

ConditionalFilter(last, last, last.trim(1,0), "YDifferenceToNext()", ">", "10", true)

Pozostałe funkcje wewnętrzne to:

YPlaneMax(clip, float threshold)
UPlaneMax(clip, float threshold)
VPlaneMax(clip, float threshold)
YPlaneMin(clip, float threshold)
UPlaneMin(clip, float threshold)
VPlaneMin(clip, float threshold)
YPlaneMedian(clip)
UPlaneMedian(clip)
VPlaneMedian(clip)
YPlaneMinMaxDifference(clip, float threshold)
UPlaneMinMaxDifference(clip, float threshold)
VPlaneMinMaxDifference(clip, float threshold)

Parametr threshold (próg) stanowi procent liczby pikseli, które są dopuszczane powyżej lub poniżej wartości minimalnej. Parametr ten jest nieobowiązkowy i domyślnie równy 0.

Jeżeli rozumiesz działanie powyższych filtrów to możesz przystąpić do zapoznania się z "zaawansowanym filtrowaniem warunkowym", które umożliwi bliższe zapoznanie się z filtrowaniem warunkowym.


Zaawansowane filtrowanie warunkowe: część pierwsza

Żeby zrozumieć tą część musisz znać podstawy funkcjonowania Avisynth: skrypty są wykonywane w kolejności od góry do dołu, lecz gdy istnieje żądana klatka to tak naprawdę ostatni filtr jest wywoływany jako pierwszy, i żąda on klatek od filtrów znajdujących się powyżej. Dla przykładu:

AviSource("myfile.avi")
ColorYUV(analyze=true)
Histogram()

Gdy otworzysz ten skrypt w programie VirtualDub to kolejno:
- gdy VirtualDub żąda daną klatkę to AviSynth żąda tą klatkę od filtru Histogram
- Histogram żąda klatkę od ColorYUV
- a ColorYUV z kolei od AviSource; AviSource, który wybiera klatkę z pliku "myfile.avi" dostarcza ją filtrowi ColorYUV
- ColorYUV filtruje obraz i wysyła go do filtru Histogram, który po wykonaniu filtrowania zwraca go do programu VirtualDub

Tak więc w rzeczywistości ciąg filtrów działa w odwrotnej kolejności. Daje to filtrowi możliwość żądania kilku klatek z źródła znajdującego się nad nim.
Jednakże filtry warunkowe muszą zwrócić klip zanim poproszą o klatki z filtrów znajdujących się nad nimi, ponieważ muszą wiedzieć, który filtr mają wywołać (w zależności od wyniku porównania funkcji z wartością /patrz ConditionalFilter/). Następna ważną rzeczą jest to, że tylko zmienne zdefiniowane w globalny sposób w "środowisku" filtru warunkowego mogą być użyte też poza nim (i na odwrót tzn. zmienne globalne zdefiniowane poza filtrem warunkowym mogą być użyte w "środowisku" filtru). Spójrz na poniższy skrypt:

v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12
function g(clip c)
{
global w = c
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "t = String(text)")
c4 = FrameEvaluate(c3, "text = YDifferenceFromPrevious(w)")
return c4
}

g(v)

Ciąg filtrów pracuje w następujący sposób:
- gdy VirtualDub potrzebuje klatki to AviSynth żąda klatkę od funkcji g()
- funkcja g() żąda klatkę od filtru AviSource
- AviSynth żąda klatkę od drugiego filtru FrameEvaluate
- drugi filtr FrameEvaluate oblicza wartość wyrażenia YDifferenceFromPrevious(w) i przypisuje ją do zmiennej text (po uprzednim pobraniu 
klatki poprzez AviSource).
- po tym ta klatka jest żądana przez pierwszy filtr FrameEvaluate
- Pierwszy filtr FrameEvaluate potrzebuje tej klatki od ScriptClip, który to wylicza wyrażenie String(text) i przypisuje wynik pod zmienną t
- ScriptClip żąda klatkę od ConvertToYV12 i przeprowadza na tej klatce operację Subtitle(t)
- ConvertToYV12 potrzebuje klatki od filtru źródłowego AviSource
- AviSource pobiera klatkę z pliku "atomic_kitten.avi" i dostarcza ją do funkcji g(), która zwraca tą klatkę do programu VirtualDub

Jak można zauważyć w jest zdefiniowana jako zmienna globalna. Dzięki temu można będzie ją użyć w dalszej części skryptu w środowisku filtru warunkowego. Jeżeli chcemy użyć zmiennych t i text w innej funkcji niż g() (wewnątrz lub na zewnątrz środowiska filtru warunkowego), to te zmienne powinny być także zdefiniowane jako zmienne globalne. I tak na przykład:

v = AviSource("E:\Temp\Test3\atomic_kitten.avi").ConvertToYV12

function g(clip c)
{
global w = c
c2 = ScriptClip(c, "subtitle(t)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = YDifferenceFromPrevious(w)")
return c4
}

function me()
{
global t = String(text)
}

g(v)

Znaczna część powyższego skryptu jest zbyteczna i może zostać usunięta. Poniższy skrypt daje dokładnie taki sam rezultat:

v = AviSource("c:\clip.avi")
ScriptClip(v, "Subtitle(String(YDifferenceFromPrevious))")

Zaawansowane filtrowanie warunkowe: część druga

W poniższym przykładzie do pliku tekstowego zostaną zapisane niektóre informacje, które zależą od wyświetlanej klatki. Pierwsza zmienna "a" wskazuje czy klatka jest złożona (ang. combed) (dla pewnych wartości progowych). Należy zwrócić uwagę, że filtr IsCombed wchodzi w skład pakietu DeComb. Druga zmienna "b" określa "poziom" ruchu w klatce.

global sep="."
global combedthreshold=25

function IsMoving()
{
global b = (diff < 1.0) ? false : true
}

function CombingInfo(clip c)
{
file = "F:\interlace.log"
global clip = c

c = WriteFile(c, file, "a", "sep", "b")
c = FrameEvaluate(c, "global a = IsCombed(clip,combedthreshold)")
c = FrameEvaluate(c, "IsMoving")
c = FrameEvaluate(c,"global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")

return c
}

v = mpeg2source("F:\From_hell\from_hell.d2v").trim(100,124)
CombingInfo(v)

Zaawansowane filtrowanie warunkowe: część trzecia

Na forum doom9 pojawiły się filtry, które dobierają algorytmy do zmiany rozdzielczości w zależności od poziomu ruchu w klipie. Te filtry rozróżniają trzy natężenia ruchu tj. poziom niski, średni i wysoki (ocena jest dokonywana na podstawie zmian w klatkach). Chodzi oto, żeby jeden algorytm użył wygładzania czasowego w scenach o małej ilości ruchu, inny zastosował wygładzanie przestrzenne gdy ilość ruchu jest duża, a jeszcze inny algorytm użył wygładzania przestrzenno-czasowego w ujęciach o średnim poziomie ruchu.

Poniżej zamieszczona jest uproszczona wersja filtru o nazwie QUANTIFIED MOTION FILTER v1.5 b1 (10/07/2003) napisana przez HomiE FR:

# QUANTIFIED MOTION FILTER v1.3
# ZAŁADOWANIE WTYCZEK AVISYNTH
LoadPlugin("C:\PROGRA~1\GORDIA~1\mpeg2dec3.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\TemporalCleaner.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\FluxSmooth.dll")
LoadPlugin("C:\PROGRA~1\GORDIA~1\UnFilter.dll")

# ZAŁADOWANIE SKRYPTU "QUANTIFIED MOTION FILTER"
Import("E:\temp\QMF\qmf.avs")

# FILTR DO ZMIANY ROZDZIELCZOŚCI DLA UJĘĆ O MAŁEJ ILOŚCI RUCHÓW
# -> ZMIANA ROZDZIELCZOŚCI Z MAKSYMALNYM ZACHOWANIEM OSTROŚCI + WYGŁADZANIE CZASOWE
function Low_Motion_Filter(clip c)
{
c = TemporalCleaner(c, 5, 10)
c = LanczosResize(c, 512, 272)
return c
}

# FILTR DO ZMIANY ROZDZIELCZOŚCI DLA UJĘĆ O ŚREDNIEJ ILOŚCI RUCHÓW
# -> ZMIANA ROZDZIELCZOŚCI ZE ŚREDNIM ZACHOWANIEM OSTROŚCI + WYGŁADZANIE CZASOWO-PRZESTRZENNE
function Medium_Motion_Filter(clip c)
{
c = FluxSmooth(c, 7, 7)
c = BicubicResize(c, 512, 272, 0.00, 0.50)
return c
}

# FILTR DO ZMIANY ROZDZIELCZOŚCI DLA UJĘĆ O DUŻEJ ILOŚCI RUCHÓW
# -> ZMIANA ROZDZIELCZOŚCI Z MAŁYM ZACHOWANIEM OSTROŚCI + WYGŁADZANIE PRZESTRZENNE
function High_Motion_Filter(clip c)
{
c = FluxSmooth(c, -1, 14)
c = UnFilter(c, -30, -30)
c = BilinearResize(c, 512, 272)
return c
}

# WCZYTANIE KLIPU ŹRÓDŁOWEGO
AviSource("E:\temp\QMF\britney-I_love_rock_'n_roll.avi")
ConvertToYV12(interlaced=true)
Telecide(0)

# UŻYCIE FILTRU STOSUJĄCEGO ALGORYTM ZMIANY ROZDZIELCZOŚCI W ZALEŻNOŚCI OD ILOŚCI RUCHU (UŻYCIE QMF)
QMF()

Poniższy skrypt należy umieścić w oddzielnym pliku o nazwie "qmf.avs":

# QUANTIFIED MOTION FILTER (17/08/2003) napisany przez HomiE FR (homie.fr@wanadoo.fr)
# FUNKCJA SZACUJĄCA POZIOM RUCHU
function ME()
{
# USTALANIE WARTOŚCI PARAMETRU 'motion_level' W ZALEŻNOŚCI OD ŚREDNIEJ RÓŻNICY [1]
global motion_level = (diff < threshold_lm) ? 0 : motion_level
global motion_level = (diff >= threshold_lm && diff <= threshold_hm) ? 1 : motion_level
global motion_level = (diff > threshold_hm) ? 2 : motion_level
}

# FUNKCJA QUANTIFIED MOTION FILTER (pol. filtr służący do przyporządkowania ilości ruchu do trzech kategorii /w tym konkretnym wypadku/)
function QMF(clip c, float "threshold_lm", float "threshold_hm", bool "debug")
{
# USTAWIENIE PROGÓW DLA POSZCZEGÓLNYCH KATEGORII ILOŚCI RUCHU [2]
threshold_lm = default(threshold_lm, 4.0)
threshold_hm = default(threshold_hm, 12.0)
global threshold_lm = threshold_lm
global threshold_hm = threshold_hm

# WŁĄCZENIE/WYŁĄCZENIE INFORMACJI SŁUŻĄCEJ DO MONITOROWANIA DZIAŁANIA FILTRU [3]
debug = default(debug, false)

# ZAINICJOWANIE ZMIENNEJ 'motion_level'
global motion_level = 0

# OKREŚLENIE BIEŻĄCEGO KLIPU [4]
global clip = c

# POBRANIE ROZDZIELCZOŚCI WYJŚCIOWEJ [5]
width = Width(Low_Motion_Filter(c))
height = Height(Low_Motion_Filter(c))
global c_resized = PointResize(c, width, height)

# ZASTOSOWANIE ODPOWIEDNIEGO FILTRU W ZALEŻNOŚCI OD ILOŚCI RUCHU [6]
c = ConditionalFilter(c, Low_Motion_Filter(c), c_resized, "motion_level", "=", "0") # [6a]
c = ConditionalFilter(c, Medium_Motion_Filter(c), c, "motion_level", "=", "1") # [6b]
c = ConditionalFilter(c, High_Motion_Filter(c), c, "motion_level", "=", "2") # [6c]

# WYŚWIETLENIE INFORMACJI O DZIAŁANIU FILTRU [7]
c = (debug == true) ? ScriptClip(c, "Debug()") : c

# OTRZYMANIE POZIOMU RUCHU Z FUNKCJI SZACUJĄCEJ TEN POZIOM [8]
c = FrameEvaluate(c, "ME()")

# OTRZYMANIE RÓŻNICY POMIĘDZY POPRZEDNIĄ, A AKTUALNĄ KLATKĄ [9]
c = FrameEvaluate(c, "global diff = 0.50*YDifferenceFromPrevious(clip) + 0.25*UDifferenceFromPrevious(clip) + 0.25*VDifferenceFromPrevious(clip)")
return c
}

# FUNKCJA WYŚWIETLAJĄCA INFORMACJE O DZIAŁANIU FILTRU
function Debug(clip c)
{
# WYŚWIETLENIE INFORMACJI O WERSJI FILTRU [10]
c = Subtitle(c, "Quantified Motion Filter", x=20, y=30, font="lucida console", size=18, text_color=$FFFFFF)
c = Subtitle(c, "by HomiE FR (homie.fr@wanadoo.fr)", x=20, y=45, font="lucida console", size=14, text_color=$FFFFFF)

# WYŚWEITLENIE INFORMACJI O OSZACOWANYM POZIOMIE RUCHU [11]
c = Subtitle(c, "motion estimation", x=20, y=85, font="lucida console", size=18, text_color=$FFFFFF)
c = Subtitle(c, "diff = "+string(diff), x=20,y=110, font="lucida console", size=16, text_color=$FFCCCC)

# WYŚWIETLENIE KATEGORII, DO KTÓREJ ZOSTAŁ PRZYPISANY POZIOM RUCHU [12]
c = Subtitle(c, "quantified motion filter", x=20, y=135, font="lucida console", size=18, text_color=$FFFFFF)
c = (motion_level == 0) ? Subtitle(c, "scene type = low motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
c = (motion_level == 1) ? Subtitle(c, "scene type = medium motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
c = (motion_level == 2) ? Subtitle(c, "scene type = high motion", x=20, y=160, font="lucida console", size=16, text_color=$66FF66) : c
return c
}

Ciąg filtrów pracuje w następujący sposób:
- gdy VirtualDub potrzebuje klatkę, AviSynth żąda jej od funkcji filtru QMF
- QMF żąda klatki od FrameEvaluate [9].
- następnie skrypt [9] jest wykonywany i po dostarczeniu klatki przez AviSource zmiennej globalnej diff przypisywana jest wartość; FrameEvaluate [9] żąda klatki od FrameEvaluate [8]
- ponownie jest wyliczana wartość skryptu [8]
- po obliczeniu funkcji me(), zmiennej globalnej motion level przypisana jest wartość dla tej klatki [1]
- jeżeli parametr debug=true to klatka jest żądana przez ScriptClip i w ten sposób przez Debug()
- następnie (i gdy debug=false) klatka jest żądana przez ostatni warunkowy filtr ConditionalFilter [6c], który żąda klatki od [6b], natomiast [6b] żąda klatki od [6a]
- należy pamiętać o tym, że klatka z filtrów High_Motion_filter, Medium_Motion_filter, lub Low_Motion_filter jest żądana w zależności od
wartości zmiennej motion_level
- QMF żąda klatki od Telecide, Telecide od ConvertToYV12 i na koniec ConvertToYV12 żąda klatki od AviSource
- AviSource pobiera klatkę z pliku "britney-I_love_rock_'n_roll.avi" i dostarcza ją do ConvertYV12, itd.

Kilka szczegółów zostało pominiętych po drodze, lecz dzięki temu sposób działania tego skryptu został "z grubsza" wyjaśniony.


translated by Dj_AnT