LVS: Unterschied zwischen den Versionen

Aus WiFX - The Karaoke Wiki for ASSCalc, NyuFX, Lua, AFX, Tenfex & Templater
Wechseln zu: Navigation, Suche
K (Grafikprogrammierung)
K (Audioprogrammierung)
Zeile 84: Zeile 84:
  
 
Unter Zuhilfenahme der Metainformationen, wie die Anzahl an Kanälen und der Sample Rate, lässt sich mit ihnen arbeiten.
 
Unter Zuhilfenahme der Metainformationen, wie die Anzahl an Kanälen und der Sample Rate, lässt sich mit ihnen arbeiten.
 
<blockquote style="color: red;">TODO</blockquote>
 
  
 
==Grafikprogrammierung==
 
==Grafikprogrammierung==

Version vom 2. Oktober 2013, 11:47 Uhr

LVS

LVS.png

LVS ("Lua Video Sync") ist ein Filter-Plugin für die populären Windows Frameserver Avisynth, VirtualDub und DirectShow. Durch Angabe eines Skriptes (Lua Code enthaltend) als Parameter zum durch das Plugin registrierten Filter lassen sich Videobearbeitungen vornehmen (unter Avisynth auch Audio).

Die Macht der Lua Programmiersprache in Version 5.2, erweitert u.a. durch eine einfache, mächtige 2D Grafikbibliothek, ermöglicht eindrucksvolle grafische Bearbeitung von streamenden Video Frames in hoher Geschwindigkeit und mit vielen Mitteln.

Geschichte

Die Entwicklung von LVS begann im Jahre 2013 durch den Fansubber "Youka".

Inspiriert von Overlua wurde LVS als Nachfolger jenes unausgereiften Projektes beschlossen und sollte dessen großes Potenzial, programmatisch und direkt zu rendern und manipulieren, in einem frischen Gewand ausschöpfen. Als Alternative zu AFX zum typesetten komplexerer Erscheinungen und als mächtigeres Karaoke-FX Werkzeug zu den bisherigen fand es ersten Nutzen bei Fansubbern.

Definition

LVS sollte in folgenden Schritten verstanden werden, da es all diese vereint.

Frameserver plugin

LVS ist kein eigenständiges Programm, sondern eine Erweiterung für Frameserver, um eine Bearbeitung zwischen der Dekodierung eines Videos und dessen Ausgabe einzufügen. Abspielprogramme und Kodierer, welche Frameserver nutzen, können somit Filter auf das Eingangsmaterial anwenden, womit ein anderes Ausgangsmaterial entsteht. Nach Hinzufügen von LVS als Filter muss diesem ein Parameter angegeben werden: das Skript, das die Bearbeitung beschreibt.

Im Folgenden wird der Gebrauch von LVS mit den nutzbaren Frameservern gezeigt (dies schließt den Umgang mit den Frameservern selbst nicht ein).

Avisynth

Avisynth wird über eine Skriptsprache gesteuert, dementsprechend wird auch LVS eingefügt.

LoadPlugin("E:\LVS\plugin\LVS.dll")	#Lädt Plugin 'LVS'/registriert Funktion 'LVS'

BlankClip()				#Erstellt einen leeren Clip
LVS("hello.lua")			#Führt Videobearbeitungsskript mit LVS aus

Die Definition der Funktion sieht wie folgt aus:

clip = LVS(clip, string "video", string "audio", string "data")

clip (1): Ausgabe-Video
clip (2): Eingabe-Video
string "video" (2): Skript zur Videobearbeitung
string "audio" (2): Skript zur Audiobearbeitung
string "data" (2): String zur Übergabe in Skript-Umgebung

VirtualDub

VirtualDubs Video-Filterung ist über das Menü "Video", Menüeintrag "Filters...", erreichbar. Über den Button "Add..." lässt sich LVS aus einer Liste von Filtern hinzufügen und anschließend über einen Dialog dessen Skript-Parameter eingeben. Sollte LVS noch nicht in genannter Liste verfügbar sein, kann über den Button "Load..." das Plugin geladen werden.

LVS - VirtualDub.png

DirectShow

Filter müssen erst als COM Objekt in der Windows-Registry registriert werden, um sie nutzbar für DirectShow gebrauchende Programme zu machen. Dies ist möglich mit dem Kommandozeilen-Programm regsvr32. Anschließend hängt es vom Anwenderprogramm ab, wie der Filter geladen wird.

Am Beispiel von MPC-HC kann über Menü View -> Options... -> External Filter LVS hinzugefügt, anschließend durch Setzen der Priorität auf 'Prefer' in die Filter-Kette gezwungen und nach Neustart des Programms über Menü Play -> Filters -> LVS konfiguriert werden.

LVS - DirectShow.png

Skript-Basis

Basis eines jeden LVS Skripts ist die Filter Funktion, durch welche Frames bzw. Samples geschickt werden.

Im Falle der Videobearbeitung muss diese GetFrame heißen. Der erste Aufrufparameter ist ein Frame als Bildobjekt, der zweite der Frame Index.

function GetFrame(frame, frame_i)
	-- Füll mich
end

Bei Audiobearbeitung lautet der Funktionsname GetSamples. Der erste Aufrufparameter ist ein Table, die Samples enthaltend, der zweite die Table-Größe des letzteren und der dritte der Sample Index des ersten erhaltenen Samples (kanalübergreifend).

function GetSamples(samples, samples_n, sample_i)
	-- Füll mich
end

Metainformationen eines Streams sind als globale Variablen verfügbar. Diese umfassen VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_HAS_ALPHA, VIDEO_FPS, VIDEO_FRAMES, AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, AUDIO_SAMPLES und USERDATA (letzteres ist das data Argument in Avisynth und ist in beiden Stream-Typen verfügbar).

Audioprogrammierung

Samples werden im Format Float32, also einer Amplitudenangabe von -1.0 bis +1.0, und als channel interlaced, also in Kanäle-Blöcken, empfangen.

S1

C1

S1

C2

S2

C1

S2

C2

S3

C1

S3

C2

...
S = Sample Index
C = Channel

Unter Zuhilfenahme der Metainformationen, wie die Anzahl an Kanälen und der Sample Rate, lässt sich mit ihnen arbeiten.

Grafikprogrammierung

Frames werden als Bildobjekt empfangen, welches Teil der nutzbaren g2d Grafikbibliothek ist. Neben dem Bildobjekt gibt es andere Grafikobjekte, welche zur Bearbeitung gebraucht werden. Um all diese zu verwenden, werden über Member-Funktionen ihre Attribute verändert.

Eine Liste der Grafikobjekte:

TODO

Erweiterungen

TODO

Beispiele

Folgende Beispiele sind Skripte zur Ausführung mit LVS.

Audio

Folgende Skripte dienen der Audiobearbeitung.

Rauschen

Erstellt ein Rauschen.

function GetSamples(samples, samples_n, start_sample_i)
	for i = 1, samples_n do
		samples[i] = math.random(-1000,1000) / 1000
	end
end

Audio zu Text

Schreibt Audiodaten als Text in eine Datei.

local file = io.open("audio.txt", "w")
file:write(string.format("Channels: %d\nSample rate: %d\nSamples: %d\n\n", AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, AUDIO_SAMPLES))

function GetSamples(samples, samples_n, start_sample_i)
	file:write(table.concat(samples, "\n"))
	file:write("\n")
end

Video

Folgende Skripte dienen der Videobearbeitung.

Minimal

Farben aller Frames werden invertiert.

function GetFrame(frame, frame_i)
	frame:invert()
end

Zeichnen

Zeichnet eine gelbe Aussenlinie eines Halbkreises.

function GetFrame(frame, frame_i)
	local ctx = frame:get_context()
	ctx:path_move_to(100, 100)
	ctx:path_line_to(200, 100)
	ctx:path_add_arc(150, 100, 50, 0, -180)
	ctx:set_line_width(5)
	ctx:set_line_join("BEVEL")
	ctx:set_source(g2du.yellow)
	ctx:stroke()
end

Text

"Hello world\nfrom LVS!" mit einem rot-zu-grün Farbverlauf.

local pos = {
	x = 100,
	y = 100
}
local text_properties = {
	"Hello world\nfrom LVS!",	-- Text
	"Arial",	-- Font
	50,	-- Size
	true,	-- Bold?
	true,	-- Italic?
	true,	-- Underline?
	true	-- Strikeout?
}
local text_extents = {g2d.text_extents(table.unpack(text_properties))}

function GetFrame(frame, frame_i)
	local ctx = frame:get_context()
	ctx:path_add_text(pos.x, pos.y, table.unpack(text_properties))
	ctx:set_source(
		g2d.create_lgradient(pos.x, pos.y, pos.x + text_extents[1], pos.y + text_extents[2])
		:add_color(0, 1,0,0)
		:add_color(1, 0,1,0)
	)
	ctx:fill()
end

Karaoke

-- Parse ASS file and fill global tables
ass.load("my_ktime.ass")

-- Roumaji & Kanji
local function roumaji_kanji(ctx, ms, line)
	-- Iterate through sylables
	for _, syl in ipairs(line.styleref.alignment < 7 and line.chars or line.syls) do	-- Use characters in case of kanjis
		-- Set color dependent on sylable activity
		ctx:set_source(ms >= syl.start_time and ms < syl.end_time and g2du.red or g2du.yellow)
		-- Draw sylable text
		ctx:path_add_text(syl.x, syl.y, syl.text, ass.unpack_font(line.styleref))
		ctx:fill()
		ctx:path_clear()
	end
end

-- Subtitle
local function subtitle(ctx, line)
	-- Draw line text
	ctx:path_add_text(line.x, line.y, line.text, ass.unpack_font(line.styleref))
	ctx:set_source(g2du.yellow)
	ctx:fill()
	ctx:path_clear()
end

-- Process frames
function GetFrame(frame, frame_i)
	-- Create drawing context for frame
	local ctx = frame:get_context()
	-- Get frame time
	local ms = frame_i / VIDEO_FPS * 1000
	-- Look for frame-related ASS lines
	for _, line in ipairs(lines) do
		if ms >= line.start_time and ms < line.end_time then
			-- Draw ASS line
			if line.styleref.alignment > 3 then
				roumaji_kanji(ctx, ms, line)
			else
				subtitle(ctx, line)
			end
		end
	end
end

Videos

Karaoke Beispiele

Oreimo S2 ED13

Links