Hello colleagues,
I'm trying to make an app that takes video and pictures.
I have two fragments each with TextureViews. One fragment handles ImageCapture while the other handles VideoCapture. In my main activity I have the FragmentLayout and a button to replace one fragment with the other. However, I get an error with BufferedQueue saying that the surface is 'already connected' when I try to switch. I don't understand what the problem is. I call CameraX.unbindAll() when switching fragments and set up the preview each time, not only that but the previews and TextureViews are separated into their own fragments. What is 'already connected'?
private void startCamera() {
CameraX.unbindAll();
Rational aspectRatio = new Rational(textureView.getWidth(), textureView.getHeight());
Size screen = new Size(textureView.getWidth(), textureView.getHeight());
pConfig = new PreviewConfig.Builder().setTargetAspectRatio(aspectRatio).setTargetResolution(screen).build();
}
private void setupPictures() {
preview = new Preview(pConfig);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(Preview.PreviewOutput output) {
ViewGroup parent = (ViewGroup) textureView.getParent();
parent.removeView(textureView);
parent.addView(textureView);
textureView.setSurfaceTexture(output.getSurfaceTexture());
updateTransform();
}
});
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY).
setTargetRotation(getActivity().getWindowManager().getDefaultDisplay().getRotation()).build();
final ImageCapture imgCap = new ImageCapture(imageCaptureConfig);
view.findViewById(R.id.snap_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
File imageOutputFile = createOutputFile(true);
imgCap.takePicture(imageOutputFile, new ImageCapture.OnImageSavedListener() {
@Override
public void onImageSaved(@NonNull File file) {
String msg = "Pic capture at " + file.getAbsolutePath();
Toast.makeText(getActivity().getBaseContext(), msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause) {
String msg = "Pic Capture failed: " + message;
Toast.makeText(getActivity().getBaseContext(), msg, Toast.LENGTH_SHORT).show();
if (cause != null) {
cause.printStackTrace();
}
}
});
}
});
CameraX.bindToLifecycle(this, preview, imgCap);
}
I believe this is all that is necessary for the camera. I left out all the other code from the fragment since it doesn't have to do anything with the CameraX I don't think. This is for pictures. The video class looks the same except it's using VideoCapture.