Von Jan Braitinger

Große Videodateien klein machen und Platz sparen – heute noch sinnvoll? Ja klar! Gerade wenn Videos über das Internet verschickt werden sollen, ist es nützlich diese zu komprimieren und sie somit in kürzerer Zeit übermitteln zu können.

Im Rahmen eines Informatikprojektes wurde eine Webanwendung zur Komprimierung von Videodateien entwickelt. Der Nutzer ist dadurch in der Lage, Videos ohne jegliche Zusatzsoftware im Browser zu komprimieren und anschließend herunterzuladen bzw. zu versenden.

Bedienoberfläche

Bei diesem Projekt wurden unterschiedliche Webtechnologien, Skript- und Programmiersprachen, Bibliotheken und eine NoSQL-Datenbank verwendet. Das Backend basiert auf der Plattform node.js, agiert zusammen mit einer MongoDB-Datenbank und nutzt FFmpeg, eine führende Bibliothek zur Verarbeitung und Komprimierung von Videodaten. Der Client bzw. das Frontend besteht aus einer Mischung aus Embedded JavaScript (ejs), HTML, CSS und JavaScript.

Architektur
Die Webanwendung basiert auf einer Client-Server-Architektur. Der Client bzw. das Frontend nimmt Daten und Eingaben des Nutzers entgegen und übermittelt diese dem Server. Dieser verarbeitet die Daten und schickt sie zurück an den Client. Großer Vorteil dieser Architektur ist, dass der Client und somit der Rechner des Nutzers vollkommen entlastet wird, da die komplette Datenverarbeitung auf Seiten des Servers stattfindet.

Das HTTP-Protokoll unterstützt verschiedene Anfragemethoden, unter anderem POST- und GET-Requests. Erstere werden genutzt, wenn durch einen Request Daten auf dem Server geändert oder beispielsweise Passwörter an diesen übermittelt werden sollen. GET-Requests werden dann genutzt, wenn der Client Daten als Antwort vom Server beziehen möchte.

Sobald ein Nutzer auf die Webseite mit der Webanwendung zugreift, sendet der Client einen GET-Request an den Server und bekommt die Webseite ausgeliefert. Nach der Eingabe der Parameter und Auswahl der Videodatei durch den Nutzer sendet der Client alle Daten per POST-Request an den Server. Dieser verarbeitet die Daten und schickt das komprimierte Video mit einem komplett neuem HTML-Gerüst (Vorschauseite) zurück an den Client.

Server

Node.js

Der Server wurde mittels node.js implementiert. Die serverseitige Plattform wird oft für die Realisierung von Webanwendungen genutzt. Betrieben wir diese in einer JavasScript-Laufzeitumgebung. Grund für die Wahl ist zum einen die einfache Möglichkeit vom asynchronen, nicht-blockierende Ein- und Ausgabe von Daten und zum anderen die Vielzahl an verfügbaren Bibliotheken durch den Paketmanager npm. Als Grundlage für diese Webanwendung dient das Web-Framework express.  Es bringt leistungsfähige Features und Funktionen für Webanwendungen mit sich.

const express = require('express');
const app = express();
app.use(express.static('./public')); // Verzeichnis waehlen

Eine weitere wichtige Library ist multer. Durch diese ist es einfach multipart/form-data zu verarbeiten.  Mithilfe von multer werden die vom Client entgegen genommenen Videodateien auf den Server geladen.

 const storage = multer.diskStorage({
     destination: './public/upload',
     filename: function(req, file, cb) {
         cb(null, file.fieldname + '-   ' + Date.now() + generateRandomValue() + path.extname(file.originalname));      }
 });

Mit Hilfe von einfachen Deklarationen werden Pfad und Dateiname der hochgeladenen Dateien festgelegt. Des Weiteren ist die Angabe einer Speicherobergrenze wichtig. Damit soll eine Überlastung des Servers aufgrund zu hoher Datenmengen verhindert werden.

MongoDB

Die NoSQL-Datenbank MongoDB läuft eigenständig und ist für die Verwaltung der Daten zuständig. Dementsprechend muss zuvor der MongoDB-Client auf dem Server eingerichtet und anschließend verknüpft werden.

const MongoClient = require('mongodb').MongoClient

Die Verbindung mit der Datenbank ist über eine asynchrone Methode geregelt. Hier werden die davor definierten Parameter übergeben und anschließend eine Collection erstellt. In dieser sind die Informationen der komprimierten Videodateien abgespeichert.

function handleDBConnection() {
     MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
         if (err) throw err;
         dbo = db.db("mydb");
         createCollection();
     });
 }

Als Vorsichtsmaßnahme werden alle Videodateien nur für eine bestimmte Zeit gespeichert. Dadurch soll verhindert werden, dass der Speicher des Servers knapp wird bzw. sogar überläuft. Jeden Tag wird zu einer bestimmt festgelegten Uhrzeit ein Trigger ausgelöst. Dieser prüft die Zeitstempel der einzelnen Datenbestände (Datum der Komprimierung des Videos). Anschließend berechnet der Server anhand einer fest definierten maximalen Speicherdauer, ob der jeweilige Datenbestand gelöscht wird oder in der Datenbank erhalten bleibt.

Ein Datensatz besitzt verschiedene Parameter. Um die Videodateien eindeutig identifizieren zu können, besitzen alle eine ID. Diese wird automatisch aus dem Datum des Uploads und einer Zufallszahl generiert. Weitere Teile des Datensatzes sind zum Beispiel noch der Pfad und der Zeitstempel der Konvertierung.

FFmpeg

FFmpeg umfasst eine Reihe von Programmen und Bibliotheken zum Komprimieren und Konvertieren von Video- und Audiodateien. Es enthält eine große Sammlung gängiger Audio- und Videocodecs. Für dieses Projekt sind speziell die Codecs H.264, H.265 und AV1 interessant.

H.264 ist ein auf dem MPEG-4 basierender Videokompressionsstandard und seit der Nutzung von Full HD (1920×1080 Pixel) einer der Standards in der Industrie. Entwickelt wurde der Standard gemeinsam von der ITU-T Video Coding Experts Group (VCEG) und der ISO/IEC JTC1 Moving Picture Expferts Group (MPEG).

Dateiupload

Im Jahr 2013 wurde der Nachfolger H.265 vorgestellt. Im Vergleich zu seinem Vorgänger hat dieser eine „[…] doppelt so hohe Kompression bei gleichbleibender Qualität.“ Zusätzlich ist es mit H.265 möglich Ultra HD bzw. Videodateien bis 8K (8192 × 4320 Pixel) zu verarbeiten. Ein gravierender Nachteil des Codes ist jedoch, dass der HTML-Standard -Videoplayer diesen nicht unterstützt.

Beide vorgestellten Algorithmen stehen nicht frei zur Verfügung und müssen lizenzrechtlich erworben werden. Eine Alternative dazu bietet das neue Komprimierungsverfahren AV1. Der Codec ist Open-Source und steht frei zur Nutzung zur Verfügung. Vorgestellt wurde dieser am 2018 von der Alliance for Open Media und ist seitdem vor allem bei Open-Source-Projekten stark vertreten. Ziel des Algorithmus ist es eine um 25% bessere Kompressionsrate als sein Konkurrent H.265 zu erzielen. AV1 kommt speziell für Echtzeitanwendungen sowie höhere Auflösungen zum Einsatz.

Die Initialisierung und Verknüpfung der Webanwendung mit FFmpeg ist simpel. Ein einfaches Einbinden des Programms reicht aus, um damit arbeiten zu können.

var ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath("C:\\ffmpeg\\bin\\ffmpeg.exe"); 

Zu Beginn werden wichtige Parameter wie die oben beschriebenen Codecs definiert.

const compressedPath = "/upload/compressed/",
     _standardFPS = '25',
     _codec = {
         H264: 'libx264',
         H265: 'libx265',
         AV1: 'libaom-av1'
     },
     { H264, H265, AV1 } = _codec,
     _audio = {
         ON: '1.0',
         OFF: '0.0'
     };

Das eigentliche Komprimieren bzw. Konvertieren findet statt, indem ein neues Objekt des Typs ffmpeg erstellt wird. Diesem werden die Parameter (Codec, Bilder pro Sekunde, Audio) für das Zielvideo mitgegeben. Das alles kann der Nutzer über die Webseite definieren.

new ffmpeg(path)
         .videoCodec(codec)
         .fps(framePerSecond)
         .audioFilters({
             filter: 'volume',
             options: 
         })

Die Kompression findet auf dem Server und nicht auf dem Rechner des Clients statt. Dementsprechend gilt es zu beachten, dass der Server hardwaretechnisch so ausgestattet sein muss, dass er eine Komprimierung in adäquater Zeit durchführen kann, auch wenn mehrere Videodateien zeitgleich komprimiert werden.

Client

Ein wichtiges Element hierbei sind Embedded JavaScript templates (ejs). Mit Hilfe dieser Template-Sprache ist es möglich HTML aus JavaScript generieren zu können. Serverseitig wird ejs direkt zu Beginn als sogenannte „view engine“ festgelegt.

app.set('view engine', 'ejs');

Sobald der Server die Videodatei(en) vom Client erhalten und komprimiert hat, schickt er dem Client eine neue ejs-Datei mit den relevanten Parametern wie z.B. dem Pfad zum komprimierten Video.

   res.render('show.ejs', {
                    // send videoparameters to client
                    link: downloadLinkHelper(compressedPath + filename),
                    videoname: filename,
                    codec: codec,
                    date: dateFormat(deadline, "dd.mm.yyyy"),
                    size: formatBytes(metadata.format.size),
                    url: `http://${hostname}:${port}${compressedPath}
                         ${filename.split('.').slice(0, -1).join('.')}`
                });

Ejs wird im Frontend direkt in HTML-Tags eingebunden.

<source src="<%= link %>"> type="video/mp4">
   Your browser does not support the video tag.
 </video>

Nach Abschluss der Kompression kann der Nutzer die Videodatei nun direkt herunterladen oder den generierten Link an Dritte weitersenden.

Fazit

Abschließend kann festgehalten werden, dass das Projekt großen Spaß gemacht hat. Zu Beginn war es recht schwierig sich in das Thema einzuarbeiten, da eigene Vorkenntnisse häufig nicht vorhanden waren. Aber gerade das hat den Reiz ausgemacht – etwas Neues zu lernen. Dementsprechend war die Lernkurve steil und seit dem Projekt nutzt man beispielsweise FFmpeg verstärkt auch im privaten Gebrauch.
Insgesamt konnten fast alle formulierten Anforderungen umgesetzt werden. Einzig kleinere Funktionalitäten wie zum Beispiel „Drag and Drop“ wurden aus Gründen von Fehleranfälligkeit deaktiviert, sind jedoch im Code weiter vorhanden.

Für Videofreaks und solche, die es noch werden wollen: Der Code der Anwendung kann heruntergeladen werden unter diesem GitHub-Account.


Literaturnachweise:

https://www.black-box.de/de-de/page/38306/Information/Technische-Ressourcen/black-box-erklaert/multimedia/H264-Videokompression

https://www.slashcam.de/news/single/Open-Source-AV1-vs-H-264-vs-H-265–ist-der-Videoco-13327.html

https://github.com/Kagami/ffmpeg.js/

https://wiki.selfhtml.org/wiki/HTTP/Anfragemethoden