Migrando del viejo Flash a HTML5

Hace pocos días que salió la noticia de que Adobe eliminará Flash de una vez por todas, y es que aunque llegue 10 años más tarde esta decisión, es algo que tarde o temprano tenía que suceder.

Y la verdad es que todavía hay un montón de páginas web, servicios dirigidos a clientes que siguen utilizando FLASH en su operativa diaria. Y desconozco si es porque son sistemas muy arcaicos que son imposibles de mejorar (cosa que dudo), o es por la vagancia de sus administradores/personas a cargo, que pasan completamente de ello bajo la excusa de…

Para que voy a cambiarlo si funciona

Pues queridos amigos, aquí os dejo unas cuantas razones:

  • Google Chrome, uno de los navegadores con mayor cuota de mercado dejará de dar soporte a Flash y a sus plugins
  • Flash no es compatible con Android
  • Los motores de búsqueda como Google o Bing, no son capaces de indexar webs en flash.
  • Se necesita tener descargado ‘Flash Player‘ de Adobe antes de poder acceder al contenido, lo cual es perder eficacia para el usuario final
  • Pérdida de usuarios por las razones anteriormente comentadas
  • Y muchos más

Pero no todo son malas noticias.

A día de hoy, y siendo 2017, hay soluciones que nos permiten enriquecer la web como lo hacíamos antes sin flash, pero eso si, de una forma elegante. Y es que actualmente hay algo conocido por sólo unos privilegiados, que se llama HTML5 y que incorpora soluciones nativas para realizar dibujos, reproducir audio, vídeo, etc.

En esta entrada, intentaré explicar de manera sencilla cómo usar la API de HTML5 para mostrar un vídeo y realizar dibujos en un canvas. Aaah, ¡y todo ello sin flash!!

La API de HTML5

 

Gracias a HTML5 se tiene soporte integrado para contenido multimedia gracias a los elementos <audio> y <vídeo>, ofreciendo la posibilidad de insertar contenido multimedia en documentos HTML sin necesidad de herramientas de terceros. De toda la API que HTML5 tiene, en esta entrada nos interesaremos por aquella relacionada con el video, y básicamente se resume a los siguientes métodos:

Method                  Description

addTextTrack()          Adds a new text track to the audio/video
canPlayType()           Checks if the browser can play the specified audio/video type
load()                  Re-loads the audio/video element
play()                  Starts playing the audio/video
pause()                 Pauses the currently playing audio/video

Pero ya vale de escribir, ¡veamos cómo funciona esto con ejemplos!

Ejemplos prácticos

Insertar un vídeo en la web

<video src="http://www.domain.tld/path/to/video.mp4" controls>
Tu navegador no es capaz de reproducir contenido multimedia de forma nativa en HTML5
</video>

Con estas tres simples líneas, ya somos capaces de mostrar un video en la web, incluso con los botones de control ( play, pause, volumen). Además, la línea

Tu navegador no es capaz de reproducir contenido multimedia de forma nativa.

nos sirve como fallback en caso de que el navegador que esté usando el usuario no sea compatible con HTML5. De esta forma, el usuario final sabrá que su dispositivo no va a ser capaz de reproducir el vídeo correctamente. Con todo esto en marcha, el resultado final seria algo así:

Aunque este ejemplo es bastante sencillo, veamos cómo realizar uno más complejo que tenga las siguientes características:

  • Añadir una imagen de póster antes de que el vídeo inicie.
  • Añadir pistas de subtítulos a vídeo.
  • Añadir múltiples fuentes de vídeo para maximizar la compatibilidad.
  • Iniciar la reproducción del vídeo con un evento custom.

Añadir el póster

Según la especificación de la API, el póster se define como:

The poster attribute specifies an image to be shown while the video is downloading, or until the user hits the play button. If this is not included, the first frame of the video will be used instead.

Y se implementa mediante el siguiente snippet:

" > <video controls poster="https://www.domain.tld/path/to/poster/image.jpg">
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>

Añadir las pistas de subtítulos

Es curioso mencionar que un mismo vídeo puede tener de 1 a N subtítulos definidos y todos se realizan de la siguiente manera:

<video controls poster="https://www.domain.tld/path/to/poster/image.jpg">
	<source src="movie.mp4" type="video/mp4">
	<track label="English" kind="subtitles" srclang="en" src="captions/vtt/en.vtt" default>
	<track label="Deutsch" kind="subtitles" srclang="de" src="captions/vtt/de.vtt">
	<track label="Español" kind="subtitles" srclang="es" src="captions/vtt/es.vtt">
	Your browser does not support the video tag.
</video>

Hay que mencionar que para que los subtítulos se muestren correctamente tienen que estar definidos como WebVTT, siguiendo la especificación definida en:

https://www.w3.org/TR/webvtt1/

Además es importante aplicar la extensión vtt al fichero de subtítulos así como establecer correctamente el MimeType de la respuesta HTTP para que los navegadores la entiendan correctamente, y así minimizar los errores.

Toda esta información acerca de los subtítulos, como colorearlos, personalizarlos y demás, se puede consultar en:

https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video

Añadir múltiples fuentes de video

Dependiendo del dispositivo o navegador en que se ejecute el vídeo, se necesitará un formato u otro. Por eso, y con el objetivo de maximizar las reproducciones del vídeo independientemente de donde se ejecute, HTML5 nos proporciona ciertas facilidades para ello. Dichas facilidades son la posibilidad de admitir como vídeo los siguientes formatos:

  • WebM: se basa en una versión restringida del formato contenedor Matroska. Siempre utiliza el códec de vídeo VP8 y el códec de audio Vorbis. WebM es soportado nativamente en Gecko (Firefox), Chrome y Ópera, y el soporte para el formato se puede agregar a Internet Explorer y Safari mediante la instalación de un add-on.
  • Ogg Theora Vorbis: El formato contenedor Ogg con el códec de vídeo Theora y el códec de audio Vorbis es compatible con Gecko (Firefox), Chrome y Opera, y el soporte para el formato se puede agregar a Safari mediante la instalación de un add-on. El formato no es compatible en Internet Explorer.

  • Ogg Opus: El contenedor Ogg también puede contener audio codificado con el códec Opus. El apoyo está disponible en Gecko 15.0 (Firefox 15.0 / Thunderbird 15.0 / SeaMonkey 2.12) y superior. (Como curiosidad, este es el formato que usa Whatsapp para codificar las notas de audio que se envían en los chats)
  • MP4: El formato contenedor MP4 con el códec de vídeo H.264 y, o bien el códec de audio AAC o el códec de audio MP3 es nativamente compatible con Internet Explorer, Safari y Chrome, pero Chromium y Ópera no son compatibles con el formato. Firefox pronto admite el formato, pero sólo cuando un decodificador de terceros esté disponible.
  • Wave PCM: El formato contenedor WAVE, con el códec de audio PCM (WAVE codec «1») con el apoyo de Gecko (Firefox), y Safari. Archivos en el formato contenedor WAVE normalmente terminan con la extensión «. wav».

Sabiendo que se admiten todos estos formatos, cada uno con sus propias restricciones y beneficios, podemos implementarlos de la siguiente manera:

<video controls poster="https://www.domain.tld/path/to/poster/image.jpg">
	<source src="movie.mp4" type="video/mp4">
	<source src="movie.ogg" type="video/ogg">
	<track label="English" kind="subtitles" srclang="en" src="captions/vtt/en.vtt" default>
	<track label="Deutsch" kind="subtitles" srclang="de" src="captions/vtt/de.vtt">
	<track label="Español" kind="subtitles" srclang="es" src="captions/vtt/es.vtt">
	Your browser does not support the video tag.
</video>

Iniciar la reproducción del vídeo con un evento custom

Por supuesto, al igual que con cualquier elemento de HTML, se puede controlar su comportamiento perfectamente desde JS. Para ello, vamos a partir del siguiente ejemplo:

<div class="playercontent">
  <div class="videocontent">
    <video id="submission_video" style="width:100%" poster="https://www.domain.tld/path/to/poster/01.jpg" controls="" crossorigin="anonymous">
      <source src="https://www.domain.tld/path/to/video/999.mp4" type="video/mp4">
      <source src="https://www.domain.tld/path/to/video/999.ogg" type="video/webm">
      <track kind="captions" label="Default subtitles" src="//path/to/subtitles/999.vtt" srclang="en" default="">
      video not supported
    </video>
  </div>
</div>

Una vez que tenemos el anterior snippet de código definido lo único que hace falta es recuperar mediante Js o jQuery el elemento <vídeo>. Para ello, y para hacerlo más sencillo, en este ejemplo le hemos puesto el identificador submission_vídeo.

Y para iniciar la reproducción de video mediante JS se puede realizar lo siguiente:

var video = document.getElementById('submission_video');
if (video !== undefined && video !== null) {
    //start video at the beginning
    video.currentTime = 0;
    //play video
    video.play();
}

A partir de ahí, se pueden realizar todo lo que queramos. Por ejemplo:

var video = document.getElementById('submission_video');
if (video !== undefined && video !== null) {
    video.pause();
    video.currentTime = 0;
}
var video = document.getElementById('submission_video');
if (video !== undefined) {
    //on video ended event
    video.addEventListener('ended', onVideoEnded, false);
    //on load metadata event
    if(mode == 'submission_mode'){
        video.addEventListener('loadedmetadata', function() {
            debug("video metadata loaded! parse subtitles now");
        });
    }
}

Pero… ¿y qué pasa con el audio? ¿Y si queremos grabar audio?

Pues también podemos gracias a su API.

Grabando audio con la API de HTML5

Aquí os explicamos todos los pasos necesarios para poder grabar audio de forma nativa:

  1. Se necesita que la página web donde se vaya a grabar audio disponga de certificado HTTPS válido. Esto es obligatorio porque es una restricción de la API. De lo contrario, no será capaz de obtener el stream de audio.
  2. Dar permiso de acceso al micrófono del dispositivo para que se pueda acceder al audio.
  3. Capturar el audio del dispositivo en formato PCM.
  4. Almacenarlo en memoria mientras se graba y acceder al resultado como objeto BLOB.

Solicitar permiso al micrófono

Normalmente cada vez que se quiere solicitar un permiso al navegador se realiza mediante la siguiente forma:

 function checkPermissions(permissionName, descriptor) {
     if (!recording_permission_granted) {
         initRecorder();
         //request required permissions
         //mic only for now
         try {
             navigator.permissions.query(descriptor || {
                     name: permissionName
                 })
                 .then(function(result) {
                     if (result.state === 'granted') {
                         recording_permission_granted = true;
                     } else if (result.state === 'prompt') {
                         recording_permission_granted = false;
                     } else if (result.state === 'denied') {
                         recording_permission_granted = false;
                     }
                     result.onchange = function() {
                         console.log("permission changed");
                     };
                 });
         } catch (err) {
             console.log(err);
         }
     }
 }

Pero el permiso del micrófono también se puede solicitar automáticamente cada vez que se llama a la función getUserMedia(). Por lo que el acceso al micrófono quedaría así:

 function startUserMedia(stream) {
     //detecting mics
     var mics = stream.getAudioTracks().length;
     if (mics > 0) {
         console.log("Audio tracks detected: " + mics);
         var input = audio_context.createMediaStreamSource(stream);
         //custom recorder settings
         config = {
             sampleRate: CONSTANTS.sample_rate, // 48kbps = 48000 sample rate in bits,
             numChannels: CONSTANTS.num_channels,
             bufferLen: CONSTANTS.buffer_len
         };
         recorder = new Recorder(input, config);
         recorderLoaded = true;
         recording_permission_granted = true;
     } else {
         console.log("No mics detected");
     }
 }

Capturar el audio en formato PCM

Una vez que tenemos hecho todo esto, basta con empezar a grabar de la siguiente manera:

if (recorder !== undefined) {
	audio_recorded = false;
	recorder && recorder.record();
	is_recording = true;
}

Obtener la grabación

function createDownloadLink() {
    recorder && recorder.exportWAV(function(blob) {
        var url = URL.createObjectURL(blob);
        var li = document.createElement('li');
        var au = document.createElement('audio');
        var hf = document.createElement('a');

        au.controls = true;
        au.src = url;
        hf.href = url;
        var filename = new Date().toISOString() + extension;
        hf.download = filename;
        hf.innerHTML = "Download audio"
        li.appendChild(au);
        li.appendChild(hf);
        recordingslist.appendChild(li);

        if (url !== undefined) {
            getRecordedAudioStream(blob, url, onAudioStreamReceived);
        }
    });
}

function getRecordedAudioStream(blob, bloburl, callback) {
    //using FileReader API
    var reader = new FileReader();
    reader.onloadend = function() {
        base64data = reader.result;
        if (callback !== undefined) {
            callback(base64data);
        }
    }
    if (blob !== undefined) {
        reader.readAsDataURL(blob);
    } else {
        debug("No blob audio file detected");
    }
}

function onAudioStreamReceived(audioStream) {
    if (audioStream !== undefined) {
        lastRecordedAudio = audioStream;
    }
}

 

Conclusiones

Existen todas las herramientas necesarias para poder reproducir contenido multimedia, ya sea audio o vídeo, animaciones 2D, animaciones 3D, etc. Por lo cual métodos antiguos como Flash ya no son una alternativa a la hora de desarrollar nuevos proyectos.

Sí que es cierto que para servicios que ya están desplegados, supone un cambio importante eliminar Flash de sus productos o servicios pero no todo es imposible. En Irontec ya hemos hecho desarrollos que involucraban dichos cambios. De cara a poder migrar esos servicios a futuro con el objetivo de mantenerlos disponibles a los usuarios ahora que el mundo por fin decide dejar flash de lado. Así que… difícil sí… pero no imposible.



¿Te gusta este post? Es solo un ejemplo de cómo podemos ayudar a tu empresa...
Sobre Sergio Anguita Lorenzo

Web developer; Geek & Computer Engineer; Irontec - BIlbao

1 Comentario

¿Por qué no comentas tú también?


  • Lo digo con cariño: repasa la ortografía por favor. Se hace difícil de leer.

    manwe Hace 4 años Responde


    • Buenos días Manwe.
      Gracias por el mensaje, fue un error en la edición. Solucionado

      Irontec Hace 4 años Responde


  • Si esta muy padre html5 pero pensando en eliminar flash que solucion hay de grabado de audio y toma de fotografias desde internet explorer, conosco algunas empresas que por seguridad solamente utilizan internet explorer

    David gonzalez Hace 4 años Responde


Queremos tu opinión :)