Grundlagen und Beispiele

HTML5: Video-Manipulation mit Canvas

Noch ist HTML5 nicht fertig, dennoch kann man viele Aspekte schon heute verwenden. Zu den Neuerungen gehört das canvas-Attribut, womit sich Grafiken dynamisch rendern lassen. Grund genug, sich dies einmal eingehend und praxisnah anzusehen.

Zu einer der offensichtlichen Neuerungen in HTML 5 gehört das Attribut <canvas>, das die Manipulation von Filmdaten direkt im Browser erlaubt. Im Grunde genommen, sind solche Funktionen schon längst mit der gängigen Videobearbeitungs-Software abgedeckt.

Der einzige Unterschied ist wahrscheinlich, dass der Nutzer die Autorenrolle übernimmt und weit mehr mit dem Video anstellen kann, als nur abspielen und gegebenfalls herunterladen.

Canvas-Grundlagen

Für die Effektmaschine im Browser braucht man an HTML-Elementen nichts weiter als ein Video-Element, zwei Canvas-Elemente und einen Script-Block:

<!doctype html>

<video id="film" width="320" height="180" controls>

<source src="video.mp4" type="video/mp4">

<source src="video.ogv" type="video/ogg">

</video>

<canvas id="zwischenablage" width="320" height="180" style="display:none"></canvas>

<canvas id="ziel" width="320" height="180"></canvas>

<script></script>

Zwei getrennte Canvas-Elemente braucht man in diesem Fall, weil die Video-Bearbeitung in zwei Schritten erfolgt (die einzelnen Pixel auf einem Video-Element kann man nur lesen - Ändern geht nur bei Canvas-Elementen). Dafür kopiert man die Video-Frames vom Canvas-Element in Canvas 1 und von dort in Canvas 2. Da Canvas 1 nur als Zwischenablage dient, kann man sie auch mit display:none unsichtbar machen. Jetzt fehlt nur noch DOM-Zugriff auf die drei Elemente …

// Elemente in der Seite

var film = document.getElementById('film'),

ziel = document.getElementById('ziel').getContext('2d');

zwischenablage = document.getElementById('zwischenablage').getContext('2d');

… und schon kann es losgehen.

Die richtige Framerate abpassen

Das Ziel ist also nun, jedes Frame des Videos abzupassen, zu kopieren und zu modifizieren. Das ist schwieriger als man vielleicht zunächst meint, denn herkömmliche JavaScript-Timing-Mechanismen (setTimeout() und setInterval()) sind nicht besonders exakt; mit ihnen kann man nicht garantieren, dass man jedes Frame erwischt oder dass man nicht manche Frames zweimal kopiert. Die korrekte Lösung für dieses Problem ist eine Funktion namens requestAnimationFrame(), die auf das nächste vom Browser gerenderte Frame wartet und dann einen Callback ausführt. Dieses Werkzeug sorgt, rekursiv angewendet, für einen präzisen Animations-Loop.

Making Apps Developer Days HTML 5

Making Apps Developer Days
Making Apps Developer Days

HTML 5 heißt das Zauberwort für alle App-Entwickler, die OS-übergreifende Apps entwickeln wollen. Die Grundlagen dafür liefert Making Apps mit einem zweitägigen Entwicklerworkshop am 13./14. September in München.

Wann: 13.-14. September 2011, 09 - 18 Uhr. Das Programm finden Sie hier.

Referenten: Peter Kröner, Jochen Grochtdreis

Wo: Skylounge, München

Preise:
Tag 1: 199 Euro (zzgl. MwSt.)
Tag 2: 599 Euro (zzgl: MwSt)
Tag 1+2: 749 Euro (zzgl. MwSt)
Early Birds buchen beide Tage im Paket für nur 699 Euro (zzgl. MwSt., Anmeldung bis zum 19.08.2011)

Weitere Infos und Anmeldung hier

Der Haken an der Sache ist, dass requestAnimationFrame() eine ziemlich neue Erfindung ist und in den diversen Browsern nur mit Vendor-Prefix zu finden ist. Damit man an dieser Stelle diese Funktion für jeden Browser einzeln programmiert, gibt es bereits eine Modifikation im Code, die die Verwendung von requestAnimationFrame() in allen Browsern erlaubt:

// Modifikation für requestAnimationFrame in allen Browsern

var animate = (function(){

return window.requestAnimationFrame ||

window.webkitRequestAnimationFrame ||

window.mozRequestAnimationFrame ||

window.oRequestAnimationFrame ||

window.msRequestAnimationFrame ||

function(callback){

setTimeout(callback, 1000 / 60);

};

})();

Hier wird dafür gesorgt, dass der Nutzer unter animate die bestmögliche Implementierung von requestAnimationFrame() vorfindet, die der Browser zu bieten hat; zur Not auch eine Variante mit Vendor-Prefix oder, wenn nichts davon funktioniert, auch ein herkömmlicher setTimeout().

Damit man auch eine Animationsschleife erhält, muss man animate wieder und wieder aufrufen, wobei jeder Aufruf der Funktion ein einzelnes Frame abhandelt. Auch diese Funktionalität wird wieder in eine Hilfsfunktion versteckt:

// Die Kopier-Schleife

function loop(){

if(!film.paused){

animate(loop);

}

}

Hier wird loop() immer wieder automatisch aufgerufen - jeweils durch den requestAnimationFrame() gesteuert und nur so lange, wie das Video läuft. Jetzt fehlt nur noch die Auslösung für die Kopier-Schleife, wofür das Video-Element einen passenden Event bereitstellt:

// Die Kopier-Schleife starten

film.addEventListener('play', function(){

loop();

}, false);

Zu diesem Zeitpunkt kann man die Animationsschleife starten, laufen lassen und stoppen. Damit mit dem Video wirklich etwas passiert, muss man noch ein paar weitere Funktionen programmieren.