mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Using GStreamer for 64-bit.
This commit is contained in:
parent
eca1472d5b
commit
16bcfda076
@ -52,6 +52,7 @@ file.reference.sis-metadata-0.6.jar=release/modules/ext/sis-metadata-0.6.jar
|
||||
file.reference.sis-netcdf-0.6.jar=release/modules/ext/sis-netcdf-0.6.jar
|
||||
file.reference.sis-utility-0.6.jar=release/modules/ext/sis-utility-0.6.jar
|
||||
file.reference.slf4j-api-1.7.24.jar=release/modules/ext/slf4j-api-1.7.24.jar
|
||||
file.reference.sqlite-jdbc-3.25.2.jar=release/modules/ext/sqlite-jdbc-3.25.2.jar
|
||||
file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar
|
||||
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
|
||||
file.reference.jempbox-1.8.13.jar=release/modules/ext/jempbox-1.8.13.jar
|
||||
@ -77,6 +78,7 @@ file.reference.xz-1.6.jar=release/modules/ext/xz-1.6.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
|
||||
javac.source=1.8
|
||||
javac.compilerargs=-Xlint -Xlint:-serial
|
||||
license.file=../LICENSE-2.0.txt
|
||||
|
@ -415,6 +415,10 @@
|
||||
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jackson-core-2.9.7.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jackson-core-2.9.7.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/pdfbox-tools-2.0.8.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/pdfbox-tools-2.0.8.jar</binary-origin>
|
||||
@ -431,10 +435,6 @@
|
||||
<runtime-relative-path>ext/tika-parsers-1.17.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/tika-parsers-1.17.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sqlite-jdbc-3.25.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sqlite-jdbc-3.25.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/json-simple-1.1.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/json-simple-1.1.1.jar</binary-origin>
|
||||
@ -447,6 +447,10 @@
|
||||
<runtime-relative-path>ext/jhighlight-1.0.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jhighlight-1.0.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jempbox-1.8.13.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jempbox-1.8.13.jar</binary-origin>
|
||||
@ -499,10 +503,6 @@
|
||||
<runtime-relative-path>ext/isoparser-1.1.18.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/isoparser-1.1.18.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/vorbis-java-core-0.8.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/vorbis-java-core-0.8.jar</binary-origin>
|
||||
@ -608,8 +608,8 @@
|
||||
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jackson-core-2.9.7.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jackson-core-2.9.7.jar</binary-origin>
|
||||
<runtime-relative-path>ext/sqlite-jdbc-3.25.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sqlite-jdbc-3.25.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path>
|
||||
@ -619,10 +619,6 @@
|
||||
<runtime-relative-path>ext/grib-4.5.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/grib-4.5.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jackson-core-2.9.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jackson-core-2.9.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
|
||||
|
443
Core/src/org/freedesktop/gstreamer/examples/SimpleVideoComponent.java
Executable file
443
Core/src/org/freedesktop/gstreamer/examples/SimpleVideoComponent.java
Executable file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Neil C Smith
|
||||
* Copyright (c) 2007 Wayne Meissner
|
||||
*
|
||||
* This file is part of gstreamer-java.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License version 3 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* version 3 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.freedesktop.gstreamer.examples;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import org.freedesktop.gstreamer.Element;
|
||||
import org.freedesktop.gstreamer.Structure;
|
||||
import org.freedesktop.gstreamer.elements.AppSink;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import org.freedesktop.gstreamer.Buffer;
|
||||
import org.freedesktop.gstreamer.Caps;
|
||||
import org.freedesktop.gstreamer.FlowReturn;
|
||||
import org.freedesktop.gstreamer.Sample;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
//DLG: Made public
|
||||
public class SimpleVideoComponent extends javax.swing.JComponent {
|
||||
|
||||
private BufferedImage currentImage = null;
|
||||
private final Lock bufferLock = new ReentrantLock();
|
||||
private final AppSink videosink;
|
||||
// private Pad videoPad;
|
||||
private RenderComponent renderComponent = new RenderComponent();
|
||||
private boolean keepAspect = true;
|
||||
private Timer resourceTimer;
|
||||
private VolatileImage volatileImage;
|
||||
private boolean frameRendered = false;
|
||||
private volatile boolean updatePending = false;
|
||||
private final boolean useVolatile;
|
||||
|
||||
/**
|
||||
* Creates a new instance of GstVideoComponent
|
||||
*/
|
||||
public SimpleVideoComponent() {
|
||||
this(new AppSink("GstVideoComponent"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of GstVideoComponent
|
||||
*/
|
||||
public SimpleVideoComponent(AppSink appsink) {
|
||||
this.videosink = appsink;
|
||||
videosink.set("emit-signals", true);
|
||||
AppSinkListener listener = new AppSinkListener();
|
||||
videosink.connect((AppSink.NEW_SAMPLE) listener);
|
||||
videosink.connect((AppSink.NEW_PREROLL) listener);
|
||||
StringBuilder caps = new StringBuilder("video/x-raw,pixel-aspect-ratio=1/1,");
|
||||
// JNA creates ByteBuffer using native byte order, set masks according to that.
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
|
||||
caps.append("format=BGRx");
|
||||
} else {
|
||||
caps.append("format=xRGB");
|
||||
}
|
||||
videosink.setCaps(new Caps(caps.toString()));
|
||||
|
||||
useVolatile = true;
|
||||
|
||||
// Kick off a timer to free up the volatile image if there have been no recent updates
|
||||
// (e.g. the player is paused)
|
||||
//
|
||||
resourceTimer = new Timer(250, resourceReaper);
|
||||
|
||||
//
|
||||
// Don't use a layout manager - the output component will positioned within this
|
||||
// component according to the aspect ratio and scaling mode
|
||||
//
|
||||
setLayout(null);
|
||||
add(renderComponent);
|
||||
|
||||
//
|
||||
// Listen for the child changing its preferred size to the size of the
|
||||
// video stream.
|
||||
//
|
||||
renderComponent.addPropertyChangeListener("preferredSize", new PropertyChangeListener() {
|
||||
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
setPreferredSize(renderComponent.getPreferredSize());
|
||||
scaleVideoOutput();
|
||||
}
|
||||
});
|
||||
//
|
||||
// Scale the video output in response to this component being resized
|
||||
//
|
||||
addComponentListener(new ComponentAdapter() {
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent arg0) {
|
||||
scaleVideoOutput();
|
||||
}
|
||||
|
||||
});
|
||||
renderComponent.setBounds(getBounds());
|
||||
setOpaque(true);
|
||||
setBackground(Color.BLACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales the video output component according to its aspect ratio
|
||||
*/
|
||||
private void scaleVideoOutput() {
|
||||
final Component child = renderComponent;
|
||||
final Dimension childSize = child.getPreferredSize();
|
||||
final int width = getWidth(), height = getHeight();
|
||||
// Figure out the aspect ratio
|
||||
double aspect = keepAspect ? (double) childSize.width / (double) childSize.height : 1.0f;
|
||||
|
||||
//
|
||||
// Now scale and position the videoChild component to be in the correct position
|
||||
// to keep the aspect ratio correct.
|
||||
//
|
||||
int scaledHeight = (int) ((double) width / aspect);
|
||||
if (!keepAspect) {
|
||||
//
|
||||
// Just make the child match the parent
|
||||
//
|
||||
child.setBounds(0, 0, width, height);
|
||||
} else if (scaledHeight < height) {
|
||||
//
|
||||
// Output window is taller than the image is when scaled, so move the
|
||||
// video component to sit vertically in the centre of the VideoComponent.
|
||||
//
|
||||
final int y = (height - scaledHeight) / 2;
|
||||
child.setBounds(0, y, width, scaledHeight);
|
||||
} else {
|
||||
final int scaledWidth = (int) ((double) height * aspect);
|
||||
final int x = (width - scaledWidth) / 2;
|
||||
child.setBounds(x, 0, scaledWidth, height);
|
||||
}
|
||||
}
|
||||
private ActionListener resourceReaper = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
if (!frameRendered) {
|
||||
if (volatileImage != null) {
|
||||
volatileImage.flush();
|
||||
volatileImage = null;
|
||||
}
|
||||
|
||||
// Stop the timer so we don't wakeup needlessly
|
||||
resourceTimer.stop();
|
||||
}
|
||||
frameRendered = false;
|
||||
}
|
||||
};
|
||||
|
||||
public Element getElement() {
|
||||
return videosink;
|
||||
}
|
||||
|
||||
public void setKeepAspect(boolean keepAspect) {
|
||||
this.keepAspect = keepAspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLightweight() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
if (isOpaque()) {
|
||||
Graphics2D g2d = (Graphics2D) g.create();
|
||||
g2d.setColor(getBackground());
|
||||
g2d.fillRect(0, 0, getWidth(), getHeight());
|
||||
g2d.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private class RenderComponent extends javax.swing.JComponent {
|
||||
|
||||
private static final long serialVersionUID = -4736605073704494268L;
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
int width = getWidth(), height = getHeight();
|
||||
Graphics2D g2d = (Graphics2D) g.create();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
if (currentImage != null) {
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
render(g2d, 0, 0, width, height);
|
||||
} else {
|
||||
g2d.setColor(getBackground());
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
}
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return SimpleVideoComponent.this.isOpaque();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLightweight() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderVolatileImage(BufferedImage bufferedImage) {
|
||||
do {
|
||||
int w = bufferedImage.getWidth(), h = bufferedImage.getHeight();
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
if (volatileImage == null || volatileImage.getWidth() != w
|
||||
|| volatileImage.getHeight() != h
|
||||
|| volatileImage.validate(gc) == VolatileImage.IMAGE_INCOMPATIBLE) {
|
||||
if (volatileImage != null) {
|
||||
volatileImage.flush();
|
||||
}
|
||||
volatileImage = gc.createCompatibleVolatileImage(w, h);
|
||||
volatileImage.setAccelerationPriority(1.0f);
|
||||
}
|
||||
//
|
||||
// Now paint the BufferedImage into the accelerated image
|
||||
//
|
||||
Graphics2D g = volatileImage.createGraphics();
|
||||
g.drawImage(bufferedImage, 0, 0, null);
|
||||
g.dispose();
|
||||
} while (volatileImage.contentsLost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders to a volatile image, and then paints that to the screen. This
|
||||
* helps with scaling performance on accelerated surfaces (e.g. OpenGL)
|
||||
*
|
||||
* @param g the graphics to paint the image to
|
||||
* @param x the left coordinate to start painting at.
|
||||
* @param y the top coordinate to start painting at.
|
||||
* @param w the width of the paint area
|
||||
* @param h the height of the paint area
|
||||
*/
|
||||
private void volatileRender(Graphics g, int x, int y, int w, int h) {
|
||||
do {
|
||||
if (updatePending || volatileImage == null
|
||||
|| volatileImage.validate(getGraphicsConfiguration()) != VolatileImage.IMAGE_OK) {
|
||||
bufferLock.lock();
|
||||
try {
|
||||
updatePending = false;
|
||||
renderVolatileImage(currentImage);
|
||||
} finally {
|
||||
bufferLock.unlock();
|
||||
}
|
||||
}
|
||||
g.drawImage(volatileImage, x, y, w, h, null);
|
||||
} while (volatileImage.contentsLost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders directly to the given <tt>Graphics</tt>. This is only really
|
||||
* useful on MacOS where swing graphics are unaccelerated so using a
|
||||
* volatile just incurs an extra memcpy().
|
||||
*
|
||||
* @param g the graphics to paint the image to
|
||||
* @param x the left coordinate to start painting at.
|
||||
* @param y the top coordinate to start painting at.
|
||||
* @param w the width of the paint area
|
||||
* @param h the height of the paint area
|
||||
*/
|
||||
private void heapRender(Graphics g, int x, int y, int w, int h) {
|
||||
bufferLock.lock();
|
||||
try {
|
||||
updatePending = false;
|
||||
g.drawImage(currentImage, x, y, w, h, null);
|
||||
} finally {
|
||||
bufferLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the current frame to the given <tt>Graphics</tt>.
|
||||
*
|
||||
* @param g the graphics to paint the image to
|
||||
* @param x the left coordinate to start painting at.
|
||||
* @param y the top coordinate to start painting at.
|
||||
* @param w the width of the paint area
|
||||
* @param h the height of the paint area
|
||||
*/
|
||||
private void render(Graphics g, int x, int y, int w, int h) {
|
||||
if (useVolatile) {
|
||||
volatileRender(g, x, y, w, h);
|
||||
} else {
|
||||
heapRender(g, x, y, w, h);
|
||||
}
|
||||
//
|
||||
// Restart the resource reaper timer if neccessary
|
||||
//
|
||||
if (!frameRendered) {
|
||||
frameRendered = true;
|
||||
if (!resourceTimer.isRunning()) {
|
||||
resourceTimer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int imgWidth = 0, imgHeight = 0;
|
||||
|
||||
private final void update(final int width, final int height) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
//
|
||||
// If the image changed size, resize the component to fit
|
||||
//
|
||||
if (width != imgWidth || height != imgHeight) {
|
||||
renderComponent.setPreferredSize(new Dimension(width, height));
|
||||
imgWidth = width;
|
||||
imgHeight = height;
|
||||
}
|
||||
|
||||
if (renderComponent.isVisible()) {
|
||||
renderComponent.paintImmediately(0, 0,
|
||||
renderComponent.getWidth(), renderComponent.getHeight());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private BufferedImage getBufferedImage(int width, int height) {
|
||||
if (currentImage != null && currentImage.getWidth() == width
|
||||
&& currentImage.getHeight() == height) {
|
||||
return currentImage;
|
||||
}
|
||||
if (currentImage != null) {
|
||||
currentImage.flush();
|
||||
}
|
||||
currentImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
currentImage.setAccelerationPriority(0.0f);
|
||||
return currentImage;
|
||||
}
|
||||
|
||||
private class AppSinkListener implements AppSink.NEW_SAMPLE, AppSink.NEW_PREROLL {
|
||||
|
||||
public void rgbFrame(boolean isPrerollFrame, int width, int height, IntBuffer rgb) {
|
||||
// If the EDT is still copying data from the buffer, just drop this frame
|
||||
//
|
||||
if (!bufferLock.tryLock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// If there is already a swing update pending, also drop this frame.
|
||||
//
|
||||
if (updatePending && !isPrerollFrame) {
|
||||
bufferLock.unlock();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final BufferedImage renderImage = getBufferedImage(width, height);
|
||||
int[] pixels = ((DataBufferInt) renderImage.getRaster().getDataBuffer()).getData();
|
||||
rgb.get(pixels, 0, width * height);
|
||||
updatePending = true;
|
||||
} finally {
|
||||
bufferLock.unlock();
|
||||
}
|
||||
|
||||
// int scaledWidth = currentImage.getWidth();
|
||||
// if (keepAspect) {
|
||||
// // Scale width according to pixel aspect ratio.
|
||||
// Caps videoCaps = videoPad.getNegotiatedCaps();
|
||||
// Structure capsStruct = videoCaps.getStructure(0);
|
||||
// if (capsStruct.hasField("pixel-aspect-ratio")) {
|
||||
// Fraction pixelAspectRatio = capsStruct.getFraction("pixel-aspect-ratio");
|
||||
// scaledWidth = scaledWidth * pixelAspectRatio.getNumerator() / pixelAspectRatio.getDenominator();
|
||||
// }
|
||||
// }
|
||||
// Tell swing to use the new buffer
|
||||
update(currentImage.getWidth(), currentImage.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowReturn newSample(AppSink elem) {
|
||||
Sample sample = elem.pullSample();
|
||||
Structure capsStruct = sample.getCaps().getStructure(0);
|
||||
int w = capsStruct.getInteger("width");
|
||||
int h = capsStruct.getInteger("height");
|
||||
Buffer buffer = sample.getBuffer();
|
||||
ByteBuffer bb = buffer.map(false);
|
||||
if (bb != null) {
|
||||
rgbFrame(false, w, h, bb.asIntBuffer());
|
||||
buffer.unmap();
|
||||
}
|
||||
sample.dispose();
|
||||
return FlowReturn.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowReturn newPreroll(AppSink elem) {
|
||||
Sample sample = elem.pullPreroll();
|
||||
Structure capsStruct = sample.getCaps().getStructure(0);
|
||||
int w = capsStruct.getInteger("width");
|
||||
int h = capsStruct.getInteger("height");
|
||||
Buffer buffer = sample.getBuffer();
|
||||
ByteBuffer bb = buffer.map(false);
|
||||
if (bb != null) {
|
||||
rgbFrame(false, w, h, bb.asIntBuffer());
|
||||
buffer.unmap();
|
||||
}
|
||||
sample.dispose();
|
||||
return FlowReturn.OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
@ -66,6 +68,7 @@ import org.sleuthkit.autopsy.corecomponents.VideoFrame;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.VideoUtils;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -73,11 +76,8 @@ import org.sleuthkit.datamodel.TskData;
|
||||
/**
|
||||
* Video viewer part of the Media View layered pane.
|
||||
*/
|
||||
@ServiceProviders(value = {
|
||||
@ServiceProvider(service = FrameCapture.class)
|
||||
})
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
public class FXVideoPanel extends JPanel implements MediaFileViewer.MediaViewPanel {
|
||||
|
||||
// Refer to https://docs.oracle.com/javafx/2/api/javafx/scene/media/package-summary.html
|
||||
// for Javafx supported formats
|
||||
@ -109,8 +109,7 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setupVideo(final AbstractFile file, final Dimension dims) {
|
||||
void loadFile(final AbstractFile file, final Dimension dims) {
|
||||
if (file.equals(currentFile)) {
|
||||
return;
|
||||
}
|
||||
@ -150,7 +149,6 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void reset() {
|
||||
Platform.runLater(() -> {
|
||||
if (mediaPane != null) {
|
||||
@ -199,7 +197,6 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
private javafx.embed.swing.JFXPanel jFXPanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public boolean isInited() {
|
||||
return fxInited;
|
||||
}
|
||||
@ -641,29 +638,49 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file a video file from which to capture frames
|
||||
* @param numFrames the number of frames to capture. These frames will be
|
||||
* captured at successive intervals given by
|
||||
* durationOfVideo/numFrames. If this frame interval is
|
||||
* less than MIN_FRAME_INTERVAL_MILLIS, then only one frame
|
||||
* will be captured and returned.
|
||||
*
|
||||
* @return a List of VideoFrames representing the captured frames.
|
||||
*/
|
||||
@Override
|
||||
public List<VideoFrame> captureFrames(java.io.File file, int numFrames) throws Exception {
|
||||
//What is/was the point of this method /interface.
|
||||
return null;
|
||||
public List<String> getSupportedExtensions() {
|
||||
return Arrays.asList(EXTENSIONS.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExtensions() {
|
||||
return EXTENSIONS.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMimeTypes() {
|
||||
public List<String> getSupportedMimeTypes() {
|
||||
return MIMETYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file) {
|
||||
String extension = file.getNameExtension();
|
||||
/**
|
||||
* Although it seems too restrictive, requiring both a supported
|
||||
* extension and a supported MIME type prevents two undesirable
|
||||
* behaviors:
|
||||
*
|
||||
* 1) Until AUT-1766 and AUT-1801 are fixed, we incorrectly identify all
|
||||
* iff files as audio/aiff. This means that if this panel went with the
|
||||
* looser 'mime type OR extension' criteria we use for images, then this
|
||||
* panel would attempt (and fail) to display all iff files, even non
|
||||
* audio ones.
|
||||
*
|
||||
* 2) The looser criteria means we are less confident about the files we
|
||||
* are potentialy sending to GStreamer on 32bit jvms. We are less
|
||||
* comfortable with the error handling for GStreamer, and don't want to
|
||||
* send it files which might cause it trouble.
|
||||
*/
|
||||
if (getSupportedExtensions().contains("." + extension)) {
|
||||
SortedSet<String> mimeTypes = new TreeSet<>(getSupportedMimeTypes());
|
||||
try {
|
||||
String mimeType = new FileTypeDetector().getMIMEType(file);
|
||||
return mimeTypes.contains(mimeType);
|
||||
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
|
||||
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
||||
if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return getSupportedExtensions().contains("." + extension);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
156
Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoRendererPanel.java
Executable file
156
Core/src/org/sleuthkit/autopsy/contentviewers/GstVideoRendererPanel.java
Executable file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 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;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.PixelFormat;
|
||||
import javafx.scene.image.PixelWriter;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import org.freedesktop.gstreamer.Buffer;
|
||||
import org.freedesktop.gstreamer.Caps;
|
||||
import org.freedesktop.gstreamer.FlowReturn;
|
||||
import org.freedesktop.gstreamer.Sample;
|
||||
import org.freedesktop.gstreamer.Structure;
|
||||
import org.freedesktop.gstreamer.elements.AppSink;
|
||||
|
||||
/**
|
||||
* This is a video renderer for GStreamer.
|
||||
*/
|
||||
class GstVideoRendererPanel extends JFXPanel {
|
||||
|
||||
private static final String CAP_MIME_TYPE = "video/x-raw";
|
||||
private static final String CAP_BYTE_ORDER = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? "format=BGRx" : "format=xRGB");
|
||||
private static final int PROP_MAX_BUFFERS = 5000;
|
||||
private AppSink videoSink;
|
||||
private ImageView fxImageView;
|
||||
private BorderPane borderpane;
|
||||
|
||||
/**
|
||||
* Create an instance.
|
||||
*/
|
||||
GstVideoRendererPanel() {
|
||||
initImageView();
|
||||
initVideoSink();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ImageView to show the current frame.
|
||||
*/
|
||||
private void initImageView() {
|
||||
fxImageView = new ImageView(); // Will hold the current video frame.
|
||||
borderpane = new BorderPane(fxImageView); // Center and size ImageView.
|
||||
Scene scene = new Scene(borderpane); // Root of the JavaFX tree.
|
||||
setScene(scene);
|
||||
|
||||
// Bind size of image to that of scene, while keeping proportions
|
||||
fxImageView.fitWidthProperty().bind(scene.widthProperty());
|
||||
fxImageView.fitHeightProperty().bind(scene.heightProperty());
|
||||
fxImageView.setPreserveRatio(true);
|
||||
fxImageView.setSmooth(true);
|
||||
fxImageView.setCache(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the video sink.
|
||||
*/
|
||||
private void initVideoSink() {
|
||||
videoSink = new AppSink("GstVideoComponent");
|
||||
videoSink.set("emit-signals", true);
|
||||
AppSinkListener gstListener = new AppSinkListener();
|
||||
videoSink.connect(gstListener);
|
||||
videoSink.setCaps(new Caps(
|
||||
String.format("%s, %s", CAP_MIME_TYPE, CAP_BYTE_ORDER)));
|
||||
videoSink.set("max-buffers", PROP_MAX_BUFFERS);
|
||||
videoSink.set("drop", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the video sink.
|
||||
*
|
||||
* @return The video sink.
|
||||
*/
|
||||
AppSink getVideoSink() {
|
||||
return videoSink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for NEW_SAMPLE events to update the ImageView with the newest
|
||||
* video frame.
|
||||
*/
|
||||
class AppSinkListener implements AppSink.NEW_SAMPLE {
|
||||
|
||||
private Image videoFrame;
|
||||
private int lastWidth = 0;
|
||||
private int lastHeight = 0;
|
||||
private byte[] byteArray;
|
||||
|
||||
@Override
|
||||
public FlowReturn newSample(AppSink appSink) {
|
||||
Sample sample = appSink.pullSample();
|
||||
Buffer buffer = sample.getBuffer();
|
||||
ByteBuffer byteBuffer = buffer.map(false);
|
||||
if (byteBuffer != null) {
|
||||
Structure capsStruct = sample.getCaps().getStructure(0);
|
||||
int width = capsStruct.getInteger("width");
|
||||
int height = capsStruct.getInteger("height");
|
||||
if (width != lastWidth || height != lastHeight) {
|
||||
lastWidth = width;
|
||||
lastHeight = height;
|
||||
byteArray = new byte[width * height * 4];
|
||||
}
|
||||
byteBuffer.get(byteArray);
|
||||
videoFrame = convertBytesToImage(byteArray, width, height);
|
||||
Platform.runLater(() -> {
|
||||
fxImageView.setImage(videoFrame);
|
||||
});
|
||||
buffer.unmap();
|
||||
}
|
||||
sample.dispose();
|
||||
|
||||
return FlowReturn.OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an image from a byte array of pixels.
|
||||
*
|
||||
* @param pixels The byte array of pixels.
|
||||
* @param width The width of the image.
|
||||
* @param height The height of the image.
|
||||
*
|
||||
* @return The image.
|
||||
*/
|
||||
private Image convertBytesToImage(byte[] pixels, int width, int height) {
|
||||
WritableImage img = new WritableImage(width, height);
|
||||
PixelWriter pw = img.getPixelWriter();
|
||||
pw.setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), pixels, 0, width * 4);
|
||||
return img;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,24 +36,24 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
|
||||
private AbstractFile lastFile;
|
||||
//UI
|
||||
private final MediaViewVideoPanel videoPanel;
|
||||
private final boolean videoPanelInited;
|
||||
private final MediaPlayerPanel mediaPlayerPanel;
|
||||
private final boolean mediaPlayerPanelInited;
|
||||
private final MediaViewImagePanel imagePanel;
|
||||
private final boolean imagePanelInited;
|
||||
|
||||
private static final String IMAGE_VIEWER_LAYER = "IMAGE"; //NON-NLS
|
||||
private static final String VIDEO_VIEWER_LAYER = "VIDEO"; //NON-NLS
|
||||
private static final String MEDIA_PLAYER_LAYER = "AUDIO_VIDEO"; //NON-NLS
|
||||
|
||||
/**
|
||||
* Creates new form DataContentViewerVideo
|
||||
* Creates a new MediaFileViewer.
|
||||
*/
|
||||
public MediaFileViewer() {
|
||||
|
||||
initComponents();
|
||||
|
||||
// get the right panel for our platform
|
||||
videoPanel = MediaViewVideoPanel.createVideoPanel();
|
||||
videoPanelInited = videoPanel.isInited();
|
||||
mediaPlayerPanel = new MediaPlayerPanel();
|
||||
mediaPlayerPanelInited = mediaPlayerPanel.isInited();
|
||||
|
||||
imagePanel = new MediaViewImagePanel();
|
||||
imagePanelInited = imagePanel.isInited();
|
||||
@ -64,9 +64,9 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
private void customizeComponents() {
|
||||
add(imagePanel, IMAGE_VIEWER_LAYER);
|
||||
add(videoPanel, VIDEO_VIEWER_LAYER);
|
||||
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
|
||||
|
||||
showVideoPanel(false);
|
||||
showImagePanel();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,8 +94,8 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
List<String> mimeTypes = new ArrayList<>();
|
||||
|
||||
mimeTypes.addAll(this.imagePanel.getMimeTypes());
|
||||
mimeTypes.addAll(this.videoPanel.getMimeTypes());
|
||||
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
|
||||
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
|
||||
|
||||
return mimeTypes;
|
||||
}
|
||||
@ -123,12 +123,12 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
final Dimension dims = MediaFileViewer.this.getSize();
|
||||
//logger.info("setting node on media viewer"); //NON-NLS
|
||||
if (videoPanelInited && videoPanel.isSupported(file)) {
|
||||
videoPanel.setupVideo(file, dims);
|
||||
this.showVideoPanel(true);
|
||||
if (mediaPlayerPanelInited && mediaPlayerPanel.isSupported(file)) {
|
||||
mediaPlayerPanel.loadFile(file, dims);
|
||||
this.showVideoPanel();
|
||||
} else if (imagePanelInited && imagePanel.isSupported(file)) {
|
||||
imagePanel.showImageFx(file, dims);
|
||||
this.showVideoPanel(false);
|
||||
this.showImagePanel();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception while setting node", e); //NON-NLS
|
||||
@ -136,17 +136,19 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
}
|
||||
|
||||
/**
|
||||
* switch to visible video or image panel
|
||||
*
|
||||
* @param showVideo true if video panel, false if image panel
|
||||
* Show the media player panel.
|
||||
*/
|
||||
private void showVideoPanel(boolean showVideo) {
|
||||
private void showVideoPanel() {
|
||||
CardLayout layout = (CardLayout) this.getLayout();
|
||||
if (showVideo) {
|
||||
layout.show(this, VIDEO_VIEWER_LAYER);
|
||||
} else {
|
||||
layout.show(this, IMAGE_VIEWER_LAYER);
|
||||
}
|
||||
layout.show(this, MEDIA_PLAYER_LAYER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the image panel.
|
||||
*/
|
||||
private void showImagePanel() {
|
||||
CardLayout layout = (CardLayout) this.getLayout();
|
||||
layout.show(this, IMAGE_VIEWER_LAYER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,24 +158,24 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
videoPanel.reset();
|
||||
mediaPlayerPanel.reset();
|
||||
imagePanel.reset();
|
||||
lastFile = null;
|
||||
}
|
||||
|
||||
interface MediaViewPanel {
|
||||
protected interface MediaViewPanel {
|
||||
|
||||
/**
|
||||
* @return supported mime types
|
||||
*/
|
||||
List<String> getMimeTypes();
|
||||
List<String> getSupportedMimeTypes();
|
||||
|
||||
/**
|
||||
* returns supported extensions (each starting with .)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<String> getExtensionsList();
|
||||
List<String> getSupportedExtensions();
|
||||
|
||||
boolean isSupported(AbstractFile file);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Copyright 2013-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,20 +20,19 @@ package org.sleuthkit.autopsy.contentviewers;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.EventQueue;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
@ -43,14 +42,18 @@ import javax.swing.JSlider;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import org.gstreamer.ClockTime;
|
||||
import org.gstreamer.Gst;
|
||||
import org.gstreamer.GstException;
|
||||
import org.gstreamer.State;
|
||||
import org.gstreamer.StateChangeReturn;
|
||||
import org.gstreamer.elements.PlayBin2;
|
||||
import org.gstreamer.elements.RGBDataSink;
|
||||
import org.gstreamer.swing.VideoComponent;
|
||||
import org.freedesktop.gstreamer.Bus;
|
||||
import org.freedesktop.gstreamer.ClockTime;
|
||||
import org.freedesktop.gstreamer.Format;
|
||||
import org.freedesktop.gstreamer.Gst;
|
||||
import org.freedesktop.gstreamer.GstException;
|
||||
import org.freedesktop.gstreamer.GstObject;
|
||||
import org.freedesktop.gstreamer.Message;
|
||||
import org.freedesktop.gstreamer.MessageType;
|
||||
import org.freedesktop.gstreamer.State;
|
||||
import org.freedesktop.gstreamer.StateChangeReturn;
|
||||
import org.freedesktop.gstreamer.Structure;
|
||||
import org.freedesktop.gstreamer.elements.PlayBin;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
@ -62,39 +65,133 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.VideoUtils;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ServiceProviders(value = {
|
||||
@ServiceProvider(service = FrameCapture.class)
|
||||
})
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaViewPanel {
|
||||
|
||||
private static final String[] EXTENSIONS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"}; //NON-NLS
|
||||
private static final List<String> MIMETYPES = Arrays.asList("video/quicktime", "audio/mpeg", "audio/x-mpeg", "video/mpeg", "video/x-mpeg", "audio/mpeg3", "audio/x-mpeg-3", "video/x-flv", "video/mp4", "audio/x-m4a", "video/x-m4v", "audio/x-wav"); //NON-NLS
|
||||
private static final String[] EXTENSIONS = new String[] {
|
||||
".3gp",
|
||||
".aac", //froze
|
||||
".aif",
|
||||
".aiff",
|
||||
".amr",
|
||||
".asf", //froze
|
||||
".au",
|
||||
".avi",
|
||||
".flac",
|
||||
".flv",
|
||||
".m4a",
|
||||
".m4v",
|
||||
".mka",
|
||||
".mkv",
|
||||
".mov",
|
||||
".mp2", //froze
|
||||
".mp3", //froze
|
||||
".mp4",
|
||||
".mpeg",
|
||||
".mpg",
|
||||
".mxf",
|
||||
".ogg",
|
||||
".ra", //froze
|
||||
".wav",
|
||||
".webm",
|
||||
".wma",
|
||||
".wmv",
|
||||
}; //NON-NLS
|
||||
private static final List<String> MIMETYPES = Arrays.asList(
|
||||
"video/3gpp", //tested
|
||||
"audio/aiff", //tested
|
||||
"audio/amr-wb",
|
||||
"audio/basic",
|
||||
"audio/mp4", //tested
|
||||
"video/mp4", //tested
|
||||
"audio/mpeg", //froze
|
||||
"video/mpeg", //tested
|
||||
"audio/mpeg3",
|
||||
"application/mxf", //tested
|
||||
"application/ogg",
|
||||
"video/quicktime", //tested
|
||||
"audio/vorbis", //tested
|
||||
"application/vnd.rn-realmedia",
|
||||
"audio/vnd.wave", //tested
|
||||
"video/webm", //tested
|
||||
"video/x-3ivx",
|
||||
"audio/x-aac",
|
||||
"audio/x-adpcm",
|
||||
"audio/x-alaw",
|
||||
"audio/x-cinepak",
|
||||
"video/x-divx",
|
||||
"audio/x-dv",
|
||||
"video/x-dv",
|
||||
"video/x-ffv",
|
||||
"audio/x-flac", //tested
|
||||
"video/x-flv", //tested
|
||||
"audio/x-gsm",
|
||||
"video/x-h263",
|
||||
"video/x-h264",
|
||||
"video/x-huffyuv",
|
||||
"video/x-indeo",
|
||||
"video/x-intel-h263",
|
||||
"audio/x-ircam",
|
||||
"video/x-jpeg",
|
||||
"audio/x-m4a",
|
||||
"video/x-m4v", //tested
|
||||
"audio/x-mace",
|
||||
"audio/x-matroska", //tested
|
||||
"video/x-matroska", //tested
|
||||
"audio/x-mpeg",
|
||||
"video/x-mpeg",
|
||||
"audio/x-mpeg-3",
|
||||
"video/x-ms-asf",
|
||||
"audio/x-ms-wma", //tested
|
||||
"video/x-ms-wmv", //tested
|
||||
"video/x-msmpeg",
|
||||
"video/x-msvideo", //tested
|
||||
"video/x-msvideocodec",
|
||||
"audio/x-mulaw",
|
||||
"audio/x-nist",
|
||||
"audio/x-oggflac", //tested
|
||||
"audio/x-paris",
|
||||
"audio/x-qdm2",
|
||||
"audio/x-raw",
|
||||
"video/x-raw",
|
||||
"video/x-rle",
|
||||
"audio/x-speex",
|
||||
"video/x-svq",
|
||||
"audio/x-svx",
|
||||
"video/x-tarkin",
|
||||
"video/x-theora",
|
||||
"audio/x-voc",
|
||||
"audio/x-vorbis",
|
||||
"video/x-vp3",
|
||||
"audio/x-w64",
|
||||
"audio/x-wav",
|
||||
"audio/x-wma",
|
||||
"video/x-wmv",
|
||||
"video/x-xvid"
|
||||
); //NON-NLS
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GstVideoPanel.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(MediaPlayerPanel.class.getName());
|
||||
private boolean gstInited;
|
||||
private static final long MIN_FRAME_INTERVAL_MILLIS = 500;
|
||||
private static final long FRAME_CAPTURE_TIMEOUT_MILLIS = 1000;
|
||||
private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(GstVideoPanel.class, "GstVideoPanel.cannotProcFile.err");
|
||||
private static final String MEDIA_PLAYER_ERROR_STRING = NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.cannotProcFile.err");
|
||||
//playback
|
||||
private long durationMillis = 0;
|
||||
private VideoProgressWorker videoProgressWorker;
|
||||
private int totalHours, totalMinutes, totalSeconds;
|
||||
private volatile PlayBin2 gstPlaybin2;
|
||||
private VideoComponent gstVideoComponent;
|
||||
private volatile PlayBin gstPlayBin;
|
||||
private GstVideoRendererPanel gstVideoRenderer;
|
||||
private boolean autoTracking = false; // true if the slider is moving automatically
|
||||
private final Object playbinLock = new Object(); // lock for synchronization of gstPlaybin2 player
|
||||
private final Object playbinLock = new Object(); // lock for synchronization of gstPlayBin player
|
||||
private AbstractFile currentFile;
|
||||
private final Set<String> badVideoFiles = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
/**
|
||||
* Creates new form MediaViewVideoPanel
|
||||
*/
|
||||
public GstVideoPanel() {
|
||||
public MediaPlayerPanel() {
|
||||
initComponents();
|
||||
customizeComponents();
|
||||
}
|
||||
@ -115,11 +212,11 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
return videoPanel;
|
||||
}
|
||||
|
||||
public VideoComponent getVideoComponent() {
|
||||
return gstVideoComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Has this MediaPlayerPanel been initialized correctly?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isInited() {
|
||||
return gstInited;
|
||||
}
|
||||
@ -140,19 +237,19 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
*/
|
||||
int time = progressSlider.getValue();
|
||||
synchronized (playbinLock) {
|
||||
if (gstPlaybin2 != null && !autoTracking) {
|
||||
State orig = gstPlaybin2.getState();
|
||||
if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.pause() failed."); //NON-NLS
|
||||
if (gstPlayBin != null && !autoTracking) {
|
||||
State orig = gstPlayBin.getState();
|
||||
if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
if (gstPlaybin2.seek(ClockTime.fromMillis(time)) == false) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.seek() failed."); //NON-NLS
|
||||
if (gstPlayBin.seek(ClockTime.fromMillis(time)) == false) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.seek() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
gstPlaybin2.setState(orig);
|
||||
gstPlayBin.setState(orig);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -182,9 +279,14 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Initialize all the necessary variables to play an audio/video file.
|
||||
*
|
||||
* @param file Media file to play.
|
||||
* @param dims Dimension of the parent window.
|
||||
*/
|
||||
@NbBundle.Messages ({"GstVideoPanel.noOpenCase.errMsg=No open case available."})
|
||||
void setupVideo(final AbstractFile file, final Dimension dims) {
|
||||
void loadFile(final AbstractFile file, final Dimension dims) {
|
||||
reset();
|
||||
infoLabel.setText("");
|
||||
currentFile = file;
|
||||
@ -221,32 +323,75 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
progressSlider.setEnabled(true);
|
||||
|
||||
|
||||
gstVideoComponent = new VideoComponent();
|
||||
//gstVideoComponent = new SimpleVideoComponent();
|
||||
gstVideoRenderer = new GstVideoRendererPanel();
|
||||
synchronized (playbinLock) {
|
||||
if (gstPlaybin2 != null) {
|
||||
gstPlaybin2.dispose();
|
||||
if (gstPlayBin != null) {
|
||||
gstPlayBin.dispose();
|
||||
}
|
||||
gstPlaybin2 = new PlayBin2("VideoPlayer"); //NON-NLS
|
||||
gstPlaybin2.setVideoSink(gstVideoComponent.getElement());
|
||||
gstPlayBin = new PlayBin("VideoPlayer"); //NON-NLS
|
||||
gstPlayBin.setVideoSink(gstVideoRenderer.getVideoSink());
|
||||
|
||||
videoPanel.removeAll();
|
||||
|
||||
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
||||
videoPanel.add(gstVideoComponent);
|
||||
//videoPanel.add(gstVideoComponent);
|
||||
|
||||
EventQueue.invokeLater(() -> {
|
||||
videoPanel.add(gstVideoRenderer);//add jfx ui to JPanel
|
||||
});
|
||||
|
||||
videoPanel.setVisible(true);
|
||||
|
||||
gstPlaybin2.setInputFile(ioFile);
|
||||
gstPlayBin.setInputFile(ioFile);
|
||||
|
||||
if (gstPlaybin2.setState(State.READY) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.READY) failed."); //NON-NLS
|
||||
if (gstPlayBin.setState(State.READY) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.setState(State.READY) failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
}
|
||||
|
||||
gstPlayBin.getBus().connect(new Bus.EOS() {
|
||||
@Override
|
||||
public void endOfStream(GstObject source) {
|
||||
long test = durationMillis;
|
||||
System.out.println(test);
|
||||
System.out.println();
|
||||
}
|
||||
});
|
||||
gstPlayBin.getBus().connect(new Bus.ERROR() {
|
||||
@Override
|
||||
public void errorMessage(GstObject source, int code, String message) {
|
||||
long test = durationMillis;
|
||||
System.out.println(test);
|
||||
System.out.println();
|
||||
}
|
||||
});
|
||||
gstPlayBin.getBus().connect(new Bus.STATE_CHANGED() {
|
||||
@Override
|
||||
public void stateChanged(GstObject source, State old, State current, State pending) {
|
||||
if (durationMillis == 0 && current.equals(State.PLAYING)) {
|
||||
durationMillis = gstPlayBin.queryDuration().toMillis();
|
||||
|
||||
// pick out the total hours, minutes, seconds
|
||||
long durationSeconds = (int) durationMillis / 1000;
|
||||
totalHours = (int) durationSeconds / 3600;
|
||||
durationSeconds -= totalHours * 3600;
|
||||
totalMinutes = (int) durationSeconds / 60;
|
||||
durationSeconds -= totalMinutes * 60;
|
||||
totalSeconds = (int) durationSeconds;
|
||||
}
|
||||
long test = durationMillis;
|
||||
System.out.println(test);
|
||||
System.out.println();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Prepare this MediaViewVideoPanel to accept a different media file.
|
||||
*/
|
||||
void reset() {
|
||||
|
||||
// reset the progress label text on the event dispatch thread
|
||||
@ -259,25 +404,26 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
}
|
||||
|
||||
synchronized (playbinLock) {
|
||||
if (gstPlaybin2 != null) {
|
||||
if (gstPlaybin2.isPlaying()) {
|
||||
if (gstPlaybin2.stop() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.stop() failed."); //NON-NLS
|
||||
if (gstPlayBin != null) {
|
||||
if (gstPlayBin.isPlaying()) {
|
||||
if (gstPlayBin.stop() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.stop() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (gstPlaybin2.setState(State.NULL) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.NULL) failed."); //NON-NLS
|
||||
if (gstPlayBin.setState(State.NULL) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.setState(State.NULL) failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
if (gstPlaybin2.getState().equals(State.NULL)) {
|
||||
gstPlaybin2.dispose();
|
||||
if (gstPlayBin.getState().equals(State.NULL)) {
|
||||
gstPlayBin.dispose();
|
||||
}
|
||||
gstPlaybin2 = null;
|
||||
gstPlayBin = null;
|
||||
}
|
||||
gstVideoComponent = null;
|
||||
//gstVideoComponent = null;
|
||||
gstVideoRenderer = null;
|
||||
}
|
||||
|
||||
// get rid of any existing videoProgressWorker thread
|
||||
@ -289,152 +435,6 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
currentFile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file a video file from which to capture frames
|
||||
* @param numFrames the number of frames to capture. These frames will be
|
||||
* captured at successive intervals given by
|
||||
* durationOfVideo/numFrames. If this frame interval is
|
||||
* less than MIN_FRAME_INTERVAL_MILLIS, then only one frame
|
||||
* will be captured and returned.
|
||||
*
|
||||
* @return a List of VideoFrames representing the captured frames.
|
||||
*/
|
||||
@Override
|
||||
public List<VideoFrame> captureFrames(java.io.File file, int numFrames) throws Exception {
|
||||
|
||||
List<VideoFrame> frames = new ArrayList<>();
|
||||
|
||||
Object lock = new Object();
|
||||
FrameCaptureRGBListener rgbListener = new FrameCaptureRGBListener(lock);
|
||||
|
||||
if (!isInited()) {
|
||||
return frames;
|
||||
}
|
||||
|
||||
// throw exception if this file is known to be problematic
|
||||
if (badVideoFiles.contains(file.getName())) {
|
||||
throw new Exception(
|
||||
NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemFile.msg", file.getName()));
|
||||
}
|
||||
|
||||
// set up a PlayBin2 object
|
||||
RGBDataSink videoSink = new RGBDataSink("rgb", rgbListener); //NON-NLS
|
||||
PlayBin2 playbin = new PlayBin2("VideoFrameCapture"); //NON-NLS
|
||||
playbin.setInputFile(file);
|
||||
playbin.setVideoSink(videoSink);
|
||||
|
||||
// this is necessary to get a valid duration value
|
||||
StateChangeReturn ret = playbin.play();
|
||||
if (ret == StateChangeReturn.FAILURE) {
|
||||
// add this file to the set of known bad ones
|
||||
badVideoFiles.add(file.getName());
|
||||
throw new Exception(NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemPlay.msg"));
|
||||
}
|
||||
ret = playbin.pause();
|
||||
if (ret == StateChangeReturn.FAILURE) {
|
||||
// add this file to the set of known bad ones
|
||||
badVideoFiles.add(file.getName());
|
||||
throw new Exception(NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemPause.msg"));
|
||||
}
|
||||
playbin.getState();
|
||||
|
||||
// get the duration of the video
|
||||
TimeUnit unit = TimeUnit.MILLISECONDS;
|
||||
long myDurationMillis = playbin.queryDuration(unit);
|
||||
if (myDurationMillis <= 0) {
|
||||
return frames;
|
||||
}
|
||||
|
||||
// calculate the number of frames to capture
|
||||
int numFramesToGet = numFrames;
|
||||
long frameInterval = myDurationMillis / numFrames;
|
||||
if (frameInterval < MIN_FRAME_INTERVAL_MILLIS) {
|
||||
numFramesToGet = 1;
|
||||
}
|
||||
|
||||
// for each timeStamp, grap a frame
|
||||
for (int i = 0; i < numFramesToGet; ++i) {
|
||||
long timeStamp = i * frameInterval;
|
||||
|
||||
ret = playbin.pause();
|
||||
if (ret == StateChangeReturn.FAILURE) {
|
||||
// add this file to the set of known bad ones
|
||||
badVideoFiles.add(file.getName());
|
||||
throw new Exception(
|
||||
NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemPauseCaptFrame.msg"));
|
||||
}
|
||||
playbin.getState();
|
||||
|
||||
if (!playbin.seek(timeStamp, unit)) {
|
||||
logger.log(Level.INFO, "There was a problem seeking to {0} {1}", new Object[]{timeStamp, unit.name().toLowerCase()}); //NON-NLS
|
||||
}
|
||||
|
||||
ret = playbin.play();
|
||||
if (ret == StateChangeReturn.FAILURE) {
|
||||
// add this file to the set of known bad ones
|
||||
badVideoFiles.add(file.getName());
|
||||
throw new Exception(
|
||||
NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemPlayCaptFrame.msg"));
|
||||
}
|
||||
|
||||
// wait for FrameCaptureRGBListener to finish
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait(FRAME_CAPTURE_TIMEOUT_MILLIS);
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.INFO, "InterruptedException occurred while waiting for frame capture.", e); //NON-NLS
|
||||
}
|
||||
}
|
||||
Image image = rgbListener.getImage();
|
||||
|
||||
ret = playbin.stop();
|
||||
if (ret == StateChangeReturn.FAILURE) {
|
||||
// add this file to the set of known bad ones
|
||||
badVideoFiles.add(file.getName());
|
||||
throw new Exception(
|
||||
NbBundle.getMessage(this.getClass(), "GstVideoPanel.exception.problemStopCaptFrame.msg"));
|
||||
}
|
||||
|
||||
if (image == null) {
|
||||
logger.log(Level.WARNING, "There was a problem while trying to capture a frame from file {0}", file.getName()); //NON-NLS
|
||||
badVideoFiles.add(file.getName());
|
||||
break;
|
||||
}
|
||||
|
||||
frames.add(new VideoFrame(image, timeStamp));
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
private class FrameCaptureRGBListener implements RGBDataSink.Listener {
|
||||
|
||||
public FrameCaptureRGBListener(Object waiter) {
|
||||
this.waiter = waiter;
|
||||
}
|
||||
|
||||
private BufferedImage bi;
|
||||
private final Object waiter;
|
||||
|
||||
@Override
|
||||
public void rgbFrame(boolean bln, int w, int h, IntBuffer rgbPixels) {
|
||||
synchronized (waiter) {
|
||||
bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
bi.setRGB(0, 0, w, h, rgbPixels.array(), 0, w);
|
||||
waiter.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public Image getImage() {
|
||||
synchronized (waiter) {
|
||||
Image image = bi;
|
||||
bi = null;
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
@ -462,16 +462,16 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
.addGap(0, 231, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(pauseButton, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.pauseButton.text")); // NOI18N
|
||||
pauseButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
pauseButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.progressLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(GstVideoPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaViewVideoPanel.infoLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
|
||||
controlPanel.setLayout(controlPanelLayout);
|
||||
@ -523,30 +523,33 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
|
||||
synchronized (playbinLock) {
|
||||
State state = gstPlaybin2.getState();
|
||||
if (gstPlayBin == null) {
|
||||
return;
|
||||
}
|
||||
State state = gstPlayBin.getState();
|
||||
if (state.equals(State.PLAYING)) {
|
||||
if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.pause() failed."); //NON-NLS
|
||||
if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
pauseButton.setText("►");
|
||||
// Is this call necessary considering we just called gstPlaybin2.pause()?
|
||||
if (gstPlaybin2.setState(State.PAUSED) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.PAUSED) failed."); //NON-NLS
|
||||
// Is this call necessary considering we just called gstPlayBin.pause()?
|
||||
if (gstPlayBin.setState(State.PAUSED) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.setState(State.PAUSED) failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
} else if (state.equals(State.PAUSED)) {
|
||||
if (gstPlaybin2.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.play() failed."); //NON-NLS
|
||||
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
pauseButton.setText("||");
|
||||
// Is this call necessary considering we just called gstPlaybin2.play()?
|
||||
if (gstPlaybin2.setState(State.PLAYING) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.PLAYING) failed."); //NON-NLS
|
||||
// Is this call necessary considering we just called gstPlayBin.play()?
|
||||
if (gstPlayBin.setState(State.PLAYING) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.setState(State.PLAYING) failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
@ -584,23 +587,23 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
private boolean isPlayBinReady() {
|
||||
synchronized (playbinLock) {
|
||||
return gstPlaybin2 != null && !gstPlaybin2.getState().equals(State.NULL);
|
||||
return gstPlayBin != null && !gstPlayBin.getState().equals(State.NULL);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetVideo() throws Exception {
|
||||
synchronized (playbinLock) {
|
||||
if (gstPlaybin2 != null) {
|
||||
if (gstPlaybin2.stop() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.stop() failed."); //NON-NLS
|
||||
if (gstPlayBin != null) {
|
||||
if (gstPlayBin.stop() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.stop() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
}
|
||||
// ready to be played again
|
||||
if (gstPlaybin2.setState(State.READY) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.setState(State.READY) failed."); //NON-NLS
|
||||
if (gstPlayBin.setState(State.READY) == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.setState(State.READY) failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
}
|
||||
gstPlaybin2.getState(); //NEW
|
||||
gstPlayBin.getState(); //NEW
|
||||
}
|
||||
}
|
||||
pauseButton.setText("►");
|
||||
@ -631,7 +634,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
while (hasNotEnded() && isPlayBinReady() && !isCancelled()) {
|
||||
|
||||
synchronized (playbinLock) {
|
||||
pos = gstPlaybin2.queryPosition();
|
||||
pos = gstPlayBin.queryPosition();
|
||||
}
|
||||
millisElapsed = pos.toMillis();
|
||||
|
||||
@ -699,7 +702,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
@Override
|
||||
protected Long doInBackground() throws Exception {
|
||||
if (tempFile.exists() == false || tempFile.length() < sourceFile.getSize()) {
|
||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(GstVideoPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> ExtractMedia.this.cancel(true));
|
||||
progress = ProgressHandle.createHandle(NbBundle.getMessage(MediaPlayerPanel.class, "GstVideoPanel.ExtractMedia.progress.buffering", sourceFile.getName()), () -> ExtractMedia.this.cancel(true));
|
||||
progressLabel.setText(NbBundle.getMessage(this.getClass(), "GstVideoPanel.progress.buffering"));
|
||||
progress.start(100);
|
||||
try {
|
||||
@ -744,20 +747,26 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
ClockTime dur;
|
||||
synchronized (playbinLock) {
|
||||
// must play, then pause and get state to get duration.
|
||||
if (gstPlaybin2.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.play() failed."); //NON-NLS
|
||||
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
if (gstPlaybin2.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.pause() failed."); //NON-NLS
|
||||
/*gstPlayBin.getBus().connect(new Bus.DURATION() {
|
||||
@Override
|
||||
public void durationChanged(GstObject go, Format format, long l) {
|
||||
System.out.println();
|
||||
}
|
||||
});*/
|
||||
//DLG:
|
||||
/*if (gstPlayBin.pause() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.pause() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
return;
|
||||
}
|
||||
gstPlaybin2.getState();
|
||||
dur = gstPlaybin2.queryDuration();
|
||||
}*/
|
||||
State state = gstPlayBin.getState();
|
||||
dur = gstPlayBin.queryDuration();
|
||||
}
|
||||
durationMillis = dur.toMillis();
|
||||
|
||||
// pick out the total hours, minutes, seconds
|
||||
long durationSeconds = (int) durationMillis / 1000;
|
||||
@ -771,12 +780,12 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
progressSlider.setMaximum((int) durationMillis);
|
||||
progressSlider.setMinimum(0);
|
||||
|
||||
synchronized (playbinLock) {
|
||||
if (gstPlaybin2.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin2.play() failed."); //NON-NLS
|
||||
/*synchronized (playbinLock) {
|
||||
if (gstPlayBin.play() == StateChangeReturn.FAILURE) {
|
||||
logger.log(Level.WARNING, "Attempt to call PlayBin.play() failed."); //NON-NLS
|
||||
infoLabel.setText(MEDIA_PLAYER_ERROR_STRING);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
pauseButton.setText("||");
|
||||
videoProgressWorker = new VideoProgressWorker();
|
||||
videoProgressWorker.execute();
|
||||
@ -785,13 +794,49 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExtensions() {
|
||||
return EXTENSIONS.clone();
|
||||
public List<String> getSupportedExtensions() {
|
||||
return Arrays.asList(EXTENSIONS.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMimeTypes() {
|
||||
public List<String> getSupportedMimeTypes() {
|
||||
return MIMETYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file) {
|
||||
String extension = file.getNameExtension();
|
||||
/**
|
||||
* Although it seems too restrictive, requiring both a supported
|
||||
* extension and a supported MIME type prevents two undesirable
|
||||
* behaviors:
|
||||
*
|
||||
* 1) Until AUT-1766 and AUT-1801 are fixed, we incorrectly identify all
|
||||
* iff files as audio/aiff. This means that if this panel went with the
|
||||
* looser 'mime type OR extension' criteria we use for images, then this
|
||||
* panel would attempt (and fail) to display all iff files, even non
|
||||
* audio ones.
|
||||
*
|
||||
* 2) The looser criteria means we are less confident about the files we
|
||||
* are potentialy sending to GStreamer on 32bit jvms. We are less
|
||||
* comfortable with the error handling for GStreamer, and don't want to
|
||||
* send it files which might cause it trouble.
|
||||
*/
|
||||
if (getSupportedExtensions().contains("." + extension)) {
|
||||
SortedSet<String> mimeTypes = new TreeSet<>(getSupportedMimeTypes());
|
||||
try {
|
||||
String mimeType = new FileTypeDetector().getMIMEType(file);
|
||||
return mimeTypes.contains(mimeType);
|
||||
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
|
||||
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
||||
if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return getSupportedExtensions().contains("." + extension);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -230,7 +230,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* @return supported mime types
|
||||
*/
|
||||
@Override
|
||||
public List<String> getMimeTypes() {
|
||||
public List<String> getSupportedMimeTypes() {
|
||||
return Collections.unmodifiableList(Lists.newArrayList(supportedMimes));
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<String> getExtensionsList() {
|
||||
public List<String> getSupportedExtensions() {
|
||||
return getExtensions();
|
||||
}
|
||||
|
||||
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 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;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.autopsy.corecomponents.FrameCapture;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
* Video viewer part of the Media View layered pane. Uses different engines
|
||||
* depending on platform.
|
||||
*/
|
||||
abstract class MediaViewVideoPanel extends JPanel implements FrameCapture, MediaFileViewer.MediaViewPanel {
|
||||
|
||||
private static final Set<String> AUDIO_EXTENSIONS = new TreeSet<>(Arrays.asList(".mp3", ".wav", ".wma")); //NON-NLS
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName());
|
||||
|
||||
// 64 bit architectures
|
||||
private static final String[] ARCH64 = new String[]{"amd64", "x86_64"}; //NON-NLS NON-NLS
|
||||
|
||||
// 32 bit architectures
|
||||
private static final String[] ARCH32 = new String[]{"x86"}; //NON-NLS
|
||||
|
||||
/**
|
||||
* Factory Method to create a MediaViewVideoPanel.
|
||||
*
|
||||
* Implementation is dependent on the architecture of the JVM.
|
||||
*
|
||||
* @return a MediaViewVideoPanel instance.
|
||||
*/
|
||||
public static MediaViewVideoPanel createVideoPanel() {
|
||||
if (is64BitJVM()) {
|
||||
logger.log(Level.INFO, "64 bit JVM detected. Creating JavaFX Video Player."); //NON-NLS
|
||||
return getFXImpl();
|
||||
} else {
|
||||
logger.log(Level.INFO, "32 bit JVM detected. Creating GStreamer Video Player."); //NON-NLS
|
||||
return getGstImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the JVM architecture 64 bit?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static boolean is64BitJVM() {
|
||||
String arch = System.getProperty("os.arch");
|
||||
return Arrays.asList(ARCH64).contains(arch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a GStreamer video player implementation.
|
||||
*
|
||||
* @return a GstVideoPanel
|
||||
*/
|
||||
private static MediaViewVideoPanel getGstImpl() {
|
||||
return new GstVideoPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JavaFX video player implementation.
|
||||
*
|
||||
* @return a FXVideoPanel
|
||||
*/
|
||||
private static MediaViewVideoPanel getFXImpl() {
|
||||
return new FXVideoPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this MediaViewVideoPanel been initialized correctly?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean isInited();
|
||||
|
||||
/**
|
||||
* Prepare this MediaViewVideoPanel to accept a different media file.
|
||||
*/
|
||||
abstract void reset();
|
||||
|
||||
/**
|
||||
* Initialize all the necessary vars to play a video/audio file.
|
||||
*
|
||||
* @param file video file to play
|
||||
* @param dims dimension of the parent window
|
||||
*/
|
||||
abstract void setupVideo(final AbstractFile file, final Dimension dims);
|
||||
|
||||
/**
|
||||
* Return the extensions supported by this video panel.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract public String[] getExtensions();
|
||||
|
||||
/**
|
||||
* Return the MimeTypes supported by this video panel.
|
||||
*/
|
||||
@Override
|
||||
abstract public List<String> getMimeTypes();
|
||||
|
||||
@Override
|
||||
public List<String> getExtensionsList() {
|
||||
return Arrays.asList(getExtensions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file) {
|
||||
String extension = file.getNameExtension();
|
||||
/**
|
||||
* Although it seems too restrictive, requiring both a supported
|
||||
* extension and a supported MIME type prevents two undesirable
|
||||
* behaviors:
|
||||
*
|
||||
* 1) Until AUT-1766 and AUT-1801 are fixed, we incorrectly identify all
|
||||
* iff files as audio/aiff. This means that if this panel went with the
|
||||
* looser 'mime type OR extension' criteria we use for images, then this
|
||||
* panel would attempt (and fail) to display all iff files, even non
|
||||
* audio ones.
|
||||
*
|
||||
* 2) The looser criteria means we are less confident about the files we
|
||||
* are potentialy sending to GStreamer on 32bit jvms. We are less
|
||||
* comfortable with the error handling for GStreamer, and don't want to
|
||||
* send it files which might cause it trouble.
|
||||
*/
|
||||
if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) {
|
||||
SortedSet<String> mimeTypes = new TreeSet<>(getMimeTypes());
|
||||
try {
|
||||
String mimeType = new FileTypeDetector().getMIMEType(file);
|
||||
return mimeTypes.contains(mimeType);
|
||||
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
|
||||
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
|
||||
if (!mimeTypes.isEmpty() && file.isMimeType(mimeTypes) == AbstractFile.MimeMatchEnum.TRUE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return getExtensionsList().contains("." + extension);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 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.corecomponents;
|
||||
|
||||
/**
|
||||
* This class exists to support backwards compatibility of an erroneous call to
|
||||
* Logger.getLogger(GSTVideoPanel.class.getName()) in OpenCVFrameCapture.java in
|
||||
* an older version of the Video Triage Net Beans Module (NBM). It should be
|
||||
* removed when we are ready to stop supporting older Video Triage NBMs. The
|
||||
* current Video Triage code has already been updated.
|
||||
*/
|
||||
@Deprecated
|
||||
public class GSTVideoPanel {
|
||||
|
||||
}
|
@ -11,6 +11,8 @@
|
||||
|
||||
<!-- for viewers -->
|
||||
<dependency conf="autopsy_core->*" org="com.googlecode.gstreamer-java" name="gstreamer-java" rev="1.5"/>
|
||||
<dependency conf="autopsy_core->*" org="org.freedesktop.gstreamer" name="gst1-java-core" rev="0.9.3"/>
|
||||
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="jna" rev="3.4.0"/>
|
||||
|
||||
<!-- for file search -->
|
||||
<dependency conf="autopsy_core->*" org="com.github.lgooddatepicker" name="LGoodDatePicker" rev="10.3.1"/>
|
||||
@ -66,5 +68,8 @@
|
||||
<dependency conf="autopsy_core->default" org="com.twelvemonkeys.imageio" name="imageio-thumbsdb" rev="3.2" />
|
||||
<dependency conf="autopsy_core->default" org="com.twelvemonkeys.imageio" name="imageio-core" rev="3.2" />
|
||||
<dependency conf="autopsy_core->default" org="com.twelvemonkeys.imageio" name="imageio-metadata" rev="3.2" />
|
||||
|
||||
<!-- conflict resolutions for multiple JAR versions -->
|
||||
<conflict org="net.java.dev.jna" module="jna" rev="3.4.0"/>
|
||||
</dependencies>
|
||||
</ivy-module>
|
||||
|
@ -24,6 +24,8 @@ 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-1.4.jar=release/modules/ext/gson-1.4.jar
|
||||
file.reference.gstreamer-java-1.5.jar=release/modules/ext/gstreamer-java-1.5.jar
|
||||
file.reference.gst1-java-core-0.9.3.jar=release/modules/ext/gst1-java-core-0.9.3.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
|
||||
|
@ -583,6 +583,24 @@
|
||||
<package>org.dom4j.util</package>
|
||||
<package>org.dom4j.xpath</package>
|
||||
<package>org.dom4j.xpp</package>
|
||||
<package>org.freedesktop.gstreamer</package>
|
||||
<package>org.freedesktop.gstreamer.controller</package>
|
||||
<package>org.freedesktop.gstreamer.elements</package>
|
||||
<package>org.freedesktop.gstreamer.elements.good</package>
|
||||
<package>org.freedesktop.gstreamer.event</package>
|
||||
<package>org.freedesktop.gstreamer.example</package>
|
||||
<package>org.freedesktop.gstreamer.glib</package>
|
||||
<package>org.freedesktop.gstreamer.interfaces</package>
|
||||
<package>org.freedesktop.gstreamer.io</package>
|
||||
<package>org.freedesktop.gstreamer.lowlevel</package>
|
||||
<package>org.freedesktop.gstreamer.lowlevel.annotations</package>
|
||||
<package>org.freedesktop.gstreamer.media</package>
|
||||
<package>org.freedesktop.gstreamer.media.event</package>
|
||||
<package>org.freedesktop.gstreamer.message</package>
|
||||
<package>org.freedesktop.gstreamer.query</package>
|
||||
<package>org.freedesktop.gstreamer.swing</package>
|
||||
<package>org.freedesktop.gstreamer.swt</package>
|
||||
<package>org.freedesktop.gstreamer.swt.overlay</package>
|
||||
<package>org.gstreamer</package>
|
||||
<package>org.gstreamer.controller</package>
|
||||
<package>org.gstreamer.elements</package>
|
||||
@ -966,6 +984,10 @@
|
||||
<runtime-relative-path>ext/gstreamer-java-1.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/gstreamer-java-1.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/gst1-java-core-0.9.3.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/gst1-java-core-0.9.3.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/dom4j-1.6.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/dom4j-1.6.1.jar</binary-origin>
|
||||
|
@ -123,7 +123,7 @@
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\bin -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
</exec>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\lib\gstreamer-0.10 -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name GSTREAMER_PATH -value [APPDIR]gstreamer\lib\gstreamer-1.0 -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
</exec>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
|
@ -103,7 +103,7 @@
|
||||
<copy file="${basedir}/Running_Linux_OSX.txt" tofile="${zip-tmp}/${app.name}/Running_Linux_OSX.txt"/>
|
||||
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
|
||||
<replaceregexp file="${zip-tmp}/${app.name}/unix_setup.sh" match="TSK_VERSION=(.*)" replace="TSK_VERSION=${TSK_VERSION}" byline="true"/>
|
||||
<unzip src="${thirdparty.dir}/gstreamer/windows/i386/0.10.7/gstreamer.zip" dest="${zip-tmp}/${app.name}/gstreamer"/>
|
||||
<unzip src="${thirdparty.dir}/gstreamer/windows/i386/1.14.4/gstreamer.zip" dest="${zip-tmp}/${app.name}/gstreamer"/>
|
||||
|
||||
|
||||
<copy file="${basedir}/icons/icon.ico" tofile="${zip-tmp}/${app.name}/icon.ico" overwrite="true"/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user