<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss1full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="http://blog.neovov.com/">
  <title>NeoBlog</title>
  <description />
  <link>http://blog.neovov.com/</link>
  <dc:language>fr</dc:language>
  <dc:creator />
  <dc:rights />
  <dc:date>2016-01-27T09:00:00+01:00</dc:date>

  <sy:updatePeriod>daily</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>
  <sy:updateBase>2016-01-27T09:00:00+01:00</sy:updateBase>

  <items>
  <rdf:Seq>
    <rdf:li rdf:resource="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/" />
    <rdf:li rdf:resource="http://blog.neovov.com/2013/03/23/le-svg-c-est-maintenant/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/09/28/colombo/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/09/18/maldives/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/09/12/dubai-des-etoiles/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/09/05/dubai/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/09/03/vagabond/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/01/19/gone/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2012/01/18/sopa/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2010/11/02/10-trucs-html5-quon-ne-peut-pas-faire-en-flash/" />
  <rdf:li rdf:resource="http://blog.neovov.com/2010/10/18/faux-compte-rendu-de-paris-web-2010/" />
  </rdf:Seq>
  </items>
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rdf+xml" href="http://feeds.feedburner.com/neovov" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="neovov" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /></channel>

<item rdf:about="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/">
  <title>HTML5 &lt;video&gt; like a boss</title>
  <link>http://blog.neovov.com/2016/01/27/html5-video-like-a-boss</link>
  <dc:date>2016-01-27T09:00:00+01:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>Utile</dc:subject>
  <description>J’avais commencé cet article en juillet 2015 mais il était un peu tombé dans les oubliettes (trop de travail, tout ça).

	J’avais dans l’idée de présenter et d’expérimenter la manipulation de flux audio et vidéo en HTML5 mais je me suis limité devant la quantité d’informations et la complexité à l’expliquer simplement et succinctement…</description>
  <content:encoded><![CDATA[<header>
						<p>J’avais commencé cet article en juillet 2015 mais il était un peu tombé dans les oubliettes (trop de travail, tout ça).</p>

						<p>J’avais dans l’idée de présenter et d’expérimenter la manipulation de flux audio et vidéo en HTML5 mais je me suis limité devant la quantité d’informations et la complexité à l’expliquer simplement et succinctement. En espérant que cet article vous soit tout de même utile :-).</p>

						<p><strong>Note</strong> : Le contenu de cet article est tout à fait applicable à <code class="html tag">&lt;<span class="tag-name">audio</span>&gt;</code>.</p>
					</header>

					<section id="ajouter-une-video-a-une-page">
						<h2>Ajouter une vidéo à une page</h2>
						<p>Je ne vais pas m’attarder sur ce point, HTML5 permet maintenant d’ajouter facilement une vidéo à une page. Les premières difficultés seront liées aux formats de fichier à utiliser et aux <span lang="en">fallbacks</span> à mettre en place (non couvert dans cet article).</p>

						<figure>
							<pre><code class="html tag">&lt;<span class="tag-name">video</span> <span class="attribute"><span class="attribute-name">src</span>=<span class="attribute-value">"bip-bop.mp4"</span></span> <span class="attribute"><span class="attribute-name">controls</span></span>&gt;&lt;/<span class="tag-name">video</span>&gt;</code></pre>
							<p class="center"><video width="480" height="360" preload="none" poster="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.jpg" controls>
								<source src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.mp4"  type="video/mp4" />
								<source src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.webm" type="video/webm" />
							</video></p>
							<figcaption class="center">Code HTML permettant d’ajouter une vidéo, accompagné de son rendu</figcaption>
						</figure>

						<p>Cette vidéo pèse plus de 50 Mo ce qui, pour 30 minutes, est correct. Toutefois, cela soulève un problème de bande passante.</p>
						<p>Dès le lancement de la lecture, le navigateur va commencer à la télécharger <strong>en entier</strong>, même si l’utilisateur met le lecteur en pause. Dans mon exemple, je doute que quiconque regarde la vidéo en entier ; vous allez donc gaspiller plus de 50 Mo (problématique si votre fournisseur d’accès vous impose un quota). Le serveur sera également occupé à transférer ce fichier et aura moins de capacité de charge.</p>
					</section>

					<section id="progressive-download-et-streaming">
						<h2><span lang="en">Progressive download</span> et <span lang="en">streaming</span></h2>
						<p>Le <span lang="en">progressive download</span> est la technique de chargement de média utilisée par les navigateurs. Dans le cas d’une vidéo, cela permet de commencer la lecture avant la fin du chargement du fichier.</p>

						<p>Le chargement est <strong>linéaire</strong> et <strong>la totalité du fichier sera récupéré</strong>. Si vous souhaitez accéder à une partie non chargée, votre navigateur va attendre avant de reprendre la lecture (en réalité les navigateurs gèrent mieux ce cas, nous le verrons plus tard).</p>

						<figure class="center">
							<img style="box-sizing: border-box; width: 100%;" src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/img/progressive-download.svg" alt="" />
							<figcaption>Illustration du chargement et de la lecture en <span lang="en">progressive download</span><br/>(supposant que la connexion soit capable de charger plus vite que la lecture)</figcaption>
						</figure>

						<p>Le <span lang="en">streaming</span> est une autre technique de chargement de média. Cette fois, le fichier sera découpé en segments qui seront <strong>téléchargé à la demande</strong>. Un fichier <strong>manifeste</strong>, listant les segments, sera à utiliser comme source pour le lecteur.</p>

						<figure class="center">
							<img style="box-sizing: border-box; width: 100%;" src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/img/streaming.svg" alt="" />
							<figcaption>Illustration du chargement et de la lecture en <span lang="en">streaming</span></figcaption>
						</figure>

						<p>La consommation de données est réduite côté client comme côté serveur. En bénéfice, le lecteur peut commencer la lecture sur n’importe quel segment, sans avoir à en télécharger les précédents.</p>

						<p>Malheureusement, HTML5 ne permet pas « nativement » d’utiliser le streaming. Il est toutefois possible de faire du <strong lang="en">pseudo-streaming</strong> permettant au moins de démarrer la lecture à un endroit donné, sans attendre le chargement préalable. Les navigateurs actuels envoient un <span lang="en">header</span> HTTP <code>Range</code> indiquant au serveur quelle portion est à récupérer. Ce dernier doit être capable d’extraire une partie de la vidéo, cela peut nécessiter de la configuration et/ou l’utilisation d’un module.</p>

					<section id="adaptive-streaming">
						<h2 lang="en">Adaptive streaming</h2>
						<p>L’<span lang="en">adaptive streaming</span> (et non « adaptative ») est une technique permettant d’adapter (ça alors !) la qualité d’une vidéo en fonction de l’utilisation de la bande passante du client voire même de l’utilisation CPU.</p>

						<p>Concrètement, cela veut dire que la lecture peut commencer sur des segments en basse qualité puis passer en haute qualité, si le client en est capable. Le manifeste utilisé comporte <strong>une déclinaison</strong> des segments à utiliser.</p>

						<figure>
							<p class="center"><video width="480" height="360" preload="none" poster="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop-adaptive.jpg" controls>
								<source src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop-adaptive.mp4"  type="video/mp4" />
								<source src="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop-adaptive.webm" type="video/webm" />
							</video></p>
							<figcaption class="center">Simulation d’<span lang="en">adaptive streaming</span><br/>Toutes les 4 secondes la qualité est améliorée</figcaption>
						</figure>
					</section>

					<p>Avec cette technique, le démarrage de la lecture peut être plus rapide, mais surtout cela évite d’avoir à envoyer une qualité trop élevée aux clients n’en ayant pas la capacité.</p>

					<p>Par contre, l’inconvénient majeur est qu’il faut préparer toutes les qualités disponibles. Si vous proposez 5 qualités, il va falloir encoder (compresser) 5 fois la vidéo et la stocker en 5 exemplaires.</p>

					<p>Vous l’aurez compris, idéalement un lecteur HTML5 devrait avoir la capacité de télécharger des segments <strong>et</strong> avoir un algorithme de décision de qualité.</p>

					<section id="media-source-extensions">
						<h2 lang="en">Media Source Extensions</h2>
						<p><a hreflang="en" href="http://caniuse.com/#feat=mediasource">Media Source Extensions</a> (MSE) est une spécification décrivant un ensemble d’interfaces JavaScript permettant de <strong>créer une source</strong> lisible avec une balise <code class="html tag">&lt;<span class="tag-name">video</span>&gt;</code> ou <code class="html tag">&lt;<span class="tag-name">audio</span>&gt;</code>.</p>

						<p>Cela permet d’agir directement sur les flux, comme par exemple changer de piste audio, charger uniquement les segments nécessaires (<span lang="en">streaming</span>), adapter la qualité (<span lang="en">adaptive streaming</span>), valider des segments (<span title="Digital Rights Management" lang="en">DRM</span>) ou encore faire du <a lang="en" hreflang="en" href="https://en.wikipedia.org/wiki/Gapless_playback">gapless playback</a>.</p>

						<p>Essayons de nous en servir :</p>

						<figure>
							<pre><code class="language-js">var
  video  = document.getElementById("video"),
  source = new MediaSource();

video.src = URL.createObjectURL(source);</code></pre>
						</figure>

						<p>Pour le moment rien de compliqué, nous créons une source que nous attachons à une balise <code class="html tag">&lt;<span class="tag-name">video</span>&gt;</code> présente dans notre page. Vous noterez que cette source est une <a hreflang="en" href="http://caniuse.com/#feat=bloburls">Blob URL</a> (une URL vers un objet binaire).</p>

						<p>Il faut maintenant remplir cette source :</p>

						<figure>
							<pre><code class="language-js">source.addEventListener("sourceopen", function() {
  var
    buffer = source.addSourceBuffer("video/mp4"),
    xhr    = new XMLHttpRequest();

  xhr.open("GET", "http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop.dash.mp4", true);
  xhr.responseType = "arraybuffer";
  xhr.setRequestHeader("Range", "bytes=0-307200");
  xhr.send();

  xhr.onload = function() {
    buffer.appendBuffer(xhr.response);
  }
}, false);</code></pre>
						</figure>

						<p>L’événement <code>sourceopen</code> est déclenché par le navigateur lorsqu’il juge nécessaire de commencer à charger la source (en fonction de l’attribut <code class="html attribute">preload</code>, du lancement de la lecture voire d’autres optimisations internes au navigateur). Nous créons un <span lang="en">buffer</span> dans lequel nous injectons les données brutes de la vidéo.</p>

						<p>Pour cet exemple, nous limitons les données à 300 ko en ajoutant un <span lang="en">header</span> <code>Range</code> à la requête HTTP. Notez également que nous définissons le type de réponse à <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/ArrayBuffer"><code>arraybuffer</code></a> afin de manipuler correctement la réponse.</p>

						<figure>
							<p class="center"><video id="video-3" width="480" height="360" controls></video></p>
							<figcaption class="center">Rendu du code précédent<br/>Seul 300 ko du fichier sont chargés (environ 10 secondes)<br/>(Le rendu peut ne pas fonctionner suivant votre navigateur)</figcaption>
							<script>
								(function() {
									var
										video  = document.getElementById("video-3"),
										source = new MediaSource();

									video.src = URL.createObjectURL(source);

									source.addEventListener("sourceopen", function() {
										var
											buffer = source.addSourceBuffer('video/mp4; codecs="avc1.4d4028,mp4a.40.2"'),
											xhr    = new XMLHttpRequest();

										xhr.open("GET", "http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.dash.mp4", true);
										xhr.setRequestHeader("Range", "bytes=0-307200");
										xhr.responseType = "arraybuffer";
										xhr.send();

										xhr.onload = function() {
											buffer.appendBuffer(xhr.response);
										}
									}, false);
								}());
							</script>
						</figure>

						<p>J’ai volontairement simplifié cet exemple, en réalité il faut tenir compte de certains points :</p>

						<ul>
							<li>Au moment d’ajouter un <span lang="en">buffer</span> (<code>source.addSourceBuffer()</code>) il faut spécifier le type MIME des données qu’il va recevoir (probablement pour que l’algorithme de sélection de source fonctionne). Certains navigateurs auront également besoin de l’information concernant les codecs (<code>"video/webm; codecs=vp9,vorbis"</code> ou <code>"video/mp4; codecs=avc1.4d4028,mp4a.40.2"</code> par exemple).</li>
							<li>Après avoir ajouté des données au <span lang="en">buffer</span> il sera verrouillé pendant quelque temps (le temps que le codec valide ou invalide les données). Pour continuer à l’alimenter correctement, il vaut mieux lancer la requête pour le segment suivant après avoir reçu l’événement <code>updateend</code> (déclenché par le <span lang="en">buffer</span>).</li>
							<li>Vous aurez sans doute besoin de préparer vos fichiers MP4 pour un chargement en <span lang="en">streaming</span>.</li>
							<li>Les 300 ko sont arbitraires. Dans le cas d’un fichier MP4 cela ne sera peut-être pas suffisant pour commencer la lecture (le début du fichier contenant des métadonnées pouvant être imposantes). L’idéal serait d’utiliser un manifeste DASH décrivant les intervalles des segments.</li>
						</ul>

						<p>Modifions cet exemple pour charger les autres segments :</p>
						<figure>
							<pre><code class="language-js">var
  video  = document.getElementById("video"),
  source = new MediaSource(),
  buffer,
  ranges          = ["0-291281", …, "53143120-53444342"],
  rangesRetrieved = [],
  segmentDuration = 10.021;

video.src = URL.createObjectURL(source);</code></pre>
						</figure>

						<p>Tout d’abord, nous devons lister les <span lang="en">headers</span> <code>Range</code> nous permettant de récupérer les segments. Nous allons également avoir besoin de conserver une liste des segments en cours de récupération et de la durée d’un segment.</p>

						<p>Nous allons avoir besoin de récupérer plusieurs segments, il est donc nécessaire d’externaliser la requête :</p>

						<figure>
							<pre><code class="language-js">source.addEventListener("sourceopen", function() {
  buffer = source.addSourceBuffer("video/mp4");
  retrieve(0); // Récupérons le premier segment
}, false);

function retrieve(range) {
  // Il faut ignorer les segments en cours de récupération ou déjà récupéré
  if (rangesRetrieved.indexOf(range) !== -1) { return; }

  rangesRetrieved.push(range); // Marquons ce segment comme "récupéré"
  range = ranges[range]; // Retrouvons les bytes à utiliser pour la requête

  var xhr = new XMLHttpRequest();
  xhr.open("GET", "http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop.dash.mp4", true);
  xhr.setRequestHeader("Range", "bytes=" + range);
  xhr.responseType = "arraybuffer";
  xhr.send();

  xhr.onload = function() {
    buffer.appendBuffer(xhr.response);
  }
}</code></pre>
						</figure>

						<p>Il nous suffit d’écouter l’événement <code>timeupdate</code> et de charger le prochain segment, si nécessaire :</p>

						<figure>
							<pre><code class="language-js">video.addEventListener("timeupdate", function() {
  var
    index,
    i     = 0,
    count = this.buffered.length,
    time  = this.currentTime + segmentDuration;

  // Vérifions s’il est nécessaire de récupérer le prochain segment
  for (; i < count; i++) {
    if (time > this.buffered.start(i) && time < this.buffered.end(i)) {
      return; // Le prochain segment semble déjà chargé, inutile de continuer
    }
  }

  index = Math.floor(time / segmentDuration);
  retrieve(index);
}, false);</code></pre>
						</figure>

						<p>Enfin, en écoutant l’événement <code>seeking</code> nous pouvons lancer le chargement du segment pour une position demandée :</p>

						<figure>
							<pre><code class="language-js">video.addEventListener("seeking", function() {
  index = Math.floor(this.currentTime / segmentDuration);
  retrieve(index);
}, false);</code></pre>
						</figure>

						<figure>
							<p class="center"><video id="video-4" width="480" height="360" controls></video></p>
							<figcaption class="center">Rendu du code précédent
							<br/>Vous pouvez consulter le code complet dans le code source de cette page
							<br/>(Le rendu peut ne pas fonctionner suivant votre navigateur)</figcaption>
							<script>
								(function() {
									var
										video  = document.getElementById("video-4"),
										source = new MediaSource(),
										buffer,
										ranges = ["0-291281", "291282-582910", "582911-874893", "874894-1166959", "1166960-1457868", "1457869-1752399", "1752400-2045034", "2045035-2336401", "2336402-2628428", "2628429-2921509", "2921510-3216427", "3216428-3510407", "3510408-3804549", "3804550-4098107", "4098108-4393888", "4393889-4687643", "4687644-4984206", "4984207-5278187", "5278188-5571710", "5571711-5866414", "5866415-6161190", "6161191-6454828", "6454829-6747961", "6747962-7041671", "7041672-7335075", "7335076-7629052", "7629053-7923749", "7923750-8218201", "8218202-8513348", "8513349-8809779", "8809780-9104807", "9104808-9399075", "9399076-9693324", "9693325-9987359", "9987360-10283496", "10283497-10577912", "10577913-10874997", "10874998-11168798", "11168799-11463223", "11463224-11758382", "11758383-12054528", "12054529-12349484", "12349485-12644194", "12644195-12940243", "12940244-13237352", "13237353-13534885", "13534886-13833137", "13833138-14129815", "14129816-14427515", "14427516-14725885", "14725886-15023707", "15023708-15322073", "15322074-15619970", "15619971-15917186", "15917187-16215345", "16215346-16511968", "16511969-16810856", "16810857-17107123", "17107124-17404091", "17404092-17700937", "17700938-18000507", "18000508-18298264", "18298265-18596934", "18596935-18894461", "18894462-19192327", "19192328-19489586", "19489587-19787068", "19787069-20083258", "20083259-20380707", "20380708-20679044", "20679045-20972876", "20972877-21270144", "21270145-21566753", "21566754-21863529", "21863530-22160764", "22160765-22457288", "22457289-22755816", "22755817-23053799", "23053800-23351332", "23351333-23648602", "23648603-23948228", "23948229-24246588", "24246589-24545065", "24545066-24843046", "24843047-25142345", "25142346-25439733", "25439734-25738903", "25738904-26035360", "26035361-26331939", "26331940-26626249", "26626250-26921164", "26921165-27216953", "27216954-27511444", "27511445-27808194", "27808195-28105023", "28105024-28402315", "28402316-28700036", "28700037-28995097", "28995098-29290235", "29290236-29585104", "29585105-29881676", "29881677-30177745", "30177746-30474679", "30474680-30771141", "30771142-31068844", "31068845-31364201", "31364202-31662067", "31662068-31957590", "31957591-32253270", "32253271-32550363", "32550364-32848748", "32848749-33147088", "33147089-33444598", "33444599-33743388", "33743389-34042161", "34042162-34339305", "34339306-34638373", "34638374-34936481", "34936482-35234452", "35234453-35532853", "35532854-35830629", "35830630-36127395", "36127396-36425388", "36425389-36722567", "36722568-37020633", "37020634-37316896", "37316897-37613194", "37613195-37910004", "37910005-38208857", "38208858-38507723", "38507724-38804163", "38804164-39101671", "39101672-39397777", "39397778-39698304", "39698305-39996946", "39996947-40296391", "40296392-40593908", "40593909-40891405", "40891406-41189684", "41189685-41485811", "41485812-41782688", "41782689-42079608", "42079609-42376930", "42376931-42676454", "42676455-42976011", "42976012-43274185", "43274186-43573014", "43573015-43870820", "43870821-44170346", "44170347-44470433", "44470434-44770013", "44770014-45069328", "45069329-45367337", "45367338-45665643", "45665644-45963198", "45963199-46262455", "46262456-46559250", "46559251-46856097", "46856098-47154502", "47154503-47452579", "47452580-47753032", "47753033-48053015", "48053016-48351884", "48351885-48651445", "48651446-48951911", "48951912-49249551", "49249552-49548688", "49548689-49846986", "49846987-50146866", "50146867-50447133", "50447134-50746184", "50746185-51045914", "51045915-51345265", "51345266-51643452", "51643453-51941942", "51941943-52241568", "52241569-52540219", "52540220-52840284", "52840285-53143119", "53143120-53444342"],
										rangesRetrieved = [],
										segmentDuration = 10.021;

									video.src = URL.createObjectURL(source);

									source.addEventListener("sourceopen", function() {
										buffer = source.addSourceBuffer('video/mp4; codecs="avc1.4d4028,mp4a.40.2"');
										retrieve(0);
									}, false);

									function retrieve(range) {
										if (rangesRetrieved.indexOf(range) !== -1) { return; }

										rangesRetrieved.push(range);
										range = ranges[range];

										var xhr = new XMLHttpRequest();
										xhr.open("GET", "http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.dash.mp4", true);
										xhr.setRequestHeader("Range", "bytes=" + range);
										xhr.responseType = "arraybuffer";
										xhr.send();

										xhr.onload = function() {
											buffer.appendBuffer(xhr.response);
										}
									}

									video.addEventListener("timeupdate", function() {
										var
											index,
											i     = 0,
											count = this.buffered.length,
											time  = this.currentTime + segmentDuration;

										for (; i < count; i++) {
											if (time > this.buffered.start(i) && time < this.buffered.end(i)) {
												return;
											}
										}

										index = Math.floor(time / segmentDuration);
										retrieve(index);
									}, false);

									video.addEventListener("seeking", function() {
										index = Math.floor(this.currentTime / segmentDuration);
										retrieve(index);
									}, false);
								}());
							</script>
						</figure>

						<p>Bien entendu, le résultat n’est pas parfait. Idéalement, les <span lang="en">headers</span> <code>Range</code> et la durée des segments seraient à récupérer dans <a href="http://blog.neovov.com/2016/01/27/html5-video-like-a-boss/bip-bop/bip-bop.dash.mpd">un manifeste DASH</a>. Il est également possible d’opter pour une autre méthode de récupération des segments, comme avoir un fichier par segment par exemple.</p>

						<p>Ce petit code est facilement modifiable afin de réaliser de l’<span lang="en">adaptive streaming</span>. Il suffit d’ajouter un algorithme changeant l’URL vers les segments.</p>

						<p>C’est d’ailleurs là un grand intérêt de MSE : donner la possibilité aux développeurs d’implémenter les algorithmes qui conviennent le mieux au contexte de consommation du contenu.</p>
					</section>

					<section id="conclusion">
						<h2>Conclusion</h2>
						<p>Il y aurait encore énormément à présenter, comme <a href="https://www.w3.org/TR/encrypted-media/">EME</a> qui permet de décrypter les segments et donc de proposer une protection des flux ou encore énumérer des algorithmes adaptatifs. Un jour, peut-être.</p>
					</section>]]></content:encoded>
</item>

<item rdf:about="http://blog.neovov.com/2013/03/23/le-svg-c-est-maintenant/">
  <title>Le SVG, c'est maintenant</title>
  <link>http://blog.neovov.com/2013/03/23/le-svg-c-est-maintenant</link>
  <dc:date>2013-03-23T12:26:30+01:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>Utile</dc:subject>
  <description>À la lecture d’un article sur SVG sur CSS-Tricks, je n’ai pas pu m’empêcher d’écrire ce billet.

	L’article est intéressant mais à prendre avec des pincettes. L’auteur y indique différentes façons d’embarquer du SVG sur une page : en utilisant une balise &lt;img&gt;,...</description>
  <content:encoded><![CDATA[ <header>
	<p>À la lecture d’<a href=/"http://css-tricks.com/using-svg/" hreflang="en">un article sur <abbr title="Scalable Vector Graphics">SVG</abbr></a> sur <a href="http://css-tricks.com" hreflang="en" lang="en">CSS-Tricks</a>, je n’ai pas pu m’empêcher d’écrire ce billet.</p>

	<p>L’article est intéressant mais à prendre avec des pincettes. L’auteur y indique différentes façons d’embarquer du SVG sur une page&nbsp;: en utilisant une balise <code class="html tag">&lt;<span class="tag-name">img</span>&gt;</code>, avec un <code class="css"><span class="property">background-image</span></code>, en ligne dans le HTML ou en utilisant une balise <code class="html tag">&lt;<span class="tag-name">object</span>&gt;</code>. Les méthodes décrites sont correctes, mais je trouve la gestion des <span lang="en">fallbacks</span> améliorables.</p>
</header>

<p>Avant d’utiliser SVG, comme toutes autres fonctionnalités, vous devez être conscient des <a href="http://caniuse.com/svg" hreflang="en">plateformes qui supportent ce format</a>. Le support est très correct, si ce n’est sous <span lang="en">Internet Explorer</span> inférieur à la version 9.</p>

<section id="html">
	<h2>HTML</h2>

	<p>Vous pouvez utiliser le code HTML le plus simple&nbsp;:</p>

	<figure>
		<pre><code class="html tag">&lt;<span class="tag-name">img</span> <span class="attribute"><span class="attribute-name">width</span>=<span class="attribute-value">634"</span></span> <span class="attribute"><span class="attribute-name">height</span>=<span class="attribute-value">"557"</span></span> <span class="attribute"><span class="attribute-name">src</span>=<span class="attribute-value">"octocat.svg"</span></span> <span class="attribute"><span class="attribute-name">alt</span>=<span class="attribute-value">"Octocat, la mascotte de GitHub"</span></span> /&gt;</code></pre>
		<p class="center">
			<img width="634" height="557" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat.svg" alt="Octocat, la mascotte de GitHub" />
		</p>
		<figcaption class="center"><span lang="en">Octocat</span>, la mascote de <a href="http://github.com" hreflang="en" lang="en">GitHub</a> au <a href="https://gist.github.com/johan/1007813" hreflang="en">format SVG</a> par <a href="https://github.com/johan" hreflang="en">johan</a></figcaption>
	</figure>

	<p>Tout en gardant à l’esprit que seul le <span lang="en">fallback</span> textuel sera fourni sous IE &lt; 9.</p>
	<p>L’indication de taille n’est présente que pour aider le navigateur à réserver la place lors du rendu de la page.</p>

	<p>Dans l’article de <span lang="en">CSS-Tricks</span>, le <span lang="en">fallback bitmap</span> est effectué via JavaScript soit en utilisant <a href="http://modernizr.com" hreflang="en" lang="en">Modernizr</a> et <a href="http://jquery.com" hreflang="en" lang="en">jQuery</a>, soit avec du JavaScript en ligne (!). Il y a une façon plus simple&nbsp;:</p>

	<figure>
		<pre><code class="html tag">&lt;<span class="tag-name">object</span> <span class="attribute"><span class="attribute-name">width</span>=<span class="attribute-value">"634"</span></span> <span class="attribute"><span class="attribute-name">height</span>=<span class="attribute-value">"557"</span></span> <span class="attribute"><span class="attribute-name">data</span>=<span class="attribute-value">"octocat.svg"</span></span> <span class="attribute"><span class="attribute-name">type</span>=<span class="attribute-value">"image/xml+svg"</span></span>&gt;
	<span class="tag">&lt;<span class="tag-name">img</span> <span class="attribute"><span class="attribute-name">width</span>=<span class="attribute-value">"634"</span></span> <span class="attribute"><span class="attribute-name">height</span>=<span class="attribute-value">"557"</span></span> <span class="attribute"><span class="attribute-name">src</span>=<span class="attribute-value">"octocat.png"</span></span> <span class="attribute"><span class="attribute-name">alt</span>=<span class="attribute-value">"Octocat, la mascotte de GitHub"</span></span> /&gt;</span>
&lt;/<span class="tag-name">object</span>&gt;</code></pre>
		<p class="center">
			<object width="634" height="557" data="https://static.neovov.com/neoblog/img/2013/03/svg/octocat.svg" type="image/xml+svg">
				<img width="634" height="557" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat.png" alt="Octocat, la mascotte de GitHub" />
			</object>
		</p>
	</figure>

	<p>Cette fois, le SVG s’affichera sur les plateformes supportant le type <abbr title="Multipurpose Internet Mail Extensions">MIME</abbr> <code>image/xml+svg</code>, sinon la balise <code class="html tag">&lt;<span class="tag-name">img</span>&gt;</code> s’occupera d’afficher le <span lang="en">fallback bitmap</span>. Cependant, je ne sais pas comment un lecteur d’écran va réagir en rencontrant ce type de code.</p>

	<p><a href="http://www.webkit.org" hreflang="en" lang="en">Webkit</a> semble télécharger le <span lang="en">fallback bitmap</span> avant le SVG, ce qui est assez problématique pour les performances.</p>
</section>

<section id="css">
	<h2>CSS</h2>

	<p>Côté CSS, vous avez deux solutions. Soit vous utilisez la détection de fonctionnalité (<span lang="en">Modernizr</span> ou autre)&nbsp;:</p>

	<figure>
	<pre><code class="js">document.body.className += (document.createElementNS && document.createElementNS(’http://www.w3.org/2000/svg’, ’svg’).createSVGRect ? "" : "no-svg");</code></pre>
	<figcaption class="center">Exemple de code permettant de détecter le support du SVG</figcaption>
	</figure>

	<figure>
	<pre><code class="css rules">        <span class="rule"><span class="selector id">#element</span> { <span class="property">background-image</span>: url(<span class="string">octocat.svg</span>); }</span>
<span class="rule"><span class="selector"><span class="class">.no-svg</span> <span class="id">#element</span></span> { <span class="property">background-image</span>: url(<span class="string">octocat.png</span>); }</span></code></pre>
	<figcaption class="center">On gère les deux cas&nbsp;: présence ou non de SVG</figcaption>
	</figure>

	<p>Soit vous bidouillez en CSS&nbsp;:</p>

	<figure>
	<pre><code class="css rule"><span class="id">#element</span> {
	<span class="property">background-image</span>: url(<span class="string">octocat.png</span>); <span class="comment">/* 1) Supporté partout */</span>
	<span class="property">background-image</span>: none, url(<span class="string">octocat.svg</span>); <span class="comment">/* 2) Multiple background */</span>
}</code></pre>
	</figure>

	<p>Dans cet exemple on fournit le <span lang="en">bitmap</span> en premier (1). Puis on définit un <span lang="en">multiple background</span> (2) qui ne sera retenu que sur les plateformes supportant cette fonctionnalité. Heureusement, <a href="http://caniuse.com/multibackgrounds" hreflang="en">le support de <span lang="en">multiple background</span></a> est assez similaire à celui de SVG.</p>
</section>

<p>L’article fait également (trop) mention du SVG en ligne ou d’encodage en base64. Il est vrai que ces techniques réduisent le nombre de requêtes <abbr title="HyperText Transfer Protocol">HTTP</abbr>, mais je trouve que cela nuit trop à la maintenance et devrait faire partie d’un processus automatisé.</p>

<section id="sprites-svg">
	<h2><span lang="en">Sprites</span> SVG&nbsp;?</h2>

	<p>Pour réduire le nombre de requête HTTP nous utilisons des <span lang="en">sprites</span>&nbsp;; une image en contenant d’autres. À y réfléchir, c’est également possible en SVG.</p>

	<p>Ne vous emballez pas trop vite, <a href="http://caniuse.com/svg-fragment" hreflang="en">le support</a> des <a href="http://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers" hreflang="en">fragments identifiers</a> (la fonctionnalité</a> permettant d’utiliser des <span lang="en">sprites</span> SVG) n’est pas bon.</p>

	<p>Le <span lang="en">fragment identifier</span> vous permet d’afficher une zone ou un élément du SVG&nbsp;.</p>

	<p>Prenons <a href="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite.svg">ce <span lang="en">sprite</span></a>&nbsp;:</p>

	<figure class="center">
		<img width="777" height="328" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite.jpg" alt="" />
		<figcaption>Capture d’écran de l’éditeur utilisé pour créer le SVG.<br/>Le rectangle blanc représente la <span lang="en">viewBox</span> ; la partie visible du SVG</figcaption>
	</figure>

	<p>Si on essaye d’accéder à ce SVG on obtient un premier «&nbsp;état&nbsp;»&nbsp;:</p>

	<figure class="center">
		<img width="378" height="307" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite.svg" alt="" />
	</figure>

	<p>Maintenant, si dans l’URL de cette ressource on spécifie un fragment décrivant une autre zone à afficher (un autre <span lang="en">viewBox</span>)&nbsp;:</p>

	<figure class="center">
		<img id="s1color" data-state="color" width="378" height="307" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite.svg#svgView(viewBox(378, 0, 378, 307)" alt="" />
		<figcaption>Après avoir rajouté le fragment <code>#svgView(viewBox(378, 0, 378, 307))</code> à l’URL.<br/>Les valeurs numériques représentent respectivement x, y, <span lang="en">width</span> et <span lang="en">height</span>.<br/>Par rapport au premier «&nbsp;état&nbsp;» nous avons modifié le x.<br/>(passez la souris sur l’image pour un <span lang="en">fallback</span>)</figcaption>
	</figure>

	<p>Il existe une autre méthode, plus souple à utiliser, mais qui requiert <a href="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite-2.svg">un <span lang="en">sprite</span> différent</a>.</p>

	<p>Plutôt que de spécifier une zone à afficher, nous allons indiquer un élément du SVG. Par défaut, nous allons cacher toutes les images et n’afficher que celle qui correspond au fragment en cours, grâce à du CSS embarqué dans notre SVG&nbsp;:</p>

	<figure>
		<pre><code class="html"><span class="tag">&lt;<span class="tag-name">svg</span> …&gt;
	<span class="tag">&lt;<span class="tag-name">style</span>&gt;…&lt;/<span class="tag-name">style</span>&gt;</span>
	<span class="tag">&lt;<span class="tag-name">g</span> <span class="attribute"><span class="attribute-name">id</span>=<span class="attribute-value">"color"</span></span>&gt;…&lt;/<span class="tag-name">g</span>&gt;</span>
	<span class="tag">&lt;<span class="tag-name">g</span> <span class="attribute"><span class="attribute-name">id</span>=<span class="attribute-value">"gray"</span></span>&gt;…&lt;/<span class="tag-name">g</span>&gt;</span></span></code></pre>
		<figcaption class="center">Chaque image est regroupée dans un groupe ayant un identifiant</figcaption>
	</figure>

	<figure>
		<pre><code class="css"><span class="rule"><span class="selector tag">svg</span> &gt; <span class="selector tag">g</span>        { <span class="property">display</span>: <span class="value">none</span>; }</span>
<span class="rule"><span class="selector tag">svg</span> &gt; <span class="selector tag">g</span><span class="selector-pseudo-separator">:</span><span class="selector-pseudo">target</span> { <span class="property">display</span>: <span class="value">block</span>; }</span></code></pre>
	<figcaption class="center">En CSS, on cache tous les groupes sauf le <span lang="en">target</span></figcaption>
	</figure>

	<p>Ensuite, pour s’en servir&nbsp;:</p>

	<figure class="center">
		<img width="378" height="307" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite-2.svg" alt="" />
		<figcaption>Sans fragment le <span lang="en">sprite</span> n’affiche rien</figcaption>
	</figure>

	<figure class="center">
		<img id="s2gray" data-state="gray" width="378" height="307" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite-2.svg#gray" alt="" />
		<figcaption><code>octocat.svg#gray</code><br/>(passez la souris sur l’image pour un <span lang="en">fallback</span>)</figcaption>
	</figure>

	<figure class="center">
		<img id="s2color" data-state="color" width="378" height="307" src="https://static.neovov.com/neoblog/img/2013/03/svg/octocat-sprite-2.svg#color" alt="" />
		<figcaption><code>octocat.svg#color</code><br/>(passez la souris sur l’image pour un <span lang="en">fallback</span>)</figcaption>
	</figure>

	<script>
		var
			s1color = document.getElementById( "s1color" );
			s2gray  = document.getElementById( "s2gray" ),
			s2color = document.getElementById( "s2color" );

		function fallback( e ) {
			var img = e.target;

			if (/\.svg/.test( img.src )) {
				img.old = img.src;
				img.src = img.src.replace( /sprite(?:-2)?\.svg.*/, "sprite-" + img.getAttribute( "data-state" ) + ".png" );
			}
		}

		function restore( e ) {
			var img = e.target;
			img.src = img.old;
		}

		s1color.addEventListener("mouseover", fallback, false);
		s1color.addEventListener("mouseout", restore, false);
		s2gray.addEventListener("mouseover", fallback, false);
		s2gray.addEventListener("mouseout", restore, false);
		s2color.addEventListener("mouseover", fallback, false);
		s2color.addEventListener("mouseout", restore, false);
	</script>

	<p>Si vous souhaitez utiliser cette méthode il faudra revoir votre façon de concevoir vos <span lang="en">sprites</span>. Cette fois, toutes les images seront placées les unes par dessus les autres. Cela veut également dire que votre <span lang="en">viewBox</span> doit être fixe et que chaque image doit avoir la même taille.</p>
</section>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2012/09/28/colombo/">
  <title>Colombo</title>
  <link>http://blog.neovov.com/2012/09/28/colombo</link>
  <dc:date>2012-09-28T22:44:30+02:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>La vie</dc:subject>
  <description>Des Maldives pour rejoindre notre prochaine destination, nous devions effectuer un transit à Colombo.

Le Sri Lanka est probablement un pays agréable à arpenter, mais le premier contact est surprenant. En débarquant, nous avons perdu du temps à comprendre le type de visa qu’il nous fallait,...</description>
  <content:encoded><![CDATA[ <p>Des Maldives pour rejoindre notre prochaine destination, nous devions effectuer un transit à Colombo.</p>

<p>Le Sri Lanka est probablement un pays agréable à arpenter, mais le premier contact est surprenant. En débarquant, nous avons perdu du temps à comprendre le type de visa qu’il nous fallait, l’agent de l’immigration, particulièrement louche, a essayé de nous vendre quelque chose, des vendeurs nous ont hélé pour nous re-fourguer n’importe quoi et nous avons été halluciné de leur façon de conduire.</p>

<p>Cela séduira peut-être certains, mais je n’ai pas vraiment aimé cette première impression.</p>

<p class=/"center"><a href="http://www.flickr.com/photos/neovov/7987836986/in/set-72157631539524038"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/colombo/1.jpg" alt="" /></a><br/>L’unique photo que j’aurai le temps de prendre</p>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2012/09/18/maldives/">
  <title>Maldives</title>
  <link>http://blog.neovov.com/2012/09/18/maldives</link>
  <dc:date>2012-09-18T22:17:09+02:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>La vie</dc:subject>
  <description>Comme première destination nous avons voulu marquer le coup. Nous avons même poussé l’excès jusqu’à effectuer une partie du voyage en hydravion.



	Dès l’avion, la couleur est annoncée


L’archipel des Maldives est une destination prisée de couples fraîchement mariés....</description>
  <content:encoded><![CDATA[ <p>Comme première destination nous avons voulu marquer le coup. Nous avons même poussé l’excès jusqu’à effectuer une partie du voyage en hydravion.</p>

<p class=/"center">
	<a href="http://www.flickr.com/photos/neovov/7987761449/in/set-72157631539361376"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/1.jpg" alt="" /></a><br/>
	Dès l’avion, la couleur est annoncée
</p>

<p>L’archipel des Maldives est une destination prisée de couples fraîchement mariés. Souvent qualifié de paradis, même si je préfère laisser à chacun sa propre définition du paradis, la faune, la flore et la météo annoncent&nbsp;: «&nbsp;bienvenue sous les tropiques&nbsp;».</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987777682/in/set-72157631539665823"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/2.jpg" alt="" /></a><br/>
	Vue de la chambre, cela me change du périphérique Parisien
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987787162/in/set-72157631539406510"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/3.jpg" alt="" /></a><br/>
	Malgré un temps changeant, l’environnement est plaisant
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987820742/in/set-72157631539771661"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/4.jpg" alt="" /></a><br/>
	Des allures de cartes postales
</p>

<p>Cette mer bleue turquoise est un appel à la plongée. Je vous passerai les détails de cette mauvaise première expérience (j’ai toujours été angoissé par l’eau). De retour sur le bateau, je vis le temps se dégrader de manière inquiétante. Sans que l’on s’en rende compte, nous voilà en pleine tempête tropicale.</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987772035/in/set-72157631539665823"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/5.jpg" alt="" /></a><br/>
	Des nuages peu rassurants
</p>

<p>Le maigre rafiot luttait tant bien que mal contre des creux de trois mètres. J’ai bien cru que j’allais y rester, ce qui a atténué le mal de mer. Le moniteur de plongée, un grec massif toujours là pour gaudrioler, ne nous a pas vraiment rassuré lorsqu’il nous tint, d’une mine des plus sérieuses&nbsp;: «&nbsp;Je vous recommande fortement de remettre vos combinaisons&nbsp;». Après une heure de bataille, le capitaine a préféré rebrousser chemin pour se réfugier sur une île plus proche.</p>

<p>Un mal pour un bien, nous voici débarqué sur une île de locaux. Peu habitué à voir des étrangers, ceux-ci étaient plutôt amusés de notre sort. Nous avons pu gouter une noix de coco fraîchement ouverte (et son cœur très particulier), ainsi qu’une autre noix, dont je n’ai pas compris le nom, qu’ils concassent, font sécher et probablement frire. Ce n’était pas très goûteux, contrairement à la bonté du geste.</p>

<p>J’ai été assez étonné de constater qu’une île si éloignée soit tout de même touchée par la religion (musulmane, mais ce détail n’a que peu d’importance). Pour eux, Dieu n’est pas mort.</p>

<p>Après des heures d’attente, l’espoir de rentrer s’était effacée avec le soleil. Je trouvais cette perspective plus intéressante que de reprendre une mer agitée. Mais, après un repas concocté par les femmes (qui se cachaient), un bateau plus puissant nous ramènera sur une mer toujours peu clémente.</p>

<p>Le reste de notre séjour sera ponctué de <span lang="it">farniente</span>, de piscine et de lecture au son des vagues. Ce qui me sied plus&nbsp;!</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987801799/in/set-72157631539739849"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/6.jpg" alt="" /></a><br/>
	Piscine avec vue sur la mer <small>(ainsi que mon somptueux bronzage)</small>
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987812959/in/set-72157631539771661/"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/7.jpg" alt="" /></a><br/>
	À contempler la mer, on en oublie la flore tropicale
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987802771/in/set-72157631539739849"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/maldives/8.jpg" alt="" /></a><br/>
	Même la faune profite du paysage
</p>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2012/09/12/dubai-des-etoiles/">
  <title>Dubaï, des étoiles</title>
  <link>http://blog.neovov.com/2012/09/12/dubai-des-etoiles</link>
  <dc:date>2012-09-12T16:30:16+02:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>La vie</dc:subject>
  <description>Rien de tel qu’une folie pour s’arracher de l’onirisme. Dubaï nous semblait une bonne destination pour sauter en parachute.



	À ce moment, plus que jamais, on se dit « C’est une très mauvaise idée »




	Une minute de chute libre, la tête façonnée par des...</description>
  <content:encoded><![CDATA[ <p>Rien de tel qu’une folie pour s’arracher de l’onirisme. Dubaï nous semblait une bonne destination pour sauter en parachute.</p>

<p class=/"center">
	<a href="http://www.flickr.com/photos/neovov/7987678221/in/set-72157631539473163"><img width="500" height="311" src="https://static.neovov.com/neoblog/img/2012/09/parachute/1.jpg" alt="" /></a><br/>
	À ce moment, plus que jamais, on se dit «&nbsp;C’est une très mauvaise idée&nbsp;»
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987687012/in/set-72157631539473163"><img width="500" height="311" src="https://static.neovov.com/neoblog/img/2012/09/parachute/2.jpg" alt="" /></a><br/>
	Une minute de chute libre, la tête façonnée par des vents à 200km/h
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987689771/in/set-72157631539473163"><img width="500" height="311" src="https://static.neovov.com/neoblog/img/2012/09/parachute/3.jpg" alt="" /></a><br/>
	Quelques minutes de descente parachute ouvert, de quoi admirer la vue et sentir la chaleur du désert nous regagner
</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7987692069/in/set-72157631539473163"><img width="500" height="311" src="https://static.neovov.com/neoblog/img/2012/09/parachute/4.jpg" alt="" /></a><br/>
	Rien ne vaut la terre ferme
</p>

<p>L’intensité émotionnelle est hors normes. Bien trop pour que j’eusse apprécié.</p>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2012/09/05/dubai/">
  <title>Dubaï</title>
  <link>http://blog.neovov.com/2012/09/05/dubai</link>
  <dc:date>2012-09-05T05:58:08+02:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>La vie</dc:subject>
  <description>Cette destination ne nous faisait pas rêver, mais il s’agit d’une plateforme aérienne nous permettant de rejoindre d’autres points intéressants.



	Levé de soleil vu de l’avion


Dubaï n’est pas une ville très intéressante.
Les immeubles, jouant dans la démesure,...</description>
  <content:encoded><![CDATA[ <p>Cette destination ne nous faisait pas rêver, mais il s’agit d’une plateforme aérienne nous permettant de rejoindre d’autres points intéressants.</p>

<p class=/"center">
	<a href="http://www.flickr.com/photos/neovov/7984753384/in/set-72157631532436017"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/dubai/plane.jpg" alt="" /></a><br/>
	Levé de soleil vu de l’avion
</p>

<p>Dubaï n’est pas une ville très intéressante.</p>
<p>Les immeubles, jouant dans la démesure, s’articulent aux abords de <em>Sheikh Zayed Road</em>.
En s’y aventurant, on peut observer un luxe clinquant et dérangeant. On rentre dans un univers formaté par des marques à faire-valoir.</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7984749757/in/set-72157631532436017/"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/dubai/sheikh-zayed-road.jpg" alt="" /></a><br/>
	<a href="http://www.flickr.com/photos/neovov/7984831502/in/set-72157631532286862/"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/dubai/burj-khalifa.jpg" alt="" /></a><br/>
	La <em>Sheikh Zayed Road</em> et le <em>Burj Khalifa</em>
</p>

<p>Cette aseptisation est plutôt étrange&nbsp;; hormis les djellabas et l’arabe (systématiquement traduit en anglais) l’occidentalisation est très forte. Nous avons également croisé beaucoup d’asiatiques, certains touristes, d’autres travailleurs (pour la plupart Philippins). Cette surenchère donne une ville particulièrement fausse.</p>

<p class="center">
	<a href="http://www.flickr.com/photos/neovov/7984748709/in/set-72157631532436017/"><img width="500" height="375" src="https://static.neovov.com/neoblog/img/2012/09/dubai/slum.jpg" alt="" /></a>
</p>

<p>Au détour d’un immeuble, on peut voir ce qui s’apparentera bientôt à des taudis perdus dans le désert, déjà appelé «&nbsp;Vieux Dubaï&nbsp;».</p>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2012/09/03/vagabond/">
  <title>Vagabond</title>
  <link>http://blog.neovov.com/2012/09/03/vagabond</link>
  <dc:date>2012-09-03T03:32:50+02:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>La vie</dc:subject>
  <description>Notre vie est, ou devrait être, comme une promenade que l’on apprécie.
Nous choisissons notre chemin, plus ou moins parsemé d’embûches.

Une fois embarqué, il est difficile de changer de voie.
Pourtant, changer ouvre d’autres horizons.

Certains disent que c’est « l’occasion...</description>
  <content:encoded><![CDATA[ <p>Notre vie est, ou devrait être, comme une promenade que l’on apprécie.<br/>
Nous choisissons notre chemin, plus ou moins parsemé d’embûches.</p>

<p>Une fois embarqué, il est difficile de changer de voie.<br/>
Pourtant, changer ouvre d’autres horizons.</p>

<p>Certains disent que c’est « l’occasion d’une vie », je préfère me dire qu’il faut créer ces occasions.<br/>
Il est temps pour moi de continuer mes rêveries ailleurs.</p>]]></content:encoded>
</item>
<item rdf:about=/"http://blog.neovov.com/2012/01/19/gone/">
  <title>Gone</title>
  <link>http://blog.neovov.com/2012/01/19/gone</link>
  <dc:date>2012-01-19T01:50:35+01:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>News</dc:subject>
  <description>Parfois, un mot peut être lourd de sens. L’empathie, qui fait de nous ce que nous sommes, donne tout son sens. Souvent, l’absence d’une personne nous fait réaliser sa valeur.
Je vis avec des maux depuis longtemps ; eux ne sont pas partis, bien au contraire. Les mots, eux, sont difficiles à...</description>
  <content:encoded><![CDATA[ <p>Parfois, un mot peut être lourd de sens. L’empathie, qui fait de nous ce que nous sommes, donne tout son sens. Souvent, l’absence d’une personne nous fait réaliser sa valeur.</p>
<p>Je vis avec des maux depuis longtemps ; eux ne sont pas partis, bien au contraire. Les mots, eux, sont difficiles à choisir.</p>
<p>Le web m’a beaucoup apporté. Je ne suis pas sûr d’en avoir fait de même, bien que je l’aurais voulu.</p>
<p>Ce blog date de 2006. J’avoue ne pas y avoir écris régulièrement, ou plutôt comme je le souhaitais. À vouloir trop bien faire on se condamne à ne rien faire.</p>
<p>Il est temps de partir.</p>]]></content:encoded>
</item>
<item rdf:about=/"http://blog.neovov.com/2012/01/18/sopa/">
  <title>SOPA</title>
  <link>http://blog.neovov.com/2012/01/18/sopa</link>
  <dc:date>2012-01-18T09:00:00+01:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>News</dc:subject>
  <description>SOPA est un projet de loi actuellement débattu aux États-Unis. Son but honorable est de combattre le « piratage » en utilisant des moyens plus ou moins douteux.
Ce n’est pas la première fois que ce genre de loi est à l’étude. En France, nous avons déjà combattu la HADOPI,...</description>
  <content:encoded><![CDATA[ <p><a href=/"http://en.wikipedia.org/wiki/Sopa" hreflang="en">SOPA</a> est un projet de loi actuellement débattu aux États-Unis. Son but honorable est de combattre le «&nbsp;piratage&nbsp;» en utilisant des moyens plus ou moins douteux.</p>
<p>Ce n’est pas la première fois que ce genre de loi est à l’étude. En France, nous avons déjà combattu la <a href="http://fr.wikipedia.org/wiki/Haute_Autorit%C3%A9_pour_la_diffusion_des_%C5%93uvres_et_la_protection_des_droits_sur_internet"><abbr title="Haute Autorité pour la diffusion des œuvres et la protection des droits sur internet">HADOPI</abbr></a>, sans trop de succès. Cette loi n’est que peu efficace malgré un budget conséquent.</p>
<p>À défaut de résoudre les problèmes que ces lois proposent de résoudre, elles composent une menace pour les libertés fondamentales du web.</p>
<p>Ce n’est pas pour autant que ce qui est appelé «&nbsp;piratage&nbsp;» ne doit pas être combattu. Seulement, tant que les mentalités des combattants n’auront pas évoluées cette guerre aura toujours lieu.</p>]]></content:encoded>
</item>
<item rdf:about="http://blog.neovov.com/2010/11/02/10-trucs-html5-quon-ne-peut-pas-faire-en-flash/">
  <title>10 trucs HTML5 qu’on ne peut pas faire en Flash</title>
  <link>http://blog.neovov.com/2010/11/02/10-trucs-html5-quon-ne-peut-pas-faire-en-flash</link>
  <dc:date>2010-11-02T01:38:18+01:00</dc:date>
  <dc:language>fr</dc:language>
  <dc:creator>Neovov</dc:creator>
  <dc:subject>Coup de gueule</dc:subject>
  <description>Il y a des matins où j’aimerais rester au lit. Bon, après réflexion ça ne changerait rien vu que même de mon lit je pourrais lire des aberrations tel que “10 Flash Things You Can’t Do With HTML5” (« 10 trucs Flash qu’on ne peut pas faire en HTML5 »).

Ce genre...</description>
  <content:encoded><![CDATA[ <p>Il y a des matins où j’aimerais rester au lit. Bon, après réflexion ça ne changerait rien vu que même de mon lit je pourrais lire des aberrations tel que “<a href=/"http://active.tutsplus.com/articles/roundups/10-flash-things-you-can%E2%80%99t-do-with-html5/" hreflang="en" lang="en">10 Flash Things You Can’t Do With HTML5</a>” («&nbsp;10 trucs Flash qu’on ne peut pas faire en HTML5&nbsp;»).</p>

<p>Ce genre d’articles m’énerve. Si je mets de côté le débat «&nbsp;qui a la plus grosse <del>liste de possibilités</del>&nbsp;», il n’empêche que ces comparaisons sont foireuses, car HTML5 y est souvent mal compris. Ça craint, le HTML c’est quand même la base du web.</p>

<p>On a pu en avoir la preuve avec la dernière conférence <a href="http://max.adobe.com/" hreflang="en">Adobe MAX</a>. Il y a été présenté un «&nbsp;convertisseur Flash vers HTML5&nbsp;». Je veux bien concéder le raccourcis marketing « trucs cools = HTML5 », mais c’est quand même se tirer une balle dans le pied. Le but de HTML est, et restera, de structurer des données. Si on parle d’animations, il faut inclure CSS et/ou Javascript (après il y a un autre débat pour définir si une animation est de la présentation ou du comportement). En bref, il ne faut pas dire «&nbsp;regarde c’est cool, c’est du HTML5&nbsp;» puisque ça n’a rien de sexy en soit. Par contre, utiliser les dernières avancées des trois langages fondamentaux du web permet de faire des trucs vraiment cools. Si vous n’êtes pas convaincu, je vous présente <a href="http://paulrouget.com/" hreflang="en">Paul Rouget</a>.</p>

<p>Je suis encore assez étonné de l’incompréhension du travail du W3C sur HTML5. Le but de HTML5 n’est pas d’innover, mais de <strong>standardiser</strong>. C’est déjà énorme en soit. Il y a énormément de choses en HTML5 qu’on pouvait déjà faire (à quelques exceptions). Le W3C ne fait que regarder l’existant et propose une façon cohérente pour le faire (via des balises et/ou des API).</p>

<p>Bon, maintenant qu’on a ça en tête, prenons les 10 trucs <del>super cools</del> qu’on peut faire en Flash et pas en HTML/CSS/Javascript&nbsp;:</p>

<ol>
	<li>
		<h3><span lang="en">HTML5 can’t interact with webcam</span> — HTML5 ne peut pas utiliser la <span lang="en">webcam</span></h3>
		<p>Soit, pour l’instant. <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#devices" hreflang="en" lang="en"><code>&lt;device&gt;</code></a> est précisément en cours de conceptualisation pour faire ça. Petite précision, il faut bien évidemment se dire que ça sera à utiliser via une API et donc en Javascript.</p>
		<p>D’un point de vue plus personnel je trouve l’intérêt relatif. J’ai très rarement utilisé ma <span lang="en">webcam</span> dans Flash.</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 video cannot be used on a 3D plane</span> — Les vidéos HTML5 ne peuvent pas être utilisées avec de la 3D</h3>
		<p>Bon, toujours d’un point de vue personnel, l’intérêt est toujours aussi limité hormis le côté bling-bling.</p>
		<p>Ensuite, <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html" hreflang="en"><code lang="en">&lt;video&gt;</code></a> + <a href="http://www.w3.org/TR/css3-3d-transforms/" hreflang="en">CSS3 transform</a> + Javascript ça ne permet pas de le faire&nbsp;?</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 cannot record audio from your microphone</span> — HTML5 ne peut pas enregistrer à partir du microphone</h3>
		<p>Voir 1).</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 cannot do any sort of web conferencing</span> — HTML5 ne permet pas de faire de visioconférence</h3>
		<p>Ce point était vraiment gratuit à partir du moment où il n’est pas possible d’utiliser ni la <span lang="en">webcam</span> ni le micro. L’usage est particulièrement ciblé ce qui réduit les cas d’utilisation (&lt;troll&gt;mon MacBook Pro i5 flambant neuf a déjà du mal à lire une pauvre vidéo Flash alors de la visioconférence…&lt;/troll&gt;).</p>
		<p>Ensuite, j’imagine qu’en combinant <code>&lt;video&gt;</code>, <code>&lt;device&gt;</code> et les <a href="http://dev.w3.org/html5/websockets/" hreflang="en" lang="en">WebSockets</a> (en mode binaire, j’en fait la demande. <a href="https://developer.mozilla.org/fr">Mozilla</a> tu me lis&nbsp;?) j’imagine que c’est largement faisable. (Voir aussi <a href="http://www.w3.org/TR/2008/WD-html5-20080122/#peer-to-peer" hreflang="en" lang="en">P2P connections</a>)</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 cannot add dynamic objects to go over the video, like captions, titles, or navigational items</span> — HTML5 ne permet pas d’afficher des objets sur une vidéo comme des sous-titres, des titres, ou une navigation</h3>
		<p>Bon, là c’est clairement du <span lang="en">bullshit</span>. Oui, on ne peut pas faire ça en HTML5. Mais on ne peut pas le faire non plus en <a href="http://fr.wikipedia.org/wiki/MXML">MXML</a>. Il faudra forcément utiliser autre chose, comme de l’ActionScript. Oh&nbsp;! Mais on peut faire la même chose avec Javascript&nbsp;! Sans parler de <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-track-element" hreflang="en"><code>&lt;track&gt;</code></a> qui permet de baliser des éléments à synchroniser, <a href="http://www.w3.org/TR/2008/REC-SMIL3-20081201/" hreflang="en">SMIL</a> qui est un standard spécialement conçu pour ça ou encore de la possibilité de le faire avec n’importe quelle balise et du Javascript.</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 cannot record from your webcam</span> — HTML5 ne peut pas enregistrer à partir de la <span lang="en">webcam</span></h3>
		<p>Voir 1). En rajoutant <span lang="en">localStorage</span> c’est faisable.</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 cannot create desktop apps</span> — HTML5 ne permet pas de créer des applications</h3>
		<p>Quoi&nbsp;? HTML5 n’est pas un poney&nbsp;? Grosse déception.</p>
		<p>Allez, pour ceux qui n’ont toujours pas compris, HTML5 permet de structurer des données, ce n’est pas à lui de se lancer en mode <span lang="en">desktop</span>, c’est le boulot du navigateur. Et puis c’est un peu ridicule de parler de <a href="http://fr.wikipedia.org/wiki/Adobe_Integrated_Runtime">AIR</a> qui permet d’utiliser du Flash en mode <span lang="en">desktop</span> ET aussi du web.</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 can’t handle video with alpha channels</span> — HTML5 ne gère pas les vidéo qui ont un canal alpha</h3>
		<p>Bon, une fois de plus une utilisation de niche. Par contre, on peut effectivement <a href="http://html5doctor.com/video-canvas-magic/" hreflang="en">utiliser le canal alpha d’une vidéo</a> en utilisant <code>&lt;canvas&gt;</code>.</p>
	</li>
	<li>
		<h3><span lang="en">HTML5 doesn’t yet support P2P</span> — HTML5 ne permet pas le P2P</h3>
		<p>Je crois que j’ai déjà répondu au point 4). <span lang="en">WebSockets <abbr title="For The Win">FTW</abbr>!</span></p>
	</li>
	<li>
		<h3><span lang="en">HTML5 doesn’t do fullscreen mode</span> — HTML5 ne permet pas le plein écran</h3>
		<p>J’imagine que l’auteur parlait essentiellement de la vidéo. Je veux bien accorder ce point. Autant je comprends la position du W3C qui n’autorise pas ces pratiques pour des raisons de sécurité et de confort utilisateur. Autant c’est une demande constante chez les clients et une grosse cause de déception. Cela dit, le <span lang="en">fullwindows</span> c’est joli (ça change quoi).</p>
	</li>
</ol>

<p>Un peu de sérieux. J’ai peut-être un ton moqueur, mais l’article cache en fait un autre problème qui m’énerve particulièrement.</p>

<p>Le <span lang="en">buzz</span>, si je puis dire (ah, on me dit que je devrais écrire «&nbsp;ramdam&nbsp;»), autour de HTML5 a créé beaucoup d’articles comme celui-ci. Je comprends tout à fait l’engouement que des développeurs peuvent avoir pour les technologies qu’ils affectionnent (ce billet n’existerait pas si je n’en faisais pas partie). Mais le vrai problème est que tout cela est un débat stérile et qu’on en oublie l’essentiel. Pire, ces articles vont être relayés, référencés, lu, mal-compris et faire partie d’un tout estampillé HTML5.</p>

<p>Par exemple, j’ai déjà vu des présentations sur HTML5 qui parlaient de la balise <code>&lt;dialog&gt;</code>. C’est une balise morte-née mais qui existe tout de même dans l’inconscient du web. Peu sont ceux qui vont consulter la spécification pour s’assurer que ce qu’ils lisent est correct.</p>

<p>C’est un conseil que je donne quand je fais mon cours sur HTML5&nbsp;: Méfiez-vous de ce que vous pouvez lire sur le web. Il y a beaucoup d’articles périmés ou prématurés.</p>

<p>Pendant que j’y suis, ignorez, oubliez, offusquez toutes dates concernant HTML5. Tout d’abord, parce qu’elles ne signifient rien, ce ne sont que des estimations. Ensuite, il ne faut surtout pas attendre un quelconque aval du W3C pour se lancer sur HTML5 (à moins que vous n’ayez attendu <a href="http://www.w3.org/TR/CSS2/" hreflang="en">le 8 septembre 2009</a> avant de faire du CSS 2.1&nbsp;?). Et, pour finir, justement, la dernière étape de la spécification est la recommandation. Pour avoir ce statut la technologie doit avoir fait ses preuves comme étant stable. Si vous attendez… Elle ne deviendra jamais une recommandation. J’ai même envie de dire, si vous attendez, elle mettra encore plus de temps avant de devenir une recommandation.</p>

<p>Bon, maintenant que vous avez tout lu, allez apprendre HTML5 ou me faire un truc de folie avec les nouvelles API.</p>]]></content:encoded>
</item>
</rdf:RDF>
