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!
Camera2 is the latest low-level Android camera package and replaces the deprecated Camera class. Camera2 provides in-depth controls for complex use cases, but requires you to manage device-specific configurations.
Full: These devices support all of the major capabilities of Camera API2 and must use Camera HAL 3.2 or higher and Android 5.0 or higher. Level_3: These devices support YUV reprocessing and RAW image capture, along with additional output stream configurations on top of full Camera2 API support.
prop in the /system partition of your Android device, you can enable the Camera2 API functionality. First you'll need a rooted phone, and a method of editing your build. prop file. You can either use a root file explorer app (like ES Explorer) to navigate to the /system partition on your phone and open build.
PreviewView is a subclass of FrameLayout . To display the camera feed, it uses either a SurfaceView or TextureView , provides a preview surface to the camera when it's ready, tries to keep it valid as long as the camera is using it, and when released prematurely, provides a new surface if the camera is still in use.
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 new Surface
from mImageReader
Surface mImageSurface = mImageReader.getSurface();
Add that new surface as a output target of your CaptureRequest.Builder
variable. Using the Camera2Basic sample, the variable will be mPreviewRequestBuilder
mPreviewRequestBuilder.addTarget(mImageSurface);
Here's the snippet with the new lines (see my @AngeloS comments):
private void createCameraPreviewSession() { try { SurfaceTexture texture = mTextureView.getSurfaceTexture(); assert texture != null; // We configure the size of default buffer to be the size of camera preview we want. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // This is the output Surface we need to start preview. Surface surface = new Surface(texture); //@AngeloS - Our new output surface for preview frame data Surface mImageSurface = mImageReader.getSurface(); // We set up a CaptureRequest.Builder with the output Surface. mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //@AngeloS - Add the new target to our CaptureRequest.Builder mPreviewRequestBuilder.addTarget(mImageSurface); mPreviewRequestBuilder.addTarget(surface); ...
Next, in setUpCameraOutputs()
, change the format from ImageFormat.JPEG
to ImageFormat.YUV_420_888
when you init your ImageReader
. (PS, I also recommend dropping your preview size for smoother operation - one nice feature of Camera2)
mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2);
Finally, in your onImageAvailable()
method of ImageReader.OnImageAvailableListener
, be sure to use @Kamala's suggestion because the preview will stop after a few frames if you don't close it
@Override public void onImageAvailable(ImageReader reader) { Log.d(TAG, "I'm an image frame!"); Image image = reader.acquireNextImage(); ... if (image != null) image.close(); }
Since the Camera2
API is very different from the current Camera
API, it might help to go through the documentation.
A good starting point is camera2basic
example. It demonstrates how to use Camera2
API and configure ImageReader
to get JPEG images and register ImageReader.OnImageAvailableListener
to receive those images
To receive preview frames, you need to add your ImageReader
's surface to setRepeatingRequest
's CaptureRequest.Builder
.
Also, you should set ImageReader
's format to YUV_420_888
, which will give you 30fps at 8MP (The documentation guarantees 30fps at 8MP for Nexus 5).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With