diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 23067adf05..cf03389e6a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -80,7 +80,7 @@ DataContentViewerArtifact.pageLabel.text=Result: AdvancedConfigurationDialog.applyButton.text=OK DataContentViewerMedia.pauseButton.text=\u25ba -DataContentViewerMedia.progressLabel.text=00:00/00:00 +DataContentViewerMedia.progressLabel.text= DataContentViewerString.goToPageLabel.text=Go to Page: DataContentViewerString.goToPageTextField.text= DataContentViewerHex.goToPageTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.form index a8f4017e03..2dc5d049de 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.form @@ -16,14 +16,13 @@ - - + + - - - - - + + + + @@ -34,7 +33,7 @@ - + @@ -66,7 +65,7 @@ - + @@ -83,6 +82,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java index 2857368f12..837afbaf9c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerMedia.java @@ -61,6 +61,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo private boolean autoTracking = false; // true if the slider is moving automatically private final Object playbinLock = new Object(); // lock for synchronization of playbin2 player private VideoProgressWorker videoProgressWorker; + private int totalHours, totalMinutes, totalSeconds; /** * Creates new form DataContentViewerVideo @@ -72,6 +73,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo private void customizeComponents() { Gst.init(); + progressSlider.setEnabled(false); // disable slider; enable after user plays vid progressSlider.addChangeListener(new ChangeListener() { /** * Should always try to synchronize any call to @@ -121,7 +123,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo videoPanel.setLayout(videoPanelLayout); videoPanelLayout.setHorizontalGroup( videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 283, Short.MAX_VALUE) + .addGap(0, 0, Short.MAX_VALUE) ); videoPanelLayout.setVerticalGroup( videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -130,6 +132,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo progressSlider.setValue(0); + progressLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); progressLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerMedia.class, "DataContentViewerMedia.progressLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -140,10 +143,9 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo .addGroup(layout.createSequentialGroup() .addComponent(pauseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE) + .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(progressLabel) - .addContainerGap()) + .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -152,7 +154,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(pauseButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) ); }// //GEN-END:initComponents @@ -315,7 +317,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - progressLabel.setText(" "); + progressLabel.setText(""); } }); synchronized (playbinLock) { @@ -418,7 +420,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo return ExtractMedia.this.cancel(true); } }); - progressLabel.setText("Buffering..."); + progressLabel.setText("Buffering... "); progress.start(); progress.switchToDeterminate(100); try { @@ -464,19 +466,20 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo duration = dur.toString(); durationMillis = dur.toMillis(); + // pick out the total hours, minutes, seconds + long durationSeconds = (int)durationMillis / 1000; + totalHours = (int) durationSeconds / 3600; + durationSeconds -= totalHours * 3600; + totalMinutes = (int) durationSeconds / 60; + durationSeconds -= totalMinutes * 60; + totalSeconds = (int) durationSeconds; + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { progressSlider.setMaximum((int) durationMillis); progressSlider.setMinimum(0); - final String finalDuration; - if (duration.length() == 8 && duration.substring(0, 3).equals("00:")) { - finalDuration = duration.substring(3); - progressLabel.setText("00:00/" + duration); - } else { - finalDuration = duration; - progressLabel.setText("00:00:00/" + duration); - } + synchronized (playbinLock) { playbin2.play(); } @@ -490,13 +493,18 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo private class VideoProgressWorker extends SwingWorker { + private String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; + private long millisElapsed = 0; + private final long INTER_FRAME_PERIOD_MS = 20; + private final long END_TIME_MARGIN_MS = 50; + private boolean isPlayBinReady() { synchronized (playbinLock) { return playbin2 != null && !playbin2.getState().equals(State.NULL); } } - public void restartVideo() { + public void resetVideo() { synchronized (playbinLock) { if (playbin2 != null) { playbin2.stop(); @@ -505,54 +513,65 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo } pauseButton.setText("►"); progressSlider.setValue(0); + + String durationStr = String.format(durationFormat, 0, 0, 0, + totalHours, totalMinutes, totalSeconds); + progressLabel.setText(durationStr); + } + + /** + * @return true while millisElapsed is greater than END_TIME_MARGIN_MS + * from durationMillis. This is used to indicate when the video has ended + * because for some videos the time elapsed never becomes equal to the + * reported duration of the video. + */ + private boolean hasNotEnded() { + return (durationMillis - millisElapsed) > END_TIME_MARGIN_MS; } @Override protected Object doInBackground() throws Exception { - long positionMillis = 0; - String finalDuration = ""; - while (positionMillis < durationMillis - && isPlayBinReady() && !isCancelled()) { - ClockTime pos = null; + + // enable the slider + progressSlider.setEnabled(true); + + int elapsedHours = -1, elapsedMinutes = -1, elapsedSeconds = -1; + ClockTime pos = null; + while (hasNotEnded() && isPlayBinReady() && !isCancelled()) { + synchronized (playbinLock) { pos = playbin2.queryPosition(); } - String position = pos.toString(); - positionMillis = pos.toMillis(); + millisElapsed = pos.toMillis(); - if (position.length() == 8) { - position = position.substring(3); - } - - String duration = playbin2.queryDuration().toString(); - if (duration.length() == 8 && duration.substring(0, 3).equals("00:")) { - finalDuration = duration.substring(3); - progressLabel.setText("00:00/" + duration); - } else { - finalDuration = duration; - progressLabel.setText("00:00:00/" + duration); - } - - progressLabel.setText(position + "/" + finalDuration); + // pick out the elapsed hours, minutes, seconds + long secondsElapsed = millisElapsed / 1000; + elapsedHours = (int) secondsElapsed / 3600; + secondsElapsed -= elapsedHours * 3600; + elapsedMinutes = (int) secondsElapsed / 60; + secondsElapsed -= elapsedMinutes * 60; + elapsedSeconds = (int) secondsElapsed; + + String durationStr = String.format(durationFormat, + elapsedHours, elapsedMinutes, elapsedSeconds, + totalHours, totalMinutes, totalSeconds); + + progressLabel.setText(durationStr); autoTracking = true; - progressSlider.setValue((int) positionMillis); + progressSlider.setValue((int) millisElapsed); autoTracking = false; + try { - Thread.sleep(20); + Thread.sleep(INTER_FRAME_PERIOD_MS); } catch (InterruptedException ex) { - throw ex; + break; } } - - if (finalDuration.length() == 5) { - progressLabel.setText("00:00/" + finalDuration); - } else { - progressLabel.setText("00:00:00/" + finalDuration); - } - // If it reached the end - if (progressSlider.getValue() == progressSlider.getMaximum()) { - restartVideo(); - } + + // disable the slider + progressSlider.setEnabled(false); + + resetVideo(); return null; }