4

I've been following the camera2 documentation trying to implement a non-previewed camera with an ImageReader, but when I get to cameraDevice.createCaptureSession(outputs, mccsStateCallback, cameraHandler);, the cameraDevice object is null, even though I'm sure it should have been assigned in the CameraCaptureSession.StateCallback event listener (which isn't being triggered either because the CameraCaptureSession itself is null). Either I have this all completely wrong or I've missed something big. Here's my code:

private CameraDevice cameraDevice;
private String cameraId;
private Handler cameraHandler = new Handler();
private CameraCharacteristics cameraCharacteristics;
private ImageReader jpgReader;
Bitmap bitmap;
private Handler imgHandler = new Handler();
private CameraCaptureSession mSession;
private CameraManager cameraManager;

private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        cameraDevice = camera;
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        cameraDevice.close();
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        cameraDevice.close();
        cameraDevice = null;
    }
};

OnImageAvailableListener imageAvailableListener = new OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        Image.Plane[] planes = image.getPlanes();
        Buffer buffer = planes[0].getBuffer().rewind();
        bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
        bitmap.copyPixelsFromBuffer(buffer);
        mFaceOverlayView.setBitmap(bitmap);

    }
};

private CameraCaptureSession.StateCallback mccsStateCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(@NonNull CameraCaptureSession session) {
        try {
            if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(getBaseContext(), android.Manifest.permission.CAMERA)) {
                mSession = session;
                CaptureRequest.Builder request = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                request.addTarget(jpgReader.getSurface());
                mSession.setRepeatingRequest(request.build(), new CameraCaptureSession.CaptureCallback() {
                    @Override
                    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                        super.onCaptureCompleted(session, request, result);
                    }
                }, null);
                cameraManager.openCamera(cameraId, mStateCallback, cameraHandler);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession session) {

    }
};

private void initialiseCamera() {
    cameraManager = (CameraManager) FilesPlayer.this.getSystemService(Context.CAMERA_SERVICE);
    try {
        cameraId = getFrontFacingCameraId(cameraManager);
        if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)) {

            cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);

            StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            android.util.Size[] jpegSizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);

            Size biggestSize = new Size(0, 0);
            for (Size size : jpegSizes) {
                if (size.getHeight() >= biggestSize.getHeight() && size.getWidth() >= biggestSize.getWidth()) {
                    biggestSize = size;
                }
            }
            jpgReader = ImageReader.newInstance(biggestSize.getWidth(), biggestSize.getHeight(), ImageFormat.JPEG, 1);
            jpgReader.setOnImageAvailableListener(imageAvailableListener, imgHandler);
            List<Surface> outputs = Arrays.asList(jpgReader.getSurface());
            cameraDevice.createCaptureSession(outputs, mccsStateCallback, cameraHandler);

        }
        else{
            Log.d("NOOO","NOOOO");
        }

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private String getFrontFacingCameraId(CameraManager cameraManager) {
    try {
        for (String id : cameraManager.getCameraIdList()) {
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
            Integer cameraOrientation = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
            if (cameraOrientation != null && cameraOrientation == CameraMetadata.LENS_FACING_FRONT) {
                return id;
            }
        }

    } catch (CameraAccessException ex) {
        ex.printStackTrace();
    }
    return null;
}

EDIT: I've managed to make the CameraDevice assign itself by placing cameraManager.openCamera(cameraId,mStateCallback,cameraHandler); before cameraDevice.createCaptureSession(outputs, mccsStateCallback, cameraHandler); in initialiseCamera(). Now I'm having an issue where the camera output isn't being directed to the ImageReader's surface, and I'm getting an error in the console saying E/Surface: getSlotFromBufferLocked: unknown buffer: 0xa1ae7000.

Floern
  • 33,559
  • 24
  • 104
  • 119
Kelyn Ferguson
  • 143
  • 2
  • 7
  • After you done with image object in onImageAvailable method, you need to release it by calling `image.close();`. Also I'm not sure, if it's possible to create a bitmap from JPEG just using `bitmap.copyPixelsFromBuffer(buffer);`, because JPEG is compressed format. – Maxim Metelskiy Oct 23 '16 at 10:57

1 Answers1

0

This is a quick note.

Be sure to include permission in Manifest. Also be sure that the user can grant permission to the app through ActivityCompact and ContextCompact. On Android 6.0 and above, permissions are also granted at runtime by the user. See docs here.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Permission is not granted
    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
        // Show an explanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.
    } else {
        // No explanation needed; request the permission
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
} else {
    // Permission has already been granted
}