Streng genommen bietet die AviSynth Syntax nur eine einzige Kontrollstruktur (eigentlich zwei, die andere ist der bedingte Operator:?, der an anderer Stelle erklärt wird), das try..catch Statement.
Das try..catch Statement erlaubt die Ausführung von Code, der eventuell einen Runtime Error hervorrufen kann und den Umgang mit dem Fehler, falls er eintritt.
Die volle Syntax des try..catch Statements ist:
try {
...
statements
...
}
catch(err_msg) {
...
statements
...
}
Die err_msg Zeichenkette im catch-Block enthält den Text, den AviSynth erzeugt, wenn der Fehler innerhalb des try
Blocks aufgetreten ist. Dieser Text ist derselbe, der in der vertrauten
MessageBox erscheinen würde, die sich zeigt, wenn sich ein
schwerwiegender Skriptfehler ereignet.
Du kannst den Text abfragen (es ist eine normale String Variable),
um bestimmte Unterzeichenketten im Inneren zu finden, die anzeigen,
dass der Fehler aufgetreten ist. Das ist eine Technik, die viele
nützliche Ergebnisse erzielen bringen kann (ein Beispiel siehe hier).
Im weiteren Sinn gibt es viele Elemente in der AviSynth
Syntax,
die obwohl sie nicht selbst Strukturen steuern, zusammengenommen
ermöglichen, Sprachkonstrukte zu erstellen, die einer Kontrollstruktur
entsprechen. Diese Konstrukte wiederum ermöglichen die Durchführung
komplexer Programmieraufgaben.
Die zu berücksichtigen Elemente sind die folgenden:
Die ersten drei erlauben es, einfache Block-Anweisungen wie Verzweigungsblöcke zu erstellen (analog zur if..elseif..else Steuerstruktur, der man häufig
in Programmier-und Skriptsprachen begegnet). Ein einfaches
Beispiel folgt unten (siehe den obigen Link für weitere Informationen)t:
# verschiedene Filterung definieren, basierend auf diesem Flag
heavy_filtering = true AviSource("c:\sources\meinequelle.avi")
# Das Ergebnis von Eval() einer Variable zuweisen, um es in einer Sondervariable zu bewahren
dummy = flag ? Eval("""
Levels(0, 1.2, 255, 20, 235)
stext = "schwer gefiltert"
Spline36Resize(720, 400)
""") : Eval("""
stext = "leicht gefiltert"
BicubicResize(720, 400)
"""
AddBorders(0, 40, 0, 40)
Subtitle(stext)
Das vierte (Rekursion) ist das allgemeinste Instrument, welches durch die Syntax bereit
gestellt wird, um auf Sammlungen einzuwirken und Berechnungen
beliebiger Komplexität durchzuführen. Es ist auch derzeit das einzig wirkliche Werkzeug.
Dies bedeutet nicht, dass man irgendetwas nicht in der
AviSynth Script-Sprache tun könnte. In der Tat kann Rekursion zusammen
mit Zuweisungen praktisch alles erreichen, was eine imperative Sprache
mit Schleifenkonstrukten tun kann. Sie tut es nur einfach in einer Weise,
mit der die meisten Menschen ohne besondere Programmierkenntnisse nicht
vertraut sind, da die funktionale Programmierung eher eine spezielles
Thema ist.
Das fünfte (Steuerfunktionen) sind die mehr oder weniger notwendigen Werkzeuge innerhab der
obigen Konstrukte, um Input, Einstellwerte und Unterstützung des
ordnungsgemäßen Ablaufs des Konstrukts zu ermöglichen.
Schauen wir uns einige Beispiele für Rekursion an, um das allgemeine
Muster zu erkennen, dem man folgen muss, um sie erfolgreich für seine Zwecke einzusetzen.
Wir nehmen eine schon existierende Anwendung aus der AVSLib für unser Beispiel:
Function StrFill(string s, int count, bool "strict") {
strict = Default(strict, true)
Assert((strict ? count >= 0 : true), "StrFill: 'count' kann nicht negativ sein")
return count > 0 ? s + StrFill(s, count - 1) : ""
}
Die Rekursion ist der Aufruf, den die Funktion auf sich selbst macht
in der return-Anweisung. Damit das richtig getan werden kann, muss die
Reihenfolge der rekursiven Aufrufe schließlich mit einem einzigen
Rückgabewert enden. Daher wird die return-Anweisung einer rekursiven
Funktion immer einen bedingten Operator,?: verwenden.
Das ist alles, was über Rekursion zu sagen ist. Die beiden anderen
Zeilen (wo das fünfte Element, die Steuerfunktionen verwendet werden)
sind einfach nur dafür da, damit richtige Argumente hineingegeben
werden. Das "strict"-Argument ist einfach ein Add-On für die Fälle, wo
die Funktion still (ohne Auslösen eines Fehlers) einen leeren String
zurück geben soll.
Filter wie SelectEvery
ermöglichen die effiziente Auswahl von beliebigen Sets von Frames. Sie
verlangen aber, dass jeder Satz von Frames eine konstanten Abstand von seinem Nachfolger und Vorgänger hat (in anderen Worten,
die Sätze sind in der Bildnummer periodisch). Um Frames mit
unterschiedlichen Trennung (also nicht-periodisch) auszuwählen, müssen
wir auf Skript-Funktionen zurückgreifen, die Rekursion verwenden.
Die untenstehende Funktion ist ein generisches Frameauswahl-Filter, das
um beliebige Bilder auswählen zu können eine benutzerdefinierte
Funktion verwendet (das func Argument muss ihren Namen enthalten), die das Intervall [s_idx..e_idx) auf die Frames legt, die ausgewählt wurden. func muss eine einzelne Ganzzahl als Argument akzeptieren und liefert die entsprechende zugeordnete Frame-Nummer zurück.
Function FSelectEvery(clip c, string func, int s_idx, int e_idx) {
Assert(s_idx >= 0, "FSelectEvery: start frame index (s_idx) is negative")
f = Apply(func, s_idx)
return (s_idx < e_idx && f >= 0 && f < c.Framecount) \
? c.Trim(f, -1) + FSelectEvery(c, func, s_idx + 1, e_idx) \
: c.BlankClip(length=0)
}
Der rekursive Schritt (erste bedingte Verzweigung in der return
-Anweisung) ist wieder ein Ausdruck, der die Funktion als Teilabschnitt
umfasst. Dies ist im allgemeinen nicht nötig (abhängig von der
spezifischen Aufgabe, könnte auch nur die Funktion aufgerufen werden),
aber es ist der übliche Fall beim Bau von komplexen Konstrukten.
Apply ruft die benutzerdefinierte Funktion, um die
Frame-Nummer zu berechnen (eine robustere Implementierung würde diesen
Aufruf in einen try...catch -Block umschließen). Wenn
die Framenummer innerhalb des Clips liegt, dann wird das zugehörige
Frame ans Ergebnis angehängt, sonst endet die Rekursion.
Das folgende Beispiel soll den Aufbau verdeutlichen:
# mein eigener Selector (x^2)
Function CalcFrame(int idx) { return Int(Pow(idx, 2)) }
AviSource("my_200_frames.avi")
# wählt bis zu 20 Frames, die von CalcFrame gemappt werden
# in diesem Fall: 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196
FSelectEvery(last, "CalcFrame", 0, 20)
$Date: 2008/04/21 20:31:23 $