Start · Sprachen · JavaScript · Referenz · HTMLMediaElement.captureStream()

HTMLMediaElement.captureStream()

Methode

Gibt einen <code>MediaStream</code> zurück, der in Echtzeit das Bild und den Ton liefert, die gerade in einem <code>&lt;video&gt;</code>- oder <code>&lt;audio&gt;</code>-Element abgespielt werden.

seit JavaScript Chrome/Edge 62+, Opera 49+; Firefox nur mit Präfix Kategorie: webapi

Signatur

HTMLMediaElement.prototype.captureStream()

Beschreibung

captureStream() macht aus einem <video>- oder <audio>-Element eine Live-Quelle. Die Methode gibt ein MediaStream-Objekt zurück, dessen Spuren (MediaStreamTrack) genau das enthalten, was das Element gerade wiedergibt. Wie die Medien ins Element gelangt sind, spielt keine Rolle: Das kann eine Datei-URL sein, ein MediaSource-Puffer oder ein anderer MediaStream über srcObject.

Typische Einsatzfälle:

  • Aufnehmen einer laufenden Wiedergabe mit MediaRecorder, z. B. um einen Ausschnitt als WebM zu speichern.
  • Weitergeben eines Videos an eine WebRTC-Verbindung (RTCPeerConnection.addTrack()), etwa um gemeinsam einen Film zu schauen oder eine Datei in ein Gespräch einzuspielen.
  • Weiterverarbeiten des Tons über die Web Audio API (AudioContext.createMediaStreamSource()) oder des Bildes über ein weiteres <video>- oder Canvas-Element.

Der Stream ist an den Zustand des Elements gekoppelt. Pausiert das Element, kommen keine neuen Bilder und kein Ton mehr an. Wechselt die Quelle (src) oder ändern sich die verfügbaren Spuren, werden Spuren im Stream hinzugefügt oder entfernt. Diese Änderungen lassen sich mit den Ereignissen addtrack und removetrack am MediaStream verfolgen. Direkt nach dem Aufruf kann der Stream noch leer sein, wenn die Metadaten des Mediums noch nicht geladen sind.

Rückgabewert

Typ
MediaStream
Beschreibung
Ein MediaStream mit je einer Video- und/oder Audiospur, passend zu den Spuren, die das Element gerade abspielt. Bei mehreren Aufrufen entstehen jeweils neue, voneinander unabhängige Streams.

Beispiele

Wiedergabe mit MediaRecorder aufnehmen

const video = document.querySelector('#player');

const recordClip = async (durationMs = 5000) => {
  await video.play();
  const stream = video.captureStream();
  const recorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
  const chunks = [];

  recorder.addEventListener('dataavailable', (e) => chunks.push(e.data));

  const stopped = new Promise((resolve) =>
    recorder.addEventListener('stop', resolve, { once: true })
  );

  recorder.start();
  setTimeout(() => recorder.stop(), durationMs);
  await stopped;

  const blob = new Blob(chunks, { type: 'video/webm' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = 'ausschnitt.webm';
  a.click();
  console.log(`Aufnahme fertig: ${blob.size} Bytes`);
};

document.querySelector('#rec').addEventListener('click', () => recordClip());
Aufnahme fertig: 1234567 Bytes

Unterstützung prüfen, Firefox-Präfix als Ersatz

const getElementStream = (media) => {
  if (typeof media.captureStream === 'function') {
    return media.captureStream();
  }
  if (typeof media.mozCaptureStream === 'function') {
    // Firefox: Präfix-Variante
    return media.mozCaptureStream();
  }
  throw new Error('captureStream() wird in diesem Browser nicht unterstützt');
};

const video = document.querySelector('video');
video.addEventListener('loadedmetadata', () => {
  const stream = getElementStream(video);
  console.log(stream.getTracks().map((t) => t.kind));
}, { once: true });
["audio", "video"]

Lokales Video an eine WebRTC-Verbindung senden

const video = document.querySelector('#film');
const pc = new RTCPeerConnection();

const shareVideo = async () => {
  await video.play();
  const stream = video.captureStream();

  // Spuren, die schon da sind
  stream.getTracks().forEach((track) => pc.addTrack(track, stream));

  // Spuren, die später dazukommen (z. B. nach einem Quellwechsel)
  stream.addEventListener('addtrack', ({ track }) => {
    console.log('Neue Spur:', track.kind);
    pc.addTrack(track, stream);
  });

  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  // offer anschließend über den Signalisierungskanal verschicken
};

shareVideo();
Neue Spur: audio

Ton an die Web Audio API übergeben

const audio = document.querySelector('audio');
const ctx = new AudioContext();

audio.addEventListener('play', async () => {
  await ctx.resume();
  const source = ctx.createMediaStreamSource(audio.captureStream());
  const analyser = ctx.createAnalyser();
  source.connect(analyser);

  const data = new Uint8Array(analyser.frequencyBinCount);
  setInterval(() => {
    analyser.getByteFrequencyData(data);
    console.log('Pegel:', Math.max(...data));
  }, 1000);
}, { once: true });
Pegel: 187

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chromium-Browser unterstützen die Methode ohne Präfix. Firefox bietet sie lange nur als mozCaptureStream() (dazu mozCaptureStreamUntilEnded()) an. Dort wird der Ton je nach Version in den Stream umgeleitet und nicht mehr über die Lautsprecher ausgegeben. Safari unterstützt captureStream() an Medienelementen nicht; HTMLCanvasElement.captureStream() funktioniert dort dagegen. Ob die Methode verfügbar ist, deshalb immer vorher prüfen.
  • Medien von fremden Ursprüngen (Cross-Origin): Stammt die Quelle von einem anderen Ursprung und ist sie nicht per CORS freigegeben (crossorigin-Attribut plus passender Access-Control-Allow-Origin-Header), wirft Chrome einen NotSupportedError. Andere Browser liefern stumme oder schwarze Spuren. So wird verhindert, dass fremde Inhalte unbemerkt abgegriffen werden.
  • DRM-Inhalte (Encrypted Media Extensions) lassen sich nicht aufnehmen. Der Aufruf schlägt fehl oder liefert leere Spuren.
  • Timing: Vor loadedmetadata hat der Stream oft noch keine Spuren. Auf addtrack reagieren oder erst nach dem Laden der Metadaten aufrufen.
  • Pausieren: Pausiert das Element, liefert der Stream keine neuen Bilder mehr. Ein laufender MediaRecorder nimmt dann ein stehendes Bild oder Stille auf.
  • Speicher und Ressourcen: Nicht mehr benötigte Spuren mit track.stop() beenden. Erzeugte Objekt-URLs mit URL.revokeObjectURL() wieder freigeben.