Signatur
Beschreibung
Die Methode seekToNextFrame() springt in einem <video>- oder <audio>-Element genau einen Frame weiter. Sie ist für Anwendungen gedacht, die ein Video Bild für Bild durchgehen: Schnitt- und Annotationswerkzeuge, Sportanalyse, Bewegungsstudien oder das Auslesen einzelner Frames in ein <canvas>.
Die Suche läuft asynchron. Beim Aufruf wird currentTime auf den Zeitpunkt des nächsten Frames gesetzt, danach feuern wie bei einer normalen Suche die Ereignisse seeking und seeked. Das zurückgegebene Promise wird erfüllt, sobald der neue Frame dekodiert und angezeigt ist. Erst danach sollte man den Frame weiterverarbeiten, etwa mit drawImage() auf ein Canvas zeichnen.
Gegenüber dem Setzen von currentTime um 1 / Bildrate hat die Methode einen Vorteil: Die Bildrate muss nicht bekannt sein. Auch Videos mit variabler Bildrate (VFR) werden korrekt Frame für Frame durchlaufen, ohne dass Frames übersprungen oder doppelt angezeigt werden.
Achtung: Die Methode steht in keinem Standard, gilt als veraltet und wurde nur von Firefox umgesetzt. Im Produktivcode sollte man immer zuerst prüfen, ob sie verfügbar ist, und einen Ersatzweg einbauen.
Rückgabewert
Promise, das erfüllt wird, sobald der nächste Frame angezeigt ist. Schlägt die Suche fehl (z. B. weil das Medium nicht durchsuchbar ist oder noch keine Daten geladen sind), wird es abgelehnt.Beispiele
Einen Frame weiterspringen (mit Verfügbarkeitsprüfung)
const video = document.querySelector('video');
const nextBtn = document.querySelector('#next-frame');
nextBtn.addEventListener('click', async () => {
video.pause();
if (typeof video.seekToNextFrame === 'function') {
await video.seekToNextFrame();
} else {
// Ersatzweg: feste Bildrate annehmen (hier 25 fps)
video.currentTime = Math.min(video.duration, video.currentTime + 1 / 25);
}
console.log(`Aktuelle Position: ${video.currentTime.toFixed(3)} s`);
});
Alle Frames eines Videos in ein Canvas auslesen
const video = document.querySelector('video');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const extractFrames = async (maxFrames = 50) => {
await new Promise((resolve) => {
if (video.readyState >= 2) resolve();
else video.addEventListener('loadeddata', resolve, { once: true });
});
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const frames = [];
for (let i = 0; i < maxFrames && !video.ended; i++) {
ctx.drawImage(video, 0, 0);
frames.push(canvas.toDataURL('image/jpeg', 0.8));
await video.seekToNextFrame();
}
return frames;
};
extractFrames().then((frames) => console.log(`${frames.length} Frames extrahiert`));
Fehlerbehandlung beim Frame-Sprung
const video = document.querySelector('video');
const stepFrame = async () => {
try {
await video.seekToNextFrame();
console.log('Neuer Frame bei', video.currentTime);
} catch (err) {
console.error('Frame-Sprung fehlgeschlagen:', err.name);
}
};
video.addEventListener('seeked', () => console.log('seeked ausgelöst'));
stepFrame();
// Wichtig · Fallstricke
- Nicht standardisiert und veraltet: Nur Firefox hat die Methode umgesetzt. Chrome, Edge und Safari kennen sie nicht. Vor dem Aufruf deshalb immer mit
typeof video.seekToNextFrame === 'function'prüfen. - Moderne Alternativen:
HTMLVideoElement.requestVideoFrameCallback()meldet jeden dargestellten Frame mit genauem Zeitstempel (mediaTime). Wer Frames genau verarbeiten will, greift zur WebCodecs-API (VideoDecoder,VideoFrame). - Ohne Frame-Metadaten ist der Ersatzweg über
currentTime += 1 / fpsungenau. Bei variabler Bildrate oder Rundungsfehlern können Frames übersprungen werden. - Vor dem Aufruf sollte
readyStatemindestensHAVE_CURRENT_DATA(2) sein. Sonst kann dasPromiseabgelehnt werden oder erst spät erfüllt werden. - Den nächsten Aufruf erst starten, wenn das vorherige
Promiseerfüllt ist. Mehrere Aufrufe gleichzeitig können sich gegenseitig abbrechen. - Beim Auslesen von Frames in ein Canvas gilt die Same-Origin-Regel: Videos von fremden Domains ohne passende CORS-Header (
crossorigin-Attribut) machen das Canvas „tainted“, undtoDataURL()wirft dann einenSecurityError.