Skip to content

Commit

Permalink
Force reinit of c2 view on surface change #150
Browse files Browse the repository at this point in the history
The problem was that sometimes `onMeasure()` was being called after the
preview was initialized, so the `startPreview()` call in the
`onSurfaceChanged()` method would not do anything.

The only way to force a reset of the preview is to pause and resume it,
so the capture session is destroyed and can be properly recreated with
the new resolutions.

This added the issue of concurrent calls to `startPreview()`, some which
were actually needed to update the resolution, while others were not. As
we cannot create multiple captureSessions, we have to wait for the
ongoing init to finish before destroying the session and calling the
method again.
  • Loading branch information
DaSpood committed May 14, 2024
1 parent 69ed577 commit 30ea720
Showing 1 changed file with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class CameraBarcodeScanViewV2 extends CameraBarcodeScanViewBase<Image> {
private String cameraId;
private CameraManager cameraManager;

private int concurrentCameraSessionInitAttempt = 0;
private CameraCaptureSession captureSession;
private CaptureRequest.Builder captureRequestBuilder;
private CaptureRequest captureRequest;
Expand Down Expand Up @@ -569,7 +570,11 @@ public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int pixelFormat, int newWidth, int newHeight) {
Log.i(TAG, "surface changed " + this.hashCode());
camPreviewSurfaceView.post(this::startPreview);

// Force a full re-init of the view to ensure resolution is up to date.
pauseCamera();
resumeCamera();
//camPreviewSurfaceView.post(this::startPreview);
}

@Override
Expand Down Expand Up @@ -650,8 +655,25 @@ private synchronized void startPreview() {
Log.d(TAG, "Camera device not ready yet");
return;
}

// Handling of the case where resolution was changed while init was ongoing
this.concurrentCameraSessionInitAttempt++;
if (this.concurrentCameraSessionInitAttempt > 1) {
Log.i(TAG, "A camera session is already being initialized, will re-init later");
Log.d(TAG, concurrentCameraSessionInitAttempt + " concurrent attempts");
return;
}

// This block needs to be AFTER the concurrent init check, because if an init is already in
// progress, pauseCamera() will not run and imageReader will not be null, but we still want to
// queue a re-init for later.
// If this block is reached, it means there is no ongoing initialization, so if imageReader is
// not null here, it cannot be due to pauseCamera() not running, so it is safe to return without
// initializing.
// Basically: a hack to deal with race conditions.
if (this.imageReader != null) {
Log.d(TAG, "Image reader already created");
this.concurrentCameraSessionInitAttempt--;
return;
}

Expand Down Expand Up @@ -756,6 +778,15 @@ public void onConfigured(@NonNull final CameraCaptureSession cameraCaptureSessio
}

Log.i(TAG, "Camera repeating capture request was set up " + CameraBarcodeScanViewV2.this.hashCode());

// Handling of the case where resolution was changed while init was ongoing
concurrentCameraSessionInitAttempt--;
if (concurrentCameraSessionInitAttempt > 0) {
Log.i(TAG, "More recent initialization attempts were made, re-initializing capture session");
concurrentCameraSessionInitAttempt = 0;
pauseCamera();
resumeCamera();
}
}

@Override
Expand Down

0 comments on commit 30ea720

Please sign in to comment.