Autopsy  4.19.3
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  */
19 package org.sleuthkit.autopsy.contentviewers;
20 
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;
37 
41 final class JavaFxAppSink extends AppSink {
42 
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;
46 
47  private final JavaFxFrameUpdater updater;
48 
56  public JavaFxAppSink(String name, JFXPanel target) {
57  super(name);
58  set("emit-signals", true);
59  updater = new JavaFxFrameUpdater(target);
60  connect((AppSink.NEW_SAMPLE) updater);
61  connect((AppSink.NEW_PREROLL) updater);
62  setCaps(new Caps(
63  String.format("%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
64  set("max-buffers", PROP_MAX_BUFFERS);
65  set("drop", true);
66  }
67 
71  public void clear() {
72  disconnect((AppSink.NEW_SAMPLE) updater);
73  disconnect((AppSink.NEW_PREROLL) updater);
74  updater.clear();
75  }
76 
81  static class JavaFxFrameUpdater implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
82  private final ImageView fxImageView;
83 
84  public JavaFxFrameUpdater(JFXPanel target) {
85  //We should probably pass an ImageView instead of a JFXPanel to make
86  //it more reuseable
87  fxImageView = new ImageView(); // Will hold the current video frame.
88  BorderPane borderpane = new BorderPane(fxImageView); // Center and size ImageView.
89  Scene scene = new Scene(borderpane); // Root of the JavaFX tree.
90  target.setScene(scene);
91 
92  // Bind size of image to that of scene, while keeping proportions
93  fxImageView.fitWidthProperty().bind(scene.widthProperty());
94  fxImageView.fitHeightProperty().bind(scene.heightProperty());
95  fxImageView.setPreserveRatio(true);
96  fxImageView.setSmooth(true);
97  fxImageView.setCache(true);
98  }
99 
106  @Override
107  public FlowReturn newSample(AppSink appSink) {
108  return setSample(appSink.pullSample());
109  }
110 
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);
129  buffer.unmap();
130  }
131  input.dispose();
132 
133  //Keep frames rolling
134  return FlowReturn.OK;
135  }
136 
148  @Override
149  public FlowReturn newPreroll(AppSink sink) {
150  //Grab the next frame without removing it from the pipeline
151  Sample sample = sink.pullPreroll();
152  return setSample(sample);
153  }
154 
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);
168  return image;
169  }
170 
174  void clear() {
175  fxImageView.setImage(null);
176  }
177  }
178 }

Copyright © 2012-2022 Basis Technology. Generated on: Wed Oct 5 2022
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.