Camera2API: session closed; further changes are illegal

I am using Camera2API to create a camera activity that sends the received image to another activity. On some devices this works, but on others (slower) I get a java.lang.IllegalStateException that says "Session closed, further changes are illegal."

I am getting this exception on this line (in updatePreview ()):

cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);

      

Here is my complete code:

public class NewCamera extends CustomActivity implements TimingActivity {

private static final String TAG = "NewCamera";
private ImageView takePictureButton;
private TextureView textureView;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

private String cameraId;
protected CameraDevice cameraDevice;
protected CameraCaptureSession cameraCaptureSessions;
protected CaptureRequest.Builder captureRequestBuilder;
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
private Size imageDimension;
private ImageReader imageReader;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.new_camera);

    textureView = (TextureView) findViewById(R.id.textureView);
    textureView.setSurfaceTextureListener(textureListener);
    takePictureButton = (ImageView) findViewById(R.id.capture);
    takePictureButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            takePicture();
            captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            finish();
        }
    });

    changeFlashImage();
}

TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        //open your camera here

        //transfromImage(width, height);
        openCamera();
    }
    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // Transform you image captured size according to the surface width and height
    }
    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }
    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
};
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {
        mCameraOpenCloseLock.release();
        cameraDevice = camera;
        createCameraPreview();
    }

    @Override
    public void onDisconnected(CameraDevice camera) {
        mCameraOpenCloseLock.release();
        camera.close();
        cameraDevice = null;
    }

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

        safeDestroy();
    }
};
final CameraCaptureSession.CaptureCallback captureCallbackListener = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
        super.onCaptureCompleted(session, request, result);
        createCameraPreview();
    }
};

private void safeDestroy() {
    Intent intent = getIntent();
    finish();
    startActivity(intent);
}

protected void startBackgroundThread() {
    mBackgroundThread = new HandlerThread("Camera Background");
    mBackgroundThread.start();
    mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}

protected void stopBackgroundThread() {
    mBackgroundThread.quitSafely();
    try {
        mBackgroundThread.join();
        mBackgroundThread = null;
        mBackgroundHandler = null;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

protected void takePicture() {
    if(null == cameraDevice) {
        Log.e(TAG, "cameraDevice is null");
        return;
    }
    try {
        ImageReader reader = ImageReader.newInstance(imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.JPEG, 1);
        List<Surface> outputSurfaces = new ArrayList<Surface>(2);
        outputSurfaces.add(reader.getSurface());
        outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureRequestBuilder.addTarget(reader.getSurface());
        captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 100);

        switch(Preferences.getInstance().flashMode % 2) {
            case 0:
                //off
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                break;
            case 1:
                //on
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                break;
        }

        // Orientation
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
        ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                ByteBuffer buffer = reader.acquireLatestImage().getPlanes()[0].getBuffer();
                byte[] bytes = new byte[buffer.capacity()];
                buffer.get(bytes);

                //handle bytes - pass to another activity
            }
        };

        reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
        final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
            }
        };
        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.capture(captureRequestBuilder.build(), captureListener, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onConfigureFailed(CameraCaptureSession session) {
                safeDestroy();
            }
        }, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

protected void createCameraPreview() {
    try {
        SurfaceTexture texture = textureView.getSurfaceTexture();

        if(texture == null) {
            return;
        }

        texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
        Surface surface = new Surface(texture);
        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        captureRequestBuilder.addTarget(surface);
        captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 100);
        cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){
            @Override
            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                //The camera is already closed
                if (null == cameraDevice) {
                    return;
                }
                // When the session is ready, we start displaying the preview.
                cameraCaptureSessions = cameraCaptureSession;
                updatePreview();
            }
            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

            }
        }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}
private void openCamera() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
            || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(NewCamera.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
        return;
    }
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    Log.e(TAG, "is camera open");
    try {
        cameraId = manager.getCameraIdList()[0];
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
        StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        assert map != null;
        imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
        transfromImage(textureView.getWidth(), textureView.getHeight());
        manager.openCamera(cameraId, stateCallback, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
    Log.e(TAG, "openCamera X");
}
protected void updatePreview() {
    if(null == cameraDevice) {
        Log.e(TAG, "updatePreview error, return");
    }
    captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    try {
        cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

@Override
protected void onRestart() {
    super.onRestart();

    changeFlashImage();
}

@Override
protected void onResume() {
    super.onResume();

    changeFlashImage();
    startBackgroundThread();

    if (textureView.isAvailable()) {
        openCamera();
    } else {
        textureView.setSurfaceTextureListener(textureListener);
    }
}
@Override
protected void onPause() {
    closeCamera();
    stopBackgroundThread();
    super.onPause();
}

private void closeCamera() {
    try {
        mCameraOpenCloseLock.acquire();
        if (cameraCaptureSessions != null) {
            cameraCaptureSessions.close();
            cameraCaptureSessions = null;
        }

        if (cameraDevice != null) {
            cameraDevice.close();
            cameraDevice = null;
        }

        if (null != imageReader) {
            imageReader.close();
            imageReader = null;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
    } finally {
        mCameraOpenCloseLock.release();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if(cameraCaptureSessions!=null){
        cameraCaptureSessions.close();
        cameraCaptureSessions=null;
    }
    if (cameraDevice!=null){
        cameraDevice.close();
        cameraDevice=null;

        if(imageReader!=null){
            imageReader.close();
            imageReader=null;

        }
    }
}

private void transfromImage (int width, int height) {
    Matrix matrix = new Matrix();
    int rotation = getWindowManager().getDefaultDisplay().getRotation();
    RectF textureRectF = new RectF(0, 0, width, height);
    RectF previewRectF = new RectF(0, 0, imageDimension.getHeight(), imageDimension.getWidth());
    float centerX = textureRectF.centerX();
    float centerY = textureRectF.centerY();

    if ((rotation == Surface.ROTATION_90) || (rotation == Surface.ROTATION_270)) {
        previewRectF.offset(centerX - previewRectF.centerX(), centerY - previewRectF.centerY());
        matrix.setRectToRect(textureRectF, previewRectF, Matrix.ScaleToFit.FILL);
        float scale = Math.max ((float) width / imageDimension.getWidth(), (float)height / imageDimension.getHeight());
        matrix.postScale(scale, scale, centerX, centerY);
        matrix.postRotate(90 * (rotation - 2), centerX, centerY);
    }

    textureView.setTransform(matrix);
}

public void changeFlashImage() {
    ImageView ivFlash = (ImageView) findViewById(R.id.flash);

    switch(Preferences.getInstance().flashMode % 2) {
        case 0:
            ivFlash.setImageResource(R.drawable.flash_off);
            break;
        case 1:
            ivFlash.setImageResource(R.drawable.flash_on);
            break;
    }
}

public void changeFlash(View view) {
    Preferences.getInstance().flashMode++;
    changeFlashImage();
}
}

      

I am getting this exception when the camera activity is started. When this happens, textureView is not updated. I don't have much experience with Camera2API. Many thanks to the people who are ready to help!

+3


source to share


1 answer


Check if all camera settings have been set with flags, as you should give some delay to the repeatatingRequest of your mCaptureSession while it configures the configuration for you in parallel in the background. In my case, I resolved this exception by setting a delay of 500ms to set a repeating request like this:

new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                        mCaptureCallback, null);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e);
            } catch (IllegalStateException e) {
                Log.e(TAG, "Failed to start camera preview.", e);
            }
        }
    }, 500);

      



All the best, happy coding :-)

0


source







All Articles