Add support to update image only when there is a new frame

This commit is contained in:
Eduardo Ramos 2022-12-21 13:26:13 +01:00
parent 0704fc70a3
commit ee165b50ff
6 changed files with 95 additions and 44 deletions

View File

@ -53,30 +53,39 @@ public class TestDriver extends Application {
root.getChildren().add(imageView);
Webcam.getWebcams().stream()
.findFirst()
.ifPresent((final Webcam camera) -> {
final WebcamDevice device = camera.getDevice();
LOG.info("Found camera: {}, device = {}", camera, device);
.findFirst()
.ifPresent((final Webcam camera) -> {
final WebcamDevice device = camera.getDevice();
LOG.info("Found camera: {}, device = {}", camera, device);
final int width = device.getResolution().width;
final int height = device.getResolution().height;
final WritableImage fxImage = new WritableImage(width, height);
Platform.runLater(() -> {
imageView.setImage(fxImage);
stage.setWidth(width);
stage.setHeight(height);
stage.centerOnScreen();
final int width = device.getResolution().width;
final int height = device.getResolution().height;
final WritableImage fxImage = new WritableImage(width, height);
Platform.runLater(() -> {
imageView.setImage(fxImage);
stage.setWidth(width);
stage.setHeight(height);
stage.centerOnScreen();
});
camera.getLock().disable();
camera.open();
if (device instanceof WebcamDeviceWithBufferOperations) {
final WebcamDeviceWithBufferOperations dev = ((WebcamDeviceWithBufferOperations) device);
EXECUTOR.scheduleAtFixedRate(new Runnable() {
private long lastFrameTimestamp = -1;
@Override
public void run() {
if (dev.updateFXIMage(fxImage, lastFrameTimestamp)) {
lastFrameTimestamp = dev.getLastFrameTimestamp();
}
}
}, 0, 16, TimeUnit.MILLISECONDS);
}
});
camera.getLock().disable();
camera.open();
if (device instanceof WebcamDeviceWithBufferOperations) {
EXECUTOR.scheduleAtFixedRate(() -> {
((WebcamDeviceWithBufferOperations) device).updateFXIMage(fxImage);
}, 0, 16, TimeUnit.MILLISECONDS);
}
});
stage.setOnCloseRequest(t -> {
Platform.exit();
System.exit(0);
@ -89,7 +98,6 @@ public class TestDriver extends Application {
stage.show();
}
}
```
# Future work

View File

@ -54,8 +54,17 @@ public class TestDriver extends Application {
camera.getLock().disable();
camera.open();
if (device instanceof WebcamDeviceWithBufferOperations) {
EXECUTOR.scheduleAtFixedRate(() -> {
((WebcamDeviceWithBufferOperations) device).updateFXIMage(fxImage);
final WebcamDeviceWithBufferOperations dev = ((WebcamDeviceWithBufferOperations) device);
EXECUTOR.scheduleAtFixedRate(new Runnable() {
private long lastFrameTimestamp = -1;
@Override
public void run() {
if (dev.updateFXIMage(fxImage, lastFrameTimestamp)) {
lastFrameTimestamp = dev.getLastFrameTimestamp();
}
}
}, 0, 16, TimeUnit.MILLISECONDS);
}
});

View File

@ -7,9 +7,11 @@ import javafx.scene.image.WritableImage;
public interface WebcamDeviceWithBufferOperations extends WebcamDevice {
BufferedImage getImage(final ByteBuffer byteBuffer);
BufferedImage getImage(ByteBuffer byteBuffer);
boolean updateFXIMage(final WritableImage writableImage, final ByteBuffer byteBuffer);
boolean updateFXIMage(WritableImage writableImage);
boolean updateFXIMage(final WritableImage writableImage);
boolean updateFXIMage(WritableImage writableImage, long lastFrameTimestamp);
long getLastFrameTimestamp();
}

View File

@ -36,6 +36,7 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
private ByteBuffer imgBuffer = null;
private byte[] arrayByteBuffer = null;
private BufferedImage bufferedImage = null;
private long lastFrameTimestamp = -1;
public AVFVideoDevice(final int deviceIndex, final String id, final String name, final Collection<Dimension> resolutions) {
this.deviceIndex = deviceIndex;
@ -159,6 +160,11 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
return open;
}
@Override
public long getLastFrameTimestamp() {
return lastFrameTimestamp;
}
public static final int MAX_FPS = 30;
@Override
@ -217,18 +223,23 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
}
@Override
public synchronized boolean updateFXIMage(WritableImage writableImage) {
public boolean updateFXIMage(WritableImage writableImage) {
return updateFXIMage(writableImage, -1);
}
@Override
public synchronized boolean updateFXIMage(final WritableImage writableImage, final long lastFrameTimestamp) {
return updateFXIMage(writableImage, imgBuffer, lastFrameTimestamp);
}
private boolean updateFXIMage(final WritableImage writableImage, final ByteBuffer byteBuffer, final long lastFrameTimestamp) {
if (!isOpen()) {
return false;
}
updateBuffer();
return updateFXIMage(writableImage, imgBuffer);
}
public boolean updateFXIMage(final WritableImage writableImage, final ByteBuffer byteBuffer) {
if (!isOpen()) {
if (this.lastFrameTimestamp <= lastFrameTimestamp) {
return false;
}
@ -249,9 +260,11 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
private void updateBuffer() {
if (LibVideoCapture.INSTANCE.vcavf_has_new_frame(deviceIndex)) {
LibVideoCapture.INSTANCE.vcavf_grab_frame(
if (LibVideoCapture.INSTANCE.vcavf_grab_frame(
deviceIndex,
Native.getDirectBufferPointer(imgBuffer), imgBuffer.capacity());
Native.getDirectBufferPointer(imgBuffer), imgBuffer.capacity())) {
lastFrameTimestamp = System.currentTimeMillis();
};
}
}

View File

@ -37,6 +37,7 @@ public class CaptureManagerFrameGrabberSession {
private int videoWidth = -1;
private int videoHeight = -1;
private int bufferSizeBytes = -1;
private long lastFrameTimestamp = -1;
public boolean init(
final CaptureManagerSource source,
@ -223,6 +224,10 @@ public class CaptureManagerFrameGrabberSession {
session.closeSession();
}
public long getLastFrameTimestamp() {
return lastFrameTimestamp;
}
public synchronized BufferedImage toBufferedImage() {
if (!isOpen()) {
return null;
@ -249,7 +254,7 @@ public class CaptureManagerFrameGrabberSession {
return bufferedImage;
}
public synchronized boolean updateFXIMage(final WritableImage writableImage) {
public synchronized boolean updateFXIMage(final WritableImage writableImage, long lastFrameTimestamp) {
if (!isOpen()) {
return false;
}
@ -260,6 +265,10 @@ public class CaptureManagerFrameGrabberSession {
return false;
}
if (this.lastFrameTimestamp <= lastFrameTimestamp) {
return false;
}
updateFXIMage(writableImage, directBuffer);
return true;
@ -285,7 +294,12 @@ public class CaptureManagerFrameGrabberSession {
public synchronized int updateDirectBuffer() {
return sampleGrabberCall.readData(directBuffer);
final int readSize = sampleGrabberCall.readData(directBuffer);
if (readSize > 0) {
lastFrameTimestamp = System.currentTimeMillis();
}
return readSize;
}
public boolean isOpen() {

View File

@ -144,6 +144,15 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
return session != null && session.isOpen();
}
@Override
public long getLastFrameTimestamp() {
if (isOpen()) {
return session.getLastFrameTimestamp();
}
return -1;
}
private static Pair<CaptureManagerStreamDescriptor, CaptureManagerMediaType> findBestMediaTypeInStreams(
final Collection<CaptureManagerStreamDescriptor> videoStreams,
final Dimension resolution
@ -231,9 +240,9 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
}
@Override
public boolean updateFXIMage(WritableImage writableImage, ByteBuffer byteBuffer) {
public boolean updateFXIMage(final WritableImage writableImage, final long lastFrameTimestamp) {
if (isOpen()) {
session.updateFXIMage(writableImage, byteBuffer);
session.updateFXIMage(writableImage, lastFrameTimestamp);
return true;
}
@ -242,11 +251,7 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
@Override
public boolean updateFXIMage(WritableImage writableImage) {
if (isOpen()) {
return session.updateFXIMage(writableImage);
}
return false;
return updateFXIMage(writableImage, -1);
}
@Override