اندروید 10 APIهای اختیاری مدیریت بافر دوربین HAL3 را معرفی می کند که به شما امکان می دهد منطق مدیریت بافر را برای دستیابی به حافظه های مختلف و ثبت معاوضه تاخیر در اجرای HAL دوربین پیاده سازی کنید.
دوربین HAL به N درخواست (که در آن N برابر با عمق خط لوله است) در خط لوله خود نیاز دارد، اما اغلب به همه N مجموعه بافرهای خروجی به طور همزمان نیاز ندارد.
برای مثال، HAL ممکن است هشت درخواست در صف خط لوله داشته باشد، اما فقط به بافرهای خروجی برای دو درخواست در آخرین مراحل خط لوله نیاز دارد. در دستگاههایی که اندروید 9 و پایینتر دارند، چارچوب دوربین زمانی که درخواست در HAL در صف قرار میگیرد، بافرها را اختصاص میدهد، بنابراین ممکن است شش مجموعه بافر در HAL وجود داشته باشد که استفاده نمیشوند. در اندروید 10، API های مدیریت بافر دوربین HAL3 امکان جداسازی بافرهای خروجی را برای آزاد کردن شش مجموعه بافر فراهم می کند. این می تواند به صدها مگابایت صرفه جویی در حافظه در دستگاه های پیشرفته منجر شود و همچنین می تواند برای دستگاه های با حافظه کم مفید باشد.
شکل 1 نمودار رابط HAL دوربین را برای دستگاههای دارای اندروید 9 و پایینتر نشان میدهد. شکل 2 رابط دوربین HAL را در اندروید 10 با 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 دوربین سیگنال دهد تا بافرها را برگرداند.
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++ اجرا می کند.