protofunc()

jme – das erste HTML6 audio/video development kit

Tags: HTML 5, accessibility, deutsch, javascript, jquery, video

Es gibt zwei Dinge mit denen mein jMediaelement Projekt allein nicht beschrieben wäre: HTML5 audio / video einerseits und Player-Script andererseits. Die von jme genutzen HTML5 Media-Elemente sind nur eine Abspieltechnologie von insgesamt dreien. Würde man den HTML5 Teil weglassen und damit lediglich Flash und VLC als Abspieltechnik dienen, hätte jme weiterhin imense Vorteile für Frontendentwickler. Das liegt unter anderem daran, daß jme eben kein reines Player-Script ist.

jme besteht aus 2 Hauptkomponeten:

  1. einem leichtgewichtigem, kugelsicheren reinen embed-Teil
  2. der “Vollversion”, welche neben dem embed-Teil, auch die DOM-API und die Markup-API (Controls) enthält

Media-Elemente einbinden schnell und einfach wie ein Bild

In vielen Fällen, in denen ein Entwickler einen Videoplayer einbinden muß, ist kein spezielles Design und kein besonderes Feature verlangt. Es geht schlicht weg darum einen Player zum Abspieln von Videos/Audios zu haben.

Der reine embed-Teil von jme ist daher in einer separaten Version als leichtgewichtiger Helper eingebunden.

Der notwendige HTML-Code ist identisch mit dem HTML5 Code:

<video src="myvideo.webm" poster="mein-poster.jpg" controls="controls">
	<!-- Fallback Content -->
</video>

Damit dies auch ohne Bugs und mit älteren Browsern funktioniert, kopiert man einfach die mm.embed.min.js aus dem packages Ordner vom jMediaelement-Download zusammen mit der player.swf und – falls man youtube-videos einbinden will – der yt.swf in einen gemeinsamen Ordner.

Danach kann man bei DOM-Ready seine HTML5 Media-Elemente mit jmeEmbed registieren:

$(document).ready(function(){
	$('audio, video').jmeEmbed({showFallback: true});
});

Der embed Teil kümmert sich um die Erkennung von Browser- und Plugin-Features, deren Einbindung/Initialisierung, der Normalisierung der HTML5 Mediaelement Attribute sowie der hiermit zusammenhängenden Bugs. Ist die Vollversion von jme eingebunden, wird hierdurch auch die DOM-API initialisiert. Die Vorteile für den Entwickler:

  • er hat einen einfachen, intuitiven und semantischen Einbindecode
  • Sofern ein Video mit richtigem Container/Codec eingebunden wird, erhöht sich die Zugänglichkeit für bestimmte Endgeräte
  • der Entwickler ist nicht gezwungen mehrere Video-Formate anzubieten. Letztendlich können auch nicht HTML5-Formate wie zum Beispiel flv-Dateien oder Youtube-Seiten als Datengrundlage genommen werden.
  • Die jeweiligen Browser-, Plugin-Player rendern die Kontrolelemente automatisch, so daß keine weiteren HTML-/CSS-Anpassungen anfallen.

Kurz: Gegenüber der Art wie man derzeit Videos einbindet, kommt man hier mit jme schneller, semantischer und manchmal auch zugänglicher ans Ziel.

HTML ist die Schnittstelle zwischen JavaScript und CSS oder “divide et impera” – Teile und herrsche

Der zweite Teil ist keine reine JavaScript API, sondern gliedert sich in DOM-API und Markup-API auf. Dieser Aufbau ist der Erkenntnis geschuldet, daß JavaScript nur wenig HTML diktieren sollte und HTML unter anderem eine Schnittstelle zwischen einerseits JavaScript und CSS und andererseits zwischen Frontend und Backend darstellt.

Die Erstellung von funktionsfähigen Kontrollelementen ist Aufgabe der Markup-API. Features welche nicht über die Markup-API realisiert sind, können mit Hilfe der DOM-API erledigt werden.

HTML6 Control-Elemente = jme Markup-API/Kontrollklassen

Anstatt, daß durch einen JavaScript-Aufruf ein Haufen unsemantischer HTML-Code um den Player gepackt wird, besteht jme aus kleinen Bausteinen, die einfach zusammengesetzt werden können und so einen individuellen Player ermöglichen. Hierbei besteht als oberstes Prinzip, daß sich die verwendeten Bausteine flexibel in die HTML-/DOM-Welt integrieren laßen müßen.

Stell Dir vor HTML5 ist Schnee von gestern und das W3C würde mit HTML6 einige neue Elemente spezifizieren, welche als Kontrollelemente für das audio- und video-element dienen. Ein Abspiel-/-Pause Button könnte wie folgt aussehen:

<button type="play-pause">play / pause</button>

Das schöne daran, der Browser kümmert sich um Funktionalität und Zugänglichkeit und der Entwickler besitzt die Flexibilität die Kontrollelemente erstens frei zu platzieren und zweitens mit weiterem HTML anzureichen, um Sie dann beispielsweise per CSS besser zu stylen oder um ein gewünschtes Userinterface-Verhalten zu erreichen.

Damit der Browser weiß, mit welchem Mediaelement das jeweilige Kontrollelement verbunden ist, werden die Kontrollelemente gemeinsam mit dem Mediaelement in einem ebenfalls neuen Element mit dem Namen player gewrappt. Das Ergebnis sieht dann wie folgt aus:

<player>
	<video src="myvideo.webm"></video>
	<button type="play-pause">play / pause</button>
</player>

Die jme Kontrollelement-Bausteine funktionieren hierbei auf ähnliche Weise. Die neuen Kontrollelemente werden durch beliebige valide Elemente mit bestimmten HTML-Klassen symbolisiert und lediglich das Wrapper-Element “player” wird durch einen JavaScript Aufruf ersetzt:

<div class="player-wrapper">
	<video src="myvideo.webm" controls="controls"></video>
	<button class="play-pause">play / pause</button>
</div>

Das jQuery-Plugin ‘jmeControl’, welches auf dem wrapper-Element aufgerufen wird, registriert hierbei sozusagen die einzelnen Kontrolelemente und ruft bei Bedarf, die embed-Methode auf. Genau wie bei der jmeEmbed-Methode muß grundsätzlich keine weitere Konfiguration vorgenommen werden.

$('div.player-wrapper').jmeControl();

Werden die nativen Kontrollelemente nicht angezeigt, wird der Flashplayer – sofern nicht ausdrücklich anders konfiguriert – automatisch in den wmode=transparent Zustand versetzt, um auch schöne Overlay-Kontrollelemente oder Overlay-Logos über dem Video erstellen zu können.

Man kann selbstverständlich auch mehrere Kontrollelemente unterbringen:

<div class="player-wrapper">
	<video src="myvideo.webm" controls="controls"></video>
	<button class="play-pause">play / pause</button>
	<span class="current-time">--:--</span>
</div>

jme kümmert sich hierbei nicht nur um die Funktionalität und rendert die jeweils aktuelle Zeit in das span-Element und erstellt ein Play-Pause-Toggle Verhalten aus dem button-element, sondern auch um die Zugänglichkeit. Insbesondere dann, wenn zum einfacheren Stylen statt dem button-Element ein span-Element genommen wird, fügt jme die gewollte Semantik per WAI-ARIA ein. Folgendes geschriebenes HTML ….

<div class="player-wrapper">
	<video src="myvideo.webm" controls="controls"></video>
	<span class="play-pause">play / pause</span>
	<span class="current-time">--:--</span>
</div>

…wird durch jme in folgendes HTML umgewandelt:

<div class="player-wrapper">
	<video src="myvideo.webm"></video>
	<span role="button" tabindex="0" class="play-pause">play / pause</span>
	<span role="timer" class="current-time">--:--</span>
</div>

Neben allgemein üblichen Video/Audio Kontroll-Elementen bietet jme über Plugins auch Verhaltensklassen für eine Playliste und Captions an.

Die Tatsache, daß wir eine Markup-API verwenden, die nicht von JavaScript diktiert wird, heißt aber nicht, daß wir nun alle möglichen Kontroll-/Verhaltensklassen auswendig lernen und wieder und wieder ins HTML schreiben müßen. jme bietet im utils-Ordner das jmeEmbedControls-Plugin an, welches nichts anderes macht, als einen Haufen Kontrollelemente in das Element, auf dem es aufgerufen wurde, einzufügen, um dann hierauf die jmeControl-Methode auszuführen. Diese Methode ist sozusagen das Schnellstarter-Kit für jme. Er ist bewußt ausgelagert, um jedem Webentwickler eine projektspezifische Anpassung zu ermöglichen.

einheitliche DOM-API statt vereinheitlichte JavaScript-API

Die vereinheitlichte JavaScript-API ist bei jme bewußt eine DOM-API, da nur so sich Mediaelemente, sei es nun HTML5, Flash oder VLC, in den normalen Workflow eines Frontendentwicklers integrieren können.

Ein Beispiel: JW-Player for HTML5 ist das erste HTML5 Player-Script, welches eine dokumentierte API vorweisen kann. Und obwohl jQuery, also ein klassischer DOM-Wrapper, als JavaScript Grundlage gewählt wurde, wurde keine DOM-API implementiert. Um einen Player zu scripten, sieht der Code wie folgt aus:

$.jwplayer().play();

Laut Dokumentation wird nun immer auf dem ersten eingebundenen Mediaelement die Methode play aufgerufen, möchte man nun jedoch auf einem anderen Mediaelement Methoden ausführen, muß man bereits zum Zeitpunkt der Initialisierung die Referenz auf dieses Objekt speichern und sicherstellen, daß alle Module die hiermit interagieren müßen an diese Referenz kommen:

//holen der Referenz auf ein bestimmtes Video bei der Initialisierung
var player = $('#stage video').jwplayer({
	flashplayer:'/static/files/player.swf',
	skin:'/static/files/five.xml'
});

//initialisieren aller anderen videos
$('video').not('#stage video').jwplayer({
	flashplayer:'/static/files/player.swf',
	skin:'/static/files/five.xml'
});

//arbeiten mit der gespeicherten Referenz
//irgendwo ganz anders im script
player.play();

Mit einer DOM-API sieht die Sache dagegen anders aus, denn die API ist Teil des DOMs und kann wie jede DOM-API mit der jQuery-Selektorengine selektiert werden.:

$('#stage video').play();

Ebenso wie man bei anderen DOM-Elementen auf Events horcht, Methoden chained etc., funktioniert dies auch bei jme. Das video bzw. das audio Element bleiben hierbei immer das zentrale API Element, gleichgültig ob tatsächlich HTML5 oder eben ein Plugin zur Anzeige der Mediainahlte genutzt wird.

$('video').bind('ended', function(){
	$(this).attr('autoplay', true).loadSrc('my-video2.webm');
});

Kurz: nur so kann Scripten Spaß machen.

Fazit

Merkwürdig aber wahr: jme stellt in vielen Punkten einige Weltrekorde auf:

  1. jme ist das erste audio/video Script mit Fallback, welches eine dokumentierte DOM-API besitzt (das werden garantiert einige nachmachen, da es sooo nahe liegt)
  2. jme ist das erste audio/video Script, welches eine Markup-API für Kontroll- und Zustandselemente verwendet
  3. jme ist – und das ist wirklich traurig – das erste Script seiner Art, welches semantischen Code erlaubt/nutzt (notfalls mit WAI-ARIA forciert)

Oder anders gesagt: jme versucht nicht aus HTML5 Flash zu machen, sondern aus Flash HTML5.

Written June 6, 2010 by
alexander farkas

9 Comments »

  1. Hi
    excelent work,

    i have a question,how i can load this link
    http://srv2.streaming-ingenierie.fr:8142/;stream.nsv

    this is houtcast radio streaming and the player of JW permit to load this types

    thanks advance.

    Comment by dztic — July 19, 2010 @ 10:26 pm

  2. Hello dztic,

    Could you provide me with the right JW-Player embed code, so I can provide you with a transformable “HTML5/JME”-Code. For now the following code did the job, but I don’t know wether this is the exactly right code for JW-Player:

    $(‘audio’).jmeEmbed({
    jwPlayer: {
    vars: {
    type: ’sound’
    }
    }
    });

    [audio controls="controls" data-provider="rtmp"]
    [source src="http://srv2.streaming-ingenierie.fr:8142/;stream.nsv" type="audio/x-fla" /]
    [/audio]

    The trick is:

    1. configure the vars-property for the jw-player to match type=sound
    2. add a data-provider, wich makes the same as the flashvar provider
    3. use the type attribute to force jwplayer

    Comment by alexander farkas — July 20, 2010 @ 9:00 pm

  3. Hallo Alexander,
    vielen Dank für deine Arbeit an einer wirklich Benutzerfreundlichen Lösung.

    Bei einer Sache allerdings komme ich nicht weiter. Ich versuche die Videos in einer Fancybox zu zeigen. Mit den Tags funktioniert das auch prima. Nur das script für den Flash fallback bleibt anscheinend stecken. Nur der Opera 10.10 unter osx bringt den JW Player an den Start.

    Kannst Du mir einen Tip geben?

    Kirk

    Comment by Kirk Monteux — July 26, 2010 @ 2:21 pm

  4. Hallo Kirk,

    ich brauche leider mehr Informationen. Ich habe unter http://protofunc.com/jme/demos/fancybox/ mehrere kleine Beispiele mit der fancybox gemacht (inline Beispiel) und es funktioniert mit allen Beispielen ohne Probleme (auch mit dem Flashfallback).

    Hier ein paar Fragen:

    1. Welche Version von jme nutzt du?
    2. Ist der Pfad zum JW Player richtig gesetzt? Du kannst das überprüfen, indem du jQuery.fn.jmeEmbed.defaults.jwPlayer.path
    in die Firebug Console eingibst.
    3. Wurde jmeEmbed/jmeControl auf dem video-element / wrapper-element aufgerufen?
    4. Versucht jme das Fallback zu rendern (dann wird das video-element auf display: none gesetzt und direkt vor dem video erscheint ein neuer div-container. <- mit Firebug überprüfen).
    5. Wenn 5. klappt hat der div-container die richtige Größe ist der Pfad zum video richtig, ist der pfad zum Flashfallback richtig?
    6. Nutzt du eine andere fancybox-Methode als “inline”?

    Wenn das nicht weiterführt, wäre es hilfreich, wenn du eine vereinfachte Version mit dem Fehler hochladen könntest.

    Grüße
    Alex

    Comment by alexander farkas — July 28, 2010 @ 12:43 pm

  5. Hallo Alex,
    vielen Dank für deine Antwort.
    Mittlerweile habe ich weiter experimentiert und festgestellt das ich mit einer alten Version von fancybox gebastelt habe. Ich werde jetzt mal mit der aktuellen fancybox 1.3.1 deine Beispiele nachbauen und werde berichten.

    Kirk

    Comment by Kirk Monteux — July 29, 2010 @ 3:02 am

  6. Hallo Alex,
    ich habe jetzt jede Menge ausprobiert und eigens ein ipad angeschafft um alles zu testen.
    Es gibt mit der fancybox ein merkwürdiges Verhalten auch deine Beispiele sind davon betroffen.
    Mann muss den Link zum Video dreimal erneut klicken und jeweils die fancybox wieder schließen erst dann kann das Video abgespielt werden. klickst du ein viertes mal geht das ganze wieder von vorne los. Wieder 3 mal klicken bis der Play Button gezeigt wird. Sehr merkwürdig. Im vergleich ein youtube Video geht auf der Stelle. Kannst Du dir das erklären hast Du die Möglichkeit das auch auf einem iPad zu testen?

    Kirk

    Comment by Kirk Monteux — August 3, 2010 @ 11:56 pm

  7. Hallo Alex,
    ich nochmal. Habe da wohl eine Erklärung gefunden. Schau dir das mal an:

    http://blog.noinc.com/2010/05/13/html5-video-tag-iphone-ipad-ihaveheadache/

    Die Äpfel werden immer fauler!!

    Kirk

    Comment by Kirk Monteux — August 4, 2010 @ 2:48 am

  8. Hi Kirk,

    danke für den Artikel. Habe ihn noch nicht durchgelesen, was ich tun werde. (vielleicht hilft es mir bei der Erledigung des Bugs)

    Ich hatte mir aus unserer Firma mal das iPad ausgeliehen, um hier zu testen. Grundsätzlich müßte das Player Script funktionieren. Es gab hierbei übrigens mehrere kleine Probleme. Das offenkundigste war, daß das iPad wie auch das iPhone weder ein progress (Safari 5) noch ein load (Safari 5) kennt, um den aktuellen Bufferstatus mitzuteilen, man muß vielmehr mit einem interval ständig pollen.

    Ich weiß aber auch, daß mein “offizielles Dialog/Tab-Beispiel” im iPad/iPhone nicht funktioniert. Oberflächliche Ursache war, daß das iPad videos irgendwie nicht richtig initialisiert, wenn diese in einem display:none Bereich liegen. Damit verhält sich das video-Element im iPad ziemlich ähnlich zu dem, was uns normale Frontendentwickler so an Flash und anderen Plugins stört. Sie verhalten sich eben nicht normal wie andere HTML-Elemente. Sogar die offiziellen HTML5-Video-Beispiele von Apple funktionieren im iPad nicht so wie man es erwartet (http://www.apple.com/html5/showcase/video/). Das video hört nachdem man transform anwendet – meiner Erinnerung nach – einfach auf zu spielen. Im Ergebnis ziemlich peinlich für Steve.

    Als Lösungsmöglichkeit könnte ich mir eine Art Reinitialiserungsscript vorstellen, welches praktisch kurz nach dem Anzeigen der Fancybox aufgerufen werden muß, um das Videoelement in die richtige Bahn zu treten. Soetwas würde ich aber wohl nur als extra Plugin veröffentlichen. Interesse?

    P.S. In Desktop-Browsern funktionert aber dein Beispiel jetzt?

    Grüße
    Alexander

    Comment by alexander farkas — August 5, 2010 @ 8:29 pm

  9. Hallo Alexander,
    In den Desktop-Browsern ist alles in Ordnung.

    Dein Angebot ein Plugin zu verfassen interessiert mich sehr. Ich weis allerdings nicht wie Aufwändig das für dich wird. Und wie kompliziert das für mich wird. Bin Designer kein Prog.

    Ausserdem sollten wir vielleicht erst mal das bevorstehende ios4 update für das ipad abwarten.

    Was meinst Du?

    Kirk

    Comment by Kirk Monteux — August 6, 2010 @ 11:17 pm

RSS feed for comments on this post | TrackBack URL

Leave a comment