В Android 10 представлены дополнительные API-интерфейсы управления буфером камеры HAL3 , которые позволяют реализовать логику управления буфером для достижения различных компромиссов в отношении памяти и задержки в реализациях камеры HAL.
Камера HAL требует N запросов (где N равно глубине конвейера ), поставленных в очередь в конвейере, но часто не требует всех N наборов выходных буферов одновременно.
Например, HAL может иметь восемь запросов в очереди в конвейере, но ему требуются выходные буферы только для двух запросов на последних этапах конвейера. На устройствах под управлением Android 9 и более ранних версий платформа камеры выделяет буферы, когда запрос ставится в очередь в HAL, поэтому в HAL может быть шесть наборов буферов, которые не используются. В Android 10 API-интерфейсы управления буфером HAL3 камеры позволяют отделить выходные буферы, чтобы освободить шесть наборов буферов. Это может привести к экономии сотен мегабайт памяти на высокопроизводительных устройствах, а также может быть полезно для устройств с малым объемом памяти.
На рисунке 1 представлена схема HAL-интерфейса камеры для устройств под управлением Android 9 и ниже. На рис. 2 показан интерфейс камеры HAL в Android 10 с реализованными API-интерфейсами управления буфером камеры HAL3.
Рисунок 1. HAL-интерфейс камеры в Android 9 и ниже
Рис. 2. Интерфейс камеры HAL в Android 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
.
сигналStreamFlush
Метод 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, а это означает, что платформа камеры может вызывать другие блокирующие API до того, как HAL получит вызов signalStreamFlush
. Это означает, что метод 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-интерфейсами управления буфером это поведение регулирования больше не существует, и реализация HAL камеры не должна принимать вызовыprocessCaptureRequest
когда в очереди HAL слишком много запросов на захват.Задержка вызова
requestStreamBuffers
значительно различается: существует множество причин, по которым вызовrequestStreamBuffers
может занимать больше времени, чем в среднем. Например:- Для первых нескольких буферов вновь созданного потока вызовы могут занять больше времени, поскольку устройству необходимо выделить память.
- Ожидаемая задержка увеличивается пропорционально количеству буферов, запрошенных при каждом вызове.
- Приложение удерживает буферы и занято обработкой. Это может привести к замедлению запросов к буферу или истечению времени ожидания из-за нехватки буферов или загруженности ЦП.
Стратегии управления буфером
API управления буфером позволяют реализовать различные виды стратегий управления буфером. Некоторые примеры:
- Обратная совместимость: HAL запрашивает буферы для запроса захвата во время вызова
processCaptureRequest
. Эта стратегия не обеспечивает никакой экономии памяти, но может служить первой реализацией API-интерфейсов управления буфером, требуя очень небольшого изменения кода в существующем HAL камеры. - Максимальная экономия памяти: камера HAL запрашивает выходные буферы только непосредственно перед тем, как один из них необходимо заполнить. Эта стратегия обеспечивает максимальную экономию памяти. Потенциальным недостатком является более частый рывок конвейера камеры, когда запросы к буферу занимают необычно много времени.
- Кэширование: камера HAL кэширует несколько буферов, чтобы на нее с меньшей вероятностью повлиял случайный медленный запрос буфера.
Камера HAL может использовать разные стратегии для конкретных вариантов использования, например, используя стратегию максимального сохранения памяти для вариантов использования, которые используют много памяти, и используя стратегию обратной совместимости для других вариантов использования.
Пример реализации во внешней камере HAL
Внешняя камера HAL была представлена в Android 9, и ее можно найти в дереве исходного кода в hardware/interfaces/camera/device/3.5/
. В Android 10 он был обновлен и теперь включает ExternalCameraDeviceSession.cpp
— реализацию API управления буфером. Эта внешняя камера HAL реализует стратегию максимальной экономии памяти, упомянутую в разделе «Стратегии управления буфером » в нескольких сотнях строк кода C++.