Add support to update image only when there is a new frame
This commit is contained in:
parent
0704fc70a3
commit
ee165b50ff
52
README.md
52
README.md
|
@ -53,30 +53,39 @@ public class TestDriver extends Application {
|
||||||
root.getChildren().add(imageView);
|
root.getChildren().add(imageView);
|
||||||
|
|
||||||
Webcam.getWebcams().stream()
|
Webcam.getWebcams().stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.ifPresent((final Webcam camera) -> {
|
.ifPresent((final Webcam camera) -> {
|
||||||
final WebcamDevice device = camera.getDevice();
|
final WebcamDevice device = camera.getDevice();
|
||||||
LOG.info("Found camera: {}, device = {}", camera, device);
|
LOG.info("Found camera: {}, device = {}", camera, device);
|
||||||
|
|
||||||
final int width = device.getResolution().width;
|
final int width = device.getResolution().width;
|
||||||
final int height = device.getResolution().height;
|
final int height = device.getResolution().height;
|
||||||
final WritableImage fxImage = new WritableImage(width, height);
|
final WritableImage fxImage = new WritableImage(width, height);
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
imageView.setImage(fxImage);
|
imageView.setImage(fxImage);
|
||||||
stage.setWidth(width);
|
stage.setWidth(width);
|
||||||
stage.setHeight(height);
|
stage.setHeight(height);
|
||||||
stage.centerOnScreen();
|
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 -> {
|
stage.setOnCloseRequest(t -> {
|
||||||
Platform.exit();
|
Platform.exit();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
|
@ -89,7 +98,6 @@ public class TestDriver extends Application {
|
||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# Future work
|
# Future work
|
||||||
|
|
|
@ -54,8 +54,17 @@ public class TestDriver extends Application {
|
||||||
camera.getLock().disable();
|
camera.getLock().disable();
|
||||||
camera.open();
|
camera.open();
|
||||||
if (device instanceof WebcamDeviceWithBufferOperations) {
|
if (device instanceof WebcamDeviceWithBufferOperations) {
|
||||||
EXECUTOR.scheduleAtFixedRate(() -> {
|
final WebcamDeviceWithBufferOperations dev = ((WebcamDeviceWithBufferOperations) device);
|
||||||
((WebcamDeviceWithBufferOperations) device).updateFXIMage(fxImage);
|
EXECUTOR.scheduleAtFixedRate(new Runnable() {
|
||||||
|
private long lastFrameTimestamp = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (dev.updateFXIMage(fxImage, lastFrameTimestamp)) {
|
||||||
|
lastFrameTimestamp = dev.getLastFrameTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}, 0, 16, TimeUnit.MILLISECONDS);
|
}, 0, 16, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,9 +7,11 @@ import javafx.scene.image.WritableImage;
|
||||||
|
|
||||||
public interface WebcamDeviceWithBufferOperations extends WebcamDevice {
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
|
||||||
private ByteBuffer imgBuffer = null;
|
private ByteBuffer imgBuffer = null;
|
||||||
private byte[] arrayByteBuffer = null;
|
private byte[] arrayByteBuffer = null;
|
||||||
private BufferedImage bufferedImage = null;
|
private BufferedImage bufferedImage = null;
|
||||||
|
private long lastFrameTimestamp = -1;
|
||||||
|
|
||||||
public AVFVideoDevice(final int deviceIndex, final String id, final String name, final Collection<Dimension> resolutions) {
|
public AVFVideoDevice(final int deviceIndex, final String id, final String name, final Collection<Dimension> resolutions) {
|
||||||
this.deviceIndex = deviceIndex;
|
this.deviceIndex = deviceIndex;
|
||||||
|
@ -159,6 +160,11 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
|
||||||
return open;
|
return open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastFrameTimestamp() {
|
||||||
|
return lastFrameTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
public static final int MAX_FPS = 30;
|
public static final int MAX_FPS = 30;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -217,18 +223,23 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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()) {
|
if (!isOpen()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBuffer();
|
updateBuffer();
|
||||||
|
|
||||||
return updateFXIMage(writableImage, imgBuffer);
|
if (this.lastFrameTimestamp <= lastFrameTimestamp) {
|
||||||
}
|
|
||||||
|
|
||||||
public boolean updateFXIMage(final WritableImage writableImage, final ByteBuffer byteBuffer) {
|
|
||||||
if (!isOpen()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,9 +260,11 @@ public class AVFVideoDevice implements WebcamDevice, WebcamDevice.FPSSource, Web
|
||||||
|
|
||||||
private void updateBuffer() {
|
private void updateBuffer() {
|
||||||
if (LibVideoCapture.INSTANCE.vcavf_has_new_frame(deviceIndex)) {
|
if (LibVideoCapture.INSTANCE.vcavf_has_new_frame(deviceIndex)) {
|
||||||
LibVideoCapture.INSTANCE.vcavf_grab_frame(
|
if (LibVideoCapture.INSTANCE.vcavf_grab_frame(
|
||||||
deviceIndex,
|
deviceIndex,
|
||||||
Native.getDirectBufferPointer(imgBuffer), imgBuffer.capacity());
|
Native.getDirectBufferPointer(imgBuffer), imgBuffer.capacity())) {
|
||||||
|
lastFrameTimestamp = System.currentTimeMillis();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class CaptureManagerFrameGrabberSession {
|
||||||
private int videoWidth = -1;
|
private int videoWidth = -1;
|
||||||
private int videoHeight = -1;
|
private int videoHeight = -1;
|
||||||
private int bufferSizeBytes = -1;
|
private int bufferSizeBytes = -1;
|
||||||
|
private long lastFrameTimestamp = -1;
|
||||||
|
|
||||||
public boolean init(
|
public boolean init(
|
||||||
final CaptureManagerSource source,
|
final CaptureManagerSource source,
|
||||||
|
@ -223,6 +224,10 @@ public class CaptureManagerFrameGrabberSession {
|
||||||
session.closeSession();
|
session.closeSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastFrameTimestamp() {
|
||||||
|
return lastFrameTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized BufferedImage toBufferedImage() {
|
public synchronized BufferedImage toBufferedImage() {
|
||||||
if (!isOpen()) {
|
if (!isOpen()) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -249,7 +254,7 @@ public class CaptureManagerFrameGrabberSession {
|
||||||
return bufferedImage;
|
return bufferedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean updateFXIMage(final WritableImage writableImage) {
|
public synchronized boolean updateFXIMage(final WritableImage writableImage, long lastFrameTimestamp) {
|
||||||
if (!isOpen()) {
|
if (!isOpen()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -260,6 +265,10 @@ public class CaptureManagerFrameGrabberSession {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.lastFrameTimestamp <= lastFrameTimestamp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
updateFXIMage(writableImage, directBuffer);
|
updateFXIMage(writableImage, directBuffer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -285,7 +294,12 @@ public class CaptureManagerFrameGrabberSession {
|
||||||
|
|
||||||
|
|
||||||
public synchronized int updateDirectBuffer() {
|
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() {
|
public boolean isOpen() {
|
||||||
|
|
|
@ -144,6 +144,15 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
|
||||||
return session != null && session.isOpen();
|
return session != null && session.isOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastFrameTimestamp() {
|
||||||
|
if (isOpen()) {
|
||||||
|
return session.getLastFrameTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private static Pair<CaptureManagerStreamDescriptor, CaptureManagerMediaType> findBestMediaTypeInStreams(
|
private static Pair<CaptureManagerStreamDescriptor, CaptureManagerMediaType> findBestMediaTypeInStreams(
|
||||||
final Collection<CaptureManagerStreamDescriptor> videoStreams,
|
final Collection<CaptureManagerStreamDescriptor> videoStreams,
|
||||||
final Dimension resolution
|
final Dimension resolution
|
||||||
|
@ -231,9 +240,9 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateFXIMage(WritableImage writableImage, ByteBuffer byteBuffer) {
|
public boolean updateFXIMage(final WritableImage writableImage, final long lastFrameTimestamp) {
|
||||||
if (isOpen()) {
|
if (isOpen()) {
|
||||||
session.updateFXIMage(writableImage, byteBuffer);
|
session.updateFXIMage(writableImage, lastFrameTimestamp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,11 +251,7 @@ public class CaptureManagerVideoDevice implements WebcamDevice, WebcamDevice.FPS
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateFXIMage(WritableImage writableImage) {
|
public boolean updateFXIMage(WritableImage writableImage) {
|
||||||
if (isOpen()) {
|
return updateFXIMage(writableImage, -1);
|
||||||
return session.updateFXIMage(writableImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue