Passer au contenu principal

Apprenez à utiliser le requestVideoFrameCallback () pour travailler plus efficacement avec les vidéos dans le navigateur.


Mise à jour

Il y a une nouvelle API Web dans le bloc, définie dans le
HTMLVideoElement.requestVideoFrameCallback ()

spécification. Les requestVideoFrameCallback () La méthode permet aux auteurs Web d'enregistrer un rappel qui exécute les étapes de rendu lorsqu'une nouvelle image vidéo est envoyée au compositeur. Ceci est destiné à permettre aux développeurs d'effectuer des opérations efficaces par image de vidéo à vidéo, telles que le traitement vidéo et la peinture sur une toile, l'analyse vidéo ou la synchronisation avec des sources audio externes.

Différence avec requestAnimationFrame ()

Opérations telles que dessiner une image vidéo sur un canevas à l'aide
drawImage ()

igraal_fr-fr

fait via cette API sera synchronisé au mieux avec la fréquence d'images de la vidéo qui est lue à l'écran. Différent de
window.requestAnimationFrame (), qui se déclenche généralement environ 60 fois par seconde,
requestVideoFrameCallback () est lié à la fréquence d'images réelle de la vidéo, avec un
exception:

Le taux effectif auquel les rappels sont exécutés est le taux le plus bas du taux vidéo et du taux du navigateur. Cela signifie qu'une vidéo à 25 ips lue dans un navigateur qui peint à 60 Hz déclencherait des rappels à 25 Hz. Une vidéo à 120 ips sur ce même navigateur à 60 Hz déclencherait des rappels à 60 Hz.

Qu'est-ce qu'il y a dans un nom?

En raison de sa similitude avec window.requestAnimationFrame (), la méthode était initialement proposé comme video.requestAnimationFrame (), mais je suis content du nouveau nom,
requestVideoFrameCallback (), ce qui a été convenu après un longue discussion. Hourra, vélos pour la victoire!

Prise en charge du navigateur et détection des fonctionnalités

La méthode est
implémenté dans Chromium
déjà, et
Les gens de Mozilla aiment. Pour ce que ça vaut, j'ai également soumis un
Erreur WebKit le demander. La détection des fonctionnalités de l'API fonctionne comme ceci:

if ( 'requestVideoFrameCallback' dans HTMLVideoElement . prototype ) {
}

Utilisation de la méthode requestVideoFrameCallback ()

Si vous avez déjà utilisé le requestAnimationFrame () méthode, vous vous sentirez immédiatement chez vous avec la requestVideoFrameCallback () méthode. Vous enregistrez un rappel initial une fois, puis vous vous réinscrivez chaque fois que le rappel est déclenché.

const doSomethingWithTheFrame = ( maintenant , métadonnées ) => {
console . log ( maintenant , métadonnées ) ;
vidéo . requestVideoFrameCallback ( doSomethingWithTheFrame ) ;
} ;
vidéo . requestVideoFrameCallback ( doSomethingWithTheFrame ) ;

Dans le rappel, à présent c'est un DOMHighResTimeStamp

y métadonnées c'est un VideoFrameMetadata

dictionnaire avec les propriétés suivantes:

  • presentationTime, de type DOMHighResTimeStamp: Heure à laquelle l'agent utilisateur a envoyé le cadre pour la composition.
  • attenduDisplayTime, de type DOMHighResTimeStamp: Heure à laquelle l'agent utilisateur s'attend à ce que le cadre soit visible.
  • largeur, de type non signé longtemps: La largeur de l'image vidéo, en pixels multimédias.
  • la taille, de type non signé longtemps: La hauteur de l'image vidéo, en pixels multimédia.
  • mediaTime, de type double: L'horodatage d'affichage du média (PTS) en secondes de l'image affichée (par exemple, votre horodatage dans le video.currentTime ligne de temps).
  • Cadres présentés, de type non signé longtemps: Compte du nombre d'images envoyées pour la composition. Permet aux clients de déterminer si des trames ont été perdues entre les instances de VideoFrameRequestCallback.
  • traitementDurée, de type double: La durée écoulée en secondes depuis l'envoi du paquet codé avec le même horodatage de présentation (PTS) que cette trame (par exemple, le même que le mediaTime) au décodeur jusqu'à ce que la trame décodée soit prête à être présentée.

Pour les applications WebRTC, des propriétés supplémentaires peuvent apparaître:

  • captureTime, de type DOMHighResTimeStamp: Pour les images vidéo provenant d'une source locale ou distante, c'est le moment où la caméra a capturé l'image. Pour une source distante, l'heure de capture est estimée à l'aide de la synchronisation d'horloge de l'émetteur RTCP et de la génération de rapports pour convertir les horodatages RTP en heure de capture.
  • recevoirTime, de type DOMHighResTimeStamp: Pour les trames vidéo provenant d'une source distante, il s'agit de l'heure à laquelle la plate-forme a reçu la trame codée, c'est-à-dire l'heure à laquelle le dernier paquet appartenant à cette trame a été reçu via le réseau.
  • rtpTimestamp, de type non signé longtemps: Horodatage RTP associé à cette image vidéo.

Notez que largeur y la taille peut différer de videoWidth y vidéoHeight dans certains cas (par exemple, une vidéo anamorphique peut avoir des pixels rectangulaires).

Un intérêt particulier dans cette liste est mediaTime. Dans l'implémentation Chromium, nous utilisons l'horloge audio comme source de temps qui prend en charge video.currentTime, Pendant ce temps, il mediaTime est peuplé directement par le PrésentationTimestamp du cadre. Les mediaTime est ce qu'il faut utiliser si vous souhaitez identifier avec précision les images de manière reproductible, même pour identifier exactement les images qui ont été perdues.

Malheureusement, l'élément vidéo ne garantit pas la précision des images recherche. Cela a été un sujet de discussion.
WebCodecs cela permettra éventuellement des applications précises.

Si les choses semblent être une boîte loin ...

La synchronisation verticale (ou simplement vsync) est une technologie graphique qui synchronise la fréquence d'images d'une vidéo et la fréquence de rafraîchissement d'un moniteur. Car requestVideoFrameCallback () il s'exécute dans le fil principal, mais sous le capot, la composition vidéo se produit dans le fil du compositeur, tout ce qui provient de cette API est un meilleur effort et nous n'offrons aucune garantie stricte. Ce qui peut se produire, c'est que l'API peut retarder un vsync par rapport au moment où une image vidéo est rendue. Un vsync est requis pour que les modifications apportées à la page Web via l'API apparaissent à l'écran (comme window.requestAnimationFrame ()). Donc, si vous continuez à mettre à jour mediaTime ou le numéro d'image sur votre page Web et comparez-le aux images vidéo numérotées, la vidéo aura finalement l'air d'avoir une image d'avance.

Ce qui se passe réellement, c'est que la trame est prête dans vsync x, le rappel se déclenche et la trame est traitée dans vsync x + 1, et les modifications apportées au rappel sont traitées dans vsync x + 2. Vous pouvez vérifier si le rappel est un vsync tardif (et le cadre est déjà rendu à l'écran) en vérifiant si le metadata.expectedDisplayTime est d'environ à présent ou un vsync dans le futur. Si c'est dans les cinq à dix microsecondes de à présent, l'image est déjà rendue; Si il attenduDisplayTime il reste environ seize millisecondes dans le futur (en supposant que votre navigateur / écran se mette à jour à 60 Hz), alors il est synchronisé avec le cadre.

Manifestation

J'ai créé un petit
Démo Glitch
qui montre comment les images sont dessinées sur un canevas à exactement la fréquence d'image de la vidéo et où les métadonnées d'image sont enregistrées à des fins de débogage. La logique de base n'est que quelques lignes de JavaScript.

laissez paintCount = 0 ;
laissez startTime = 0.0 ;

const updateCanvas = ( maintenant , métadonnées ) => {
if ( startTime === 0.0 ) {
startTime = maintenant ;
}

ctx . drawImage ( vidéo , 0 , 0 , toile . largeur , toile . hauteur ) ;

const elapsed = ( maintenant - startTime) / 1000.0 ;
const fps = ( ++ paintCount / elapsed) . toFixed ( 3 ) ;
fpsInfo . innerText = ` fps vidéo: $ { fps } ` ;
metadataInfo . innerText = JSON . stringify ( métadonnées , null , 2 ) ;

vidéo . requestVideoFrameCallback ( updateCanvas ) ;
} ;

vidéo . requestVideoFrameCallback ( updateCanvas ) ;

Conclusions

J'ai fait du traitement au niveau de la trame pendant longtemps, sans avoir accès aux trames réelles, juste en fonction de video.currentTime. J'ai implémenté la segmentation des plans vidéo en JavaScript de manière approximative; vous pouvez toujours lire la pièce jointe
travail de recherche. Avait le requestVideoFrameCallback () existait à l'époque, ma vie aurait été beaucoup plus simple ...

Merci

Les requestVideoFrameCallback L'API a été spécifiée et mise en œuvre par
Thomas Guilbert. Cet article a été révisé par Joe medley
y Kayce Basques.
Image de héros pour
Denise Jans sur Unsplash.

Erreur: Attention: Contenu protégé.