عدد اللقطات في الثانية

تتيح واجهة برمجة التطبيقات الخاصة بمعدّل عرض اللقطات للتطبيقات إبلاغ منصة Android بمعدّل عرض اللقطات المطلوب، وهي متاحة للتطبيقات التي تستهدف الإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. في السابق، كانت معظم الأجهزة تتوافق مع معدّل تحديث واحد فقط للشاشة، وهو عادةً 60 هرتز، ولكن هذا الوضع بدأ يتغيّر. تتيح العديد من الأجهزة الآن معدّلات تحديث إضافية، مثل 90 هرتز أو 120 هرتز. تتيح بعض الأجهزة التبديل السلس لمعدّل التحديث، بينما تعرض أجهزة أخرى شاشة سوداء لفترة وجيزة، تستغرق عادةً ثانية واحدة.

الغرض الأساسي من واجهة برمجة التطبيقات هو تمكين التطبيقات من الاستفادة بشكل أفضل من جميع معدّلات تحديث الشاشة المتوافقة. على سبيل المثال، قد يؤدي تشغيل تطبيق لفيديو بمعدل 24 هرتز يستدعي setFrameRate() إلى تغيير الجهاز لمعدل تحديث الشاشة من 60 هرتز إلى 120 هرتز. يتيح معدّل التحديث الجديد هذا تشغيل الفيديو بمعدّل 24 هرتز بسلاسة وبدون تقطّع، بدون الحاجة إلى عملية تحويل معدّل عرض الإطارات من 24 إلى 60 إطارًا في الثانية، كما هو مطلوب لتشغيل الفيديو نفسه على شاشة بمعدّل 60 هرتز. ويؤدي ذلك إلى تحسين تجربة المستخدم.

الاستخدام الأساسي

يتيح نظام التشغيل Android عدة طرق للوصول إلى الشاشات والتحكّم فيها، لذا تتوفّر عدة إصدارات من واجهة برمجة التطبيقات setFrameRate(). تتلقّى كل نسخة من واجهة برمجة التطبيقات المعلمات نفسها وتعمل بالطريقة نفسها كما هو الحال مع النسخ الأخرى:

ليس على التطبيق مراعاة معدّلات تحديث الشاشة المتوافقة الفعلية، والتي يمكن الحصول عليها من خلال استدعاء Display.getSupportedModes()، وذلك من أجل استدعاء setFrameRate() بأمان. على سبيل المثال، حتى إذا كان الجهاز لا يتوافق إلا مع 60 هرتز، يمكنك استدعاء setFrameRate() مع معدّل اللقطات الذي يفضّله تطبيقك. ستبقى الأجهزة التي لا تتوافق مع معدّل عرض اللقطات في التطبيق على معدّل التحديث الحالي للشاشة.

لمعرفة ما إذا كانت المكالمة إلى setFrameRate() تؤدي إلى تغيير في معدّل إعادة تحميل الشاشة، سجِّل للحصول على إشعارات بتغيير الشاشة من خلال استدعاء DisplayManager.registerDisplayListener() أو AChoreographer_registerRefreshRateCallback().

عند استدعاء setFrameRate()، من الأفضل إدخال معدّل اللقطات الدقيق بدلاً من تقريبه إلى عدد صحيح. على سبيل المثال، عند عرض فيديو تم تسجيله بمعدل 29.97 هرتز، يجب إدخال القيمة 29.97 بدلاً من تقريبها إلى 30.

بالنسبة إلى تطبيقات الفيديو، يجب ضبط مَعلمة التوافق التي يتم تمريرها إلى setFrameRate() على Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE لتقديم تلميح إضافي إلى نظام التشغيل Android بأنّ التطبيق سيستخدم ميزة "السحب للأسفل" للتكيّف مع معدّل تحديث عرض غير متطابق (ما سيؤدي إلى حدوث تقطّع).

في بعض السيناريوهات، ستتوقف مساحة عرض الفيديو عن إرسال اللقطات، ولكنها ستظل مرئية على الشاشة لبعض الوقت. تشمل السيناريوهات الشائعة الحالات التي يصل فيها التشغيل إلى نهاية الفيديو أو عندما يوقف المستخدم التشغيل مؤقتًا. في هذه الحالات، استخدِم الدالة setFrameRate() مع ضبط مَعلمة معدّل عرض اللقطات على 0 لإعادة ضبط معدّل عرض اللقطات للسطح إلى القيمة التلقائية. ليس من الضروري محو إعداد معدّل عرض اللقطات بهذه الطريقة عند إيقاف العرض أو عندما يكون العرض مخفيًا لأنّ المستخدم ينتقل إلى تطبيق آخر. يجب محو إعداد معدّل عرض اللقطات فقط عندما يظل العرض مرئيًا بدون استخدامه.

التبديل غير السلس لعدد اللقطات في الثانية

في بعض الأجهزة، قد يؤدي التبديل بين معدّلات تحديث الشاشة إلى حدوث انقطاعات مرئية، مثل ظهور شاشة سوداء لمدة ثانية أو ثانيتَين. ويحدث ذلك عادةً على أجهزة استقبال البث الرقمي وشاشات التلفزيون والأجهزة المشابهة. لا يغيّر إطار عمل Android الأوضاع تلقائيًا عند استدعاء واجهة برمجة التطبيقات Surface.setFrameRate()، وذلك لتجنُّب حدوث أي انقطاعات مرئية.

يفضّل بعض المستخدمين أن تظهر إعلانات مرئية في بداية الفيديوهات الطويلة ونهايتها. يتيح ذلك مطابقة معدل إعادة التحميل للعرض مع عدد اللقطات في الثانية للفيديو، وتجنُّب تشوّهات تحويل عدد اللقطات في الثانية، مثل تشوّه 3:2 الناتج عن عملية تحويل عدد اللقطات في الثانية عند تشغيل الأفلام.

لهذا السبب، يمكن تفعيل عمليات تبديل معدّل التحديث غير السلسة إذا وافق كل من المستخدم والتطبيقات على ذلك:

ننصحك دائمًا باستخدام CHANGE_FRAME_RATE_ALWAYS للفيديوهات الطويلة، مثل الأفلام. ويرجع ذلك إلى أنّ فائدة مطابقة عدد اللقطات في الثانية للفيديو تفوق الانقطاع الذي يحدث عند تغيير معدّل التحديث.

اقتراحات إضافية

اتّبِع هذه الاقتراحات للسيناريوهات الشائعة.

أسطح متعدّدة

تم تصميم منصة Android للتعامل بشكل صحيح مع السيناريوهات التي تتضمّن عدة مساحات عرض بإعدادات مختلفة لمعدّل عرض اللقطات. عندما يتضمّن تطبيقك عدة مساحات عرض بمعدّلات لقطات مختلفة، استخدِم الدالة setFrameRate() مع معدّل اللقطات الصحيح لكل مساحة عرض. حتى إذا كان الجهاز يشغّل تطبيقات متعددة في الوقت نفسه، باستخدام وضع تقسيم الشاشة أو وضع "نافذة ضمن النافذة"، يمكن لكل تطبيق استدعاء setFrameRate() بأمان لمساحات العرض الخاصة به.

لا تتغيّر المنصة إلى عدد اللقطات في الثانية للتطبيق.

حتى إذا كان الجهاز يتيح معدّل عرض اللقطات الذي يحدّده التطبيق في طلب إلى setFrameRate()، هناك حالات لن يغيّر فيها الجهاز معدّل تحديث الشاشة إلى هذا المعدّل. على سبيل المثال، قد يكون لسطح العرض ذي الأولوية الأعلى إعداد مختلف لمعدّل عرض اللقطات في الثانية، أو قد يكون الجهاز في وضع "توفير شحن البطارية" (ما يؤدي إلى فرض قيود على معدّل إعادة تحميل الشاشة للحفاظ على شحن البطارية). يجب أن يظل التطبيق يعمل بشكل صحيح عندما لا يغيّر الجهاز معدّل تحديث الشاشة إلى إعداد معدّل اللقطات في التطبيق، حتى إذا كان الجهاز يغيّر المعدّل في الظروف العادية.

ويعود إلى التطبيق تحديد كيفية الاستجابة عندما لا يتطابق معدّل إعادة تحميل شاشة العرض مع معدّل عرض اللقطات في التطبيق. بالنسبة إلى الفيديو، يتم تثبيت عدد اللقطات في الثانية على عدد اللقطات في الفيديو المصدر، وسيكون من الضروري استخدام تقنية "سحب لأسفل" لعرض محتوى الفيديو. قد تختار إحدى الألعاب بدلاً من ذلك محاولة التشغيل بمعدّل تحديث شاشة العرض بدلاً من البقاء على معدّل اللقطات المفضّل لديها. يجب ألا يغيّر التطبيق القيمة التي يرسلها إلى setFrameRate() استنادًا إلى ما تفعله المنصة. ويجب أن يظل مضبوطًا على معدّل اللقطات المفضّل للتطبيق، بغض النظر عن الطريقة التي يتعامل بها التطبيق مع الحالات التي لا تتوافق فيها المنصة مع طلب التطبيق. بهذه الطريقة، إذا تغيّرت شروط الجهاز للسماح باستخدام معدّلات إطار إضافية، ستتوفّر لدى النظام الأساسي المعلومات الصحيحة للتبديل إلى معدّل الإطار المفضّل للتطبيق.

في الحالات التي لا يمكن فيها تشغيل التطبيق بمعدّل تجديد الشاشة، يجب أن يحدّد التطبيق طوابع زمنية للعرض لكل إطار، وذلك باستخدام إحدى آليات النظام الأساسي لضبط الطوابع الزمنية للعرض:

يمنع استخدام هذه الطوابع الزمنية المنصة من عرض إطار تطبيق مبكرًا جدًا، ما قد يؤدي إلى حدوث اهتزاز غير ضروري. قد يكون الاستخدام الصحيح للطوابع الزمنية لعرض اللقطات أمرًا معقّدًا بعض الشيء. بالنسبة إلى الألعاب، يمكنك الاطّلاع على دليل عرض اللقطات للحصول على مزيد من المعلومات حول تجنُّب التقطّع، ويمكنك أيضًا استخدام مكتبة Android Frame Pacing.

في بعض الحالات، قد تنتقل المنصة إلى مضاعف لمعدل عرض اللقطات الذي حدّده التطبيق في setFrameRate(). على سبيل المثال، قد يطلب تطبيق معدّل setFrameRate() بتردد 60 هرتز، وقد يغيّر الجهاز معدّل عرض الشاشة إلى 120 هرتز. قد يحدث ذلك إذا كان تطبيق آخر يتضمّن مساحة عرض تم ضبط معدّل عرض اللقطات فيها على 24 هرتز. في هذه الحالة، سيسمح تشغيل الشاشة بمعدل 120 هرتز بتشغيل كلّ من مساحة العرض بمعدل 60 هرتز ومساحة العرض بمعدل 24 هرتز بدون الحاجة إلى تقليل معدل عرض الإطارات.

عندما يتم تشغيل العرض بمعدّل أضعاف عدد اللقطات في الثانية للتطبيق، يجب أن يحدّد التطبيق الطوابع الزمنية للعرض لكل لقطة لتجنُّب التقطُّع غير الضروري. بالنسبة إلى الألعاب، تكون مكتبة Android Frame Pacing مفيدة في ضبط الطوابع الزمنية لعرض اللقطات بشكل صحيح.

‫setFrameRate() مقابل preferredDisplayModeId

WindowManager.LayoutParams.preferredDisplayModeId هي طريقة أخرى يمكن للتطبيقات من خلالها الإشارة إلى عدد اللقطات في الثانية على المنصة. لا تريد بعض التطبيقات تغيير معدّل تحديث الشاشة، بل تريد تغيير إعدادات وضع العرض الأخرى، مثل دقّة الشاشة. بشكل عام، استخدِم setFrameRate() بدلاً من preferredDisplayModeId. تتميّز الدالة setFrameRate() بسهولة الاستخدام لأنّ التطبيق لا يحتاج إلى البحث في قائمة أوضاع العرض للعثور على وضع بمعدّل لقطات معيّن.

تمنح السمة setFrameRate() المنصة المزيد من الفرص لاختيار معدل عرض متوافق مع سيناريوهات تتضمّن مساحات عرض متعددة تعمل بمعدلات عرض مختلفة. على سبيل المثال، لنفترض أنّ تطبيقَين يعملان في وضع تقسيم الشاشة على هاتف Pixel 4، أحدهما يعرض فيديو بمعدّل 24 إطارًا في الثانية والآخر يعرض للمستخدم قائمة قابلة للتمرير. يتوافق هاتف Pixel 4 مع معدلَي إعادة تحميل للشاشة: 60 هرتز و90 هرتز. باستخدام واجهة برمجة التطبيقات preferredDisplayModeId، يتم فرض اختيار معدل 60 هرتز أو 90 هرتز لمساحة عرض الفيديو. من خلال طلب setFrameRate() بمعدل 24 هرتز، توفّر مساحة عرض الفيديو للمنصة المزيد من المعلومات حول معدل عرض اللقطات للفيديو المصدر، ما يتيح للمنصة اختيار معدل تحديث العرض 90 هرتز، وهو أفضل من 60 هرتز في هذه الحالة.

ومع ذلك، هناك سيناريوهات يجب فيها استخدام preferredDisplayModeId بدلاً من setFrameRate()، مثل ما يلي:

  • إذا كان التطبيق يريد تغيير دقّة الشاشة أو إعدادات وضع العرض الأخرى، استخدِم preferredDisplayModeId.
  • لن تبدّل المنصة أوضاع العرض إلا استجابةً لطلب setFrameRate() إذا كان تبديل الوضع بسيطًا ومن غير المرجّح أن يلاحظه المستخدم. إذا كان التطبيق يفضّل تبديل معدّل تحديث الشاشة حتى إذا كان ذلك يتطلّب تبديل الوضع بشكل كبير (على سبيل المثال، على جهاز Android TV)، استخدِم preferredDisplayModeId.
  • يجب أن تستخدم التطبيقات التي لا يمكنها التعامل مع العرض الذي يعمل بمضاعفات معدّل عرض اللقطات في الثانية للتطبيق، والذي يتطلب ضبط الطوابع الزمنية للعرض على كل لقطة، السمة preferredDisplayModeId.

‫setFrameRate() مقابل preferredRefreshRate

يضبط WindowManager.LayoutParams#preferredRefreshRate معدّل لقطات مفضّلاً في نافذة التطبيق، ويكون المعدّل ساريًا على جميع مساحات العرض داخل النافذة. يجب أن يحدّد التطبيق معدّل انتقال الإطارات المفضّل بغض النظر عن معدّلات التحديث المتوافقة مع الجهاز، على غرار setFrameRate()، وذلك لمنح المجدول إشارة أفضل إلى معدّل انتقال الإطارات المقصود للتطبيق.

يتم تجاهل preferredRefreshRate في "الأسطح" التي تستخدم setFrameRate(). ننصحك بشكل عام باستخدام setFrameRate() إذا أمكن ذلك.

preferredRefreshRate vs preferredDisplayModeId

إذا كانت التطبيقات تريد تغيير معدل التحديث المفضّل فقط، يُفضّل استخدام preferredRefreshRate بدلاً من preferredDisplayModeId.

تجنُّب استدعاء setFrameRate() بشكل متكرّر

على الرغم من أنّ طلب setFrameRate() ليس مكلفًا جدًا من حيث الأداء، يجب أن تتجنّب التطبيقات طلب setFrameRate() في كل إطار أو عدة مرات في الثانية. من المحتمل أن تؤدي المكالمات إلى setFrameRate() إلى تغيير في معدّل تجديد الشاشة، ما قد يؤدي إلى انخفاض عدد اللقطات في الثانية أثناء الانتقال. عليك تحديد معدّل اللقطات الصحيح مسبقًا واستدعاء setFrameRate() مرة واحدة.

الاستخدام في الألعاب أو التطبيقات الأخرى غير الفيديو

على الرغم من أنّ الفيديو هو حالة الاستخدام الأساسية لواجهة برمجة التطبيقات setFrameRate()، يمكن استخدامها مع تطبيقات أخرى. على سبيل المثال، يمكن للعبة التي لا تريد أن تعمل بسرعة أعلى من 60 هرتز (لتقليل استهلاك الطاقة وإتاحة جلسات لعب أطول) استدعاء Surface.setFrameRate(60, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT). بهذه الطريقة، سيتم تشغيل الجهاز بمعدل 60 هرتز بدلاً من 90 هرتز أثناء تشغيل اللعبة، ما سيؤدي إلى تجنُّب التقطُّع الذي كان سيحدث إذا تم تشغيل اللعبة بمعدل 60 هرتز بينما كانت الشاشة تعمل بمعدل 90 هرتز.

استخدام FRAME_RATE_COMPATIBILITY_FIXED_SOURCE

تطبيق "FRAME_RATE_COMPATIBILITY_FIXED_SOURCE" مخصّص لتطبيقات الفيديو فقط. بالنسبة إلى الاستخدام غير المرتبط بالفيديو، يُرجى استخدام FRAME_RATE_COMPATIBILITY_DEFAULT.

اختيار استراتيجية لتغيير معدّل عرض اللقطات

  • ننصح بشدة بأن تستدعي التطبيقات الدالة setFrameRate(fps, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS) عند عرض فيديوهات طويلة المدة، مثل الأفلام، حيث يمثّل fps عدد اللقطات في الثانية للفيديو.
  • ننصحك بشدة بعدم استخدام التطبيقات التي تستدعي setFrameRate() مع CHANGE_FRAME_RATE_ALWAYS عندما تتوقّع أن يستمر تشغيل الفيديو لعدة دقائق أو أقل.

مثال على الدمج لتطبيقات تشغيل الفيديو

ننصح باتّباع الخطوات التالية لدمج مفاتيح تبديل معدّل التحديث في تطبيقات تشغيل الفيديو:

  1. حدِّد changeFrameRateStrategy:
    1. إذا كنت تشغّل فيديو طويلاً، مثل فيلم، استخدِم MATCH_CONTENT_FRAMERATE_ALWAYS
    2. إذا كنت تشغّل فيديو قصيرًا، مثل مقطع دعائي لفيلم، استخدِم CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS.
  2. إذا كانت قيمة changeFrameRateStrategy هي CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS ، انتقِل إلى الخطوة 4.
  3. يمكنك رصد ما إذا كان سيتم تبديل معدّل التحديث غير السلس من خلال التأكّد من صحة ما يلي:
    1. لا يمكن التبديل إلى الوضع السلس من معدّل التحديث الحالي (لنسمّه C) إلى عدد اللقطات في الثانية للفيديو (لنسمّه V). سيحدث ذلك إذا كان C وV مختلفَين ولم يكن Display.getMode().getAlternativeRefreshRates مضاعفًا لـ V.
    2. وافق المستخدم على تغييرات معدّل إعادة التحميل غير السلسة. يمكنك رصد ذلك من خلال التحقّق مما إذا كانت الدالة DisplayManager.getMatchContentFrameRateUserPreference تعرض القيمة MATCH_CONTENT_FRAMERATE_ALWAYS.
  4. إذا كان التبديل سلسًا، اتّبِع الخطوات التالية:
    1. استدعِ الدالة setFrameRate ومرِّر إليها fps وFRAME_RATE_COMPATIBILITY_FIXED_SOURCE وchangeFrameRateStrategy، حيث fps هو عدد اللقطات في الثانية للفيديو.
    2. بدء تشغيل الفيديو
  5. إذا كان سيتم تغيير الوضع بشكل غير سلس، اتّبِع الخطوات التالية:
    1. عرض تجربة المستخدم لإشعار المستخدم يُرجى العِلم أنّنا ننصحك بتوفير طريقة للمستخدم لإغلاق تجربة المستخدم هذه وتخطّي التأخير الإضافي في الخطوة 5.د. ويرجع ذلك إلى أنّ التأخير الذي ننصح به أكبر من اللازم على الشاشات التي تعرض أوقات تبديل أسرع.
    2. استدعِ الدالة setFrameRate ومرِّر إليها fps وFRAME_RATE_COMPATIBILITY_FIXED_SOURCE وCHANGE_FRAME_RATE_ALWAYS، حيث fps هو عدد اللقطات في الثانية للفيديو.
    3. انتظِر onDisplayChanged معاودة الاتصال.
    4. انتظِر ثانيتَين إلى أن يكتمل تبديل الوضع.
    5. بدء تشغيل الفيديو

في ما يلي الرمز الزائف الذي يتيح التبديل السلس فقط:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
transaction.setFrameRate(surfaceControl,
    contentFrameRate,
    FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
    CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
transaction.apply();
beginPlayback();

في ما يلي الرمز الزائف الذي يتيح التبديل السلس وغير السلس كما هو موضّح أعلاه:

SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (isSeamlessSwitch(contentFrameRate)) {
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
  transaction.apply();
  beginPlayback();
} else if (displayManager.getMatchContentFrameRateUserPreference()
      == MATCH_CONTENT_FRAMERATE_ALWAYS) {
  showRefreshRateSwitchUI();
  sleep(shortDelaySoUserSeesUi);
  displayManager.registerDisplayListener();
  transaction.setFrameRate(surfaceControl,
      contentFrameRate,
      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
      CHANGE_FRAME_RATE_ALWAYS);
  transaction.apply();
  waitForOnDisplayChanged();
  sleep(twoSeconds);
  hideRefreshRateSwitchUI();
  beginPlayback();
}