I'm writing a screencast application in Java.
I decided to use Xuggle to do it and I followed up the installation instructions on the xuggle wiki.
I set up the PATH environment with %XUGGLE_HOME%\bin and %XUGGLE_HOME%\lib. Everything seems OK.
I made this application as a RCP plugin. I tried it on the "RCP-mail" template and the plugin is working and the video is generated correctly.
But when I decided to use it on a "real" application, the plug-in crashed with a strange error message:
Starting Capture
2011-11-10 08:08:45,438 [Thread-5] WARN com.xuggle.ferry.JNILibraryLoader - Failure: library load of library: xuggle-xuggler; version: 3: absolute path: C:\Program Files (x86)\Xuggle\bin\libxuggle-xuggler-3.dll; error: java.lang.UnsatisfiedLinkError: C:\Program Files (x86)\Xuggle\bin\libxuggle-xuggler-3.dll: Can't find dependent libraries
2011-11-10 08:08:45,447 [Thread-5] WARN com.xuggle.ferry.JNILibraryLoader - Failure: library load of library: xuggle-xuggler; version: 3: absolute path: C:\Program Files (x86)\Xuggle\bin\libxuggle-xuggler-3.dll; error: java.lang.UnsatisfiedLinkError: C:\Program Files (x86)\Xuggle\bin\libxuggle-xuggler-3.dll: Can't find dependent libraries
2011-11-10 08:08:45,453 [Thread-5] ERROR com.xuggle.ferry.JNILibraryLoader - Could not load library: xuggle-xuggler; version: 3; Visit http://www.xuggle.com/xuggler/faq/ to find common solutions to this problem
But this strange because the java.library.path is well defined:
logger.info(System.getProperty("java.library.path"));
returns
Nov 10, 2011 8:08:45 AM com.gvs.tools.ui.record.video.handler.RecordHandler startRecording
INFO: C:\Program Files (x86)\Java\jre6\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:/Program Files (x86)/Java/jre6/bin/client;C:/Program Files (x86)/Java/jre6/bin;C:/Program Files (x86)/Java/jre6/lib/i386;C:\Program Files (x86)\Xuggle\bin;C:\Program Files (x86)\Xuggle\lib;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\JProbe 8.3\bin;C:\Program Files\TortoiseSVN\bin;D:\Work\Paul\eclipse;;.
What I'm missing to make the plug-in work with this application?
Is this issue due to the fact that the application uses other native libraries such as 3D-dll?
Here is the code used to make the screencast video:
RecordHandler.java:
private void startRecording() {
Logger logger = Logger.getLogger(RecordHandler.class.getName());
logger.info(System.getProperty("java.library.path"));
// Initialize framesQueue
framesQueue = new LinkedBlockingQueue<BufferedImage>();
// Initialize the capture thread
captureThread = new ScreenCapturer();
captureThread.setCaptureFramesQueue(framesQueue);
// Initialize the recorder
encoderThread = new FrameEncoder("test.mp4");
encoderThread.setCapturedFramesQueue(framesQueue);
// Start capture
captureThread.start();
// wait for the Queue to be feed before encoding
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
}
encoderThread.start();
}
ScreenCapturer.java:
#Override
public void run() {
// Retrieve the application main window's shell
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
appShell = Display.getCurrent().getActiveShell();
}
});
isRunning = true;
System.out.println("Starting Capture");
for (numberOfFramesTaken = 0; isRunning && numberOfFramesTaken <= IVideoEncoderConfiguration.MAXIMUM_NUMBER_OF_FRAMES; numberOfFramesTaken++) {
try {
takeScreenShot();
Thread.sleep(IVideoEncoderConfiguration.CAPTURE_TIME_INTERVAL_MILLIS);
} catch (InterruptedException e) {
}
}
System.out.println("Capture has ended");
System.out.println("Number of frames taken: "
+ numberOfFramesTaken);
}
/**
* Take a screen capture and store it in the capturedFramesQueue
*/
private void takeScreenShot() {
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
if (appShell != null) {
Rectangle bounds = appShell.getBounds();
java.awt.Rectangle awtBounds = new java.awt.Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
final BufferedImage screenCapture = robot.createScreenCapture(awtBounds);
try {
capturedFramesQueue.put(screenCapture);
} catch (InterruptedException e) {
}
}
}
});
}
FrameEncoder.java:
public void run() {
isRunning = true;
String outFile = outputdirectoryPath + outputFileName;
// First, let's make a IMediaWriter to write the file.
final IMediaWriter writer = ToolFactory.makeWriter(outFile);
// Retrieve the first frame to guess video dimensions
BufferedImage firstFrame = null;
try {
firstFrame = capturedFramesQueue.take();
} catch (InterruptedException e) {
}
if (firstFrame == null) {
return;
}
// We tell it we're going to add one video stream, with id 0,
// at position 0, and that it will have a fixed frame rate of
// FRAME_RATE.
writer.addVideoStream(0, 0,
IVideoEncoderConfiguration.FRAME_RATE,
firstFrame.getWidth(), firstFrame.getHeight());
long startTime = System.nanoTime();
for (numberOfFramesRecorded = 0; isRunning
&& numberOfFramesRecorded <= IVideoEncoderConfiguration.MAXIMUM_NUMBER_OF_FRAMES; numberOfFramesRecorded++) {
// Retrieve the captured frame
try {
final BufferedImage currentFrame = convertToType(capturedFramesQueue.take(), BufferedImage.TYPE_3BYTE_BGR);
// encode the next frame
writer.encodeVideo(0, currentFrame, System.nanoTime() - startTime,
TimeUnit.NANOSECONDS);
// sleep, time depending of FRAME_RATE
Thread.sleep(IVideoEncoderConfiguration.CAPTURE_TIME_INTERVAL_MILLIS);
} catch (InterruptedException e) {
}
}
// Get the remaining frame on the queue
Collection<BufferedImage> frames = new LinkedList<BufferedImage>();
capturedFramesQueue.drainTo(frames, IVideoEncoderConfiguration.MAXIMUM_NUMBER_OF_FRAMES - numberOfFramesRecorded);
for (BufferedImage frame : frames) {
BufferedImage currentFrame = convertToType(frame, BufferedImage.TYPE_3BYTE_BGR);
writer.encodeVideo(0, currentFrame, System.nanoTime() - startTime,
TimeUnit.NANOSECONDS);
}
// close the MediaWriter, write the trailer if needed
writer.close();
}
It's a little late I know, but the problem is that Xuggler requires ALL THE DLLs to be in the operating system load-path environment, not just the java.library.path
That means that all DLLs that install with Xuggle (for example, libavcodec.dll) need to be in the %PATH% environment variable of the process that launched Java.
Cause Could be un-availability of dependency jars or version conflicts.
Adding the following jars in the class path worked fine for me:
xuggle-xuggler-5.4.jar
slf4j-api-1.6.4.jar
logback-core-1.0.0.jar
logback-classic-1.0.0.jar
Related
I made a rubiks cube application which includes a cube detection system, As im getting closer to wrapping up the project I wanted to make a JAR file. I get errors when running the JAR file and it really sucks because I can only run the project in IntelliJ(IDE).
I face two problems:
1) I cant get the JAR to link openCV properly
2)I have a problem loading an FXML file(this will occur assuming it did not crash while trying to load openCV.
For case 1 here is the code and errors:
static {
// try {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// } catch (UnsatisfiedLinkError e) {
// System.err.println("Could not find OpenCV Library!");
// }
}
and the error message:
Exception in thread "JavaFX Application Thread" Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java342 in java.library.path:
Now If i remove the try catch comments i get this error:
static {
try {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
} catch (UnsatisfiedLinkError e) {
System.err.println("Could not find OpenCV Library!");
}
}
#Override
public void start(Stage primaryStage) throws Exception {
//Loader
FXMLLoader loader = new FXMLLoader(main.class.getResource("FXML_layouts\\MainScreen.fxml"));
Scene scene = new Scene(loader.load());
((mainController)loader.getController()).setStage(primaryStage);
primaryStage.setScene(scene);
primaryStage.show();
}
Error:
Could not find OpenCV Library!
Exception in Application start method
java.lang.reflect.InvocationTargetException
....
Caused by: java.lang.IllegalStateException: Location is not set.
Here is my file structure:
and here is my artifact config:
Just go with the steps below:
Put the opencv_java342.dll in a folder let call it dll_libs in a
drive e.g C:\dll_libs
Then go to Environment Variable -> Edit path -> put C:\dll_libs ->
Apply -> OK
Restart your IDE
OR: Just put the opencv_java342.dll file in the C:\Windows\System32 folder
And it is : )
Update (for your second question): If you want to give the executable package to someone else to run the program, there are almost 2 ways:
Let them to create the environment manually, just as the answer to
your question.
Do the job programmatically, just within your code write a function
which set the .dd environment variable on the program startup, and
then load the lib.
If you choose the second one, here I will give an example code to refere to:
public static void loadOpenCVLib() throws Exception {
File file = new File(OpenCVUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath());
File opencv_libs = new File("oc_lib"); // this path is where is the lib going to copy to
String model = System.getProperty("sun.arch.data.model");
String localLibPath; // this is the path inside your program resource
if (model.equals("64")) {
localLibPath = "oc_lib/64bit";
} else {
localLibPath = "oc_lib/x86";
}
if (file.isFile()) { // when run from jar
JarFile jar = new JarFile(file);
if (!opencv_libs.exists() || !opencv_libs.isDirectory()) {
try {
JarUtils.copyResourcesToDirectory(jar, localLibPath, opencv_libs.getAbsolutePath());
} catch (Exception e) {
throw new IOException("Failed to create load opencv libs!!");
}
} else {
String[] list = opencv_libs.list();
if (list != null && list.length != 2) {
try {
JarUtils.copyResourcesToDirectory(jar, localLibPath, opencv_libs.getAbsolutePath());
} catch (Exception e) {
throw new IOException("Failed to create load opencv libs!!");
}
}
}
} else { // when run from IDE
File libPath = new File(OpenCVUtil.class.getResource("/"+localLibPath).getFile());
if (!opencv_libs.exists() || !opencv_libs.isDirectory()) {
boolean isDone = opencv_libs.mkdir();
if (!isDone && !opencv_libs.exists()) {
throw new IOException("Failed to create load opencv libs!!");
}
try {
FileUtils.copyDirectory(libPath, opencv_libs);
} catch (IOException e) {
throw new IOException("Failed to create load opencv libs!!");
}
} else {
String[] list1 = opencv_libs.list();
String[] list2 = libPath.list();
boolean contentEquals = list1 != null && list2 != null && list1.length == list2.length;
if (contentEquals) {
try {
FileUtils.copyDirectory(libPath, opencv_libs);
} catch (IOException e) {
throw new IOException("Failed to create load opencv libs!!");
}
}
}
}
System.setProperty("java.library.path", opencv_libs.getAbsolutePath());
Field sys_paths = ClassLoader.class.getDeclaredField("sys_paths");
sys_paths.setAccessible(true);
sys_paths.set(null, null);
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// it is for the ffmpeg name
String[] list = opencv_libs.list();
assert list != null;
String ffmpeg_dll_file_name = null;
for (String s : list) {
if (s.contains("ffmpeg")) {
ffmpeg_dll_file_name = s.substring(0, s.indexOf("."));
}
}
System.loadLibrary(ffmpeg_dll_file_name);
}
Hope it can help!!
I am using a java application which opens a scratch file during run time. The scratch file communicates with the arduino board and gives the output. once the communication starts i am unable to use my User interface in java which has a close button instead i tried closing my entire application using end task in task manager. Can you please tell me as how to release the memory associated with the files. I used process. destroy and system.exit(0) but did not work.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
if("Disconnect".equals(jButton1.getText()))
{
System.exit(0);
}
jButton1.setText("Disconnect");
if(jComboBox2.getSelectedItem()==null)
{
System.out.println("Select one port");
}
else
{ Runtime r = Runtime.getRuntime();
try {
this.hide();
//p = r.exec("C:\\Program Files\\Scratch 2\\Scratch 2.exe C:\\Users\\Admin\\Desktop\\fwdbckpwm12.sb2");
p = Runtime.getRuntime().exec("C:\\Program Files\\Scratch 2\\Scratch 2.exe C:\\Users\\Admin\\Desktop\\scratch files new.sb2");
//p.destroy();
//r.exec("C:\\Windows\\notepad.exe C:\\Windows\\ss.txt");
A4S a4sObj = new A4S(new String[]{jComboBox2.getSelectedItem().toString()}); //defaultline
// A4S a4sObj = new A4S(new String[]{"COM16"}); //addedline
r.gc();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
} catch (IOException ex) {
Logger.getLogger(serialportselection.class.getName()).log(Level.SEVERE, null, ex);
}
finally{
p.destroy();
System.gc();
}
}
}
I have implemented a simple file listener using Apache commons io monitor.I have also implemented a selenium script that simply do is download file into the pre hard coded path folder.That is totally working fine.My listener monitoring downloaded files and collect the necessary information.According to my requirement i should be able to stop the file listener once my selenium script is finished execution.To do that i must know that the incoming file transferring status to handle it better way.because i can not stop listener middle of the file transferring.(sometimes download file can be heavy so it will take some time to download).So how can i know that incoming file status in Apache commons io monitor before stop the file listener.If any one knows please let me know.
Sample code snippet
public class SimpleTestMonitor {
// A hardcoded path to a folder you are monitoring .
public static final String FOLDER =
"/home/skywalker/Desktop/simple-test-monitor/watchdir";
public static void main(String[] args) throws Exception {
// The monitor will perform polling on the folder every 5 seconds
final long pollingInterval = 5 * 1000;
File folder = new File(FOLDER);
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + FOLDER);
}
FileAlterationObserver observer = new FileAlterationObserver(folder);
FileAlterationMonitor monitor =
new FileAlterationMonitor(pollingInterval);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
// Is triggered when a file is created in the monitored folder
#Override
public void onFileCreate(File file) {
try {
// "file" is the reference to the newly created file
System.out.println("File created: "
+ file.getCanonicalPath());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
// Is triggered when a file is deleted from the monitored folder
#Override
public void onFileDelete(File file) {
try {
// "file" is the reference to the removed file
System.out.println("File removed: "
+ file.getCanonicalPath());
// "file" does not exists anymore in the location
System.out.println("File still exists in location: "
+ file.exists());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();
}
}
Reference
When I open the runnable jar file, it still could be opened but it get stuck after half a second like this.
(I cannot post an image, so I post the image here: https://pbs.twimg.com/media/B4RN2_MCYAAi1DD.png)
It works well in eclipse.
When I run it in CMD, it says:
Exception in thread "game" java.lang.NullPointerException: in
at javazoom.jl.decoder.Bitstream.<init>(Unknown Source)
at javazoom.jl.player.Player.<init>(Unknown Source)
at javazoom.jl.player.Player.<init>(Unknown Source)
at lian.xiangru.game.AudioHandler.<init>(AudioHandler.java:12)
at lian.xiangru.game.GameBoard.playSound(GameBoard.java:410)
at lian.xiangru.game.GameBoard.move(GameBoard.java:224)
at lian.xiangru.game.GameBoard.moveTiles(GameBoard.java:271)
at lian.xiangru.game.GameBoard.checkKeys(GameBoard.java:340)
at lian.xiangru.game.GameBoard.update(GameBoard.java:146)
at lian.xiangru.game.Game.update(Game.java:42)
at lian.xiangru.game.Game.run(Game.java:77)
at java.lang.Thread.run(Unknown Source)
It seems something goes wrong with my resources.
This is my playSound method:
private void playSound() {
// how to play mp3 https://www.youtube.com/watch?v=f-7cgX_I220
AudioHandler sound = new AudioHandler(
SOUND_LIST[(int) Math.round((Math.log(highestValue) / Math.log(2))) - 1]);
sound.start();
}
This is my AudioHandler class:
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
class AudioHandler extends Thread {
private Player playMP3;
public AudioHandler(String mp3) {
try {
playMP3 = new Player(getClass().getResourceAsStream(mp3));
} catch (JavaLayerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
try {
playMP3.play();
} catch (JavaLayerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The lists are:
public static final String[] SOUND_LIST = { "/mayuri.mp3", "/mikoto.mp3",
"/gai.mp3", "/shougo.mp3", "/gintoki.mp3", "/inori.mp3",
"/yuzuru.mp3", "/misaki.mp3", "/armin.mp3", "/alphonse.mp3",
"/alphonse.mp3", "/akane.mp3", "/armin.jpg" };
public static final String[] QUOTE_LIST = { "/mayuri.txt", "/mikoto.txt",
"/gai.txt", "/shougo.txt", "/gintoki.txt", "/inori.txt",
"/yuzuru.txt", "/misaki.txt", "/armin.txt", "/alphonse.txt",
"/alphonse.txt", "/akane.txt", "/armin.txt" };
public static final String[] ICON_LIST = {"/mayuri.jpg", "/mikoto.jpg",
"/gai.jpg", "/shougo.jpg", "/gintoki.jpg", "/inori.jpg",
"/yuzuru.jpg", "/misaki.jpg", "/armin.jpg", "/alphonse.jpg",
"/alphonse.jpg", "/akane.jpg", "/armin.jpg"
};
Thank you !!
NullPointerException when loading a resource usually means that the resource could not be found. This behavior is different than the normal file open, no exception is thrown.
Are your audio files included in your jar? If not, make sure that when you export the Jar, you set the right options so they are included. A better alternative might be to introduce a real build process into your application if you need repeatability.
I just found the reason!
There is a file called Mikoto.mp3 in my resources folder and I typed it as mikoto.mp3 in my code. This could be allowed when I use eclipse to run it. But when I run the runnable jar file, it fails because it is case sensitive.
When I change the file name to mikoto.mp3, it works!
Thanks for your answer!
This could sound strange but I want to generate my chart images on server side using JavaFX. Because JavaFX has nice canvas API to perform image transformations joins and positioning.
In particular I have a spring MVC service to generate my charts as images.
The main problem is how to invoke javaFX API from a convenient Spring bean.
If I try to just run javafx code from java application (not extending javaFX Application class) I get
java.lang.IllegalStateException: Toolkit not initialized
Do you have any suggestions/ideas how to solve this issue?
So after some research I've implemented canvas draw with JavaFX and here is a simplified example:
First I made the JavaFX application which is being launched in a separate thread (I use Spring taskExecutor but a plain java thread can be used).
public class ChartGenerator extends Application {
private static Canvas canvas;
private static volatile byte[] result;
public static void initialize(TaskExecutor taskExecutor) {
taskExecutor.execute(new Runnable() {
#Override
public void run() {
launch(ChartGenerator.class);
}
});
}
public static synchronized byte[] generateChart(final Object... params) {
Platform.runLater(new Runnable() {
#Override
public void run() {
ByteArrayOutputStream baos = null;
try {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
/**
* Do the work with canvas
**/
final SnapshotParameters snapshotParameters = new SnapshotParameters();
snapshotParameters.setFill(Color.TRANSPARENT);
WritableImage image = canvas.snapshot(snapshotParameters, null);
BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
baos = new ByteArrayOutputStream();
ImageIO.write(bImage, chartType.outputFormat, baos);
result = baos.toByteArray();
} catch (InstantiationException e) {
throw new ChartGenerationException(e);
} catch (IllegalAccessException e) {
throw new ChartGenerationException(e);
} catch (NoSuchMethodException e) {
throw new ChartGenerationException(e);
} catch (InvocationTargetException e) {
throw new ChartGenerationException(e);
} catch (IOException e) {
throw new ChartGenerationException(e);
} finally {
IOUtils.closeQuietly(baos);
}
}
});
while (result == null) {
//wait
}
byte[] ret = result;
result = null;
return ret;
}
#Override
public void start(Stage stage) {
canvas = new Canvas();
}
public static class ChartGenerationException extends RuntimeException {
public ChartGenerationException(String message) {
super(message);
}
public ChartGenerationException(Throwable cause) {
super(cause);
}
}
}
Then I call the initialize() method when the Spring application is started:
#Autowired private TaskExecutor taskExecutor;
#PostConstruct private void initChartGenerator() {
ChartGenerator.initialize(taskExecutor);
}
This solution of cource can be ported to a non-Spring application.
This is a single-threaded solution (in my case it's enough) but I think it could be adopted to multithreaded usage (maybe use RMI to invoke draw method).
Also this solution works "as is" on my windows workstation but on linux server environment some additional actions should be invoked:
You cannot use JavaFX on OpenJDK (as of Aug 2013) - have to switch to Oracle JDK
Java version must be no less than Java 7u6
The most complex - you have to use virtual display to make JavaFX run on headless environments:
apt-get install xvfb
// then on application server start:
export DISPLAY=":99"
start-stop-daemon --start --background --user jetty --exec "/usr/bin/sudo" -- -u jetty /usr/bin/Xvfb :99 -screen 0 1024x768x24
P.S. You can also use other JavaFX capabilities on server side (e.g. export html to image) with this solution.
In case other people are looking for this, this is a much simpler way.
Using JavaFX 2.2 i was able to perform the following operations.
waitForInit = new Semaphore(0);
root = new Group();
root.getChildren().add(jfxnode);
FxPlatformExecutor.runOnFxApplication(() -> {
snapshot = jfxnode.snapshot(new SnapshotParameters(), null);
waitForInit.release();
});
waitForInit.acquireUninterruptibly();
BufferedImage bi = SwingFXUtils.fromFXImage(snapshot, null);
There is no need to add the node to a group.
From there you can do any operation you want with the image.
The FxPlatformExecutor is from a JME3-JFX library I am using for my project.
See: https://github.com/empirephoenix/JME3-JFX/blob/master/src/main/java/com/jme3x/jfx/FxPlatformExecutor.java
You can easily create the runOnFxApplication() method or create the FxPlatformExecutor class.
Here is the code.
package com.jme3x.jfx;
import javafx.application.Platform;
/**
* TODO This Class should be replaced by some Workmanager implemntation
* in the future
* #author Heist
*/
public class FxPlatformExecutor {
public static void runOnFxApplication(Runnable task) {
if (Platform.isFxApplicationThread()) {
task.run();
} else {
Platform.runLater(task);
}
}
}
I did not write this code, the github link is above.
Perhaps something similar to this solution would be helpful?
JavaFX 2.1: Toolkit not initialized
Otherwise, I would consider creating a service and pushing the image to a datastore and retrieving it in your spring application.
Hope that provides at least a little help!