mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Updated vlc video component use and fixed bugs
This commit is contained in:
parent
fce1446bbc
commit
a18fdc33e7
@ -1,256 +1,259 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2013 Basis Technology Corp.
|
* Copyright 2011-2013 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.corecomponents;
|
package org.sleuthkit.autopsy.corecomponents;
|
||||||
|
|
||||||
import java.awt.CardLayout;
|
import java.awt.CardLayout;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.openide.util.lookup.ServiceProviders;
|
import org.openide.util.lookup.ServiceProviders;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Media content viewer for videos, sounds and images.
|
* Media content viewer for videos, sounds and images.
|
||||||
*/
|
*/
|
||||||
@ServiceProviders(value = {
|
@ServiceProviders(value = {
|
||||||
@ServiceProvider(service = DataContentViewer.class, position = 5)
|
@ServiceProvider(service = DataContentViewer.class, position = 5)
|
||||||
})
|
})
|
||||||
public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer {
|
public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer {
|
||||||
|
|
||||||
private String[] IMAGES; // use javafx supported
|
private String[] IMAGES; // use javafx supported
|
||||||
private static final String[] VIDEOS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"};
|
private static final String[] VIDEOS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"};
|
||||||
private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"};
|
private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"};
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName());
|
private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName());
|
||||||
|
|
||||||
private AbstractFile lastFile;
|
private AbstractFile lastFile;
|
||||||
//UI
|
//UI
|
||||||
private final MediaViewVideoPanel videoPanel;
|
private final MediaViewVideoPanel videoPanel;
|
||||||
private final MediaViewImagePanel imagePanel;
|
private final MediaViewImagePanel imagePanel;
|
||||||
private boolean videoPanelInited;
|
private boolean videoPanelInited;
|
||||||
private boolean imagePanelInited;
|
private boolean imagePanelInited;
|
||||||
|
|
||||||
private static final String IMAGE_VIEWER_LAYER = "IMAGE";
|
private static final String IMAGE_VIEWER_LAYER = "IMAGE";
|
||||||
private static final String VIDEO_VIEWER_LAYER = "VIDEO";
|
private static final String VIDEO_VIEWER_LAYER = "VIDEO";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form DataContentViewerVideo
|
* Creates new form DataContentViewerVideo
|
||||||
*/
|
*/
|
||||||
public DataContentViewerMedia() {
|
public DataContentViewerMedia() {
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
videoPanel = new MediaViewVideoPanel();
|
videoPanel = new MediaViewVideoPanel();
|
||||||
imagePanel = new MediaViewImagePanel();
|
imagePanel = new MediaViewImagePanel();
|
||||||
videoPanelInited = videoPanel.isInited();
|
videoPanelInited = videoPanel.isInited();
|
||||||
imagePanelInited = imagePanel.isInited();
|
imagePanelInited = imagePanel.isInited();
|
||||||
|
|
||||||
customizeComponents();
|
customizeComponents();
|
||||||
logger.log(Level.INFO, "Created MediaView instance: " + this);
|
logger.log(Level.INFO, "Created MediaView instance: " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
logger.log(Level.INFO, "Supported image formats by javafx image viewer: ");
|
logger.log(Level.INFO, "Supported image formats by javafx image viewer: ");
|
||||||
//initialize supported image types
|
//initialize supported image types
|
||||||
//TODO use mime-types instead once we have support
|
//TODO use mime-types instead once we have support
|
||||||
String[] fxSupportedImagesSuffixes = ImageIO.getReaderFileSuffixes();
|
String[] fxSupportedImagesSuffixes = ImageIO.getReaderFileSuffixes();
|
||||||
IMAGES = new String[fxSupportedImagesSuffixes.length];
|
IMAGES = new String[fxSupportedImagesSuffixes.length];
|
||||||
for (int i = 0; i < fxSupportedImagesSuffixes.length; ++i) {
|
for (int i = 0; i < fxSupportedImagesSuffixes.length; ++i) {
|
||||||
String suffix = fxSupportedImagesSuffixes[i];
|
String suffix = fxSupportedImagesSuffixes[i];
|
||||||
logger.log(Level.INFO, "suffix: " + suffix);
|
logger.log(Level.INFO, "suffix: " + suffix);
|
||||||
IMAGES[i] = "." + suffix;
|
IMAGES[i] = "." + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
add(imagePanel, IMAGE_VIEWER_LAYER);
|
add(imagePanel, IMAGE_VIEWER_LAYER);
|
||||||
add(videoPanel, VIDEO_VIEWER_LAYER);
|
add(videoPanel, VIDEO_VIEWER_LAYER);
|
||||||
|
|
||||||
switchPanels(false);
|
switchPanels(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
* regenerated by the Form Editor.
|
* regenerated by the Form Editor.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
setLayout(new java.awt.CardLayout());
|
setLayout(new java.awt.CardLayout());
|
||||||
getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.AccessibleContext.accessibleDescription")); // NOI18N
|
getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.AccessibleContext.accessibleDescription")); // NOI18N
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setNode(Node selectedNode) {
|
public void setNode(Node selectedNode) {
|
||||||
|
try {
|
||||||
if (selectedNode == null) {
|
if (selectedNode == null) {
|
||||||
videoPanel.reset();
|
videoPanel.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class);
|
AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.equals(lastFile)) {
|
if (file.equals(lastFile)) {
|
||||||
return; //prevent from loading twice if setNode() called mult. times
|
return; //prevent from loading twice if setNode() called mult. times
|
||||||
} else {
|
} else {
|
||||||
lastFile = file;
|
lastFile = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
videoPanel.reset();
|
videoPanel.reset();
|
||||||
|
|
||||||
final Dimension dims = DataContentViewerMedia.this.getSize();
|
final Dimension dims = DataContentViewerMedia.this.getSize();
|
||||||
|
|
||||||
if (imagePanelInited && containsExt(file.getName(), IMAGES)) {
|
if (imagePanelInited && containsExt(file.getName(), IMAGES)) {
|
||||||
imagePanel.showImageFx(file, dims);
|
imagePanel.showImageFx(file, dims);
|
||||||
this.switchPanels(false);
|
this.switchPanels(false);
|
||||||
} else if (videoPanelInited
|
} else if (videoPanelInited
|
||||||
&& (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS))) {
|
&& (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS))) {
|
||||||
videoPanel.setupVideo(file, dims);
|
videoPanel.setupVideo(file, dims);
|
||||||
switchPanels(true);
|
switchPanels(true);
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "Exception while setting node", e);
|
||||||
/**
|
}
|
||||||
* switch to visible video or image panel
|
}
|
||||||
*
|
|
||||||
* @param showVideo true if video panel, false if image panel
|
/**
|
||||||
*/
|
* switch to visible video or image panel
|
||||||
private void switchPanels(boolean showVideo) {
|
*
|
||||||
CardLayout layout = (CardLayout)this.getLayout();
|
* @param showVideo true if video panel, false if image panel
|
||||||
if (showVideo) {
|
*/
|
||||||
layout.show(this, VIDEO_VIEWER_LAYER);
|
private void switchPanels(boolean showVideo) {
|
||||||
} else {
|
CardLayout layout = (CardLayout)this.getLayout();
|
||||||
layout.show(this, IMAGE_VIEWER_LAYER);
|
if (showVideo) {
|
||||||
}
|
layout.show(this, VIDEO_VIEWER_LAYER);
|
||||||
}
|
} else {
|
||||||
|
layout.show(this, IMAGE_VIEWER_LAYER);
|
||||||
@Override
|
}
|
||||||
public String getTitle() {
|
}
|
||||||
return "Media View";
|
|
||||||
}
|
@Override
|
||||||
|
public String getTitle() {
|
||||||
@Override
|
return "Media View";
|
||||||
public String getToolTip() {
|
}
|
||||||
return "Displays supported multimedia files (images, videos, audio)";
|
|
||||||
}
|
@Override
|
||||||
|
public String getToolTip() {
|
||||||
@Override
|
return "Displays supported multimedia files (images, videos, audio)";
|
||||||
public DataContentViewer createInstance() {
|
}
|
||||||
return new DataContentViewerMedia();
|
|
||||||
}
|
@Override
|
||||||
|
public DataContentViewer createInstance() {
|
||||||
@Override
|
return new DataContentViewerMedia();
|
||||||
public Component getComponent() {
|
}
|
||||||
return this;
|
|
||||||
}
|
@Override
|
||||||
|
public Component getComponent() {
|
||||||
@Override
|
return this;
|
||||||
public void resetComponent() {
|
}
|
||||||
// we don't want this to do anything
|
|
||||||
// because we already reset on each selected node
|
@Override
|
||||||
}
|
public void resetComponent() {
|
||||||
|
// we don't want this to do anything
|
||||||
|
// because we already reset on each selected node
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public boolean isSupported(Node node) {
|
|
||||||
|
|
||||||
if (node == null) {
|
@Override
|
||||||
return false;
|
public boolean isSupported(Node node) {
|
||||||
}
|
|
||||||
|
if (node == null) {
|
||||||
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
return false;
|
||||||
if (file == null) {
|
}
|
||||||
return false;
|
|
||||||
}
|
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
||||||
|
if (file == null) {
|
||||||
|
return false;
|
||||||
if (file.getSize() == 0) {
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
if (file.getSize() == 0) {
|
||||||
String name = file.getName().toLowerCase();
|
return false;
|
||||||
|
}
|
||||||
if (imagePanelInited && containsExt(name, IMAGES)) {
|
|
||||||
return true;
|
String name = file.getName().toLowerCase();
|
||||||
} //for gstreamer formats, check if initialized first, then
|
|
||||||
//support audio formats, and video formats
|
if (imagePanelInited && containsExt(name, IMAGES)) {
|
||||||
else if (videoPanelInited && videoPanel.isInited()
|
return true;
|
||||||
&& (containsExt(name, AUDIOS)
|
} //for gstreamer formats, check if initialized first, then
|
||||||
|| (containsExt(name, VIDEOS)))) {
|
//support audio formats, and video formats
|
||||||
return true;
|
else if (videoPanelInited && videoPanel.isInited()
|
||||||
}
|
&& (containsExt(name, AUDIOS)
|
||||||
|
|| (containsExt(name, VIDEOS)))) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return false;
|
||||||
public int isPreferred(Node node, boolean isSupported) {
|
}
|
||||||
if (isSupported) {
|
|
||||||
//special case, check if deleted video, then do not make it preferred
|
@Override
|
||||||
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
public int isPreferred(Node node, boolean isSupported) {
|
||||||
if (file == null) {
|
if (isSupported) {
|
||||||
return 0;
|
//special case, check if deleted video, then do not make it preferred
|
||||||
}
|
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
|
||||||
String name = file.getName().toLowerCase();
|
if (file == null) {
|
||||||
|
return 0;
|
||||||
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
}
|
||||||
if (containsExt(name, VIDEOS) && deleted) {
|
String name = file.getName().toLowerCase();
|
||||||
return 0;
|
|
||||||
} else {
|
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||||
return 7;
|
if (containsExt(name, VIDEOS) && deleted) {
|
||||||
}
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 7;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
return 0;
|
||||||
private static boolean containsExt(String name, String[] exts) {
|
}
|
||||||
int extStart = name.lastIndexOf(".");
|
}
|
||||||
String ext = "";
|
|
||||||
if (extStart != -1) {
|
private static boolean containsExt(String name, String[] exts) {
|
||||||
ext = name.substring(extStart, name.length()).toLowerCase();
|
int extStart = name.lastIndexOf(".");
|
||||||
}
|
String ext = "";
|
||||||
return Arrays.asList(exts).contains(ext);
|
if (extStart != -1) {
|
||||||
}
|
ext = name.substring(extStart, name.length()).toLowerCase();
|
||||||
}
|
}
|
||||||
|
return Arrays.asList(exts).contains(ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,8 +38,6 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
import org.gstreamer.elements.PlayBin2;
|
|
||||||
import org.gstreamer.swing.VideoComponent;
|
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
@ -68,23 +66,21 @@ import uk.co.caprica.vlcj.runtime.RuntimeUtil;
|
|||||||
public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapture {
|
public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapture {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName());
|
||||||
private boolean gstInited;
|
|
||||||
private boolean vlcInited;
|
private boolean vlcInited;
|
||||||
private static final long MIN_FRAME_INTERVAL_MILLIS = 500;
|
private static final long MIN_FRAME_INTERVAL_MILLIS = 500;
|
||||||
private static final long FRAME_CAPTURE_TIMEOUT_MILLIS = 1000;
|
private static final long FRAME_CAPTURE_TIMEOUT_MILLIS = 1000;
|
||||||
private static final String MEDIA_PLAYER_ERROR_STRING = "The media player cannot process this file.";
|
private static final String MEDIA_PLAYER_ERROR_STRING = "The media player cannot process this file.";
|
||||||
|
private static final int POS_FACTOR = 10000;
|
||||||
//playback
|
//playback
|
||||||
private long durationMillis = 0;
|
private long durationMillis = 0;
|
||||||
private VideoProgressWorker videoProgressWorker;
|
private VideoProgressWorker videoProgressWorker;
|
||||||
private int totalHours, totalMinutes, totalSeconds;
|
private int totalHours, totalMinutes, totalSeconds;
|
||||||
private volatile PlayBin2 gstPlaybin2;
|
|
||||||
private MediaPlayer vlcMediaPlayer;
|
private MediaPlayer vlcMediaPlayer;
|
||||||
private VideoComponent gstVideoComponent;
|
|
||||||
private EmbeddedMediaPlayerComponent vlcVideoComponent;
|
private EmbeddedMediaPlayerComponent vlcVideoComponent;
|
||||||
private boolean autoTracking = false; // true if the slider is moving automatically
|
private boolean autoTracking = false; // true if the slider is moving automatically
|
||||||
private final Object playbinLock = new Object(); // lock for synchronization of gstPlaybin2 player
|
|
||||||
private AbstractFile currentFile;
|
private AbstractFile currentFile;
|
||||||
private boolean isFileLoaded;
|
private java.io.File currentVideoFile;
|
||||||
|
private boolean replay;
|
||||||
private Set<String> badVideoFiles = Collections.synchronizedSet(new HashSet<String>());
|
private Set<String> badVideoFiles = Collections.synchronizedSet(new HashSet<String>());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,12 +108,10 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EmbeddedMediaPlayerComponent getVideoComponent() {
|
public EmbeddedMediaPlayerComponent getVideoComponent() {
|
||||||
// return gstVideoComponent;
|
|
||||||
return vlcVideoComponent;
|
return vlcVideoComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInited() {
|
public boolean isInited() {
|
||||||
// return gstInited;
|
|
||||||
return vlcInited;
|
return vlcInited;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,14 +131,15 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent e) {
|
public void stateChanged(ChangeEvent e) {
|
||||||
int time = progressSlider.getValue();
|
if (vlcMediaPlayer != null && !autoTracking) {
|
||||||
if (vlcMediaPlayer != null && !autoTracking) {
|
float positionValue = progressSlider.getValue() / (float) POS_FACTOR;
|
||||||
boolean wasPlaying = !vlcMediaPlayer.isPlaying();
|
// Avoid end of file freeze-up
|
||||||
vlcMediaPlayer.setPause(true);
|
if (positionValue > 0.99f) {
|
||||||
vlcMediaPlayer.setTime(time);
|
positionValue = 0.99f;
|
||||||
vlcMediaPlayer.setPause(wasPlaying);
|
|
||||||
}
|
}
|
||||||
|
vlcMediaPlayer.setPosition(positionValue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +156,28 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
pauseButton.setText("||");
|
pauseButton.setText("||");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the video for replaying the current file.
|
||||||
|
*
|
||||||
|
* Called when finished Event is fired from MediaPlayer.
|
||||||
|
*/
|
||||||
|
private void finished() {
|
||||||
|
if (videoProgressWorker != null) {
|
||||||
|
videoProgressWorker.cancel(true);
|
||||||
|
videoProgressWorker = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log(Level.INFO, "Resetting media");
|
||||||
|
replay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the VLC library dll using JNA.
|
||||||
|
*
|
||||||
|
* @return <code>true</code>, if the library was loaded correctly.
|
||||||
|
* <code>false</code>, otherwise.
|
||||||
|
*/
|
||||||
private boolean initVlc() {
|
private boolean initVlc() {
|
||||||
try {
|
try {
|
||||||
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
|
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
|
||||||
@ -184,7 +200,7 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
void setupVideo(final AbstractFile file, final Dimension dims) {
|
void setupVideo(final AbstractFile file, final Dimension dims) {
|
||||||
infoLabel.setText("");
|
infoLabel.setText("");
|
||||||
currentFile = file;
|
currentFile = file;
|
||||||
isFileLoaded = false;
|
replay = false;
|
||||||
final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
infoLabel.setText("Playback of deleted videos is not supported, use an external player.");
|
infoLabel.setText("Playback of deleted videos is not supported, use an external player.");
|
||||||
@ -204,8 +220,6 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
infoLabel.setToolTipText(path);
|
infoLabel.setToolTipText(path);
|
||||||
pauseButton.setEnabled(true);
|
pauseButton.setEnabled(true);
|
||||||
progressSlider.setEnabled(true);
|
progressSlider.setEnabled(true);
|
||||||
|
|
||||||
java.io.File ioFile = getJFile(file);
|
|
||||||
|
|
||||||
vlcVideoComponent = new EmbeddedMediaPlayerComponent();
|
vlcVideoComponent = new EmbeddedMediaPlayerComponent();
|
||||||
vlcMediaPlayer = vlcVideoComponent.getMediaPlayer();
|
vlcMediaPlayer = vlcVideoComponent.getMediaPlayer();
|
||||||
@ -216,6 +230,9 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
videoPanel.add(vlcVideoComponent);
|
videoPanel.add(vlcVideoComponent);
|
||||||
videoPanel.setVisible(true);
|
videoPanel.setVisible(true);
|
||||||
logger.log(Level.INFO, "Created media player.");
|
logger.log(Level.INFO, "Created media player.");
|
||||||
|
|
||||||
|
ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile));
|
||||||
|
em.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
@ -230,7 +247,13 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
if (!isInited()) {
|
if (!isInited()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get rid of any existing videoProgressWorker thread
|
||||||
|
if (videoProgressWorker != null) {
|
||||||
|
videoProgressWorker.cancel(true);
|
||||||
|
videoProgressWorker = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (vlcMediaPlayer != null) {
|
if (vlcMediaPlayer != null) {
|
||||||
if (vlcMediaPlayer.isPlaying()) {
|
if (vlcMediaPlayer.isPlaying()) {
|
||||||
vlcMediaPlayer.stop();
|
vlcMediaPlayer.stop();
|
||||||
@ -245,13 +268,8 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
logger.log(Level.INFO, "Released video component");
|
logger.log(Level.INFO, "Released video component");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get rid of any existing videoProgressWorker thread
|
|
||||||
if (videoProgressWorker != null) {
|
|
||||||
videoProgressWorker.cancel(true);
|
|
||||||
videoProgressWorker = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentFile = null;
|
currentFile = null;
|
||||||
|
currentVideoFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private java.io.File getJFile(AbstractFile file) {
|
private java.io.File getJFile(AbstractFile file) {
|
||||||
@ -268,6 +286,45 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
java.io.File tempFile = new java.io.File(tempPath);
|
java.io.File tempFile = new java.io.File(tempPath);
|
||||||
return tempFile;
|
return tempFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void playMedia() {
|
||||||
|
logger.log(Level.INFO, "In play media");
|
||||||
|
if (currentVideoFile == null || !currentVideoFile.exists()) {
|
||||||
|
progressLabel.setText("Error buffering file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean mediaPrepared = vlcMediaPlayer.prepareMedia(currentVideoFile.getAbsolutePath());
|
||||||
|
if (mediaPrepared) {
|
||||||
|
vlcMediaPlayer.parseMedia();
|
||||||
|
durationMillis = vlcMediaPlayer.getMediaMeta().getLength();
|
||||||
|
logger.log(Level.INFO, "Media loaded correctly");
|
||||||
|
} else {
|
||||||
|
progressLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pick out the total hours, minutes, seconds
|
||||||
|
long durationSeconds = (int) durationMillis / 1000;
|
||||||
|
totalHours = (int) durationSeconds / 3600;
|
||||||
|
durationSeconds -= totalHours * 3600;
|
||||||
|
totalMinutes = (int) durationSeconds / 60;
|
||||||
|
durationSeconds -= totalMinutes * 60;
|
||||||
|
totalSeconds = (int) durationSeconds;
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
progressSlider.setMaximum(POS_FACTOR);
|
||||||
|
progressSlider.setMinimum(0);
|
||||||
|
|
||||||
|
logger.log(Level.INFO, "Starting the media...");
|
||||||
|
vlcMediaPlayer.start();
|
||||||
|
pauseButton.setText("||");
|
||||||
|
videoProgressWorker = new VideoProgressWorker();
|
||||||
|
videoProgressWorker.execute();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param file a video file from which to capture frames
|
* @param file a video file from which to capture frames
|
||||||
@ -359,6 +416,8 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
progressSlider.setSnapToTicks(true);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(MediaViewVideoPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
|
||||||
@ -407,15 +466,16 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
|
private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
|
||||||
if (!isFileLoaded) {
|
if (replay) {
|
||||||
// First time play button is pressed
|
// File has completed playing. Play button now replays
|
||||||
logger.log(Level.INFO, "Loading media file");
|
logger.log(Level.INFO, "Replaying video.");
|
||||||
ExtractMedia em = new ExtractMedia(currentFile, getJFile(currentFile));
|
replay = false;
|
||||||
em.execute();
|
playMedia();
|
||||||
em.getExtractedBytes();
|
|
||||||
} else if (vlcMediaPlayer.isPlaying()) {
|
} else if (vlcMediaPlayer.isPlaying()) {
|
||||||
|
logger.log(Level.INFO, "Pausing.");
|
||||||
this.pause();
|
this.pause();
|
||||||
} else {
|
} else {
|
||||||
|
logger.log(Level.INFO, "Playing");
|
||||||
this.unPause();
|
this.unPause();
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_pauseButtonActionPerformed
|
}//GEN-LAST:event_pauseButtonActionPerformed
|
||||||
@ -428,10 +488,23 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
private javax.swing.JPanel videoPanel;
|
private javax.swing.JPanel videoPanel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
void releaseVlcComponents() {
|
||||||
|
if (vlcMediaPlayer != null) {
|
||||||
|
vlcMediaPlayer.release();
|
||||||
|
vlcMediaPlayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlcVideoComponent != null) {
|
||||||
|
vlcVideoComponent.release();
|
||||||
|
vlcVideoComponent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class VideoProgressWorker extends SwingWorker<Object, Object> {
|
private class VideoProgressWorker extends SwingWorker<Object, Object> {
|
||||||
|
|
||||||
private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d ";
|
private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d ";
|
||||||
private long millisElapsed = 0;
|
private long millisElapsed = 0;
|
||||||
|
private float currentPosition = 0.0f;
|
||||||
private final long INTER_FRAME_PERIOD_MS = 20;
|
private final long INTER_FRAME_PERIOD_MS = 20;
|
||||||
private final long END_TIME_MARGIN_MS = 50;
|
private final long END_TIME_MARGIN_MS = 50;
|
||||||
private boolean hadError = false;
|
private boolean hadError = false;
|
||||||
@ -441,28 +514,23 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void resetVideo() throws Exception {
|
private void resetVideo() throws Exception {
|
||||||
logger.log(Level.INFO, "Resetting video.");
|
|
||||||
if (vlcMediaPlayer != null) {
|
|
||||||
vlcMediaPlayer.stop();
|
|
||||||
}
|
|
||||||
pauseButton.setText("►");
|
pauseButton.setText("►");
|
||||||
progressSlider.setValue(0);
|
|
||||||
|
|
||||||
String durationStr = String.format(durationFormat, 0, 0, 0,
|
String durationStr = String.format(durationFormat, 0, 0, 0,
|
||||||
totalHours, totalMinutes, totalSeconds);
|
totalHours, totalMinutes, totalSeconds);
|
||||||
progressLabel.setText(durationStr);
|
progressLabel.setText(durationStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* @return true while millisElapsed is greater than END_TIME_MARGIN_MS
|
// * @return true while millisElapsed is greater than END_TIME_MARGIN_MS
|
||||||
* from durationMillis. This is used to indicate when the video has
|
// * from durationMillis. This is used to indicate when the video has
|
||||||
* ended because for some videos the time elapsed never becomes equal to
|
// * ended because for some videos the time elapsed never becomes equal to
|
||||||
* the reported duration of the video.
|
// * the reported duration of the video.
|
||||||
*/
|
// */
|
||||||
private boolean hasNotEnded() {
|
// private boolean hasNotEnded() {
|
||||||
boolean ended = (durationMillis - millisElapsed) > END_TIME_MARGIN_MS;
|
// boolean ended = (durationMillis - millisElapsed) > END_TIME_MARGIN_MS;
|
||||||
return ended;
|
// return ended;
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object doInBackground() throws Exception {
|
protected Object doInBackground() throws Exception {
|
||||||
@ -471,10 +539,11 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
progressSlider.setEnabled(true);
|
progressSlider.setEnabled(true);
|
||||||
|
|
||||||
int elapsedHours = -1, elapsedMinutes = -1, elapsedSeconds = -1;
|
int elapsedHours = -1, elapsedMinutes = -1, elapsedSeconds = -1;
|
||||||
while (hasNotEnded() && isMediaPlayerReady() && !isCancelled()) {
|
while (isMediaPlayerReady() && !isCancelled()) {
|
||||||
|
|
||||||
millisElapsed = vlcMediaPlayer.getTime();
|
millisElapsed = vlcMediaPlayer.getTime();
|
||||||
|
currentPosition = vlcMediaPlayer.getPosition();
|
||||||
|
|
||||||
// pick out the elapsed hours, minutes, seconds
|
// pick out the elapsed hours, minutes, seconds
|
||||||
long secondsElapsed = millisElapsed / 1000;
|
long secondsElapsed = millisElapsed / 1000;
|
||||||
elapsedHours = (int) secondsElapsed / 3600;
|
elapsedHours = (int) secondsElapsed / 3600;
|
||||||
@ -489,7 +558,7 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
|
|
||||||
progressLabel.setText(durationStr);
|
progressLabel.setText(durationStr);
|
||||||
autoTracking = true;
|
autoTracking = true;
|
||||||
progressSlider.setValue((int) millisElapsed);
|
progressSlider.setValue((int) (currentPosition * POS_FACTOR));
|
||||||
autoTracking = false;
|
autoTracking = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -562,58 +631,41 @@ public class MediaViewVideoPanel extends javax.swing.JPanel implements FrameCapt
|
|||||||
logger.log(Level.SEVERE, "Fatal error during media buffering.", ex);
|
logger.log(Level.SEVERE, "Fatal error during media buffering.", ex);
|
||||||
} finally {
|
} finally {
|
||||||
progress.finish();
|
progress.finish();
|
||||||
isFileLoaded = true;
|
|
||||||
if (!this.isCancelled()) {
|
if (!this.isCancelled()) {
|
||||||
logger.log(Level.INFO, "Loaded media file");
|
logger.log(Level.INFO, "Loaded media file");
|
||||||
|
currentVideoFile = jFile;
|
||||||
playMedia();
|
playMedia();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void playMedia() {
|
|
||||||
if (jFile == null || !jFile.exists()) {
|
|
||||||
progressLabel.setText("Error buffering file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean mediaPrepared = vlcMediaPlayer.prepareMedia(jFile.getAbsolutePath());
|
|
||||||
if (mediaPrepared) {
|
|
||||||
vlcMediaPlayer.parseMedia();
|
|
||||||
durationMillis = vlcMediaPlayer.getMediaMeta().getLength();
|
|
||||||
logger.log(Level.INFO, "Media loaded correctly");
|
|
||||||
} else {
|
|
||||||
progressLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pick out the total hours, minutes, seconds
|
|
||||||
long durationSeconds = (int) durationMillis / 1000;
|
|
||||||
totalHours = (int) durationSeconds / 3600;
|
|
||||||
durationSeconds -= totalHours * 3600;
|
|
||||||
totalMinutes = (int) durationSeconds / 60;
|
|
||||||
durationSeconds -= totalMinutes * 60;
|
|
||||||
totalSeconds = (int) durationSeconds;
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
progressSlider.setMaximum((int) durationMillis);
|
|
||||||
progressSlider.setMinimum(0);
|
|
||||||
|
|
||||||
logger.log(Level.INFO, "Starting the media...");
|
|
||||||
vlcMediaPlayer.start();
|
|
||||||
pauseButton.setText("||");
|
|
||||||
videoProgressWorker = new VideoProgressWorker();
|
|
||||||
videoProgressWorker.execute();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VlcMediaPlayerEventListener extends MediaPlayerEventAdapter {
|
private class VlcMediaPlayerEventListener extends MediaPlayerEventAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished(MediaPlayer mediaPlayer) {
|
||||||
|
logger.log(Level.INFO, "Media Player finished playing the media");
|
||||||
|
finished();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void error(MediaPlayer mediaPlayer) {
|
public void error(MediaPlayer mediaPlayer) {
|
||||||
logger.log(Level.INFO, "an Error occured.");
|
logger.log(Level.INFO, "an Error occured.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mediaDurationChanged(MediaPlayer mediaPlayer, long newDuration) {
|
||||||
|
logger.log(Level.INFO, "DURATION CHANGED: " + newDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mediaFreed(MediaPlayer mediaPlayer) {
|
||||||
|
logger.log(Level.INFO, "Media was freed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lengthChanged(MediaPlayer mediaPlayer, long newLength) {
|
||||||
|
logger.log(Level.INFO, "LENGTH CHANGED: " + newLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user