Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
JavaFxAppSink.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2019 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.contentviewers;
20
21import java.nio.ByteBuffer;
22import java.nio.ByteOrder;
23import javafx.application.Platform;
24import javafx.embed.swing.JFXPanel;
25import javafx.scene.Scene;
26import javafx.scene.image.Image;
27import javafx.scene.image.ImageView;
28import javafx.scene.image.PixelFormat;
29import javafx.scene.image.PixelWriter;
30import javafx.scene.image.WritableImage;
31import javafx.scene.layout.BorderPane;
32import org.freedesktop.gstreamer.Buffer;
33import org.freedesktop.gstreamer.Caps;
34import org.freedesktop.gstreamer.FlowReturn;
35import org.freedesktop.gstreamer.Sample;
36import org.freedesktop.gstreamer.Structure;
37import org.freedesktop.gstreamer.elements.AppSink;
38
42final class JavaFxAppSink extends AppSink {
43
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
48 private final JavaFxFrameUpdater updater;
49
57 public JavaFxAppSink(String name, JFXPanel target) {
58 super(name);
59 set("emit-signals", true);
60 updater = new JavaFxFrameUpdater(target);
61 connect((AppSink.NEW_SAMPLE) updater);
62 connect((AppSink.NEW_PREROLL) updater);
63 setCaps(new Caps(
64 String.format("%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
65 set("max-buffers", PROP_MAX_BUFFERS);
66 set("drop", true);
67 }
68
72 public void clear() {
73 disconnect((AppSink.NEW_SAMPLE) updater);
74 disconnect((AppSink.NEW_PREROLL) updater);
75 updater.clear();
76 }
77
82 static class JavaFxFrameUpdater implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
83 private final ImageView fxImageView;
84
85 public JavaFxFrameUpdater(JFXPanel target) {
86 //We should probably pass an ImageView instead of a JFXPanel to make
87 //it more reuseable
88 fxImageView = new ImageView(); // Will hold the current video frame.
89 BorderPane borderpane = new BorderPane(fxImageView); // Center and size ImageView.
90 Scene scene = new Scene(borderpane); // Root of the JavaFX tree.
91 // Although the documentation for JFXPanel.setScene() claims that it
92 // can be called on either the EDT or the JavaFX thread, with JavaFX 11
93 // it doesn't work unless you call it on the JavaFX application thread.
94 Platform.runLater(() -> {
95 target.setScene(scene);
96 });
97
98 // Bind size of image to that of scene, while keeping proportions
99 fxImageView.fitWidthProperty().bind(scene.widthProperty());
100 fxImageView.fitHeightProperty().bind(scene.heightProperty());
101 fxImageView.setPreserveRatio(true);
102 fxImageView.setSmooth(true);
103 fxImageView.setCache(true);
104 }
105
112 @Override
113 public FlowReturn newSample(AppSink appSink) {
114 return setSample(appSink.pullSample());
115 }
116
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);
135 buffer.unmap();
136 }
137 input.dispose();
138
139 //Keep frames rolling
140 return FlowReturn.OK;
141 }
142
154 @Override
155 public FlowReturn newPreroll(AppSink sink) {
156 //Grab the next frame without removing it from the pipeline
157 Sample sample = sink.pullPreroll();
158 return setSample(sample);
159 }
160
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);
174 return image;
175 }
176
180 void clear() {
181 fxImageView.setImage(null);
182 }
183 }
184}

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.