mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 00:16:16 +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.Dimension;
|
||||
import java.util.List;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
@ -32,10 +31,7 @@ import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -52,11 +48,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
private final MediaViewVideoPanel videoPanel;
|
||||
private final boolean videoPanelInited;
|
||||
private final SortedSet<String> videoExtensions; // get them from the panel
|
||||
private final SortedSet<String> videoMimes;
|
||||
private final MediaViewImagePanel imagePanel;
|
||||
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 VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS
|
||||
@ -72,12 +65,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
videoPanel = MediaViewVideoPanel.createVideoPanel();
|
||||
videoPanelInited = videoPanel.isInited();
|
||||
videoExtensions = new TreeSet<>(videoPanel.getExtensionsList());
|
||||
videoMimes = new TreeSet<>(videoPanel.getMimeTypes());
|
||||
|
||||
imagePanel = new MediaViewImagePanel();
|
||||
imagePanelInited = imagePanel.isInited();
|
||||
imageExtensions = new TreeSet<>(imagePanel.getExtensionsList());
|
||||
imageMimes = new TreeSet<>(imagePanel.getMimeTypes());
|
||||
|
||||
customizeComponents();
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
String extension = file.getNameExtension();
|
||||
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||
|
||||
if (videoExtensions.contains("." + extension) && deleted) {
|
||||
if (videoPanel.isSupported(file) && deleted) {
|
||||
return 0;
|
||||
} else {
|
||||
return 7;
|
||||
@ -263,28 +252,6 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
*/
|
||||
List<String> getExtensionsList();
|
||||
|
||||
default 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;
|
||||
}
|
||||
|
||||
boolean isSupported(AbstractFile file);
|
||||
}
|
||||
}
|
||||
|
@ -220,8 +220,7 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file) {
|
||||
return DataContentViewerMedia.MediaViewPanel.super.isSupported(file)
|
||||
|| ImageUtils.hasImageFileHeader(file);
|
||||
return ImageUtils.isImageThumbnailSupported(file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,12 +21,16 @@ package org.sleuthkit.autopsy.corecomponents;
|
||||
import java.awt.Dimension;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
//TODO: is this what we want, to require both extension and mimetype support?
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -74,26 +73,11 @@ public class ImageUtils {
|
||||
|
||||
private static final Logger logger = LOGGER;
|
||||
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_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 List<String> SUPPORTED_VIDEO_MIME_TYPES
|
||||
= 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("audio/x-aiff", "application/octet-stream");
|
||||
|
||||
private static final boolean openCVLoaded;
|
||||
|
||||
static {
|
||||
@ -128,31 +112,19 @@ public class ImageUtils {
|
||||
openCVLoaded = openCVLoadedTemp;
|
||||
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()));
|
||||
/* special cases and variants that we support, but don't get registered
|
||||
* with ImageIO automatically */
|
||||
SUPPORTED_IMAGE_MIME_TYPES.addAll(Arrays.asList(
|
||||
"image/x-rgb",
|
||||
"image/x-ms-bmp",
|
||||
"image/x-portable-graymap",
|
||||
"image/x-portable-bitmap",
|
||||
"application/x-123"));
|
||||
SUPPORTED_MIME_TYPES.addAll(SUPPORTED_IMAGE_MIME_TYPES);
|
||||
SUPPORTED_MIME_TYPES.addAll(SUPPORTED_VIDEO_MIME_TYPES);
|
||||
|
||||
//this is rarely usefull
|
||||
SUPPORTED_MIME_TYPES.removeIf("application/octet-stream"::equals);
|
||||
SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default Icon, which is the icon for a file.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
*
|
||||
*
|
||||
* /** initialized lazily */
|
||||
/** initialized lazily */
|
||||
private static FileTypeDetector fileTypeDetector;
|
||||
|
||||
/** thread that saves generated thumbnails to disk in the background */
|
||||
@ -167,26 +139,10 @@ public class ImageUtils {
|
||||
return Collections.unmodifiableList(SUPPORTED_IMAGE_EXTENSIONS);
|
||||
}
|
||||
|
||||
public static List<String> getSupportedVideoExtensions() {
|
||||
return SUPPORTED_VIDEO_EXTENSIONS;
|
||||
}
|
||||
|
||||
public static SortedSet<String> getSupportedImageMimeTypes() {
|
||||
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
|
||||
* not
|
||||
@ -229,31 +185,59 @@ public class ImageUtils {
|
||||
}
|
||||
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 {
|
||||
String mimeType = getFileTypeDetector().getFileType(file);
|
||||
if (Objects.nonNull(mimeType)) {
|
||||
return SUPPORTED_MIME_TYPES.contains(mimeType)
|
||||
|| (mimeType.equalsIgnoreCase("audio/x-aiff") && "iff".equalsIgnoreCase(file.getNameExtension()));
|
||||
return supportedMimeTypes.contains(mimeType)
|
||||
|| (conditionalMimes.contains(mimeType.toLowerCase()) && supportedExtension.contains(extension));
|
||||
}
|
||||
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException 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) {
|
||||
return true;
|
||||
} else if (mimeMatch == AbstractFile.MimeMatchEnum.FALSE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have an extension, check it
|
||||
final String extension = file.getNameExtension();
|
||||
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);
|
||||
return StringUtils.isNotBlank(extension) && supportedExtension.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,22 +287,27 @@ public class ImageUtils {
|
||||
* problem making a thumbnail.
|
||||
*/
|
||||
public static Image getThumbnail(Content content, int iconSize) {
|
||||
// If a thumbnail file is already saved locally
|
||||
File cacheFile = getCachedThumbnailLocation(content.getId());
|
||||
if (cacheFile.exists()) {
|
||||
try {
|
||||
BufferedImage thumbnail = ImageIO.read(cacheFile);
|
||||
if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) {
|
||||
return generateAndSaveThumbnail(content, iconSize, cacheFile);
|
||||
} else {
|
||||
return thumbnail;
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
// If a thumbnail file is already saved locally
|
||||
File cacheFile = getCachedThumbnailLocation(content.getId());
|
||||
if (cacheFile.exists()) {
|
||||
try {
|
||||
BufferedImage thumbnail = ImageIO.read(cacheFile);
|
||||
if (isNull(thumbnail) || thumbnail.getWidth() != iconSize) {
|
||||
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) {
|
||||
LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS
|
||||
return generateAndSaveThumbnail(content, iconSize, cacheFile);
|
||||
} else {
|
||||
return generateAndSaveThumbnail(file, iconSize, cacheFile);
|
||||
}
|
||||
} 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.
|
||||
*
|
||||
* @param content File to generate icon for
|
||||
* @param file File to generate icon for
|
||||
* @param iconSize
|
||||
* @param cacheFile Location to save thumbnail to
|
||||
*
|
||||
* @return Generated icon or null on error
|
||||
*/
|
||||
private static Image generateAndSaveThumbnail(Content content, int iconSize, File cacheFile) {
|
||||
AbstractFile f = (AbstractFile) content;
|
||||
final String extension = f.getNameExtension();
|
||||
private static Image generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) {
|
||||
BufferedImage thumbnail = null;
|
||||
try {
|
||||
if (SUPPORTED_VIDEO_EXTENSIONS.contains(extension)) {
|
||||
if (VideoUtils.isVideoThumbnailSupported(file)) {
|
||||
if (openCVLoaded) {
|
||||
thumbnail = VideoUtils.generateVideoThumbnail((AbstractFile) content, iconSize);
|
||||
thumbnail = VideoUtils.generateVideoThumbnail(file, iconSize);
|
||||
} else {
|
||||
return DEFAULT_THUMBNAIL;
|
||||
}
|
||||
} else {
|
||||
thumbnail = generateImageThumbnail(content, iconSize);
|
||||
thumbnail = generateImageThumbnail(file, iconSize);
|
||||
}
|
||||
|
||||
if (thumbnail == null) {
|
||||
@ -492,12 +479,12 @@ public class ImageUtils {
|
||||
}
|
||||
ImageIO.write(toSave, FORMAT, cacheFile);
|
||||
} 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) {
|
||||
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;
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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 org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
@ -29,6 +34,7 @@ import org.opencv.core.Mat;
|
||||
import org.opencv.highgui.VideoCapture;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
|
||||
import static org.sleuthkit.autopsy.coreutils.ImageUtils.isMediaThumbnailSupported;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
@ -37,6 +43,34 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
*/
|
||||
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_ROWS = 3;
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
java.io.File tempFile = getTempVideoFile(file);
|
||||
|
||||
@ -93,11 +131,11 @@ public class VideoUtils {
|
||||
for (int x = 0; x < THUMB_COLUMNS; x++) {
|
||||
for (int y = 0; y < THUMB_ROWS; y++) {
|
||||
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
|
||||
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) {
|
||||
@ -122,6 +160,6 @@ public class VideoUtils {
|
||||
|
||||
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