با () requestVideoFrameCallback، عملیات کارآمد در هر فریم ویدیو را روی ویدیو انجام دهید.

بیاموزید که چگونه از requestVideoFrameCallback() برای کار موثرتر با ویدیوهای موجود در مرورگر استفاده کنید.

متد HTMLVideoElement.requestVideoFrameCallback() به نویسندگان وب اجازه می دهد تا زمانی که یک فریم ویدیویی جدید به کامپوزیتور ارسال می شود، یک فراخوانی را ثبت کنند که در مراحل رندر اجرا می شود. این به توسعه‌دهندگان اجازه می‌دهد تا عملیات کارآمدی را برای هر فریم ویدیو روی ویدیو انجام دهند، مانند پردازش ویدیو و نقاشی روی بوم، تجزیه و تحلیل ویدیو، یا همگام‌سازی با منابع صوتی خارجی.

عملیاتی مانند کشیدن یک فریم ویدیو بر روی بوم با استفاده از drawImage() ساخته شده از طریق این API به عنوان بهترین تلاش با نرخ فریم ویدیویی که روی صفحه پخش می شود همگام می شود. متفاوت از window.requestAnimationFrame() ، که معمولاً حدود 60 بار در ثانیه شلیک می شود ، requestVideoFrameCallback() به نرخ فریم واقعی ویدیو محدود می شود - با یک استثنا مهم:

نرخ موثری که با آن تماس‌های برگشتی اجرا می‌شوند، نرخ کمتری بین نرخ ویدیو و نرخ مرورگر است. این به این معنی است که یک ویدیو با سرعت 25 فریم در ثانیه در مرورگری که با فرکانس 60 هرتز پخش می‌شود، با فرکانس 25 هرتز پاسخ تماس می‌گیرد. یک ویدیوی 120 فریم بر ثانیه در همان مرورگر 60 هرتزی، پاسخ تماس‌ها را با فرکانس 60 هرتز انجام می‌دهد.

در یک نام چیست؟

به دلیل شباهت آن با window.requestAnimationFrame() ، این روش در ابتدا به عنوان video.requestAnimationFrame() پیشنهاد شد و به requestVideoFrameCallback() تغییر نام داد که پس از یک بحث طولانی با آن موافقت شد.

تشخیص ویژگی

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

پشتیبانی از مرورگر

پشتیبانی مرورگر

  • کروم: 83.
  • لبه: 83.
  • فایرفاکس: 132.
  • سافاری: 15.4.

منبع

پلی پر

یک polyfill برای متد requestVideoFrameCallback() بر اساس Window.requestAnimationFrame() و HTMLVideoElement.getVideoPlaybackQuality() موجود است. قبل از استفاده از این، از محدودیت های ذکر شده در 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);

در callback، now یک DOMHighResTimeStamp است و metadata یک فرهنگ لغت VideoFrameMetadata با ویژگی های زیر است:

  • presentationTime ، از نوع DOMHighResTimeStamp : زمانی که عامل کاربر فریم را برای ترکیب ارسال کرد.
  • expectedDisplayTime ، از نوع DOMHighResTimeStamp : زمانی که عامل کاربر انتظار دارد فریم قابل مشاهده باشد.
  • width , از نوع unsigned long : عرض فریم ویدیو بر حسب پیکسل رسانه.
  • height ، از نوع unsigned long : ارتفاع فریم ویدیو، بر حسب پیکسل رسانه.
  • mediaTime ، از نوع double : مهر زمانی ارائه رسانه (PTS) در ثانیه از فریم ارائه شده (به عنوان مثال، مهر زمانی آن در جدول زمانی video.currentTime ).
  • presentedFrames ، از نوع unsigned long : شمارش تعداد فریم های ارسال شده برای ترکیب. به کلاینت‌ها اجازه می‌دهد تعیین کنند که آیا فریم‌ها بین نمونه‌های VideoFrameRequestCallback از دست رفته است یا خیر.
  • processingDuration از نوع double : مدت زمان سپری شده بر حسب ثانیه از ارسال بسته رمزگذاری شده با همان مهر زمان ارائه (PTS) مانند این فریم (مثلاً همان mediaTime ) به رمزگشا تا زمانی که فریم رمزگشایی شده برای ارائه آماده شود.

برای برنامه های WebRTC، ممکن است ویژگی های اضافی ظاهر شود:

  • captureTime ، از نوع DOMHighResTimeStamp : برای فریم های ویدیویی که از منبع محلی یا راه دور می آیند، این زمانی است که در آن قاب توسط دوربین گرفته شده است. برای یک منبع راه دور، زمان ضبط با استفاده از همگام‌سازی ساعت و گزارش‌های فرستنده RTCP برای تبدیل مهرهای زمانی RTP به زمان تصویربرداری تخمین زده می‌شود.
  • receiveTime از نوع DOMHighResTimeStamp : برای فریم های ویدئویی که از منبع راه دور می آیند، این زمانی است که فریم کدگذاری شده توسط پلتفرم دریافت می شود، یعنی زمانی که آخرین بسته متعلق به این فریم از طریق شبکه دریافت می شود.
  • rtpTimestamp ، از نوع unsigned long : مهر زمانی RTP مرتبط با این فریم ویدیویی.

مورد توجه ویژه در این لیست mediaTime است. پیاده‌سازی Chromium از ساعت صوتی به‌عنوان منبع زمانی استفاده می‌کند که از video.currentTime پشتیبانی می‌کند، در حالی که mediaTime مستقیماً با نشان presentationTimestamp قاب پر می‌شود. اگر می‌خواهید دقیقاً فریم‌ها را به روشی تکرارپذیر شناسایی کنید، از جمله شناسایی دقیق فریم‌هایی که از دست داده‌اید، باید از mediaTime استفاده کنید.

اگر همه چیز یک فریم به نظر می رسد…

همگام سازی عمودی (یا فقط vsync)، یک فناوری گرافیکی است که نرخ فریم یک ویدیو و نرخ تازه سازی یک مانیتور را همگام می کند. از آنجایی که requestVideoFrameCallback() روی رشته اصلی اجرا می‌شود، اما در زیر پوشش، ترکیب ویدیو در رشته ترکیب‌کننده اتفاق می‌افتد، همه چیز از این API بهترین تلاش است و مرورگر هیچ ضمانت دقیقی ارائه نمی‌دهد. چیزی که ممکن است اتفاق بیفتد این است که API می تواند نسبت به زمانی که یک فریم ویدیو رندر می شود یک vsync کند. یک vsync طول می کشد تا تغییرات ایجاد شده در صفحه وب از طریق API روی صفحه نمایش داده شود (همانند window.requestAnimationFrame() ). بنابراین اگر مدام mediaTime یا شماره فریم را در صفحه وب خود به روز کنید و آن را با فریم های ویدیویی شماره گذاری شده مقایسه کنید، در نهایت ویدیو به نظر می رسد که یک فریم جلوتر است.

چیزی که واقعاً اتفاق می افتد این است که فریم در vsync x آماده است، callback فعال می شود و فریم در vsync x+1 رندر می شود و تغییرات ایجاد شده در callback در vsync x+2 رندر می شود. با بررسی اینکه آیا metadata.expectedDisplayTime تقریباً now است یا یک vsync در آینده، می‌توانید بررسی کنید که آیا تماس برگشتی با تأخیر vsync است (و فریم قبلاً روی صفحه نمایش داده شده است). اگر در حدود پنج تا ده میکروثانیه از 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() تا حد زیادی این راه حل را بهبود می بخشد.

قدردانی ها

API requestVideoFrameCallback توسط Thomas Guilbert مشخص و اجرا شد. این پست توسط Joe Medley و Kayce Basques بازبینی شده است. تصویر قهرمان توسط Denise Jans در Unsplash.