Manipulation Audio et Vidéo

La beauté du web est qu'on peut combiner différentes technologies pour en créer de nouvelles. Avoir de l'audio et vidéo nativement dans le navigateur nous donne la possibilité d'utiliser ces flux de données avec d'autres technologies comme <canvas>, WebGL ou Web Audio API pour modifier le média — par exemple ajouter des effets de réverbération ou de compression à l'audio, ou encore des filtres noir & blanc/sépia aux vidéos. Cet article fournit une référence pour expliquer ce que vous pouvez faire.

Manipulation Vidéo

La possibilité de lire les valeurs de pixels de chaque image d'une vidéo peut être très utile, cela nous permet de placer ces images dans d'autres contextes.

Vidéo et Canvas

<canvas> est un moyen de dessiner de manière scripté sur des pages web; c'est un outil très puissant et qui peut être couplé avec du contenu vidéo.

La technique générale est comme suit:

  1. Dessiner une image de l'élément <video> sur un élément <canvas> intermédiaire.
  2. Lire les données de l'élément <canvas> et les manipuler.
  3. Écrire les données manipulées dans le <canvas> que l'on veut afficher.
  4. Marquer une pause et répéter.

On peut configurer notre lecteur vidéo et l'élément <canvas> comme ceci:

html
<video
  id="my-video"
  controls="true"
  width="480"
  height="270"
  crossorigin="anonymous">
  <source
    src="https://jplayer.org/video/webm/Big_Buck_Bunny_Trailer.webm"
    type="video/webm" />
  <source
    src="https://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"
    type="video/mp4" />
</video>

<canvas id="my-canvas" width="480" height="270"></canvas>

Et les manipuler comme ceci: (en l'occurence, on affiche une version en noir et blanc de la vidéo)

js
var processor = {
  timerCallback: function () {
    if (this.video.paused || this.video.ended) {
      return;
    }
    this.computeFrame();
    var self = this;
    setTimeout(function () {
      self.timerCallback();
    }, 16); // roughly 60 frames per second
  },

  doLoad: function () {
    this.video = document.getElementById("my-video");
    this.c1 = document.getElementById("my-canvas");
    this.ctx1 = this.c1.getContext("2d");
    var self = this;

    this.video.addEventListener(
      "play",
      function () {
        self.width = self.video.width;
        self.height = self.video.height;
        self.timerCallback();
      },
      false,
    );
  },

  computeFrame: function () {
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
    var frame = this.ctx1.getImageData(0, 0, this.width, this.height);
    var l = frame.data.length / 4;

    for (var i = 0; i < l; i++) {
      var grey =
        (frame.data[i * 4 + 0] +
          frame.data[i * 4 + 1] +
          frame.data[i * 4 + 2]) /
        3;

      frame.data[i * 4 + 0] = grey;
      frame.data[i * 4 + 1] = grey;
      frame.data[i * 4 + 2] = grey;
    }
    this.ctx1.putImageData(frame, 0, 0);

    return;
  },
};

Une fois que la page est chargée, on peut appeler

js
processor.doLoad();

Note : En raison de problèmes de sécurité potentiels, si votre vidéo se trouve sur un domaine différent de votre page, vous devez activer CORS (Cross Origin Resource Sharing) sur le serveur qui héberge la vidéo et utiliser l'attribut crossorigin sur la balise vidéo.

Note : L'exemple présenté est un exemple minimal de manipulation vidéo avec canvas; pour plus d'efficacité, vous pouvez envisager d'utiliser requestAnimationFrame à la place de setTimeout pour les navigateurs qui le prennent en charge.

Vidéo e WebGL

WebGL est une API puissante qui utilise canvas pour (typiquement) afficher des scènes en trois dimensions. On peut combiner WebGL et l'élément <video> pour créer des textures vidéo, ce qui veut dire que vous pouvez placer une vidéo dans des scènes 3D.

Exemple:

Note : Vous pouvez trouver le code source de cette démo sur GitHub (la voir en direct aussi).

Vitesse de lecture

On peut ajuster la vitesse de lecture de l'audio et vidéo en utilisant l'attribut playbackRate (voir HTMLMediaElement). Il prend pour valeur un nombre qui est le coefficient à appliquer à la vitesse de lecture: par exemple, 0.5 représente la moitié de la vitesse tandis que 2 représente le double.

HTML:

html
<video
  id="my-video"
  controls
  src="https://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v"></video>

JavaScript:

js
var myVideo = document.getElementById("my-video");
myVideo.playbackRate = 2;

Code jouable

Note : Essayez l' exemple playbackRate en direct.

Note : playbackRate marche avec les éléments <audio> et <video>; cependant, dans les deux cas, la vitesse change mais pas la hauteur du son. Pour manipuler la hauteur du son, vous devez utliliser l'API Web Audio — voir la propriété AudioBufferSourceNode.playbackRate.

Manipulation Audio

Laissons playbackRate de côté. Pour manipuler l'audio, on utilise typiquement l'API Web Audio.

Sélectionner une source audio

On peut utiliser la piste audio d'un élément <audio> ou <video> comme source pour alimenter l'API Web Audio, ou un simple buffer audio, une onde sinusoïdale/oscillateur, un flux (comme getUserMedia de WebRTC)... Découvrez exactement comment les utiliser en lisant les pages suivantes:

Filtres Audio

L'API Web Audio a beaucoup de différents filtres/effets qui peuvent être appliqués à l'audio en utilisant BiquadFilterNode, par exemple:

HTML:

html
<video id="my-video" controls src="myvideo.mp4" type="video/mp4"></video>

JavaScript:

js
var context = new AudioContext(),
  audioSource = context.createMediaElementSource(
    document.getElementById("my-video"),
  ),
  filter = context.createBiquadFilter();
audioSource.connect(filter);
filter.connect(context.destination);

// Configure filter
filter.type = "lowshelf";
filter.frequency.value = 1000;
filter.gain.value = 25;

Code jouable 2

Note : À moins que CORS ne soit activé, vous devrez pour éviter les problèmes de sécurité placer la vidéo sur le même domaine que votre code.

Les filtres pouvant être appliqués sont:

  • Low Pass: Les fréquences en dessous de la fréquence de coupure sont inchangées et celles au-dessus sont atténuées.
  • High Pass: Les fréquences au-dessus de la fréquence de coupure sont inchangées et celles en dessous sont atténuées.
  • Band Pass: Les fréquence comprises entre deux bornes sont inchangées et celles en dehors sont atténuées.
  • Low Shelf: Les fréquences basses obtiennent un boost (ou une atténuation).
  • High Shelf: Les fréquences hautes obtiennent un boost (ou une atténuation).
  • Peaking: Les fréquences à l'intérieur d'une gamme donnée obtiennent un boost (ou une atténuation).
  • Notch: Les fréquences à l'intérieur d'une gamme donnée sont atténuées.
  • Allpass: Laisse touts les fréquences inchangées mais modifie le rapport de phrase entre les différentes fréquences.

Note : Voir BiquadFilterNode pour plus d'informations.

Convolutions et Impulsions

Il est également possible d'appliquer des réponses impulsionnelles à l'audio en utilisant ConvolverNode (en-US). Une réponse impulsionnelle (impulse response en anglais) est un son crée après une brève impulsion sonore (comme un applaudissement) et qui s'applique sur l'environnement qui l'a créée. Exemple: un écho crée en frappant des mains dans un tunnel.

Exemple:

js
var convolver = context.createConvolver();
convolver.buffer = this.impulseResponseBuffer;
// Connect the graph.
source.connect(convolver);
convolver.connect(context.destination);

Note : Voir ce Codepen pour un exemple appliqué.

Note : Voir ConvolverNode (en-US) pour plus d'informations.

Audio dans l'espace

On peut également positionner l'audio dans l'espace en utilisant un noeud panoramique (un panner). Ce noeud permet de définir un cône source ainsi que des éléments positionnels et directionnels — le tout dans un espace 3D définit par des coordonnées cartésiennes 3D.

Exemple:

js
var panner = context.createPanner();
panner.coneOuterGain = 0.2;
panner.coneOuterAngle = 120;
panner.coneInnerAngle = 0;

panner.connect(context.destination);
source.connect(panner);
source.start(0);

// Position the listener at the origin.
context.listener.setPosition(0, 0, 0);

Note : Vous pouvez trouver un exemple sur notre repo GitHub (le voir en direct aussi).

Note : Voir PannerNode (en-US) pour plus d'informations.

Codecs JavaScript

Il est possible de manipuler l'audio au bas niveau en utilisant JavaScript. Cela peut être utile si vous voulez créer des codecs audio.

Des bibliothèques existent actuellement pour les formats suivants:

Note : Sur AudioCogs, vous pouvez essayer quelques démos; Audiocogs fournit également un Framework, Aurora.js, qui est destiné à vous aider à créer vos propres codecs en JavaScript.

Tutoriels

Référence