Android Camera2: доступ CPU/GPU к данным изображения и MediaRecorder/MediaCodec в одном конвейереAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Гость
 Android Camera2: доступ CPU/GPU к данным изображения и MediaRecorder/MediaCodec в одном конвейере

Сообщение Гость »


Я занимаюсь сопровождением популярной кроссплатформенной библиотеки мобильных камер, которая может одновременно выполнять предварительный просмотр, захват фотографий, захват видео и обработку кадров. На iOS это работает отлично. Но на Android это практически невозможно сделать с помощью API Camera2/android.media.

Моя структура на высоком уровне:


Изображение


Важная деталь: VideoPipeline будет выполнять обработку кадров/анализ изображений и запись видео в одном, то есть синхронно.
[*]Мне нужен доступ к буферу CPU/GPU к собственному кадру [*]Мне нужно, чтобы формат кадра можно было настраивать (YUV_420_888, PRIVATE, RGBA_8888) [*]Мне нужно, чтобы он был синхронным (он же сначала запускается MLKit Frame Processor, затем запускается MediaRecorder/MediaCodec; таким образом я могу применять такие вещи, как фильтры лиц, если это необходимо) [*]MediaRecorder/MediaCodec записывает кадр в видеофайл h264/h265 (.mp4).
Кажется, что с Camera2 это вообще невозможно, верно?

Несколько потенциальных решений/идей, которые у меня были:
1. Отдельные выходы
Использовать отдельные выходы камеры, MediaRecorder и ImageReader. Не работает, поскольку камера поддерживает только 3 выхода. У нас уже есть 3 (превью, фото, видео).
2. Используйте ImageReader/ImageWriter, чтобы передать его

Изображение


Это самое близкое решение, которое у меня было до сих пор, и кажется, что ImageReader/ImageWriter действительно эффективны, поскольку они просто перемещают буферы (по крайней мере, на самом деле). Но у этого подхода есть несколько проблем:
[*]
Это работает не на всех устройствах. Не гарантируется, что MediaRecorder/MediaCodec может быть загружен изображениями из ImageWriter, поэтому иногда он просто вылетает > 🤦‍♂️
[*]
Похоже, что для этого требуется установить флаги графического процессора (только API 29), но даже они в большинстве случаев не работают:

val flags = HardwareBuffer.USAGE_VIDEO_ENCODE или HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE val readFormat = ImageFormat.YUV_420_888 // (может быть YUV, PRIVATE или RGBA_8888) imageReader = ImageReader.newInstance(ширина, высота, ReaderFormat, MAX_IMAGES, флаги) // ... вал mediaRecorder = ... mediaRecorder.prepare() val writeFormat = readFormat // или теперь это должно быть ImageFormat.PRIVATE??? imageWriter = ImageWriter.newInstance(mediaRecorder.surface, MAX_IMAGES, writeFormat) imageReader.setOnImageAvailableListener({читатель -> val image = reader.acquireNextImage() если (isRecording) imageWriter.queueInputImage(изображение) еще изображение.закрыть() }, обработчик) configureCamera(imageReader.surface, ...) // позже: mediaRecorder.start() [*]Насколько я понимаю, для этого требуется дополнительный шаг преобразования из моего формата в любой формат, который хочет MediaRecorder/MediaCodec. Поэтому мне может понадобиться дополнительный ImageReader в формате PRIVATE:
Изображение


...что просто смешно.
[*]
Он не поддерживает переворот камеры (сзади спереди) во время записи, поскольку ширина/высота буферов изображений может измениться, и это может привести к изменению в этом конвейере нет этапа масштабирования/изменения размера.
3. Создайте собственный конвейер OpenGL
Создаем собственный конвейер OpenGL, в который будет выполняться рендеринг камеры, а затем выполняем сквозной проход рендеринга для рендеринга кадра на все выходные данные:


Изображение


Но у этого решения есть четыре основных недостатка:
[*]Это действительно очень сложно построить (я уже построил это, см. этот PR, так что это не проблема, если честно) [*]Похоже, что это не так эффективно, как подход ImageReader/ImageWriter, поскольку мы выполняем неявное преобразование RGB и фактический проход рендеринга, тогда как ImageReader /ImageWriter просто перемещает буферы изображений (по крайней мере, насколько я это понимаю) [*]Он работает только в RGBA_8888, так как OpenGL работает в RGB. Это означает, что наш процессор кадров (MLKit) не работает, если он обучен на данных YUV_420_888 — это жесткое требование. [*]Это не синхронно, ImageReader вызывается позже. Мы не могли использовать информацию из фрейма, чтобы решить, что будет отображаться позже (например, чтобы применить фильтр лица).
На данный момент я совершенно ничего не знаю, если честно. Неужели синхронный видеоконвейер вообще невозможен в Android?

Мои требования:
[*]У меня нет проблем с использованием C++/JNI для этого [*]Минимальный уровень API не имеет значения. Если только 33, то это то, что есть.
Я буду признателен за любые подсказки/помощь, возможно, я не знаю некоторых хороших API. Спасибо!
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»