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. Интерфейс Camera HAL в Android 9 и более ранних версиях.

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

Рисунок 2. Интерфейс Camera 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 .

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, что означает, что платформа камеры может вызывать другие блокирующие API до того, как HAL получит вызов signalStreamFlush . Это означает, что метод signalStreamFlush и другие методы (в частности, метод configureStreams ) могут поступать в HAL камеры в другом порядке, чем порядок их вызова в платформе камеры. Для решения этой проблемы асинхронности в StreamConfiguration было добавлено поле streamConfigCounter , которое также было добавлено в качестве аргумента к методу 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++.