Merge pull request #5721 from dannysmyda/6069-gstreamer-crash-with-review-fixes

6069 gstreamer crash with review fixes
This commit is contained in:
Richard Cordovano 2020-03-20 16:32:01 -04:00 committed by GitHub
commit 496939e684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 259 additions and 173 deletions

View File

@ -45,7 +45,6 @@ file.reference.jericho-html-3.3.jar=release/modules/ext/jericho-html-3.3.jar
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar
file.reference.jhighlight-1.0.3.jar=release\\modules\\ext\\jhighlight-1.0.3.jar
file.reference.jmatio-1.5.jar=release\\modules\\ext\\jmatio-1.5.jar
file.reference.jna-5.1.0.jar=release\\modules\\ext\\jna-5.1.0.jar
file.reference.json-simple-1.1.1.jar=release\\modules\\ext\\json-simple-1.1.1.jar
file.reference.jsoup-1.11.3.jar=release\\modules\\ext\\jsoup-1.11.3.jar
file.reference.jul-to-slf4j-1.7.25.jar=release\\modules\\ext\\jul-to-slf4j-1.7.25.jar
@ -97,7 +96,6 @@ file.reference.xz-1.8.jar=release\\modules\\ext\\xz-1.8.jar
file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
file.reference.SparseBitSet-1.1.jar=release/modules/ext/SparseBitSet-1.1.jar
file.reference.commons-validator-1.6.jar=release/modules/ext/commons-validator-1.6.jar
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
file.reference.api-common-1.7.0.jar=release/modules/ext/api-common-1.7.0.jar
file.reference.gax-1.44.0.jar=release/modules/ext/gax-1.44.0.jar
file.reference.gax-grpc-1.44.0.jar=release/modules/ext/gax-grpc-1.44.0.jar

View File

@ -615,10 +615,6 @@
<runtime-relative-path>ext/commons-validator-1.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-validator-1.6.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jna-5.1.0.jar</runtime-relative-path>
<binary-origin>release\modules\ext\jna-5.1.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jbig2-imageio-3.0.2.jar</runtime-relative-path>
<binary-origin>release\modules\ext\jbig2-imageio-3.0.2.jar</binary-origin>

View File

@ -41,6 +41,7 @@ MediaFileViewer.AccessibleContext.accessibleDescription=
MediaFileViewer.title=Media
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
MediaPlayerPanel.noSupport=File not supported.
MediaPlayerPanel.playbackDisabled=A problem was encountered with the video and audio playback service. Video and audio playback will be disabled for the remainder of the session.
MediaPlayerPanel.timeFormat=%02d:%02d:%02d
MediaPlayerPanel.unknownTime=Unknown
MediaViewImagePanel.createTagOption=Create
@ -168,7 +169,7 @@ MediaPlayerPanel.playBackSpeedLabel.text=Speed:
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
# {0} - tableName
SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}
TextTranslatableComponent.setPanelContent.onSetContentError=Unable to display text at this time.
TextTranslatableComponent.setTranslated.onTranslateError=Unable to translate text at this time.
TranslatablePanel.comboBoxOption.originalText=Original Text
TranslatablePanel.comboBoxOption.translatedText=Translated Text
# {0} - exception message
TranslatablePanel.onSetContentError.text=There was an error displaying the text: {0}

View File

@ -194,6 +194,6 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override
public boolean isSupported(AbstractFile file){
return true;
return mediaPlayerPanel.isSupported(file) || imagePanel.isSupported(file);
}
}

View File

@ -63,7 +63,7 @@
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="progressLabel" max="32767" attributes="0"/>
<Component id="playBackPanel" pref="0" max="32767" attributes="0"/>
<Component id="playBackPanel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
</Group>
@ -129,12 +129,6 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.playButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 29]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 29]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[49, 29]"/>
</Property>

View File

@ -74,7 +74,9 @@ import org.freedesktop.gstreamer.Format;
import org.freedesktop.gstreamer.GstException;
import org.freedesktop.gstreamer.event.SeekFlags;
import org.freedesktop.gstreamer.event.SeekType;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.contentviewers.utils.GstLoader;
import org.sleuthkit.autopsy.contentviewers.utils.GstLoader.GstStatus;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/**
* This is a video player that is part of the Media View layered pane. It uses
@ -213,6 +215,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
//and the TrackListener on the slider itself.
private final Semaphore sliderLock;
private static volatile boolean IS_GST_ENABLED = true;
/**
* Creates a new MediaPlayerPanel
*/
@ -222,18 +226,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
//True for fairness. In other words,
//acquire() calls are processed in order of invocation.
sliderLock = new Semaphore(1, true);
/**
* See JIRA-5888 for details. Initializing gstreamer here is more stable
* on Windows.
*/
if (PlatformUtil.isWindowsOS()) {
Gst.init();
}
}
private void customizeComponents() {
progressSlider.setEnabled(false); // disable slider; enable after user plays vid
enableComponents(false);
progressSlider.setMinimum(0);
progressSlider.setMaximum(PROGRESS_SLIDER_SIZE);
progressSlider.setValue(0);
@ -390,13 +386,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
}
timer.stop();
if (gstPlayBin != null) {
gstPlayBin.stop();
gstPlayBin.getBus().disconnect(endOfStreamListener);
gstPlayBin.getBus().disconnect(stateChangeListener);
gstPlayBin.getBus().disconnect(errorListener);
gstPlayBin.dispose();
fxAppSink.clear();
gstPlayBin = null;
Gst.getExecutor().submit(() -> {
gstPlayBin.stop();
gstPlayBin.getBus().disconnect(endOfStreamListener);
gstPlayBin.getBus().disconnect(stateChangeListener);
gstPlayBin.getBus().disconnect(errorListener);
gstPlayBin.getBus().dispose();
gstPlayBin.dispose();
fxAppSink.clear();
gstPlayBin = null;
});
}
videoPanel.removeAll();
resetComponents();
@ -425,6 +424,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
@Override
public boolean isSupported(AbstractFile file) {
if (!IS_GST_ENABLED) {
return false;
}
String extension = file.getNameExtension();
/**
* Although it seems too restrictive, requiring both a supported
@ -542,6 +545,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
/*
* Initialize the playback components if the extraction was successful.
*/
@NbBundle.Messages({
"MediaPlayerPanel.playbackDisabled=A problem was encountered with"
+ " the video and audio playback service. Video and audio "
+ "playback will be disabled for the remainder of the session."
})
@Override
protected void done() {
try {
@ -551,44 +559,49 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
return;
}
// Initialize Gstreamer. It is safe to call this for every file.
// It was moved here from the constructor because having it happen
// earlier resulted in conflicts on Linux. See JIRA-5888.
if (!PlatformUtil.isWindowsOS()) {
Gst.init();
GstStatus loadStatus = GstLoader.tryLoad();
if (loadStatus == GstStatus.FAILURE) {
MessageNotifyUtil.Message.error(Bundle.MediaPlayerPanel_playbackDisabled());
// This will disable the panel for future use.
IS_GST_ENABLED = false;
return;
}
//Video is ready for playback. Create new components
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
//Configure event handling
if (gstPlayBin != null) {
Gst.getExecutor().submit(() -> {
//Video is ready for playback. Create new components
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
//Configure event handling
Bus playBinBus = gstPlayBin.getBus();
playBinBus.connect(endOfStreamListener);
playBinBus.connect(stateChangeListener);
playBinBus.connect(errorListener);
}
if (this.isCancelled()) {
return;
}
if (this.isCancelled()) {
return;
}
JFXPanel fxPanel = new JFXPanel();
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(fxPanel);
fxAppSink = new JavaFxAppSink("JavaFxAppSink", fxPanel);
if (gstPlayBin != null) {
gstPlayBin.setVideoSink(fxAppSink);
}
if (this.isCancelled()) {
return;
}
if (gstPlayBin != null) {
gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
gstPlayBin.pause();
}
timer.start();
enableComponents(true);
JFXPanel fxPanel = new JFXPanel();
videoPanel.removeAll();
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
videoPanel.add(fxPanel);
fxAppSink = new JavaFxAppSink("JavaFxAppSink", fxPanel);
if (gstPlayBin != null) {
gstPlayBin.setVideoSink(fxAppSink);
}
if (this.isCancelled()) {
return;
}
if (gstPlayBin != null) {
gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
gstPlayBin.pause();
}
timer.start();
SwingUtilities.invokeLater(() -> {
enableComponents(true);
});
});
} catch (CancellationException ex) {
logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS
} catch (InterruptedException ex) {
@ -607,23 +620,29 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
@Override
public void actionPerformed(ActionEvent e) {
if (!progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
sliderLock.acquireUninterruptibly();
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
/**
* Duration may not be known until there is video data in the
* pipeline. We start this updater when data-flow has just been
* initiated so buffering may still be in progress.
*/
if (duration >= 0 && position >= 0) {
double relativePosition = (double) position / duration;
progressSlider.setValue((int) (relativePosition * PROGRESS_SLIDER_SIZE));
}
Gst.getExecutor().submit(() -> {
try {
sliderLock.acquireUninterruptibly();
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
/**
* Duration may not be known until there is video data
* in the pipeline. We start this updater when data-flow
* has just been initiated so buffering may still be in
* progress.
*/
if (duration >= 0 && position >= 0) {
double relativePosition = (double) position / duration;
progressSlider.setValue((int) (relativePosition * PROGRESS_SLIDER_SIZE));
}
SwingUtilities.invokeLater(() -> {
updateTimeLabel(position, duration);
SwingUtilities.invokeLater(() -> {
updateTimeLabel(position, duration);
});
} finally {
sliderLock.release();
}
});
sliderLock.release();
}
}
}
@ -643,7 +662,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
* thumb at the given width and height. It also paints the track blue as
* the thumb progresses.
*
* @param slider JSlider component
* @param slider JSlider component
* @param thumbDimension
*/
public CircularJSliderUI(JSlider slider, Dimension thumbDimension) {
@ -991,96 +1010,104 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
}// </editor-fold>//GEN-END:initComponents
private void rewindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rewindButtonActionPerformed
if (gstPlayBin != null) {
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Skip 30 seconds.
long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
//Ensure new video position is within bounds
long newTime = Math.max(currentTime - rewindDelta, 0);
double playBackRate = getPlayBackRate();
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the start position to newTime
SeekType.SET, newTime,
//Do nothing for the end position
SeekType.NONE, -1);
}
}//GEN-LAST:event_rewindButtonActionPerformed
private void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fastForwardButtonActionPerformed
if (gstPlayBin != null) {
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Skip 30 seconds.
long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
//Don't allow skipping within 2 seconds of video ending. Skipping right to
//the end causes undefined behavior for some gstreamer plugins.
long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
if ((duration - currentTime) <= twoSecondsInNano) {
return;
}
long newTime;
if (currentTime + fastForwardDelta >= duration) {
//If there are less than 30 seconds left, only fast forward to the midpoint.
newTime = currentTime + (duration - currentTime) / 2;
} else {
newTime = currentTime + fastForwardDelta;
}
double playBackRate = getPlayBackRate();
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the start position to newTime
SeekType.SET, newTime,
//Do nothing for the end position
SeekType.NONE, -1);
}
}//GEN-LAST:event_fastForwardButtonActionPerformed
private void playButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playButtonActionPerformed
if (gstPlayBin != null) {
if (gstPlayBin.isPlaying()) {
gstPlayBin.pause();
} else {
double playBackRate = getPlayBackRate();
Gst.getExecutor().submit(() -> {
if (gstPlayBin != null) {
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Set playback rate before play.
//Skip 30 seconds.
long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
//Ensure new video position is within bounds
long newTime = Math.max(currentTime - rewindDelta, 0);
double playBackRate = getPlayBackRate();
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the start position to newTime
SeekType.SET, currentTime,
SeekType.SET, newTime,
//Do nothing for the end position
SeekType.NONE, -1);
gstPlayBin.play();
}
}
}//GEN-LAST:event_playButtonActionPerformed
});
}//GEN-LAST:event_rewindButtonActionPerformed
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playBackSpeedComboBoxActionPerformed
if (gstPlayBin != null) {
double playBackRate = getPlayBackRate();
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the position to the currentTime, we are only adjusting the
//playback rate.
SeekType.SET, currentTime,
SeekType.NONE, 0);
}
}//GEN-LAST:event_playBackSpeedComboBoxActionPerformed
private void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {
Gst.getExecutor().submit(() -> {
if (gstPlayBin != null) {
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Skip 30 seconds.
long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
//Don't allow skipping within 2 seconds of video ending. Skipping right to
//the end causes undefined behavior for some gstreamer plugins.
long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
if ((duration - currentTime) <= twoSecondsInNano) {
return;
}
long newTime;
if (currentTime + fastForwardDelta >= duration) {
//If there are less than 30 seconds left, only fast forward to the midpoint.
newTime = currentTime + (duration - currentTime) / 2;
} else {
newTime = currentTime + fastForwardDelta;
}
double playBackRate = getPlayBackRate();
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the start position to newTime
SeekType.SET, newTime,
//Do nothing for the end position
SeekType.NONE, -1);
}
});
}
private void playButtonActionPerformed(java.awt.event.ActionEvent evt) {
Gst.getExecutor().submit(() -> {
if (gstPlayBin != null) {
if (gstPlayBin.isPlaying()) {
gstPlayBin.pause();
} else {
double playBackRate = getPlayBackRate();
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Set playback rate before play.
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the start position to newTime
SeekType.SET, currentTime,
//Do nothing for the end position
SeekType.NONE, -1);
gstPlayBin.play();
}
}
});
}
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
Gst.getExecutor().submit(() -> {
if (gstPlayBin != null) {
double playBackRate = getPlayBackRate();
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
gstPlayBin.seek(playBackRate,
Format.TIME,
//FLUSH - flushes the pipeline
//ACCURATE - video will seek exactly to the position requested
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
//Set the position to the currentTime, we are only adjusting the
//playback rate.
SeekType.SET, currentTime,
SeekType.NONE, 0);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel VolumeIcon;

View File

@ -0,0 +1,74 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.contentviewers.utils;
import java.util.logging.Level;
import org.freedesktop.gstreamer.Gst;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* A utility class that loads the gstreamer bindings.
*/
public final class GstLoader {
private static final Logger logger = Logger.getLogger(GstLoader.class.getName());
private static GstStatus status;
/**
* Attempts to load the gstreamer bindings. Only one attempt will be
* performed per Autopsy process. Clients should not attempt to interact
* with the gstreamer bindings unless the load was successful.
*
* @return Status - SUCCESS or FAILURE
*/
public synchronized static GstStatus tryLoad() {
// Null is our 'unknown' status. Prior to the first call, the status
// is unknown.
if (status != null) {
return status;
}
try {
// Setting the following property causes the GST
// Java bindings to call dispose() on the GST
// service thread instead of running it in the GST
// Native Object Reaper thread.
System.setProperty("glib.reapOnEDT", "true");
Gst.init();
status = GstStatus.SUCCESS;
} catch (Throwable ex) {
status = GstStatus.FAILURE;
logger.log(Level.WARNING, "Failed to load gsteamer bindings", ex);
}
return status;
}
/**
* The various init statuses that tryLoad can return.
*/
public enum GstStatus {
SUCCESS, FAILURE
}
private GstLoader() {
}
}

View File

@ -14,8 +14,7 @@
<!-- for viewers -->
<dependency conf="autopsy_core->*" org="org.freedesktop.gstreamer" name="gst1-java-core" rev="1.0.0"/>
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="jna" rev="3.4.0"/>
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="platform" rev="3.4.0"/>
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="jna-platform" rev="5.5.0"/>
<!-- for file search -->
<dependency conf="autopsy_core->*" org="com.github.lgooddatepicker" name="LGoodDatePicker" rev="10.3.1"/>
@ -73,8 +72,5 @@
<dependency conf="autopsy_core->default" org="com.googlecode.plist" name="dd-plist" rev="1.20"/>
<exclude org="*" ext="*" type="javadoc"/>
<!-- conflict resolutions for multiple JAR versions -->
<conflict org="net.java.dev.jna" module="jna" rev="3.4.0"/>
<conflict org="net.java.dev.jna" module="platform" rev="3.4.0"/>
</dependencies>
</ivy-module>

View File

@ -21,7 +21,6 @@ file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar
file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar
file.reference.gson-2.8.5.jar=release/modules/ext/gson-2.8.5.jar
file.reference.gst1-java-core-1.0.0.jar=release\\modules\\ext\\gst1-java-core-1.0.0.jar
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
file.reference.guava-19.0.jar=release/modules/ext/guava-19.0.jar
file.reference.imageio-bmp-3.2.jar=release/modules/ext/imageio-bmp-3.2.jar
file.reference.imageio-core-3.2.jar=release/modules/ext/imageio-core-3.2.jar
@ -44,6 +43,8 @@ file.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-
file.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4.jar
file.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4.jar
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
file.reference.jna-5.5.0.jar=release\\modules\\ext\\jna-5.5.0.jar
file.reference.jna-platform-5.5.0.jar=release\\modules\\ext\\jna-platform-5.5.0.jar
file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar
file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar
file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar
@ -52,7 +53,6 @@ file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.3.jar
file.reference.platform-3.4.0.jar=release/modules/ext/platform-3.4.0.jar
file.reference.poi-4.0.1.jar=release\\modules\\ext\\poi-4.0.1.jar
file.reference.poi-excelant-4.0.1.jar=release\\modules\\ext\\poi-excelant-4.0.1.jar
file.reference.poi-ooxml-4.0.1.jar=release\\modules\\ext\\poi-ooxml-4.0.1.jar

View File

@ -806,10 +806,6 @@
<runtime-relative-path>ext/sigar-1.6.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sigar-1.6.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jna-3.4.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jna-3.4.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/gson-2.8.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/gson-2.8.5.jar</binary-origin>
@ -902,6 +898,10 @@
<runtime-relative-path>ext/commons-csv-1.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-csv-1.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jna-5.5.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jna-5.5.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/imageio-sgi-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-sgi-3.2.jar</binary-origin>
@ -946,10 +946,6 @@
<runtime-relative-path>ext/imageio-bmp-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-bmp-3.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/platform-3.4.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/platform-3.4.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-lang-2.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-lang-2.6.jar</binary-origin>
@ -1018,6 +1014,10 @@
<runtime-relative-path>ext/dom4j-1.6.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/dom4j-1.6.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jna-platform-5.5.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jna-platform-5.5.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/imageio-metadata-3.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/imageio-metadata-3.2.jar</binary-origin>