Предварительный обратный вызов в Camera2 значительно медленнее, чем в Camera1
Это 2017 год, и я, наконец, начинаю переключение с Camera1 на Camera2. В Camera1 я очень полагался на setPreviewCallbackWithBuffer()
для выполнения обработки в реальном времени, однако в Camera2 это работает намного медленнее до такой степени, что становится почти непригодным.
Для сравнения, на Moto G3 Camera1 можно легко производить 30-40 FPS, а на Camera2 я не мог получить более 10-15 FPS.
Вот как я создаю ImageReader
imageReader = ImageReader
.newInstance(
previewSize.width, // size is around 1280x720
previewSize.height,
ImageFormat.YUV_420_888, // note, it is not JPEG
2 // max number of images, does not really affect performance
);
imageReader.setOnImageAvailableListener(
callback,
CameraThread.getInstance().createHandler()
);
Сам обратный вызов выполняет минимально возможное задание:
Image image = reader.acquireNextImage();
image.close();
Я уже проверил аналогичные ответы, например этот. Однако их проблема заключается в том, что они используют JPEG
формат изображения вместо YUV_420_888
.
Как добиться производительности, аналогичной Camera1?
Ответы
Ответ 1
Это просто наблюдение, но я все равно отправлю его.
Вы говорите, что регистрируете OnImageAvailableListener. Этот слушатель не доставляет изображения, а ссылку на тот же ImageReader
, на который вы подписаны. И тогда вы должны позвонить либо acquireLatestImage
, либо acquireNextImage
, чтобы получить фактическое изображение.
В docs есть абзац, который может быть полезен для понимания того, что происходит:
Данные изображения инкапсулируются в объекты Image
, и к ним можно одновременно обращаться к нескольким таким объектам, вплоть до числа, указанного параметром конструктора maxImages
. Новые изображения, отправленные на ImageReader
через его поверхность, помещаются в очередь до тех пор, пока не будут доступны через вызов acquireLatestImage()
или acquireNextImage()
. Из-за ограничений памяти источник изображения в конечном итоге сдерживает или удаляет изображения при попытке визуализации на поверхность, если ImageReader
не получает и не отпускает изображения со скоростью, равной скорости производства.
Итак, некоторые вещи, которые могут помочь:
- запрос большой памяти в манифесте
- Передайте достаточно большой аргумент
maxImages
конструктору ImageReader
(вы получите IllegalStateException
, если вы все равно исчерпаете очередь).
- Предпочитает
acquireLatestImage
более acquireNextImage
для обработки в реальном времени. Этот метод автоматически удаляет старые изображения, а другой - нет, и, следовательно, использование acquireNextImage
по ошибке будет все более замедлять доставку изображений до тех пор, пока вы не исчерпаете память.
Ответ 2
У меня были те же проблемы с производительностью в приложении, поддерживающем как Camera1, так и Camera2 API. Когда версия Android была выше Lollipop, я использовал для переключения на Camera2 API, что приводило к очень плохим результатам (у меня было две цели: ImageReader и Surface).
Я закончил использовать Camera2 API только тогда, когда по телефону была полная аппаратная поддержка. Вы можете проверить, используя CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL
Надеюсь, что это поможет