Blokta tanımlanan yeni bir Web API’si var. HTMLVideoElement.requestVideoFrameCallback()
Şartname. bu requestVideoFrameCallback()
yöntem, web yazarlarının, oluşturucuya yeni bir video karesi gönderildiğinde işleme adımlarında çalışan bir geri arama kaydetmesine olanak tanır. Bunun amacı, geliştiricilerin video işleme ve bir tuvale boyama, video analizi veya harici ses kaynaklarıyla senkronizasyon gibi video üzerinde verimli video karesi başına işlemler gerçekleştirmesine olanak tanımaktır.
requestAnimationFrame() ile fark #
Bir kanvasa video karesi çizmek gibi işlemler drawImage()
Bu API aracılığıyla yapılan, ekranda oynatılan videonun kare hızıyla en iyi şekilde senkronize edilecektir. Dan farklı window.requestAnimationFrame()
genellikle saniyede yaklaşık 60 kez ateşleyen, requestVideoFrameCallback()
gerçek video kare hızına bağlıdır—önemli bir istisna:
Geri aramaların çalıştırıldığı etkili oran, videonun oranı ile tarayıcının oranı arasındaki daha düşük orandır. Bu, 60 Hz’de resim yapan bir tarayıcıda oynatılan 25 fps’lik bir videonun 25 Hz’de geri aramaları tetikleyeceği anlamına gelir. Aynı 60Hz tarayıcıdaki 120 fps video, 60Hz’de geri aramaları başlatır.
İsim nedir? #
ile benzerliği nedeniyle window.requestAnimationFrame()
yöntem başlangıçta olarak önerildi video.requestAnimationFrame()
ama yeni ismimden memnunum, requestVideoFrameCallback()
bir süre sonra üzerinde anlaşmaya varılan uzun tartışma. Yay, bisiklet sürme kazanmak için!
Özellik algılama #
if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
// The API is supported!
}
tarayıcı desteği #
- Chrome 83, Desteklenir 83
- Firefox, desteklenmiyor
- Kenar 83, Desteklenen 83
- Safari 15.4, Desteklenir 15.4
çoklu dolgu #
A için çoklu dolgu requestVideoFrameCallback()
yöntem dayalı Window.requestAnimationFrame()
Ve HTMLVideoElement.getVideoPlaybackQuality()
gecerli. Bunu kullanmadan önce şunlara dikkat edin: belirtilen sınırlamalar README
.
requestVideoFrameCallback() yöntemini kullanma #
Daha önce kullandıysanız requestAnimationFrame()
yöntemi ile kendinizi hemen evinizde hissedeceksiniz. requestVideoFrameCallback()
yöntem. Bir ilk geri aramayı bir kez kaydedersiniz ve ardından geri arama her tetiklendiğinde yeniden kayıt olursunuz.
const doSomethingWithTheFrame = (now, metadata) => {
// Do something with the frame.
console.log(now, metadata);
// Re-register the callback to be notified about the next frame.
video.requestVideoFrameCallback(doSomethingWithTheFrame);
};
// Initially register the callback to be notified about the first frame.
video.requestVideoFrameCallback(doSomethingWithTheFrame);
Geri aramada, now
bir DOMHighResTimeStamp
Ve metadata
bir VideoFrameMetadata
aşağıdaki özelliklere sahip sözlük:
presentationTime
türDOMHighResTimeStamp
: Kullanıcı aracısının kompozisyon için çerçeveyi gönderdiği saat.expectedDisplayTime
türDOMHighResTimeStamp
: Kullanıcı aracısının çerçevenin görünür olmasını beklediği zaman.width
türunsigned long
: Medya piksel cinsinden video çerçevesinin genişliği.height
türunsigned long
: Medya piksel cinsinden video karesinin yüksekliği.mediaTime
türdouble
: Sunulan çerçevenin saniye cinsinden medya sunumu zaman damgası (PTS) (örn.video.currentTime
zaman çizelgesi).presentedFrames
türunsigned long
: Kompozisyon için gönderilen çerçeve sayısı. İstemcilerin, örnekleri arasında çerçevelerin kaçırılıp kaçırılmadığını belirlemesine izin verir.VideoFrameRequestCallback
.processingDuration
türdouble
: Bu çerçeveyle aynı sunum zaman damgasına (PTS) sahip kodlanmış paketin gönderilmesinden itibaren saniye cinsinden geçen süre (örn.mediaTime
) kodu çözülmüş çerçeve sunum için hazır olana kadar kod çözücüye.
WebRTC uygulamaları için ek özellikler görünebilir:
captureTime
türDOMHighResTimeStamp
: Yerel veya uzak bir kaynaktan gelen video kareleri için bu, karenin kamera tarafından yakalandığı zamandır. Uzak bir kaynak için, yakalama süresi, yakalama süresine RTP zaman damgalarını dönüştürmek için saat senkronizasyonu ve RTCP gönderen raporları kullanılarak tahmin edilir.receiveTime
türDOMHighResTimeStamp
: Uzak bir kaynaktan gelen video çerçeveleri için bu, kodlanmış çerçevenin platform tarafından alındığı zamandır, yani bu çerçeveye ait son paketin ağ üzerinden alındığı zamandır.rtpTimestamp
türunsigned long
: Bu video karesiyle ilişkili RTP zaman damgası.
Bu listede özel ilgi mediaTime
. Chromium’un uygulamasında, ses saatini destekleyen zaman kaynağı olarak kullanıyoruz. video.currentTime
oysa mediaTime
tarafından doğrudan doldurulur presentationTimestamp
çerçevenin. bu mediaTime
tam olarak hangi kareleri kaçırdığınızı belirlemek de dahil olmak üzere kareleri tekrarlanabilir bir şekilde tam olarak belirlemek istiyorsanız kullanmanız gereken şey budur.
Olaylar bir kare yanlış görünüyorsa… #
Dikey senkronizasyon (veya sadece vsync), bir videonun kare hızı ile monitörün yenileme hızını senkronize eden bir grafik teknolojisidir. O zamandan beri requestVideoFrameCallback()
ana iş parçacığında çalışır, ancak arka planda video birleştirme, birleştirici iş parçacığında gerçekleşir, bu API’deki her şey en iyi çabadır ve herhangi bir kesin garanti sunmuyoruz. Olan şey, API’nin bir video karesi oluşturulduğunda göreli olarak bir vsync geç olabilmesidir. API aracılığıyla web sayfasında yapılan değişikliklerin ekranda görünmesi için bir vsync gerekir (aynı window.requestAnimationFrame()
). Yani güncellemeye devam ederseniz mediaTime
veya web sayfanızdaki kare numarası ve bunu numaralı video kareleriyle karşılaştırın, sonunda video bir kare öndeymiş gibi görünecektir.
Gerçekte olan şey, çerçevenin vsync x’te hazır olması, geri aramanın başlatılması ve çerçevenin vsync x+1’de işlenmesi ve geri aramada yapılan değişikliklerin vsync x+2’de işlenmesidir. Geri aramanın bir vsync gecikmesi olup olmadığını (ve çerçevenin zaten ekranda görüntülenip görüntülenmediğini) kontrol edebilirsiniz. metadata.expectedDisplayTime
kabaca now
veya gelecekte bir vsync. Yaklaşık beş ila on mikrosaniye içindeyse now
, çerçeve zaten oluşturulmuştur; Eğer expectedDisplayTime
gelecekte yaklaşık on altı milisaniye ise (tarayıcınızın/ekranınızın 60 Hz’de yenilendiğini varsayarsak), o zaman çerçeve ile senkronize olursunuz.
Demo #
küçük oluşturdum Glitch’te demo bu, çerçevelerin tam olarak videonun kare hızında tuval üzerine nasıl çizildiğini ve hata ayıklama amacıyla çerçeve meta verilerinin nerede kaydedildiğini gösterir. Temel mantık, yalnızca birkaç satır JavaScript’tir.
let paintCount = 0;
let startTime = 0.0;const updateCanvas = (now, metadata) => {
if (startTime === 0.0) {
startTime = now;
}
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const elapsed = (now - startTime) / 1000.0;
const fps = (++paintCount / elapsed).toFixed(3);
fpsInfo.innerText = `video fps: ${fps}`;
metadataInfo.innerText = JSON.stringify(metadata, null, 2);
video.requestVideoFrameCallback(updateCanvas);
};
video.requestVideoFrameCallback(updateCanvas);
Sonuçlar #
Uzun bir süre çerçeve düzeyinde işleme yaptım—gerçek çerçevelere erişimim olmadan, yalnızca video.currentTime
. JavaScript’te video çekimi segmentasyonunu kabaca ve hazır bir şekilde uyguladım; hala ekteki okuyabilirsiniz Araştırma kağıdı. Vardı requestVideoFrameCallback()
o zamanlar olsaydı hayatım çok daha basit olurdu…
teşekkürler #
bu requestVideoFrameCallback
API tarafından belirlendi ve uygulandı Thomas Guilbert. Bu makale tarafından incelendi Joe Karışık Ve Kayce Baskları. Kahraman resmi ile Denise Jans Unsplash’ta.