19 package org.sleuthkit.autopsy.contentviewers;
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import javafx.application.Platform;
24 import javafx.embed.swing.JFXPanel;
25 import javafx.scene.Scene;
26 import javafx.scene.image.Image;
27 import javafx.scene.image.ImageView;
28 import javafx.scene.image.PixelFormat;
29 import javafx.scene.image.PixelWriter;
30 import javafx.scene.image.WritableImage;
31 import javafx.scene.layout.BorderPane;
32 import org.freedesktop.gstreamer.Buffer;
33 import org.freedesktop.gstreamer.Caps;
34 import org.freedesktop.gstreamer.FlowReturn;
35 import org.freedesktop.gstreamer.Sample;
36 import org.freedesktop.gstreamer.Structure;
37 import org.freedesktop.gstreamer.elements.AppSink;
42 final class JavaFxAppSink
extends AppSink {
44 private static final String CAP_MIME_TYPE =
"video/x-raw";
45 private static final String CAP_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ?
"format=BGRx" :
"format=xRGB");
46 private static final int PROP_MAX_BUFFERS = 5000;
48 private final JavaFxFrameUpdater updater;
57 public JavaFxAppSink(String name, JFXPanel target) {
59 set(
"emit-signals",
true);
60 updater =
new JavaFxFrameUpdater(target);
61 connect((AppSink.NEW_SAMPLE) updater);
62 connect((AppSink.NEW_PREROLL) updater);
64 String.format(
"%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
65 set(
"max-buffers", PROP_MAX_BUFFERS);
73 disconnect((AppSink.NEW_SAMPLE) updater);
74 disconnect((AppSink.NEW_PREROLL) updater);
82 static class JavaFxFrameUpdater
implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
83 private final ImageView fxImageView;
85 public JavaFxFrameUpdater(JFXPanel target) {
88 fxImageView =
new ImageView();
89 BorderPane borderpane =
new BorderPane(fxImageView);
90 Scene scene =
new Scene(borderpane);
94 Platform.runLater(() -> {
95 target.setScene(scene);
99 fxImageView.fitWidthProperty().bind(scene.widthProperty());
100 fxImageView.fitHeightProperty().bind(scene.heightProperty());
101 fxImageView.setPreserveRatio(
true);
102 fxImageView.setSmooth(
true);
103 fxImageView.setCache(
true);
113 public FlowReturn newSample(AppSink appSink) {
114 return setSample(appSink.pullSample());
124 public FlowReturn setSample(Sample input) {
125 Buffer buffer = input.getBuffer();
126 ByteBuffer byteBuffer = buffer.map(
false);
127 if (byteBuffer != null) {
128 Structure capsStruct = input.getCaps().getStructure(0);
129 int width = capsStruct.getInteger(
"width");
130 int height = capsStruct.getInteger(
"height");
131 byte[] byteArray =
new byte[width * height * 4];
132 byteBuffer.get(byteArray);
133 Image videoFrame = convertBytesToImage(byteArray, width, height);
134 fxImageView.setImage(videoFrame);
140 return FlowReturn.OK;
155 public FlowReturn newPreroll(AppSink sink) {
157 Sample sample = sink.pullPreroll();
158 return setSample(sample);
170 private Image convertBytesToImage(byte[] pixels,
int width,
int height) {
171 WritableImage image =
new WritableImage(width, height);
172 PixelWriter pixelWriter = image.getPixelWriter();
173 pixelWriter.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);
181 fxImageView.setImage(null);