What I want to achieve is capturing a picture without showing the preview, sending directly the output to an ImageReader
. I have used the Camera2Basic example as a starting point. However, the callback of my ImageReader
is never called, hence no image is sent to its Surface
. Do I really need to display a preview first?
This is the camera code, which is ordered following the flow of the asynchronous callbacks:
private ImageReader imageReader; private Handler backgroundHandler; private HandlerThread backgroundThread; private String cameraId; private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSession; @Override public void onCreate() { setupCamera2(); } private void setupCamera2() { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { for (String cameraId : manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); if (characteristics.get(CameraCharacteristics.LENS_FACING) != CameraCharacteristics.LENS_FACING_FRONT) { continue; } this.cameraId = cameraId; int[] picSize = Settings.getPictureSize(); int picWidth = picSize[0]; int picHeight = picSize[1]; imageReader = ImageReader.newInstance(picWidth, picHeight, ImageFormat.JPEG, 2); imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler); } } catch (CameraAccessException | NullPointerException e) { e.printStackTrace(); } } private void openCamera2() { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { manager.openCamera(cameraId, cameraStateCallback, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } private final CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice device) { cameraDevice = device; createCameraCaptureSession(); } @Override public void onDisconnected(CameraDevice cameraDevice) {} @Override public void onError(CameraDevice cameraDevice, int error) {} }; private void createCaptureSession() { List<Surface> outputSurfaces = new LinkedList<>(); outputSurfaces.add(imageReader.getSurface()); try { cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { cameraCaptureSession = session; } @Override public void onConfigureFailed(CameraCaptureSession session) {} }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { createCaptureRequest(); } }; private void createCaptureRequest() { try { CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); requestBuilder.addTarget(imageReader.getSurface()); // Focus requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // Orientation int rotation = windowManager.getDefaultDisplay().getRotation(); requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); cameraCaptureSession.capture(requestBuilder.build(), camera2Callback, null); } catch (CameraAccessException e) { e.printStackTrace(); } }
camera2 API for new applications. This class was deprecated in API level 21. We recommend using the new android.
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.
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.
For new apps, we recommend starting with CameraX. It provides a consistent, easy-to-use API that works across the vast majority of Android devices, with backward-compatibility to Android 5.0 (API level 21).
You should capture photos in "onConfigured" function but not onImageAvailable.
public void onConfigured(CameraCaptureSession session) { cameraCaptureSession = session; createCaptureRequest(); }
In this function "onImageAvailable",you should save images,
Image image = mImageReader.acquireLatestImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); try { save(bytes, file); } catch (IOException e) { e.printStackTrace(); } image.close();
"onImageAvailable" function will be invoked after session.capture() .
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