4.15. مخازن الإطارات¶
بمجرد تهيئة مستشعر الكاميرا، فإنه يُصدر الإطارات باستمرار بمعدل إطاراته -- إطار جديد واحد في كل فترة إطار سواء كان التطبيق جاهزاً له أم لا. يحتاج كل إطار إلى مكان في الذاكرة RAM ليستقر فيه وإلا فقد. تجمّع مخازن الإطارات هو المكان الذي تعيش فيه تلك الإطارات بين مغادرتها وحدة DMA ومعالجتها بواسطة كود المستخدم، وعدد مخازن الإطارات التي تحتفظ بها الكاميرا في ذلك التجمّع يتحكم في كيفية تقاسم وحدة DMA والتطبيق لها. يُتاح هذا الخيار عبر framebuffers()، وتتوفر أربعة أوضاع، تُختار بحسب عدد المخازن.
4.15.1. مخزن مفرد (count = 1)¶
مخزن إطارات واحد في الذاكرة RAM. تملؤه وحدة DMA؛ ويقرأ منه التطبيق؛ ولا يمكن أن يبدأ الاستدعاء التالي لـ snapshot() حتى يحرر التطبيق المخزن، لأن المخزن نفسه مطلوب لكليهما.
تعمل الكاميرا والتطبيق بتزامن تام. على وحدة DMA أن تنتظر انتهاء التطبيق، وعلى التطبيق أن ينتظر انتهاء وحدة DMA، مما يعني أن معدل الإطارات القابل للتحقيق هو في أفضل الأحوال نصف معدل إطارات المستشعر -- فكل إطار آخر يُصدره المستشعر يصل بينما يكون المخزن مشغولاً فيُفقد.
هذا الوضع هو الأصغر من حيث استخدام الذاكرة RAM والأبطأ من حيث الإنتاجية. استخدمه فقط عندما تكون الذاكرة RAM ضيقة جداً بحيث يتعذر تخصيص مخزن ثانٍ.
4.15.2. مخزن مزدوج (count = 2)¶
مخزنا إطارات في الذاكرة RAM: مخزن خلفي تملؤه وحدة DMA، ومخزن أمامي يقرأ منه التطبيق. عندما ينتهي التطبيق من المخزن الأمامي يتبادل الاثنان دوريهما، وتبدأ وحدة DMA في ملء المخزن المُحرر حديثاً بينما يقرأ التطبيق من المخزن الذي امتلأ للتو.
ما دام التطبيق يعالج كل إطار في أقل من فترة إطار كاميرا واحدة، فإن التطبيق يرى معدل إطارات المستشعر الكامل -- فإطار وحدة DMA التالي يكون منتظراً بالفعل في المخزن الخلفي عندما يستدعي التطبيق snapshot() مرة أخرى. ومع ذلك، في اللحظة التي يتجاوز فيها زمن المعالجة فترة إطار واحدة، ينخفض المعدل إلى النصف: ستنتج الكاميرا إطارين في الوقت الذي يستغرقه التطبيق لمعالجة إطار واحد، وسيُسلَّم الثاني فقط من هذين الإطارين.
بعد تلك النقطة يتدهور المعدل بسلاسة مع زمن المعالجة. في كل مرة تنهي فيها وحدة DMA إطاراً جديداً في المخزن الخلفي بينما لا يزال التطبيق يعمل على المخزن الأمامي، يحل الإطار الجديد محل اللقطة السابقة في مكانها بدلاً من التخلص منه. يحصل التطبيق دائماً على أحدث إطار أنتجته الكاميرا عند استدعائه التالي لـ snapshot()، ويصبح معدل التطبيق القابل للتحقيق مقلوب زمن معالجته.
4.15.3. مخزن ثلاثي (count = 3)¶
ثلاثة مخازن إطارات في الذاكرة RAM: مخزنان خلفيان تتنقل وحدة DMA بينهما ومخزن أمامي واحد يعمل عليه التطبيق حالياً. هذا هو الوضع الافتراضي الذي تختاره OpenMV Cam عندما تتوفر ذاكرة RAM كافية، مع تراجع تلقائي إلى المخزن المزدوج أو المفرد عند عدم توفرها.
يفصل المخزن الثالث فصلاً تاماً معدل إطارات الكاميرا عن معدل إطارات التطبيق. تمتلك وحدة DMA دائماً مخزناً للكتابة فيه؛ ويمتلك التطبيق دائماً مخزناً للقراءة منه؛ وعند كل snapshot() يصبح أحدث مخزن خلفي جاهز هو المخزن الأمامي الجديد ويُحرَّر المخزن الأمامي السابق لوحدة DMA. يطابق معدل إطارات التطبيق الزمن الفعلي الذي يستغرقه لمعالجة كل إطار -- دون الانخفاض إلى النصف الذي يقع فيه المخزن المزدوج عندما يتجاوز زمن المعالجة فترة إطار واحدة بقليل.
4.15.4. FIFO للفيديو (count = 4 أو أكثر)¶
أربعة مخازن إطارات أو أكثر في الذاكرة RAM، مرتبة كحلقة من الإطارات الملتقطة تباعاً. كل إطار تُسلِّمه الكاميرا يُدرَج في قائمة FIFO، ويُعيد snapshot() الإطار الأقدم في القائمة بدلاً من الأحدث. يتنقل التطبيق عبر الإطارات الملتقطة بترتيب الالتقاط، في الوقت الفعلي المتاح له لكل إطار.
هذا الوضع هو الخيار الصحيح عندما يهم كل إطار وتكون التوقفات المؤقتة القصيرة في المعالجة متوقعة: كتابة الفيديو إلى بطاقة SD قد تتوقف حزمة تخزينها لعشرات الميلي ثانية أثناء عملية مسح، أو البث عبر USB إلى مضيف يتوقف عن القراءة لفترة وجيزة، أو تخزين دفقة قصيرة لحدث سريع لفحصها في الكود.
تتعامل سياستان مع الحالة التي تمتلئ فيها قائمة FIFO قبل أن يكون التطبيق قد أفرغها.
إسقاط الإطارات القديمة (الافتراضي). عندما تمتلئ قائمة FIFO، يُتخلص من جميع الإطارات المُدرَجة باستثناء الإطار النشط بحيث يُعيد
snapshot()التالي إطاراً حديثاً بدلاً من إطار قديم. تستمر وحدة DMA في الالتقاط طوال الوقت، فيرى التطبيق دائماً بيانات جديدة بعد التوقف المؤقت. هذه هي السياسة الصحيحة عندما يكون الهدف الحفاظ على حداثة الدفق الملتقط -- تسجيل الفيديو والبث المباشر.إيقاف الالتقاط عند الفيضان. مرر
fflush=Falseإلى مُنشئCSIفتتوقف وحدة DMA عن ملء قائمة FIFO عندما تكون ممتلئة، تاركة الإطارات المُدرَجة سليمة. يستمرsnapshot()في إعادة الإطارات بترتيب الالتقاط حتى يفرغها التطبيق، وبعد ذلك تستأنف وحدة DMA. هذه هي السياسة الصحيحة عندما يكون الهدف الحفاظ على كل إطار من دفقة قصيرة -- التقاط حركة سريعة لفحصها إطاراً بإطار في الكود لاحقاً.
راجع csi.CSI.framebuffers() للاطلاع على الواجهة البرمجية الكاملة.
4.15.5. الوضع المُشغَّل بالمؤثرات¶
بديل عن الأوضاع الدائمة التشغيل أعلاه هو الالتقاط المُشغَّل بالمؤثرات، حيث يُصدر المستشعر إطاراً فقط عندما يطلبه snapshot(). تظل الكاميرا خاملة بين اللقطات وتبدأ تعريضاً جديداً في كل مرة يستدعيها فيها التطبيق.
التكلفة هي الإنتاجية: لا يمكن أن يتداخل التقاط مُشغَّل مع الالتقاط السابق، لذا فإن أقصى معدل إطارات قابل للتحقيق هو نصف المعدل العادي للمستشعر. والفائدة هي توقيت التعريض. تتحكم اللقطة بدقة في متى يبدأ التعريض، وهو ما يريده التطبيق عندما يجب أن يتوافق التعريض مع حدث خارجي -- وميض ضوء خاطف، أو مستشعر موضع ناقل، أو نبضة على خط GPIO -- بدلاً من أن يقع أينما صادف أن يكون الإطار المتدحرج للمستشعر الحر التشغيل عندما يكون التطبيق جاهزاً لقراءته.
الوضع المُشغَّل بالمؤثرات خاص بكل مستشعر. على المستشعرات المدعومة يُفعَّل باستدعاء csi0.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True) ويُعطَّل بتمرير False.