diff --git a/Core/build.xml b/Core/build.xml
index deb035b6099ad3f12f05e50725a6f8b4ee05abe4..461de2ed41d43e983588f1cdc1ce65300841131e 100644
--- a/Core/build.xml
+++ b/Core/build.xml
@@ -116,6 +116,10 @@
             <fileset dir="${thirdparty.dir}/yara/bin"/>
         </copy>
         <copy file="${thirdparty.dir}/yara/bin/YaraJNIWrapper.jar" todir="${ext.dir}" />
+		<!--Copy ffmpeg to release-->
+        <copy todir="${basedir}/release/ffmpeg" >
+            <fileset dir="${thirdparty.dir}/ffmpeg"/>
+        </copy>
     </target>
     
     
diff --git a/Core/src/org/sleuthkit/autopsy/report/video/VideoSnapShotWorker.java b/Core/src/org/sleuthkit/autopsy/report/video/VideoSnapShotWorker.java
new file mode 100755
index 0000000000000000000000000000000000000000..462258d91d6c3fe348a925313e16b56a02c9e0ea
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/report/video/VideoSnapShotWorker.java
@@ -0,0 +1,168 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2022 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.report.video;
+
+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;
+import org.opencv.imgproc.Imgproc;
+import org.opencv.videoio.VideoCapture;
+import org.opencv.videoio.VideoWriter;
+import org.opencv.videoio.Videoio;
+
+/**
+ * A SwingWorker that will create a video of screen captures.
+ * 
+ * To have the the gui update with process add a PropertyChangeListener for
+ * the property 'progress'.
+ * 
+ * To update the gui on completion subclass this class and implement 
+ * the SwingWorker done method.
+ * 
+ */
+public class VideoSnapShotWorker extends SwingWorker<Void, Void>{
+    private static final long MIN_FRAME_INTERVAL_MILLIS = 500;
+    
+    private static final int DEFAULT_FRAMES_PER_SECOND = 1;
+    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 long numFrames;
+    private final double scale;
+    private final int framesPerSecond;
+    
+    /**
+     * 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.
+     */
+    public VideoSnapShotWorker(Path inputPath, Path outputPath) {
+        this(inputPath, outputPath, 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 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;
+        this.scale = scale;
+        this.numFrames = numFrames;
+        this.framesPerSecond = framesPerSecond;
+    }
+
+    @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();
+        outputFile.mkdirs();
+
+        String file_name = inputPath.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
+        {
+            // add this file to the set of known bad ones
+            throw new Exception("Problem with video file; problem when attempting to open file.");
+        }
+        VideoWriter writer = null;
+        try {
+            // get the duration of the video
+            double fps = framesPerSecond == 0 ? videoCapture.get(Videoio.CAP_PROP_FPS) : framesPerSecond; // gets frame per second
+            double total_frames = videoCapture.get(7); // gets total frames
+            double milliseconds = 1000 * (total_frames / fps); //convert to ms duration
+            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()));
+            }
+
+            // calculate the number of frames to capture
+            int numFramesToGet = (int) numFrames;
+            long frameInterval = myDurationMillis / numFrames;
+
+            if (frameInterval < MIN_FRAME_INTERVAL_MILLIS) {
+                numFramesToGet = 1;
+            }
+
+            // for each timeStamp, grab a frame
+            Mat mat = new Mat(); // holds image received from video in mat format (opencv format)
+
+            Size s = new Size((int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH), (int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT));
+            Size newSize = (scale == 0 || scale == 100) ? s : new Size((int) (videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH) * scale), (int) (videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT) * scale));
+
+            writer = new VideoWriter(outputFile.toString(), VideoWriter.fourcc('M', 'J', 'P', 'G'), 1, newSize, true);
+
+            if (!writer.isOpened()) {
+                throw new Exception(String.format("Problem with video file; problem when attempting to open output file. %s", outputFile.toString()));
+            }
+
+            for (int frame = 0; frame < numFramesToGet; ++frame) {
+                
+                if(isCancelled()) {
+                    break;
+                }
+                
+                long timeStamp = frame * frameInterval;
+                videoCapture.set(0, timeStamp); //set video in timeStamp ms
+
+                if (!videoCapture.read(mat)) { // on Wav files, usually the last frame we try to read does not succeed.
+                    continue;
+                }
+
+                Mat resized = new Mat();
+                Imgproc.resize(mat, resized, newSize, 0, 0, Imgproc.INTER_CUBIC);
+                writer.write(resized);
+                
+                setProgress(numFramesToGet/frame);
+            }
+
+        } finally {
+            videoCapture.release();
+            if (writer != null) {
+                writer.release();
+            }
+        }
+        
+        if(isCancelled()) {
+            if(outputFile.exists()) {
+                outputFile.delete();
+            }
+        }
+        
+        return null;
+    }
+    
+}
diff --git a/Core/src/org/sleuthkit/autopsy/report/video/VideoUtilis.java b/Core/src/org/sleuthkit/autopsy/report/video/VideoUtilis.java
new file mode 100755
index 0000000000000000000000000000000000000000..0a185ffe09ab51e12126a8831b5db4f7437bb786
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/report/video/VideoUtilis.java
@@ -0,0 +1,93 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2022 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.report.video;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.openide.modules.InstalledFileLocator;
+import org.sleuthkit.autopsy.coreutils.ExecUtil;
+import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
+
+public class VideoUtilis {
+    
+    private static final String FFMPEG = "ffmpeg";
+    private static final String FFMPEG_EXE = "ffmpeg.exe";
+    
+    private VideoUtilis() {}
+    
+    static void compressVideo(Path inputPath, Path outputPath, ProcessTerminator terminator) throws Exception {
+        Path executablePath = Paths.get(FFMPEG, FFMPEG_EXE);
+        File exeFile = InstalledFileLocator.getDefault().locate(executablePath.toString(), VideoUtilis.class.getPackage().getName(), true);
+        if(exeFile == null) {
+            throw new IOException("Unable to compress ffmpeg.exe was not found.");
+        } 
+        
+        if(!exeFile.canExecute()) {
+            throw new IOException("Unable to compress ffmpeg.exe could not be execute");
+        }
+        
+                
+        ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
+                "\"" + exeFile.getAbsolutePath() + "\"",
+                "-i", "\"" + inputPath.toAbsolutePath().toString() + "\"",
+                "-vf", "scale=1280:-1",
+                "-c:v", "libx264",
+                "-preset", "veryslow",
+                "-crf", "24",
+                "\"" + outputPath.toAbsolutePath().toString() + "\"");
+        
+        ExecUtil.execute(processBuilder, terminator);
+    }
+    
+    static void scaleVideo(Path inputPath, Path outputPath, int width, int height, ProcessTerminator terminator) throws Exception{
+        Path executablePath = Paths.get(FFMPEG, FFMPEG_EXE);
+        File exeFile = InstalledFileLocator.getDefault().locate(executablePath.toString(), VideoUtilis.class.getPackage().getName(), true);
+        if(exeFile == null) {
+            throw new IOException("Unable to compress ffmpeg.exe was not found.");
+        } 
+        
+        if(!exeFile.canExecute()) {
+            throw new IOException("Unable to compress ffmpeg.exe could not be execute");
+        }
+        
+        String scaleParam = Integer.toString(width) + ":" + Integer.toString(height);
+        
+        ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
+                "\"" + exeFile.getAbsolutePath() + "\"",
+                "-i", "\"" + inputPath.toAbsolutePath().toString() + "\"",
+                "-s", scaleParam,
+                "-c:a", "copy",
+                "\"" + outputPath.toAbsolutePath().toString() + "\"");
+        
+        ExecUtil.execute(processBuilder, terminator);
+
+    }
+    
+    static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) {
+        ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
+        /*
+         * Add an environment variable to force aLeapp to run with the same
+         * permissions Autopsy uses.
+         */
+        processBuilder.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS
+        return processBuilder;
+    }
+}
diff --git a/thirdparty/ffmpeg/avcodec-59.dll b/thirdparty/ffmpeg/avcodec-59.dll
new file mode 100755
index 0000000000000000000000000000000000000000..4241f36f291479f6f8917fca031f08e9e16c01ef
Binary files /dev/null and b/thirdparty/ffmpeg/avcodec-59.dll differ
diff --git a/thirdparty/ffmpeg/avdevice-59.dll b/thirdparty/ffmpeg/avdevice-59.dll
new file mode 100755
index 0000000000000000000000000000000000000000..07f8b8226e5256c5bcaf0e6e3d4f00c498fbc911
Binary files /dev/null and b/thirdparty/ffmpeg/avdevice-59.dll differ
diff --git a/thirdparty/ffmpeg/avfilter-8.dll b/thirdparty/ffmpeg/avfilter-8.dll
new file mode 100755
index 0000000000000000000000000000000000000000..7aa9015c2067df40295bdfa1d813546acb9e10ae
Binary files /dev/null and b/thirdparty/ffmpeg/avfilter-8.dll differ
diff --git a/thirdparty/ffmpeg/avformat-59.dll b/thirdparty/ffmpeg/avformat-59.dll
new file mode 100755
index 0000000000000000000000000000000000000000..c579d74098c0e63c6cc6b48298ac1ddd946b00b2
Binary files /dev/null and b/thirdparty/ffmpeg/avformat-59.dll differ
diff --git a/thirdparty/ffmpeg/avutil-57.dll b/thirdparty/ffmpeg/avutil-57.dll
new file mode 100755
index 0000000000000000000000000000000000000000..95fd4168d8a8ec51faa7c0ef3296e276e838f658
Binary files /dev/null and b/thirdparty/ffmpeg/avutil-57.dll differ
diff --git a/thirdparty/ffmpeg/ffmpeg.exe b/thirdparty/ffmpeg/ffmpeg.exe
new file mode 100755
index 0000000000000000000000000000000000000000..7112dfddde9d696d1343c7f8f1eeb17e04c2b85f
Binary files /dev/null and b/thirdparty/ffmpeg/ffmpeg.exe differ
diff --git a/thirdparty/ffmpeg/postproc-56.dll b/thirdparty/ffmpeg/postproc-56.dll
new file mode 100755
index 0000000000000000000000000000000000000000..323746c09928bf6248c165c307f7de81e1e44969
Binary files /dev/null and b/thirdparty/ffmpeg/postproc-56.dll differ
diff --git a/thirdparty/ffmpeg/swresample-4.dll b/thirdparty/ffmpeg/swresample-4.dll
new file mode 100755
index 0000000000000000000000000000000000000000..d78700ed59794cdf641c61106d7e6dc61308ea0a
Binary files /dev/null and b/thirdparty/ffmpeg/swresample-4.dll differ
diff --git a/thirdparty/ffmpeg/swscale-6.dll b/thirdparty/ffmpeg/swscale-6.dll
new file mode 100755
index 0000000000000000000000000000000000000000..71b4fd0522441fadd193cd686ea15b18f00c0470
Binary files /dev/null and b/thirdparty/ffmpeg/swscale-6.dll differ