mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 08:26:15 +00:00
Merge pull request #1475 from millmanorama/application/octet-stream_fix
Application/octet stream fix
This commit is contained in:
commit
5d8a59a10a
@ -22,7 +22,6 @@ import java.awt.CardLayout;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import static java.util.Objects.nonNull;
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -32,10 +31,7 @@ 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.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.AbstractFile.MimeMatchEnum;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,11 +48,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
|||||||
private final MediaViewVideoPanel videoPanel;
|
private final MediaViewVideoPanel videoPanel;
|
||||||
private final boolean videoPanelInited;
|
private final boolean videoPanelInited;
|
||||||
private final SortedSet<String> videoExtensions; // get them from the panel
|
private final SortedSet<String> videoExtensions; // get them from the panel
|
||||||
private final SortedSet<String> videoMimes;
|
|
||||||
private final MediaViewImagePanel imagePanel;
|
private final MediaViewImagePanel imagePanel;
|
||||||
private final boolean imagePanelInited;
|
private final boolean imagePanelInited;
|
||||||
private final SortedSet<String> imageExtensions; // get them from the panel
|
|
||||||
private final SortedSet<String> imageMimes;
|
|
||||||
|
|
||||||
private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS
|
private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS
|
||||||
private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS
|
private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS
|
||||||
@ -72,12 +65,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
|||||||
videoPanel = MediaViewVideoPanel.createVideoPanel();
|
videoPanel = MediaViewVideoPanel.createVideoPanel();
|
||||||
videoPanelInited = videoPanel.isInited();
|
videoPanelInited = videoPanel.isInited();
|
||||||
videoExtensions = new TreeSet<>(videoPanel.getExtensionsList());
|
videoExtensions = new TreeSet<>(videoPanel.getExtensionsList());
|
||||||
videoMimes = new TreeSet<>(videoPanel.getMimeTypes());
|
|
||||||
|
|
||||||
imagePanel = new MediaViewImagePanel();
|
imagePanel = new MediaViewImagePanel();
|
||||||
imagePanelInited = imagePanel.isInited();
|
imagePanelInited = imagePanel.isInited();
|
||||||
imageExtensions = new TreeSet<>(imagePanel.getExtensionsList());
|
|
||||||
imageMimes = new TreeSet<>(imagePanel.getMimeTypes());
|
|
||||||
|
|
||||||
customizeComponents();
|
customizeComponents();
|
||||||
logger.log(Level.INFO, "Created MediaView instance: {0}", this); //NON-NLS
|
logger.log(Level.INFO, "Created MediaView instance: {0}", this); //NON-NLS
|
||||||
@ -239,10 +229,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
|||||||
if (file == null) {
|
if (file == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
String extension = file.getNameExtension();
|
|
||||||
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||||
|
|
||||||
if (videoExtensions.contains("." + extension) && deleted) {
|
if (videoPanel.isSupported(file) && deleted) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 7;
|
return 7;
|
||||||
@ -263,28 +252,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
|||||||
*/
|
*/
|
||||||
List<String> getExtensionsList();
|
List<String> getExtensionsList();
|
||||||
|
|
||||||
default boolean isSupported(AbstractFile file) {
|
boolean isSupported(AbstractFile file);
|
||||||
SortedSet<String> mimeTypes = new TreeSet<>(getMimeTypes());
|
|
||||||
try {
|
|
||||||
String mimeType = new FileTypeDetector().getFileType(file);
|
|
||||||
if (nonNull(mimeType)) {
|
|
||||||
return mimeTypes.contains(mimeType);
|
|
||||||
}
|
|
||||||
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
|
||||||
if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == MimeMatchEnum.TRUE) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String extension = file.getNameExtension();
|
|
||||||
|
|
||||||
if (getExtensionsList().contains("." + extension)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,8 +220,7 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSupported(AbstractFile file) {
|
public boolean isSupported(AbstractFile file) {
|
||||||
return DataContentViewerMedia.MediaViewPanel.super.isSupported(file)
|
return ImageUtils.isImageThumbnailSupported(file);
|
||||||
|| ImageUtils.hasImageFileHeader(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,12 +21,16 @@ package org.sleuthkit.autopsy.corecomponents;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import static java.util.Objects.nonNull;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Video viewer part of the Media View layered pane.
|
* Video viewer part of the Media View layered pane.
|
||||||
@ -132,9 +136,21 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
|||||||
String extension = file.getNameExtension();
|
String extension = file.getNameExtension();
|
||||||
//TODO: is this what we want, to require both extension and mimetype support?
|
//TODO: is this what we want, to require both extension and mimetype support?
|
||||||
if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) {
|
if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) {
|
||||||
return DataContentViewerMedia.MediaViewPanel.super.isSupported(file); //To change body of generated methods, choose Tools | Templates.
|
SortedSet<String> mimeTypes = new TreeSet<>(getMimeTypes());
|
||||||
|
try {
|
||||||
|
String mimeType = new FileTypeDetector().getFileType(file);
|
||||||
|
if (nonNull(mimeType)) {
|
||||||
|
return mimeTypes.contains(mimeType);
|
||||||
|
}
|
||||||
|
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
||||||
|
if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getExtensionsList().contains("." + extension);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -74,26 +73,11 @@ public class ImageUtils {
|
|||||||
|
|
||||||
private static final Logger logger = LOGGER;
|
private static final Logger logger = LOGGER;
|
||||||
private static final BufferedImage DEFAULT_THUMBNAIL;
|
private static final BufferedImage DEFAULT_THUMBNAIL;
|
||||||
private static final TreeSet<String> SUPPORTED_MIME_TYPES = new TreeSet<>();
|
|
||||||
private static final List<String> SUPPORTED_EXTENSIONS = new ArrayList<>();
|
|
||||||
private static final List<String> SUPPORTED_IMAGE_EXTENSIONS;
|
private static final List<String> SUPPORTED_IMAGE_EXTENSIONS;
|
||||||
private static final List<String> SUPPORTED_VIDEO_EXTENSIONS
|
|
||||||
= Arrays.asList("mov", "m4v", "flv", "mp4", "3gp", "avi", "mpg",
|
|
||||||
"mpeg", "asf", "divx", "rm", "moov", "wmv", "vob", "dat",
|
|
||||||
"m1v", "m2v", "m4v", "mkv", "mpe", "yop", "vqa", "xmv",
|
|
||||||
"mve", "wtv", "webm", "vivo", "vc1", "seq", "thp", "san",
|
|
||||||
"mjpg", "smk", "vmd", "sol", "cpk", "sdp", "sbg", "rtsp",
|
|
||||||
"rpl", "rl2", "r3d", "mlp", "mjpeg", "hevc", "h265", "265",
|
|
||||||
"h264", "h263", "h261", "drc", "avs", "pva", "pmp", "ogg",
|
|
||||||
"nut", "nuv", "nsv", "mxf", "mtv", "mvi", "mxg", "lxf",
|
|
||||||
"lvf", "ivf", "mve", "cin", "hnm", "gxf", "fli", "flc",
|
|
||||||
"flx", "ffm", "wve", "uv2", "dxa", "dv", "cdxl", "cdg",
|
|
||||||
"bfi", "jv", "bik", "vid", "vb", "son", "avs", "paf", "mm",
|
|
||||||
"flm", "tmv", "4xm"); //NON-NLS
|
|
||||||
private static final TreeSet<String> SUPPORTED_IMAGE_MIME_TYPES;
|
private static final TreeSet<String> SUPPORTED_IMAGE_MIME_TYPES;
|
||||||
private static final List<String> SUPPORTED_VIDEO_MIME_TYPES
|
private static final List<String> CONDITIONAL_MIME_TYPES = Arrays.asList("audio/x-aiff", "application/octet-stream");
|
||||||
= Arrays.asList("application/x-shockwave-flash", "video/x-m4v", "video/quicktime", "video/avi", "video/msvideo", "video/x-msvideo",
|
|
||||||
"video/mp4", "video/x-ms-wmv", "video/mpeg", "video/asf"); //NON-NLS
|
|
||||||
private static final boolean openCVLoaded;
|
private static final boolean openCVLoaded;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -128,31 +112,19 @@ public class ImageUtils {
|
|||||||
openCVLoaded = openCVLoadedTemp;
|
openCVLoaded = openCVLoadedTemp;
|
||||||
SUPPORTED_IMAGE_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes());
|
SUPPORTED_IMAGE_EXTENSIONS = Arrays.asList(ImageIO.getReaderFileSuffixes());
|
||||||
|
|
||||||
SUPPORTED_EXTENSIONS.addAll(SUPPORTED_IMAGE_EXTENSIONS);
|
|
||||||
SUPPORTED_EXTENSIONS.addAll(SUPPORTED_VIDEO_EXTENSIONS);
|
|
||||||
|
|
||||||
SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes()));
|
SUPPORTED_IMAGE_MIME_TYPES = new TreeSet<>(Arrays.asList(ImageIO.getReaderMIMETypes()));
|
||||||
/* special cases and variants that we support, but don't get registered
|
/* special cases and variants that we support, but don't get registered
|
||||||
* with ImageIO automatically */
|
* with ImageIO automatically */
|
||||||
SUPPORTED_IMAGE_MIME_TYPES.addAll(Arrays.asList(
|
SUPPORTED_IMAGE_MIME_TYPES.addAll(Arrays.asList(
|
||||||
"image/x-rgb",
|
"image/x-rgb",
|
||||||
"image/x-ms-bmp",
|
"image/x-ms-bmp",
|
||||||
|
"image/x-portable-graymap",
|
||||||
|
"image/x-portable-bitmap",
|
||||||
"application/x-123"));
|
"application/x-123"));
|
||||||
SUPPORTED_MIME_TYPES.addAll(SUPPORTED_IMAGE_MIME_TYPES);
|
SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals);
|
||||||
SUPPORTED_MIME_TYPES.addAll(SUPPORTED_VIDEO_MIME_TYPES);
|
|
||||||
|
|
||||||
//this is rarely usefull
|
|
||||||
SUPPORTED_MIME_TYPES.removeIf("application/octet-stream"::equals);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** initialized lazily */
|
||||||
* Get the default Icon, which is the icon for a file.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* /** initialized lazily */
|
|
||||||
private static FileTypeDetector fileTypeDetector;
|
private static FileTypeDetector fileTypeDetector;
|
||||||
|
|
||||||
/** thread that saves generated thumbnails to disk in the background */
|
/** thread that saves generated thumbnails to disk in the background */
|
||||||
@ -167,26 +139,10 @@ public class ImageUtils {
|
|||||||
return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS);
|
return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getSupportedVideoExtensions() {
|
|
||||||
return SUPPORTED_VIDEO_EXTENSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SortedSet<String> getSupportedImageMimeTypes() {
|
public static SortedSet<String> getSupportedImageMimeTypes() {
|
||||||
return Collections.unmodifiableSortedSet(SUPPORTED_IMAGE_MIME_TYPES);
|
return Collections.unmodifiableSortedSet(SUPPORTED_IMAGE_MIME_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getSupportedVideoMimeTypes() {
|
|
||||||
return SUPPORTED_VIDEO_MIME_TYPES;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> getSupportedExtensions() {
|
|
||||||
return Collections.unmodifiableList(SUPPORTED_EXTENSIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SortedSet<String> getSupportedMimeTypes() {
|
|
||||||
return Collections.unmodifiableSortedSet(SUPPORTED_MIME_TYPES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default thumbnail, which is the icon for a file. Used when we can
|
* Get the default thumbnail, which is the icon for a file. Used when we can
|
||||||
* not
|
* not
|
||||||
@ -229,31 +185,59 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
AbstractFile file = (AbstractFile) content;
|
AbstractFile file = (AbstractFile) content;
|
||||||
|
|
||||||
|
return VideoUtils.isVideoThumbnailSupported(file)
|
||||||
|
|| isImageThumbnailSupported(file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isImageThumbnailSupported(AbstractFile file) {
|
||||||
|
|
||||||
|
return isMediaThumbnailSupported(file, SUPPORTED_IMAGE_MIME_TYPES, SUPPORTED_IMAGE_EXTENSIONS, CONDITIONAL_MIME_TYPES)
|
||||||
|
|| hasImageFileHeader(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file is "supported" by checking it mimetype and extension
|
||||||
|
*
|
||||||
|
* //TODO: this should move to a better place. Should ImageUtils and
|
||||||
|
* VideoUtils both implement/extend some base interface/abstract class. That
|
||||||
|
* would be the natural place to put this.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* @param supportedMimeTypes a set of mimetypes that the could have to be
|
||||||
|
* supported
|
||||||
|
* @param supportedExtension a set of extensions a file could have to be
|
||||||
|
* supported if the mime lookup fails or is
|
||||||
|
* inconclusive
|
||||||
|
* @param conditionalMimes a set of mimetypes that a file could have to be
|
||||||
|
* supoprted if it also has a supported extension
|
||||||
|
*
|
||||||
|
* @return true if a thumbnail can be generated for the given file with the
|
||||||
|
* given lists of supported mimetype and extensions
|
||||||
|
*/
|
||||||
|
static boolean isMediaThumbnailSupported(AbstractFile file, final SortedSet<String> supportedMimeTypes, final List<String> supportedExtension, List<String> conditionalMimes) {
|
||||||
|
if (file.getSize() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String extension = file.getNameExtension();
|
||||||
try {
|
try {
|
||||||
String mimeType = getFileTypeDetector().getFileType(file);
|
String mimeType = getFileTypeDetector().getFileType(file);
|
||||||
if (Objects.nonNull(mimeType)) {
|
if (Objects.nonNull(mimeType)) {
|
||||||
return SUPPORTED_MIME_TYPES.contains(mimeType)
|
return supportedMimeTypes.contains(mimeType)
|
||||||
|| (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension()));
|
|| (conditionalMimes.contains(mimeType.toLowerCase()) && supportedExtension.contains(extension));
|
||||||
}
|
}
|
||||||
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) {
|
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
LOGGER.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
||||||
|
|
||||||
AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(SUPPORTED_MIME_TYPES);
|
AbstractFile.MimeMatchEnum mimeMatch = file.isMimeType(supportedMimeTypes);
|
||||||
if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) {
|
if (mimeMatch == AbstractFile.MimeMatchEnum.TRUE) {
|
||||||
return true;
|
return true;
|
||||||
} else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) {
|
} else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have an extension, check it
|
// if we have an extension, check it
|
||||||
final String extension = file.getNameExtension();
|
return StringUtils.isNotBlank(extension) && supportedExtension.contains(extension);
|
||||||
if (StringUtils.isNotBlank(extension) && SUPPORTED_EXTENSIONS.contains(extension)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no extension or one that is not for an image, then read the content
|
|
||||||
return isJpegFileHeader(file) || isPngFileHeader(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -303,22 +287,27 @@ public class ImageUtils {
|
|||||||
* problem making a thumbnail.
|
* problem making a thumbnail.
|
||||||
*/
|
*/
|
||||||
public static Image getThumbnail(Content content, int iconSize) {
|
public static Image getThumbnail(Content content, int iconSize) {
|
||||||
// If a thumbnail file is already saved locally
|
if (content instanceof AbstractFile) {
|
||||||
File cacheFile = getCachedThumbnailLocation(content.getId());
|
AbstractFile file = (AbstractFile) content;
|
||||||
if (cacheFile.exists()) {
|
// If a thumbnail file is already saved locally
|
||||||
try {
|
File cacheFile = getCachedThumbnailLocation(content.getId());
|
||||||
BufferedImage thumbnail = ImageIO.read(cacheFile);
|
if (cacheFile.exists()) {
|
||||||
if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) {
|
try {
|
||||||
return generateAndSaveThumbnail(content, iconSize, cacheFile);
|
BufferedImage thumbnail = ImageIO.read(cacheFile);
|
||||||
} else {
|
if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) {
|
||||||
return thumbnail;
|
return generateAndSaveThumbnail(file, iconSize, cacheFile);
|
||||||
|
} else {
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS
|
||||||
|
return generateAndSaveThumbnail(file, iconSize, cacheFile);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} else {
|
||||||
LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS
|
return generateAndSaveThumbnail(file, iconSize, cacheFile);
|
||||||
return generateAndSaveThumbnail(content, iconSize, cacheFile);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return generateAndSaveThumbnail(content, iconSize, cacheFile);
|
return DEFAULT_THUMBNAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,25 +447,23 @@ public class ImageUtils {
|
|||||||
/**
|
/**
|
||||||
* Generate an icon and save it to specified location.
|
* Generate an icon and save it to specified location.
|
||||||
*
|
*
|
||||||
* @param content File to generate icon for
|
* @param file File to generate icon for
|
||||||
* @param iconSize
|
* @param iconSize
|
||||||
* @param cacheFile Location to save thumbnail to
|
* @param cacheFile Location to save thumbnail to
|
||||||
*
|
*
|
||||||
* @return Generated icon or null on error
|
* @return Generated icon or null on error
|
||||||
*/
|
*/
|
||||||
private static Image generateAndSaveThumbnail(Content content, int iconSize, File cacheFile) {
|
private static Image generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) {
|
||||||
AbstractFile f = (AbstractFile) content;
|
|
||||||
final String extension = f.getNameExtension();
|
|
||||||
BufferedImage thumbnail = null;
|
BufferedImage thumbnail = null;
|
||||||
try {
|
try {
|
||||||
if (SUPPORTED_VIDEO_EXTENSIONS.contains(extension)) {
|
if (VideoUtils.isVideoThumbnailSupported(file)) {
|
||||||
if (openCVLoaded) {
|
if (openCVLoaded) {
|
||||||
thumbnail = VideoUtils.generateVideoThumbnail((AbstractFile) content, iconSize);
|
thumbnail = VideoUtils.generateVideoThumbnail(file, iconSize);
|
||||||
} else {
|
} else {
|
||||||
return DEFAULT_THUMBNAIL;
|
return DEFAULT_THUMBNAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumbnail = generateImageThumbnail(content, iconSize);
|
thumbnail = generateImageThumbnail(file, iconSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thumbnail == null) {
|
if (thumbnail == null) {
|
||||||
@ -492,12 +479,12 @@ public class ImageUtils {
|
|||||||
}
|
}
|
||||||
ImageIO.write(toSave, FORMAT, cacheFile);
|
ImageIO.write(toSave, FORMAT, cacheFile);
|
||||||
} catch (IllegalArgumentException | IOException ex1) {
|
} catch (IllegalArgumentException | IOException ex1) {
|
||||||
LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex1); //NON-NLS
|
LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex1); //NON-NLS
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (NullPointerException ex) {
|
} catch (NullPointerException ex) {
|
||||||
logger.log(Level.WARNING, "Could not write cache thumbnail: " + content, ex); //NON-NLS
|
logger.log(Level.WARNING, "Could not write cache thumbnail: " + file, ex); //NON-NLS
|
||||||
}
|
}
|
||||||
return thumbnail;
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,11 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||||
@ -29,6 +34,7 @@ import org.opencv.core.Mat;
|
|||||||
import org.opencv.highgui.VideoCapture;
|
import org.opencv.highgui.VideoCapture;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
|
import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
|
||||||
|
import static org.sleuthkit.autopsy.coreutils.ImageUtils.isMediaThumbnailSupported;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
@ -37,6 +43,34 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
*/
|
*/
|
||||||
public class VideoUtils {
|
public class VideoUtils {
|
||||||
|
|
||||||
|
private static final List<String> SUPPORTED_VIDEO_EXTENSIONS
|
||||||
|
= Arrays.asList("mov", "m4v", "flv", "mp4", "3gp", "avi", "mpg",
|
||||||
|
"mpeg", "asf", "divx", "rm", "moov", "wmv", "vob", "dat",
|
||||||
|
"m1v", "m2v", "m4v", "mkv", "mpe", "yop", "vqa", "xmv",
|
||||||
|
"mve", "wtv", "webm", "vivo", "vc1", "seq", "thp", "san",
|
||||||
|
"mjpg", "smk", "vmd", "sol", "cpk", "sdp", "sbg", "rtsp",
|
||||||
|
"rpl", "rl2", "r3d", "mlp", "mjpeg", "hevc", "h265", "265",
|
||||||
|
"h264", "h263", "h261", "drc", "avs", "pva", "pmp", "ogg",
|
||||||
|
"nut", "nuv", "nsv", "mxf", "mtv", "mvi", "mxg", "lxf",
|
||||||
|
"lvf", "ivf", "mve", "cin", "hnm", "gxf", "fli", "flc",
|
||||||
|
"flx", "ffm", "wve", "uv2", "dxa", "dv", "cdxl", "cdg",
|
||||||
|
"bfi", "jv", "bik", "vid", "vb", "son", "avs", "paf", "mm",
|
||||||
|
"flm", "tmv", "4xm"); //NON-NLS
|
||||||
|
|
||||||
|
private static final SortedSet<String> SUPPORTED_VIDEO_MIME_TYPES = new TreeSet<>(
|
||||||
|
Arrays.asList("application/x-shockwave-flash", "video/x-m4v", "video/quicktime", "video/avi", "video/msvideo", "video/x-msvideo",
|
||||||
|
"video/mp4", "video/x-ms-wmv", "video/mpeg", "video/asf")); //NON-NLS
|
||||||
|
|
||||||
|
private static final List<String> CONDITIONAL_MIME_TYPES = Arrays.asList("application/octet-stream");
|
||||||
|
|
||||||
|
public static List<String> getSupportedVideoExtensions() {
|
||||||
|
return SUPPORTED_VIDEO_EXTENSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SortedSet<String> getSupportedVideoMimeTypes() {
|
||||||
|
return Collections.unmodifiableSortedSet(SUPPORTED_VIDEO_MIME_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
private static final int THUMB_COLUMNS = 3;
|
private static final int THUMB_COLUMNS = 3;
|
||||||
private static final int THUMB_ROWS = 3;
|
private static final int THUMB_ROWS = 3;
|
||||||
private static final int CV_CAP_PROP_POS_MSEC = 0;
|
private static final int CV_CAP_PROP_POS_MSEC = 0;
|
||||||
@ -52,6 +86,10 @@ public class VideoUtils {
|
|||||||
return Paths.get(Case.getCurrentCase().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile();
|
return Paths.get(Case.getCurrentCase().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isVideoThumbnailSupported(AbstractFile file) {
|
||||||
|
return isMediaThumbnailSupported(file, SUPPORTED_VIDEO_MIME_TYPES, SUPPORTED_VIDEO_EXTENSIONS, CONDITIONAL_MIME_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
static BufferedImage generateVideoThumbnail(AbstractFile file, int iconSize) {
|
static BufferedImage generateVideoThumbnail(AbstractFile file, int iconSize) {
|
||||||
java.io.File tempFile = getTempVideoFile(file);
|
java.io.File tempFile = getTempVideoFile(file);
|
||||||
|
|
||||||
@ -93,11 +131,11 @@ public class VideoUtils {
|
|||||||
for (int x = 0; x < THUMB_COLUMNS; x++) {
|
for (int x = 0; x < THUMB_COLUMNS; x++) {
|
||||||
for (int y = 0; y < THUMB_ROWS; y++) {
|
for (int y = 0; y < THUMB_ROWS; y++) {
|
||||||
if (!videoFile.set(CV_CAP_PROP_POS_MSEC, timestamp + x * framkeskip + y * framkeskip * THUMB_COLUMNS)) {
|
if (!videoFile.set(CV_CAP_PROP_POS_MSEC, timestamp + x * framkeskip + y * framkeskip * THUMB_COLUMNS)) {
|
||||||
break;
|
break; // if we can't set the time, return black for that frame
|
||||||
}
|
}
|
||||||
//read the frame into the image/matrix
|
//read the frame into the image/matrix
|
||||||
if (!videoFile.read(imageMatrix)) {
|
if (!videoFile.read(imageMatrix)) {
|
||||||
break; //if the image for some reason is bad, return default icon
|
break; //if the image for some reason is bad, return black for that frame
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferedImage == null) {
|
if (bufferedImage == null) {
|
||||||
@ -122,6 +160,6 @@ public class VideoUtils {
|
|||||||
|
|
||||||
videoFile.release(); // close the file
|
videoFile.release(); // close the file
|
||||||
|
|
||||||
return ScalrWrapper.resizeFast(bufferedImage, iconSize);
|
return bufferedImage == null ? bufferedImage : ScalrWrapper.resizeFast(bufferedImage, iconSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user