Signatur
Beschreibung
Die schreibgeschützte Eigenschaft writable eines MediaStreamTrackGenerator gibt einen WritableStream zurück. Jeder Chunk, den du in diesen Stream schreibst, wird als neues Medien-Frame der Spur ausgegeben. Der Generator selbst ist ein MediaStreamTrack und lässt sich deshalb überall einsetzen, wo eine Spur erwartet wird: in einem <video>-Element über srcObject, in einer RTCPeerConnection oder im MediaRecorder.
Welcher Typ von Chunk erwartet wird, hängt von kind ab, das beim Erzeugen angegeben wurde: Bei "video" sind es VideoFrame-Objekte, bei "audio" AudioData-Objekte. Werden falsche Typen geschrieben, wird der Schreibvorgang mit einem TypeError abgewiesen.
Typischerweise nutzt man writable zusammen mit MediaStreamTrackProcessor („Insertable Streams for MediaStreamTrack“): Der Prozessor liefert die Frames einer Kamera-Spur als ReadableStream, ein TransformStream verändert sie (z. B. Filter, Hintergrundunschärfe, Wasserzeichen), und das Ergebnis wird per pipeThrough()/pipeTo() in generator.writable geleitet. Genauso können Frames komplett synthetisch erzeugt werden, etwa aus einem Canvas oder aus WebCodecs-Dekodern.
Rückgabewert
WritableStream, dessen Chunks als Frames der generierten Spur ausgegeben werden. Es wird immer dasselbe Stream-Objekt zurückgegeben.Beispiele
Kamerabild in Graustufen umwandeln (Pipeline)
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const processor = new MediaStreamTrackProcessor({ track });
const generator = new MediaStreamTrackGenerator({ kind: 'video' });
const canvas = new OffscreenCanvas(1, 1);
const ctx = canvas.getContext('2d');
const grayscale = new TransformStream({
transform(frame, controller) {
canvas.width = frame.displayWidth;
canvas.height = frame.displayHeight;
ctx.filter = 'grayscale(1)';
ctx.drawImage(frame, 0, 0);
const newFrame = new VideoFrame(canvas, { timestamp: frame.timestamp });
frame.close(); // Original freigeben!
controller.enqueue(newFrame);
}
});
processor.readable
.pipeThrough(grayscale)
.pipeTo(generator.writable)
.catch((err) => console.error('Pipeline abgebrochen:', err));
document.querySelector('video').srcObject = new MediaStream([generator]);
Synthetische Frames direkt mit einem Writer schreiben
const generator = new MediaStreamTrackGenerator({ kind: 'video' });
const writer = generator.writable.getWriter();
const canvas = new OffscreenCanvas(320, 180);
const ctx = canvas.getContext('2d');
let n = 0;
const timer = setInterval(async () => {
ctx.fillStyle = `hsl(${(n * 5) % 360} 80% 50%)`;
ctx.fillRect(0, 0, 320, 180);
ctx.fillStyle = '#fff';
ctx.font = '32px sans-serif';
ctx.fillText(`Frame ${n}`, 20, 100);
const frame = new VideoFrame(canvas, { timestamp: n * 33_333 });
await writer.write(frame);
frame.close();
n++;
}, 33);
document.querySelector('video').srcObject = new MediaStream([generator]);
console.log(generator.readyState);
Stream beenden und Spur schließen
const generator = new MediaStreamTrackGenerator({ kind: 'audio' });
const writer = generator.writable.getWriter();
generator.addEventListener('ended', () => console.log('Spur beendet'));
// ... AudioData-Objekte schreiben ...
await writer.close(); // beendet die Spur
console.log(generator.readyState);
// Wichtig · Fallstricke
- Kompatibilität:
MediaStreamTrackGeneratorist nicht standardisiert und nur in Chromium-Browsern verfügbar. Die W3C-Spezifikation sieht stattdessenVideoTrackGenerator(nur Video, nur in Workern, mit Eigenschafttrack) vor – Safari unterstützt diese Variante. Immer per Feature-Detection prüfen:'MediaStreamTrackGenerator' in self. - Speicher:
VideoFrame/AudioDatabelegen oft GPU- oder Hardware-Ressourcen. Frames, die du nicht weiterreichst, musst du mitclose()freigeben, sonst stockt die Kamera oder der Speicher läuft voll. - Sperre: Nach
getWriter()oderpipeTo()ist der Stream gesperrt; ein zweiter Writer wirft einenTypeError, bisreleaseLock()aufgerufen wurde. - Beenden:
close()oderabort()am Stream beendet die Spur (readyStatewird"ended"); umgekehrt schlagen Schreibvorgänge nachgenerator.stop()fehl. - Zeitstempel (
timestampin Mikrosekunden) sollten monoton steigen, damit Wiedergabe und Encoder korrekt arbeiten.