اندروید ۱۰ رابطهای برنامهنویسی کاربردی (API) اختیاری مدیریت بافر دوربین HAL3 را معرفی میکند که به شما امکان میدهد منطق مدیریت بافر را برای دستیابی به تعادلهای مختلف در حافظه و تأخیر ضبط در پیادهسازیهای HAL دوربین پیادهسازی کنید.
دوربین HAL به N درخواست (که N برابر با عمق خط لوله است) در صف خط لوله خود نیاز دارد، اما اغلب به همه N مجموعه بافر خروجی به طور همزمان نیاز ندارد.
برای مثال، HAL ممکن است هشت درخواست در صف پردازش داشته باشد، اما فقط برای دو درخواست در مراحل آخر پردازش به بافر خروجی نیاز دارد. در دستگاههایی که اندروید ۹ و پایینتر دارند، چارچوب دوربین هنگام صفبندی درخواست در HAL، بافرهایی را اختصاص میدهد، بنابراین ممکن است شش مجموعه بافر در HAL وجود داشته باشد که در حال استفاده نیستند. در اندروید ۱۰، APIهای مدیریت بافر دوربین HAL3 امکان جداسازی بافرهای خروجی را برای آزاد کردن شش مجموعه بافر فراهم میکنند. این امر میتواند منجر به صدها مگابایت صرفهجویی در حافظه در دستگاههای پیشرفته شود و همچنین میتواند برای دستگاههای کمحافظه مفید باشد.
شکل ۱ نموداری از رابط کاربری دوربین HAL را برای دستگاههایی که اندروید ۹ و پایینتر را اجرا میکنند نشان میدهد. شکل ۲ رابط کاربری دوربین HAL را در اندروید ۱۰ با APIهای مدیریت بافر دوربین HAL3 پیادهسازی شده نشان میدهد.

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

شکل 2. رابط کاربری دوربین HAL در اندروید 10 با استفاده از APIهای مدیریت بافر
پیادهسازی APIهای مدیریت بافر
برای پیادهسازی APIهای مدیریت بافر، دوربین HAL باید:
- HIDL
ICameraDevice@3.5را پیاده سازی کنید. - کلید مشخصات دوربین
android.info.supportedBufferManagementVersionرا رویHIDL_DEVICE_3_5تنظیم کنید.
دوربین HAL از متدهای requestStreamBuffers و returnStreamBuffers در ICameraDeviceCallback.hal برای درخواست و بازگرداندن بافرها استفاده میکند. HAL همچنین باید متد signalStreamFlush را در ICameraDeviceSession.hal پیادهسازی کند تا به دوربین HAL سیگنال دهد تا بافرها را برگرداند.
درخواستStreamBuffers
از متد 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 برای بازگرداندن بافرهای اضافی به فریمورک دوربین استفاده کنید. دوربین HAL معمولاً بافرها را از طریق متد processCaptureResult به فریمورک دوربین برمیگرداند، اما فقط میتواند درخواستهای ضبطی را که به دوربین HAL ارسال شدهاند، در نظر بگیرد. با متد requestStreamBuffers ، پیادهسازی دوربین HAL میتواند بافرهای بیشتری نسبت به آنچه توسط فریمورک دوربین درخواست شده است، نگه دارد. این زمانی است که باید از متد returnStreamBuffers استفاده شود. اگر پیادهسازی HAL هرگز بافرهای بیشتری از آنچه درخواست شده است را در خود نگه ندارد، پیادهسازی دوربین HAL نیازی به فراخوانی متد returnStreamBuffers ندارد.
سیگنالاستریمفلش
متد 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 مراجعه کنید.

شکل ۳. چگونه دوربین HAL باید تماسهای signalStreamFlush را که دیر میرسند، تشخیص داده و مدیریت کند
هنگام پیادهسازی APIهای مدیریت بافر، رفتار تغییر میکند
هنگام استفاده از APIهای مدیریت بافر برای پیادهسازی منطق مدیریت بافر، تغییرات رفتاری احتمالی زیر را در دوربین و پیادهسازی HAL دوربین در نظر بگیرید:
درخواستهای ضبط سریعتر و بیشتر به دوربین HAL میرسند: بدون APIهای مدیریت بافر، چارچوب دوربین قبل از ارسال درخواست ضبط به دوربین HAL، برای هر درخواست ضبط، بافرهای خروجی را درخواست میکند. هنگام استفاده از APIهای مدیریت بافر، چارچوب دوربین دیگر نیازی به انتظار برای بافرها ندارد و بنابراین میتواند درخواستهای ضبط را زودتر به دوربین HAL ارسال کند.
همچنین، بدون APIهای مدیریت بافر، اگر یکی از جریانهای خروجی درخواست ضبط به حداکثر تعداد بافرهایی که HAL میتواند در یک زمان نگه دارد، رسیده باشد، چارچوب دوربین ارسال درخواستهای ضبط را متوقف میکند (این مقدار توسط HAL دوربین در فیلد
HalStream::maxBuffersدر مقدار بازگشتی یک فراخوانیconfigureStreamsتعیین میشود). با APIهای مدیریت بافر، این رفتار محدودکننده دیگر وجود ندارد و پیادهسازی HAL دوربین نباید فراخوانیهایprocessCaptureRequestرا زمانی که HAL درخواستهای ضبط زیادی در صف دارد، بپذیرد.تأخیر فراخوانی
requestStreamBuffersبه طور قابل توجهی متفاوت است: دلایل زیادی وجود دارد که یک فراخوانیrequestStreamBuffersممکن است مدت زمان بیشتری نسبت به حالت معمول طول بکشد. برای مثال:- برای چند بافر اول یک جریان تازه ایجاد شده، فراخوانیها میتوانند بیشتر طول بکشند زیرا دستگاه نیاز به تخصیص حافظه دارد.
- تأخیر مورد انتظار متناسب با تعداد بافرهای درخواستی در هر تماس افزایش مییابد.
- برنامه بافرها را نگه داشته و مشغول پردازش است. این میتواند باعث شود که درخواستهای بافر به دلیل کمبود بافر یا مشغول بودن CPU، کند شوند یا به زمان انقضا برسند.
استراتژیهای مدیریت بافر
رابطهای برنامهنویسی کاربردی (API) مدیریت بافر، امکان پیادهسازی انواع مختلفی از استراتژیهای مدیریت بافر را فراهم میکنند. برخی از نمونهها عبارتند از:
- سازگار با نسخههای قبلی: HAL در طول فراخوانی
processCaptureRequest، برای درخواست ضبط، بافر درخواست میکند. این استراتژی هیچ صرفهجویی در حافظه ایجاد نمیکند، اما میتواند به عنوان اولین پیادهسازی APIهای مدیریت بافر عمل کند و نیاز به تغییرات کد بسیار کمی در دوربین HAL موجود دارد. - حداکثر صرفهجویی در حافظه: دوربین HAL فقط بلافاصله قبل از نیاز به پر شدن بافرهای خروجی، آنها را درخواست میکند. این استراتژی حداکثر صرفهجویی در حافظه را امکانپذیر میسازد. نکته منفی احتمالی، کندی بیشتر خط لوله دوربین است، زمانی که درخواستهای بافر زمان بسیار طولانی برای اتمام نیاز دارند.
- ذخیره شده: دوربین HAL چند بافر را ذخیره میکند تا احتمال کمتری داشته باشد که تحت تأثیر درخواستهای کند بافر قرار گیرد.
دوربین HAL میتواند استراتژیهای مختلفی را برای موارد استفاده خاص اتخاذ کند، به عنوان مثال، از استراتژی حداکثر صرفهجویی در حافظه برای مواردی که از حافظه زیادی استفاده میکنند و از استراتژی سازگار با عقب برای سایر موارد استفاده استفاده کند.
پیادهسازی نمونه در دوربین خارجی HAL
دوربین خارجی HAL در اندروید ۹ معرفی شد و میتوانید آن را در درخت منبع در hardware/interfaces/camera/device/3.5/ پیدا کنید. در اندروید ۱۰، این دوربین بهروزرسانی شده است تا ExternalCameraDeviceSession.cpp ، پیادهسازی API مدیریت بافر، را شامل شود. این دوربین خارجی HAL، استراتژی صرفهجویی حداکثری در حافظه ذکر شده در استراتژیهای مدیریت بافر را در چند صد خط کد C++ پیادهسازی میکند.