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(); // 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 frames = new LinkedList(); 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(); }