Tarayıcıda videolarla daha verimli bir şekilde çalışmak için requestVideoFrameCallback()
kullanmayı öğrenin.
HTMLVideoElement.requestVideoFrameCallback()
yöntemi, web yazarlarının birleştiriciye yeni bir video karesi gönderildiğinde oluşturma adımlarında çalışan bir geri çağırma kaydetmesine olanak tanır.
Bu, geliştiricilerin video üzerinde video işleme ve tuvale boyama, video analizi veya harici ses kaynaklarıyla senkronizasyon gibi etkili video karesi başına işlemler gerçekleştirmesine olanak tanır.
requestAnimationFrame() ile fark
Bu API üzerinden drawImage()
kullanarak tuvale video karesi çizme gibi işlemler, ekranda oynatılan videonun kare hızıyla mümkün olduğunca senkronize edilir.
Genellikle saniyede yaklaşık 60 kez tetiklenen window.requestAnimationFrame()
'ten farklı olarak requestVideoFrameCallback()
, önemli bir istisna dışında gerçek video kare hızına bağlıdır:
Geri çağırmaların etkin olduğu hız, videonun hızı ile tarayıcının hızı arasındaki daha düşük değerdir. Bu, 60 Hz'de boyanan bir tarayıcıda oynatılan 25 fps videonun 25 Hz'de geri çağırmaları tetikleyeceği anlamına gelir. Aynı 60 Hz tarayıcıda 120 fps'lik bir video 60 Hz'de geri çağırmaları tetikler.
Adın önemi var mı?
Yöntem, window.requestAnimationFrame()
ile benzerliğinden dolayı başlangıçta video.requestAnimationFrame()
olarak önerilmiş ve uzun bir tartışmanın ardından üzerinde anlaşılan requestVideoFrameCallback()
olarak yeniden adlandırılmıştır.
Özellik algılama
if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
// The API is supported!
}
Tarayıcı desteği
Polyester Lifi
Window.requestAnimationFrame()
ve HTMLVideoElement.getVideoPlaybackQuality()
temel alınarak requestVideoFrameCallback()
yöntemi için bir çoklu dolgu kullanılabilir. Bunu kullanmadan önce README
dokümanında belirtilen sınırlamalar hakkında bilgi edinin.
requestVideoFrameCallback() yöntemini kullanma
Daha önce requestAnimationFrame()
yöntemini kullandıysanız requestVideoFrameCallback()
yöntemine hemen aşina olacaksınız.
İlk geri çağırmayı bir kez kaydedersiniz. Geri arama her tetiklendiğinde yeniden kaydedersiniz.
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 çağırmada now
DOMHighResTimeStamp
, metadata
ise aşağıdaki özelliklere sahip VideoFrameMetadata
sözlüktür:
presentationTime
,DOMHighResTimeStamp
türü: Kullanıcı aracısının beste için çerçeveyi gönderdiği zaman.expectedDisplayTime
, türüDOMHighResTimeStamp
: Kullanıcı aracısının, karenin görünür olmasını beklediği zaman.width
,unsigned long
türünde: Video karesinin medya pikseli olarak genişliği.height
, türüunsigned long
: Video karesinin medya pikseli cinsinden yüksekliği.mediaTime
, türüdouble
: Sunulan karenin saniye cinsinden medya sunumu zaman damgası (PTS) (ör.video.currentTime
zaman çizelgesindeki zaman damgası).presentedFrames
,unsigned long
türünde: Beste için gönderilen kare sayısı. İstemcilerin,VideoFrameRequestCallback
örnekleri arasında karelerin eksik olup olmadığını belirlemesine olanak tanır.processingDuration
, türüdouble
: Bu çerçeveyle aynı sunum zaman damgasına (PTS) sahip kodlanmış paketin (ör.mediaTime
ile aynı) kod çözücüye gönderilmesinden sonra kodu çözülmüş kare sunum için hazır olana kadar geçen saniye cinsinden geçen süre.
WebRTC uygulamaları için ek özellikler görünebilir:
captureTime
,DOMHighResTimeStamp
türü: Yerel veya uzak kaynaktan gelen video kareleri için bu, karenin kamera tarafından yakalandığı zamandır. Uzak bir kaynakta, RTP zaman damgalarını yakalama zamanına dönüştürmek için saat senkronizasyonu ve RTCP gönderen raporları kullanılarak yakalama süresi tahmin edilir.receiveTime
,DOMHighResTimeStamp
türünde: Uzak bir kaynaktan gelen video kareleri için kodlanmış karenin platform tarafından alındığı, diğer bir deyişle bu kareye ait son paketin ağ üzerinden alındığı zamandır.rtpTimestamp
, türüunsigned long
: Bu video çerçevesiyle ilişkili RTP zaman damgası.
Bu listede özellikle mediaTime
önemli bir yere sahip.
Chromium'un uygulamasında, video.currentTime
yedeğini geri alan zaman kaynağı olarak ses saati kullanılır, mediaTime
ise doğrudan karenin presentationTimestamp
kısmı tarafından doldurulur.
Kareleri tekrarlanabilir bir şekilde tam olarak tanımlamak ve kaçırdığınız kareleri tam olarak belirlemek için mediaTime
kullanmalısınız.
Görüntüler bir kare eksik gibi görünüyorsa
Dikey senkronizasyon (veya kısaca vsync), videonun kare hızını ve monitörün yenileme hızını senkronize eden bir grafik teknolojisidir.
requestVideoFrameCallback()
ana iş parçacığında çalıştırıldığı ancak, arka planda video birleştirme işlemi birleştirici iş parçacığında gerçekleştiğinden, bu API'deki her şey en iyi çabayı gösterir ve tarayıcı kesin garantiler vermez.
API, video karesinin oluşturulma zamanına göre bir vsync gecikmesi olabilir.
API aracılığıyla web sayfasında yapılan değişikliklerin ekranda görünmesi için bir vsync gerekir (window.requestAnimationFrame()
ile aynı).
Bu nedenle web sayfanızdaki mediaTime
veya kare numarasını güncellemeye devam eder ve bunu numaralı video kareleriyle karşılaştırırsanız sonunda video bir kare ilerideymiş gibi görünür.
Aslında, çerçeve vsync x'te hazırdır, geri çağırma tetiklenir ve çerçeve vsync x+1 konumunda oluşturulur ve geri çağırmada yapılan değişiklikler vsync x+2 konumunda oluşturulur.
metadata.expectedDisplayTime
öğesinin yaklaşık olarak now
veya gelecekte bir vsync olup olmadığını kontrol ederek geri çağırmanın bir vsync gecikmesi olup olmadığını (ve karenin ekranda zaten oluşturulup oluşturulmadığını) kontrol edebilirsiniz.
now
yaklaşık beş ila on mikrosaniye içindeyse çerçeve zaten oluşturulmuştur. expectedDisplayTime
değeri gelecekte yaklaşık on altı milisaniye sonraysa (tarayıcınızın/ekranınızın 60 Hz hızda yenilendiği varsayılırsa) kareyle senkronizesiniz demektir.
Demografi
Glitch'te, karelerin bir tuvalde tam olarak videonun kare hızında nasıl çizildiğini ve hata ayıklama amacıyla kare meta verilerinin kaydedildiği yeri gösteren küçük bir demo oluşturdum.
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
Kullanıcılar, yalnızca video.currentTime
verilerine dayalı olarak gerçek karelere erişmeden uzun bir süre kare düzeyinde işlem gerçekleştirdi.
requestVideoFrameCallback()
yöntemi, bu geçici çözümü son derece geliştirir.
Teşekkür
requestVideoFrameCallback
API, Thomas Guilbert tarafından belirlenmiş ve uygulanmıştır.
Bu yayın Joe Medley ve Kayce Basques tarafından incelendi.
Denise Jans'ın Unsplash'teki hero resmi.