Merge branch 'release-4.11.0' of github.com:sleuthkit/autopsy into 4868_gstreamer_deployment

This commit is contained in:
esaunders 2019-04-02 15:39:58 -04:00
commit 8a2ee04a0d
10 changed files with 932 additions and 804 deletions

View File

@ -8,7 +8,7 @@ FXVideoPanel.progress.bufferingFile=Buffering {0}
FXVideoPanel.progressLabel.buffering=Buffering...
FXVideoPanel.media.unsupportedFormat=Unsupported Format.
GstVideoPanel.cannotProcFile.err=The media player cannot process this file.
GstVideoPanel.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
MediaFileViewer.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
GstVideoPanel.setupVideo.infoLabel.text=Playback of deleted videos is not supported, use an external player.
GstVideoPanel.exception.problemFile.msg=Cannot capture frames from this file ({0}).
GstVideoPanel.exception.problemPlay.msg=Problem with video file; problem when attempting to play while obtaining duration.
@ -84,3 +84,8 @@ MediaViewImagePanel.zoomTextField.text=
MediaViewImagePanel.rotationTextField.text=
MediaViewImagePanel.rotateLeftButton.toolTipText=
HtmlPanel.showImagesToggleButton.text=Show Images
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.infoLabel.text=No Errors

View File

@ -19,8 +19,12 @@ FXVideoPanel.progress.bufferingFile=Buffering {0}
FXVideoPanel.progressLabel.buffering=Buffering...
FXVideoPanel.media.unsupportedFormat=Unsupported Format.
GstVideoPanel.cannotProcFile.err=The media player cannot process this file.
GstVideoPanel.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
GstVideoPanel.noOpenCase.errMsg=No open case available.
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
HtmlPanel_showImagesToggleButton_hide=Hide Images
HtmlPanel_showImagesToggleButton_show=Show Images
HtmlViewer_file_error=This file is missing or unreadable.
MediaFileViewer.initGst.gstException.msg=Error initializing gstreamer for audio/video viewing and frame extraction capabilities. Video and audio viewing will be disabled.
GstVideoPanel.setupVideo.infoLabel.text=Playback of deleted videos is not supported, use an external player.
GstVideoPanel.exception.problemFile.msg=Cannot capture frames from this file ({0}).
GstVideoPanel.exception.problemPlay.msg=Problem with video file; problem when attempting to play while obtaining duration.
@ -32,13 +36,12 @@ GstVideoPanel.progress.buffering=Buffering...
GstVideoPanel.progressLabel.bufferingErr=Error buffering file
GstVideoPanel.progress.infoLabel.updateErr=Error updating video progress: {0}
GstVideoPanel.ExtractMedia.progress.buffering=Buffering {0}
Html_text_display_error=The HTML text cannot be displayed, it may not be correctly formed HTML.
HtmlPanel_showImagesToggleButton_hide=Hide Images
HtmlPanel_showImagesToggleButton_show=Show Images
HtmlViewer_file_error=This file is missing or unreadable.
MediaFileViewer.AccessibleContext.accessibleDescription=
MediaFileViewer.title=Media
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
MediaPlayerPanel.noSupport=File not supported.
MediaPlayerPanel.timeFormat=%02d:%02d:%02d
MediaPlayerPanel.unknownTime=Unknown
MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory.
MediaViewImagePanel.errorLabel.text=Could not load file into Media View.
MediaViewImagePanel.externalViewerButton.text=Open in External Viewer Ctrl+E
@ -143,6 +146,11 @@ MediaViewImagePanel.zoomTextField.text=
MediaViewImagePanel.rotationTextField.text=
MediaViewImagePanel.rotateLeftButton.toolTipText=
HtmlPanel.showImagesToggleButton.text=Show Images
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.infoLabel.text=No Errors
# {0} - tableName
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
# {0} - tableName

View File

@ -1,151 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.contentviewers;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import org.freedesktop.gstreamer.Buffer;
import org.freedesktop.gstreamer.Caps;
import org.freedesktop.gstreamer.FlowReturn;
import org.freedesktop.gstreamer.Sample;
import org.freedesktop.gstreamer.Structure;
import org.freedesktop.gstreamer.elements.AppSink;
/**
* This is a video renderer for GStreamer.
*/
final class GstVideoRendererPanel extends JFXPanel {
private static final String CAP_MIME_TYPE = "video/x-raw";
private static final String CAP_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? "format=BGRx" : "format=xRGB");
private static final int PROP_MAX_BUFFERS = 5000;
private AppSink videoSink;
private ImageView fxImageView;
/**
* Create an instance.
*/
GstVideoRendererPanel() {
initImageView();
initVideoSink();
}
/**
* Initialize the ImageView to show the current frame.
*/
private void initImageView() {
fxImageView = new ImageView(); // Will hold the current video frame.
BorderPane borderpane = new BorderPane(fxImageView); // Center and size ImageView.
Scene scene = new Scene(borderpane); // Root of the JavaFX tree.
setScene(scene);
// Bind size of image to that of scene, while keeping proportions
fxImageView.fitWidthProperty().bind(scene.widthProperty());
fxImageView.fitHeightProperty().bind(scene.heightProperty());
fxImageView.setPreserveRatio(true);
fxImageView.setSmooth(true);
fxImageView.setCache(true);
}
/**
* Initialize the video sink.
*/
private void initVideoSink() {
videoSink = new AppSink("GstVideoComponent");
videoSink.set("emit-signals", true);
AppSinkListener gstListener = new AppSinkListener();
videoSink.connect(gstListener);
videoSink.setCaps(new Caps(
String.format("%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
videoSink.set("max-buffers", PROP_MAX_BUFFERS);
videoSink.set("drop", true);
}
/**
* Get the video sink.
*
* @return The video sink.
*/
AppSink getVideoSink() {
return videoSink;
}
/**
* Listen for NEW_SAMPLE events to update the ImageView with the newest
* video frame.
*/
class AppSinkListener implements AppSink.NEW_SAMPLE {
private Image videoFrame;
private int lastWidth = 0;
private int lastHeight = 0;
private byte[] byteArray;
@Override
public FlowReturn newSample(AppSink appSink) {
Sample sample = appSink.pullSample();
Buffer buffer = sample.getBuffer();
ByteBuffer byteBuffer = buffer.map(false);
if (byteBuffer != null) {
Structure capsStruct = sample.getCaps().getStructure(0);
int width = capsStruct.getInteger("width");
int height = capsStruct.getInteger("height");
if (width != lastWidth || height != lastHeight) {
lastWidth = width;
lastHeight = height;
byteArray = new byte[width * height * 4];
}
byteBuffer.get(byteArray);
videoFrame = convertBytesToImage(byteArray, width, height);
Platform.runLater(() -> {
fxImageView.setImage(videoFrame);
});
buffer.unmap();
}
sample.dispose();
return FlowReturn.OK;
}
/**
* Create an image from a byte array of pixels.
*
* @param pixels The byte array of pixels.
* @param width The width of the image.
* @param height The height of the image.
*
* @return The image.
*/
private Image convertBytesToImage(byte[] pixels, int width, int height) {
WritableImage image = new WritableImage(width, height);
PixelWriter pixelWriter = image.getPixelWriter();
pixelWriter.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);
return image;
}
}
}

View File

@ -0,0 +1,178 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.contentviewers;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import org.freedesktop.gstreamer.Buffer;
import org.freedesktop.gstreamer.Caps;
import org.freedesktop.gstreamer.FlowReturn;
import org.freedesktop.gstreamer.Sample;
import org.freedesktop.gstreamer.Structure;
import org.freedesktop.gstreamer.elements.AppSink;
/**
* This is a JavaFX Video renderer for GStreamer
*/
final class JavaFxAppSink extends AppSink {
private static final String CAP_MIME_TYPE = "video/x-raw";
private static final String CAP_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? "format=BGRx" : "format=xRGB");
private static final int PROP_MAX_BUFFERS = 5000;
private final JavaFxFrameUpdater updater;
/**
* Creates a new AppSink that hooks an ImageView into a JFXPanel. This AppSink
* comes prepackaged with an AppSink listener to accomplish the previous statement.
*
* @param name AppSink internal name
* @param target JFXPanel to display video playback in
*/
public JavaFxAppSink(String name, JFXPanel target) {
super(name);
set("emit-signals", true);
updater = new JavaFxFrameUpdater(target);
connect((AppSink.NEW_SAMPLE) updater);
connect((AppSink.NEW_PREROLL) updater);
setCaps(new Caps(
String.format("%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
set("max-buffers", PROP_MAX_BUFFERS);
set("drop", true);
}
/**
* Clear the current frame in the JFXPanel
*/
public void clear() {
disconnect((AppSink.NEW_SAMPLE) updater);
disconnect((AppSink.NEW_PREROLL) updater);
updater.clear();
}
/**
* Responsible for keeping the ImageView that is hooked into the JFXPanel up-to-date
* with the most current or available frame from GStreamer.
*/
static class JavaFxFrameUpdater implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
private final ImageView fxImageView;
public JavaFxFrameUpdater(JFXPanel target) {
//We should probably pass an ImageView instead of a JFXPanel to make
//it more reuseable
fxImageView = new ImageView(); // Will hold the current video frame.
BorderPane borderpane = new BorderPane(fxImageView); // Center and size ImageView.
Scene scene = new Scene(borderpane); // Root of the JavaFX tree.
target.setScene(scene);
// Bind size of image to that of scene, while keeping proportions
fxImageView.fitWidthProperty().bind(scene.widthProperty());
fxImageView.fitHeightProperty().bind(scene.heightProperty());
fxImageView.setPreserveRatio(true);
fxImageView.setSmooth(true);
fxImageView.setCache(true);
}
/**
* Updates the ImageView when a brand new frame is in the pipeline.
*
* @param appSink Pipeline containing the new frame
* @return Result of update
*/
@Override
public FlowReturn newSample(AppSink appSink) {
return setSample(appSink.pullSample());
}
/**
* Set the ImageView to the input sample. Sample here is synonymous with
* frame.
*
* @param input Frame
* @return Result of update
*/
public FlowReturn setSample(Sample input) {
Buffer buffer = input.getBuffer();
ByteBuffer byteBuffer = buffer.map(false);
if (byteBuffer != null) {
Structure capsStruct = input.getCaps().getStructure(0);
int width = capsStruct.getInteger("width");
int height = capsStruct.getInteger("height");
byte[] byteArray = new byte[width * height * 4];
byteBuffer.get(byteArray);
Image videoFrame = convertBytesToImage(byteArray, width, height);
fxImageView.setImage(videoFrame);
buffer.unmap();
}
input.dispose();
//Keep frames rolling
return FlowReturn.OK;
}
/**
* Updates the ImageView with the next frame in the pipeline, without
* removing it. This function is invoked when Gstreamer is not in a
* PLAYING state, but we can peek at what's to come.
*
* It's essential for displaying the initial frame when a video is first
* selected.
*
* @param sink Pipeline containing video data
* @return
*/
@Override
public FlowReturn newPreroll(AppSink sink) {
//Grab the next frame without removing it from the pipeline
Sample sample = sink.pullPreroll();
return setSample(sample);
}
/**
* Create an image from a byte array of pixels.
*
* @param pixels The byte array of pixels.
* @param width The width of the image.
* @param height The height of the image.
*
* @return The image.
*/
private Image convertBytesToImage(byte[] pixels, int width, int height) {
WritableImage image = new WritableImage(width, height);
PixelWriter pixelWriter = image.getPixelWriter();
pixelWriter.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);
return image;
}
/**
* Remove the current frame from the display
*/
void clear() {
fxImageView.setImage(null);
}
}
}

View File

@ -20,11 +20,13 @@ package org.sleuthkit.autopsy.contentviewers;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.freedesktop.gstreamer.GstException;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.datamodel.AbstractFile;
/**
@ -36,8 +38,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
private AbstractFile lastFile;
//UI
private final MediaPlayerPanel mediaPlayerPanel;
private final boolean mediaPlayerPanelInited;
private MediaPlayerPanel mediaPlayerPanel;
private final MediaViewImagePanel imagePanel;
private final boolean imagePanelInited;
@ -51,10 +52,14 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
initComponents();
// get the right panel for our platform
mediaPlayerPanel = new MediaPlayerPanel();
mediaPlayerPanelInited = mediaPlayerPanel.isInited();
try {
mediaPlayerPanel = new MediaPlayerPanel();
} catch (GstException | UnsatisfiedLinkError ex) {
LOGGER.log(Level.SEVERE, "Error initializing gstreamer for audio/video viewing and frame extraction capabilities", ex); //NON-NLS
MessageNotifyUtil.Notify.error(
NbBundle.getMessage(this.getClass(), "MediaFileViewer.initGst.gstException.msg"),
ex.getMessage());
}
imagePanel = new MediaViewImagePanel();
imagePanelInited = imagePanel.isInited();
@ -64,7 +69,10 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
private void customizeComponents() {
add(imagePanel, IMAGE_VIEWER_LAYER);
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
if(mediaPlayerPanel != null) {
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
}
showImagePanel();
}
@ -86,30 +94,31 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
/**
* Returns a list of mimetypes supported by this viewer
*
*
* @return list of supported mimetypes
*/
@Override
public List<String> getSupportedMIMETypes() {
List<String> mimeTypes = new ArrayList<>();
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
if(mediaPlayerPanel != null) {
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
}
return mimeTypes;
}
/**
* Set up the view to display the given file.
*
*
* @param file file to display
*/
@Override
public void setFile(AbstractFile file) {
try {
if (file == null) {
resetComponent();
return;
@ -120,14 +129,11 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
}
lastFile = file;
final Dimension dims = MediaFileViewer.this.getSize();
//logger.info("setting node on media viewer"); //NON-NLS
if (mediaPlayerPanelInited && mediaPlayerPanel.isSupported(file)) {
mediaPlayerPanel.loadFile(file, dims);
if (mediaPlayerPanel != null && mediaPlayerPanel.isSupported(file)) {
mediaPlayerPanel.loadFile(file);
this.showVideoPanel();
} else if (imagePanelInited && imagePanel.isSupported(file)) {
imagePanel.showImageFx(file, dims);
imagePanel.showImageFx(file);
this.showImagePanel();
}
} catch (Exception e) {
@ -142,7 +148,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
CardLayout layout = (CardLayout) this.getLayout();
layout.show(this, MEDIA_PLAYER_LAYER);
}
/**
* Show the image panel.
*/
@ -158,7 +164,9 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override
public void resetComponent() {
mediaPlayerPanel.reset();
if (mediaPlayerPanel != null) {
mediaPlayerPanel.reset();
}
imagePanel.reset();
lastFile = null;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -16,8 +16,8 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="controlPanel" max="32767" attributes="0"/>
<Component id="videoPanel" alignment="0" max="32767" attributes="0"/>
<Component id="controlPanel" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -41,7 +41,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="231" max="32767" attributes="0"/>
<EmptySpace min="0" pref="259" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -51,66 +51,116 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="playButton" min="-2" pref="64" max="-2" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="progressSlider" pref="680" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="progressLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressSlider" pref="265" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="progressLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="infoLabel" max="32767" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="VolumeIcon" min="-2" pref="64" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Component id="audioSlider" min="-2" pref="229" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="progressSlider" min="-2" max="-2" attributes="0"/>
<Component id="pauseButton" min="-2" max="-2" attributes="0"/>
<Component id="progressLabel" alignment="0" min="-2" pref="29" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="progressLabel" max="32767" attributes="0"/>
<Component id="progressSlider" max="32767" attributes="0"/>
</Group>
<Component id="playButton" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="audioSlider" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="VolumeIcon" alignment="3" min="-2" pref="23" max="-2" attributes="0"/>
<Component id="infoLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="pauseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.pauseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pauseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JSlider" name="progressSlider">
</Component>
<Component class="javax.swing.JLabel" name="progressLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.progressLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="value" type="int" value="0"/>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
</Property>
<Property name="doubleBuffered" type="boolean" value="true"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[36, 21]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 21]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="infoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="MediaViewVideoPanel.infoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.infoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="playButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.playButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="playButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="progressLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.progressLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="VolumeIcon">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.VolumeIcon.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSlider" name="audioSlider">
<Properties>
<Property name="majorTickSpacing" type="int" value="10"/>
<Property name="maximum" type="int" value="50"/>
<Property name="minorTickSpacing" type="int" value="5"/>
<Property name="paintTicks" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.audioSlider.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="value" type="int" value="25"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 21]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 21]"/>
</Property>
</Properties>
</Component>

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.contentviewers;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.Collections;
@ -172,9 +171,8 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
* Show the contents of the given AbstractFile as a visual image.
*
* @param file image file to show
* @param dims dimension of the parent window (ignored)
*/
void showImageFx(final AbstractFile file, final Dimension dims) {
void showImageFx(final AbstractFile file) {
if (!fxInited) {
return;
}

View File

@ -230,6 +230,20 @@ public class CreatePortableCaseModule implements GeneralReportModule {
return;
}
// Set up tracking to support any custom artifact or attribute types
for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) {
oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
}
for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
try {
oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel()));
} catch (TskCoreException ex) {
handleError("Error looking up attribute name " + type.getLabel(),
Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()),
ex, progressPanel);
}
}
// Copy the tagged files
try {
for(TagName tagName:tagNames) {
@ -245,20 +259,6 @@ public class CreatePortableCaseModule implements GeneralReportModule {
return;
}
// Set up tracking to support any custom artifact or attribute types
for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) {
oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
}
for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
try {
oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel()));
} catch (TskCoreException ex) {
handleError("Error looking up attribute name " + type.getLabel(),
Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()),
ex, progressPanel);
}
}
// Copy the tagged artifacts and associated files
try {
for(TagName tagName:tagNames) {
@ -577,17 +577,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
})
private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel) throws TskCoreException {
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
long newFileId;
CaseDbTransaction trans = portableSkCase.beginTransaction();
try {
newFileId = copyContent(content, trans);
trans.commit();
return newFileId;
} catch (TskCoreException ex) {
trans.rollback();
throw(ex);
}
return copyContent(content);
}
/**
@ -600,7 +590,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
*
* @throws TskCoreException
*/
private long copyContent(Content content, CaseDbTransaction trans) throws TskCoreException {
private long copyContent(Content content) throws TskCoreException {
// Check if we've already copied this content
if (oldIdToNewContent.containsKey(content.getId())) {
@ -612,67 +602,82 @@ public class CreatePortableCaseModule implements GeneralReportModule {
// - Copy this content
long parentId = 0;
if (content.getParent() != null) {
parentId = copyContent(content.getParent(), trans);
parentId = copyContent(content.getParent());
}
Content newContent;
if (content instanceof Image) {
Image image = (Image)content;
newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
} else if (content instanceof VolumeSystem) {
VolumeSystem vs = (VolumeSystem)content;
newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
} else if (content instanceof Volume) {
Volume vs = (Volume)content;
newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
vs.getDescription(), vs.getFlags(), trans);
} else if (content instanceof FileSystem) {
FileSystem fs = (FileSystem)content;
newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
fs.getName(), trans);
} else if (content instanceof AbstractFile) {
AbstractFile abstractFile = (AbstractFile)content;
if (abstractFile instanceof LocalFilesDataSource) {
LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile;
newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
} else {
if (abstractFile.isDir()) {
newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
} else {
try {
// Copy the file
String fileName = abstractFile.getId() + "-" + FileUtil.escapeFileName(abstractFile.getName());
String exportSubFolder = getExportSubfolder(abstractFile);
File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
File localFile = new File(exportFolder, fileName);
ContentUtils.writeToFile(abstractFile, localFile);
// Get the new parent object in the portable case database
Content oldParent = abstractFile.getParent();
if (! oldIdToNewContent.containsKey(oldParent.getId())) {
throw new TskCoreException("Parent of file with ID " + abstractFile.getId() + " has not been created");
}
Content newParent = oldIdToNewContent.get(oldParent.getId());
// Construct the relative path to the copied file
String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
true, TskData.EncodingType.NONE,
newParent, trans);
} catch (IOException ex) {
throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID "
+ abstractFile.getId(), ex);
}
}
}
if (content instanceof BlackboardArtifact) {
BlackboardArtifact artifactToCopy = (BlackboardArtifact)content;
newContent = copyArtifact(parentId, artifactToCopy);
} else {
throw new TskCoreException("Trying to copy unexpected Content type " + content.getClass().getName());
CaseDbTransaction trans = portableSkCase.beginTransaction();
try {
if (content instanceof Image) {
Image image = (Image)content;
newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
} else if (content instanceof VolumeSystem) {
VolumeSystem vs = (VolumeSystem)content;
newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
} else if (content instanceof Volume) {
Volume vs = (Volume)content;
newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
vs.getDescription(), vs.getFlags(), trans);
} else if (content instanceof FileSystem) {
FileSystem fs = (FileSystem)content;
newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
fs.getName(), trans);
} else if (content instanceof BlackboardArtifact) {
BlackboardArtifact artifactToCopy = (BlackboardArtifact)content;
newContent = copyArtifact(parentId, artifactToCopy);
} else if (content instanceof AbstractFile) {
AbstractFile abstractFile = (AbstractFile)content;
if (abstractFile instanceof LocalFilesDataSource) {
LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile;
newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
} else {
if (abstractFile.isDir()) {
newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
} else {
try {
// Copy the file
String fileName = abstractFile.getId() + "-" + FileUtil.escapeFileName(abstractFile.getName());
String exportSubFolder = getExportSubfolder(abstractFile);
File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
File localFile = new File(exportFolder, fileName);
ContentUtils.writeToFile(abstractFile, localFile);
// Get the new parent object in the portable case database
Content oldParent = abstractFile.getParent();
if (! oldIdToNewContent.containsKey(oldParent.getId())) {
throw new TskCoreException("Parent of file with ID " + abstractFile.getId() + " has not been created");
}
Content newParent = oldIdToNewContent.get(oldParent.getId());
// Construct the relative path to the copied file
String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
true, TskData.EncodingType.NONE,
newParent, trans);
} catch (IOException ex) {
throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID "
+ abstractFile.getId(), ex);
}
}
}
} else {
throw new TskCoreException("Trying to copy unexpected Content type " + content.getClass().getName());
}
trans.commit();
} catch (TskCoreException ex) {
trans.rollback();
throw(ex);
}
}
// Save the new object

View File

@ -514,7 +514,7 @@ public final class DrawableDB {
private boolean initializeDBSchema() {
dbWriteLock();
try {
boolean existingDB = true;
boolean drawableDbTablesExist = true;
if (isClosed()) {
logger.log(Level.SEVERE, "The drawables database is closed"); //NON-NLS
@ -533,11 +533,11 @@ public final class DrawableDB {
*/
try (Statement stmt = con.createStatement()) {
// Check if the database is a new or existing database
existingDB = doesTableExist("datasources");
// Check if the database is new or an existing database
drawableDbTablesExist = doesTableExist("drawable_files");
if (false == doesTableExist(IG_DB_INFO_TABLE)) {
try {
VersionNumber ig_creation_schema_version = existingDB
VersionNumber ig_creation_schema_version = drawableDbTablesExist
? IG_STARTING_SCHEMA_VERSION
: IG_SCHEMA_VERSION;
@ -651,7 +651,8 @@ public final class DrawableDB {
String autogenKeyType = (DbType.POSTGRESQL == tskCase.getDatabaseType()) ? "BIGSERIAL" : "INTEGER";
try {
VersionNumber ig_creation_schema_version = existingDB
boolean caseDbTablesExist = tskCase.getCaseDbAccessManager().tableExists(GROUPS_TABLENAME);
VersionNumber ig_creation_schema_version = caseDbTablesExist
? IG_STARTING_SCHEMA_VERSION
: IG_SCHEMA_VERSION;
@ -935,13 +936,14 @@ public final class DrawableDB {
*/
private VersionNumber upgradeCaseDbIgSchema1dot0TO1dot1(VersionNumber currVersion, CaseDbTransaction caseDbTransaction ) throws TskCoreException {
if (currVersion.getMajor() != 1 ||
currVersion.getMinor() != 0) {
// Upgrade if current version is 1.0
// or 1.1 - a bug in versioning alllowed some databases to be versioned as 1.1 without the actual corresponding upgrade. This allows such databases to be fixed, if needed.
if (!(currVersion.getMajor() == 1 &&
(currVersion.getMinor() == 0 || currVersion.getMinor() == 1))) {
return currVersion;
}
// 1.0 -> 1.1 upgrade
// Add a 'isAnalyzed' column to groups table in CaseDB
// Add a 'is_analyzed' column to groups table in CaseDB
String alterSQL = " ADD COLUMN is_analyzed integer DEFAULT 1 "; //NON-NLS
if (false == tskCase.getCaseDbAccessManager().columnExists(GROUPS_TABLENAME, "is_analyzed", caseDbTransaction )) {
tskCase.getCaseDbAccessManager().alterTable(GROUPS_TABLENAME, alterSQL, caseDbTransaction);