now runs much better with lower power systems as we refactored code to firstly rule out double invokelaters, and we optimized the capture loop iteslf! and we introduced a ShowError class which will be refactored and used quite thoroughly! Signed-off-by: rattatwinko <seppmutterman@gmail.com>
123 lines
3.9 KiB
Java
123 lines
3.9 KiB
Java
package io.swtc.proccessing;
|
|
|
|
import com.github.sarxos.webcam.Webcam;
|
|
import com.github.sarxos.webcam.WebcamException;
|
|
import com.github.sarxos.webcam.WebcamResolution;
|
|
|
|
import java.awt.Dimension;
|
|
import java.awt.image.BufferedImage;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.concurrent.locks.LockSupport;
|
|
import java.util.function.Consumer;
|
|
import javax.swing.*;
|
|
|
|
import io.swtc.proccessing.ui.ShowError;
|
|
|
|
public class WebcamCaptureLoop {
|
|
private final Webcam webcam;
|
|
private final Consumer<BufferedImage> onFrameCaptured;
|
|
private volatile boolean running = false;
|
|
private final AtomicBoolean cleanedUp = new AtomicBoolean(false);
|
|
private final int targetframes = 20;
|
|
|
|
public WebcamCaptureLoop(Webcam webcam, Consumer<BufferedImage> onFrameCaptured) {
|
|
this.webcam = webcam;
|
|
this.onFrameCaptured = onFrameCaptured;
|
|
|
|
Dimension vga = WebcamResolution.VGA.getSize();
|
|
if (isSizeSupported(webcam, vga)) { // we dont do stupid shit anymore! cause we are smarter than before...
|
|
webcam.setViewSize(vga);
|
|
} else {
|
|
Dimension[] dimensions = webcam.getViewSizes();
|
|
webcam.setViewSize(dimensions[dimensions.length - 1]);
|
|
}
|
|
}
|
|
|
|
private boolean isSizeSupported(Webcam webcam, Dimension vga) {
|
|
for (Dimension d: webcam.getViewSizes()) {
|
|
if (
|
|
d.width == vga.width && d.height == vga.height
|
|
) return true; // this should return 640x480 :)
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void start() {
|
|
if (running) return;
|
|
running = true;
|
|
|
|
Thread captureThread = new Thread(() -> {
|
|
try {
|
|
if (!webcam.isOpen()) webcam.open(); // open if not
|
|
|
|
long frameDurationLimitns = 1_000_000_000L / targetframes; // we use NanoSeconds cause its more accurate
|
|
|
|
while (running) {
|
|
long startTime = System.nanoTime();
|
|
|
|
BufferedImage img = webcam.getImage();
|
|
if (img != null)
|
|
// there is no need for a invoke later swing wise!
|
|
onFrameCaptured.accept(img);
|
|
|
|
long timespent = System.nanoTime() - startTime;
|
|
long sleeptime = frameDurationLimitns - timespent;
|
|
|
|
if (sleeptime > 0) {
|
|
LockSupport.parkNanos(sleeptime);
|
|
} else {
|
|
// do a yield to prevent ui freezes
|
|
Thread.yield();
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
ShowError.warning(
|
|
null,
|
|
"Exception" + e,
|
|
"Exception"
|
|
);
|
|
} finally {
|
|
cleanup();
|
|
}
|
|
}, "cam_cap_thread");
|
|
captureThread.start();
|
|
}
|
|
|
|
/**
|
|
* Safely release webcam
|
|
*/
|
|
private synchronized void cleanup() {
|
|
if (!cleanedUp.compareAndSet(false, true)) {
|
|
return;
|
|
}
|
|
|
|
boolean success = false;
|
|
|
|
try {
|
|
if (webcam.isOpen())
|
|
webcam.close();
|
|
|
|
success = true;
|
|
|
|
} catch (WebcamException exception) {
|
|
SwingUtilities.invokeLater(() ->
|
|
JOptionPane.showMessageDialog(
|
|
null,
|
|
"Cleanup failed \nWebCamException@"+exception.getMessage(),
|
|
"WebCamException",
|
|
JOptionPane.WARNING_MESSAGE // changed to warning, its better tbh
|
|
));
|
|
} finally {
|
|
if (!success)
|
|
cleanedUp.set(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Arguments: null (or just none)
|
|
* What does this method do? : Sets CameraThreads running flag to false and calls cleanup();
|
|
*/
|
|
public void stop() {
|
|
running = false;
|
|
}
|
|
} |