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));
 
  309                     progressLabel.setText(
"");
 
  314         stateChangeListener = 
new Bus.STATE_CHANGED() {
 
  316             public void stateChanged(GstObject go, State oldState, State currentState, State pendingState) {
 
  317                 if (State.PLAYING.equals(currentState)) {
 
  318                     SwingUtilities.invokeLater(() -> {
 
  319                         playButton.setIcon(pauseIcon);
 
  322                     SwingUtilities.invokeLater(() -> {
 
  323                         playButton.setIcon(playIcon);
 
  328         endOfStreamListener = 
new Bus.EOS() {
 
  330             public void endOfStream(GstObject go) {
 
  331                 if (gstPlayBin != null) {
 
  332                     gstPlayBin.seek(ClockTime.ZERO);
 
  336                     Gst.getExecutor().submit(() -> gstPlayBin.pause());
 
  348     @NbBundle.Messages({
"GstVideoPanel.noOpenCase.errMsg=No open case available."})
 
  349     void loadFile(
final AbstractFile file) {
 
  351         infoLabel.setText(
"");
 
  352         if (file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC)) {
 
  353             infoLabel.setText(NbBundle.getMessage(
this.getClass(), 
"GstVideoPanel.setupVideo.infoLabel.text"));
 
  359             extractMediaWorker = 
new ExtractMedia(file, VideoUtils.getVideoFileInTempDir(file));
 
  360             extractMediaWorker.execute();
 
  361         } 
catch (NoCurrentCaseException ex) {
 
  362             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  363             infoLabel.setText(String.format(
"<html><font color='red'>%s</font></html>", Bundle.GstVideoPanel_noOpenCase_errMsg()));
 
  364             enableComponents(
false);
 
  373         "MediaPlayerPanel.noSupport=File not supported." 
  375     void resetComponents() {
 
  376         progressLabel.setText(String.format(
"%s/%s", Bundle.MediaPlayerPanel_unknownTime(),
 
  377                 Bundle.MediaPlayerPanel_unknownTime()));
 
  378         infoLabel.setText(Bundle.MediaPlayerPanel_noSupport());
 
  379         progressSlider.setValue(0);
 
  386         if (extractMediaWorker != null) {
 
  387             extractMediaWorker.cancel(
true);
 
  390         if (gstPlayBin != null) {
 
  391             Gst.getExecutor().submit(() -> {
 
  393                 gstPlayBin.getBus().disconnect(endOfStreamListener);
 
  394                 gstPlayBin.getBus().disconnect(stateChangeListener);
 
  395                 gstPlayBin.getBus().disconnect(errorListener);
 
  396                 gstPlayBin.getBus().dispose();
 
  397                 gstPlayBin.dispose();
 
  402         videoPanel.removeAll();
 
  404         enableComponents(
false);
 
  408         playButton.setEnabled(isEnabled);
 
  409         progressSlider.setEnabled(isEnabled);
 
  410         videoPanel.setEnabled(isEnabled);
 
  411         audioSlider.setEnabled(isEnabled);
 
  412         rewindButton.setEnabled(isEnabled);
 
  413         fastForwardButton.setEnabled(isEnabled);
 
  414         playBackSpeedComboBox.setEnabled(isEnabled);
 
  419         return Arrays.asList(FILE_EXTENSIONS.clone());
 
  429         if (!IS_GST_ENABLED) {
 
  450         if (getSupportedExtensions().contains(
"." + extension)) {
 
  451             SortedSet<String> mimeTypes = 
new TreeSet<>(getSupportedMimeTypes());
 
  454                 return mimeTypes.contains(mimeType);
 
  456                 logger.log(Level.WARNING, 
"Failed to look up mimetype for " + file.
getName() + 
" using FileTypeDetector.  Fallingback on AbstractFile.isMimeType", ex);
 
  462             return getSupportedExtensions().contains(
"." + extension);
 
  475         progressLabel.setText(formatTime(start) + 
"/" + formatTime(total));
 
  484         int selectIndex = playBackSpeedComboBox.getSelectedIndex();
 
  485         String selectText = playBackSpeedComboBox.getItemAt(selectIndex);
 
  486         return Double.valueOf(selectText.substring(0, selectText.length() - 1));
 
  493         "MediaPlayerPanel.unknownTime=Unknown",
 
  494         "MediaPlayerPanel.timeFormat=%02d:%02d:%02d" 
  498             return Bundle.MediaPlayerPanel_unknownTime();
 
  501         long seconds = TimeUnit.SECONDS.convert(ns, TimeUnit.NANOSECONDS);
 
  502         long hours = TimeUnit.HOURS.convert(seconds, TimeUnit.SECONDS);
 
  503         seconds -= TimeUnit.SECONDS.convert(hours, TimeUnit.HOURS);
 
  504         long minutes = TimeUnit.MINUTES.convert(seconds, TimeUnit.SECONDS);
 
  505         seconds -= TimeUnit.SECONDS.convert(minutes, TimeUnit.MINUTES);
 
  507         return String.format(Bundle.MediaPlayerPanel_timeFormat(), hours, minutes, seconds);
 
  521             this.sourceFile = sFile;
 
  522             this.tempFile = jFile;
 
  527             if (this.isCancelled()) {
 
  528                 throw new InterruptedException(
"Thread has been interrupted");
 
  536             if (this.isCancelled()) {
 
  537                 throw new InterruptedException(
"Thread has been interrupted");
 
  540             if (!tempFile.exists() || tempFile.length() < sourceFile.
getSize()) {
 
  541                 progress = ProgressHandle.createHandle(NbBundle.getMessage(
MediaPlayerPanel.class, 
"GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.
getName()), () -> this.cancel(
true));
 
  543                 SwingUtilities.invokeLater(() -> {
 
  544                     progressLabel.setText(NbBundle.getMessage(
this.getClass(), 
"GstVideoPanel.progress.buffering"));
 
  549                     Files.createParentDirs(tempFile);
 
  551                 } 
catch (IOException ex) {
 
  552                     logger.log(Level.WARNING, 
"Error creating parent directory for copying video/audio in temp directory", ex); 
 
  564             "MediaPlayerPanel.playbackDisabled=A problem was encountered with" 
  565             + 
" the video and audio playback service. Video and audio " 
  566             + 
"playback will be disabled for the remainder of the session." 
  571                 if (this.isCancelled()) {
 
  580                 if (this.isCancelled()) {
 
  584                 Gst.getExecutor().submit(() -> {
 
  586                     gstPlayBin = 
new PlayBin(
"VideoPlayer", tempFile.toURI());
 
  588                     Bus playBinBus = gstPlayBin.getBus();
 
  589                     playBinBus.connect(endOfStreamListener);
 
  590                     playBinBus.connect(stateChangeListener);
 
  591                     playBinBus.connect(errorListener);
 
  593                     if (this.isCancelled()) {
 
  597                     JFXPanel fxPanel = 
new JFXPanel();
 
  598                     videoPanel.removeAll();
 
  599                     videoPanel.setLayout(
new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
 
  600                     videoPanel.add(fxPanel);
 
  601                     fxAppSink = 
new JavaFxAppSink(
"JavaFxAppSink", fxPanel);
 
  602                     if (gstPlayBin != null) {
 
  603                         gstPlayBin.setVideoSink(fxAppSink);
 
  605                     if (this.isCancelled()) {
 
  608                     if (gstPlayBin != null) {
 
  609                         gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
 
  614                     SwingUtilities.invokeLater(() -> {
 
  615                         enableComponents(
true);
 
  618             } 
catch (CancellationException ex) {
 
  619                 logger.log(Level.INFO, 
"Media buffering was canceled."); 
 
  620             } 
catch (InterruptedException ex) {
 
  621                 logger.log(Level.INFO, 
"Media buffering was interrupted."); 
 
  622             } 
catch (ExecutionException ex) {
 
  623                 logger.log(Level.SEVERE, 
"Fatal error during media buffering.", ex); 
 
  635             if (!progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
 
  636                 Gst.getExecutor().submit(() -> {
 
  638                         sliderLock.acquireUninterruptibly();
 
  639                         long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
  640                         long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
 
  647                         if (duration >= 0 && position >= 0) {
 
  648                             double relativePosition = (double) position / duration;
 
  649                             progressSlider.setValue((
int) (relativePosition * PROGRESS_SLIDER_SIZE));
 
  652                         SwingUtilities.invokeLater(() -> {
 
  653                             updateTimeLabel(position, duration);
 
  656                         sliderLock.release();
 
  683             this.thumbDimension = thumbDimension;
 
  686             Color lightBlue = 
new Color(0, 130, 255);
 
  687             thumbColor = lightBlue;
 
  688             trackSeen = lightBlue;
 
  689             trackUnseen = Color.LIGHT_GRAY;
 
  694             return new Dimension(thumbDimension);
 
  703             Rectangle thumb = this.thumbRect;
 
  705             Color original = graphic.getColor();
 
  709             graphic.setColor(thumbColor);
 
  710             graphic.fillOval(thumb.x, thumb.y, thumbDimension.width, thumbDimension.height);
 
  713             graphic.setColor(original);
 
  721             Rectangle track = this.trackRect;
 
  725             Rectangle thumb = this.thumbRect;
 
  726             int thumbX = thumb.x;
 
  727             int thumbY = thumb.y;
 
  729             Color original = graphic.getColor();
 
  732             graphic.setColor(trackSeen);
 
  733             graphic.drawLine(track.x, track.y + track.height / 2,
 
  734                     thumbX, thumbY + track.height / 2);
 
  737             graphic.setColor(trackUnseen);
 
  738             graphic.drawLine(thumbX, thumbY + track.height / 2,
 
  739                     track.x + track.width, track.y + track.height / 2);
 
  742             graphic.setColor(original);
 
  755             return new TrackListener() {
 
  757                 public void mousePressed(MouseEvent e) {
 
  758                     if (!slider.isEnabled() || !SwingUtilities.isLeftMouseButton(e)) {
 
  762                     scrollDueToClickInTrack(0);
 
  765                     super.mousePressed(e);
 
  774             Point mousePosition = slider.getMousePosition();
 
  775             if (mousePosition == null) {
 
  778             int value = this.valueForXPosition(mousePosition.x);
 
  784             sliderLock.acquireUninterruptibly();
 
  785             slider.setValueIsAdjusting(
true);
 
  786             slider.setValue(value);
 
  787             slider.setValueIsAdjusting(
false);
 
  788             sliderLock.release();
 
  795         public void update(Graphics graphic, JComponent component) {
 
  796             if (graphic instanceof Graphics2D) {
 
  797                 Graphics2D graphic2 = (Graphics2D) graphic;
 
  798                 graphic2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 
  799                         RenderingHints.VALUE_ANTIALIAS_ON);
 
  802             super.update(graphic, component);
 
  811     @SuppressWarnings(
"unchecked")
 
  813     private 
void initComponents() {
 
  814         java.awt.GridBagConstraints gridBagConstraints;
 
  816         videoPanel = 
new javax.swing.JPanel();
 
  817         controlPanel = 
new javax.swing.JPanel();
 
  818         progressSlider = 
new javax.swing.JSlider();
 
  819         progressLabel = 
new javax.swing.JLabel();
 
  820         buttonPanel = 
new javax.swing.JPanel();
 
  821         playButton = 
new javax.swing.JButton();
 
  822         fastForwardButton = 
new javax.swing.JButton();
 
  823         rewindButton = 
new javax.swing.JButton();
 
  824         VolumeIcon = 
new javax.swing.JLabel();
 
  825         audioSlider = 
new javax.swing.JSlider();
 
  826         infoLabel = 
new javax.swing.JLabel();
 
  827         playBackPanel = 
new javax.swing.JPanel();
 
  828         playBackSpeedComboBox = 
new javax.swing.JComboBox<>();
 
  829         playBackSpeedLabel = 
new javax.swing.JLabel();
 
  831         javax.swing.GroupLayout videoPanelLayout = 
new javax.swing.GroupLayout(videoPanel);
 
  832         videoPanel.setLayout(videoPanelLayout);
 
  833         videoPanelLayout.setHorizontalGroup(
 
  834             videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  835             .addGap(0, 0, Short.MAX_VALUE)
 
  837         videoPanelLayout.setVerticalGroup(
 
  838             videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  839             .addGap(0, 117, Short.MAX_VALUE)
 
  842         progressSlider.setValue(0);
 
  843         progressSlider.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
 
  844         progressSlider.setDoubleBuffered(
true);
 
  845         progressSlider.setMinimumSize(
new java.awt.Dimension(36, 21));
 
  846         progressSlider.setPreferredSize(
new java.awt.Dimension(200, 21));
 
  847         progressSlider.setUI(
new CircularJSliderUI(progressSlider, 
new Dimension(18,18)));
 
  849         org.openide.awt.Mnemonics.setLocalizedText(progressLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.progressLabel.text")); 
 
  851         buttonPanel.setLayout(
new java.awt.GridBagLayout());
 
  853         playButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"))); 
 
  854         org.openide.awt.Mnemonics.setLocalizedText(playButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.playButton.text")); 
 
  855         playButton.setMaximumSize(
new java.awt.Dimension(53, 29));
 
  856         playButton.setMinimumSize(
new java.awt.Dimension(53, 29));
 
  857         playButton.setPreferredSize(
new java.awt.Dimension(49, 29));
 
  858         playButton.addActionListener(
new java.awt.event.ActionListener() {
 
  859             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  860                 playButtonActionPerformed(evt);
 
  863         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  864         gridBagConstraints.gridx = 1;
 
  865         gridBagConstraints.gridy = 0;
 
  866         gridBagConstraints.ipadx = 21;
 
  867         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  868         gridBagConstraints.insets = 
new java.awt.Insets(5, 6, 0, 0);
 
  869         buttonPanel.add(playButton, gridBagConstraints);
 
  871         fastForwardButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Fast-forward-01.png"))); 
 
  872         org.openide.awt.Mnemonics.setLocalizedText(fastForwardButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.fastForwardButton.text")); 
 
  873         fastForwardButton.addActionListener(
new java.awt.event.ActionListener() {
 
  874             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  875                 fastForwardButtonActionPerformed(evt);
 
  878         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  879         gridBagConstraints.gridx = 2;
 
  880         gridBagConstraints.gridy = 0;
 
  881         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  882         gridBagConstraints.insets = 
new java.awt.Insets(5, 6, 0, 0);
 
  883         buttonPanel.add(fastForwardButton, gridBagConstraints);
 
  885         rewindButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/contentviewers/images/Fast-rewind-01.png"))); 
 
  886         org.openide.awt.Mnemonics.setLocalizedText(rewindButton, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.rewindButton.text")); 
 
  887         rewindButton.addActionListener(
new java.awt.event.ActionListener() {
 
  888             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  889                 rewindButtonActionPerformed(evt);
 
  892         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  893         gridBagConstraints.gridx = 0;
 
  894         gridBagConstraints.gridy = 0;
 
  895         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  896         gridBagConstraints.insets = 
new java.awt.Insets(5, 0, 1, 0);
 
  897         buttonPanel.add(rewindButton, gridBagConstraints);
 
  899         org.openide.awt.Mnemonics.setLocalizedText(VolumeIcon, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.VolumeIcon.text")); 
 
  900         VolumeIcon.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
 
  901         VolumeIcon.setMaximumSize(
new java.awt.Dimension(34, 29));
 
  902         VolumeIcon.setMinimumSize(
new java.awt.Dimension(34, 29));
 
  903         VolumeIcon.setPreferredSize(
new java.awt.Dimension(34, 19));
 
  904         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  905         gridBagConstraints.gridx = 3;
 
  906         gridBagConstraints.gridy = 0;
 
  907         gridBagConstraints.ipadx = 8;
 
  908         gridBagConstraints.ipady = 7;
 
  909         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  910         gridBagConstraints.insets = 
new java.awt.Insets(6, 14, 0, 0);
 
  911         buttonPanel.add(VolumeIcon, gridBagConstraints);
 
  913         audioSlider.setMajorTickSpacing(10);
 
  914         audioSlider.setMaximum(50);
 
  915         audioSlider.setMinorTickSpacing(5);
 
  916         audioSlider.setToolTipText(
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.audioSlider.toolTipText")); 
 
  917         audioSlider.setValue(25);
 
  918         audioSlider.setMaximumSize(
new java.awt.Dimension(32767, 19));
 
  919         audioSlider.setMinimumSize(
new java.awt.Dimension(200, 19));
 
  920         audioSlider.setPreferredSize(
new java.awt.Dimension(200, 30));
 
  921         audioSlider.setRequestFocusEnabled(
false);
 
  923         gridBagConstraints = 
new java.awt.GridBagConstraints();
 
  924         gridBagConstraints.gridx = 4;
 
  925         gridBagConstraints.gridy = 0;
 
  926         gridBagConstraints.ipadx = -116;
 
  927         gridBagConstraints.ipady = 7;
 
  928         gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
 
  929         gridBagConstraints.insets = 
new java.awt.Insets(3, 1, 0, 10);
 
  930         buttonPanel.add(audioSlider, gridBagConstraints);
 
  932         infoLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
 
  933         org.openide.awt.Mnemonics.setLocalizedText(infoLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.infoLabel.text")); 
 
  934         infoLabel.setCursor(
new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
 
  936         playBackSpeedComboBox.setModel(
new javax.swing.DefaultComboBoxModel<>(
new String[] { 
"0.25x", 
"0.50x", 
"0.75x", 
"1x", 
"1.25x", 
"1.50x", 
"1.75x", 
"2x" }));
 
  937         playBackSpeedComboBox.setSelectedIndex(3);
 
  938         playBackSpeedComboBox.setMaximumSize(
new java.awt.Dimension(53, 29));
 
  939         playBackSpeedComboBox.setMinimumSize(
new java.awt.Dimension(53, 29));
 
  940         playBackSpeedComboBox.setPreferredSize(
new java.awt.Dimension(53, 29));
 
  941         playBackSpeedComboBox.setRequestFocusEnabled(
false);
 
  942         playBackSpeedComboBox.addActionListener(
new java.awt.event.ActionListener() {
 
  943             public void actionPerformed(java.awt.event.ActionEvent evt) {
 
  944                 playBackSpeedComboBoxActionPerformed(evt);
 
  948         org.openide.awt.Mnemonics.setLocalizedText(playBackSpeedLabel, 
org.openide.util.NbBundle.getMessage(
MediaPlayerPanel.class, 
"MediaPlayerPanel.playBackSpeedLabel.text")); 
 
  949         playBackSpeedLabel.setMaximumSize(
new java.awt.Dimension(34, 19));
 
  950         playBackSpeedLabel.setMinimumSize(
new java.awt.Dimension(34, 19));
 
  951         playBackSpeedLabel.setPreferredSize(
new java.awt.Dimension(34, 19));
 
  953         javax.swing.GroupLayout playBackPanelLayout = 
new javax.swing.GroupLayout(playBackPanel);
 
  954         playBackPanel.setLayout(playBackPanelLayout);
 
  955         playBackPanelLayout.setHorizontalGroup(
 
  956             playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  957             .addGroup(playBackPanelLayout.createSequentialGroup()
 
  958                 .addComponent(playBackSpeedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  959                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  960                 .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
 
  963         playBackPanelLayout.setVerticalGroup(
 
  964             playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  965             .addGroup(playBackPanelLayout.createSequentialGroup()
 
  967                 .addGroup(playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  968                     .addGroup(playBackPanelLayout.createSequentialGroup()
 
  970                         .addComponent(playBackSpeedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
  971                     .addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
  975         javax.swing.GroupLayout controlPanelLayout = 
new javax.swing.GroupLayout(controlPanel);
 
  976         controlPanel.setLayout(controlPanelLayout);
 
  977         controlPanelLayout.setHorizontalGroup(
 
  978             controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  979             .addGroup(controlPanelLayout.createSequentialGroup()
 
  981                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  982                     .addComponent(infoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  983                     .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, controlPanelLayout.createSequentialGroup()
 
  984                         .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
 
  985                             .addComponent(buttonPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  986                             .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE))
 
  987                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
  988                         .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  989                             .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
  990                             .addComponent(playBackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
 
  991                         .addGap(10, 10, 10)))
 
  994         controlPanelLayout.setVerticalGroup(
 
  995             controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
  996             .addGroup(controlPanelLayout.createSequentialGroup()
 
  998                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
  999                     .addComponent(progressLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1000                     .addComponent(progressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
 1002                 .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
 
 1003                     .addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1004                     .addComponent(playBackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
 
 1006                 .addComponent(infoLabel))
 
 1009         javax.swing.GroupLayout layout = 
new javax.swing.GroupLayout(
this);
 
 1010         this.setLayout(layout);
 
 1011         layout.setHorizontalGroup(
 
 1012             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1013             .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1014             .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1016         layout.setVerticalGroup(
 
 1017             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
 
 1018             .addGroup(layout.createSequentialGroup()
 
 1019                 .addComponent(videoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
 
 1020                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
 
 1021                 .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
 
 1026         Gst.getExecutor().submit(() -> {
 
 1027             if (gstPlayBin != null) {
 
 1028                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1030                 long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
 
 1032                 long newTime = Math.max(currentTime - rewindDelta, 0);
 
 1033                 double playBackRate = getPlayBackRate();
 
 1034                 gstPlayBin.seek(playBackRate,
 
 1038                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1040                         SeekType.SET, newTime,
 
 1048         Gst.getExecutor().submit(() -> {
 
 1049             if (gstPlayBin != null) {
 
 1050                 long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
 
 1051                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1053                 long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
 
 1056                 long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
 
 1057                 if ((duration - currentTime) <= twoSecondsInNano) {
 
 1062                 if (currentTime + fastForwardDelta >= duration) {
 
 1064                     newTime = currentTime + (duration - currentTime) / 2;
 
 1066                     newTime = currentTime + fastForwardDelta;
 
 1069                 double playBackRate = getPlayBackRate();
 
 1070                 gstPlayBin.seek(playBackRate,
 
 1074                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1076                         SeekType.SET, newTime,
 
 1084         Gst.getExecutor().submit(() -> {
 
 1085             if (gstPlayBin != null) {
 
 1086                 if (gstPlayBin.isPlaying()) {
 
 1089                     double playBackRate = getPlayBackRate();
 
 1090                     long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1092                     gstPlayBin.seek(playBackRate,
 
 1096                             EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1098                             SeekType.SET, currentTime,
 
 1108         Gst.getExecutor().submit(() -> {
 
 1109             if (gstPlayBin != null) {
 
 1110                 double playBackRate = getPlayBackRate();
 
 1111                 long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
 
 1112                 gstPlayBin.seek(playBackRate,
 
 1116                         EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
 
 1119                         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
 
String getNameExtension()
 
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)
 
MimeMatchEnum isMimeType(SortedSet< String > mimeTypes)
 
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