Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MediaPlayerPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2019 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.contentviewers;
20 
21 import com.google.common.io.Files;
22 import java.awt.Dimension;
23 import java.awt.EventQueue;
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.SortedSet;
29 import java.util.TreeSet;
30 import java.util.concurrent.CancellationException;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.TimeUnit;
33 import java.util.logging.Level;
34 import javax.swing.BoxLayout;
35 import javax.swing.JButton;
36 import javax.swing.JLabel;
37 import javax.swing.JPanel;
38 import javax.swing.JSlider;
39 import javax.swing.SwingUtilities;
40 import javax.swing.SwingWorker;
41 import javax.swing.Timer;
42 import javax.swing.event.ChangeEvent;
43 import javax.swing.event.ChangeListener;
44 import org.freedesktop.gstreamer.ClockTime;
45 import org.freedesktop.gstreamer.Gst;
46 import org.freedesktop.gstreamer.GstException;
47 import org.freedesktop.gstreamer.State;
48 import org.freedesktop.gstreamer.StateChangeReturn;
49 import org.freedesktop.gstreamer.elements.PlayBin;
50 import org.netbeans.api.progress.ProgressHandle;
51 import org.openide.util.NbBundle;
58 import org.sleuthkit.datamodel.AbstractFile;
59 import org.sleuthkit.datamodel.TskCoreException;
60 import org.sleuthkit.datamodel.TskData;
61 
66 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
67 public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaViewPanel {
68 
69  private static final String[] FILE_EXTENSIONS = new String[] {
70  ".3g2",
71  ".3gp",
72  ".3gpp",
73  ".aac",
74  ".aif",
75  ".aiff",
76  ".amr",
77  ".asf",
78  ".au",
79  ".avi",
80  ".flac",
81  ".flv",
82  ".m4a",
83  ".m4v",
84  ".mka",
85  ".mkv",
86  ".mov",
87  ".mp2",
88  ".mp3",
89  ".mp4",
90  ".mpeg",
91  ".mpg",
92  ".mxf",
93  ".ogg",
94  ".wav",
95  ".webm",
96  ".wma",
97  ".wmv",
98  }; //NON-NLS
99  private static final List<String> MIME_TYPES = Arrays.asList(
100  "video/3gpp",
101  "video/3gpp2",
102  "audio/aiff",
103  "audio/amr-wb",
104  "audio/basic",
105  "audio/mp4",
106  "video/mp4",
107  "audio/mpeg",
108  "video/mpeg",
109  "audio/mpeg3",
110  "application/mxf",
111  "application/ogg",
112  "video/quicktime",
113  "audio/vorbis",
114  "audio/vnd.wave",
115  "video/webm",
116  "video/x-3ivx",
117  "audio/x-aac",
118  "audio/x-adpcm",
119  "audio/x-alaw",
120  "audio/x-cinepak",
121  "video/x-divx",
122  "audio/x-dv",
123  "video/x-dv",
124  "video/x-ffv",
125  "audio/x-flac",
126  "video/x-flv",
127  "audio/x-gsm",
128  "video/x-h263",
129  "video/x-h264",
130  "video/x-huffyuv",
131  "video/x-indeo",
132  "video/x-intel-h263",
133  "audio/x-ircam",
134  "video/x-jpeg",
135  "audio/x-m4a",
136  "video/x-m4v",
137  "audio/x-mace",
138  "audio/x-matroska",
139  "video/x-matroska",
140  "audio/x-mpeg",
141  "video/x-mpeg",
142  "audio/x-mpeg-3",
143  "video/x-ms-asf",
144  "audio/x-ms-wma",
145  "video/x-ms-wmv",
146  "video/x-msmpeg",
147  "video/x-msvideo",
148  "video/x-msvideocodec",
149  "audio/x-mulaw",
150  "audio/x-nist",
151  "audio/x-oggflac",
152  "audio/x-paris",
153  "audio/x-qdm2",
154  "audio/x-raw",
155  "video/x-raw",
156  "video/x-rle",
157  "audio/x-speex",
158  "video/x-svq",
159  "audio/x-svx",
160  "video/x-tarkin",
161  "video/x-theora",
162  "audio/x-voc",
163  "audio/x-vorbis",
164  "video/x-vp3",
165  "audio/x-w64",
166  "audio/x-wav",
167  "audio/x-wma",
168  "video/x-wmv",
169  "video/x-xvid"
170  ); //NON-NLS
171 
172  private static final Logger logger = Logger.getLogger(MediaPlayerPanel.class.getName());
173  private boolean gstInited;
174  private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.cannotProcFile.err");
175  //playback
176  private long durationMillis = 0;
177  private int totalHours, totalMinutes, totalSeconds;
178  private volatile PlayBin gstPlayBin;
179  private GstVideoRendererPanel gstVideoRenderer;
180  private final Object playbinLock = new Object(); // lock for synchronization of gstPlayBin player
181  private AbstractFile currentFile;
182 
183  private Timer timer;
185 
186  private static final long END_TIME_MARGIN_NS = 50000000;
187  private static final int PLAYER_STATUS_UPDATE_INTERVAL_MS = 50;
188 
192  public MediaPlayerPanel() {
193  initComponents();
194  customizeComponents();
195  }
196 
197  public JButton getPauseButton() {
198  return pauseButton;
199  }
200 
201  public JLabel getProgressLabel() {
202  return progressLabel;
203  }
204 
205  public JSlider getProgressSlider() {
206  return progressSlider;
207  }
208 
209  public JPanel getVideoPanel() {
210  return videoPanel;
211  }
212 
218  public boolean isInited() {
219  return gstInited;
220  }
221 
222  private void customizeComponents() {
223  if (!initGst()) {
224  return;
225  }
226 
227  progressSlider.setEnabled(false); // disable slider; enable after user plays vid
228  progressSlider.setMinimum(0);
229  progressSlider.setMaximum(2000);
230  progressSlider.setValue(0);
231  progressSlider.addChangeListener(new ChangeListener() {
232  @Override
233  public void stateChanged(ChangeEvent event) {
234  if (gstPlayBin == null) {
235  return;
236  }
237  if (progressSlider.getValueIsAdjusting()) {
238  synchronized (playbinLock) {
239  long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
240  long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
241  if (duration > 0) {
242  double relativePosition = progressSlider.getValue() / 2000.0;
243  gstPlayBin.seek((long) (relativePosition * duration), TimeUnit.NANOSECONDS);
244  } else if (position > 0 || progressSlider.getValue() > 0) {
245  gstPlayBin.seek(ClockTime.ZERO);
246  progressSlider.setValue(0);
247  }
248  }
249  }
250  }
251  });
252  }
253 
254  private boolean initGst() {
255  try {
256  logger.log(Level.INFO, "Initializing gstreamer for video/audio viewing"); //NON-NLS
257  Gst.init();
258  gstInited = true;
259  } catch (GstException | UnsatisfiedLinkError ex) {
260  gstInited = false;
261  logger.log(Level.SEVERE, "Error initializing gstreamer for audio/video viewing and frame extraction capabilities", ex); //NON-NLS
263  NbBundle.getMessage(this.getClass(), "GstVideoPanel.initGst.gstException.msg"),
264  ex.getMessage());
265  return false;
266  }
267 
268  return true;
269  }
270 
277  @NbBundle.Messages ({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
278  void loadFile(final AbstractFile file, final Dimension dims) {
279  EventQueue.invokeLater(() -> {
280  reset();
281  infoLabel.setText("");
282  currentFile = file;
283  final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
284  if (deleted) {
285  infoLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.setupVideo.infoLabel.text"));
286  videoPanel.removeAll();
287  pauseButton.setEnabled(false);
288  progressSlider.setEnabled(false);
289  return;
290  }
291 
292  java.io.File ioFile;
293  try {
294  ioFile = VideoUtils.getVideoFileInTempDir(file);
295  } catch (NoCurrentCaseException ex) {
296  logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
297  infoLabel.setText(Bundle.GstVideoPanel_noOpenCase_errMsg());
298  pauseButton.setEnabled(false);
299  progressSlider.setEnabled(false);
300 
301  return;
302  }
303 
304  String path = "";
305  try {
306  path = file.getUniquePath();
307  } catch (TskCoreException ex) {
308  logger.log(Level.SEVERE, "Cannot get unique path of video file.", ex); //NON-NLS
309  }
310  infoLabel.setText(path);
311  infoLabel.setToolTipText(path);
312  pauseButton.setEnabled(true);
313  progressSlider.setEnabled(true);
314  timer = new Timer(PLAYER_STATUS_UPDATE_INTERVAL_MS, event -> {
315  if (!progressSlider.getValueIsAdjusting()) {
316  long duration;
317  long position;
318  synchronized (playbinLock) {
319  duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
320  position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
321  if (duration > 0) {
322  long positionDelta = duration - position;
323  if (positionDelta <= END_TIME_MARGIN_NS && gstPlayBin.isPlaying()) {
324  gstPlayBin.pause();
325  if (gstPlayBin.seek(ClockTime.ZERO) == false) {
326  logger.log(Level.WARNING, "Attempt to call PlayBin.seek() failed."); //NON-NLS
327  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
328  return;
329  }
330  progressSlider.setValue(0);
331  pauseButton.setText("►");
332  } else {
333  double relativePosition = (double) position / duration;
334  progressSlider.setValue((int) (relativePosition * 2000));
335  }
336  }
337  }
338 
339  durationMillis = duration / 1000000;
340  // pick out the total hours, minutes, seconds
341  long durationSeconds = (int) durationMillis / 1000;
342  totalHours = (int) durationSeconds / 3600;
343  durationSeconds -= totalHours * 3600;
344  totalMinutes = (int) durationSeconds / 60;
345  durationSeconds -= totalMinutes * 60;
346  totalSeconds = (int) durationSeconds;
347 
348  long millisElapsed = position / 1000000;
349  // pick out the elapsed hours, minutes, seconds
350  long secondsElapsed = millisElapsed / 1000;
351  int elapsedHours = (int) secondsElapsed / 3600;
352  secondsElapsed -= elapsedHours * 3600;
353  int elapsedMinutes = (int) secondsElapsed / 60;
354  secondsElapsed -= elapsedMinutes * 60;
355  int elapsedSeconds = (int) secondsElapsed;
356 
357  String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS
358  String durationStr = String.format(durationFormat,
359  elapsedHours, elapsedMinutes, elapsedSeconds,
360  totalHours, totalMinutes, totalSeconds);
361  progressLabel.setText(durationStr);
362  }
363  });
364  timer.start();
365 
366  gstVideoRenderer = new GstVideoRendererPanel();
367  synchronized (playbinLock) {
368  if (gstPlayBin != null) {
369  gstPlayBin.dispose();
370  }
371  gstPlayBin = new PlayBin("VideoPlayer"); //NON-NLS
372  gstPlayBin.setVideoSink(gstVideoRenderer.getVideoSink());
373 
374  videoPanel.removeAll();
375 
376  videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
377 
378  videoPanel.add(gstVideoRenderer);//add jfx ui to JPanel
379 
380  videoPanel.setVisible(true);
381 
382  gstPlayBin.setInputFile(ioFile);
383  }
384  });
385  }
386 
390  void reset() {
391  if (timer != null) {
392  timer.stop();
393  }
394 
395  // reset the progress label text on the event dispatch thread
396  SwingUtilities.invokeLater(() -> {
397  progressLabel.setText("");
398  });
399 
400  if (!isInited()) {
401  return;
402  }
403 
404  synchronized (playbinLock) {
405  if (gstPlayBin != null) {
406  if (gstPlayBin.isPlaying() && gstPlayBin.stop() == StateChangeReturn.FAILURE) {
407  logger.log(Level.WARNING, "Attempt to call PlayBin.stop() failed."); //NON-NLS
408  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
409  return;
410  }
411  gstPlayBin.dispose();
412  gstPlayBin = null;
413  }
414  gstVideoRenderer = null;
415  }
416 
417  progressSlider.setValue(0);
418  pauseButton.setText("►");
419 
420  currentFile = null;
421  }
422 
428  @SuppressWarnings("unchecked")
429  // <editor-fold defaultstate="collapsed" desc="Generated Code">
430  private void initComponents() {
431 
432  videoPanel = new javax.swing.JPanel();
433  controlPanel = new javax.swing.JPanel();
434  pauseButton = new javax.swing.JButton();
435  progressSlider = new javax.swing.JSlider();
436  progressLabel = new javax.swing.JLabel();
437  infoLabel = new javax.swing.JLabel();
438 
439  javax.swing.GroupLayout videoPanelLayout = new javax.swing.GroupLayout(videoPanel);
440  videoPanel.setLayout(videoPanelLayout);
441  videoPanelLayout.setHorizontalGroup(
442  videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
443  .addGap(0, 0, Short.MAX_VALUE)
444  );
445  videoPanelLayout.setVerticalGroup(
446  videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
447  .addGap(0, 231, Short.MAX_VALUE)
448  );
449 
450  org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N
451  pauseButton.addActionListener(new java.awt.event.ActionListener() {
452  public void actionPerformed(java.awt.event.ActionEvent evt) {
453  pauseButtonActionPerformed(evt);
454  }
455  });
456 
457  org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
458 
459  org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
460 
461  javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
462  controlPanel.setLayout(controlPanelLayout);
463  controlPanelLayout.setHorizontalGroup(
464  controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
465  .addGroup(controlPanelLayout.createSequentialGroup()
466  .addContainerGap()
467  .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
468  .addGroup(controlPanelLayout.createSequentialGroup()
469  .addGap(6, 6, 6)
470  .addComponent(infoLabel)
471  .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
472  .addGroup(controlPanelLayout.createSequentialGroup()
473  .addComponent(pauseButton)
474  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
475  .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 265, Short.MAX_VALUE)
476  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
477  .addComponent(progressLabel)
478  .addContainerGap())))
479  );
480  controlPanelLayout.setVerticalGroup(
481  controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
482  .addGroup(controlPanelLayout.createSequentialGroup()
483  .addContainerGap()
484  .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
485  .addComponent(progressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
486  .addComponent(pauseButton)
487  .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
488  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
489  .addComponent(infoLabel)
490  .addContainerGap())
491  );
492 
493  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
494  this.setLayout(layout);
495  layout.setHorizontalGroup(
496  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
497  .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
498  .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
499  );
500  layout.setVerticalGroup(
501  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
502  .addGroup(layout.createSequentialGroup()
503  .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
504  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
505  .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
506  );
507  }// </editor-fold>
508 
509  private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
510  synchronized (playbinLock) {
511  if (gstPlayBin == null) {
512  return;
513  }
514  State state = gstPlayBin.getState();
515  if (state.equals(State.PLAYING)) {
516  if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
517  logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
518  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
519  return;
520  }
521  pauseButton.setText("►");
522  } else if (state.equals(State.PAUSED)) {
523  if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
524  logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
525  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
526  return;
527  }
528  pauseButton.setText("||");
529  } else if (state.equals(State.READY) || state.equals(State.NULL)) {
530  final File tempVideoFile;
531  try {
532  tempVideoFile = VideoUtils.getVideoFileInTempDir(currentFile);
533  } catch (NoCurrentCaseException ex) {
534  logger.log(Level.WARNING, "Exception while getting open case."); //NON-NLS
535  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
536  return;
537  }
538 
539  if (extractMediaWorker != null) {
540  extractMediaWorker.cancel(true);
541  extractMediaWorker = null;
542  }
543  extractMediaWorker = new ExtractMedia(currentFile, tempVideoFile);
544  extractMediaWorker.execute();
545 
546  }
547  }
548  }//GEN-LAST:event_pauseButtonActionPerformed
549 
550  // Variables declaration - do not modify//GEN-BEGIN:variables
551  private javax.swing.JPanel controlPanel;
552  private javax.swing.JLabel infoLabel;
553  private javax.swing.JButton pauseButton;
554  private javax.swing.JLabel progressLabel;
555  private javax.swing.JSlider progressSlider;
556  private javax.swing.JPanel videoPanel;
557  // End of variables declaration//GEN-END:variables
558 
562  private class ExtractMedia extends SwingWorker<Long, Void> {
563 
564  private ProgressHandle progress;
565  private final AbstractFile sourceFile;
566  private final java.io.File tempFile;
567 
568  ExtractMedia(AbstractFile sFile, java.io.File jFile) {
569  this.sourceFile = sFile;
570  this.tempFile = jFile;
571  }
572 
573  @Override
574  protected Long doInBackground() throws Exception {
575  if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) {
576  progress = ProgressHandle.createHandle(NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> this.cancel(true));
577  progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering"));
578  progress.start(100);
579  try {
580  Files.createParentDirs(tempFile);
581  return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true);
582  } catch (IOException ex) {
583  logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS
584  return 0L;
585  }
586  }
587  return 0L;
588  }
589 
590  /*
591  * clean up or start the worker threads
592  */
593  @Override
594  protected void done() {
595  try {
596  super.get(); //block and get all exceptions thrown while doInBackground()
597  } catch (CancellationException ex) {
598  logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS
599  } catch (InterruptedException ex) {
600  logger.log(Level.INFO, "Media buffering was interrupted."); //NON-NLS
601  } catch (ExecutionException ex) {
602  logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS
603  } finally {
604  if (progress != null) {
605  progress.finish();
606  }
607  if (!this.isCancelled()) {
608  playMedia();
609  }
610  }
611  }
612 
613  void playMedia() {
614  if (tempFile == null || !tempFile.exists()) {
615  progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progressLabel.bufferingErr"));
616  return;
617  }
618  synchronized (playbinLock) {
619  gstPlayBin.seek(ClockTime.ZERO);
620  // must play, then pause and get state to get duration.
621  if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
622  logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
623  infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
624  return;
625  }
626  pauseButton.setText("||");
627  }
628  }
629  }
630 
631  @Override
632  public List<String> getSupportedExtensions() {
633  return Arrays.asList(FILE_EXTENSIONS.clone());
634  }
635 
636  @Override
637  public List<String> getSupportedMimeTypes() {
638  return MIME_TYPES;
639  }
640 
641  @Override
642  public boolean isSupported(AbstractFile file) {
643  String extension = file.getNameExtension();
660  if (getSupportedExtensions().contains("." + extension)) {
661  SortedSet<String> mimeTypes = new TreeSet<>(getSupportedMimeTypes());
662  try {
663  String mimeType = new FileTypeDetector().getMIMEType(file);
664  return mimeTypes.contains(mimeType);
666  logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
667  if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
668  return true;
669  }
670  }
671 
672  return getSupportedExtensions().contains("." + extension);
673  }
674  return false;
675  }
676 
677 }
static File getVideoFileInTempDir(AbstractFile file)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void pauseButtonActionPerformed(java.awt.event.ActionEvent evt)

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.