W zasadzie, AviSynth działa następująco: najpierw tworzysz prosty dokument tekstowy ze specjalnymi poleceniami,
który nazywa się skryptem, a polecenia odnoszą się do jednego lub więcej klipów video i filtrów, które chcesz użyć. Następnie uruchamiasz aplikację video, taką jak np. VD (VirtualDub), i wczytujesz do niej skrypt. W tym
właśnie momencie AviSynth zaczyna działać. Otwiera klipy video, które wskazałeś w skrypcie, uruchamia określone filtry i wyprowadza materiał wyjściowy do aplikacji video. Jednakże aplikacja nie jest świadoma, że w tle pracuje AviSynth. Zamiast tego, aplikacja sądzi, że jest to bezpośredni plik AVI z HDD.
Ta wersja AviSynth jest ważnym, wewnętrznym uaktualnieniem.
Edycja liniowa
Prostą rzeczą, którą możesz wykonać w AviSynth jest rodzaj edycji
podobny do tego co w VD. Skrypty są proste do napisania, ponieważ, jeśli nie chcesz, nie musisz martwić się o zmienne ani o skomplikowane składnie.
Dla próby, stwórz plik o nazwie test.avs i umieść w nim następującą pojedynczą linię tekstu:
|
Teraz otwórz ten plik w jakimś odtwarzaczu video (chociażby w Windows
Media Player'ze). Powinieneś zobaczyć dziesięciosekundowy klip video wyświetlający
numer wersji używanego AviSynth’a oraz notkę o prawach autorskich.
Version jest tym co nazywa się "filtrem źródłowym", oznacz to, że zamiast
modyfikowania, tworzy klip video. Pierwszym poleceniem w skrypcie AviSynth zawsze
powinno być wywołaniem filtru źródłowego.
Do poprzedniego skryptu dodaj drugą linijkę poleceń, tak by skrypt wyglądał następująco:
|
Ponownie odtwórz skrypt w jakimś player'ze. Tym razem również powinieneś
zobaczyć notkę o prawach autorskich, jednakże w zmniejszoną o połowę
rozdzielczości. ReduceBy2 jest "filtrem transformacyjnym",
oznacza to, że pobiera poprzedni klip video i modyfikuje go w jakiś sposób. Możesz łączyć ze sobą wiele filtrów transformacyjnych, tak jak w VD.
Dodaj kolejną linijkę skryptu, powodującą ściemnienie się klipu video do czerni na jego końcu:
|
Ponownie odtwórz skrypt. Klip powinien być taki sam jak poprzedni, ale
tylko przez dziewięć pierwszych sekund, w ostatniej sekundzie, powinien spokojnie ściemniać się do uzyskania czerni.
Filtr FadeOut przyjmie numeryczny argument, który wskazuje liczbą klatek podlegające ściemnianiu. Video wytworzone przez filtr
Version ma prędkość klatek równą 24 (fps=24, fps: frames per
second - klatki na sekundę), więc argument równy 24 dla FadeOut sprawi, iż ściemnianie rozpocznie się w ostatniej sekundzie trwania klipu.
Dużo czasu zajmuje oczekiwanie na rozpoczęcie ściemniania, by skrócić ten czas
należy użyć filtra Trim.
Klip wytworzony przez Version ma długość 240 klatek (24 fps, 10
sekund). AviSynth rozpoczyna numerację klatek od 0, więc klip posiada numerację klatek od 0 do 239. Filtr
FadeOut dodaje jedną, dodatkową klatkę na końcu klip, czyli nasz klip będzie miał numerację klatek od 0 do 240.
By pozbyć się pierwszych 192 klatek (8 sekund, 192/24=8), zmodyfikuj poprzedni skrypt dopisując kolejną linijkę tekstu:
|
Po raz pierwszy użyliśmy komentarza. Komentarz rozpoczyna się od znaku # i jest aktywny do końca linii
(AviSynth ignoruje wszystko co jest po znaku #).
Filtr Trim przyjmuje dwa argumenty oddzielone przecinkiem: pierwszą i
ostatnią klatkę, które wskazują na aktywny zakres klatek (pozostała część klipu video jest ignorowana). Jeśli ostatnią klatkę określisz
jako 0, będzie to oznaczało "eof" (end of file - koniec pliku), więc powyższe wywołanie
filtra Trim mogłoby wyglądać tak: Trim(192,0).
Określanie zakresu klatek w ten sposób jest dosyć żmudne. Jest jednak prostszy sposób.
Otwórz częściowo ukończony skrypt w VD lub innej aplikacji, która pokazuje numer wyświetlanej klatki. Możesz również użyć filtra
ShowFrameNumber, który wyświetla na każdej klatce jej numer.
W praktyce, bardziej przydatnym filtrem źródłowym niż Version jest AVISource, który wczytuje plik AVI (lub jeden z kilku innych typów pliku) z HDD. Jeśli masz
pod ręką jakiś plik AVI spróbuj zastosować te same filtry dla swojego
klipu:
|
Nawet pojedyncza linia skryptu zawierająca tylko polecenie AVISource może być przydatna przy korzystaniu z aplikacji przyjmujących pliki AVI, które mają wielkość poniżej 2 GB, dzięki temu skryptowi zabezpieczenie to zostanie ominięte (najczęściej dotyczy to materiału DV).
Edycja nieliniowa
Stwórz plik AVS z następującym skryptem:
|
Teraz odtwórz go. Rezultat: wyjściowy materiał video zawiera dwie identyczne notki o prawach autorskich, przy czym jedna jest nad drugą.
Zamiast przyjmowania argumentu numerycznego lub znakowego, StackVertical
przyjmuje, jako argumenty, klipy video. W tym skrypcie filtr Version jest określony dwa razy. Każde powtórzenie zwróci kopie klipu
Version. Te dwa klipy podane są do StackVertical, który łączy je razem (bez wiedzy skąd pochodzą).
Jednym z przydatniejszych filtrów łączących jest UnalignedSplice, który łączy video metodą
"ete" (end to end - koniec z końcem). Poniższy skrypt wczytuje trzy pliki AVI i łączy je
razem:
|
Oba filtry, StackVertical i UnalignedSplice, mogą przyjąć więcej niż dwa argumenty, ale nie więcej niż sześćdziesiąt. Jako skrót dla filtra UnalignedSplice możesz użyć operatora dodawania (+). Dla przykładu, stwórz podobny skrypt do poniższego (ma on identyczne działanie jak powyższy przykład):
|
Teraz przypuśćmy, że przechwytujesz video w aplikacji, która również umożliwia zapis pliku AVI podzielonego na części, ale audio jest w jednym, oddzielnym pliku WAV. Czy możemy coś zaproponować? Oczywiście:
|
Przypisanie do zmiennej
Skrypt AviSynth składa się z różnych poleceń, również podobnych do tego:
|
W przykładzie tym, wyrażenie jest oceniane i w rezultacie przydzielone do zmienna.
|
Natomiast tym razem, wyrażenie jest oceniane i w rezultacie przydzielone do specjalnej zmiennej klipu - last. Oznacza to samo co:
|
Koniec takiego skryptu zawsze wygląda tak:
|
Powyżej zmienna zostanie oceniano i używana jako: "zwróć wartość" skryptu - jest to klip video, który będzie widziany przez aplikację podczas otwarcia pliku AVS.
Podstawowa forma wyrażenia która wywołuje funkcję jest następująca:
Funkcje klipu zawsze wytwarzają nowy klip video i nigdy nie modyfikują istniejącego.
args jest listą argumentów oddzielonych przecinkiem. Lista ta może być pusta (oznacza to przyjęcie domyślnych wartości dla wszystkich lub niektórych argumentów). Jeśli filtr, jako pierwszy argument, spodziewa się klipu video, a argument ten nie jest dostarczony to zostanie użyty klip ze specjalnej zmiennej
last.
Filtry AviSynth mogą przyjmować nazwy argumentów. Nazwy argumentów mogą być określone w obojętnie jakiej kolejności, a filtr wybierze domyślną wartość dla każdego, który zostanie ominięty. Nazwy argumentów są dodatkowe, ale przy ich wpisaniu wiadomo czego dotyczy dana wartość.
|
poniższy skrypt jest bardziej czytelny dla osoby czytającej skrypt (również w przypadku edycji skryptu, np. następnego dnia):
|
i jak widać w pierwszym przykładzie kolejność argumentów jest z góry
określona i nie może zostać zmienione, natomiast w przykładzie drugim, dzięki
dodaniu nazw argumentom ich kolejność nie jest istotna.
Alternatywną składnią (zwaną "notacja OOP") dla funkcji klipów jest:
|
jest to równoważne do:
|
Jedyną wadą notacji OOP jest to, iż może być użyta tylko z filtrami, które przyjmują jako argument tylko jeden klip
video.
Wszystkie funkcje AviSynth wytwarzają określoną liczbę klatek wyjściowych i
określoną prędkość klatek (fps). AviSynth, przed wczytaniem skryptu, wie jak długi będzie materiał wyjściowy i jaki będzie miał fps, wylicza to z "wyciętych sekwencji” wszystkich klipów wejściowych.
Wyliczane to ma miejsce w trakcie otwarcia skryptu.
Jak już dowiedzieliśmy się z jednego z powyższych przykładów, AviSynth
ignoruje wszystko co znajduje się po znaku #, czyli wszelkiego rodzaju
komentarze. Twórcy tego narzędzia postarali się również o to, by nie było
problemu z wielkością liter, tak więc aViSouRCe jaki i AVISource są równoznaczne.
Znak \ jest przydatny przy poleceniu, który jest dłuższy niż jedna
linijka tekstu i chcemy go "przerzucić" do następnej linii w
określonym miejscu, najlepiej odwzorowują to poniższe przykłady (wszystkie
trzy możliwe wywołania tego skryptu, ze znakiem \ i bez, są sobie równoważne):
|
|
|
Zmienne:
Nazwy zmiennych mogą być dłuższe niż 50 znaków i mogą zawierać litery, cyfry, i podkreślenia (_), ale nie mogą zawierać innych znaków
oraz nie mogą zaczynać się cyfrą. Następujące typy zmiennych są
wykorzystywane w AviSynth:
clip: klip video (zawiera video i/lub audio)
string: wpisywany jest w cudzysłowach i zawiera wszystkie znaki oprócz znaków cytujących (powodowałoby to błąd, kiedy dana wartość string się kończy kiedy zaczyna) oraz oprócz podwójnych apostrofów
int: liczba całkowita
float: liczba zmiennopozycyjna (ułamek dziesiętny)
val: typ zmiennej, gdy nie wiadomo czy jest to int czy float
bool : przyjmuje wartości TRUE (prawda) lub FALSE (fałsz)
hexadecimal numbers: liczby całkowite, które rozpoczynają się znakiem $. Przeważnie, tego typu, używa się do określenia koloru, np. $FF8800 jest odcieniem pomarańczowego
global: definicja zmiennej globalnej, która może być użyta przez wszystkie funkcje
zdefiniowane przez użytkownika w skrypcie głównym
Poniżej są dwa przykłady wykonujące tą samą czynność, z tą różnicą, że drugi używa zmiennej globalnej:
|
Dla większości typów zmiennych (clip, int, float, string, bool) możesz użyć następujących operatorów:
== jest równy
!= nie jest równy
|| lub
&& i
Dla typów numerycznych (int, float):
+ dodaje
- odejmuje
* mnoży
/ dzieli
% modulo (reszta z dzielenia całkowitego)
>= większe lub równe
<= mniejsze lub równe
< mniejsze
> większe
|
dla typu string:
+ dodaje (a raczej scala, jeżeli w dwóch "stringach” jest znak 1 to w wyniku otrzyma się 11)
>= większe lub równe (niewrażliwy przypadek)
<= mniejsze lub równe (niewrażliwy przypadek)
< mniejsze (niewrażliwy przypadek)
> większe (niewrażliwy przypadek)
dla typu clip:
+ taki same działanie jak filtr UnalignedSplice
++ taki same działanie jak filtr AlignedSplice
dla typu bool:
?: wykonanie kodu warunkowego
|
Danymi wejściowymi i wyjściowym w poniższych funkcjach ni są klipy video, a
jedynie zmienne używane w skyrpcie.
Funkcje numeryczne:
Floor(-1.2) = -2 Floor(-1.6) = -2 |
|
Ceil(-1.2) = -1 Ceil(-1.6) = -1 |
|
Round(-1.2) = -1 Round(-1.6) = -2 |
|
Int(-1.2) = -1 Int(-1.6) = -1 |
|
Frac(-1.8) = -0.8 |
|
Sign(3.5) = 1 Sign(0) = 0 |
|
scale = TRUE ( TRUE = tryb normalny, FALSE = tryb modulo) seed = FALSE (TRUE = używa czasu jako seed) |
|
Spline(5, 0,0, 10,10, 20,0, true) = 7 |
Funkcje znakowe:
%a skrócone nazwy dni tygodnia %A pełne nazwy dni tygodnia %b skrócone nazwy miesięcy %B pełne nazwy miesięcy %c bieżąca data i czas %d dni miesiąca w systemie dziesiętnym (01 - 31) %H godziny w formie 24-godzinnej (00 - 23) %I godziny w formie 12-godzinnej (01 - 12) %j dni roku w systemie dziesiętnym (001 - 366) %m miesiące w systemie dziesiętnym (01 - 12) %M minuty w systemie dziesiętnym (00 - 59) %p wstawia znak A.M./P.M. w formacie 12-godzinnym %S sekundy w systemie dziesiętnym (00 - 59) %U tydzień w systemie dziesiętnym; niedziela jest pierwszym dniem tygodnia (00 - 53) %w dni tygodnia w systemie dziesiętnym (0 - 6; niedziela=0) %W tydzień w systemie dziesiętnym; poniedziałek jest pierwszym dniem tygodnia (00 - 53) %x bieżąca data %X bieżący czas %y rok bez stulecia w systemie dziesiętnym (00 - 99) %Y rok ze stuleciem w systemie dziesiętnym %z, %Z nazwa strefy czasowej %% znak procentu W przypadku znaczącego formatu, znak # zmienia jego znaczenie: %#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z, %#% - znak # jest ignorowany %#c pełna forma bieżącej daty i czasu, np.: "Tuesday, March 14, 1995, 12:41:29" %#x pełna forma bieżącej daty, np.: "Tuesday, March 14, 1995" %#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y - znak # usuwa wyprowadzane zera (jeśli są), np.: %d - "05", a %#d - "5" |
Konwersje (rzutowanie):
Funkcje testowe:
IsBool (var)
IsInt (var)
IsFloat (var)
IsString (var)
IsClip (var)
Inne funkcje:
Select(index, item0 [, item1...]): zwraca wartość wskazaną przez index
(0=item0); wartości mogą być każdego typu
Defined (var): definicja dodatkowego parametru we własnej funkcji
Default (x, d): zwraca x jeśli Defined(x), w innym przypadku zwraca d
Exist(filename): zwraca TRUE lub FALSE po sprawdzeniu czy plik istnieje
NOP zwraca NULL, służy do wykonania warunku z nie zwracaną wartością, taką jak import.
Eval (string)
Apply (func-string, arg,...): Eval("f(x)") jest równoznaczne do f(x), a to jest równoznaczne do Apply("f", x))
Funkjcę Eval można została wykorzystana w poniższym przykładzie:
Import(filename): wczytuje zawartość innego skryptu AviSynth (importuje tekst innego skryptu)
By w swoich funkcjach informować o błędach należy użyć funkcji:
Assert (bool, string error-message)
Funkcja Try... Catch jest funkcją sprawdzającą, czyli działa w przypadku
wystąpienia błędu:
AviSource("file.avi") } Catch(err_msg) { Blackness.Subtitle(err_msg) } |
Funkcje uruchomieniowe
Mamy również do dyspozycji filtry warunkowe, które oceniają skrypt w
trakcie przetwarzania klatki, więc można zmieniać wartość zmiennej przed daną klatką.
Poniższy, prosty przykład wylicza średnią wartość lumy dla każdej klatki:
ConvertToYV12 # potrzebujemy przestrzeni kolorów YV12 FadeIn(10) # stworzy zmianę w kanałach lumy ScriptClip(" Subtitle(String(AverageLuma())) ") # ocenia Subtitle(...) dla każdej klatki # dane wyjściowe AverageLuma są rzutowane do # string i wyświetlane na klipie wejściowym ConvertToRGB # zamiana przestrzeni kolorów na RGB |
SetMemoryMax(int): ustala maksymalną pamięć, którą wykorzysta AviSynth (w MB)
W kilku poprzednich wersjach domyślną wartością dla tej funkcji była wartość 5MB, która,
jak się okazało, była zbyt mała. Jeśli napotkałeś jakiś problem (np. wolna prędkość) spróbuj zmienić wartość tej funkcji na chociaż 32MB.
SetWorkingDir(string): ustala domyślny katalog dla AviSynth
Nadaje się wyłącznie prosto wczytującym klipom źródłowym, itd. Nie dotyczy automatycznie wczytywanych plugin’ów. Zwraca wartość: 0 jeśli zadanie zostało wykonane pomyślnie, w innym
przypadku zwraca -1
Poniższe filtry jako argument wymagają tylko jednego klipu video i zwracają jego
określoną właściwość:
Width(clip)
Height(clip)
Framecount(clip)
Framerate(clip)
Audiorate(clip)
Audiolength(clip)
Audiochannels(clip)
Audiobits(clip)
IsRGB(clip)
IsRGB24(clip)
IsRGB32(clip)
IsYUY2(clip)
IsYV12(clip)
IsYUV(clip)
IsPlanar(clip)
IsInterleaved(clip)
IsRGB24(clip)(clip)
IsRGB32(clip)(clip)
IsFieldBased(clip)
IsFrameBased(clip)
GetParity(clip)
Nie zapomnij, że filtry te możesz używać z ukrytą zmienną last lub w notacji
OOP:
tak samo jak BilinearResize(Width(Last)/2, Height(Last)/2) tak samo jak BilinearResize(Last.Width / 2, Last.Height / 2) |
Możesz zdefiniować swoją własną funkcję. Najlepszym wyjaśnieniem jest poniższy przykład:
{ Assert(c.height == 480, "NTSC2PAL: klip wejściowy musi mieć wysokość 480 linii") Bob(c, height=576) return Weave() } |
Funkcję można również zdefiniować tak:
{ return ( start >= clip.framecount-expo ? \ Trim(clip,start,0) : \ Dissolve(Trim(clip,start,start+expo-1), \ TRANSITION(clip,start+expo,expo,overlap), \ overlap \ ) } |
Poniższe funkcje łączą w określony sposób co najmniej dwa klipy. W poniżej tabeli są tylko właściwości klipów wynikowych. Pamiętaj, że przy jakimkolwiek łączeniu, wszystkie klipy muszą mieć tą samą przestrzeń kolorów i tą samą rozdzielczość.
ilość klatek | |||||
Jak widać, funkcje nie są całkowicie symetryczne, jednak pobierają kilka cech z
pierwszego klipu.
Z wymienionymi funkcjami możesz dodać do AviSynth funkcje zewnętrzne. Kolejność funkcji, w przypadku tej samej
nazwy jest następująca:
1. funkcje zewnętrzne
2. funkcje zdefiniowane przez użytkownika
3. funkcje wewnętrzne
LoadPlugin ("filename"[,...])
Wczytuje jeden lub więcej zewnętrznych plugin’ów AviSynth (pliki DLL).
LoadVirtualDubPlugin ("filename","filtername", preroll)
Wczytuje pluginy napisane pod VD. "filename" jest nazwą pliku z rozszerzeniem .vdf. Po wywołaniu tej funkcji, filtr, w AviSynth, będzie nazywany
"filtername". Filtry VD współpracują tylko z przestrzenią kolorów RGB32. Jeśli video jest zapisane z przestrzenią kolorów RGB24, to będziesz musiał skorzystać z filtru ConvertToRGB32 (nie wystarczy
samo ConvertToRGB). Niektóre filtry wyjściowe zależą od poprzednich klatek; dla takich, parametr
preroll powinien być ustawiony przynajmniej na numer klatki, która potrzebuje danego filtra do przetwarzania, wypełnienia buforu i/lub do uaktualnienia swoich wewnętrznych zmiennych.
LoadVFAPIPlugin ("filename","filtername")
Pozwala na wykorzystanie plugin’ów VFAPI.
Automatycznie ładowane plugin’y i nazwy pierwszeństwa
Możliwe jest umieszczenie wszystkich plugin’ów i skryptów z własnymi funkcjami lub (globalnymi) zmiennymi we wspólnym katalogu, w którym
wszystkie pliki z rozszerzeniem .AVS i .DLL są wczytywane na starcie, nie
wczytywane i potem wczytywane dynamicznie jako potrzebujący skrypt. Skrypty w tym katalogu powinny zawierać tylko zdefiniowane
funkcje i zmienne globalne, a nie główne części obróbki video (mogą spowodować powstawanie dziwnych błędów) oraz nie jest zalecane
umieszczenie innego pliku w tymże katalogu.
Katalog jest przechowywany w rejestrze systemowym (oczywiście, klucz rejestru można zmienić). Możesz użyć pliku .REG z następującymi poleceniami, by ustalić ścieżkę dostępu do wspomnianego katalogu (oczywiście, wstawiasz swoją aktualną
ścieżkę, niekoniecznie tą samą co jest podana w poniższym przykładzie):
Kolejność funkcji z tą samą nazwą jest następująca:
1. funkcje zewnętrzne (zawsze mają najwyższy priorytet)
2. funkcje zdefiniowane przez użytkownika (mają wyższy priorytet niż
funkcje wewnętrzne, przez co możesz unieważnić jakąś funkcję wewnętrzną)
3. funkcje wewnętrzne
Funkcje wewnętrzne ładują się jako ostatnie, dzięki czemu nie ma
konfliktów pomiędzy nazwami filtrów.
Zmiana domyślnych wartości parametrów w filtrach zewnętrznych
Jeśli nie lubisz domyślnych wartości takie jakie są to możesz ustawić własne wartości domyślne. By unieważnić wartości domyślne, najpierw stwórz katalog plugin’ów AviSynth i wprowadź to do
rejestru (wytłumaczone w podrozdziale powyżej). Następnie tworzysz plik z wartościami domyślnymi
w katalogu z plugin'ami. Dla przykładu, by ustawić domyślną wartość dla highq=false dla
MSharpen, stwórz plik o nazwie MSharpen.def i umieść w nim taką linię
tekstu:
highq=false |
Możesz wypisać kilka parametrów w jednej linii. Nie wpisane parametry przyjmą wartości domyślne podane przez autora filtra. Oczywiście, zawsze możesz unieważnić wartości domyślne w swoim skrypcie, kiedy wywołujesz jej funkcję.