requestVideoFrameCallback() की मदद से, हर वीडियो फ़्रेम के हिसाब से बेहतर कार्रवाइयां करें

ब्राउज़र में वीडियो के साथ ज़्यादा बेहतर ढंग से काम करने के लिए, requestVideoFrameCallback() का इस्तेमाल करने का तरीका जानें.

HTMLVideoElement.requestVideoFrameCallback() तरीके की मदद से, वेब लेखक एक कॉलबैक रजिस्टर कर सकते हैं. यह कॉलबैक, कंपोजिटर को नया वीडियो फ़्रेम भेजे जाने पर, रेंडरिंग के चरणों में चलता है. इससे डेवलपर, वीडियो के हर फ़्रेम पर बेहतर तरीके से काम कर सकते हैं. जैसे, वीडियो को प्रोसेस करना और कैनवस पर पेंट करना, वीडियो का विश्लेषण करना या बाहरी ऑडियो सोर्स के साथ सिंक करना.

इस एपीआई का इस्तेमाल करके, कैनवस पर वीडियो फ़्रेम को ड्रॉ करने जैसे काम, स्क्रीन पर चल रहे वीडियो के फ़्रेम रेट के साथ सिंक किए जाएंगे. यह window.requestAnimationFrame() से अलग होता है, जो आम तौर पर हर सेकंड में करीब 60 बार फ़ायर होता है. requestVideoFrameCallback(), वीडियो का फ़्रेम रेट तय करता है. हालांकि, इसमें एक अहम अपवाद होता है:

कॉलबैक जिस दर पर चलाए जाते हैं वह वीडियो की दर और ब्राउज़र की दर के बीच की कम दर होती है. इसका मतलब है कि 60 हर्ट्ज़ पर पेंट करने वाले ब्राउज़र में 25 एफ़पीएस (फ़्रेम प्रति सेकंड) में चलने वाला वीडियो, 25 हर्ट्ज़ पर कॉलबैक ट्रिगर होगा. उसी 60 हर्ट्ज़ वाले ब्राउज़र में 120 एफ़पीएस (फ़्रेम प्रति सेकंड) वाला वीडियो, 60 हर्ट्ज़ पर कॉलबैक ट्रिगर करेगा.

साइटमैप को क्या नाम दिया जाना चाहिए?

window.requestAnimationFrame() से मिलती-जुलती होने की वजह से, शुरुआत में इस तरीके को video.requestAnimationFrame() के तौर पर सुझाया गया था और इसका नाम बदलकर requestVideoFrameCallback() किया गया. हालांकि, लंबी चर्चा के बाद इस पर सहमति मिली.

फ़ीचर का पता लगाना

if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
  // The API is supported!
}

ब्राउज़र समर्थन

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 83.
  • Edge: 83.
  • Firefox: 132.
  • Safari: 15.4.

सोर्स

पॉलीफ़िल

Window.requestAnimationFrame() और HTMLVideoElement.getVideoPlaybackQuality() के आधार पर, requestVideoFrameCallback() तरीके के लिए पॉलीफ़िल उपलब्ध है. इसका इस्तेमाल करने से पहले, README में बताई गई सीमाओं के बारे में जानें.

requestVideoFrameCallback() तरीके का इस्तेमाल करना

अगर आपने कभी requestAnimationFrame() तरीके का इस्तेमाल किया है, तो आपको requestVideoFrameCallback() तरीके के बारे में तुरंत पता चल जाएगा. शुरुआती कॉलबैक को एक बार रजिस्टर किया जाता है. इसके बाद, जब भी कॉलबैक ट्रिगर होता है, तो उसे फिर से रजिस्टर किया जाता है.

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);

कॉलबैक में, now एक DOMHighResTimeStamp और metadata एक VideoFrameMetadata डायक्शनरी है. इसमें ये प्रॉपर्टी होती हैं:

  • presentationTime, का DOMHighResTimeStamp प्रकार: वह समय जब उपयोगकर्ता एजेंट ने कंपोज़िशन के लिए फ़्रेम सबमिट किया.
  • expectedDisplayTime, DOMHighResTimeStamp टाइप का: वह समय जब उपयोगकर्ता एजेंट को फ़्रेम दिखने की उम्मीद होती है.
  • width, unsigned long टाइप: मीडिया पिक्सल में वीडियो फ़्रेम की चौड़ाई.
  • height, टाइप unsigned long: मीडिया पिक्सल में वीडियो फ़्रेम की ऊंचाई.
  • mediaTime, टाइप double: दिखाए गए फ़्रेम का मीडिया प्रज़ेंटेशन टाइमस्टैंप (पीटीएस) सेकंड में. उदाहरण के लिए, video.currentTime टाइमलाइन पर इसका टाइमस्टैंप.
  • presentedFrames, unsigned long टाइप का: कॉम्पोज़िशन के लिए सबमिट किए गए फ़्रेम की संख्या. इससे क्लाइंट यह तय कर सकते हैं कि VideoFrameRequestCallback के इंस्टेंस के बीच फ़्रेम छूटे हैं या नहीं.
  • processingDuration, टाइप double: डिकोडर में इस फ़्रेम (उदाहरण के लिए, mediaTime जैसा) के प्रज़ेंटेशन टाइमस्टैंप (पीटीएस) के साथ एन्कोड किए गए पैकेट को सबमिट करने से लेकर, डिकोड किया गया फ़्रेम प्रज़ेंटेशन के लिए तैयार होने तक बीता समय, सेकंड में.

WebRTC ऐप्लिकेशन के लिए, अन्य प्रॉपर्टी दिख सकती हैं:

  • captureTime, टाइप DOMHighResTimeStamp: लोकल या रिमोट सोर्स से आने वाले वीडियो फ़्रेम के लिए, यह वह समय होता है जब कैमरे ने फ़्रेम कैप्चर किया था. रिमोट सोर्स के लिए, कैप्चर करने के समय का अनुमान क्लॉक सिंक करने और आरटीसीपी सेंडर रिपोर्ट का इस्तेमाल करके लगाया जाता है, ताकि समय कैप्चर करने के लिए आरटीपी टाइमस्टैंप को बदला जा सके.
  • receiveTime, टाइप DOMHighResTimeStamp: रिमोट सोर्स से आने वाले वीडियो फ़्रेम के लिए, यह वह समय होता है जब प्लैटफ़ॉर्म को एन्कोड किया गया फ़्रेम मिलता है. इसका मतलब है कि यह वह समय होता है जब नेटवर्क पर इस फ़्रेम से जुड़ा आखिरी पैकेट मिलता है.
  • rtpTimestamp, टाइप unsigned long: इस वीडियो फ़्रेम से जुड़ा आरटीपी टाइमस्टैंप.

इस सूची में, दर्शकों की दिलचस्पी mediaTime है. Chromium में, ऑडियो क्लॉक का इस्तेमाल video.currentTime के लिए टाइम सोर्स के तौर पर किया जाता है, जबकि mediaTime को सीधे फ़्रेम के presentationTimestamp से पॉप्युलेट किया जाता है. अगर आपको फिर से बनाए जा सकने वाले तरीके से फ़्रेम की सटीक पहचान करनी है, तो mediaTime का इस्तेमाल करें. इसमें यह भी शामिल है कि कौनसे फ़्रेम छूट गए.

अगर आपको लगता है कि वीडियो एक फ़्रेम पीछे चल रहा है, तो…

वर्टिकल सिंक (या सिर्फ़ vsync), एक ऐसी ग्राफ़िक्स टेक्नोलॉजी है जो वीडियो के फ़्रेम रेट और मॉनिटर के रीफ़्रेश रेट को सिंक करती है. requestVideoFrameCallback() मुख्य थ्रेड पर चलता है, लेकिन वीडियो कॉम्पोज़ करने की प्रोसेस, कॉम्पोज़र थ्रेड पर होती है. इसलिए, इस एपीआई से मिलने वाली हर चीज़ को बेहतर बनाने की पूरी कोशिश की जाती है. हालांकि, ब्राउज़र इसकी कोई गारंटी नहीं देता. समस्या यह हो सकती है कि वीडियो फ़्रेम रेंडर होने के समय, एपीआई को एक vsync देरी से हो सकता है. एपीआई की मदद से वेब पेज में किए गए बदलावों को स्क्रीन पर दिखने में एक vsync लगता है (जैसा कि window.requestAnimationFrame() में होता है). इसलिए, अगर अपने वेब पेज पर mediaTime या फ़्रेम नंबर को अपडेट करते रहते हैं और उसकी तुलना नंबर वाले वीडियो फ़्रेम से करते हैं, तो वीडियो एक फ़्रेम आगे दिखेगा.

असल में, फ़्रेम vsync x पर तैयार होता है, कॉलबैक ट्रिगर होता है, और फ़्रेम vsync x+1 पर रेंडर होता है. साथ ही, कॉलबैक में किए गए बदलाव vsync x+2 पर रेंडर होते हैं. यह पता लगाया जा सकता है कि कॉलबैक, वीएसीपी (वाइड स्क्रीन ऐनिमेशन कंट्रोल पैरामीटर) के बाद हुआ है या नहीं. साथ ही, यह भी पता लगाया जा सकता है कि फ़्रेम पहले से ही स्क्रीन पर रेंडर हो चुका है या नहीं. इसके लिए, यह देखें कि metadata.expectedDisplayTime, now के आस-पास है या आने वाले समय में एक वीएसीपी है. अगर यह now के करीब पांच से दस माइक्रोसेकंड में है, तो फ़्रेम पहले ही रेंडर हो जाता है; अगर expectedDisplayTime आने वाले समय में करीब सोलह मिलीसेकंड का है (यह मानते हुए कि आपका ब्राउज़र/स्क्रीन 60 हर्ट्ज़ पर रीफ़्रेश हो रहा है), तो फ़्रेम के साथ सिंक हो जाएगा.

डेमो

मैंने Glitch पर एक छोटा डेमो बनाया है. इसमें दिखाया गया है कि वीडियो के फ़्रेम रेट के हिसाब से, कैनवस पर फ़्रेम कैसे बनाए जाते हैं. साथ ही, यह भी बताया गया है कि डीबग करने के लिए, फ़्रेम का मेटाडेटा कहां लॉग किया जाता है.

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);

मीटिंग में सामने आए नतीजे

लोग फ़्रेम-लेवल पर प्रोसेसिंग का इस्तेमाल लंबे समय से कर रहे हैं. इसके लिए, असल फ़्रेम का ऐक्सेस नहीं होना ज़रूरी है. यह प्रोसेस सिर्फ़ video.currentTime के आधार पर की जाती है. requestVideoFrameCallback() का तरीका, इस समस्या को हल करने का बेहतर तरीका है.

स्वीकार की गई

requestVideoFrameCallback एपीआई को थॉमस गिलबर्ट ने तय और लागू किया था. इस पोस्ट की समीक्षा जो मेडली और केइस बास्केस ने की है. Unsplash पर डेनिस जॉन्स की हीरो इमेज.