Video e Canvas: un esempio pratico

4 aprile 2011

In questa lezione vedremo come manipolare flussi video in tempo reale con l’ausilio di un canvas. Perché il tutto funzioni è necessario che sia il video che la pagina che costruiremo risiedano sullo stesso dominio. Questo per prevenire l’intervento di alcune policy di sicurezza del browser che impediscono di fatto la modifica di materiale multimediale che non provenga dalla stessa origine della pagina. Ecco uno schema di quanto realizzeremo:

Figura 4 (click per ingrandire)

screenshot

Utilizzeremo due canvas. Nel primo replicheremo i fotogrammi del video, mentre nel secondo andremo a inserire il risultato della nostra elaborazione sull’array di pixel estratti dal primo. Il procedimento sarà quindi il seguente:

  • Avviare la riproduzione del video;
  • Utilizzare la funzione drawImage per disegnare sul primo canvas il contenuto del fotogramma corrente del video;
  • Con la funzione getImageData recuperare dal canvas il fotogramma precedentemente disegnato, questa volta però come array di pixel modificabili;
  • Effettuare un ciclo su tutti i pixel recuperati apportando le modifiche volute;
  • Utilizzare la funzione putImageData per disegnare l’array di pixel modificato sul secondo canvas;
  • Ripetere dal secondo punto la procedura.

Ecco il codice necessario:

<!doctype html>
<html>
<head>
    <title> Canvas e Video </title>
    <script>
        decomposizioneColori = function(video, context, context_nascosto, colori){
            if(video.paused || video.ended) return false;
            context_nascosto.drawImage(video,0,0);
            var fotogramma = context_nascosto.getImageData(0,0,
                context_nascosto.canvas.width,context_nascosto.canvas.height);
            var fotogramma_data = fotogramma.data;
            var rosso = colori.rosso.checked;
            var verde = colori.verde.checked;
            var blu   = colori.blu.checked;
            for(var i=0; i < fotogramma_data.length; i+=4){
                if (!rosso)  fotogramma_data[i  ] = 0;
                if (!verde)  fotogramma_data[i+1] = 0;
                if (!blu  )  fotogramma_data[i+2] = 0;
            }
            fotogramma.data = fotogramma_data;
            context.putImageData(fotogramma,0,0);
            setTimeout(function(){
                decomposizioneColori(video, context, context_nascosto, colori)
            },0);
        }
    
        aspettaIlPlay = function(evento){
            var video            = document.querySelector('video');
            video.addEventListener("play", function(evento){
                var context          = document.querySelector('#canvas_principale').getContext('2d');
                var context_nascosto = document.querySelector('#canvas_elaborazione').getContext('2d');
                context.canvas.width = context_nascosto.canvas.width = video.clientWidth;
                context.canvas.height = context_nascosto.canvas.height = video.clientHeight;
                decomposizioneColori(evento.target,context,context_nascosto, document.forms.colori);
            },true);
        }

        window.addEventListener("load",aspettaIlPlay,true);
        
    </script>
</head>
<body>
    <canvas id="canvas_principale"></canvas>
    <canvas id="canvas_elaborazione" style="display:none;"></canvas>
    <video  poster="big_buck_bunny/poster.jpg" controls>
        <source src="big_buck_bunny/trailer.mp4"  type="video/mp4" >
        <source src="big_buck_bunny/trailer.ogg"  type="video/ogg" >
        <source src="big_buck_bunny/trailer.webm" type="video/webm">
    </video>
    <form name="colori">
        <fieldset>
            <legend>Usa le checkbox per controllare i tre canali (RGB)</legend>
            <label> Rosso <input type="checkbox" name="rosso" checked></label>
            <label> Verde <input type="checkbox" name="verde" checked></label>
            <label> Blue  <input type="checkbox" name="blu" checked></label>
        </fieldset>
    </form>
</body>
</html>

Il funzionamento si concentra in decomposizioneColori; qui vengono eseguite tutte le operazioni che abbiamo citato. All’interno del ciclo che scorre tutti i pixel (nelle componenti RGBA) un semplice controllo pilotato da una form ‘spegne’ le componenti di colore corrispondenti ad una checkbox non spuntata con un risultato simile a quello dell’immagine seguente:

Figura 5

screenshot

Merita un cenno anche l’interessante uso della funzione requestAnimationFrame; il W3C ha predisposto questo metodo per meglio coordinare la gestione di animazioni all’interno di documenti web. A differenza dei suoi ‘cugini’ setTimeout e setInterval questa funzione applica alcune tecniche per ottimizzare le perfomance e mantenere basso l’utilizzo delle risorse del sistema. Purtroppo la maggior parte dei browser la considera ancora sperimentale e quindi antepone il proprio prefisso (moz, o, ms o webkit). Per risolvere questo problema esistono alcuni snippet di codice come quello proposto da Paul Irish.

Possiamo verificare il tutto nella demo conclusiva.

Conclusioni

In queste ultime due lezioni abbiamo esplorato tutto l’ecosistema che circonda la nascita del tag video. Prima di passare alla prossima lezione ricordiamo che intorno a questo elemento già si affacciano le prime librerie, capaci di aiutare nella personalizzazione del player e nella gestione di fallback su altre tecnologie nel caso l’HTML5 non sia supportato. In particolare segnaliamo l’ottimo video.js, che sicuramente merita una visita di approfondimento.

Tutte le lezioni

1 ... 45 46 47 ... 51

Se vuoi aggiornamenti su Video e Canvas: un esempio pratico inserisci la tua e-mail nel box qui sotto:
Tags:
 
X
Se vuoi aggiornamenti su Video e Canvas: un esempio pratico

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy