19 package org.sleuthkit.autopsy.contentviewers;
21 import com.google.common.io.Files;
22 import java.awt.Color;
23 import java.awt.Dimension;
24 import java.awt.Graphics;
25 import java.awt.Graphics2D;
26 import java.awt.Point;
27 import java.awt.Rectangle;
28 import java.awt.RenderingHints;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.ActionListener;
31 import java.awt.event.MouseEvent;
33 import java.io.IOException;
34 import java.util.Arrays;
35 import java.util.EnumSet;
36 import java.util.List;
37 import java.util.SortedSet;
38 import java.util.TreeSet;
39 import java.util.concurrent.CancellationException;
40 import java.util.concurrent.ExecutionException;
41 import java.util.concurrent.Semaphore;
42 import java.util.concurrent.TimeUnit;
43 import java.util.logging.Level;
44 import javax.swing.BoxLayout;
45 import javax.swing.JPanel;
46 import javax.swing.SwingWorker;
47 import javax.swing.Timer;
48 import javax.swing.event.ChangeEvent;
49 import org.freedesktop.gstreamer.Bus;
50 import org.freedesktop.gstreamer.Gst;
51 import org.freedesktop.gstreamer.GstObject;
52 import org.freedesktop.gstreamer.State;
53 import org.freedesktop.gstreamer.elements.PlayBin;
54 import org.netbeans.api.progress.ProgressHandle;
55 import org.openide.util.NbBundle;
63 import javafx.embed.swing.JFXPanel;
64 import javax.swing.JComponent;
65 import javax.swing.JSlider;
66 import javax.swing.SwingUtilities;
67 import javax.swing.event.ChangeListener;
68 import javax.swing.plaf.basic.BasicSliderUI;
69 import javax.swing.plaf.basic.BasicSliderUI.TrackListener;
70 import org.freedesktop.gstreamer.ClockTime;
71 import org.freedesktop.gstreamer.Format;
72 import org.freedesktop.gstreamer.GstException;
73 import org.freedesktop.gstreamer.event.SeekFlags;
74 import org.freedesktop.gstreamer.event.SeekType;
80 @SuppressWarnings(
"PMD.SingularField")
81 public class
MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaViewPanel {
84 private static final String[] FILE_EXTENSIONS =
new String[]{
113 private static final List<String> MIME_TYPES = Arrays.asList(
146 "video/x-intel-h263",
162 "video/x-msvideocodec",
187 private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(
MediaPlayerPanel.class,
188 "GstVideoPanel.cannotProcFile.err");
200 private static final int PROGRESS_SLIDER_SIZE = 2000;
201 private static final int SKIP_IN_SECONDS = 30;
215 customizeComponents();
218 sliderLock =
new Semaphore(1,
true);
222 progressSlider.setEnabled(
false);
223 progressSlider.setMinimum(0);
224 progressSlider.setMaximum(PROGRESS_SLIDER_SIZE);
225 progressSlider.setValue(0);
227 progressSlider.addChangeListener(
new ChangeListener() {
229 public void stateChanged(ChangeEvent e) {
230 if (progressSlider.getValueIsAdjusting()) {
231 long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
232 double relativePosition = progressSlider.getValue() * 1.0 / PROGRESS_SLIDER_SIZE;
233 long newStartTime = (long) (relativePosition * duration);
234 double playBackRate = getPlayBackRate();
235 gstPlayBin.seek(playBackRate,
239 EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
241 SeekType.SET, newStartTime,
246 updateTimeLabel(newStartTime, duration);
251 audioSlider.addChangeListener((ChangeEvent event) -> {
252 if (audioSlider.getValueIsAdjusting()) {
253 double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
254 gstPlayBin.setVolume(audioPercent);
257 errorListener =
new Bus.ERROR() {
259 public void errorMessage(GstObject go,
int i, String
string) {
260 SwingUtilities.invokeLater(() -> {
261 enableComponents(
false);
262 infoLabel.setText(String.format(
263 "<html><font color='red'>%s</font></html>",
264 MEDIA_PLAYER_ERROR_STRING));
269 stateChangeListener =
new Bus.STATE_CHANGED() {
271 public void stateChanged(GstObject go, State oldState, State currentState, State pendingState) {
272 if (State.PLAYING.equals(currentState)) {
273 SwingUtilities.invokeLater(() -> {
274 playButton.setText(
"||");
277 SwingUtilities.invokeLater(() -> {
278 playButton.setText(
"►");
283 endOfStreamListener =
new Bus.EOS() {
285 public void endOfStream(GstObject go) {
286 gstPlayBin.seek(ClockTime.ZERO);
290 Gst.getExecutor().submit(() -> gstPlayBin.pause());
301 @NbBundle.Messages({
"GstVideoPanel.noOpenCase.errMsg=No open case available."})
302 void loadFile(
final AbstractFile file) {
304 infoLabel.setText(
"");
305 if (file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
306 infoLabel.setText(NbBundle.getMessage(
this.getClass(),
"GstVideoPanel.setupVideo.infoLabel.text"));
312 extractMediaWorker =
new ExtractMedia(file, VideoUtils.getVideoFileInTempDir(file));
313 extractMediaWorker.execute();
314 }
catch (NoCurrentCaseException ex) {
315 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
316 infoLabel.setText(String.format(
"<html><font color='red'>%s</font></html>", Bundle.GstVideoPanel_noOpenCase_errMsg()));
317 enableComponents(
false);
326 "MediaPlayerPanel.noSupport=File not supported."
328 void resetComponents() {
329 progressLabel.setText(String.format(
"%s/%s", Bundle.MediaPlayerPanel_unknownTime(),
330 Bundle.MediaPlayerPanel_unknownTime()));
331 infoLabel.setText(Bundle.MediaPlayerPanel_noSupport());
332 progressSlider.setValue(0);
339 if (extractMediaWorker != null) {
340 extractMediaWorker.cancel(
true);
343 if (gstPlayBin != null) {
345 gstPlayBin.getBus().disconnect(endOfStreamListener);
346 gstPlayBin.getBus().disconnect(stateChangeListener);
347 gstPlayBin.getBus().disconnect(errorListener);
348 gstPlayBin.dispose();
352 videoPanel.removeAll();
354 enableComponents(
false);
358 playButton.setEnabled(isEnabled);
359 progressSlider.setEnabled(isEnabled);
360 videoPanel.setEnabled(isEnabled);
361 audioSlider.setEnabled(isEnabled);
362 rewindButton.setEnabled(isEnabled);
363 fastForwardButton.setEnabled(isEnabled);
364 playBackSpeedComboBox.setEnabled(isEnabled);
369 return Arrays.asList(FILE_EXTENSIONS.clone());
379 String extension = file.getNameExtension();
396 if (getSupportedExtensions().contains(
"." + extension)) {
397 SortedSet<String> mimeTypes =
new TreeSet<>(getSupportedMimeTypes());
400 return mimeTypes.contains(mimeType);
402 logger.log(Level.WARNING,
"Failed to look up mimetype for " + file.getName() +
" using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
403 if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
408 return getSupportedExtensions().contains(
"." + extension);
421 progressLabel.setText(formatTime(start) +
"/" + formatTime(total));
430 int selectIndex = playBackSpeedComboBox.getSelectedIndex();
431 String selectText = playBackSpeedComboBox.getItemAt(selectIndex);
432 return Double.valueOf(selectText.substring(0, selectText.length() - 1));
439 "MediaPlayerPanel.unknownTime=Unknown",
440 "MediaPlayerPanel.timeFormat=%02d:%02d:%02d"
444 return Bundle.MediaPlayerPanel_unknownTime();
447 long seconds = TimeUnit.SECONDS.convert(ns, TimeUnit.NANOSECONDS);
448 long hours = TimeUnit.HOURS.convert(seconds, TimeUnit.SECONDS);
449 seconds -= TimeUnit.SECONDS.convert(hours, TimeUnit.HOURS);
450 long minutes = TimeUnit.MINUTES.convert(seconds, TimeUnit.SECONDS);
451 seconds -= TimeUnit.SECONDS.convert(minutes, TimeUnit.MINUTES);
453 return String.format(Bundle.MediaPlayerPanel_timeFormat(), hours, minutes, seconds);
467 this.sourceFile = sFile;
468 this.tempFile = jFile;
473 if (!tempFile.exists() || tempFile.length() < sourceFile.getSize()) {
474 progress = ProgressHandle.createHandle(NbBundle.getMessage(
MediaPlayerPanel.class,
"GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> this.cancel(
true));
476 SwingUtilities.invokeLater(() -> {
477 progressLabel.setText(NbBundle.getMessage(
this.getClass(),
"GstVideoPanel.progress.buffering"));
482 Files.createParentDirs(tempFile);
484 }
catch (IOException ex) {
485 logger.log(Level.WARNING,
"Error creating parent directory for copying video/audio in temp directory", ex);
501 if (this.isCancelled()) {
511 gstPlayBin =
new PlayBin(
"VideoPlayer", tempFile.toURI());
513 Bus playBinBus = gstPlayBin.getBus();
514 playBinBus.connect(endOfStreamListener);
515 playBinBus.connect(stateChangeListener);
516 playBinBus.connect(errorListener);
518 if (this.isCancelled()) {
522 JFXPanel fxPanel =
new JFXPanel();
523 videoPanel.removeAll();
524 videoPanel.setLayout(
new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
525 videoPanel.add(fxPanel);
526 fxAppSink =
new JavaFxAppSink(
"JavaFxAppSink", fxPanel);
527 gstPlayBin.setVideoSink(fxAppSink);
529 if (this.isCancelled()) {
533 gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
537 enableComponents(
true);
538 }
catch (CancellationException ex) {
539 logger.log(Level.INFO,
"Media buffering was canceled.");
540 }
catch (InterruptedException ex) {
541 logger.log(Level.INFO,
"Media buffering was interrupted.");
542 }
catch (ExecutionException ex) {
543 logger.log(Level.SEVERE,
"Fatal error during media buffering.", ex);
555 if (!progressSlider.getValueIsAdjusting()) {
556 sliderLock.acquireUninterruptibly();
557 long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
558 long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
564 if (duration >= 0 && position >= 0) {
565 double relativePosition = (double) position / duration;
566 progressSlider.setValue((
int) (relativePosition * PROGRESS_SLIDER_SIZE));
569 SwingUtilities.invokeLater(() -> {
570 updateTimeLabel(position, duration);
572 sliderLock.release();
601 Color lightBlue =
new Color(0, 130, 255);
604 unseen = Color.LIGHT_GRAY;
606 thumbColor = lightBlue;
608 this.thumbDimension =
new Dimension(thumbDimension);
624 return new Dimension(thumbDimension);
646 this.config = config;
659 Rectangle thumb = this.thumbRect;
661 Color original = graphic.getColor();
667 graphic.fillOval(thumb.x, thumb.y, thumbDimension.width, thumbDimension.height);
670 graphic.setColor(original);
678 Rectangle track = this.trackRect;
682 Rectangle thumb = this.thumbRect;
683 int thumbX = thumb.x;
684 int thumbY = thumb.y;
686 Color original = graphic.getColor();
690 graphic.drawLine(track.x, track.y + track.height / 2,
691 thumbX, thumbY + track.height / 2);
695 graphic.drawLine(thumbX, thumbY + track.height / 2,
696 track.x + track.width, track.y + track.height / 2);
699 graphic.setColor(original);
711 Point mousePosition = slider.getMousePosition();
712 if (mousePosition == null) {
715 int value = this.valueForXPosition(mousePosition.x);
721 sliderLock.acquireUninterruptibly();
722 slider.setValueIsAdjusting(
true);
723 slider.setValue(value);
724 slider.setValueIsAdjusting(
false);
725 sliderLock.release();
732 public void update(Graphics graphic, JComponent component) {
733 if (graphic instanceof Graphics2D) {
734 Graphics2D graphic2 = (Graphics2D) graphic;
735 graphic2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
736 RenderingHints.VALUE_ANTIALIAS_ON);
739 super.update(graphic, component);
753 if (!slider.isEnabled() || !SwingUtilities.isLeftMouseButton(e)) {
757 scrollDueToClickInTrack(0);
763 super.mousePressed(e);
768 if (!slider.isEnabled() || !SwingUtilities.isLeftMouseButton(e)) {
772 super.mouseReleased(e);
785 @SuppressWarnings(
"unchecked")
787 private
void initComponents() {
788 java.awt.GridBagConstraints gridBagConstraints;
790 videoPanel =
new javax.swing.JPanel();
791 controlPanel =
new javax.swing.JPanel();
792 progressSlider =
new javax.swing.JSlider();
793 progressLabel =
new javax.swing.JLabel();
794 buttonPanel =
new javax.swing.JPanel();
795 playButton =
new javax.swing.JButton();
796 fastForwardButton =
new javax.swing.JButton();
797 rewindButton =
new javax.swing.JButton();
798 VolumeIcon =
new javax.swing.JLabel();
799 audioSlider =
new javax.swing.JSlider();
800 infoLabel =
new javax.swing.JLabel();
801 playBackPanel =
new javax.swing.JPanel();
802 playBackSpeedComboBox =
new javax.swing.JComboBox<>();
803 playBackSpeedLabel =
new javax.swing.JLabel();
805 javax.swing.GroupLayout videoPanelLayout =
new javax.swing.GroupLayout(videoPanel);
806 videoPanel.setLayout(videoPanelLayout);
807 videoPanelLayout.setHorizontalGroup(
808 videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
809 .addGap(0, 0, Short.MAX_VALUE)
811 videoPanelLayout.setVerticalGroup(
812 videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
813 .addGap(0, 131, Short.MAX_VALUE)
816 progressSlider.setValue(0);
817 progressSlider.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
818 progressSlider.setDoubleBuffered(
true);
819 progressSlider.setMinimumSize(
new java.awt.Dimension(36, 21));
820 progressSlider.setPreferredSize(
new java.awt.Dimension(200, 21));
823 org.openide.awt.Mnemonics.setLocalizedText(progressLabel,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.progressLabel.text"));
825 buttonPanel.setLayout(
new java.awt.GridBagLayout());
827 org.openide.awt.Mnemonics.setLocalizedText(playButton,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.playButton.text"));
828 playButton.addActionListener(
new java.awt.event.ActionListener() {
829 public void actionPerformed(java.awt.event.ActionEvent evt) {
830 playButtonActionPerformed(evt);
833 gridBagConstraints =
new java.awt.GridBagConstraints();
834 gridBagConstraints.gridx = 1;
835 gridBagConstraints.gridy = 0;
836 gridBagConstraints.ipadx = 21;
837 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
838 gridBagConstraints.insets =
new java.awt.Insets(5, 6, 0, 0);
839 buttonPanel.add(playButton, gridBagConstraints);
841 org.openide.awt.Mnemonics.setLocalizedText(fastForwardButton,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.fastForwardButton.text"));
842 fastForwardButton.addActionListener(
new java.awt.event.ActionListener() {
843 public void actionPerformed(java.awt.event.ActionEvent evt) {
844 fastForwardButtonActionPerformed(evt);
847 gridBagConstraints =
new java.awt.GridBagConstraints();
848 gridBagConstraints.gridx = 2;
849 gridBagConstraints.gridy = 0;
850 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
851 gridBagConstraints.insets =
new java.awt.Insets(5, 6, 0, 0);
852 buttonPanel.add(fastForwardButton, gridBagConstraints);
854 org.openide.awt.Mnemonics.setLocalizedText(rewindButton,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.rewindButton.text"));
855 rewindButton.addActionListener(
new java.awt.event.ActionListener() {
856 public void actionPerformed(java.awt.event.ActionEvent evt) {
857 rewindButtonActionPerformed(evt);
860 gridBagConstraints =
new java.awt.GridBagConstraints();
861 gridBagConstraints.gridx = 0;
862 gridBagConstraints.gridy = 0;
863 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
864 gridBagConstraints.insets =
new java.awt.Insets(5, 0, 1, 0);
865 buttonPanel.add(rewindButton, gridBagConstraints);
867 org.openide.awt.Mnemonics.setLocalizedText(VolumeIcon,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.VolumeIcon.text"));
868 VolumeIcon.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
869 gridBagConstraints =
new java.awt.GridBagConstraints();
870 gridBagConstraints.gridx = 3;
871 gridBagConstraints.gridy = 0;
872 gridBagConstraints.ipadx = 8;
873 gridBagConstraints.ipady = 7;
874 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
875 gridBagConstraints.insets =
new java.awt.Insets(6, 14, 0, 0);
876 buttonPanel.add(VolumeIcon, gridBagConstraints);
878 audioSlider.setMajorTickSpacing(10);
879 audioSlider.setMaximum(50);
880 audioSlider.setMinorTickSpacing(5);
881 audioSlider.setToolTipText(
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.audioSlider.toolTipText"));
882 audioSlider.setValue(25);
883 audioSlider.setMinimumSize(
new java.awt.Dimension(200, 21));
884 audioSlider.setPreferredSize(
new java.awt.Dimension(200, 21));
886 gridBagConstraints =
new java.awt.GridBagConstraints();
887 gridBagConstraints.gridx = 4;
888 gridBagConstraints.gridy = 0;
889 gridBagConstraints.ipadx = -116;
890 gridBagConstraints.ipady = 7;
891 gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
892 gridBagConstraints.insets =
new java.awt.Insets(3, 1, 0, 10);
893 buttonPanel.add(audioSlider, gridBagConstraints);
895 infoLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
896 org.openide.awt.Mnemonics.setLocalizedText(infoLabel,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.infoLabel.text"));
897 infoLabel.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
899 playBackSpeedComboBox.setModel(
new javax.swing.DefaultComboBoxModel<>(
new String[] {
"0.25x",
"0.50x",
"0.75x",
"1x",
"1.25x",
"1.50x",
"1.75x",
"2x" }));
900 playBackSpeedComboBox.setSelectedIndex(3);
901 playBackSpeedComboBox.setMaximumSize(
new java.awt.Dimension(53, 23));
902 playBackSpeedComboBox.setMinimumSize(
new java.awt.Dimension(53, 23));
903 playBackSpeedComboBox.setPreferredSize(
new java.awt.Dimension(53, 23));
904 playBackSpeedComboBox.addActionListener(
new java.awt.event.ActionListener() {
905 public void actionPerformed(java.awt.event.ActionEvent evt) {
906 playBackSpeedComboBoxActionPerformed(evt);
910 org.openide.awt.Mnemonics.setLocalizedText(playBackSpeedLabel,
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class,
"MediaPlayerPanel.playBackSpeedLabel.text"));
912 javax.swing.GroupLayout playBackPanelLayout =
new javax.swing.GroupLayout(playBackPanel);
913 playBackPanel.setLayout(playBackPanelLayout);
914 playBackPanelLayout.setHorizontalGroup(
915 playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
916 .addGroup(playBackPanelLayout.createSequentialGroup()
917 .addComponent(playBackSpeedLabel)
918 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
919 .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
922 playBackPanelLayout.setVerticalGroup(
923 playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
924 .addGroup(playBackPanelLayout.createSequentialGroup()
926 .addGroup(playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
927 .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
928 .addComponent(playBackSpeedLabel))
929 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
932 javax.swing.GroupLayout controlPanelLayout =
new javax.swing.GroupLayout(controlPanel);
933 controlPanel.setLayout(controlPanelLayout);
934 controlPanelLayout.setHorizontalGroup(
935 controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
936 .addGroup(controlPanelLayout.createSequentialGroup()
938 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
939 .addComponent(infoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
940 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, controlPanelLayout.createSequentialGroup()
941 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
942 .addComponent(buttonPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
943 .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE))
944 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
945 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING,
false)
946 .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
947 .addComponent(playBackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
948 .addGap(10, 10, 10)))
951 controlPanelLayout.setVerticalGroup(
952 controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
953 .addGroup(controlPanelLayout.createSequentialGroup()
955 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING,
false)
956 .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
957 .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
959 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING,
false)
960 .addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
961 .addComponent(playBackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
963 .addComponent(infoLabel))
966 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
967 this.setLayout(layout);
968 layout.setHorizontalGroup(
969 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
970 .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
971 .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
973 layout.setVerticalGroup(
974 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
975 .addGroup(layout.createSequentialGroup()
976 .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
977 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
978 .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
983 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
985 long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
987 long newTime = Math.max(currentTime - rewindDelta, 0);
988 double playBackRate = getPlayBackRate();
989 gstPlayBin.seek(playBackRate,
993 EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
995 SeekType.SET, newTime,
1001 long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
1002 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
1004 long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
1007 if (currentTime + fastForwardDelta >= duration) {
1011 long newTime = currentTime + fastForwardDelta;
1012 double playBackRate = getPlayBackRate();
1013 gstPlayBin.seek(playBackRate,
1017 EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
1019 SeekType.SET, newTime,
1025 if (gstPlayBin.isPlaying()) {
1028 double playBackRate = getPlayBackRate();
1029 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
1031 gstPlayBin.seek(playBackRate,
1035 EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
1037 SeekType.SET, currentTime,
1045 double playBackRate = getPlayBackRate();
1046 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
1047 gstPlayBin.seek(playBackRate,
1051 EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
1054 SeekType.SET, currentTime,
CircularJSliderConfiguration(Dimension thumbDimension)
void actionPerformed(ActionEvent e)
void playButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JButton playButton
void updateTimeLabel(long start, long total)
final Dimension thumbDimension
boolean isSupported(AbstractFile file)
void mouseReleased(MouseEvent e)
javax.swing.JSlider progressSlider
ExtractMedia extractMediaWorker
void scrollDueToClickInTrack(int direction)
javax.swing.JPanel buttonPanel
javax.swing.JButton rewindButton
Color getUnseenTrackColor()
javax.swing.JButton fastForwardButton
void paintTrack(Graphics graphic)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt)
String getMIMEType(AbstractFile file)
CircularJSliderUI(JSlider slider, CircularJSliderConfiguration config)
TrackListener createTrackListener(JSlider slider)
List< String > getSupportedExtensions()
javax.swing.JPanel videoPanel
List< String > getSupportedMimeTypes()
Color getSeenTrackColor()
javax.swing.JLabel progressLabel
void paintThumb(Graphics graphic)
void enableComponents(boolean isEnabled)
final Semaphore sliderLock
Dimension getThumbDimension()
javax.swing.JComboBox< String > playBackSpeedComboBox
String formatTime(long ns)
Bus.EOS endOfStreamListener
void update(Graphics graphic, JComponent component)
javax.swing.JLabel playBackSpeedLabel
void mousePressed(MouseEvent e)
javax.swing.JPanel controlPanel
void customizeComponents()
javax.swing.JLabel VolumeIcon
Bus.STATE_CHANGED stateChangeListener
volatile PlayBin gstPlayBin
void rewindButtonActionPerformed(java.awt.event.ActionEvent evt)
synchronized static Logger getLogger(String name)
final CircularJSliderConfiguration config
void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JSlider audioSlider
javax.swing.JLabel infoLabel
javax.swing.JPanel playBackPanel