В 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 камеры о необходимости возврата буферов.
запрос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
Используйте метод 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++.