From f8c92f48ab2858511b72f8aa7f5e0329cd811c00 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 19 May 2022 11:53:04 -0400 Subject: [PATCH] Added wrapper methods for AbstractFiles --- .../coreutils/VideoSnapShotWorker.java | 46 ++++----- .../autopsy/coreutils/VideoUtils.java | 94 +++++++++++++++---- 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoSnapShotWorker.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoSnapShotWorker.java index cb87151ae2..6e58c6313c 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoSnapShotWorker.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoSnapShotWorker.java @@ -18,9 +18,9 @@ */ package org.sleuthkit.autopsy.coreutils; +import com.google.common.io.Files; import java.io.File; import java.io.IOException; -import java.nio.file.Path; import javax.swing.SwingWorker; import org.opencv.core.Mat; import org.opencv.core.Size; @@ -29,6 +29,7 @@ import org.opencv.videoio.VideoCapture; import org.opencv.videoio.VideoWriter; import org.opencv.videoio.Videoio; import static org.sleuthkit.autopsy.coreutils.VideoUtils.isVideoThumbnailSupported; +import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; /** @@ -48,8 +49,8 @@ public class VideoSnapShotWorker extends SwingWorker{ private static final int DEFAULT_TOTAL_FRAMES = 100; private static final int DEFAULT_SCALE = 100; - private final Path inputPath; - private final Path outputPath; + private final AbstractFile abstractFile; + private final File outputFile; private final long numFrames; private final double scale; private final int framesPerSecond; @@ -57,25 +58,25 @@ public class VideoSnapShotWorker extends SwingWorker{ /** * Creates a new instance of the SwingWorker using the default parameters. * - * @param inputPath The path to the existing video. - * @param outputPath The output path of the snapshot video. + * @param abstractFile The path to the existing video. + * @param outputFile The output path of the snapshot video. */ - public VideoSnapShotWorker(Path inputPath, Path outputPath) { - this(inputPath, outputPath, DEFAULT_TOTAL_FRAMES, DEFAULT_SCALE, DEFAULT_FRAMES_PER_SECOND); + VideoSnapShotWorker(AbstractFile abstractFile, File outputFile) { + this(abstractFile, outputFile, DEFAULT_TOTAL_FRAMES, DEFAULT_SCALE, DEFAULT_FRAMES_PER_SECOND); } /** * Creates a new instance of the SwingWorker. * - * @param inputPath The path to the existing video. - * @param outputPath The output path of the snapshot video. + * @param abstractFile The path to the existing video. + * @param outputFile The output path of the snapshot video. * @param numFrames The number of screen captures to include in the video. * @param scale % to scale from the original. Passing 0 or 100 will result in no change. * @param framesPerSecond Effects how long each frame will appear in the video. */ - public VideoSnapShotWorker(Path inputPath, Path outputPath, long numFrames, double scale, int framesPerSecond) { - this.inputPath = inputPath; - this.outputPath = outputPath; + VideoSnapShotWorker(AbstractFile abstractFile, File outputFile, long numFrames, double scale, int framesPerSecond) { + this.abstractFile = abstractFile; + this.outputFile = outputFile; this.scale = scale; this.numFrames = numFrames; this.framesPerSecond = framesPerSecond; @@ -86,20 +87,21 @@ public class VideoSnapShotWorker extends SwingWorker{ } @Override - protected Void doInBackground() throws Exception { - File input = inputPath.toFile(); - if (!input.exists() || !input.isFile() || !input.canRead()) { - throw new IOException(String.format("Unable to read input file %s", input.toString())); - } - - File outputFile = outputPath.toFile(); + protected Void doInBackground() throws Exception { outputFile.mkdirs(); if(outputFile.exists()) { - throw new IOException(String.format("Failed to compress %s, output file already exists %s", inputPath.toString(), outputPath.toString())); + throw new IOException(String.format("Failed to compress %s, output file already exists %s", abstractFile.getName(), outputFile.toString())); + } + + File inputFile = VideoUtils.getVideoFileInTempDir(abstractFile); + + if (inputFile.exists() == false || inputFile.length() < abstractFile.getSize()) { + Files.createParentDirs(inputFile); + ContentUtils.writeToFile(abstractFile, inputFile, null, this, true); } - String file_name = inputPath.toString();//OpenCV API requires string for file name + String file_name = inputFile.toString();//OpenCV API requires string for file name VideoCapture videoCapture = new VideoCapture(file_name); //VV will contain the videos if (!videoCapture.isOpened()) //checks if file is not open @@ -116,7 +118,7 @@ public class VideoSnapShotWorker extends SwingWorker{ long myDurationMillis = (long) milliseconds; if (myDurationMillis <= 0) { - throw new Exception(String.format("Failed to make snapshot video, original video has no duration. %s", inputPath.toAbsolutePath())); + throw new Exception(String.format("Failed to make snapshot video, original video has no duration. %s", inputFile.toString())); } // calculate the number of frames to capture diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java index 38341acd3e..69d9813bcd 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/VideoUtils.java @@ -240,7 +240,7 @@ public class VideoUtils { return bufferedImage == null ? null : ScalrWrapper.resizeFast(bufferedImage, iconSize); } - boolean canCompressAndScale(AbstractFile file) { + public boolean canCompressAndScale(AbstractFile file) { if (PlatformUtil.getOSName().toLowerCase().startsWith("Windows")) { return isVideoThumbnailSupported(file); @@ -249,6 +249,18 @@ public class VideoUtils { return false; } + /** + * Compress the given the files. + * + * @param inputFile The AbstractFile representing the video. + * @param outputFile Output file. + * @param terminator A processTerminator for the ffmpeg executable. + * @throws IOException + */ + static public void compressVideo(AbstractFile inputFile, File outputFile, ExecUtil.ProcessTerminator terminator) throws IOException { + compressVideo(getVideoFile(inputFile), outputFile, terminator); + } + /** * Compress the given the files. * @@ -257,7 +269,7 @@ public class VideoUtils { * @param terminator A processTerminator for the ffmpeg executable. * @throws Exception */ - static void compressVideo(Path inputPath, Path outputPath, ExecUtil.ProcessTerminator terminator) throws Exception { + static void compressVideo(File inputFile, File outputFile, ExecUtil.ProcessTerminator terminator) throws IOException { Path executablePath = Paths.get(FFMPEG, FFMPEG_EXE); File exeFile = InstalledFileLocator.getDefault().locate(executablePath.toString(), VideoUtils.class.getPackage().getName(), true); if(exeFile == null) { @@ -268,31 +280,47 @@ public class VideoUtils { throw new IOException("Unable to compress ffmpeg.exe could not be execute"); } - if(outputPath.toFile().exists()) { - throw new IOException(String.format("Failed to compress %s, output file already exists %s", inputPath.toString(), outputPath.toString())); + if(outputFile.exists()) { + throw new IOException(String.format("Failed to compress %s, output file already exists %s", inputFile.toString(), outputFile.toString())); } ProcessBuilder processBuilder = buildProcessWithRunAsInvoker( "\"" + exeFile.getAbsolutePath() + "\"", - "-i", "\"" + inputPath.toAbsolutePath().toString() + "\"", + "-i", "\"" + inputFile.toString() + "\"", "-vcodec", "libx264", "-crf", "28", - "\"" + outputPath.toAbsolutePath().toString() + "\""); + "\"" + outputFile.toString() + "\""); ExecUtil.execute(processBuilder, terminator); } /** - * Create a new video with the given width and height. + * Create a new video with the given width and height. An exception will + * be thrown if the output file exists. * - * @param inputPath Absolute path to input video. - * @param outputPath Path for scaled file. + * @param inputFile The video AbstractFile. + * @param outputFile Path for scaled file. * @param width New video width. * @param height New video height. * @param terminator A processTerminator for the ffmpeg executable. - * @throws Exception + * @throws IOException */ - static void scaleVideo(Path inputPath, Path outputPath, int width, int height, ExecUtil.ProcessTerminator terminator) throws Exception{ + static public void scaleVideo(AbstractFile inputFile, File outputFile, int width, int height, ExecUtil.ProcessTerminator terminator) throws IOException { + scaleVideo(getVideoFile(inputFile), outputFile, width, height, terminator); + } + + /** + * Create a new video with the given width and height. An exception will be + * thrown if the output file exists. + * + * @param inputPath Absolute path to input video. + * @param outputFile Path for scaled file. + * @param width New video width. + * @param height New video height. + * @param terminator A processTerminator for the ffmpeg executable. + * @throws IOException + */ + private static void scaleVideo(File inputFile, File outputFile, int width, int height, ExecUtil.ProcessTerminator terminator) throws IOException{ Path executablePath = Paths.get(FFMPEG, FFMPEG_EXE); File exeFile = InstalledFileLocator.getDefault().locate(executablePath.toString(), VideoUtils.class.getPackage().getName(), true); if(exeFile == null) { @@ -303,21 +331,55 @@ public class VideoUtils { throw new IOException("Unable to compress ffmpeg.exe could not be execute"); } - if(outputPath.toFile().exists()) { - throw new IOException(String.format("Failed to compress %s, output file already exists %s", inputPath.toString(), outputPath.toString())); + if(outputFile.exists()) { + throw new IOException(String.format("Failed to compress %s, output file already exists %s", inputFile.toString(), outputFile.toString())); } String scaleParam = Integer.toString(width) + ":" + Integer.toString(height); ProcessBuilder processBuilder = buildProcessWithRunAsInvoker( "\"" + exeFile.getAbsolutePath() + "\"", - "-i", "\"" + inputPath.toAbsolutePath().toString() + "\"", + "-i", "\"" + inputFile.toString() + "\"", "-s", scaleParam, "-c:a", "copy", - "\"" + outputPath.toAbsolutePath().toString() + "\""); + "\"" + outputFile.toString() + "\""); ExecUtil.execute(processBuilder, terminator); - + } + + /** + * Returns a File object representing a temporary copy of the video file + * representing by the AbstractFile object. + * + * @param file + * @return + */ + static File getVideoFile(AbstractFile file) { + java.io.File tempFile; + + try { + tempFile = getVideoFileInTempDir(file); + } catch (NoCurrentCaseException ex) { + LOGGER.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + return null; + } + if (tempFile.exists() == false || tempFile.length() < file.getSize()) { + ProgressHandle progress = ProgressHandle.createHandle(Bundle.VideoUtils_genVideoThumb_progress_text(file.getName())); + progress.start(100); + try { + Files.createParentDirs(tempFile); + if (Thread.interrupted()) { + return null; + } + ContentUtils.writeToFile(file, tempFile, progress, null, true); + } catch (IOException ex) { + LOGGER.log(Level.WARNING, "Error extracting temporary file for " + ImageUtils.getContentPathSafe(file), ex); //NON-NLS + } finally { + progress.finish(); + } + } + + return tempFile; } static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) {