Autopsy  4.7.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
VideoUtils.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2015-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.coreutils;
20 
21 import com.google.common.io.Files;
22 import java.awt.image.BufferedImage;
23 import java.io.File;
24 import java.io.IOException;
25 import java.nio.file.Paths;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.SortedSet;
30 import java.util.TreeSet;
31 import java.util.logging.Level;
32 import org.netbeans.api.progress.ProgressHandle;
33 import org.opencv.core.Mat;
34 import org.opencv.highgui.VideoCapture;
35 import org.openide.util.NbBundle;
39 import static org.sleuthkit.autopsy.coreutils.ImageUtils.isMediaThumbnailSupported;
41 import org.sleuthkit.datamodel.AbstractFile;
42 
46 public class VideoUtils {
47 
48  private static final List<String> SUPPORTED_VIDEO_EXTENSIONS
49  = Arrays.asList("mov", "m4v", "flv", "mp4", "3gp", "avi", "mpg", //NON-NLS
50  "mpeg", "asf", "divx", "rm", "moov", "wmv", "vob", "dat", //NON-NLS
51  "m1v", "m2v", "m4v", "mkv", "mpe", "yop", "vqa", "xmv", //NON-NLS
52  "mve", "wtv", "webm", "vivo", "vc1", "seq", "thp", "san", //NON-NLS
53  "mjpg", "smk", "vmd", "sol", "cpk", "sdp", "sbg", "rtsp", //NON-NLS
54  "rpl", "rl2", "r3d", "mlp", "mjpeg", "hevc", "h265", "265", //NON-NLS
55  "h264", "h263", "h261", "drc", "avs", "pva", "pmp", "ogg", //NON-NLS
56  "nut", "nuv", "nsv", "mxf", "mtv", "mvi", "mxg", "lxf", //NON-NLS
57  "lvf", "ivf", "mve", "cin", "hnm", "gxf", "fli", "flc", //NON-NLS
58  "flx", "ffm", "wve", "uv2", "dxa", "dv", "cdxl", "cdg", //NON-NLS
59  "bfi", "jv", "bik", "vid", "vb", "son", "avs", "paf", "mm", //NON-NLS
60  "flm", "tmv", "4xm"); //NON-NLS
61 
62  private static final SortedSet<String> SUPPORTED_VIDEO_MIME_TYPES = new TreeSet<>(
63  Arrays.asList("application/x-shockwave-flash",
64  "video/x-m4v",
65  "video/x-flv",
66  "video/quicktime",
67  "video/avi",
68  "video/msvideo",
69  "video/x-msvideo", //NON-NLS
70  "video/mp4",
71  "video/x-ms-wmv",
72  "video/mpeg",
73  "video/asf")); //NON-NLS
74 
75  public static List<String> getSupportedVideoExtensions() {
77  }
78 
79  public static SortedSet<String> getSupportedVideoMimeTypes() {
80  return Collections.unmodifiableSortedSet(SUPPORTED_VIDEO_MIME_TYPES);
81  }
82 
83  private static final int THUMB_COLUMNS = 3;
84  private static final int THUMB_ROWS = 3;
85  private static final int CV_CAP_PROP_POS_MSEC = 0;
86  private static final int CV_CAP_PROP_FRAME_COUNT = 7;
87  private static final int CV_CAP_PROP_FPS = 5;
88 
89  static final Logger LOGGER = Logger.getLogger(VideoUtils.class.getName());
90 
91  private VideoUtils() {
92  }
93 
103  public static File getVideoFileInTempDir(AbstractFile file) throws NoCurrentCaseException {
104  return Paths.get(Case.getCurrentCaseThrows().getTempDirectory(), "videos", file.getId() + "." + file.getNameExtension()).toFile(); //NON-NLS
105  }
106 
107  public static boolean isVideoThumbnailSupported(AbstractFile file) {
108  return isMediaThumbnailSupported(file, "video/", SUPPORTED_VIDEO_MIME_TYPES, SUPPORTED_VIDEO_EXTENSIONS);
109  }
110 
111  @NbBundle.Messages({"# {0} - file name",
112  "VideoUtils.genVideoThumb.progress.text=extracting temporary file {0}"})
113  static BufferedImage generateVideoThumbnail(AbstractFile file, int iconSize) {
114  java.io.File tempFile;
115  try {
116  tempFile = getVideoFileInTempDir(file);
117  } catch (NoCurrentCaseException ex) {
118  LOGGER.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS
119  return null;
120  }
121  if (tempFile.exists() == false || tempFile.length() < file.getSize()) {
122  ProgressHandle progress = ProgressHandle.createHandle(Bundle.VideoUtils_genVideoThumb_progress_text(file.getName()));
123  progress.start(100);
124  try {
125  Files.createParentDirs(tempFile);
126  if (Thread.interrupted()) {
127  return null;
128  }
129  ContentUtils.writeToFile(file, tempFile, progress, null, true);
130  } catch (IOException ex) {
131  LOGGER.log(Level.WARNING, "Error extracting temporary file for " + ImageUtils.getContentPathSafe(file), ex); //NON-NLS
132  } finally {
133  progress.finish();
134  }
135  }
136  VideoCapture videoFile = new VideoCapture(); // will contain the video
137  BufferedImage bufferedImage = null;
138 
139  try {
140 
141  if (!videoFile.open(tempFile.toString())) {
142  LOGGER.log(Level.WARNING, "Error opening {0} for preview generation.", ImageUtils.getContentPathSafe(file)); //NON-NLS
143  return null;
144  }
145  double fps = videoFile.get(CV_CAP_PROP_FPS); // gets frame per second
146  double totalFrames = videoFile.get(CV_CAP_PROP_FRAME_COUNT); // gets total frames
147  if (fps <= 0 || totalFrames <= 0) {
148  LOGGER.log(Level.WARNING, "Error getting fps or total frames for {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
149  return null;
150  }
151  double milliseconds = 1000 * (totalFrames / fps); //total milliseconds
152 
153  double timestamp = Math.min(milliseconds, 500); //default time to check for is 500ms, unless the files is extremely small
154 
155  int framkeskip = Double.valueOf(Math.floor((milliseconds - timestamp) / (THUMB_COLUMNS * THUMB_ROWS))).intValue();
156 
157  Mat imageMatrix = new Mat();
158 
159  for (int x = 0; x < THUMB_COLUMNS; x++) {
160  for (int y = 0; y < THUMB_ROWS; y++) {
161  if (Thread.interrupted()) {
162  return null;
163  }
164  if (!videoFile.set(CV_CAP_PROP_POS_MSEC, timestamp + x * framkeskip + y * framkeskip * THUMB_COLUMNS)) {
165  LOGGER.log(Level.WARNING, "Error seeking to " + timestamp + "ms in {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
166  break; // if we can't set the time, return black for that frame
167  }
168  //read the frame into the image/matrix
169  if (!videoFile.read(imageMatrix)) {
170  LOGGER.log(Level.WARNING, "Error reading frames at " + timestamp + "ms from {0}", ImageUtils.getContentPathSafe(file)); //NON-NLS
171  break; //if the image for some reason is bad, return black for that frame
172  }
173 
174  if (bufferedImage == null) {
175  bufferedImage = new BufferedImage(imageMatrix.cols() * THUMB_COLUMNS, imageMatrix.rows() * THUMB_ROWS, BufferedImage.TYPE_3BYTE_BGR);
176  }
177 
178  byte[] data = new byte[imageMatrix.rows() * imageMatrix.cols() * (int) (imageMatrix.elemSize())];
179  imageMatrix.get(0, 0, data); //copy the image to data
180 
181  //todo: this looks like we are swapping the first and third channels. so we can use BufferedImage.TYPE_3BYTE_BGR
182  if (imageMatrix.channels() == 3) {
183  for (int k = 0; k < data.length; k += 3) {
184  byte temp = data[k];
185  data[k] = data[k + 2];
186  data[k + 2] = temp;
187  }
188  }
189 
190  bufferedImage.getRaster().setDataElements(imageMatrix.cols() * x, imageMatrix.rows() * y, imageMatrix.cols(), imageMatrix.rows(), data);
191  }
192  }
193  } finally {
194  videoFile.release(); // close the file}
195  }
196  if (Thread.interrupted()) {
197  return null;
198  }
199  return bufferedImage == null ? null : ScalrWrapper.resizeFast(bufferedImage, iconSize);
200  }
201 
212  @Deprecated
213  public static File getTempVideoFile(AbstractFile file) {
214  try {
215  return getVideoFileInTempDir(file);
216  } catch (NoCurrentCaseException ex) {
217  // Mimic the old behavior.
218  throw new IllegalStateException(ex);
219  }
220  }
221 
222 }
static List< String > getSupportedVideoExtensions()
Definition: VideoUtils.java:75
static File getVideoFileInTempDir(AbstractFile file)
static SortedSet< String > getSupportedVideoMimeTypes()
Definition: VideoUtils.java:79
static final List< String > SUPPORTED_VIDEO_EXTENSIONS
Definition: VideoUtils.java:49
static final SortedSet< String > SUPPORTED_VIDEO_MIME_TYPES
Definition: VideoUtils.java:62
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static File getTempVideoFile(AbstractFile file)
static boolean isVideoThumbnailSupported(AbstractFile file)

Copyright © 2012-2016 Basis Technology. Generated on: Mon Jun 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.