Le Picture-in-picture (PIP) permet aux utilisateurs de regarder des vidéos dans une fenêtre flottante (toujours au-dessus des autres fenêtres) afin qu'il puisse garder un œil sur ce qu'il tout en interagissant avec d'autres sites ou applications.
Avec l'API Web Picture-in-picture, vous pouvez démarrer et contrôler Picture-in-picture pour les éléments vidéo de votre site Web. Essayez sur notre échantillon Picture-in-picture officiel.
Contexte
Depuis septembre 2016, Safari est compatible avec la fonctionnalité Picture-in-picture via une API WebKit. dans macOS Sierra. Six mois plus tard, Chrome jouait automatiquement Vidéo Picture-in-picture sur mobile avec la sortie d'Android O à l'aide d'un API Android native. Six mois plus tard, nous avons annoncé notre intention de créer et standardiser une API Web, une fonctionnalité compatible avec Safari, qui permettrait d'accéder aux développeurs de créer et de contrôler l'expérience complète du Picture-in-picture. Et voilà !
Découvrir le code
Utiliser le mode Picture-in-picture
Commençons simplement par un élément vidéo et un moyen d'interagir avec l'utilisateur. avec lui, comme un élément de bouton.
<video id="videoElement" src="https://example.com/file.mp4"></video>
<button id="pipButtonElement"></button>
Ne demandez le mode Picture-in-picture qu'en réponse à un geste de l'utilisateur, et jamais
promesse renvoyée par videoElement.play()
. En effet, les promesses
mais propager les gestes de l'utilisateur. Appelez plutôt requestPictureInPicture()
dans un
gestionnaire de clics sur pipButtonElement
, comme illustré ci-dessous. Il est de votre responsabilité
pour gérer ce qui se passe
si un utilisateur clique deux fois.
pipButtonElement.addEventListener('click', async function () {
pipButtonElement.disabled = true;
await videoElement.requestPictureInPicture();
pipButtonElement.disabled = false;
});
Lorsque la promesse est résolue, Chrome réduit la vidéo dans une petite fenêtre qui l'utilisateur peut se déplacer et se positionner par-dessus d'autres fenêtres.
Vous avez terminé. Bravo ! Vous pouvez arrêter de lire et aller prendre votre vacances. Malheureusement, ce n'est pas toujours le cas. La promesse peut être rejetée pour toute des raisons suivantes:
- Le Picture-in-picture n'est pas pris en charge par le système.
- L'utilisation du mode Picture-in-picture n'est pas autorisée sur le document en raison d'une règle d'autorisation.
- Les métadonnées de la vidéo n'ont pas encore été chargées (
videoElement.readyState === 0
). - Le fichier vidéo est audio uniquement.
- Le nouvel attribut
disablePictureInPicture
est présent dans l'élément vidéo. - L'appel n'a pas été effectué dans un gestionnaire d'événements de gestes de l'utilisateur (par exemple, un clic sur un bouton). À partir de Chrome 74, cela n'est applicable que s'il n'y a pas d'élément dans Picture-in-picture déjà.
La section Compatibilité des fonctionnalités ci-dessous indique comment activer/désactiver un bouton en fonction du ces restrictions.
Ajoutons un bloc try...catch
pour capturer ces erreurs potentielles et laissons
de savoir ce qui se passe.
pipButtonElement.addEventListener('click', async function () {
pipButtonElement.disabled = true;
try {
await videoElement.requestPictureInPicture();
} catch (error) {
// TODO: Show error message to user.
} finally {
pipButtonElement.disabled = false;
}
});
L'élément vidéo se comporte de la même manière, qu'il soit en mode Picture-in-picture non: les événements sont déclenchés et les méthodes d'appel fonctionnent. Elle reflète les changements d'état dans la fenêtre Picture-in-picture (pour lire, mettre en pause, rechercher, etc.) et de modifier l'état par programmation en JavaScript.
Quitter le mode Picture-in-picture
Maintenant, nous allons faire en sorte que notre bouton
passe en mode Picture-in-picture. Mer
vous devez d'abord vérifier si l'objet en lecture seule document.pictureInPictureElement
est notre élément vidéo. Si ce n'est pas le cas, nous vous envoyons une demande d'inscription
Picture-in-picture comme ci-dessus. Sinon, nous vous demandons de nous quitter en appelant
document.exitPictureInPicture()
, ce qui signifie que la vidéo sera de nouveau disponible dans
dans l'onglet d'origine. Notez que cette méthode renvoie également une promesse.
...
try {
if (videoElement !== document.pictureInPictureElement) {
await videoElement.requestPictureInPicture();
} else {
await document.exitPictureInPicture();
}
}
...
Écouter des événements Picture-in-picture
Les systèmes d'exploitation limitent généralement le Picture-in-picture à une seule fenêtre, L'implémentation de Chrome suit ce schéma. Cela signifie que les utilisateurs ne peuvent jouer une vidéo Picture-in-picture à la fois. Vous devez vous attendre à ce que les utilisateurs quittent Picture-in-picture même si vous ne l'avez pas demandé.
Les nouveaux gestionnaires d'événements enterpictureinpicture
et leavepictureinpicture
permettent
d'adapter l'expérience aux utilisateurs. Il peut s'agir de n'importe quoi,
de la consultation d'un
ou à afficher un chat en direct.
videoElement.addEventListener('enterpictureinpicture', function (event) {
// Video entered Picture-in-Picture.
});
videoElement.addEventListener('leavepictureinpicture', function (event) {
// Video left Picture-in-Picture.
// User may have played a Picture-in-Picture video from a different page.
});
Personnaliser la fenêtre Picture-in-picture
Chrome 74 prend en charge les boutons lecture/pause, titre précédent et morceau suivant dans Fenêtre Picture-in-picture que vous pouvez contrôler à l'aide de l'API Media Session.
Par défaut, un bouton de lecture/pause est toujours affiché dans la
sauf si la vidéo lit des objets MediaStream (par exemple, getUserMedia()
,
getDisplayMedia()
ou canvas.captureStream()
) ou si la vidéo dispose d'une MediaSource
la durée doit être définie sur +Infinity
(flux en direct, par exemple). Pour vous assurer qu’un
bouton lecture/pause
est toujours visible, définissez des gestionnaires d'actions de session multimédia à la fois pour "Lecture" et
"Mets en pause" les événements média comme ci-dessous.
// Show a play/pause button in the Picture-in-Picture window
navigator.mediaSession.setActionHandler('play', function () {
// User clicked "Play" button.
});
navigator.mediaSession.setActionHandler('pause', function () {
// User clicked "Pause" button.
});
Affichage du titre précédent et "Titre suivant" les commandes de fenêtre sont similaires. Paramètre Les gestionnaires d'actions de sessions multimédias associés à ces éléments les afficheront dans le mode Picture-in-picture. et vous serez en mesure de gérer ces actions.
navigator.mediaSession.setActionHandler('previoustrack', function () {
// User clicked "Previous Track" button.
});
navigator.mediaSession.setActionHandler('nexttrack', function () {
// User clicked "Next Track" button.
});
Pour voir comment cela fonctionne, essayez l'exemple officiel de session multimédia.
Obtenir la taille de la fenêtre Picture-in-picture
Si vous souhaitez régler la qualité à l'entrée et à la sortie de la vidéo vous devez connaître la taille de la fenêtre Picture-in-picture est averti si un utilisateur redimensionne manuellement la fenêtre.
L'exemple ci-dessous montre comment obtenir la largeur et la hauteur Fenêtre Picture-in-picture lorsqu'elle est créée ou redimensionnée.
let pipWindow;
videoElement.addEventListener('enterpictureinpicture', function (event) {
pipWindow = event.pictureInPictureWindow;
console.log(`> Window size is ${pipWindow.width}x${pipWindow.height}`);
pipWindow.addEventListener('resize', onPipWindowResize);
});
videoElement.addEventListener('leavepictureinpicture', function (event) {
pipWindow.removeEventListener('resize', onPipWindowResize);
});
function onPipWindowResize(event) {
console.log(
`> Window size changed to ${pipWindow.width}x${pipWindow.height}`
);
// TODO: Change video quality based on Picture-in-Picture window size.
}
Je vous conseille de ne pas connecter directement l'événement de redimensionnement à chaque petite modification apportée. à la taille de la fenêtre Picture-in-picture déclenche un événement distinct qui peut entraîner de performances si vous effectuez une opération coûteuse à chaque redimensionnement. Dans En d'autres termes, l'opération de redimensionnement déclenchera les événements à l'infini rapidement. Je vous recommande d'utiliser des techniques courantes telles que la limitation par rebond pour résoudre ce problème.
Compatibilité des caractéristiques
L'API Web Picture-in-picture n'est peut-être pas compatible. Vous devez donc le détecter.
pour apporter une
amélioration progressive. Même s'il est pris en charge, il peut être
désactivée par l'utilisateur ou désactivée par une règle d'autorisation. Heureusement, vous pouvez utiliser
la nouvelle valeur booléenne document.pictureInPictureEnabled
pour le déterminer.
if (!('pictureInPictureEnabled' in document)) {
console.log('The Picture-in-Picture Web API is not available.');
} else if (!document.pictureInPictureEnabled) {
console.log('The Picture-in-Picture Web API is disabled.');
}
Appliqué à un élément de bouton spécifique dans une vidéo, voici comment procéder : pour gérer la visibilité du bouton Picture-in-picture.
if ('pictureInPictureEnabled' in document) {
// Set button ability depending on whether Picture-in-Picture can be used.
setPipButton();
videoElement.addEventListener('loadedmetadata', setPipButton);
videoElement.addEventListener('emptied', setPipButton);
} else {
// Hide button if Picture-in-Picture is not supported.
pipButtonElement.hidden = true;
}
function setPipButton() {
pipButtonElement.disabled =
videoElement.readyState === 0 ||
!document.pictureInPictureEnabled ||
videoElement.disablePictureInPicture;
}
Compatibilité vidéo avec MediaStream
Une vidéo lit des objets MediaStream (par exemple, getUserMedia()
, getDisplayMedia()
,
canvas.captureStream()
) sont également compatibles avec le Picture-in-picture dans Chrome 71. Ce
signifie que vous pouvez afficher une fenêtre Picture-in-picture
qui contient la webcam de l'utilisateur
un flux vidéo display, un flux vidéo display ou même un élément de canevas. Notez que
l'élément vidéo n'a pas besoin d'être associé au DOM
Picture-in-picture comme indiqué ci-dessous.
Afficher la webcam de l'utilisateur dans la fenêtre Picture-in-picture
const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getUserMedia({video: true});
video.play();
// Later on, video.requestPictureInPicture();
Afficher l'affichage dans la fenêtre Picture-in-picture
const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getDisplayMedia({video: true});
video.play();
// Later on, video.requestPictureInPicture();
Afficher l'élément canevas dans la fenêtre Picture-in-picture
const canvas = document.createElement('canvas');
// Draw something to canvas.
canvas.getContext('2d').fillRect(0, 0, canvas.width, canvas.height);
const video = document.createElement('video');
video.muted = true;
video.srcObject = canvas.captureStream();
video.play();
// Later on, video.requestPictureInPicture();
En combinant canvas.captureStream()
avec l'API Media Session, vous pouvez :
créer une fenêtre de playlist audio
dans Chrome 74. Consultez la version officielle
Exemple de playlist audio.
Exemples, démonstrations et ateliers de programmation
Consultez notre exemple officiel Picture-in-picture pour essayer la fonctionnalité Picture-in-picture API Web.
Des démonstrations et des ateliers de programmation suivront.
Étapes suivantes
Tout d'abord, consultez la page d'état de l'implémentation pour savoir quelles parties sont actuellement implémentées dans Chrome et d'autres navigateurs.
Voici ce qui vous attend prochainement:
- Les développeurs Web peuvent ajouter des commandes Picture-in-picture personnalisées.
- Une nouvelle API Web sera fournie pour afficher des objets
HTMLElement
arbitraires dans une fenêtre flottante.
Prise en charge des navigateurs
L'API Web Picture-in-picture est compatible avec Chrome, Edge, Opera et Safari. Pour en savoir plus, consultez la page MDN.
Ressources
- État des fonctionnalités Chrome: https://www.chromestatus.com/feature/5729206566649856
- Bugs d'implémentation dans Chrome: https://crbug.com/?q=component:Blink>Media>PictureInPicture
- Spécification de l'API Web Picture-in-picture: https://wicg.github.io/picture-in-picture
- Problèmes de spécifications: https://github.com/WICG/picture-in-picture/issues
- Exemple: https://googlechrome.github.io/samples/picture-in-picture/
- Polyfill Picture-in-picture non officiel: https://github.com/gbentaieb/pip-polyfill/
Un grand merci à Mounir Lamouri et Jennifer Apacible pour leur travail sur Picture-in-picture, puis consultez cet article. Et un grand merci à tous impliquées dans l'effort de normalisation.