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 GstVideoRendererPanel
extends JFXPanel {
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;
47 private AppSink videoSink;
48 private ImageView fxImageView;
53 GstVideoRendererPanel() {
61 private void initImageView() {
62 fxImageView =
new ImageView();
63 BorderPane borderpane =
new BorderPane(fxImageView);
64 Scene scene =
new Scene(borderpane);
68 fxImageView.fitWidthProperty().bind(scene.widthProperty());
69 fxImageView.fitHeightProperty().bind(scene.heightProperty());
70 fxImageView.setPreserveRatio(
true);
71 fxImageView.setSmooth(
true);
72 fxImageView.setCache(
true);
78 private void initVideoSink() {
79 videoSink =
new AppSink(
"GstVideoComponent");
80 videoSink.set(
"emit-signals",
true);
81 AppSinkListener gstListener =
new AppSinkListener();
82 videoSink.connect(gstListener);
83 videoSink.setCaps(
new Caps(
84 String.format(
"%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
85 videoSink.set(
"max-buffers", PROP_MAX_BUFFERS);
86 videoSink.set(
"drop",
true);
94 AppSink getVideoSink() {
102 class AppSinkListener
implements AppSink.NEW_SAMPLE {
104 private Image videoFrame;
105 private int lastWidth = 0;
106 private int lastHeight = 0;
107 private byte[] byteArray;
110 public FlowReturn newSample(AppSink appSink) {
111 Sample sample = appSink.pullSample();
112 Buffer buffer = sample.getBuffer();
113 ByteBuffer byteBuffer = buffer.map(
false);
114 if (byteBuffer != null) {
115 Structure capsStruct = sample.getCaps().getStructure(0);
116 int width = capsStruct.getInteger(
"width");
117 int height = capsStruct.getInteger(
"height");
118 if (width != lastWidth || height != lastHeight) {
121 byteArray =
new byte[width * height * 4];
123 byteBuffer.get(byteArray);
124 videoFrame = convertBytesToImage(byteArray, width, height);
125 Platform.runLater(() -> {
126 fxImageView.setImage(videoFrame);
132 return FlowReturn.OK;
144 private Image convertBytesToImage(byte[] pixels,
int width,
int height) {
145 WritableImage image =
new WritableImage(width, height);
146 PixelWriter pixelWriter = image.getPixelWriter();
147 pixelWriter.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);