Funktionen und ihre Nutzung + If Then Else - Abfragen
Funktionen dienen in AVISynth zur erleichterten Bedienung von gewissen Routinen die aus vielen einzelnen Befehlen bestehen. Mit anderen Worten: Man verkürzt sich so Vorgänge die man immer wieder braucht.
Großes Problem in AVISynth ist das Ansprechen eines Filters in einem bestimmten Zeitbereich/Framebereich. Was weiß ich, Filter xy soll von [lexicon]Frame[/lexicon] 20 bis [lexicon]Frame[/lexicon] 60 wirken. Aber der eigentliche Filter wirkt nur auf das gesamte Video.
Um das zu realisieren in AVISynth gibt es ein Weg und der heißt Schneiden.
Wir haben also unser Video. Ich nenne ihn mal clip0. Die Schnitte erfolgen in 3 Clips. Einen Anfangsclip, ein Bearbeitungsclip und ein Endclip. Daraus ergeben sich 4 Kombinationen:
1. Nur Bearbeitungsclip
2. Anfangsclip + Bearbeitungsclip
3. Bearbeitungsclip + Endclip
4. Anfangsclip + Bearbeitungsclip + Endclip
Also 4 Möglichkeiten das Video wieder zusammzufügen. Von den 3 Clips interessiert nur der Bearbeitungsclip dann. Das ist der Bereich wo dann der Filter drauf wirkt.
Der Anfangsclip ist der, der von [lexicon]Frame[/lexicon] 0 an startet und bis zu dem [lexicon]Frame[/lexicon] Bereich geht wo wir unseren Startframe setzen.
Der Bearbeitungsclip besteht aus unseren Framestart und Frameend Position.
Der Endclip besteht aus unseren Frameend Position und der maximalen Cliplänge des Original Videos.
Wenn Filter xyz von [lexicon]Frame[/lexicon] 30 - 50 wirken soll, dann tritt Möglichkeit 4 in Kraft.
Wenn Filter xyz von [lexicon]Frame[/lexicon] 0 - 50 wirken soll, dann tritt Möglichkeit 3 in Kraft
Wenn Filter xyz von [lexicon]Frame[/lexicon] 30 - Video Endframe wirken soll, dann tritt Möglichkeit 2 in Kraft
Und wenn Filter xyz von [lexicon]Frame[/lexicon] 0 - Video Endframe wirken soll, dann tritt Möglichkeit 1 in Kraft
Das mal jetzt als Verständnis, damit man eine Vorstellung jetzt ungefähr hat 
Als nächstes brauchen wir Abfragen um das ganze zu Realisieren. Dazu können wir uns einer If Then Else (Ist Dann Ansonst) Abfrage bedienen.
Einfache Logik für Programmierer:
If x = 3 then y= 2 else y=4
Auf Deutsch:
Ist x = 3 dann y = 2 ansonsten y=4
In AVISynth:
y = (x=3) ? 2 : 4
Sollte doch verständlich sein, oder? Wenn Fragen sind, einfach fragen ;D
Kommen wir nun zur Funktion. Eine Funktion sollte so aufgebaut werden, das sie für viele Sachen mehrmals verwendet werden kann. Sprich sie sollte Dynamisch sein. Zudem sollten die meisten Funktionen in AVISynth einen Wert zurück liefern. das machen wir mit Return. Wir senden also unsere Informationen an eine Funktion, die dann das entsprechende Ergebnis liefert.
Ich möchte mit euch das bereits genannte Problem + die Lösungsansätze dafür nutzen um mit euch eine Funktion dafür zu entwickeln das Problem mit nur einen einzigen Befehl zu lösen.
Ich möchte jetzt nämlich einen Filter verwenden den man immer wieder mal braucht. Und zwars Overlay.
Was brauchen wir also alles für unsere neue Funktion? Overlay braucht 2 Clips, dann brauchen wir natürlich einen Start und einen Endframe und einen Bildbereich von x,y - x2,y2
Das würde also ein Rechteck bedeuten. Das sind also 8 Werte die wir brauchen.
Erstellen wir uns also unsere Funktion. Nennen wir sie einfach xyz. Ihr könnt diese Funktion so bezeichnen wie ihr wollt. Ich rate aber davon ab die Funktion so zu benennen wie andere Befehle ;D
Also fangen wir an mit:
Function xyz (clip clipx, clip clip0, int sw, int sh, int ew, int eh, int sframe, int eframe) {
clipx werde ich als das Video nehmen auf das gezeichnet werden soll, clip0 ist das Video auf das der Filter nachher wirken soll. sw, sh, ew und eh stehen für startwidth, startheight, endwidth und endheight. Quasi unser Bildbereich (x,y) - (x2,y2) . Und sframe und eframe stehen für unseren Framebereich auf das der Filter angewendet wird. Hier als startframe und endframe ;D
Die Funktion ist noch relativ leer. Aber man kann sie aufrufen mit dem Befehl:
xyz(last, v1, 0, 0, 320, 240, 0, 1800)
Als Anschauhung gebe ich wieder ein Beispielskript vor:
v1=BlankClip(length=1800, width=640, height=480, fps=25, color=$000000)
v2=BlankClip(length=1800, width=640, height=480, fps=25, color=$FF0000)
xyz(v1,v2,100,100,300,300,500,1000)
xyz(v2,350,200,500,500,500,1000)
Function xyz (clip clipx, clip clip0, int sw, int sh, int ew, int eh, int sframe, int eframe) {
Nehmen wir mal an v1 und v2 sind das gleiche Video. Ich hab das jetzt mal so erstellt damit man farblich erkennt was dann passiert nach dem Vorgang.
Als nächstes geben wir unserer Funktion die einzelnen Schnitte vor für unsere 3 Clips die wir brauchen um unseren Filterbereich zu verwenden.
Clip1 soll unser Anfangsframe sein. Da AVISynth uns einen Strich durch die Rechnung macht, wenn wir Trimen wollen von [lexicon]Frame[/lexicon] 0 oder [lexicon]Frame[/lexicon] 1 zu [lexicon]Frame[/lexicon] was weiß ich, muss eine Abfrage her.
Diese lautet um es verständlich zu machen für andere User:
clip1 = clip0.Trim(0, sframe - 2)
clip1 = clip0.Trim(0, sframe - 1)
In AVISynth also:
clip1 = (sframe == 1) ? clip0.Trim(0, sframe - 2) : clip0.Trim(0, sframe - 1)
Das entspricht genau das gleiche Muster.
Clip2 ist unser Bearbeitungsclip. Hier muss mit Crop unser Bereichsfenster gecroppt werden. Da der Cropbefehl auch Negative Zahlen braucht für rechts und unten, müssen wir wieder unsere Mathematik spielen lassen.
Wie berechnen wir x2 und y2 unseres Rechtecks? Genau. Indem wir uns der Clipbreite und Höhe bedienen.
Weil Breite - ew und Höhe - eh ergeben unsere x2 und y2 Position. Da es aber negative Zahlen sein müssen bei rechts und unten in Crop formen wir das um in: -Breite + ew und -Höhe + eh.
Das ganze sieht dann also so aus:
clip2 = clip0.Crop(sw, sh, -clip0.width + ew, -clip0.height + eh)
Nun müssen wir noch dafür sorgen das der neue Clip2 wieder auf die gleiche Größe kommt wie der Ursprungsclip, damit Clip1, 2 und 3 wieder zusammengefügt werden können. Und das gecroppte clip2 soll auch wieder an der gleichen Position erscheinen von da wo wir es herrausgecroppt haben.
Das machen wir mit Overlay. Gleichzeitig schneiden wir es auf Start und Endframe. Also den Bereich wo das ganze im Gesamtvideo angezeigt werden soll. Das machen wir dann mit dem Trim Befehl wieder.
Also die nächste Zeile lautet dann:
clip2 = Overlay(clipx, clip2, x = sw, y = sh).Trim(sframe, eframe)
clip2 wird auf Clipx gezeichnet auf Position sw und sh die wie ja schon verwenet haben. Da es die exakten Größen hat weil das Video ja meist identisch ist bei nur einen Video ;D sieht man dann halt keinen Unterschied das da der Bereich neu aufgelegt wurde. Bei der Beispielvorgabe allerdings sieht man es dann durch den Schwarzen und Roten Clip dann um es euch auch mal zu zeigen was da passiert. 
Jetzt brauchen wir natürlich noch unseren Clip3. Der muss 1 [lexicon]Frame[/lexicon] später anfangen und bis zum Schluss des Gesamtvideos gehen.
Das ist jetzt ganz einfach. Das machen wir so:
clip3 = clip0.Trim(eframe+1, clip0.framecount-1)
So. Wenn wir das alles haben fehlt uns nur noch ein Rückgabewert des Videos. Hier kommen unsere 4 Möglichkeiten ins Spiel die wir abfragen müssen.
Wieder einfache Logik erst mal zum Überblick:
### Frage für Möglichkeit 1 (siehe weiter oben für die Auflistung der Möglichkeiten) ###
If sframe = 0 und eframe = clip0.framecount - 1 then
### Frage für Möglichkeit 3 ###
### Frage für Möglichkeit 2 ###
If eframe = clip0.framecount - 1 then
### Als letztes bleibt nur Möglichkeit 4 ###
return clip1 ++ clip2 ++ clip3
Alles anzeigen
In AVISynth sieht das dann so aus:
return (sframe == 0 && eframe == clip0.framecount - 1) ? clip2 : (sframe == 0) ? clip2++clip3 : (eframe == clip0.framecount - 1) ? clip1++clip2 : clip1++clip2++clip3
Das wars dann auch schon. Die Funktion sollte damit fertig sein und ihr könnt diese auch mal testen. Das Return gibt wie gesagt die entsprechende Variable zurück. In unserem Fall hier ein Videoclip. Bei dem Return werden die entsprechenden Clips wieder zusammen gefügt. Da unsere Funktion sehr Framegenau ist, kommen keine Frames dazu oder werden weniger.
Diese Funktion hier Überlagert ein Video auf ein anderes.
Ihr könnt mit Clip2 nun anstellen was ihr wollt. Benutzt andere Filter oder was weiß ich. Ihr habt auf jedenfall eine Frameangabe von wo der Filter wirken soll. Das ist besser als ApplyRange, da bei dieser Methode mehr Kontrolle ist und man mehrere Filter einbauen kann die auf Clip2 wirken mit nur einem Befehl nachher.
Hier noch mal das fertige Skript für euch:
v1=BlankClip(length=1800, width=640, height=480, fps=25, color=$000000)
v2=BlankClip(length=1800, width=640, height=480, fps=25, color=$FF0000)
xyz(v1,v2,100,100,300,300,500,1000)
xyz(v2,350,200,500,500,500,1000)
Function xyz (clip clipx, clip clip0, int sw, int sh, int ew, int eh, int sframe, int eframe) {
clip1 = (sframe == 1) ? clip0.Trim(0, sframe-2) : clip0.Trim(0, sframe-1)
clip2 = clip0.Crop(sw, sh, -clip0.width + ew, -clip0.height + eh)
clip2 = Overlay(clipx, clip2, x = sw, y = sh).Trim(sframe, eframe)
clip3 = clip0.Trim(eframe+1, clip0.framecount-1)
return (sframe == 0 && eframe == clip0.framecount - 1) ? clip2 : (sframe == 0) ? clip2++clip3 : (eframe == clip0.framecount - 1) ? clip1++clip2 : clip1++clip2++clip3
Alles anzeigen
Wie ihr seht, taucht im Framebereich 500 bis 1000 ein Viereck auf und rechts daneben ein schmales Rechteck. Das sind die Bereiche die herausgecoppt wurden. Bei xyz(v2,350,200,500,500,500,1000) fehlt eine Clipangabe. Wie in den Tutorials davor erwähnt muss Last als Variable nicht angegeben werden sofern der erste Eingang des Filters ein Clip ist. Bei diesem eben genannten dick makierten Beispiel steht eigentlich xyz(last, v2,350,200,500,500,500,1000) da. Last ist das Resultat aus dem ersten xyz Aufruf mit xyz(v1,v2,100,100,300,300,500,1000).
Mit dieser Funktion ist es also Möglich viele Sachen zu machen. Wenn dazu noch Fragen sind, immer stellen. Ich versuche sie dann auch zu beantworten. 