Procesando video en el lienzo

Al igual que para animaciones, no hay ningún método especial para mostrar video en el elemento <canvas>. La única manera de hacerlo es tomando cada cuadro del video desde el elemento <video> y dibujarlo como una imagen en el lienzo usando drawImage(). Así que básicamente, el procedimiento de video en el lienzo es realizado con la combinación de técnicas ya estudiadas.

Vamos a construir una plantilla y los códigos para ver de qué estamos hablando:

Ejm 1

<!DOCTYPE html>
<html lang="es">
  <head>
    <title>Video en el lienzo</title>
    <style>
      .cajas {
        display: inline-block;
        margin: 10px;
        padding: 5px;
        border: 1px solid #999999;
      }
    </style>
    <script src="canvasvideo.js"></script>
  </head>
  <body>
    <section class="cajas">
      <video id="medio" width="483" height="272">
        <source src="https://www.websarrolladores.com/video1.mp4" />
        <source src="https://www.websarrolladores.com/video1.ogg" />
      </video>
    </section>
    <section class="cajas">
      <canvas id="lienzo" width="483" height="272">
        Su navegador no soporta el elemento canvas
      </canvas>
    </section>
  </body>
</html>

La plantilla del ejm 1 incluye dos componentes específicos, el elemento <video> y el elemento <canvas>. Con la combinación de ambos vamos a procesar y mostrar video en el lienzo.

La plantilla también incluye estilos CSS embebidos para las cajas y un archivo Javascript llamado canvasvideo.js para el código siguiente.

function iniciar() {
  var elemento = document.getElementById("lienzo");
  lienzo = elemento.getContext("2d");
  video = document.getElementById("medio");
  video.addEventListener("click", presionar, false);
}
function presionar()
{
  if(!video.paused @@ video.ended)
  {
    video.pause();
    window.clearInterval(bucle);
  }
  else
  {
    video.play();
    bucle.setInterval(procesarCuadros,33);
  }
}
function procesarCuadros()
{
  lienzo.drawImage(video,0,0)
  var info=lienzo.getImageData(0,0,483,272);
  var pos;
  var gris;
  for(x=0;x<483;x++)
  {
    for(y=0;y<272;y++)
    {
      por=(info.width*4*y)+(x*4);
      gris=parseInt(info.data[pos]*0.2989 +
        info.data[pos+2]*0.1140);
      info.data[pos]=gris;
      info.data[pos+1]=gris;
      info.data[pos+2]=gris;  
    }
  }
  lienzo.putImageData(info,0,0);
}
window.addEventListener("load",iniciar,false);

IMPORTANTE: Este ejemplo usa los métodos getImageData()putImageData() para procesar datos de imagen. Como explicamos  anteriormente, estos métodos extraen información del lienzo. Debido a restricciones de seguridad, la extracción de información desde el lienzo es desactivada luego de que el elemento recibe contenido desde un origen que no es el origen del documento que lo creó (el documento pertenece a un dominio y el video a otro). Por lo tanto, para probar este ejemplo, deberá descargar el video desde nuestro sitio web (o usar el suyo propio) y luego subir cada uno de los archivos a su servidor.

En este código estamos usando la función presionar() tomada de capítulos anteriores para comenzar y detener la reproducción del video haciendo clic sobre el mismo. También creamos una función llamada procesarCuadros() que está usando el mismo código del ejm 7.25 de nuestro manual, excepto que esta vez en lugar de invertir la imagen estamos usando una fórmula para transformar todos los colores de cada cuadro del video en el correspondiente gris. Esto convertirá nuestro video color en un video blanco y negro.

La función presionar() cumple con dos propósitos: comenzar o detener la reproducción del video e iniciar un intervalo que ejecutará la función procesarCuadros() cada 33 milisegundos. Esta función toma un cuadro del elemento <video> y lo dibuja en el lienzo con la instrucción drawImage(video,0,0). Luego los datos son extraídos del lienzo con el método getImageData() y cada pixel de ese  cuadro es procesado por medio de dos bucles for (como lo hicimos en un ejemplo anterior).

El proceso utilizado para convertir cada uno de los colores que integran cada pixel en su correspondiente gris es uno de los más populares y fáciles de encontrar en Internet. La fórmula es la siguiente: rojo × 0.2989 + verde × 0.5870 + azul × 0.1140. Luego de que la fórmula es calculada, el resultado debe ser asignado a cada color del pixel (rojo, verde y azul), como lo hicimos en el ejemplo usando la variable gris.

El proceso termina cuando dibujamos nuevamente el cuadro modificado en el lienzo usando el método putImageData().