I'm working on an android app that is processing the input image from the camera and displays it to the user. This is fairly simple, I register a PreviewCallback
on the camera object with the setPreviewCallbackWithBuffer
.
This is easy and works smoothly with the old camera API
public void onPreviewFrame(byte[] data, Camera cam) {
// custom image data processing
}
I'm trying to port my app to take advantage of the new Camera2 API and I'm not sure how exactly shall I do that. I followed the Camera2Video in L Preview samples that allows to record a video. However, there is no direct image data transfer in the sample, so I don't understand where exactly shall I get the image pixel data and how to process it.
Could anybody help me or suggest the way how one can get the the functionality of PreviewCallback
in android L, or how it's possible to process preview data from the camera before displaying it to the screen? (there is no preview callback on the camera object)
Thank you!
It's better to init
ImageReader
with max image buffer is2
then usereader.acquireLatestImage()
insideonImageAvailable()
.Because
acquireLatestImage()
will acquire the latest Image from the ImageReader's queue, dropping older one. This function is recommended to use overacquireNextImage()
for most use-cases, as it's more suited for real-time processing. Note that max image buffer should be at least2
.And remember to
close()
your image after processing.I needed the same thing, so I used their example and added a call to a new function when the camera is in preview state.
The
savePreviewShot()
is simply a recycled version of the originalcaptureStillPicture()
adapted to use the preview template.Since the
Camera2
API is very different from the currentCamera
API, it might help to go through the documentation.A good starting point is
camera2basic
example. It demonstrates how to useCamera2
API and configureImageReader
to get JPEG images and registerImageReader.OnImageAvailableListener
to receive those imagesTo receive preview frames, you need to add your
ImageReader
's surface tosetRepeatingRequest
'sCaptureRequest.Builder
.Also, you should set
ImageReader
's format toYUV_420_888
, which will give you 30fps at 8MP (The documentation guarantees 30fps at 8MP for Nexus 5).In the ImageReader.OnImageAvailableListener class, close the image after reading as shown below (this will release the buffer for next capture). You will have to handle exception on close
Combining a few answers into a more digestible one because @VP's answer, while technically clear, is difficult to understand if it's your first time moving from Camera to Camera2:
Using https://github.com/googlesamples/android-Camera2Basic as a starting point, modify the following:
In
createCameraPreviewSession()
init a newSurface
frommImageReader
Add that new surface as a output target of your
CaptureRequest.Builder
variable. Using the Camera2Basic sample, the variable will bemPreviewRequestBuilder
Here's the snippet with the new lines (see my @AngeloS comments):
Next, in
setUpCameraOutputs()
, change the format fromImageFormat.JPEG
toImageFormat.YUV_420_888
when you init yourImageReader
. (PS, I also recommend dropping your preview size for smoother operation - one nice feature of Camera2)Finally, in your
onImageAvailable()
method ofImageReader.OnImageAvailableListener
, be sure to use @Kamala's suggestion because the preview will stop after a few frames if you don't close it