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;
 
   32 import java.awt.event.MouseListener;
 
   34 import java.io.IOException;
 
   35 import java.util.Arrays;
 
   36 import java.util.EnumSet;
 
   37 import java.util.List;
 
   38 import java.util.SortedSet;
 
   39 import java.util.TreeSet;
 
   40 import java.util.concurrent.CancellationException;
 
   41 import java.util.concurrent.ExecutionException;
 
   42 import java.util.concurrent.Semaphore;
 
   43 import java.util.concurrent.TimeUnit;
 
   44 import java.util.logging.Level;
 
   45 import javax.swing.BoxLayout;
 
   46 import javax.swing.JPanel;
 
   47 import javax.swing.SwingWorker;
 
   48 import javax.swing.Timer;
 
   49 import javax.swing.event.ChangeEvent;
 
   50 import org.freedesktop.gstreamer.Bus;
 
   51 import org.freedesktop.gstreamer.Gst;
 
   52 import org.freedesktop.gstreamer.GstObject;
 
   53 import org.freedesktop.gstreamer.State;
 
   54 import org.freedesktop.gstreamer.elements.PlayBin;
 
   55 import org.netbeans.api.progress.ProgressHandle;
 
   56 import org.openide.util.NbBundle;
 
   64 import javafx.embed.swing.JFXPanel;
 
   65 import javax.swing.ImageIcon;
 
   66 import javax.swing.JComponent;
 
   67 import javax.swing.JSlider;
 
   68 import javax.swing.SwingUtilities;
 
   69 import javax.swing.event.ChangeListener;
 
   70 import javax.swing.plaf.basic.BasicSliderUI;
 
   71 import javax.swing.plaf.basic.BasicSliderUI.TrackListener;
 
   72 import org.freedesktop.gstreamer.ClockTime;
 
   73 import org.freedesktop.gstreamer.Format;
 
   74 import org.freedesktop.gstreamer.GstException;
 
   75 import org.freedesktop.gstreamer.event.SeekFlags;
 
   76 import org.freedesktop.gstreamer.event.SeekType;
 
   85 @SuppressWarnings(
"PMD.SingularField") 
 
   86 public class 
MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaViewPanel {
 
   89     private static final String[] FILE_EXTENSIONS = 
new String[]{
 
  118     private static final List<String> MIME_TYPES = Arrays.asList(
 
  151             "video/x-intel-h263",
 
  167             "video/x-msvideocodec",
 
  192     private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(
MediaPlayerPanel.class,
 
  193             "GstVideoPanel.cannotProcFile.err");
 
  205     private static final int PROGRESS_SLIDER_SIZE = 2000;
 
  206     private static final int SKIP_IN_SECONDS = 30;
 
  208     private final ImageIcon playIcon = 
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"));
 
  209     private final ImageIcon pauseIcon = 
new ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Pause-01.png"));
 
  218     private static volatile boolean IS_GST_ENABLED = 
true;
 
  225         customizeComponents();
 
  228         sliderLock = 
new Semaphore(1, 
true);
 
  232         enableComponents(
false);
 
  233         progressSlider.setMinimum(0);
 
  234         progressSlider.setMaximum(PROGRESS_SLIDER_SIZE);
 
  235         progressSlider.setValue(0);
 
  237         progressSlider.addChangeListener(
new ChangeListener() {
 
  239             public void stateChanged(ChangeEvent e) {
 
  240                 if (progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
 
  241                     long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
 
  242                     double relativePosition = progressSlider.getValue() * 1.0 / PROGRESS_SLIDER_SIZE;
 
  243                     long newStartTime = (long) (relativePosition * duration);
 
  244                     double playBackRate = getPlayBackRate();
 
  245                     gstPlayBin.seek(playBackRate,
 
  249                             EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
  251                             SeekType.SET, newStartTime,
 
  256                     updateTimeLabel(newStartTime, duration);
 
  261         progressSlider.addMouseListener(
new MouseListener() {
 
  262             private State previousState = State.NULL;
 
  265             public void mousePressed(MouseEvent e) {
 
  266                 if (gstPlayBin != null) {
 
  267                     previousState = gstPlayBin.getState();
 
  273             public void mouseReleased(MouseEvent e) {
 
  274                 if (previousState.equals(State.PLAYING) && gstPlayBin != null) {
 
  277                 previousState = State.NULL;
 
  281             public void mouseClicked(MouseEvent e) {
 
  285             public void mouseEntered(MouseEvent e) {
 
  289             public void mouseExited(MouseEvent e) {
 
  294         audioSlider.addChangeListener((ChangeEvent event) -> {
 
  295             if (audioSlider.getValueIsAdjusting() && gstPlayBin != null) {
 
  296                 double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
 
  297                 gstPlayBin.setVolume(audioPercent);
 
  300         errorListener = 
new Bus.ERROR() {
 
  302             public void errorMessage(GstObject go, 
int i, String 
string) {
 
  303                 SwingUtilities.invokeLater(() -> {
 
  304                     enableComponents(
false);
 
  305                     infoLabel.setText(String.format(
 
  306                             "<html><font color='red'>%s</font></html>",
 
  307                             MEDIA_PLAYER_ERROR_STRING));
 
  312         stateChangeListener = 
new Bus.STATE_CHANGED() {
 
  314             public void stateChanged(GstObject go, State oldState, State currentState, State pendingState) {
 
  315                 if (State.PLAYING.equals(currentState)) {
 
  316                     SwingUtilities.invokeLater(() -> {
 
  317                         playButton.setIcon(pauseIcon);
 
  320                     SwingUtilities.invokeLater(() -> {
 
  321                         playButton.setIcon(playIcon);
 
  326         endOfStreamListener = 
new Bus.EOS() {
 
  328             public void endOfStream(GstObject go) {
 
  329                 if (gstPlayBin != null) {
 
  330                     gstPlayBin.seek(ClockTime.ZERO);
 
  334                     Gst.getExecutor().submit(() -> gstPlayBin.pause());
 
  346     @NbBundle.Messages({
"GstVideoPanel.noOpenCase.errMsg=No open case available."})
 
  347     void loadFile(
final AbstractFile file) {
 
  349         infoLabel.setText(
"");
 
  350         if (file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
 
  351             infoLabel.setText(NbBundle.getMessage(
this.getClass(), 
"GstVideoPanel.setupVideo.infoLabel.text"));
 
  357             extractMediaWorker = 
new ExtractMedia(file, VideoUtils.getVideoFileInTempDir(file));
 
  358             extractMediaWorker.execute();
 
  359         } 
catch (NoCurrentCaseException ex) {
 
  360             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  361             infoLabel.setText(String.format(
"<html><font color='red'>%s</font></html>", Bundle.GstVideoPanel_noOpenCase_errMsg()));
 
  362             enableComponents(
false);
 
  371         "MediaPlayerPanel.noSupport=File not supported." 
  373     void resetComponents() {
 
  374         progressLabel.setText(String.format(
"%s/%s", Bundle.MediaPlayerPanel_unknownTime(),
 
  375                 Bundle.MediaPlayerPanel_unknownTime()));
 
  376         infoLabel.setText(Bundle.MediaPlayerPanel_noSupport());
 
  377         progressSlider.setValue(0);
 
  384         if (extractMediaWorker != null) {
 
  385             extractMediaWorker.cancel(
true);
 
  388         if (gstPlayBin != null) {
 
  389             Gst.getExecutor().submit(() -> {
 
  391                 gstPlayBin.getBus().disconnect(endOfStreamListener);
 
  392                 gstPlayBin.getBus().disconnect(stateChangeListener);
 
  393                 gstPlayBin.getBus().disconnect(errorListener);
 
  394                 gstPlayBin.getBus().dispose();
 
  395                 gstPlayBin.dispose();
 
  400         videoPanel.removeAll();
 
  402         enableComponents(
false);
 
  406         playButton.setEnabled(isEnabled);
 
  407         progressSlider.setEnabled(isEnabled);
 
  408         videoPanel.setEnabled(isEnabled);
 
  409         audioSlider.setEnabled(isEnabled);
 
  410         rewindButton.setEnabled(isEnabled);
 
  411         fastForwardButton.setEnabled(isEnabled);
 
  412         playBackSpeedComboBox.setEnabled(isEnabled);
 
  417         return Arrays.asList(FILE_EXTENSIONS.clone());
 
  427         if (!IS_GST_ENABLED) {
 
  431         String extension = file.getNameExtension();
 
  448         if (getSupportedExtensions().contains(
"." + extension)) {
 
  449             SortedSet<String> mimeTypes = 
new TreeSet<>(getSupportedMimeTypes());
 
  452                 return mimeTypes.contains(mimeType);
 
  454                 logger.log(Level.WARNING, 
"Failed to look up mimetype for " + file.getName() + 
" using FileTypeDetector.  Fallingback on AbstractFile.isMimeType", ex);
 
  455                 if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
 
  460             return getSupportedExtensions().contains(
"." + extension);
 
  473         progressLabel.setText(formatTime(start) + 
"/" + formatTime(total));
 
  482         int selectIndex = playBackSpeedComboBox.getSelectedIndex();
 
  483         String selectText = playBackSpeedComboBox.getItemAt(selectIndex);
 
  484         return Double.valueOf(selectText.substring(0, selectText.length() - 1));
 
  491         "MediaPlayerPanel.unknownTime=Unknown",
 
  492         "MediaPlayerPanel.timeFormat=%02d:%02d:%02d" 
  496             return Bundle.MediaPlayerPanel_unknownTime();
 
  499         long seconds = TimeUnit.SECONDS.convert(ns, TimeUnit.NANOSECONDS);
 
  500         long hours = TimeUnit.HOURS.convert(seconds, TimeUnit.SECONDS);
 
  501         seconds -= TimeUnit.SECONDS.convert(hours, TimeUnit.HOURS);
 
  502         long minutes = TimeUnit.MINUTES.convert(seconds, TimeUnit.SECONDS);
 
  503         seconds -= TimeUnit.SECONDS.convert(minutes, TimeUnit.MINUTES);
 
  505         return String.format(Bundle.MediaPlayerPanel_timeFormat(), hours, minutes, seconds);
 
  519             this.sourceFile = sFile;
 
  520             this.tempFile = jFile;
 
  525             if (!tempFile.exists() || tempFile.length() < sourceFile.getSize()) {
 
  526                 progress = ProgressHandle.createHandle(NbBundle.getMessage(
MediaPlayerPanel.class, 
"GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> this.cancel(
true));
 
  528                 SwingUtilities.invokeLater(() -> {
 
  529                     progressLabel.setText(NbBundle.getMessage(
this.getClass(), 
"GstVideoPanel.progress.buffering"));
 
  534                     Files.createParentDirs(tempFile);
 
  536                 } 
catch (IOException ex) {
 
  537                     logger.log(Level.WARNING, 
"Error creating parent directory for copying video/audio in temp directory", ex); 
 
  549             "MediaPlayerPanel.playbackDisabled=A problem was encountered with" 
  550             + 
" the video and audio playback service. Video and audio " 
  551             + 
"playback will be disabled for the remainder of the session." 
  558                 if (this.isCancelled()) {
 
  567                     IS_GST_ENABLED = 
false;
 
  571                 Gst.getExecutor().submit(() -> {
 
  573                     gstPlayBin = 
new PlayBin(
"VideoPlayer", tempFile.toURI());
 
  575                     Bus playBinBus = gstPlayBin.getBus();
 
  576                     playBinBus.connect(endOfStreamListener);
 
  577                     playBinBus.connect(stateChangeListener);
 
  578                     playBinBus.connect(errorListener);
 
  580                     if (this.isCancelled()) {
 
  584                     JFXPanel fxPanel = 
new JFXPanel();
 
  585                     videoPanel.removeAll();
 
  586                     videoPanel.setLayout(
new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
 
  587                     videoPanel.add(fxPanel);
 
  588                     fxAppSink = 
new JavaFxAppSink(
"JavaFxAppSink", fxPanel);
 
  589                     if (gstPlayBin != null) {
 
  590                         gstPlayBin.setVideoSink(fxAppSink);
 
  592                     if (this.isCancelled()) {
 
  595                     if (gstPlayBin != null) {
 
  596                         gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
 
  601                     SwingUtilities.invokeLater(() -> {
 
  602                         enableComponents(
true);
 
  605             } 
catch (CancellationException ex) {
 
  606                 logger.log(Level.INFO, 
"Media buffering was canceled."); 
 
  607             } 
catch (InterruptedException ex) {
 
  608                 logger.log(Level.INFO, 
"Media buffering was interrupted."); 
 
  609             } 
catch (ExecutionException ex) {
 
  610                 logger.log(Level.SEVERE, 
"Fatal error during media buffering.", ex); 
 
  622             if (!progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
 
  623                 Gst.getExecutor().submit(() -> {
 
  625                         sliderLock.acquireUninterruptibly();
 
  626                         long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
  627                         long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
 
  634                         if (duration >= 0 && position >= 0) {
 
  635                             double relativePosition = (double) position / duration;
 
  636                             progressSlider.setValue((
int) (relativePosition * PROGRESS_SLIDER_SIZE));
 
  639                         SwingUtilities.invokeLater(() -> {
 
  640                             updateTimeLabel(position, duration);
 
  643                         sliderLock.release();
 
  670             this.thumbDimension = thumbDimension;
 
  673             Color lightBlue = 
new Color(0, 130, 255);
 
  674             thumbColor = lightBlue;
 
  675             trackSeen = lightBlue;
 
  676             trackUnseen = Color.LIGHT_GRAY;
 
  681             return new Dimension(thumbDimension);
 
  690             Rectangle thumb = this.thumbRect;
 
  692             Color original = graphic.getColor();
 
  696             graphic.setColor(thumbColor);
 
  697             graphic.fillOval(thumb.x, thumb.y, thumbDimension.width, thumbDimension.height);
 
  700             graphic.setColor(original);
 
  708             Rectangle track = this.trackRect;
 
  712             Rectangle thumb = this.thumbRect;
 
  713             int thumbX = thumb.x;
 
  714             int thumbY = thumb.y;
 
  716             Color original = graphic.getColor();
 
  719             graphic.setColor(trackSeen);
 
  720             graphic.drawLine(track.x, track.y + track.height / 2,
 
  721                     thumbX, thumbY + track.height / 2);
 
  724             graphic.setColor(trackUnseen);
 
  725             graphic.drawLine(thumbX, thumbY + track.height / 2,
 
  726                     track.x + track.width, track.y + track.height / 2);
 
  729             graphic.setColor(original);
 
  742             return new TrackListener() {
 
  744                 public void mousePressed(MouseEvent e) {
 
  745                     if (!slider.isEnabled() || !SwingUtilities.isLeftMouseButton(e)) {
 
  749                     scrollDueToClickInTrack(0);
 
  752                     super.mousePressed(e);
 
  761             Point mousePosition = slider.getMousePosition();
 
  762             if (mousePosition == null) {
 
  765             int value = this.valueForXPosition(mousePosition.x);
 
  771             sliderLock.acquireUninterruptibly();
 
  772             slider.setValueIsAdjusting(
true);
 
  773             slider.setValue(value);
 
  774             slider.setValueIsAdjusting(
false);
 
  775             sliderLock.release();
 
  782         public void update(Graphics graphic, JComponent component) {
 
  783             if (graphic instanceof Graphics2D) {
 
  784                 Graphics2D graphic2 = (Graphics2D) graphic;
 
  785                 graphic2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 
  786                         RenderingHints.VALUE_ANTIALIAS_ON);
 
  789             super.update(graphic, component);
 
  798     @SuppressWarnings(
"unchecked")
 
  800     private 
void initComponents() {
 
  801         java.awt.GridBagConstraints gridBagConstraints;
 
  803         videoPanel = 
new javax.swing.JPanel();
 
  804         controlPanel = 
new javax.swing.JPanel();
 
  805         progressSlider = 
new javax.swing.JSlider();
 
  806         progressLabel = 
new javax.swing.JLabel();
 
  807         buttonPanel = 
new javax.swing.JPanel();
 
  808         playButton = 
new javax.swing.JButton();
 
  809         fastForwardButton = 
new javax.swing.JButton();
 
  810         rewindButton = 
new javax.swing.JButton();
 
  811         VolumeIcon = 
new javax.swing.JLabel();
 
  812         audioSlider = 
new javax.swing.JSlider();
 
  813         infoLabel = 
new javax.swing.JLabel();
 
  814         playBackPanel = 
new javax.swing.JPanel();
 
  815         playBackSpeedComboBox = 
new javax.swing.JComboBox<>();
 
  816         playBackSpeedLabel = 
new javax.swing.JLabel();
 
  818         javax.swing.GroupLayout videoPanelLayout = 
new javax.swing.GroupLayout(videoPanel);
 
  819         videoPanel.setLayout(videoPanelLayout);
 
  820         videoPanelLayout.setHorizontalGroup(
 
  821             videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  822             .addGap(0, 0, Short.MAX_VALUE)
 
  824         videoPanelLayout.setVerticalGroup(
 
  825             videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  826             .addGap(0, 117, Short.MAX_VALUE)
 
  829         progressSlider.setValue(0);
 
  830         progressSlider.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
 
  831         progressSlider.setDoubleBuffered(
true);
 
  832         progressSlider.setMinimumSize(
new java.awt.Dimension(36, 21));
 
  833         progressSlider.setPreferredSize(
new java.awt.Dimension(200, 21));
 
  834         progressSlider.setUI(
new CircularJSliderUI(progressSlider, 
new Dimension(18,18)));
 
  836         org.openide.awt.Mnemonics.setLocalizedText(progressLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.progressLabel.text")); 
 
  838         buttonPanel.setLayout(
new java.awt.GridBagLayout());
 
  840         playButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"))); 
 
  841         org.openide.awt.Mnemonics.setLocalizedText(playButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.playButton.text")); 
 
  842         playButton.setMaximumSize(
new java.awt.Dimension(53, 29));
 
  843         playButton.setMinimumSize(
new java.awt.Dimension(53, 29));
 
  844         playButton.setPreferredSize(
new java.awt.Dimension(49, 29));
 
  845         playButton.addActionListener(
new java.awt.event.ActionListener() {
 
  846             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  847                 playButtonActionPerformed(evt);
 
  850         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  851         gridBagConstraints.gridx = 1;
 
  852         gridBagConstraints.gridy = 0;
 
  853         gridBagConstraints.ipadx = 21;
 
  854         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  855         gridBagConstraints.insets = 
new java.awt.Insets(5, 6, 0, 0);
 
  856         buttonPanel.add(playButton, gridBagConstraints);
 
  858         fastForwardButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Fast-forward-01.png"))); 
 
  859         org.openide.awt.Mnemonics.setLocalizedText(fastForwardButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.fastForwardButton.text")); 
 
  860         fastForwardButton.addActionListener(
new java.awt.event.ActionListener() {
 
  861             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  862                 fastForwardButtonActionPerformed(evt);
 
  865         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  866         gridBagConstraints.gridx = 2;
 
  867         gridBagConstraints.gridy = 0;
 
  868         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  869         gridBagConstraints.insets = 
new java.awt.Insets(5, 6, 0, 0);
 
  870         buttonPanel.add(fastForwardButton, gridBagConstraints);
 
  872         rewindButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Fast-rewind-01.png"))); 
 
  873         org.openide.awt.Mnemonics.setLocalizedText(rewindButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.rewindButton.text")); 
 
  874         rewindButton.addActionListener(
new java.awt.event.ActionListener() {
 
  875             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  876                 rewindButtonActionPerformed(evt);
 
  879         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  880         gridBagConstraints.gridx = 0;
 
  881         gridBagConstraints.gridy = 0;
 
  882         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  883         gridBagConstraints.insets = 
new java.awt.Insets(5, 0, 1, 0);
 
  884         buttonPanel.add(rewindButton, gridBagConstraints);
 
  886         org.openide.awt.Mnemonics.setLocalizedText(VolumeIcon, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.VolumeIcon.text")); 
 
  887         VolumeIcon.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
 
  888         VolumeIcon.setMaximumSize(
new java.awt.Dimension(34, 29));
 
  889         VolumeIcon.setMinimumSize(
new java.awt.Dimension(34, 29));
 
  890         VolumeIcon.setPreferredSize(
new java.awt.Dimension(34, 19));
 
  891         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  892         gridBagConstraints.gridx = 3;
 
  893         gridBagConstraints.gridy = 0;
 
  894         gridBagConstraints.ipadx = 8;
 
  895         gridBagConstraints.ipady = 7;
 
  896         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  897         gridBagConstraints.insets = 
new java.awt.Insets(6, 14, 0, 0);
 
  898         buttonPanel.add(VolumeIcon, gridBagConstraints);
 
  900         audioSlider.setMajorTickSpacing(10);
 
  901         audioSlider.setMaximum(50);
 
  902         audioSlider.setMinorTickSpacing(5);
 
  903         audioSlider.setToolTipText(
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.audioSlider.toolTipText")); 
 
  904         audioSlider.setValue(25);
 
  905         audioSlider.setMaximumSize(
new java.awt.Dimension(32767, 19));
 
  906         audioSlider.setMinimumSize(
new java.awt.Dimension(200, 19));
 
  907         audioSlider.setPreferredSize(
new java.awt.Dimension(200, 30));
 
  908         audioSlider.setRequestFocusEnabled(
false);
 
  910         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  911         gridBagConstraints.gridx = 4;
 
  912         gridBagConstraints.gridy = 0;
 
  913         gridBagConstraints.ipadx = -116;
 
  914         gridBagConstraints.ipady = 7;
 
  915         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  916         gridBagConstraints.insets = 
new java.awt.Insets(3, 1, 0, 10);
 
  917         buttonPanel.add(audioSlider, gridBagConstraints);
 
  919         infoLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
 
  920         org.openide.awt.Mnemonics.setLocalizedText(infoLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.infoLabel.text")); 
 
  921         infoLabel.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
 
  923         playBackSpeedComboBox.setModel(
new javax.swing.DefaultComboBoxModel<>(
new String[] { 
"0.25x", 
"0.50x", 
"0.75x", 
"1x", 
"1.25x", 
"1.50x", 
"1.75x", 
"2x" }));
 
  924         playBackSpeedComboBox.setSelectedIndex(3);
 
  925         playBackSpeedComboBox.setMaximumSize(
new java.awt.Dimension(53, 29));
 
  926         playBackSpeedComboBox.setMinimumSize(
new java.awt.Dimension(53, 29));
 
  927         playBackSpeedComboBox.setPreferredSize(
new java.awt.Dimension(53, 29));
 
  928         playBackSpeedComboBox.setRequestFocusEnabled(
false);
 
  929         playBackSpeedComboBox.addActionListener(
new java.awt.event.ActionListener() {
 
  930             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  931                 playBackSpeedComboBoxActionPerformed(evt);
 
  935         org.openide.awt.Mnemonics.setLocalizedText(playBackSpeedLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.playBackSpeedLabel.text")); 
 
  936         playBackSpeedLabel.setMaximumSize(
new java.awt.Dimension(34, 19));
 
  937         playBackSpeedLabel.setMinimumSize(
new java.awt.Dimension(34, 19));
 
  938         playBackSpeedLabel.setPreferredSize(
new java.awt.Dimension(34, 19));
 
  940         javax.swing.GroupLayout playBackPanelLayout = 
new javax.swing.GroupLayout(playBackPanel);
 
  941         playBackPanel.setLayout(playBackPanelLayout);
 
  942         playBackPanelLayout.setHorizontalGroup(
 
  943             playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  944             .addGroup(playBackPanelLayout.createSequentialGroup()
 
  945                 .addComponent(playBackSpeedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  946                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  947                 .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  950         playBackPanelLayout.setVerticalGroup(
 
  951             playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  952             .addGroup(playBackPanelLayout.createSequentialGroup()
 
  954                 .addGroup(playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  955                     .addGroup(playBackPanelLayout.createSequentialGroup()
 
  957                         .addComponent(playBackSpeedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  958                     .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  962         javax.swing.GroupLayout controlPanelLayout = 
new javax.swing.GroupLayout(controlPanel);
 
  963         controlPanel.setLayout(controlPanelLayout);
 
  964         controlPanelLayout.setHorizontalGroup(
 
  965             controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  966             .addGroup(controlPanelLayout.createSequentialGroup()
 
  968                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  969                     .addComponent(infoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  970                     .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, controlPanelLayout.createSequentialGroup()
 
  971                         .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
 
  972                             .addComponent(buttonPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  973                             .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE))
 
  974                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  975                         .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  976                             .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  977                             .addComponent(playBackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
 
  978                         .addGap(10, 10, 10)))
 
  981         controlPanelLayout.setVerticalGroup(
 
  982             controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  983             .addGroup(controlPanelLayout.createSequentialGroup()
 
  985                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  986                     .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  987                     .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  989                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  990                     .addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  991                     .addComponent(playBackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  993                 .addComponent(infoLabel))
 
  996         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
  997         this.setLayout(layout);
 
  998         layout.setHorizontalGroup(
 
  999             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1000             .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1001             .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1003         layout.setVerticalGroup(
 
 1004             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1005             .addGroup(layout.createSequentialGroup()
 
 1006                 .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1007                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1008                 .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
 1013         Gst.getExecutor().submit(() -> {
 
 1014             if (gstPlayBin != null) {
 
 1015                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1017                 long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
 
 1019                 long newTime = Math.max(currentTime - rewindDelta, 0);
 
 1020                 double playBackRate = getPlayBackRate();
 
 1021                 gstPlayBin.seek(playBackRate,
 
 1025                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1027                         SeekType.SET, newTime,
 
 1035         Gst.getExecutor().submit(() -> {
 
 1036             if (gstPlayBin != null) {
 
 1037                 long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
 
 1038                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1040                 long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
 
 1043                 long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
 
 1044                 if ((duration - currentTime) <= twoSecondsInNano) {
 
 1049                 if (currentTime + fastForwardDelta >= duration) {
 
 1051                     newTime = currentTime + (duration - currentTime) / 2;
 
 1053                     newTime = currentTime + fastForwardDelta;
 
 1056                 double playBackRate = getPlayBackRate();
 
 1057                 gstPlayBin.seek(playBackRate,
 
 1061                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1063                         SeekType.SET, newTime,
 
 1071         Gst.getExecutor().submit(() -> {
 
 1072             if (gstPlayBin != null) {
 
 1073                 if (gstPlayBin.isPlaying()) {
 
 1076                     double playBackRate = getPlayBackRate();
 
 1077                     long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1079                     gstPlayBin.seek(playBackRate,
 
 1083                             EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1085                             SeekType.SET, currentTime,
 
 1095         Gst.getExecutor().submit(() -> {
 
 1096             if (gstPlayBin != null) {
 
 1097                 double playBackRate = getPlayBackRate();
 
 1098                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1099                 gstPlayBin.seek(playBackRate,
 
 1103                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1106                         SeekType.SET, currentTime,
 
void actionPerformed(ActionEvent e)
 
void playButtonActionPerformed(java.awt.event.ActionEvent evt)
 
javax.swing.JButton playButton
 
void updateTimeLabel(long start, long total)
 
boolean isSupported(AbstractFile file)
 
javax.swing.JSlider progressSlider
 
ExtractMedia extractMediaWorker
 
void scrollDueToClickInTrack(int direction)
 
javax.swing.JPanel buttonPanel
 
javax.swing.JButton rewindButton
 
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)
 
TrackListener createTrackListener(JSlider slider)
 
List< String > getSupportedExtensions()
 
javax.swing.JPanel videoPanel
 
List< String > getSupportedMimeTypes()
 
javax.swing.JLabel progressLabel
 
void paintThumb(Graphics graphic)
 
void enableComponents(boolean isEnabled)
 
final Semaphore sliderLock
 
CircularJSliderUI(JSlider slider, Dimension thumbDimension)
 
javax.swing.JComboBox< String > playBackSpeedComboBox
 
String formatTime(long ns)
 
Bus.EOS endOfStreamListener
 
void update(Graphics graphic, JComponent component)
 
javax.swing.JLabel playBackSpeedLabel
 
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 Dimension thumbDimension
 
void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt)
 
javax.swing.JSlider audioSlider
 
static synchronized GstStatus tryLoad()
 
javax.swing.JLabel infoLabel
 
javax.swing.JPanel playBackPanel
 
static void error(String message)