Videoaufnahme des Nutzers

Mat Scales

Viele Browser können jetzt auf Video- und Audioeingaben des Nutzers zugreifen. Je nach Browser kann es sich jedoch um eine vollständig dynamische und Inline-Funktion handeln oder die Funktion kann an eine andere App auf dem Gerät des Nutzers delegiert werden.

Einfach und schrittweise beginnen

Am einfachsten ist es, den Nutzer um eine vorab aufgezeichnete Datei zu bitten. Erstelle dazu ein einfaches Dateieingabeelement und füge einen accept-Filter hinzu, der angibt, dass nur Videodateien akzeptiert werden, sowie ein capture-Attribut, das angibt, dass die Datei direkt von der Kamera stammen soll.

<input type="file" accept="video/*" capture />

Diese Methode funktioniert auf allen Plattformen. Auf dem Computer wird der Nutzer aufgefordert, eine Datei aus dem Dateisystem hochzuladen. Das Attribut capture wird dabei ignoriert. In Safari unter iOS wird die Kamera-App geöffnet, mit der Sie ein Video aufnehmen und dann an die Webseite zurücksenden können. Unter Android kann der Nutzer auswählen, mit welcher App das Video aufgenommen werden soll, bevor es an die Webseite zurückgesendet wird.

Viele Mobilgeräte haben mehr als eine Kamera. Wenn du eine Präferenz hast, kannst du das Attribut capture auf user festlegen, wenn du die Kamera verwenden möchtest, die auf den Nutzer gerichtet ist, oder auf environment, wenn du die Kamera verwenden möchtest, die nach außen gerichtet ist.

<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />

Beachte, dass dies nur ein Hinweis ist. Wenn der Browser die Option nicht unterstützt oder der gewünschte Kameratyp nicht verfügbar ist, kann der Browser eine andere Kamera auswählen.

Sobald der Nutzer die Aufnahme beendet hat und wieder auf der Website ist, müssen Sie die Dateidaten irgendwie abrufen. Sie können schnell darauf zugreifen, indem Sie ein onchange-Ereignis an das Eingabeelement anhängen und dann das files-Attribut des Ereignisobjekts lesen.

<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
  var recorder = document.getElementById('recorder');
  var player = document.getElementById('player');

  recorder.addEventListener('change', function (e) {
    var file = e.target.files[0];
    // Do something with the video file.
    player.src = URL.createObjectURL(file);
  });
</script>

Sobald Sie Zugriff auf die Datei haben, können Sie damit machen, was Sie wollen. Beispielsweise können Sie…

  • Hängen Sie es direkt an ein <video>-Element an, damit Sie es abspielen können.
  • Laden Sie die App auf das Gerät des Nutzers herunter.
  • Laden Sie sie auf einen Server hoch, indem Sie sie an eine XMLHttpRequest anhängen.
  • Frames in einen Canvas zeichnen und Filter darauf anwenden

Die Methode, über das Eingabeelement auf Videodaten zuzugreifen, ist zwar weit verbreitet, aber die am wenigsten attraktive Option. Wir möchten Zugriff auf die Kamera erhalten und direkt auf der Seite eine gute Nutzererfahrung bieten.

Interaktiv auf die Kamera zugreifen

Moderne Browser können eine direkte Verbindung zur Kamera herstellen, sodass wir Erlebnisse entwickeln können, die vollständig in die Webseite integriert sind und bei denen der Nutzer den Browser nie verlässt.

Zugriff auf die Kamera erhalten

Wir können direkt auf die Kamera zugreifen, indem wir eine API in der WebRTC-Spezifikation namens getUserMedia() verwenden. getUserMedia() fordert den Nutzer auf, den Zugriff auf seine verbundenen Mikrofone und Kameras zu gewähren.

Wenn die Anfrage erfolgreich ist, gibt die API einen Stream zurück, der die Daten von der Kamera oder dem Mikrofon enthält. Diese können dann entweder an ein <video>-Element oder einen WebRTC-Stream angehängt oder mit der MediaRecorder API gespeichert werden.

Um Daten von der Kamera zu erhalten, setzen wir einfach video: true im Einschränkungsobjekt, das an die getUserMedia() API übergeben wird.

<video id="player" controls></video>
<script>
  var player = document.getElementById('player');

  var handleSuccess = function (stream) {
    player.srcObject = stream;
  };

  navigator.mediaDevices
    .getUserMedia({audio: true, video: true})
    .then(handleSuccess);
</script>

Wenn Sie eine bestimmte Kamera auswählen möchten, können Sie zuerst die verfügbaren Kameras auflisten.

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices = devices.filter((d) => d.kind === 'videoinput');
});

Anschließend kannst du die gewünschte deviceId übergeben, wenn du getUserMedia aufrufst.

navigator.mediaDevices.getUserMedia({
  audio: true,
  video: {
    deviceId: devices[0].deviceId,
  },
});

Für sich genommen ist das nicht besonders nützlich. Wir können die Videodaten nur abrufen und wiedergeben.

Zugriff auf die Rohdaten der Kamera

Wenn Sie auf die Rohvideodaten der Kamera zugreifen möchten, können Sie jeden Frame in ein <canvas>-Element zeichnen und die Pixel direkt bearbeiten.

Für ein 2D-Canvas können Sie die Methode drawImage des Kontexts verwenden, um den aktuellen Frame eines <video>-Elements in das Canvas zu zeichnen.

context.drawImage(myVideoElement, 0, 0);

Mit einem WebGL-Canvas können Sie ein <video>-Element als Quelle für eine Textur verwenden.

gl.texImage2D(
  gl.TEXTURE_2D,
  0,
  gl.RGBA,
  gl.RGBA,
  gl.UNSIGNED_BYTE,
  myVideoElement,
);

In beiden Fällen wird der aktuelle Frame eines wiedergegebenen Videos verwendet. Wenn Sie mehrere Frames verarbeiten möchten, müssen Sie das Video jedes Mal neu auf dem Canvas zeichnen.

Weitere Informationen dazu finden Sie in unserem Artikel zum Anwenden von Echtzeiteffekten auf Bilder und Videos.

Daten von der Kamera speichern

Am einfachsten lassen sich die Daten der Kamera mit der MediaRecorder API speichern.

Die MediaRecorder API übernimmt den von getUserMedia erstellten Stream und speichert die Daten aus dem Stream dann schrittweise am gewünschten Ziel.

<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
  let shouldStop = false;
  let stopped = false;
  const downloadLink = document.getElementById('download');
  const stopButton = document.getElementById('stop');

  stopButton.addEventListener('click', function() {
    shouldStop = true;
  })

  var handleSuccess = function(stream) {
    const options = {mimeType: 'video/webm'};
    const recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);

    mediaRecorder.addEventListener('dataavailable', function(e) {
      if (e.data.size > 0) {
        recordedChunks.push(e.data);
      }

      if(shouldStop === true && stopped === false) {
        mediaRecorder.stop();
        stopped = true;
      }
    });

    mediaRecorder.addEventListener('stop', function() {
      downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
      downloadLink.download = 'acetest.webm';
    });

    mediaRecorder.start();
  };

  navigator.mediaDevices.getUserMedia({ audio: true, video: true })
      .then(handleSuccess);
</script>

In unserem Fall speichern wir die Daten direkt in einem Array, das wir später in ein Blob-Objekt umwandeln können. Dieses kann dann auf unserem Webserver oder direkt im Speicher des Nutzergeräts gespeichert werden.

Berechtigung zur verantwortungsvollen Nutzung der Kamera anfordern

Wenn der Nutzer Ihrer Website zuvor keinen Zugriff auf die Kamera gewährt hat, wird er beim Aufruf von getUserMedia vom Browser aufgefordert, Ihrer Website die Berechtigung für die Kamera zu erteilen.

Nutzer hassen es, wenn sie aufgefordert werden, den Zugriff auf leistungsstarke Geräte auf ihrem Computer zu gewähren. Sie blockieren die Anfrage häufig oder ignorieren sie, wenn sie den Kontext nicht verstehen, in dem die Aufforderung erstellt wurde. Es empfiehlt sich, erst dann nach dem Zugriff auf die Kamera zu fragen, wenn er benötigt wird. Sobald der Nutzer den Zugriff gewährt hat, wird er nicht noch einmal gefragt. Wenn er den Zugriff jedoch ablehnt, können Sie nicht noch einmal auf die Berechtigung des Nutzers zugreifen.

Mit der Permissions API prüfen, ob Sie bereits Zugriff haben

Die getUserMedia API gibt keine Auskunft darüber, ob du bereits Zugriff auf die Kamera hast. Das stellt Sie vor ein Problem: Um eine ansprechende Benutzeroberfläche zu bieten, über die der Nutzer Ihnen Zugriff auf die Kamera gewährt, müssen Sie Zugriff auf die Kamera anfordern.

In einigen Browsern kann dieses Problem mithilfe der Permission API gelöst werden. Mit der navigator.permission API kannst du den Status der Zugriffsmöglichkeit auf bestimmte APIs abfragen, ohne noch einmal nachfragen zu müssen.

Wenn du prüfen möchtest, ob du Zugriff auf die Kamera des Nutzers hast, kannst du {name: 'camera'} an die Abfragemethode übergeben. Es wird dann einer der folgenden Werte zurückgegeben:

  • granted: Der Nutzer hat Ihnen zuvor Zugriff auf die Kamera gewährt.
  • prompt: Der Nutzer hat dir keinen Zugriff gewährt und wird aufgefordert, dies zu tun, wenn du getUserMedia aufrufst.
  • denied: Das System oder der Nutzer hat den Zugriff auf die Kamera explizit blockiert und Sie können nicht darauf zugreifen.

Sie können jetzt schnell prüfen, ob Sie die Benutzeroberfläche anpassen müssen, um die Aktionen zu ermöglichen, die der Nutzer ausführen muss.

navigator.permissions.query({name: 'camera'}).then(function (result) {
  if (result.state == 'granted') {
  } else if (result.state == 'prompt') {
  } else if (result.state == 'denied') {
  }
  result.onchange = function () {};
});

Feedback