Introduction aux lecteurs vidéo personnalisés

Les lecteurs HTML5 standard fonctionnent bien pour la lecture de base, mais ils limitent votre capacité à créer une interface utilisateur unique ou à ajouter une interactivité avancée. En combinant JavaScript avec l'élément , vous avez un contrôle complet sur la façon dont la vidéo est rendue, contrôlée et améliorée. Cette approche permet des peaux personnalisées, des effets visuels en temps réel, des superpositions dynamiques et une intégration transparente avec d'autres graphiques basés sur la toile.

Ce guide vous permet de parcourir chaque étape de la construction d'un lecteur vidéo entièrement personnalisé en utilisant l'API de toile HTML5. Vous apprendrez à capturer des images vidéo, à les dessiner sur une toile, à mettre en œuvre des contrôles personnalisés (jouer/pause, chercher, volume), à ajouter des filtres visuels et des sous-titres, et à optimiser les performances pour une lecture en douceur.

Comprendre la combinaison Toile et Vidéo

L'élément fournit une surface de dessin à base de pixel qui peut être manipulée en temps réel via JavaScript. Lorsqu'il est combiné avec l'élément , vous pouvez traiter chaque image comme une source d'image et l'attirer sur la toile. Cela vous permet de modifier l'image avant l'affichage, d'ajouter des superpositions ou même de remplacer les commandes par défaut du navigateur par une interface personnalisée.

Les principaux avantages de l'utilisation de toile pour la vidéo sont les suivants :

  • Contrôle complet du rendu :[ Appliquer des filtres d'image, des corrections de couleur ou des effets de composition avant que l'utilisateur ne voie le cadre.
  • Composants d'interface utilisateur personnalisés: Concevoir des boutons, des curseurs et des barres de progression qui correspondent à votre marque sans compter sur les styles de navigateur natifs.
  • Relèvement interactif:[ Ajouter des annotations, sous-titres, points chauds ou visualisation des données qui répondent aux événements de l'entrée ou de la chronologie vidéo de l'utilisateur.
  • Intégration graphique sans couture:[ Combiner la vidéo avec d'autres éléments de toile comme des graphiques, des animations ou du contenu WebGL.

Une considération importante : la toile consomme plus de ressources CPU/GPU que l'élément vidéo natif car elle redessine les images en continu. Nous aborderons l'optimisation des performances plus tard dans l'article.

Configuration de la structure HTML

Commencez par une structure HTML minimale qui comprend à la fois un élément (caché ou recouvert) et un élément . L'élément vidéo sert de source de cadres; il peut être caché ou placé derrière la toile en utilisant CSS. Pour plus de simplicité, nous superposons la toile sur la vidéo à l'intérieur d'un conteneur avec .

<div id="player-container" style="position: relative; width: 640px; height: 360px;">
 <video id="source-video" width="640" height="360" src="your-video.mp4" preload="metadata"></video>
 <canvas id="player-canvas" width="640" height="360"
 style="position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
</div>

Vous pouvez également cacher l'élément natif entièrement et uniquement l'utiliser comme fournisseur d'images. Pour ce faire, ajoutez à la vidéo. Cependant, gardez-le présent dans le DOM parce que la toile ne peut pas accéder au flux vidéo sans un élément existant . Ajustez les dimensions du conteneur pour correspondre à la taille de votre lecteur souhaitée.

Dessiner des cadres vidéo sur la toile

La fonctionnalité de base est une boucle de rendu qui efface la toile et dessine l'image vidéo actuelle chaque fois que le navigateur demande une image d'animation. Utilisez pour des mises à jour fluides et efficaces.

Mise en œuvre de base JavaScript :

const video = document.getElementById('source-video');
const canvas = document.getElementById('player-canvas');
const ctx = canvas.getContext('2d');

function renderFrame() {
 if (!video.paused && !video.ended) {
 ctx.clearRect(0, 0, canvas.width, canvas.height);
 ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
 }
 requestAnimationFrame(renderFrame);
}

video.addEventListener('play', () => {
 requestAnimationFrame(renderFrame);
});

video.addEventListener('pause', () => {
 // Optionally stop the loop or keep the last frame
});

Cette boucle attire en permanence la vidéo sur la toile tant que la vidéo est en lecture. La méthode accepte l'élément vidéo comme source. Si vous cachez l'élément vidéo, les utilisateurs ne verront que la toile, rendant le lecteur entièrement personnalisé.

Traitement des différents ratios d'aspect vidéo

Utilisez les propriétés et après les charges de métadonnées pour ajuster la taille de la toile. Pour une mise en page réactive, utilisez CSS pour limiter le conteneur et faire remplir la toile tout en maintenant le rapport d'aspect.

video.addEventListener('loadedmetadata', () => {
 canvas.width = video.videoWidth;
 canvas.height = video.videoHeight;
 // Also update container dimensions if needed
});

Construction de contrôles personnalisés sur la Toile

Bien que vous puissiez superposer des éléments HTML sur la toile (avec positionnement absolu), une approche plus intégrée consiste à dessiner des contrôles directement sur la toile. Cela vous donne la liberté de conception de niveau pixel et évite les problèmes de superposition des éléments.

Bouton de jeu/pause

Définissez une région rectangulaire sur la toile et écoutez les événements de clic. Déterminer si le clic tombe dans cette région. Pour plus de simplicité, nous utiliserons un bouton HTML pour cet exemple, mais dessiner sur la toile est aussi simple.

<button id="play-btn" style="position: absolute; top: 10px; left: 10px; z-index: 2;">Play/Pause</button>

JavaScript:

document.getElementById('play-btn').addEventListener('click', () => {
 if (video.paused) {
 video.play();
 } else {
 video.pause();
 }
});

Pour un bouton entièrement en toile, vous dessinez une forme et vérifiez les coordonnées sur . Utilisez pour la détection des coups.

Chercher une barre (Slider de progression)

Une barre de progression peut être dessinée comme un rectangle avec une section remplie indiquant la progression de la lecture. Mettez à jour sur les événements et laissez cliquer/drag chercher.

// Draw progress bar inside renderFrame or on timeupdate
const barX = 20, barY = canvas.height - 30, barWidth = canvas.width - 40, barHeight = 10;
ctx.fillStyle = '#444';
ctx.fillRect(barX, barY, barWidth, barHeight);
ctx.fillStyle = '#f00';
const progress = (video.currentTime / video.duration) || 0;
ctx.fillRect(barX, barY, barWidth * progress, barHeight);

Ajoutez un clic auditeur sur la toile pour rechercher:

canvas.addEventListener('click', (e) => {
 const rect = canvas.getBoundingClientRect();
 const x = e.clientX - rect.left;
 const y = e.clientY - rect.top;
 if (y >= barY && y <= barY + barHeight && x >= barX && x <= barX + barWidth) {
 const seekFraction = (x - barX) / barWidth;
 video.currentTime = seekFraction * video.duration;
 }
});

Contrôle du volume

Comme pour la barre de recherche, vous pouvez dessiner un curseur de volume. Utilisez et propriétés. Écoutez ou événements sur une entrée de gamme, ou manipulez des souris dessine sur toile.

Pour une approche simple, utilisez une entrée de plage HTML sur la toile :

<input type="range" id="volume-slider" min="0" max="1" step="0.01" value="1"
 style="position: absolute; bottom: 10px; right: 10px; z-index: 2;">

JavaScript:

document.getElementById('volume-slider').addEventListener('input', (e) => {
 video.volume = e.target.value;
});

Ajout d'effets visuels et de filtres

Avant de dessiner le cadre, vous pouvez ajuster les données de pixel en utilisant et , ou utiliser des filtres CSS sur une toile hors écran. Cependant, pour des performances, envisagez d'utiliser (supporté dans les navigateurs modernes) pour appliquer des filtres SVG-comme sans manipulation manuelle de pixel.

Utilisation de ctx.filter pour les effets communs

// Apply sepia filter before drawing
ctx.filter = 'sepia(0.8)';
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
ctx.filter = 'none'; // reset

Les autres filtres disponibles sont , , , , , , et . Combinez-les pour des looks complexes.

Manipulation manuelle des pixels (Avancée)

Pour les effets non couverts par les filtres CSS, vous pouvez manipuler des pixels individuels. Notez que cela est coûteux sur le plan informatique et devrait être utilisé avec parcimonie. Exemple : créer un effet de pixel.

function pixelate(video, canvas, ctx, blockSize) {
 const w = canvas.width, h = canvas.height;
 ctx.drawImage(video, 0, 0, w, h);
 const imageData = ctx.getImageData(0, 0, w, h);
 const data = imageData.data;
 for (let y = 0; y < h; y += blockSize) {
 for (let x = 0; x < w; x += blockSize) {
 const p = (x + y * w) * 4;
 const r = data[p], g = data[p+1], b = data[p+2];
 for (let dy = 0; dy < blockSize && y + dy < h; dy++) {
 for (let dx = 0; dx < blockSize && x + dx < w; dx++) {
 const pi = ((x + dx) + (y + dy) * w) * 4;
 data[pi] = r; data[pi+1] = g; data[pi+2] = b;
 }
 }
 }
 }
 ctx.putImageData(imageData, 0, 0);
}

Appelez ceci dans votre boucle de rendu au lieu de la simple .

Ajouter des sous-titres et des annotations

Canvas facilite la superposition du texte sur le dessus de la vidéo. Pour les sous-titres, analysez un fichier SRT ou VTT et dessinez le texte aux heures correctes. Pour les annotations statiques, dessinez-les en fonction des intervalles de temps.

Parsing a Simple Subtitle Format

const subtitles = [
 { start: 0.5, end: 2.0, text: 'Hello, world!' },
 { start: 3.0, end: 5.5, text: 'This is a custom player.' }
];

function drawSubtitles(currentTime) {
 const sub = subtitles.find(s => currentTime >= s.start && currentTime <= s.end);
 if (sub) {
 ctx.font = '24px Arial';
 ctx.fillStyle = 'white';
 ctx.textAlign = 'center';
 ctx.shadowColor = 'black';
 ctx.shadowBlur = 4;
 ctx.fillText(sub.text, canvas.width/2, canvas.height - 50);
 ctx.shadowBlur = 0;
 }
}

Appelez à l'intérieur de votre fonction après avoir dessiné l'image vidéo.

Optimisation des performances

L'exécution d'une boucle de rendu de toile à 60fps pendant les manipulations de pixel peut taxer le navigateur. Suivez ces pratiques pour garder la lecture en douceur:

  • Limitez la fréquence d'images: Si vous n'avez pas besoin de 60fps, utilisez un chronomètre ou sautez les images. Cependant, s'aligne déjà sur la fréquence de rafraîchissement de l'affichage.
  • Minimiser les opérations de pixel:[ Régler et seulement si nécessaire. Éviter à l'intérieur de la boucle – utiliser seulement pour les filtres qui nécessitent un contrôle par pixel, et envisager d'utiliser une toile séparée hors écran pour le traitement lourd.
  • ] Au lieu de boucles manuelles: Les filtres accélérés GPU sont beaucoup plus rapides.
  • Disable anti-aliasing pour les dessins non gradués: Set lors du dessin de la vidéo à sa taille exacte.
  • Utilisez attribut:[ Lorsque vous travaillez avec , définissez pour indiquer le navigateur.
  • Mise à jour des gaz pour les contrôles : Ne redessine pas la toile entière pour les petites interactions. Utilisez des fonctions de mise à jour distinctes pour les contrôles qui changent rarement.

Testez votre lecteur sur des appareils de bas de gamme. Si vous remarquez des bégaiements, réduisez la résolution de la toile ( et ) et l'échellez via CSS (mais gardez le rapport d'aspect). Le navigateur va réduire la vidéo en interne, en économisant le temps de rendu.

Caractéristiques avancées: Image dans la photo, Streaming, et plus encore

Une fois que vous avez un lecteur personnalisé de base, vous pouvez l'étendre avec des API web modernes:

  • Photographie (PiP): Vous ne pouvez pas utiliser directement la toile pour PiP; vous devez plutôt utiliser l'élément vidéo original. Cependant, vous pouvez cacher la toile lorsque PiP est actif et la montrer à nouveau quand PiP se termine. Utilisez .
  • Adaptive Bitrate Streaming:[ Pour HLS ou DASH, utilisez une bibliothèque comme hls.js ou dash.js pour alimenter l'élément vidéo. La toile reste la surface de rendu.
  • Intégration WebGL:[ Pour les effets accélérés du matériel, utilisez avec le contexte WebGL () et dessinez la vidéo comme une texture.
  • Enregistrer la sortie de toile:[ Utiliser avec pour enregistrer la vidéo avec des effets appliqués.

Étude de cas : Construire une peau personnalisée minimaliste

Passons à l'exemple d'un monde réel : un joueur propre et minimal avec un fond transparent, une barre de progression mince et un bouton de lecture centré avec des effets de vol stationnaire.

HTML & #160;:

<div id="player" style="position: relative; width: 800px; height: 450px; background: #000;">
 <video id="vid" preload="auto" style="display: none;" src="sample.mp4"></video>
 <canvas id="skin" width="800" height="450" style="display: block;"></canvas>
</div>

JavaScript dessine une icône de lecture/pause sur la toile et gère les événements de la souris. La barre de progression n'apparaît que sur le vol stationnaire. Tous les contrôles sont dessinés à l'aide de la toile primitives 2D. Le résultat est un lecteur léger et entièrement personnalisé qui peut être intégré n'importe où.

Principales décisions de conception : utiliser une seule couche de toile, débonner les re-rends pour la barre de progression, et mettre en cache l'image d'icône comme une toile hors écran pour éviter de redessiner les formes complexes de chaque cadre.

Conclusion

La création de lecteurs vidéo personnalisés avec JavaScript et HTML5 Canvas vous permet de contrôler de manière absolue la présentation visuelle et l'interactivité du contenu vidéo. De la simple mise en image aux filtres et sous-titres complexes en temps réel, l'API toile fournit une boîte à outils flexible. Bien que les performances doivent être gérées avec soin, les compromis en valent souvent la peine pour la capacité de fournir une expérience vidéo vraiment marquée et engageante.

Pour plus de détails, consultez la documentation officielle de l'API MDN Canvas, la HTMLVidéoRéférence d'élément[, et la spécification W3C Canvas 2D Contexte. Pour la diffusion avancée, voir hls.js et dash.js.