Why does JavaFX media player crash? - java

I have Java 8 installed correctly and it is the oracle version (NOT OpenJDK). My IDE is Eclipse. When I run the following code in a JavaFX project,
import java.io.File;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class TestPlayer {
static JFXPanel fxPanel =new JFXPanel();
private Media song;
private MediaPlayer mediaPlayer ;
public TestPlayer(String filePath) {
song=new Media(new File(filePath).toURI().toString());
mediaPlayer = new MediaPlayer(song);
}
public void play() {
this.mediaPlayer.play();
}
public static void main(String[] args) {
new TestPlayer("song\\1.mp3").play();
}
}
the mediaPlayer can only play song for several seconds, then no sound and no exception thrown.
Then I changed the line 8 from
private Media song;
to
private static Media song;
And the modified code ran successfully.
I want to know the reason although the problem solved. These 2 following screenshots are taken in the debug mode of Eclipse
Before modification:
After modification:
The difference is "JFXMedia Player EventQueueThread".

You are seeing a garbage collection issue of the media player thread - JFXMedia Player EventQueueThread. Iv'e used VisualVM to monitor the threads and GC.
Your code starts the MediaPlayer and returns, leaving the instance references eligible for GC. Here I have forced a GC a few seconds after launch (at 6:44:57):
and at the same time the JFXMedia Player EventQueueThread stopped:
By making the Media or MediaPlayer static you are tying them to the class loader instead of to the class instance, thus they are not eligible for collection. Generally, you should subclass Application when using JavaFX classes. The class's JavaDoc states:
Threading
JavaFX creates an application thread for running the application start
method, processing input events, and running animation timelines.
The Java launcher loads and initializes the specified Application
class on the JavaFX Application Thread. If there is no main method in
the Application class, or if the main method calls
Application.launch(), then an instance of the Application is then
constructed on the JavaFX Application Thread.
When running your code this way, GC can't collect the JFXMedia Player EventQueueThread. Again, I initiated a GC (at 7:19:04)
and now the thread is still alive:
Notice that the main thread is also there along with the JavaFX-Launcher.
For a true deep analysis you must inspect a heap dump, but hopefully this insight is enough for the scope of the question.

Related

Javafx music player not working

I'm coding a game in java, and I decided to add music to it. I tried with this code:
URL resource = getClass().getResource("music.mp3");
MediaPlayer a = new MediaPlayer(new Media(resource.toString()));
a.setOnEndOfMedia(new Runnable() {
public void run() {
a.seek(Duration.ZERO);
}
});
a.play();
But for some reason, I get this error:
https://pastebin.com/UPkTbWHh
The file music.mp3 is in the same folder as the class I'm running it from, and the code is running in the tick() method. Do anybody have an idea about how I can fix this?
Thanks, Lukas
You're attempting to execute the above code from outside the context of a JavaFX app. MediaPlayer is a JavaFX component, so relies on the Toolkit being initialised, you can't (by default) just spin up a JFX component as you please.
The "proper" way is to subclass a JFX Application and then launch your application from there, which will initialise the JFX platform properly.
The "hack" way is to run the following line of code in the Swing EDT:
new JFXPanel();
...which will also have the side effect of initialising the JFX toolkit and allow you to create other JFX components.
As pointed out in the comments, since Java 9 you can use the less hacky method of:
Platform.startup(() -> {
//Code to run on JFX thread
});

Linux Mint Cinnamon Lock-Up Debugging w/Eclipse

I have a reproducible problem with the Mint Cinnamon desktop locking up when hitting a breakpoint debugging with Eclipse. When I say it's locking up, I mean mouse clicks are completely inoperable (even on the Mint panel), but the mouse cursor still moves. Keyboard is unresponsive, except for some OS-level shortcuts like Alt-Tab. Alt-Tab looks like it's working, but selecting another window doesn't actually focus or activate the window (only the Alt-Tab selector popup works). I can only recover using Ctrl-Alt-ESC to restart Cinnamon. Everything proceeds fine after that.
Debugging and breakpoints work fine everywhere else as far as I can tell except when the breakpoint is inside an anon inner class or lambda.
Public git repo with a fairly simple example project causing this:
https://bitbucket.org/jfxexamples/eclipseminttest
Linux Mint 17.3 AND a totally new install of Mint 18 on a different PC - both behave the same
Eclipse Neon 4.6.0
Java 8 (1.8.0_92) - Oracle JDK (Using JavaFX)
Code below (you'll have to grab the project files to run it though):
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
package application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
public class SampleController {
#FXML
private TabPane tabPane;
public void createTab() {
Tab tab = new Tab("New tab");//Breakpoint here does NOT freeze desktop
// tab.setOnCloseRequest(e -> {
// System.out.println("bleh");//Breakpoint here, freezes desktop
// });
tab.setOnCloseRequest(new EventHandler<Event>(){
#Override public void handle(Event e){
System.out.println("bleh");//Breakpoint here, also freezes desktop
}
});
tabPane.getTabs().add(tab);//Breakpoint here does NOT freeze desktop
int index = tabPane.getTabs().size() - 1;
tabPane.getSelectionModel().select(index);
}
}
Using Win10/IntellijCE/JDK1.8.0_92 there is no problem. Try using IntellijCE on Mint. If it works the problem is most likely with Cinnamon.
Cinnamon is on Github, so use their Issue Tracker there to report the bug.
Browsing the issues, there is even something maybe related to your issue: Check out https://github.com/linuxmint/Cinnamon/issues/1084.
I have had exactly the same problem in Linux Mint 17.3 Mate, with JDK 1.8.0_101, Eclipse Neon and a JavaFX application.
When debugging the application, the system freezes completely and I have to kill the process manually.
It seems a problem related with the X display. It should work if you set, in the VM arguments of your application, the flag:
-Dsun.awt.disablegrab=true
At least that worked for me...
This is a known problem on Linux. It is related to the XGrabPointer and XGrabKeyboard API calls (see X Pointer Grabbing). This API can be used by screensavers, so it is intended to make the keyboard and mouse unusable (apart from moving the mouse cursor).
During debugging, it is a problem. In the past, a workaround was to configure AllowDeactivateGrabsin xorg. That allowed to break the "grap" by a keyboard shortcut, by default CTRL+ALT+/. Since it was possible to bypass screensavers, it was disabled around 2012 because of its security implications.
On a modern Linux system, you can enable enable grab break actions:
setxkbmap -option grab:break_actions
Now, you can trigger a grab break by executing:
xdotool key XF86Ungrab
Once your keyboard is frozen, you might be not able to run it, so during debugging, I am calling it every two seconds:
while :; do sleep 2 ; xdotool key XF86Ungrab ; done
Notes:
setxkbmap is part of xorg-setxkbmap
xdotool is part of xdotool
While testing the setup, it is useful to have a ssh connection from another machine. Thus, if mouse and keyboard freeze up, you can always kill the process that grabbed the mouse and keyboard.

How to force ImageJ to close all its windows without close event error?

I am writing a Java application for image analysis which at one point opens ImageJ with
ImageJ ij = new ImageJ();
and also opens a Windows containing an ImagePlus.
Now, whenever one closes ImageJ first, the ImagePlus will not close when pushing the close button. The other way around works, however in both cases an exception is thrown after closing ImageJ:
java.lang.reflect.InvocationTargetException
at java.awt.EventQueue.invokeAndWait(EventQueue.java:1288)
at java.awt.Window.doDispose(Window.java:1209)
at java.awt.Window.dispose(Window.java:1147)
at ij.ImageJ.run(ImageJ.java:784)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: null source
at java.util.EventObject.<init>(EventObject.java:56)
at java.awt.AWTEvent.<init>(AWTEvent.java:337)
at java.awt.event.InvocationEvent.<init>(InvocationEvent.java:285)
at java.awt.event.InvocationEvent.<init>(InvocationEvent.java:174)
at sun.awt.X11.XBaseMenuWindow.dispose(XBaseMenuWindow.java:907)
...
I don't know whether it is related as it happens in both cases.
Any suggestions on how to force ImageJ to close all its windows?
The exception
This happens when using OpenJDK 7 on Linux. The exception is fixed in Java 8.
Also: note that that exception is not the actual cause of the quitting issue you are seeing.
The disposal problem
ImageJ 1.x's application disposal is a convoluted mess. (See this news post for some technical discussion.) It was really intended primarily to run as a standalone application, and is mostly tested with the exitWhenQuitting flag set to true such that the JVM shuts down upon closure of the main window. So it is not surprising that using ImageJ in a different fashion results in hanging image windows.
I have tested various workarounds—e.g.:
ij.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(final WindowEvent e) {
// dispose all image windows
for (final int id : WindowManager.getIDList()) {
final ImagePlus imp = WindowManager.getImage(id);
if (imp == null) continue;
final ImageWindow win = imp.getWindow();
if (win != null) win.dispose();
}
// dispose all other ImageJ windows
for (final Window w : WindowManager.getAllNonImageWindows()) {
w.dispose();
}
}
});
But none of them work as one might hope. It cost me weeks of development and experimentation to make quitting work as we wanted in ImageJ2, according to the news posted linked above.
Here is some code using ImageJ2 that almost behaves the way you want:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import net.imagej.ImageJ;
public class IJDispose {
public static void main(final String... args) {
final ImageJ ij = new ImageJ();
ij.ui().showUI();
final JFrame frame = new JFrame("Hello");
final JButton b = new JButton("Close ImageJ");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
ij.getContext().dispose();
}
});
frame.getContentPane().add(b);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
After launching it, press Shift+B to open the Blobs sample image. Then click the "Close ImageJ" button from the non-ImageJ frame. You'll see that the ImageJ main window and the image window dispose as desired (using this code from ImageJ Legacy).
However, there are (at least) three problems:
This example does not hook up the ij.getContext().dispose() call to the actual ImageJ1 UI window closing event. And doing that would not be trivial (I say without having dug deeply in this code recently).
After disposing ImageJ, as well as the extra JFrame, the JVM is supposed to shut down. We put a lot of effort into making it do so, actually. But it actually doesn't with the current version of ImageJ, presumably due to some undisposed resource(s) somewhere. This is a bug.
Clicking the X on the main ImageJ window shuts down the entire JVM, because ImageJ1's exitWhenQuitting flag gets set to true. You could toggle it back to false yourself, but this is actually tricky due to class loading issues relating to the fact that ImageJ2 patches ImageJ1 at runtime using Javassist.
The next question is: How badly do you really need this to work?

How to terminate a scheduled thread when JavaFX Runtime exits?

I'm looking over similar examples to this problem. We have a JavaFX app which runs some GUI updates via thread running from: ScheduledExecutorService::scheduleAtFixedRate.
This is similar to a couple of other questions. The two I recognised as most like my situation are these:
JavaFX Task threads not terminating
how to stop "JavaFX Application Thread"
The question I need to resolve, however, is about the next step. My target is for an embedded application and there's no opportunity to manually kill the JVM-task, or the other easy answers, etc. I'm afraid a reboot is reserved for something critically-serious.
We need to ensure that all threads are closed off in an orderly way. What I'm looking for is some kind of call back or event that lets me register a clean-up routine to close-down my stuff?
I was thinking that there ought to be 'something' in the base class, JavaFX javafx.application.Application to do the deed.
http://docs.oracle.com/javafx/2/api/javafx/application/Application.html
Is the Stop method something I might use or can I register to be called when there is a stop from my FXMLController?
At present when I run my JavaFX app from Netbeans, the JVM process persists. This stops any further build scripts and locks the JAR file. Netbeans gives you an option to kill the task. The true solution means that the application/JVM closes-down orderly and neatly.
(update) ... I looked into the javafx.Application class that you use to launch the JavaFX app. I implemented a Stop() method. Here I make sure that I've called Platform.exit() ...
/////
// #see
// -- http://docs.oracle.com/javafx/2/api/javafx/application/Application.html#stop%28%29
//
public void stop()
{
Platform.exit();
}
This doesn't cure the problem when running from NetBeans. Sometimes you need to click the stop [X] button two times, but the process does stop when you use the kill button. If you are interested in progress this is reported as bug: [Bug 245284], there's a small clock example to demonstrate the problem. When you close the window, the NetBeans process running panel is still 'running'. You can't build because the JAR file is locked. At least we know to manually kill the development program.
Suggestions welcome . . .
I have a partial solution to cover fellow developers who get caught in this situation. Declare a stop() method in in your JavaFX app (called "MainApp" by the Netbeans Maven JavaFX template). There are questions of course, but first the method.
See: JavaFX Application
Stop is called at the end of your program. I had the call to call Platform.exit() to close-down JavaFX runtime. I've added a call to shutdown other active Executor threads, which I kept in an list for now, to test the solution.
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
.....
}
/**
* Close down the application
* #see
* -- http://docs.oracle.com/javafx/2/api/javafx/application/Application.html#stop%28%29
**/
#Override
public void stop()
{
Platform.exit();
for( ScheduledExecutorService sched : activeExecutorServices )
{
sched.shutdown();
}
}
}//MainAppl class
So by commenting-out the call to shutdown and running my JavaFX program, the application finishes but won't exit, and Netbeans show a running task. You need to manually click on the kill-button in Netbeans.
Uncomment the shutdown() call. When the JavaFX application exits, it also dissappears from the Netbeans running jobs. That appears to be a resolotion.
The remaining questions:
What is the correct order between Platform.exit() and shutdown()?
With more than one ScheduledExecutorService does it matter which order is used to shut them-off? LIFO or FIFO?
Is there a better way?
Ought Netbeans be able to detect the 'process overrun' and report this as a problem. That at least leave you and I with the option to ignore it or fix the program.
Hopefyully that will assist the next someone who faces a similar problem :-)
you can use setOnCloseRequest
#Override
public void start(Stage primaryStage) {
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
ThreadPool.shutdown();
}
});
initGui(primaryStage);
initData();
}

Unable to take video screenshots in java code

I have written a code using vlcj which is intended to take screenshots of a video periodically. When I try to output the length of the video, it prints 0. What is the issue ?
import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
public class ScreenShotCapture {
public static void main(String[] args){
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "C:\\Program Files\\VideoLAN\\VLC");
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
MediaPlayerFactory mediaPlayerFactory = new MediaPlayerFactory();
final EmbeddedMediaPlayer mediaPlayer =mediaPlayerFactory.newEmbeddedMediaPlayer();
mediaPlayer.playMedia("E:\\videos\\Avenged Sevenfold - So Far Away [Music Video].mp4");
mediaPlayer.setSnapshotDirectory("E:\\vidoes");
long length = mediaPlayer.getTime();
long interval = length / 21;
for(long i = 1;i <= length;i+= interval){
mediaPlayer.setTime(i);
mediaPlayer.saveSnapshot();
}
}
}
The media length is not immediately available, it will become available some time after the media has started playing when the decoder works out what the length is. That is just inherently how VLC works.
Just about everything works asynchronously, which means you must base your code on events rather than writing code in only a procedural way.
When the length changes a native event gets generated, ultimately causing a MediaPlayerEventListener#lengthChanged event to fire. When that event has fired, the call to mediaPlayer.getLength() should return a non-zero value.
The next issue is that you invoke saveSnapshot immediately after you invoke setTime. Again, setTime works asynchronously so you can not assume that the media player has reached the desired time when that method returns. You have to wait for a timeChanged event and check if your time has been reached (actually passed) yet or not.
The final issue, that may or may not be important depending on your use-case, is that the call to saveSnapshot is itself asynchronous so essentially you have requested a snapshot but it has not been generated yet. This time you need to wait for the snapshotTaken event. Only when that event has been received has the snapshot actually been saved to disk.
So basically you need to think differently and implement an event-based approach instead.
One example of that is in this vlcj example that generates snapshots: https://github.com/caprica/vlcj/blob/vlcj-3.0.1/src/test/java/uk/co/caprica/vlcj/test/condition/ConditionTest.java
If you don't like that example, then you can implement it just by responding to the events in your own MediaPlayerEventListener implementation.
An aside: you can also use the VLC "Scene" filter to generate snapshots in a reliable way.
I assume it's not caused by your spelling mistake in setting the snapshot directory?

Categories