Fermer

juillet 26, 2024

Générez et partagez des enregistrements d’écran avec l’API Media Capture

Générez et partagez des enregistrements d’écran avec l’API Media Capture


Dans cet article, nous nous concentrerons sur la création d’une application Next.js qui permet l’enregistrement d’écran et enregistre le contenu directement sur l’appareil de l’utilisateur.

L’API Media Capture and Stream fournit aux développeurs Web les interfaces nécessaires pour interagir avec les appareils multimédias de l’utilisateur, notamment la caméra, le microphone et l’écran. Cet article se concentrera sur la création d’une application Next.js qui permet l’enregistrement d’écran et enregistre le contenu directement sur l’appareil de l’utilisateur. Cette fonctionnalité est rendue possible grâce à l’API Screen Capture, une extension de l’API Media Capture and Stream.

Conditions préalables

Pour suivre ce guide, il est nécessaire que vous ayez une compréhension de base de Réagir et Manuscrit.

Configuration du projet

Exécutez la commande ci-dessous pour créer une application Next.js :

npx create-next-app

Dans l’invite ci-dessus, nous avons configuré une application Next.js optimisée par TypeScript qui utilise la plupart des paramètres par défaut du framework ; nous avons choisi d’utiliser Tailwind à des fins de style. L’application réside dans un dossier nommé screen-capture-app.

Capture d'écran du terminal

Démarrez votre application en exécutant la commande ci-dessous :

npm run dev

Nous écrirons toute la logique dans la page racine de notre application, plus précisément dans le app/page.tsx déposer. Puisque nous allons utiliser un état, faisons du composant de ce fichier un composant client en le mettant à jour avec la chaîne « use client », comme ci-dessous.

"use client";
import { useRef, useState } from "react";
export default function Home() {
  return <></>;
}

Comment fonctionne l’enregistrement d’écran

Les étapes ci-dessous expliquent le processus requis pour enregistrer l’écran d’un utilisateur. Au fur et à mesure, nous mettrons à jour le app/page.tsx fichier en créant les variables et les fonctions dont l’application aura besoin. Pour l’instant, passons en revue le déroulement du processus.

Tout d’abord, nous devons demander leur autorisation pour accéder à l’écran de l’utilisateur. Si l’utilisateur nous le permet, nous avons accès à un flux contenant les données vidéo et/ou audio dont nous avons besoin. Pour y parvenir, nous devons conserver une variable pour stocker ce flux et une fonction pour demander l’accès, comme indiqué ci-dessous :

const screenRecordingStream = (useRef < MediaStream) | (null > null);

const requestPermissionFromUserToAccessScreen = async () => {};

Ensuite, le flux nous permet de faire plusieurs choses, notamment la transmission en temps réel sur le réseau via WebRTC vers des consommateurs distants. Dans notre cas, nous utiliserons un enregistreur multimédia pour collecter et stocker les données multimédias du flux.

const recordedData = useRef<Blob[]>([]);
const recorderRef = useRef<MediaRecorder | null>(null);
const collectVideoData = (ev: BlobEvent) => {}

De plus, puisque nous utiliserons un enregistreur multimédia, nous devons créer un booléen qui nous indique si l’utilisateur est en train d’enregistrer son écran. Nous avons également besoin de fonctions pour démarrer et arrêter l’enregistrement.

const [isRecording, setIsRecording] = useState(false);

const startRecording = async () => {};
const stopRecording = async () => {};

Pour afficher le flux sur la page, nous aurons besoin d’une référence à un HTML video étiqueter.

const videoRef = (useRef < HTMLVideoElement) | (null > null);

Une fois que l’utilisateur arrête l’enregistrement, nous pouvons effectuer certaines actions avec les données vidéo. Nous pouvons le télécharger sur un serveur distant ou effectuer un transcodage et un filtrage vidéo sur le navigateur à l’aide d’un outil tel que ffmpeg.wasm, etc. Dans notre cas, nous offrirons à l’utilisateur la possibilité de télécharger le fichier sur son appareil. Pour ce faire, nous allons créer un downloadVideo() fonctionner comme indiqué ci-dessous :

const downloadVideo = () => {};

L’interface utilisateur

Avant de commencer à mettre en œuvre les étapes de la section précédente, examinons l’interface utilisateur et voyons comment l’application fonctionne.

Par défaut, l’application affiche un bouton qui permet à l’utilisateur de démarrer l’enregistrement.

Bouton d'enregistrement d'écran

Lorsque l’utilisateur commence à enregistrer son écran, un bouton est disponible pour arrêter l’enregistrement. Lorsqu’ils s’arrêtent, l’utilisateur voit une lecture vidéo du contenu de la fenêtre ou de l’onglet actuel qu’il a enregistré.

Écran enregistré

Lorsque l’utilisateur arrête l’enregistrement, des boutons lui sont présentés pour télécharger la vidéo enregistrée ou recommencer à enregistrer son écran.

Image montrant les boutons CTA

Dans la déclaration de retour du Home composant, le JSX ressemble à ceci :

export default function Home() {
    const [isRecording, setIsRecording] = useState(false);
    const recordedData = useRef<Blob[]>([]);
    const recorderRef = useRef<MediaRecorder | null>(null);
    const screenRecordingStream = useRef<MediaStream | null>(null);
    const videoRef = useRef<HTMLVideoElement | null>(null);

    const startRecording = async () => {
    };

    const requestPermissionFromUserToAccessScreen = async () => {
    };

    const collectVideoData = (ev: BlobEvent) => {
    };

    const stopRecording = async () => {
    };

    const downloadVideo = () => {
    };

    return (
        <main className='flex flex-col items-center gap-6 justify-center min-h-[100vh]'>
            <div className='mt-8'>
                {isRecording ? (
                    <>
                        <button onClick={stopRecording} className='btn btn-error'>
                            {" "}
                            stop recording
                        </button>
                    </>
                ) : (
                    <div className='flex gap-4 items-center'>
                        <button onClick={startRecording} className='btn btn-active btn-neutral'>
                            record screen
                        </button>
                        {recordedData.current.length ? (
                            <button onClick={downloadVideo} className='btn btn-active btn-neutral'>
                                download video
                            </button>
                        ) : null}
                    </div>
                )}
            </div>
            <video ref={videoRef} width={900} muted></video>
        </main>
    );
}

Accéder au flux de l’écran de l’utilisateur

Encore une fois, tout le code que nous écrirons sera dans le src/page.tsx déposer. Ajoutez ce qui suit au requestPermissionFromUserToAccessScreen fonction:

const requestPermissionFromUserToAccessScreen = async () => {
  const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: {
      noiseSuppression: true,
    },
  });
  screenRecordingStream.current = stream;
  if (videoRef.current) {
    videoRef.current.srcObject = stream;
    videoRef.current.play();
  }
  return stream;
};

Cette fonction utilise la méthode API de capture d’écran appelée getDisplayMedia(). Il est invoqué avec les options demandées que le navigateur doit autoriser pour le flux.

Dans ce cas, nous avons demandé au navigateur de vérifier s’il peut activer la suppression du bruit pour la piste audio et nous fournir la piste vidéo.

Évidemment, le partage d’écran n’est utile que lorsque l’on peut accéder au contenu vidéo. Donc en précisant {video: false} provoquera le getDisplayMedia() appeler à l’échec.

Lors de la définition des contraintes, vous pouvez transmettre des objets aux propriétés vidéo et audio pour affiner votre demande. Par exemple, vous pouvez spécifier la résolution vidéo et le codec, la fréquence d’échantillonnage audio, l’annulation de l’écho, etc. Le navigateur ignorera toute option ingérable ou générera une erreur. Pour plus d’informations, voir les documents.

Quand le getDisplayMedia() La fonction est appelée, une fenêtre contextuelle s’affiche dans le navigateur de l’utilisateur afin qu’il puisse choisir l’onglet ou la fenêtre qu’il souhaite enregistrer.

Popup pour l'enregistrement d'écran

Comme indiqué ci-dessus, il est important de savoir que l’audio n’est disponible que si l’utilisateur choisit de partager un onglet. Tenter de partager une fenêtre ou l’intégralité de l’écran n’inclura pas la piste audio.

Une fois le flux obtenu, il est connecté au video élément HTML à travers son srcObject propriété. Cette connexion rend le rendu video L’élément affiche l’écran que l’utilisateur partage.

Commencer l’enregistrement

L’accès au flux d’un écran utilisateur est distinct du processus d’enregistrement. Pour commencer l’enregistrement, définissons le startRecording() fonction.

const startRecording = async () => {
  const stream = await requestPermissionFromUserToAccessScreen();
  recordedData.current = [];
  recorderRef.current = new MediaRecorder(stream);
  recorderRef.current.addEventListener("dataavailable", collectVideoData);
  recorderRef.current.addEventListener("stop", () => setIsRecording(false));
  recorderRef.current.addEventListener("start", () => setIsRecording(true));
  recorderRef.current.start(100);
};

Après avoir récupéré le flux de l’écran, cette fonction efface d’abord toutes les données vidéo enregistrées préexistantes. Ensuite, il crée une instance de l’enregistreur multimédia et lui alimente le flux. Les trois lignes suivantes associent les écouteurs d’événements à l’enregistreur multimédia.

Le dataavailable l’événement est lié à une fonction appelée collectVideoData(). Cette fonction collecte les morceaux de données blob capturés par l’enregistreur et les stocke dans le recorderRef tableau, comme indiqué ci-dessous :

const collectVideoData = (ev: BlobEvent) => {
  recordedData.current.push(ev.data);
};

Les événements de démarrage et d’arrêt définissent le IsRecording Etat à true ou false. Quand nous appelons le start() méthode de l’instance multimédia, l’enregistrement commence. Bien que cela soit facultatif, nous avons transmis une valeur de 100. Cela signifie que toutes les 100 millisecondes, toutes les données capturées doivent être renvoyées et consommées par le système. collectVideo() rappel, transmis au dataavailable événement mentionné ci-dessus.

Arrête d’enregistrer

Une fois que l’utilisateur arrête l’enregistrement, le stopRecording() la fonction est appelée.

const stopRecording = async () => {
  const recorder = recorderRef.current;
  if (recorder && videoRef.current) {
    recorder.stop();
    screenRecordingStream.current?.getTracks().map((track) => {
      track.stop();
      return;
    });
    videoRef.current.srcObject = null;
  }
};

Cette fonction appelle le stop() sur l’enregistreur multimédia pour arrêter le processus d’enregistrement. Il déconnecte les pistes audio et vidéo de l’écran utilisateur en appelant le stop() méthode sur chaque piste. Cela garantit que notre page Web ne reçoit plus de données audio et vidéo.

Enregistrer l’enregistrement sur l’appareil de l’utilisateur

Lorsque les données enregistrées sont disponibles, l’utilisateur se voit présenter un bouton pour télécharger les données vidéo.

const downloadVideo = () => {
  const videoBlob = new Blob(recordedData.current, {
    type: recordedData.current[0].type,
  });
  const downloadURL = window.URL.createObjectURL(videoBlob);
  downloadFile(downloadURL, "my-video.mkv");
  window.URL.revokeObjectURL(downloadURL);
};

Cette fonction combine tous les morceaux de blob en un seul blob, avec un type MIME équivalent à celui de l’un des plus petits blobs. Ensuite, il crée une référence au blob en appelant le createObjectURL() méthode. Il déclenche alors le downloadFile() fonction, en lui transmettant la référence blob et le nom du fichier téléchargé sur le système de l’utilisateur. Dans ce cas, nous l’avons nommé my-video.mkv.

const downloadFile = async (URL: string, filename: string) => {
  var dlAnchorElem = document.createElement("a");
  document.body.appendChild(dlAnchorElem);
  dlAnchorElem.setAttribute("href", URL);
  dlAnchorElem.setAttribute("download", filename);
  dlAnchorElem.click();
};

Le downloadFile() la fonction crée par programme un code HTML anchor balise qui pointe vers l’URL de référence du blob qui lui est transmise. Il définit l’attribut de téléchargement sur le anchor balise le nom de fichier souhaité, puis déclenche par programme un événement de clic sur le anchor balise pour télécharger le fichier sur l’appareil de l’utilisateur.

Conclusion

Le partage d’écran est important pour améliorer la collaboration et la résolution de problèmes dans divers domaines. Ce guide fournit un moyen simple d’intégrer l’enregistrement d’écran dans nos applications.




Source link