Montag, 11. Mai 2015

Programmierung eines Lightroom Plugins mit Lua

Motivation

In meinen letzten Ferien habe ich einige Time-Lapse-Videos erstellt.
Dazu habe ich meist iStopMotion verwendet. Es wird zwar nicht ausdrücklich dafür beworben, doch es erfüllt den Zweck. Man kann Fotos importieren, die Bild-Rate wählen und das Resultat dann als Video rendern.
Es gibt zwar noch Alternativen wie LRTimelapse (99 EUR) die viele nette Features bringen, doch die Bedienung und der Workflow wirken etwas umständlich.
Wenn es nur darum geht eine erste Ansicht eines Video zu erstellen wäre es schön, wenn es einfacher wäre.

Deshalb habe ich mich entschieden ein eigenes kleines Plugin namens "Video Renderer" für Adobe Photoshop Lightroom® zu schreiben.

Meine Anforderungen sind vorerst ziemlich eingeschränkt:
- Rendern eines Filmes aus einer Sequenz von Fotos in Lightroom unter Mac OS X
- Codec: H264, Bild-Rate 30fps
- Bild-Grösse 1080p

Das Resultat steht auf Github kostenlos zum Download zur Verfügung.
Das Binary und der Source-Code stehen können unter der MIT Lizenz genutzt werden.

Vorgehen zur Entwicklung eines solchen Plugins.


1. Erkunden des SDKs

Das SDK steht bei Adobe als Download (8MB) zur Verfügung.
Das API ist in Lua geschrieben. Dies bedeutet dass Plugins grundsätzlich auch in Lua programmiert werden müssen.
Natürlich kann man mit Lua externe Prozesse starten und dies ist auch möglich in Lightroom Plugins. Somit können beliebige externe Tools eingebunden werden.

Das SDK wird begleitet von einem ausführlichem Programmers Guide als PDF und einer HTML-Basierten API-Referenz. Für alle der verschiedenen Plugin-Typen gibt es ein ausführliches Beispiel mit komplettem Programm-Code.

Grundsätzlich sind diese Features in Lightroom erweiterbar:

  • Befehle im Menu "Library", "Help" und "Export"
  • Export- und Publish-Dienste
  • Metadaten-Felder
  • HTML Web-Engine für Fotogalerien

Es gibt sowohl ein Lightroom Users Forum als auch ein Lightroom SDK Forum. Auf der Website des SDK wird aber leider nur auf das User Forum verlinkt.
Der Typ "Export-Service" scheint für meine Zwecke zu passen.

Die Verwendung des Plugins stelle ich mir etwa so vor:
  1. Fotos aus Lightroom-Katalog selektieren und exportieren.
  2. Im Export-Dialog das Plugin "Video Renderer" wählen und die Render-Parameter wählen.
  3. Button "Exportieren" anklicken und ein paar Sekunden warten.
2. Plugin implementieren

Eine einfache Möglichkeit um Bildsequenzen zu rendern, ist die Open-Source Software ffmpeg.
Der Render-Befehl damit in Lua so aus:

local ffmpegPath = LrPathUtils.child(_PLUGIN.path, "ffmpeg")
local outputPath = exportParams.LR_export_destinationPathPrefix
local outputFile = exportParams.filename
local command = string.format("\"%s\" -y -i %s/\%05d.jpg -c:v libx264 -r 30 -vf scale=-1:1080 -pix_fmt yuv420p \"%s/%s\"", 
ffmpegPath, outputPath, outputPath, outputFile)
result = LrTasks.execute(command)

LrPathUtils und LrTasks sind Teil des Lightroom SDKs.

Für das Rendern muss ich mit dem Plugin eine Version von ffmpeg mitliefern. Da ich momentan nur OS X unterstützen möchte, ist das relativ einfach. Ich besorge mir hier ein statisches Binary für Mac OS X 64-bit Intel.

Der Export-Dialog in Lightroom kann mit einigen Zeilen Lua definiert werden:

exportServiceProvider.sectionsForBottomOfDialog = function ( f, propertyTable )
local LrView = import 'LrView'
local bind = LrView.bind
local share = LrView.share
local result = {
{
title = LOC "$$$/VideoRenderer/ExportDialog/VideoSettings=Render Settings",
synopsis = bind { key = 'fullPath', object = propertyTable },
f:row {
f:static_text {
title = LOC "$$$/VideoRenderer/ExportDialog/FileName=File Name:",
alignment = 'right',
width = share 'leftLabel',
},
f:edit_field {
value = bind 'filename',
truncation = 'middle',
immediate = true,
fill_horizontal = 1,
},
}
}
}
return result
end

Schlussendlich sieht der Export-Dialog mit ein paar Erweiterung dann so aus:



3. Plugin testen

Für Lua gibt es einige Tools die Unit-Testing bzw. auch BDD-Testing ermöglichen. Am besten gefallen hat mit busted von Olivine-Labs.
Leider ist es etwas aufwändig für das Lightroom SDK ein Test-Harness zu erstellen, deshalb gibt es vorerst noch keine automatischen Tests für mein Plugin.
Ich nehme mir vor für die nächste Version das Rendern automatisiert zu testen.

4. Installer und Disk-Image erstellen

Das XCode-Tool pkgbuild ermöglich es, mit der Kommandozeile Pkg-Archive zu erstellen die sich mit dem OSX-Installer installieren lassen.

pkgbuild --identifier ch.andyhermann.videorenderer --install-location ~/Library/Application\ Support/Adobe/Lightroom/Modules/ --root plugin_src plugin.pkg

Leider erscheint ohne signieren des Packages eine Warnung beim Öffnen. Damit muss ich vorerst leben.

Unsigniertes Installer-Package


Das Verbreiten von Software für Mac OS X wird traditionell mit Disk-Images gemacht.
Auch dafür gibt es ein CLI-Tool namens hdituil dass sich einfach einbinden lässt:

hdiutil create "target/VideoRenderer.dmg" -volname "Video Renderer" -srcfolder "target/disk_image"

Natürlich soll der Build alle Schritte automatisiert durchführen. Mangels einfacher Alternativen für lua benutze ich dafür rake.

5. Plugin veröffentlichen

Ich nutze das Release-Feature von Github für ein einfaches Hosting der Dateien.
Die neuste Version des Plugins ist hier verfügbar.

Resultat eines einfachen Timelapse-Videos





Natürlich fehlen dem Plugin viele wichtige Features wie Deflickering, Stabilization, Ken-Burns etc.
Doch die Bedienung ist dafür ziemlich simpel.

Ich bin gespannt auf Feedback. Ist das Plugin nützlich für irgend jemanden?

Source Code des Projekts:
https://github.com/andreashermann/VideoRenderer