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);