Mira el video con la función Pantalla en pantalla

François Beaufort
François Beaufort

La función pantalla en pantalla (PIP) permite que los usuarios miren videos en una ventana flotante (siempre encima de otras ventanas) para que puedan vigilar lo que están mirar mientras interactúa con otros sitios o aplicaciones.

Con la API web de pantalla en pantalla, puedes iniciar y controlar Pantalla en pantalla para los elementos de video de tu sitio web. Pruébala en nuestro Ejemplo de pantalla en pantalla oficial.

Información general

En septiembre de 2016, Safari agregó compatibilidad con pantalla en pantalla a través de una API de WebKit. en macOS Sierra. Seis meses después, Chrome reprodujo automáticamente Video pantalla en pantalla en un dispositivo móvil con el lanzamiento de Android O con un API nativa de Android. Seis meses después, anunciamos nuestra intención de crear y una API web, una función compatible con Safari, que le permitiría desarrolladores para crear y controlar la experiencia completa en torno a la función pantalla en pantalla. ¡Y aquí estamos!

Ingresar al código

Ingresa al modo de pantalla en pantalla

Empecemos simplemente con un elemento de video y una forma para que el usuario interactúe con él, como un elemento de botón.

<video id="videoElement" src="https://example.com/file.mp4"></video>
<button id="pipButtonElement"></button>

Solo debes solicitar la función Pantalla en pantalla en respuesta a un gesto del usuario, y nunca en el Promise que muestra videoElement.play(). Esto se debe a que las promesas no aún propagan gestos del usuario. En su lugar, llama a requestPictureInPicture() en un y haz clic en el controlador en pipButtonElement, como se muestra a continuación. Es tu responsabilidad para controlar lo que ocurre si un usuario hace dos clics.

pipButtonElement.addEventListener('click', async function () {
  pipButtonElement.disabled = true;

  await videoElement.requestPictureInPicture();

  pipButtonElement.disabled = false;
});

Cuando se resuelve la promesa, Chrome reduce el video a una ventana pequeña que el usuario puede desplazarse y colocarse sobre otras ventanas.

Eso es todo. ¡Bien hecho! Puedes dejar de leer y llevarte tu merecido contenido vacaciones. Lamentablemente, no siempre es así. La promesa puede rechazar por cualquier por los siguientes motivos:

  • El sistema no admite la función de pantalla en pantalla.
  • No se permite usar la función Pantalla en pantalla en el documento debido a una restricción política de permisos.
  • Aún no se cargaron los metadatos del video (videoElement.readyState === 0).
  • El archivo de video es solo de audio.
  • El nuevo atributo disablePictureInPicture está presente en el elemento de video.
  • La llamada no se realizó en un controlador de eventos de gestos del usuario (p.ej., un clic en un botón). A partir de Chrome 74, esto solo se aplica si no hay un elemento en Ya se habilitó la función pantalla en pantalla.

La sección Compatibilidad con funciones que aparece a continuación muestra cómo habilitar o inhabilitar un botón según las estas restricciones.

Agreguemos un bloque try...catch para capturar estos posibles errores y dejar que la el usuario sepa lo que está sucediendo.

pipButtonElement.addEventListener('click', async function () {
  pipButtonElement.disabled = true;

  try {
    await videoElement.requestPictureInPicture();
  } catch (error) {
    // TODO: Show error message to user.
  } finally {
    pipButtonElement.disabled = false;
  }
});

El elemento de video se comporta de la misma manera ya sea en pantalla en pantalla o no: se activan los eventos y funcionan los métodos de llamada. Refleja los cambios de estado en la ventana de Pantalla en pantalla (como reproducir, pausar, saltar, etc.), y también posible cambiar el estado de forma programática en JavaScript.

Salir del modo de pantalla en pantalla

Ahora, hagamos que nuestro botón entre y salga del modo de pantalla en pantalla. Mié primero debes comprobar si el objeto de solo lectura document.pictureInPictureElement es nuestro elemento de video. Si no es así, enviaremos una solicitud para ingresar Pantalla en pantalla como se muestra arriba. De lo contrario, te pediremos que te vayas llamando document.exitPictureInPicture(), lo que significa que el video volverá a aparecer en la pestaña original. Ten en cuenta que este método también muestra una promesa.

    ...
    try {
      if (videoElement !== document.pictureInPictureElement) {
        await videoElement.requestPictureInPicture();
      } else {
        await document.exitPictureInPicture();
      }
    }
    ...

Escucha eventos de pantalla en pantalla

Los sistemas operativos suelen restringir la función pantalla en pantalla a una sola ventana, por La implementación de Chrome sigue este patrón. Esto significa que los usuarios solo pueden jugar un video de pantalla en pantalla a la vez. Los usuarios deberían cerrar Pantalla en pantalla, incluso cuando no la habías solicitado.

Los nuevos controladores de eventos enterpictureinpicture y leavepictureinpicture permiten personalizar la experiencia de los usuarios. Podría ser cualquier cosa, desde explorar un hasta un catálogo de videos o un chat en vivo.

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.
});

Personaliza la ventana de pantalla en pantalla

Chrome 74 admite los botones de reproducción/pausa, pista anterior y pista siguiente en el Ventana de pantalla en pantalla que puedes controlar mediante la API de Media Session.

Controles de reproducción multimedia en una ventana de pantalla en pantalla
Figura 1: Controles de reproducción multimedia en una ventana de pantalla en pantalla

De forma predeterminada, siempre se muestra un botón de reproducción/pausa en la función Pantalla en pantalla a menos que el video reproduzca objetos MediaStream (por ejemplo, getUserMedia(), getDisplayMedia(), canvas.captureStream()) o el video tiene una MediaSource la duración establecida en +Infinity (p.ej., feed en vivo). Para asegurarse de que haya un botón de reproducción/pausa siempre está visible, configura somesee controladores de acción de sesiones multimedia para "Play". y "Pausa" eventos multimedia como se muestra a continuación.

// 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.
});

Se muestra "Pista anterior" y “Siguiente pista” controles de ventana es similar. Parámetro de configuración Los controladores de acciones de la sesión multimedia para esos controladores los mostrarán en el modo de pantalla en pantalla. y podrás controlar estas acciones.

navigator.mediaSession.setActionHandler('previoustrack', function () {
  // User clicked "Previous Track" button.
});

navigator.mediaSession.setActionHandler('nexttrack', function () {
  // User clicked "Next Track" button.
});

Para ver esto en acción, prueba el ejemplo oficial de las sesiones multimedia.

Obtén el tamaño de la ventana de pantalla en pantalla

Si quieres ajustar la calidad del video cuando este entra y sale Pantalla en pantalla, debes conocer el tamaño de la ventana de pantalla en pantalla y notificaciones si un usuario cambia manualmente el tamaño de la ventana.

En el siguiente ejemplo, se muestra cómo obtener el ancho y la altura de la Ventana de pantalla en pantalla cuando se crea o se cambia su tamaño.

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.
}

Te sugiero que no te encajes directamente con el evento de cambio de tamaño, ya que se realiza cada pequeño cambio. al tamaño de la ventana de Pantalla en pantalla activará un evento independiente que podría problemas de rendimiento si realizas una operación costosa en cada cambio de tamaño. En otras palabras, la operación de cambio de tamaño activará los eventos una y otra vez, con rapidez. Recomendaría utilizar técnicas comunes, como regulación y de rebote para solucionar este problema.

Compatibilidad de características

Es posible que la API web de pantalla en pantalla no sea compatible, por lo que debes detectar esta para proporcionar una mejora progresiva. Incluso cuando es compatible, puede ser desactivados por el usuario o inhabilitados por una política de permisos Por suerte, puedes usar el nuevo valor booleano document.pictureInPictureEnabled para determinar esto.

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.');
}

Aplicado a un elemento de botón específico de un video, así es como te recomendamos controlar la visibilidad del botón de pantalla en pantalla.

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;
}

Compatibilidad con videos de MediaStream

Objetos MediaStream que se reproducen de video (p.ej., getUserMedia(), getDisplayMedia(), canvas.captureStream()) también admiten la función Pantalla en pantalla en Chrome 71. Esta significa que puedes mostrar una ventana de pantalla en pantalla que contenga la cámara web del usuario transmisión de video por Internet en pantalla, transmisión de video por Internet en pantalla o, incluso, un elemento de lienzo. Ten en cuenta que no es necesario adjuntar un elemento de video al DOM para ingresar Pantalla en pantalla como se muestra a continuación.

Mostrar la cámara web del usuario en la ventana de pantalla en pantalla

const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getUserMedia({video: true});
video.play();

// Later on, video.requestPictureInPicture();

Mostrar la pantalla en la ventana de pantalla en pantalla

const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getDisplayMedia({video: true});
video.play();

// Later on, video.requestPictureInPicture();

Mostrar el elemento de lienzo en la ventana de pantalla en pantalla

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();

Si combinas canvas.captureStream() con la API de Media Session, podrás crear una ventana de playlist de audio en Chrome 74. Mira el video oficial Muestra de una playlist de audio.

Playlist de audio en una ventana de pantalla en pantalla
Figura 2: Playlist de audio en una ventana de pantalla en pantalla

Ejemplos, demostraciones y codelabs

Consulta nuestra muestra oficial de pantalla en pantalla para probar la función pantalla en pantalla API web.

A continuación, se presentan demostraciones y codelabs.

¿Qué sigue?

Primero, consulta la página de estado de implementación para saber qué partes de Actualmente, la API está implementada en Chrome y otros navegadores.

Esto es lo que puedes esperar próximamente:

Navegadores compatibles

La API web de pantalla en pantalla es compatible con Chrome, Edge, Opera y Safari. Consulta MDN para obtener más detalles.

Recursos

Muchas gracias a Mounir Lamouri y Jennifer Apacible por su trabajo en pantalla en pantalla y ayúdanos con este artículo. Muchas gracias a todos que participan en el esfuerzo de estandarización.