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") |
# | 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 |
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") |
# | zostanie wyświetlona (na bieżącej klatce) różnica w luminancji pomiędzy poprzednią a bieżącą klatką |
  |
||
clip = AviSource("c:\file.avi") |
# | 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) |
# | wyświetlenie tekstu 'frame = numer_bieżącej_klatki': |
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ń).
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.
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.
Ż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))")
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)
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.