API های مدیریت بافر دوربین HAL3

اندروید 10 APIهای اختیاری مدیریت بافر دوربین HAL3 را معرفی می کند که به شما امکان می دهد منطق مدیریت بافر را برای دستیابی به حافظه های مختلف و ثبت معاوضه تاخیر در اجرای HAL دوربین پیاده سازی کنید.

دوربین HAL به N درخواست (که در آن N برابر با عمق خط لوله است) در خط لوله خود نیاز دارد، اما اغلب به همه N مجموعه بافرهای خروجی به طور همزمان نیاز ندارد.

برای مثال، HAL ممکن است هشت درخواست در صف خط لوله داشته باشد، اما فقط به بافرهای خروجی برای دو درخواست در آخرین مراحل خط لوله نیاز دارد. در دستگاه‌هایی که اندروید 9 و پایین‌تر دارند، چارچوب دوربین زمانی که درخواست در HAL در صف قرار می‌گیرد، بافرها را اختصاص می‌دهد، بنابراین ممکن است شش مجموعه بافر در HAL وجود داشته باشد که استفاده نمی‌شوند. در اندروید 10، API های مدیریت بافر دوربین HAL3 امکان جداسازی بافرهای خروجی را برای آزاد کردن شش مجموعه بافر فراهم می کند. این می تواند به صدها مگابایت صرفه جویی در حافظه در دستگاه های پیشرفته منجر شود و همچنین می تواند برای دستگاه های با حافظه کم مفید باشد.

شکل 1 نمودار رابط HAL دوربین را برای دستگاه‌های دارای اندروید 9 و پایین‌تر نشان می‌دهد. شکل 2 رابط دوربین HAL را در اندروید 10 با API های مدیریت بافر دوربین HAL3 نشان می دهد.

مدیریت بافر در 9 یا پایین تر

شکل 1. رابط دوربین HAL در اندروید 9 و پایین تر

مدیریت بافر در اندروید 10

شکل 2. رابط دوربین HAL در اندروید 10 با استفاده از APIهای مدیریت بافر

پیاده سازی API های مدیریت بافر

برای پیاده سازی API های مدیریت بافر، دوربین HAL باید:

دوربین HAL از متدهای requestStreamBuffers و returnStreamBuffers در ICameraDeviceCallback.hal برای درخواست و برگرداندن بافرها استفاده می کند. HAL همچنین باید متد signalStreamFlush را در ICameraDeviceSession.hal پیاده سازی کند تا به HAL دوربین سیگنال دهد تا بافرها را برگرداند.

requestStreamBuffers

از روش requestStreamBuffers برای درخواست بافر از چارچوب دوربین استفاده کنید. هنگام استفاده از APIهای مدیریت بافر دوربین HAL3، درخواست‌های عکسبرداری از چارچوب دوربین حاوی بافرهای خروجی نیستند، یعنی فیلد bufferId در StreamBuffer 0 است. بنابراین، دوربین HAL باید از requestStreamBuffers برای درخواست بافر از چارچوب دوربین استفاده کند.

روش requestStreamBuffers به ​​تماس‌گیرنده اجازه می‌دهد تا بافرهای متعدد را از جریان‌های خروجی متعدد در یک تماس درخواست کند، که امکان تماس‌های HIDL IPC کمتری را فراهم می‌کند. با این حال، زمانی که بافرهای بیشتری به طور همزمان درخواست می‌شوند، تماس‌ها زمان بیشتری می‌برد و این ممکن است بر کل تأخیر درخواست تا نتیجه تأثیر منفی بگذارد. همچنین، از آنجایی که فراخوانی‌ها به requestStreamBuffers در سرویس دوربین سریال می‌شوند، توصیه می‌شود دوربین HAL از یک رشته با اولویت بالا برای درخواست بافرها استفاده کند.

اگر درخواست بافر با شکست مواجه شود، دوربین HAL باید بتواند به درستی خطاهای غیر کشنده را مدیریت کند. لیست زیر دلایل متداول عدم موفقیت درخواست های بافر و نحوه رسیدگی به آنها توسط دوربین HAL را شرح می دهد.

  • برنامه از جریان خروجی قطع می شود: این یک خطای غیر کشنده است. دوربین HAL باید ERROR_REQUEST برای هر درخواست عکس برداری که جریانی قطع شده را هدف قرار می دهد ارسال کند و آماده پردازش درخواست های بعدی به طور معمول باشد.
  • مهلت زمانی: این می تواند زمانی رخ دهد که یک برنامه مشغول انجام پردازش فشرده در حالی که روی برخی از بافرها نگه داشته می شود. دوربین HAL باید ERROR_REQUEST برای درخواست‌های عکسبرداری که به دلیل خطای مهلت زمانی انجام نمی‌شوند ارسال کند و آماده پردازش درخواست‌های بعدی به طور معمول باشد.
  • چارچوب دوربین در حال آماده سازی یک پیکربندی جریان جدید است: دوربین HAL باید منتظر بماند تا تماس configureStreams بعدی کامل شود و قبل از فراخوانی مجدد requestStreamBuffers .
  • دوربین HAL به حد بافر خود رسیده است (فیلد maxBuffers ): دوربین HAL باید قبل از فراخوانی مجدد requestStreamBuffers صبر کند تا حداقل یک بافر از جریان را برگرداند.

returnStreamBuffers

از روش returnStreamBuffers برای برگرداندن بافرهای اضافی به چارچوب دوربین استفاده کنید. دوربین HAL معمولاً بافرها را از طریق روش processCaptureResult به چارچوب دوربین برمی‌گرداند، اما فقط می‌تواند درخواست‌های عکس‌برداری را که به HAL دوربین ارسال شده است، محاسبه کند. با روش requestStreamBuffers ، این امکان برای اجرای HAL دوربین وجود دارد که بافرهای بیشتری نسبت به آنچه که توسط چارچوب دوربین درخواست شده است، حفظ کند. این زمانی است که باید از متد returnStreamBuffers استفاده شود. اگر پیاده‌سازی HAL هرگز بافرهای بیشتری از درخواستی را در خود نگه نمی‌دارد، پیاده‌سازی HAL دوربین نیازی به فراخوانی متد returnStreamBuffers ندارد.

signalStreamFlush

متد signalStreamFlush توسط چارچوب دوربین فراخوانی می شود تا به دوربین HAL اطلاع دهد تا تمام بافرهای موجود را برگرداند. این معمولاً زمانی فراخوانی می‌شود که چارچوب دوربین می‌خواهد configureStreams فراخوانی کند و باید خط لوله ضبط دوربین را تخلیه کند. مشابه روش returnStreamBuffers ، اگر پیاده‌سازی HAL دوربین بافرهای بیشتری از درخواستی را در خود نگهداری نکند، ممکن است یک پیاده‌سازی خالی از این روش داشته باشیم.

پس از اینکه چارچوب دوربین signalStreamFlush را فراخوانی کرد، فریم ورک ارسال درخواست‌های عکسبرداری جدید به HAL دوربین را متوقف می‌کند تا زمانی که همه بافرها به چارچوب دوربین بازگردانده شوند. هنگامی که همه بافرها برگردانده می شوند، فراخوانی های متد requestStreamBuffers با شکست مواجه می شوند و چارچوب دوربین می تواند کار خود را در حالت تمیز ادامه دهد. چارچوب دوربین سپس روش configureStreams یا processCaptureRequest را فراخوانی می کند. اگر چارچوب دوربین متد configureStreams را فراخوانی کند، HAL دوربین می‌تواند پس از بازگشت موفقیت آمیز تماس configureStreams دوباره درخواست بافرها را آغاز کند. اگر چارچوب دوربین متد processCaptureRequest را فراخوانی کند، HAL دوربین می‌تواند در طول تماس processCaptureRequest درخواست بافرها را آغاز کند.

معناشناسی برای روش signalStreamFlush و روش flush متفاوت است. هنگامی که روش flush فراخوانی می شود، HAL می تواند درخواست های در انتظار ضبط را با ERROR_REQUEST لغو کند تا در اسرع وقت خط لوله را تخلیه کند. هنگامی که متد signalStreamFlush فراخوانی می‌شود، HAL باید تمام درخواست‌های در انتظار ضبط را به طور معمول تمام کند و همه بافرها را به چارچوب دوربین برگرداند.

تفاوت دیگر بین روش signalStreamFlush و سایر روش ها این است که signalStreamFlush یک روش HIDL یک طرفه است، به این معنی که چارچوب دوربین ممکن است قبل از اینکه HAL تماس signalStreamFlush را دریافت کند، به APIهای مسدودکننده دیگر فراخوانی کند. این بدان معنی است که روش signalStreamFlush و روش‌های دیگر (مخصوصاً روش configureStreams ) ممکن است به ترتیبی متفاوت از ترتیبی که در چارچوب دوربین فراخوانی شده‌اند، به HAL دوربین برسند. برای رفع این مشکل ناهمزمانی، فیلد streamConfigCounter به StreamConfiguration اضافه شد و به عنوان آرگومان به متد signalStreamFlush اضافه شد. پیاده سازی دوربین HAL باید از آرگومان streamConfigCounter استفاده کند تا مشخص کند که آیا یک تماس signalStreamFlush دیرتر از تماس configureStreams مربوطه می رسد یا خیر. برای مثال شکل 3 را ببینید.

رسیدگی به تماس هایی که دیر می رسد

شکل 3. چگونه دوربین HAL باید تماس های signalStreamFlush را که دیر می رسد شناسایی و مدیریت کند

تغییر رفتار هنگام اجرای APIهای مدیریت بافر

هنگام استفاده از API های مدیریت بافر برای پیاده سازی منطق مدیریت بافر، تغییرات رفتاری احتمالی زیر را در اجرای HAL دوربین و دوربین در نظر بگیرید:

  • درخواست‌های عکسبرداری سریع‌تر و بیشتر به دوربین HAL می‌رسند: بدون APIهای مدیریت بافر، چارچوب دوربین قبل از ارسال درخواست ضبط به HAL دوربین، بافرهای خروجی را برای هر درخواست عکس‌برداری درخواست می‌کند. هنگام استفاده از APIهای مدیریت بافر، چارچوب دوربین دیگر نیازی به انتظار بافرها ندارد و بنابراین می‌تواند درخواست‌های عکسبرداری را زودتر به HAL دوربین ارسال کند.

    همچنین، بدون APIهای مدیریت بافر، اگر یکی از جریان‌های خروجی درخواست ضبط به حداکثر تعداد بافرهایی که HAL می‌تواند در یک زمان نگه دارد، رسیده باشد، چارچوب دوربین ارسال درخواست‌های عکسبرداری را متوقف می‌کند (این مقدار توسط HAL دوربین در فیلد HalStream::maxBuffers در مقدار بازگشتی یک تماس configureStreams ). با APIهای مدیریت بافر، این رفتار throttling دیگر وجود ندارد و پیاده سازی HAL دوربین نباید تماس های processCaptureRequest را بپذیرد، زمانی که HAL درخواست های ضبط بیش از حد در صف دارد.

  • تأخیر تماس requestStreamBuffers به ​​طور قابل توجهی متفاوت است: دلایل زیادی وجود دارد که تماس requestStreamBuffers ممکن است بیشتر از حد متوسط ​​طول بکشد. مثلا:

    • برای چند بافر اول یک جریان تازه ایجاد شده، تماس‌ها ممکن است بیشتر طول بکشد زیرا دستگاه باید حافظه را تخصیص دهد.
    • تأخیر مورد انتظار متناسب با تعداد بافرهای درخواستی در هر تماس افزایش می یابد.
    • برنامه بافرها را نگه می دارد و مشغول پردازش است. این می‌تواند باعث کند شدن درخواست‌های بافر یا به دلیل کمبود بافر یا شلوغ بودن CPU شود.

استراتژی های مدیریت بافر

APIهای مدیریت بافر امکان پیاده سازی انواع مختلفی از استراتژی های مدیریت بافر را فراهم می کنند. چند نمونه عبارتند از:

  • سازگار با عقب: HAL در طول تماس processCaptureRequest بافرهایی را برای درخواست ضبط درخواست می کند. این استراتژی هیچ گونه صرفه جویی در حافظه را فراهم نمی کند، اما می تواند به عنوان اولین اجرای API های مدیریت بافر عمل کند، که نیاز به تغییر کد بسیار کمی در HAL دوربین موجود دارد.
  • حداکثر صرفه جویی در حافظه: دوربین HAL فقط قبل از پر کردن بافرهای خروجی درخواست می کند. این استراتژی امکان ذخیره حداکثری حافظه را فراهم می کند. هنگامی که درخواست‌های بافر زمان زیادی طول می‌کشد تا تکمیل شوند، نقطه ضعف احتمالی این است که بیشتر دوربین مداربسته خط لوله باشد.
  • حافظه پنهان: دوربین HAL چند بافر را در حافظه پنهان ذخیره می کند تا کمتر تحت تأثیر درخواست بافر آهسته گاه به گاه قرار گیرد.

دوربین HAL می‌تواند استراتژی‌های مختلفی را برای موارد استفاده خاص اتخاذ کند، به عنوان مثال، استفاده از استراتژی ذخیره حداکثری حافظه برای موارد استفاده که از حافظه زیادی استفاده می‌کنند و استفاده از استراتژی سازگار با عقب برای موارد استفاده دیگر.

اجرای نمونه در دوربین خارجی HAL

دوربین خارجی HAL در اندروید 9 معرفی شد و می‌توان آن را در درخت منبع در hardware/interfaces/camera/device/3.5/ یافت. در اندروید 10، به‌روزرسانی شده است تا ExternalCameraDeviceSession.cpp که یک پیاده‌سازی از API مدیریت بافر است، شامل شود. این دوربین خارجی HAL استراتژی ذخیره حداکثری حافظه ذکر شده در استراتژی های مدیریت بافر را در چند صد خط کد C++ اجرا می کند.