mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
General code clean-up and fix for videos not correctly reporting their total length until the play button is pressed
This commit is contained in:
parent
00a0adb175
commit
1e3358f456
@ -20,7 +20,8 @@ package org.sleuthkit.autopsy.contentviewers;
|
|||||||
|
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -36,7 +37,6 @@ import javax.swing.JButton;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JSlider;
|
import javax.swing.JSlider;
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
@ -44,7 +44,6 @@ import javax.swing.event.ChangeListener;
|
|||||||
import org.freedesktop.gstreamer.ClockTime;
|
import org.freedesktop.gstreamer.ClockTime;
|
||||||
import org.freedesktop.gstreamer.Gst;
|
import org.freedesktop.gstreamer.Gst;
|
||||||
import org.freedesktop.gstreamer.GstException;
|
import org.freedesktop.gstreamer.GstException;
|
||||||
import org.freedesktop.gstreamer.State;
|
|
||||||
import org.freedesktop.gstreamer.StateChangeReturn;
|
import org.freedesktop.gstreamer.StateChangeReturn;
|
||||||
import org.freedesktop.gstreamer.elements.PlayBin;
|
import org.freedesktop.gstreamer.elements.PlayBin;
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
@ -94,8 +93,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
".wav",
|
".wav",
|
||||||
".webm",
|
".webm",
|
||||||
".wma",
|
".wma",
|
||||||
".wmv",
|
".wmv",}; //NON-NLS
|
||||||
}; //NON-NLS
|
|
||||||
private static final List<String> MIME_TYPES = Arrays.asList(
|
private static final List<String> MIME_TYPES = Arrays.asList(
|
||||||
"video/3gpp",
|
"video/3gpp",
|
||||||
"video/3gpp2",
|
"video/3gpp2",
|
||||||
@ -172,16 +170,12 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
private static final Logger logger = Logger.getLogger(MediaPlayerPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(MediaPlayerPanel.class.getName());
|
||||||
private boolean gstInited;
|
private boolean gstInited;
|
||||||
private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.cannotProcFile.err");
|
private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.cannotProcFile.err");
|
||||||
//playback
|
|
||||||
private long durationMillis = 0;
|
|
||||||
private int totalHours, totalMinutes, totalSeconds;
|
|
||||||
private volatile PlayBin gstPlayBin;
|
private volatile PlayBin gstPlayBin;
|
||||||
private GstVideoRendererPanel gstVideoRenderer;
|
|
||||||
private final Object playbinLock = new Object(); // lock for synchronization of gstPlayBin player
|
private final Object playbinLock = new Object(); // lock for synchronization of gstPlayBin player
|
||||||
private AbstractFile currentFile;
|
|
||||||
|
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private ExtractMedia extractMediaWorker;
|
private volatile ExtractMedia extractMediaWorker;
|
||||||
|
|
||||||
private static final long END_TIME_MARGIN_NS = 50000000;
|
private static final long END_TIME_MARGIN_NS = 50000000;
|
||||||
private static final int PLAYER_STATUS_UPDATE_INTERVAL_MS = 50;
|
private static final int PLAYER_STATUS_UPDATE_INTERVAL_MS = 50;
|
||||||
@ -228,6 +222,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
progressSlider.setMinimum(0);
|
progressSlider.setMinimum(0);
|
||||||
progressSlider.setMaximum(2000);
|
progressSlider.setMaximum(2000);
|
||||||
progressSlider.setValue(0);
|
progressSlider.setValue(0);
|
||||||
|
|
||||||
|
//Manage the gstreamer video position when a user is dragging the slider in the panel.
|
||||||
progressSlider.addChangeListener(new ChangeListener() {
|
progressSlider.addChangeListener(new ChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent event) {
|
public void stateChanged(ChangeEvent event) {
|
||||||
@ -251,6 +247,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private boolean initGst() {
|
private boolean initGst() {
|
||||||
try {
|
try {
|
||||||
logger.log(Level.INFO, "Initializing gstreamer for video/audio viewing"); //NON-NLS
|
logger.log(Level.INFO, "Initializing gstreamer for video/audio viewing"); //NON-NLS
|
||||||
@ -276,130 +276,51 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
|
@NbBundle.Messages({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
|
||||||
void loadFile(final AbstractFile file, final Dimension dims) {
|
void loadFile(final AbstractFile file, final Dimension dims) {
|
||||||
EventQueue.invokeLater(() -> {
|
//Ensure everything is back in the inital state
|
||||||
reset();
|
reset();
|
||||||
infoLabel.setText("");
|
|
||||||
currentFile = file;
|
if (file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
|
||||||
final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
|
||||||
if (deleted) {
|
|
||||||
infoLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.setupVideo.infoLabel.text"));
|
infoLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.setupVideo.infoLabel.text"));
|
||||||
videoPanel.removeAll();
|
|
||||||
pauseButton.setEnabled(false);
|
|
||||||
progressSlider.setEnabled(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
java.io.File ioFile;
|
|
||||||
try {
|
try {
|
||||||
ioFile = VideoUtils.getVideoFileInTempDir(file);
|
String path = file.getUniquePath();
|
||||||
|
infoLabel.setText(path);
|
||||||
|
infoLabel.setToolTipText(path);
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Cannot get unique path of video file.", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (playbinLock) {
|
||||||
|
try {
|
||||||
|
extractMediaWorker = new ExtractMedia(file, VideoUtils.getVideoFileInTempDir(file));
|
||||||
|
extractMediaWorker.execute();
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||||
infoLabel.setText(Bundle.GstVideoPanel_noOpenCase_errMsg());
|
infoLabel.setText(Bundle.GstVideoPanel_noOpenCase_errMsg());
|
||||||
pauseButton.setEnabled(false);
|
pauseButton.setEnabled(false);
|
||||||
progressSlider.setEnabled(false);
|
progressSlider.setEnabled(false);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = "";
|
|
||||||
try {
|
|
||||||
path = file.getUniquePath();
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Cannot get unique path of video file.", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
infoLabel.setText(path);
|
|
||||||
infoLabel.setToolTipText(path);
|
|
||||||
pauseButton.setEnabled(true);
|
|
||||||
progressSlider.setEnabled(true);
|
|
||||||
timer = new Timer(PLAYER_STATUS_UPDATE_INTERVAL_MS, event -> {
|
|
||||||
if (!progressSlider.getValueIsAdjusting()) {
|
|
||||||
long duration;
|
|
||||||
long position;
|
|
||||||
synchronized (playbinLock) {
|
|
||||||
duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
|
||||||
position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
|
||||||
if (duration > 0) {
|
|
||||||
long positionDelta = duration - position;
|
|
||||||
if (positionDelta <= END_TIME_MARGIN_NS && gstPlayBin.isPlaying()) {
|
|
||||||
gstPlayBin.pause();
|
|
||||||
if (gstPlayBin.seek(ClockTime.ZERO) == false) {
|
|
||||||
logger.log(Level.WARNING, "Attempt to call PlayBin.seek() failed."); //NON-NLS
|
|
||||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
progressSlider.setValue(0);
|
|
||||||
pauseButton.setText("►");
|
|
||||||
} else {
|
|
||||||
double relativePosition = (double) position / duration;
|
|
||||||
progressSlider.setValue((int) (relativePosition * 2000));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
durationMillis = duration / 1000000;
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
long millisElapsed = position / 1000000;
|
|
||||||
// pick out the elapsed hours, minutes, seconds
|
|
||||||
long secondsElapsed = millisElapsed / 1000;
|
|
||||||
int elapsedHours = (int) secondsElapsed / 3600;
|
|
||||||
secondsElapsed -= elapsedHours * 3600;
|
|
||||||
int elapsedMinutes = (int) secondsElapsed / 60;
|
|
||||||
secondsElapsed -= elapsedMinutes * 60;
|
|
||||||
int elapsedSeconds = (int) secondsElapsed;
|
|
||||||
|
|
||||||
String durationFormat = "%02d:%02d:%02d/%02d:%02d:%02d "; //NON-NLS
|
|
||||||
String durationStr = String.format(durationFormat,
|
|
||||||
elapsedHours, elapsedMinutes, elapsedSeconds,
|
|
||||||
totalHours, totalMinutes, totalSeconds);
|
|
||||||
progressLabel.setText(durationStr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
gstVideoRenderer = new GstVideoRendererPanel();
|
|
||||||
synchronized (playbinLock) {
|
|
||||||
if (gstPlayBin != null) {
|
|
||||||
gstPlayBin.dispose();
|
|
||||||
}
|
|
||||||
gstPlayBin = new PlayBin("VideoPlayer"); //NON-NLS
|
|
||||||
gstPlayBin.setVideoSink(gstVideoRenderer.getVideoSink());
|
|
||||||
|
|
||||||
videoPanel.removeAll();
|
|
||||||
|
|
||||||
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
|
||||||
|
|
||||||
videoPanel.add(gstVideoRenderer);//add jfx ui to JPanel
|
|
||||||
|
|
||||||
videoPanel.setVisible(true);
|
|
||||||
|
|
||||||
gstPlayBin.setInputFile(ioFile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare this MediaViewVideoPanel to accept a different media file.
|
* Prepare this MediaViewVideoPanel to accept a different media file.
|
||||||
*/
|
*/
|
||||||
void reset() {
|
void reset() {
|
||||||
|
if (!isInited()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
timer.stop();
|
timer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the progress label text on the event dispatch thread
|
pauseButton.setEnabled(false);
|
||||||
SwingUtilities.invokeLater(() -> {
|
progressSlider.setEnabled(false);
|
||||||
progressLabel.setText("");
|
progressLabel.setText("00:00:00/00:00:00");
|
||||||
});
|
infoLabel.setText("");
|
||||||
|
|
||||||
if (!isInited()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (playbinLock) {
|
synchronized (playbinLock) {
|
||||||
if (gstPlayBin != null) {
|
if (gstPlayBin != null) {
|
||||||
@ -411,13 +332,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
gstPlayBin.dispose();
|
gstPlayBin.dispose();
|
||||||
gstPlayBin = null;
|
gstPlayBin = null;
|
||||||
}
|
}
|
||||||
gstVideoRenderer = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extractMediaWorker != null) {
|
||||||
|
extractMediaWorker.cancel(true);
|
||||||
|
extractMediaWorker = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
videoPanel.removeAll();
|
||||||
progressSlider.setValue(0);
|
progressSlider.setValue(0);
|
||||||
pauseButton.setText("►");
|
pauseButton.setText("►");
|
||||||
|
|
||||||
currentFile = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -511,38 +435,23 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
if (gstPlayBin == null) {
|
if (gstPlayBin == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
State state = gstPlayBin.getState();
|
switch (gstPlayBin.getState()) {
|
||||||
if (state.equals(State.PLAYING)) {
|
case PLAYING:
|
||||||
|
pauseButton.setText("►");
|
||||||
if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
|
if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
|
||||||
logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
|
logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
|
||||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pauseButton.setText("►");
|
break;
|
||||||
} else if (state.equals(State.PAUSED)) {
|
case PAUSED:
|
||||||
|
case READY:
|
||||||
|
case NULL:
|
||||||
|
pauseButton.setText("||");
|
||||||
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
||||||
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
||||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pauseButton.setText("||");
|
break;
|
||||||
} else if (state.equals(State.READY) || state.equals(State.NULL)) {
|
|
||||||
final File tempVideoFile;
|
|
||||||
try {
|
|
||||||
tempVideoFile = VideoUtils.getVideoFileInTempDir(currentFile);
|
|
||||||
} catch (NoCurrentCaseException ex) {
|
|
||||||
logger.log(Level.WARNING, "Exception while getting open case."); //NON-NLS
|
|
||||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extractMediaWorker != null) {
|
|
||||||
extractMediaWorker.cancel(true);
|
|
||||||
extractMediaWorker = null;
|
|
||||||
}
|
|
||||||
extractMediaWorker = new ExtractMedia(currentFile, tempVideoFile);
|
|
||||||
extractMediaWorker.execute();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_pauseButtonActionPerformed
|
}//GEN-LAST:event_pauseButtonActionPerformed
|
||||||
@ -556,78 +465,6 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
private javax.swing.JPanel videoPanel;
|
private javax.swing.JPanel videoPanel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread that extracts and plays a file
|
|
||||||
*/
|
|
||||||
private class ExtractMedia extends SwingWorker<Long, Void> {
|
|
||||||
|
|
||||||
private ProgressHandle progress;
|
|
||||||
private final AbstractFile sourceFile;
|
|
||||||
private final java.io.File tempFile;
|
|
||||||
|
|
||||||
ExtractMedia(AbstractFile sFile, java.io.File jFile) {
|
|
||||||
this.sourceFile = sFile;
|
|
||||||
this.tempFile = jFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Long doInBackground() throws Exception {
|
|
||||||
if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) {
|
|
||||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> this.cancel(true));
|
|
||||||
progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering"));
|
|
||||||
progress.start(100);
|
|
||||||
try {
|
|
||||||
Files.createParentDirs(tempFile);
|
|
||||||
return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean up or start the worker threads
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void done() {
|
|
||||||
try {
|
|
||||||
super.get(); //block and get all exceptions thrown while doInBackground()
|
|
||||||
} catch (CancellationException ex) {
|
|
||||||
logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
logger.log(Level.INFO, "Media buffering was interrupted."); //NON-NLS
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
if (progress != null) {
|
|
||||||
progress.finish();
|
|
||||||
}
|
|
||||||
if (!this.isCancelled()) {
|
|
||||||
playMedia();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void playMedia() {
|
|
||||||
if (tempFile == null || !tempFile.exists()) {
|
|
||||||
progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progressLabel.bufferingErr"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synchronized (playbinLock) {
|
|
||||||
gstPlayBin.seek(ClockTime.ZERO);
|
|
||||||
// must play, then pause and get state to get duration.
|
|
||||||
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
|
||||||
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
|
||||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pauseButton.setText("||");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSupportedExtensions() {
|
public List<String> getSupportedExtensions() {
|
||||||
return Arrays.asList(FILE_EXTENSIONS.clone());
|
return Arrays.asList(FILE_EXTENSIONS.clone());
|
||||||
@ -674,4 +511,134 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread that extracts and plays a file
|
||||||
|
*/
|
||||||
|
private class ExtractMedia extends SwingWorker<Long, Void> {
|
||||||
|
|
||||||
|
private ProgressHandle progress;
|
||||||
|
private final AbstractFile sourceFile;
|
||||||
|
private final java.io.File tempFile;
|
||||||
|
|
||||||
|
ExtractMedia(AbstractFile sFile, File jFile) {
|
||||||
|
this.sourceFile = sFile;
|
||||||
|
this.tempFile = jFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Long doInBackground() throws Exception {
|
||||||
|
if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) {
|
||||||
|
progress = ProgressHandle.createHandle(NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> this.cancel(true));
|
||||||
|
progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering"));
|
||||||
|
progress.start(100);
|
||||||
|
try {
|
||||||
|
Files.createParentDirs(tempFile);
|
||||||
|
return ContentUtils.writeToFile(sourceFile, tempFile, progress, this, true);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error buffering file", ex); //NON-NLS
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clean up or start the worker threads
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
try {
|
||||||
|
super.get(); //block and get all exceptions thrown while doInBackground()
|
||||||
|
} catch (CancellationException ex) {
|
||||||
|
logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
logger.log(Level.INFO, "Media buffering was interrupted."); //NON-NLS
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Fatal error during media buffering.", ex); //NON-NLS
|
||||||
|
} finally {
|
||||||
|
if (progress != null) {
|
||||||
|
progress.finish();
|
||||||
|
}
|
||||||
|
if (!this.isCancelled()) {
|
||||||
|
//PlayBin file is ready for playback, initialize all components.
|
||||||
|
synchronized (playbinLock) {
|
||||||
|
gstPlayBin = new PlayBin("VideoPlayer"); //NON-NLS
|
||||||
|
gstPlayBin.setInputFile(tempFile);
|
||||||
|
GstVideoRendererPanel gstVideoRenderer = new GstVideoRendererPanel();
|
||||||
|
gstPlayBin.setVideoSink(gstVideoRenderer.getVideoSink());
|
||||||
|
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
||||||
|
videoPanel.add(gstVideoRenderer);//add jfx ui to JPanel
|
||||||
|
/*
|
||||||
|
* It seems like PlayBin cannot be queried for duration
|
||||||
|
* until the video is actually being played. This call
|
||||||
|
* to pause below is used to 'initialize' the PlayBin to
|
||||||
|
* display the duration in the content viewer before the
|
||||||
|
* play button is pressed. This is a suggested solution
|
||||||
|
* in the gstreamer google groups page.
|
||||||
|
*/
|
||||||
|
gstPlayBin.pause();
|
||||||
|
timer = new Timer(PLAYER_STATUS_UPDATE_INTERVAL_MS, new VideoPanelUpdater());
|
||||||
|
timer.start();
|
||||||
|
videoPanel.setVisible(true);
|
||||||
|
pauseButton.setEnabled(true);
|
||||||
|
progressSlider.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class VideoPanelUpdater implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (!progressSlider.getValueIsAdjusting()) {
|
||||||
|
synchronized (playbinLock) {
|
||||||
|
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||||
|
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
|
//Duration is -1 when the PlayBin is in the inital READY or
|
||||||
|
//NULL states, do nothing in these cases.
|
||||||
|
//if (duration <= 0) {
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
long positionDelta = duration - position;
|
||||||
|
//NOTE: This conditional is problematic and is responsible for JIRA-4863
|
||||||
|
if (positionDelta <= END_TIME_MARGIN_NS && gstPlayBin.isPlaying()) {
|
||||||
|
gstPlayBin.pause();
|
||||||
|
if (gstPlayBin.seek(ClockTime.ZERO) == false) {
|
||||||
|
logger.log(Level.WARNING, "Attempt to call PlayBin.seek() failed."); //NON-NLS
|
||||||
|
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
progressSlider.setValue(0);
|
||||||
|
pauseButton.setText("►");
|
||||||
|
} else {
|
||||||
|
double relativePosition = (double) position / duration;
|
||||||
|
progressSlider.setValue((int) (relativePosition * 2000));
|
||||||
|
}
|
||||||
|
|
||||||
|
String durationStr = String.format("%s/%s", formatTime(position), formatTime(duration));
|
||||||
|
progressLabel.setText(durationStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert nanoseconds into an HH:MM:SS format.
|
||||||
|
*/
|
||||||
|
private String formatTime(long ns) {
|
||||||
|
long millis = ns / 1000000;
|
||||||
|
long seconds = (int) millis / 1000;
|
||||||
|
long hours = (int) seconds / 3600;
|
||||||
|
seconds -= hours * 3600;
|
||||||
|
long minutes = (int) seconds / 60;
|
||||||
|
seconds -= minutes * 60;
|
||||||
|
seconds = (int) seconds;
|
||||||
|
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user