You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a Camera library that can do preview, photo capture, video capture, and frame processing at the same time. On iOS, this works perfectly. But on Android, it actually seems to be impossible to do this with Camera2/android.media APIs.
Important detail: The VideoPipeline would do Frame Processing/ImageAnalysis and Video Recording in one, aka synchronous.
MLKit Image Processing requires either YUV_420_888, PRIVATE or RGBA_8888 buffers, so this pipeline should work for all 3 pixel formats.
MediaRecorder/MediaCodec records the Frame to a h264/h265 video file (.mp4).
It seems like this is not possible with Camera2 at all, right?
Few potential solutions/ideas I had:
1. Separate outputs
Use separate Camera outputs, MediaRecorder and ImageReader - Does not work because the Camera only allows 3 outputs. We already have 3 (preview, photo, video).
This is the closest solution I had so far, and it seems like ImageReader/ImageWriter are really efficient as they are just moving buffers around. But there are multiple problems with this approach:
It does not work on every device. It is not guaranteed that MediaRecorder/MediaCodec can be fed with Images from an ImageWriter, so sometimes it just silently crashes 🤦♂️
It seems like it requires the GPU flags to be set - API 29 only - but even those don't really work most of the time:
val flags =HardwareBuffer.USAGE_VIDEO_ENCODEorHardwareBuffer.USAGE_GPU_SAMPLED_IMAGEval readerFormat =ImageFormat.YUV_420_888// (or PRIVATE or RGBA_8888)
imageReader =ImageReader.newInstance(width, height, readerFormat, MAX_IMAGES, flags) // <-- API 29+// ...val mediaRecorder =...
mediaRecorder.prepare()
val writerFormat = readerFormat // or does this now need to be ImageFormat.PRIVATE???
imageWriter =ImageWriter.newInstance(mediaRecorder.surface, MAX_IMAGES, writerFormat) // <-- API 29+
imageReader.setOnImageAvailableListener({ reader ->val image = reader.acquireNextImage()
imageWriter.queueInputImage(image)
}, handler)
As far as I understand, it requires an additional conversion step from my format to whatever format the MediaRecorder/MediaCodec wants. So I might need an additional ImageReader that has the PRIVATE format:
It does not support Camera flipping (back <-> front) while recording, because the width/height of the Image Buffers might change and there is no scaling/resizing step in this pipeline.
3. Create a custom OpenGL Pipeline
Create a custom OpenGL pipeline that the Camera will render to, then we do a pass-through render pass to render the Frame to all the outputs:
It's really really complex to build (I already built it, see this PR, so not a real problem tbh)
It seems like this is not as efficient as a ImageReader/ImageWriter approach, as we do an implicit RGB conversion and an actual render pass, whereas ImageReader/ImageWriter just moving Image Buffers around (at least as far as I understood this)
It only works in RGBA_8888, as OpenGL works in RGB. This means, our frame processor (MLKit) does not work if it is trained on YUV_420_888 data - this is a hard requirement.
It is not synchronous, the ImageReader gets called at a later point. We could not really use information from the Frame to decide what gets rendered later (e.g. to apply a face filter).
At this point I'm pretty clueless tbh. Is a synchronous video pipeline simply not possible at all in Android? I'd appreciate any pointers/help here, maybe I'm not aware of some great APIs.
I only need CPU/GPU buffer access to the native Frame, but I need the format to be configurable (YUV, PRIVATE, RGB), and I need it to be synchronous - e.g. block before Frame is written to MediaRecorder.
Also happy to pay $150/h for consultancy sessions if anyone knows more.
The text was updated successfully, but these errors were encountered:
Hey all!
I have a Camera library that can do preview, photo capture, video capture, and frame processing at the same time. On iOS, this works perfectly. But on Android, it actually seems to be impossible to do this with Camera2/android.media APIs.
This is my structure:
Important detail: The
VideoPipeline
would do Frame Processing/ImageAnalysis and Video Recording in one, aka synchronous.It seems like this is not possible with Camera2 at all, right?
Few potential solutions/ideas I had:
1. Separate outputs
Use separate Camera outputs,
MediaRecorder
andImageReader
- Does not work because the Camera only allows 3 outputs. We already have 3 (preview, photo, video).2. Use
ImageReader
/ImageWriter
to pass it throughThis is the closest solution I had so far, and it seems like
ImageReader
/ImageWriter
are really efficient as they are just moving buffers around. But there are multiple problems with this approach:It does not work on every device. It is not guaranteed that
MediaRecorder
/MediaCodec
can be fed with Images from anImageWriter
, so sometimes it just silently crashes 🤦♂️It seems like it requires the GPU flags to be set - API 29 only - but even those don't really work most of the time:
As far as I understand, it requires an additional conversion step from my format to whatever format the
MediaRecorder
/MediaCodec
wants. So I might need an additionalImageReader
that has the PRIVATE format:...which is just ridiculous.
It does not support Camera flipping (back <-> front) while recording, because the
width
/height
of the Image Buffers might change and there is no scaling/resizing step in this pipeline.3. Create a custom OpenGL Pipeline
Create a custom OpenGL pipeline that the Camera will render to, then we do a pass-through render pass to render the Frame to all the outputs:
But, this has four major drawbacks:
ImageReader
/ImageWriter
approach, as we do an implicit RGB conversion and an actual render pass, whereasImageReader
/ImageWriter
just moving Image Buffers around (at least as far as I understood this)ImageReader
gets called at a later point. We could not really use information from the Frame to decide what gets rendered later (e.g. to apply a face filter).At this point I'm pretty clueless tbh. Is a synchronous video pipeline simply not possible at all in Android? I'd appreciate any pointers/help here, maybe I'm not aware of some great APIs.
I only need CPU/GPU buffer access to the native Frame, but I need the format to be configurable (YUV, PRIVATE, RGB), and I need it to be synchronous - e.g. block before Frame is written to MediaRecorder.
Also happy to pay $150/h for consultancy sessions if anyone knows more.
The text was updated successfully, but these errors were encountered: