fall back to the next usable camera instead of failing the qr scan on one reporting no resolutions

This commit is contained in:
Craig Raw
2026-08-26 15:35:17 +02:00
parent 5f7770b873
commit 344700f0c4
2 changed files with 33 additions and 21 deletions
@@ -133,7 +133,6 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
List<CaptureDevice> newDevices = new ArrayList<>(webcamService.getAvailableDevices());
newDevices.removeAll(foundDevices);
foundDevices.addAll(newDevices);
foundDevices.removeIf(device -> !webcamService.getDevices().contains(device));
if(webcamService.getDevice() != null) {
for(CaptureDevice device : foundDevices) {
@@ -143,6 +142,8 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
}
}
foundDevices.removeIf(device -> !webcamService.getAvailableDevices().contains(device));
updateList(availableResolutions, webcamService.getResolutions());
webcamResolutionProperty.set(webcamService.getResolution());
} finally {
@@ -189,10 +190,12 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
}
});
webcamDeviceProperty.addListener((_, _, newValue) -> {
Config.get().setWebcamDevice(newValue.getName());
Config.get().setWebcamDeviceId(newValue.getUniqueId());
if(!Objects.equals(webcamService.getDevice(), newValue)) {
webcamService.cancel();
if(newValue != null) {
Config.get().setWebcamDevice(newValue.getName());
Config.get().setWebcamDeviceId(newValue.getUniqueId());
if(!Objects.equals(webcamService.getDevice(), newValue)) {
webcamService.cancel();
}
}
});
@@ -133,15 +133,24 @@ public class WebcamService extends ScheduledService<Image> {
try {
if(devices == null) {
devices = capture.getDevices();
availableDevices = new ArrayList<>(devices);
availableDevices = devices.stream().filter(d -> !d.getFormats().isEmpty()).collect(Collectors.toCollection(ArrayList::new));
List<String> unsupportedDevices = devices.stream().filter(d -> d.getFormats().isEmpty()).map(CaptureDevice::getName).toList();
if(!unsupportedDevices.isEmpty()) {
log.warn("Ignoring cameras with no supported resolutions: " + String.join(", ", unsupportedDevices));
}
if(devices.isEmpty()) {
throw new UnsupportedOperationException("No cameras available");
}
if(availableDevices.isEmpty()) {
throw new UnsupportedOperationException("No resolutions supported by cameras " + String.join(", ", unsupportedDevices));
}
}
while(stream == null && !availableDevices.isEmpty()) {
CaptureDevice selectedDevice = availableDevices.stream().filter(d -> !d.getFormats().isEmpty()).findFirst().orElse(availableDevices.getFirst());
CaptureDevice selectedDevice = availableDevices.getFirst();
if(device != null) {
for(CaptureDevice webcam : availableDevices) {
@@ -165,10 +174,6 @@ public class WebcamService extends ScheduledService<Image> {
device = selectedDevice;
if(device.getFormats().isEmpty()) {
throw new UnsupportedOperationException("No resolutions supported by camera " + device.getName());
}
List<CaptureFormat> deviceFormats = new ArrayList<>(device.getFormats());
//On *nix prioritise supported camera pixel formats, preferring RGB3, then YUYV, then MJPG
@@ -206,23 +211,27 @@ public class WebcamService extends ScheduledService<Image> {
log.debug("Opening capture stream on " + device + " with format " + format.formatInfo().width() + "x" + format.formatInfo().height() + " (" + WebcamPixelFormat.fourCCToString(format.formatInfo().fourcc()) + ")");
}
opening.set(true);
stream = device.openStream(format);
opening.set(false);
try {
zoomLimits = stream.getPropertyLimits(CaptureProperty.ZOOM);
} catch(Throwable e) {
log.debug("Error getting zoom limits on " + device + ", assuming no zoom function");
opening.set(true);
stream = device.openStream(format);
} catch(Exception e) {
log.warn("Error opening capture stream on " + device.getName() + ", trying next available camera", e);
availableDevices.remove(device);
} finally {
opening.set(false);
}
if(stream == null) {
availableDevices.remove(device);
if(stream != null) {
try {
zoomLimits = stream.getPropertyLimits(CaptureProperty.ZOOM);
} catch(Throwable e) {
log.debug("Error getting zoom limits on " + device + ", assuming no zoom function");
}
}
}
if(stream == null) {
throw new UnsupportedOperationException("No usable cameras available, tried " + devices);
throw new UnsupportedOperationException("No usable cameras available, tried " + devices.stream().map(CaptureDevice::getName).collect(Collectors.joining(", ")));
}
opened.set(true);