HTML5 videospeler

Met de komst van HTML5 werd de video-tag geïntroduceerd en daarmee een alternatief voor de Adobe Flash-player om video in een site af te spelen. Dat is vooral handig op devices die geen Flash ondersteuning aanbieden.
Zoals verder in detail aangegeven is implementatie in de huidige browsers niet optimaal en voorzien we nog altijd een Flash-player als fallback voor browsers zoals Internet Explorer 6, 7 en 8.

De basiscode

  1. <video width="608" height="256" controls">
  2. <source src="video/walle_small.mp4">
  3. </video>

Ondersteuning van video

  • Firefox 3.5+, Chrome 5.0+, Opera 10.5+: Theora (.ogv files)
  • Safari 3.0+, Chrome 5.0+, iPhone 3.0+, Android 2.0+: H.264 (.mp4 files, baseline Profile + AAC audio met een “low-complexity” profile)
  • Internet Explorer 9, Firefox 4.0+, Chrome 6.0+, Opera 11.0+: WebM (.webm files)

Zoals je ziet, wordt de video-tag enkel in recente browsers ondersteund, en bovendien ondersteunen ze niet allemaal hetzelfde formaat. We moeten daarom 3 verschillende sources vermelden in de code. Daarbij vermelden we ook het type en de codec die gebruikt moet worden op het bijhorende bestand te kunnen lezen. De enige uitzondering daarop is de .mp4 want Android 2.2 kan dit dan weer niet lezen.
Ook de volgorde is belangrijk. De .mp4 moet eerst staat, vooral omdat iOS 3.x enkel de eerste source-tag leest en de rest overslaat.
Meer informatie over codecs en converteren vind je op Dive into HTML5

De code

  1. <video width="608" height="256" controls>
  2. <source src="video/walle_small.mp4"><!-- H.264 -->
  3. <source src="video/walle_small.webm" type="video/webm; codecs="vp8, vorbis""><!-- WebM -->
  4. <source src="video/walle_small.ogv" type="video/ogg; codecs="theora, vorbis""><!-- Theora/Vorbis -->
  5. <!-- Include fallback here -->
  6. </video>

Om ervoor te zorgen dat de server het juiste mime-type gebruikt plaatsen we nog deze regels in onze .htaccess file. als dit niet werkt moeten de mime-types waarschijnlijk nog toegevoegd worden aan de server zelf.

  1. AddType video/ogg .ogv
  2. AddType video/mp4 .mp4
  3. AddType video/webm .webm

Oudere browsers

De fall-back code (bvb. een embed van een Flash player of een YouTube video) mag je tussen de video-tags, na de source-tags zetten. Recente browsers zullen die code negeren, terwijl oudere browsers de video- en source-tags dan weer niet gebruiken.

Mobiele browsers

  • Android 2.2 bevat een bug waardoor de default controls van video niet gebruikt kunnen worden, we zijn dus genoodzaakt om via javascript custom controls te voorzien.
  • iPad/iPhone kunnen dan weer geen custom controls inlezen dus moeten we daar terugvallen op de default controls.
  • iOS 3.x op iPad en iPhone bevat een bug waardoor de video niet zal spelen als er een poster-attribute meegegeven is aan de video. Dus vooral geen poster gebruiken als je deze wil ondersteunen.

Custom controls

Als we graag wat meer controle hebben over hoe onze player eruit ziet (en als we Android 2.2 willen ondersteunen) gaan we zelf knoppen toevoegen en aansturen via JavaScript. In onderstaande custom player gebruiken we alvast deze functies, opgebouwd via JQuery:

  • Play/pauze knop
  • Grote play/pauze knop als overlay
  • Rewind
  • Tijdsverloop
  • scrubber
  • Totale speeltijd
  • Mute
  • Volume slider

Demo

Je kan de player zien in deze demo.

CSS sprites in de praktijk: Plan België titels

Dit is het eerste deel van een reeks artikels over CSS technieken waarbij sprites op een creatieve manier worden gebruikt om flexibele en performante resultaten te bekomen.

Aan de hand van CSS sprites kan je het aantal requests op een website beperken, door verschillende afbeeldingen in 1 of meerdere afbeeldingen te combineren. Dit heeft een grote impact op de performantie van je website. Als de sprites dan ook nog eens gecached worden, kan dit de rendering van de pagina’s drastisch optimaliseren.

Plan België

Zo hebben we ondermeer gezorgd voor een grondige frontend optimalisatie bij de uitwerking van de Plan België website. Het doel daar, was om het aantal requests tot een minimum beperken, omwille van het grafische karakter van de site. Daarom leek het ons wel een uitdaging om creatief aan de slag te gaan met PNG afbeeldingen en trachten 1 sprite te maken voor alle titels over heel de website.

Flexibele en herbruikbare PNG’s

Doorheen de Plan België website vind je dit soort titels:

Voorbeeld titels op Plan België website

Voorbeeld titels op Plan België website

Zoals je kan zien: verschillende kleuren en variabele breedtes zijn mogelijk.

Analyse en aanpak

Het idee dat we hadden, was om een transparante afbeelding te gebruiken, waarbij we hetgene dat wit moet zijn, wit houden en hetgene ingekleurd moet worden, transparant. Daardoor kunnen we via CSS een achtergrondafbeelding + achtergrondkleur specifiëren.

Om het gewenste effect te krijgen, maken we gebruik van een 24-bit PNG file. De afbeelding omvat tevens een semi-transparant gedeelte, waar een lichtere variant van de kleur doorschijnt (opacity 85%).

(Semi)transparante 24-bit PNG waarbij ter illustratie het transparante gedeelte groen is ingekleurd

(Semi)transparante 24-bit PNG waarbij ter illustratie het transparante gedeelte groen is ingekleurd

De sprite bestaat dus uit twee delen: .bg en .border

De sprite bestaat dus uit twee delen: .bg en .border

Omdat transparante 24-bit PNG files niet ondersteund worden in Internet Explorer 6, opteren we ervoor om in die browser een 8-bit PNG versie te voorzien. Het resultaat in deze browser is een iets ruwere versie, maar omdat bij Plan België het toch ging om een grunge look, vormde dat geen probleem.

De code

HTML
  1. <h2>
  2. <span class="border">Steun Plan</span>
  3. <span class="bg"></span>
  4. </h2>
Er zijn twee extra spans nodig om de styling naar behoren uit te voeren.

CSS
  1. h2 {
  2. position: relative;
  3. font-size: 15px;
  4. height: 32px;
  5. }
Position wordt op relative geplaatst, om een span absoluut te kunnen positioneren t.o.v. de h2. Verder wordt een vaste hoogte bepaald, omdat de children ofwel absoluut gepositioneerd zullen zijn, ofwel een float zullen krijgen.

  1. .bg {
  2. position: absolute;
  3. left: 0;
  4. height: 18px;
  5. padding: 7px 10px 3px;
  6. color: #fff;
  7. background: #0D5F99 url(img/sprite.png) no-repeat 0 0;
  8. }
De .bg class is het gekleurde vlak achter de tekst. Het wordt absoluut gepositioneerd, krijgt een witte tekstkleur, als achtergrond een kleur én een afbeelding (het bovenste deel van de sprite).

De totale hoogte is 18px + 7px (padding-top) + 3px (padding-bottom) = 28px.

  1. .border {
  2. float: left;
  3. margin: 2px 0 0;
  4. height: 28px;
  5. width: 100%;
  6. background: #0D5F99 url(img/sprite.png) no-repeat 0 100%;
  7. }
De .border class krijgt een float: left, alsook de achtergrondkleur en afbeelding (het onderste deel van de sprite). De hoogte wordt ook ingesteld op 28px, maar met een margin-top van 2px, zodat de lijn net onder het tekstvlak wordt getoond.

De breedte van de .border krijgt een waarde van 100%. Hij neemt dus de hele breedte van zijn parent in (dus de h2). Hierdoor zal de titel steeds even breed zijn als de container waarin hij zich bevindt (bvb smalle kolom, volledige pagina breedte, …)

Om een gelijkaardig resultaat te krijgen in IE6 waren nog enkele aanpassingen nodig in de conditional stylesheet.

  1. .bg, .border {
  2. background-image: url(img/sprite_8bit.png);
  3. z-index: 20;
  4. }
  5. .example .border {
  6. position: absolute;
  7. margin-top: 0;
  8. height: 30px;
  9. z-index: 10;
  10. }

Varianten

Op de Plan België website wordt ook een vereenvoudigde versie van deze titels gebruikt, waarbij een grunge lijntje onder de titel staat. Ook hier hanteren we dezelfde techniek.

Voorbeeld van vereenvoudigde PNG titels

Voorbeeld van vereenvoudigde PNG titels

Demo

Voor het gemak heb ik een demo klaargezet.

Voordelen van deze techniek

  • Slechts 1 HTTP request voor de afbeelding
  • Alle kleuren van titels (voor- en achtergrond alsook het semi-transparante gedeelte) kunnen eenvoudig via CSS aangepast worden
  • Geen image replacement technieken nodig
  • Titel zijn horizontaal schaalbaar
  • Je moet geen afzonderlijke images maken voor de verschillende titels of kleuren

CouchDB met Zend Framework

CouchDB is *hot*, getuige de verschillende blogposts en tutorials die momenteel overal opduiken. Niet op de kar springen betekent later gegarandeerd een drive-by door collega developers met de gekende vinger door de achteruitkijkspiegel dus wie zijn wij om langs de kant van de weg te blijven staan.

CouchDB is een database die momenteel volop wordt ontwikkeld door de Apache Foundation. Het huidige releasenummer (0.9.0) laat blijken dat het project nog steeds work in progress is. Dat neemt echter niet weg dat wij het project als ontwikkelaars met een open geest al eens niet van dichtbij kunnen bekijken.

Wat CouchDB precies is en wat je er allemaal mee kan doen lees je best op de CouchDB-website zelf. Je vind er algemene documentatie over de werking van CouchDB, een installatiegids maar ook implementatie-voorbeelden voor verschillende programmeertalen (PHP, .Net, Ruby, …). Eén van de grote voordelen van CouchDB is dat de database aangesproken kan worden via een REST-API. Inderdaad: GET, POST, PUT en DELETE. Deze blogpost gaat wat dieper in op een concrete implementatie in PHP voor communcatie met zo’n CouchDB-database door gebruik van de Zend Framework component Zend_Rest_Client.

Zend_Rest_Client vind je momenteel al terug in de laatste versie van het framework en kan je hier downloaden. Er wordt op dit moment hard gewerkt aan een “Zend_CouchDB”-component, maar deze ontwikkeling zit nog steeds in de incubator. Nog even afwachten dus.

Eens je CouchDB-daemon draait is het opzetten van de communicatie via Zend_Rest_Client erg makkelijk (default poort van de CouchDB service is 5984):

$client = new Zend_Rest_Client('http://localhost:5984');

In CouchDB is geen sprake van records of rows. Een eenheid van data wordt er een document genoemd. Zo’n document bevat dan enkele door jouw gespecifieerde velden. Een document kan als JSON doorgestuurd worden naar de server. (standaard wordt steeds JSON gebruikt, dit kan eventueel worden gewijzigd)

Een document toevoegen doe je door een POST-request te versturen naar de server. (Meer informatie omtrent het gebruik van de soorten requests vind je hier)

Gebruik makende van de Zend Framework componenten Zend_Rest_Client, Zend_Json en Zend_Debug bekomen we volgende resultaat:

// compose document
$document = array();
$document['title'] = 'document title';
$document['content'] = 'document content';

// JSON-ize document
$document = Zend_Json::encode($document);

// add document (use POST here)
$response = $client->restPost('test', $document);

// print response
Zend_Debug::dump($response);

Indien alles goed ging krijg je als response een “201 – Created”-boodschap terug:

object(Zend_Http_Response)#6 (5) {
  ["version:protected"] => string(3) "1.1"
  ["code:protected"] => int(201)
  ["message:protected"] => string(7) "Created"
  ["headers:protected"] => array(6) {
    ["Server"] => string(39) "CouchDB/0.10.0a773105 (Erlang OTP/R12B)"
    ["Location"] => string(59) "http://localhost:5984/test/c447a8366d74d880f35720d92d68419e"
    ["Date"] => string(29) "Tue, 19 May 2009 18:23:59 GMT"
    ["Content-type"] => string(24) "text/plain;charset=utf-8"
    ["Content-length"] => string(2) "73"
    ["Cache-control"] => string(15) "must-revalidate"
  }
  ["body:protected"] => string(73) "{"ok":true,"id":"c447a8366d74d880f35720d92d68419e","rev":"1-3753022840"}
"
}

In de body van deze response krijg je het uniek genereerde ID van het document terug alsook het revisie-nummer (hier 1). Indien gewenst kan je wanneer je een document toevoegt zelf ook een uniek ID kiezen. (vb.: doc1, doc2, doc3, …)

Een document ophalen gebeurt met een GET-request op basis van het unieke ID:

// get document
$response = $client->restGet('test/c447a8366d74d880f35720d92d68419e');

// un-Json-ize document
$document = Zend_Json::decode($response->getBody());

// print document
Zend_Debug::dump($document);

Een document aanpassen gebeurt door een PUT-request met als parameter in de URL van de service het unieke ID van het record dat wordt ge-updated:

// get document
$response = $client->restGet('test/c447a8366d74d880f35720d92d68419e');

// un-Json-ize document
$document = Zend_Json::decode($response->getBody());

// change values
$document['title'] = '"updated title!"';

// update document
$response = $client->restPut('test/c447a8366d74d880f35720d92d68419e', Zend_Json::encode($document));

// print response
Zend_Debug::dump($response);

Deze response geeft terug een “201 – Created” weer met dezelfde unieke documentID. Hier is het revisienummer echter van 1 naar 2 verhoogt.

object(Zend_Http_Response)#7 (5) {
  ["version:protected"] => string(3) "1.1"
  ["code:protected"] => int(201)
  ["message:protected"] => string(7) "Created"
  ["headers:protected"] => array(7) {
    ["Server"] => string(39) "CouchDB/0.10.0a773105 (Erlang OTP/R12B)"
    ["Location"] => string(59) "http://localhost:5984/test/c447a8366d74d880f35720d92d68419e"
    ["Etag"] => string(13) ""2-114293395""
    ["Date"] => string(29) "Tue, 19 May 2009 18:41:10 GMT"
    ["Content-type"] => string(24) "text/plain;charset=utf-8"
    ["Content-length"] => string(2) "72"
    ["Cache-control"] => string(15) "must-revalidate"
  }
  ["body:protected"] => string(72) "{"ok":true,"id":"c447a8366d74d880f35720d92d68419e","rev":"2-114293395"}
"
}

CouchDB zorgt dus zelf voor versionering van de documenten in de database! Dit betekent dat je op ieder moment een document terug kunt halen uit de database. Ook indien een document werd verwijderd kan een document terug worden gevonden om eventueel te gaan herstellen. (verwijderen betekent voor CouchDB intern dus eigenlijk een nieuwe (niet toegankelijke) versie aanmaken)

Een ander groot voordeel van een objectgeoriënteerde database als CouchDb is dat je eender welk document kunt opslaan. Je moet immers niet op voorhand, zoals bij vb. Mysql, een databaseschema gaan opmaken om zo de structuur van je database vast te leggen. Dit betekent ook dat je een document waarvan je de structuur hebt aangepast zonder problemen kunt aanpassen en bijwerken. Aanpassingen aan de structuur van objecten (vb. een blog-entry krijgt een extra veld bij: summary) vereisen in dat geval geen aanpassingen aan de database.

Get on with it! >> http://couchdb.apache.org/

Source code van deze voorbeelden vind je via GitHub: http://github.com/FabriZZio/couchdb-zend-rest/tree/master