19 package org.sleuthkit.autopsy.contentviewers;
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import javafx.embed.swing.JFXPanel;
24 import javafx.scene.Scene;
25 import javafx.scene.image.Image;
26 import javafx.scene.image.ImageView;
27 import javafx.scene.image.PixelFormat;
28 import javafx.scene.image.PixelWriter;
29 import javafx.scene.image.WritableImage;
30 import javafx.scene.layout.BorderPane;
31 import org.freedesktop.gstreamer.Buffer;
32 import org.freedesktop.gstreamer.Caps;
33 import org.freedesktop.gstreamer.FlowReturn;
34 import org.freedesktop.gstreamer.Sample;
35 import org.freedesktop.gstreamer.Structure;
36 import org.freedesktop.gstreamer.elements.AppSink;
41 final class JavaFxAppSink
extends AppSink {
43 private static final String CAP_MIME_TYPE =
"video/x-raw";
44 private static final String CAP_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ?
"format=BGRx" :
"format=xRGB");
45 private static final int PROP_MAX_BUFFERS = 5000;
47 private final JavaFxFrameUpdater updater;
56 public JavaFxAppSink(String name, JFXPanel target) {
58 set(
"emit-signals",
true);
59 updater =
new JavaFxFrameUpdater(target);
60 connect((AppSink.NEW_SAMPLE) updater);
61 connect((AppSink.NEW_PREROLL) updater);
63 String.format(
"%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
64 set(
"max-buffers", PROP_MAX_BUFFERS);
72 disconnect((AppSink.NEW_SAMPLE) updater);
73 disconnect((AppSink.NEW_PREROLL) updater);
81 static class JavaFxFrameUpdater
implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
82 private final ImageView fxImageView;
84 public JavaFxFrameUpdater(JFXPanel target) {
87 fxImageView =
new ImageView();
88 BorderPane borderpane =
new BorderPane(fxImageView);
89 Scene scene =
new Scene(borderpane);
90 target.setScene(scene);
93 fxImageView.fitWidthProperty().bind(scene.widthProperty());
94 fxImageView.fitHeightProperty().bind(scene.heightProperty());
95 fxImageView.setPreserveRatio(
true);
96 fxImageView.setSmooth(
true);
97 fxImageView.setCache(
true);
107 public FlowReturn newSample(AppSink appSink) {
108 return setSample(appSink.pullSample());
118 public FlowReturn setSample(Sample input) {
119 Buffer buffer = input.getBuffer();
120 ByteBuffer byteBuffer = buffer.map(
false);
121 if (byteBuffer != null) {
122 Structure capsStruct = input.getCaps().getStructure(0);
123 int width = capsStruct.getInteger(
"width");
124 int height = capsStruct.getInteger(
"height");
125 byte[] byteArray =
new byte[width * height * 4];
126 byteBuffer.get(byteArray);
127 Image videoFrame = convertBytesToImage(byteArray, width, height);
128 fxImageView.setImage(videoFrame);
134 return FlowReturn.OK;
149 public FlowReturn newPreroll(AppSink sink) {
151 Sample sample = sink.pullPreroll();
152 return setSample(sample);
164 private Image convertBytesToImage(byte[] pixels,
int width,
int height) {
165 WritableImage image =
new WritableImage(width, height);
166 PixelWriter pixelWriter = image.getPixelWriter();
167 pixelWriter.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);
175 fxImageView.setImage(null);