requestVideoFrameCallback() ile videoda video karesi başına verimli işlemler gerçekleştirin

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

Tarayıcı Desteği

  • 83
  • 83
  • x
  • 15,4

Kaynak

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.