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