API управления буфером камеры HAL3

В 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.

Управление буфером в 9 или ниже

Рисунок 1. HAL-интерфейс камеры в Android 9 и ниже

Управление буфером в Android 10

Рис. 2. Интерфейс камеры HAL в Android 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 .

сигнал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++.