JavaFX MediaView rendering a white video - java

TL;DR : Solution : Increase the JavaFX version to 15.0.1.
I am re-writing the question I asked yesterday because it was poorly formulated and poorly explained.
What I do : I use JavaFX to create a Media and a MediaView to render a .mp4 video in a scene.
What happens : The screen stays blank.
What should happen : The video should be rendered properly and visible by the user.
What I've tried :
Changing the file encoding (from H.264 to QuickTime (outputs as .mov)).
Result : QuickTime encoding isn't recognized by JavaFX.
Changing the FPS value from 30 to 60 and from 60 to 30.
Result : no difference.
Tweaking the file size by shortening the video.
Result : no difference.
Changing the video resolution scale from 16:9 to 16:10.
Result : no difference.
Changing the video resolution value from 2560x1440 to 1920x1080.
Result : the video is shown on the screen, but I need a 2560x1440 video to fill the screen. I will take care of different resolutions later on by myself.
Using different videos from my computer.
Result : resolutions less or equal to 1920x1080 are working fine. I tried video a different video with a 2560x1440 resolution and it does not work.
Using a 2560x1440 video referenced by an internet URL.
Result : same behavior as described above.
My code :
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
import java.io.File;
public class Application extends javafx.application.Application {
Stage window;
#Override
public void start(Stage primaryStage) {
window = primaryStage;
window.setWidth(2560);
window.setHeight(1440);
window.setX(0);
window.setY(0);
window.setResizable(false);
window.setFullScreen(true);
window.setFullScreenExitHint("");
Pane pane = new Pane();
// Example to show that adding a simple figure to the pane works fine.
javafx.scene.shape.Rectangle r = new javafx.scene.shape.Rectangle(0, 0, 150, 150);
Media media = new Media(new File(/*Insert file name you own for testing purposes*/).toURI().toString());
// The path I would use : "src\\main\\resources\\img\\Animated Titlescreen Background.mp4".
// This is obtained using other classes and methods that read the computer directories,
// so it works fine across different computers.
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
MediaView mediaView = new MediaView(mediaPlayer);
pane.getChildren().addAll(mediaView, r);
Scene scene = new Scene(pane, 2560, 1440);
window.setScene(scene);
window.show();
}
public static void main(String[] args) {
launch(args);
}
}

After reading more on this link, it says Windows 8 increase H.264 decoder resolution to 4096x2304, which is available on JavaFX version 15.0.1. I was using version 12.0.1 because of a critical issue on Linux with version 15.0.1.
Solution : Increase the JavaFX version to 15.0.1.

Related

JavaFX ImageView display GIFanimation high GPU [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am creating JavaFX application and made a loading scene. In this scene i want to show some text like loading or initializing and add some loading spinner animated image as a visual notification that something is loading.
I generate a loading .gif animation created via https://loading.io/ and also downloaded it like frames of animation (multiple .png files).
I noticed that in the JavaFX Scene Builder 8.5.0 when I set the .gif in ImageView, my GPU in Windows task manager went up to 20%, on NVidia GeForce RTX 2070 graphic card and in my opinion this is a problem. I tested with a javafx desktop application, to rule out that is not a problem generated by the scene builder application and got similar results.
The next step that i tried is to create my custom animation using javafx.​animation.Timeline. This is the initializing function that i call from the controller initialize(URL location, ResourceBundle resources) function. This function doesn't use the .gif image, it uses the multiple .png images of the same .gif image as frames.
private void initializeAnimation() {
imgLoading.setCache(true);
imgLoading.setCacheHint(CacheHint.SPEED);
Image[] images = new Image[31];
for(int i = 0; i <= 30; i++){
images[i] = new Image(getClass().getResourceAsStream("/es/main/gui/javafx/images/loading/frame-" + i + ".png"));
}
Timeline timeLine = new Timeline();
Collection<KeyFrame> frames = timeLine.getKeyFrames();
Duration frameGap = Duration.millis(100);
Duration frameTime = Duration.ZERO;
for (Image img : images) {
frameTime = frameTime.add(frameGap);
frames.add(new KeyFrame(frameTime, e -> imgLoading.setImage(img)));
}
timeLine.setCycleCount(Timeline.INDEFINITE);
timeLine.play();
}
In the first version i didn't call .setCache() and .setCacheHint() functions, I added them later while testing different variations of the same code. Also i tried adding
-Dprism.forceGPU=true -Dsun.java2d.opengl=true -Dprism.order=es2,es1,sw,j2d
as VMOption or some variants that I have read on this forum on improving graphic related settings for java. At the end, after all the changes, results in my task manager didn't change drastically. In the current version i use up to 17% of my GPU on this scene.
When the scene ends, in the next scene with no .gif images or Timeline's my GPU drops to almost 0%.
Running configurations:
Processor: i9-9900KF
Graphic card: GeForce RTX 2070
Java version "1.8.0_251"
JavaFX version "8.0.251-b08"
Short summary question: How to display animated .gif images correctly in JavaFX without having drastic overhead on the GPU (or CPU when with integrated graphics).
(Edit) 14.09.2020 - Java naming conventions
First thing I didn't noticed that i was not using the same size on my ImageView, so the first thing i changed for testing is adjusting the ImageView the same size as my .gif image (same width and height on both ImageView and .gif image). With this change the GPU percentage lowered to about %5.
As suggested I also upgrading the Java and JavaFX versions:
Tried using the jdk 1.8.0_261 with JavaFX built in version 8.0.261-b12 and got similar results.
Tried using jdk 14.0.2 with JavaFX version 15+9 (latest openjfx-15) and still got similar results.
Short summary: Upgrading the Java and JavaFX version didn't change anything relating this issue. Using the same size helped, but I think I can improve even better with your help.
My guess is you'd probably see some performance gains if you used one or more RotateTransition rather than key frame animation.
Here's a simple example using multiple transitions in a ParallelTransition:
import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 500, 200);
stage.setScene(scene);
Rectangle rect = new Rectangle (100, 40, 100, 100);
rect.setArcHeight(50);
rect.setArcWidth(50);
rect.setFill(Color.VIOLET);
RotateTransition rt = new RotateTransition(Duration.millis(3000));
rt.setByAngle(180);
rt.setAutoReverse(true);
FadeTransition ft = new FadeTransition(Duration.millis(3000));
ft.setFromValue(1.0);
ft.setToValue(0.3);
ft.setCycleCount(4);
ft.setAutoReverse(true);
ParallelTransition pt = new ParallelTransition(rect, ft, rt);
pt.play();
root.getChildren().add(rect);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

How to convert an image into a shape in Java?

I'm currently working on a stock market program that teaches students how to interact with the stock market. An issue that I'm working on right now revolves around the issue of efficiency and memory. I make all of my 2D icons (such as a settings icon, portfolio icons, etc) in adobe illustrator, I export those files as png files, and throw them into my program. I currently use JavaFX, and one of the features of JavaFX is what's called imageView, which is a method that handles the opening and viewing of images.
So let's say that the user would like to press on the Settings icon in the game, I would like to change the settings icon to a darker or lighter color when the user hovers over that icon in order to provide the user with a better user experience (UX) at the moment, I use two different images and remove one from the frame, and replace it with another, which is highly inefficient.
I know that JavaFX has a Shape class that inherits many methods such as Fill, or setFill, but these methods can only affect those of the Shape class.
My question is, "How can I convert an image that is imported into the project, into something that I can use methods such as setFill and Fill on"
If you're only aiming for basic changes such as darkening or lightning your icons, you can look at the Effects part of javaFx, you can read about it here, or else you can import your images as SVG as suggested in the comments
If you're planning to do it using Effects, you can achieve a darken-on-hover effect using the ColorAdjust Effect by setting the brightness value to something negative (the brightness in ColorAdjust ranges between -1 and +1 where 0 is the default) as in the following example
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage s) {
ImageView image = new ImageView(new Image("img.png"));
ColorAdjust darker = new ColorAdjust();
darker.setBrightness(-.3);
image.setOnMouseEntered(e-> {
image.setEffect(darker);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});
s.setScene(new Scene(new StackPane(image)));
s.show();
}
public static void main(String[] args) {
launch(args);
}
}
Changing the color of an image might involve adjusting the hue using ColorAdjust by setting the hue value
ColorAdjust hueShift = new ColorAdjust();
hueShift.setHue(-.3);
image.setOnMouseEntered(e-> {
image.setEffect(hueShift);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});
You can combine effects by setting effects as input to other effects, so for example, if you want to darken a Node and blur it at the same time you can set the blur effect as input to the darkening colorAdjust
GaussianBlur blur = new GaussianBlur();
blur.setRadius(10);
ColorAdjust darker = new ColorAdjust();
darker.setBrightness(-.3);
darker.setInput(blur);
image.setOnMouseEntered(e-> {
image.setEffect(darker);
});
image.setOnMouseExited(e-> {
image.setEffect(null);
});

JavaFX - Music On/Off Toggle Button (Not Working)

Below is the code sample, with other features left out. The code below encompasses the media player only. It's used on a menu screen for a project I'm working on. My issue is getting the musicButton (which is a toggle button- On/Off) to work properly. Using the following code, when I interact with the music toggle button, the playing music stops. When I click it again to resume playing, it does not resume. It stops once and stops altogether.
You can see I've tried simply using the boolean values of the toggle button in two if statements... If it's off and pressed, pause the music. If its on and pressed, resume the music. The problem is, as stated earlier, pausing the music works but it cannot be resumed. I've tried some combinations with loops, but nothing worked either.
I think if statements are too simple for this. I've scoured the JavaDocs and various online articles but I cannot find anything definitive. I've read a little about listeners, but they seem overly-complex for an on/off switch.
My question:
How do I get the musicButton to pause/play the music, whenver the user clicks it?
Any help is appreciated, thanks.
-Bagger
/* A simple game, the mechanics not yet implemented.
This is simply working on the title screen. */
import java.io.File;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
public class MenuFX extends Application {
#Override
public void start (Stage primaryStage) {
// Make the window a set size...
primaryStage.setResizable(false);
// Create media player
// Rather than inputting the entire absolute URI, which would confine the program
// to the creator's device, we create a new file, grab the URI on whatever machine
// the program is running on and convert it to a string... portability.
Media menuMusic = new Media(new File("music/menu.mp3").toURI().toString());
MediaPlayer menuPlayer = new MediaPlayer(menuMusic);
// Want to see the absolute URI? Uncomment the next line
//System.out.println(new File("music/menu.mp3").toURI().toString());
// Adjust the cycles and volume then start playing menu music
// Lazy, but it will suffice
menuPlayer.setCycleCount(999999999);
menuPlayer.setVolume(0.1);
menuPlayer.setAutoPlay(true);
/*
Need assistance here
*/
// Create music toggle button
ToggleButton musicButton = new ToggleButton("Music On/Off");
if (musicButton.isSelected() == false) {
musicButton.setOnAction(e -> menuPlayer.pause());
}
if (musicButton.isSelected() == true) {
musicButton.setOnAction(e -> menuPlayer.play());
}
// Add all nodes to the vbox pane and center it all
// Must be in order from top to bottom
menuVBox.getChildren().add(musicButton);
menuVBox.setAlignment(Pos.CENTER);
// New scene, place pane in it
Scene scene = new Scene(menuVBox, 630, 730);
// Place scene in stage
primaryStage.setTitle("-tiles-");
primaryStage.setScene(scene);
primaryStage.show();
}
// Needed to run JavaFX w/o the use of the command line
public static void main(String[] args) {
launch(args);
}
}
I think you are over thinking it. You should have an EventListener on your ToggleButton to Pause and Play the music.
musicButton.setOnAction(event -> {
if (musicButton.isSelected()) {
menuPlayer.pause();
}else {
menuPlayer.play();
}
});
This should give you the desired effect.
The reason your code was not working is because the ToggleButton is not selected by default, so the only EventListener that gets associated with it is the menuPlayer.pause();. So when you click on it, it only ever pauses. I have moved your code into one EventListener, and used the approriate if-else.

How to control volume in vlcj?

I am creating a project for my college using vlcj. this is my code
public class MediaPlayerUI extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public static EmbeddedMediaPlayer mediaPlayer;
public static FullScreenStrategy fullScreenStrategy;
public MediaPlayerUI(String title) {
super(title);
// finding native library of vlc player
new NativeDiscovery().discover();
//setting a layout
setLayout(new BorderLayout());
//setting up mediaplayer components
String[] libvlcArgs = {};
MediaPlayerFactory mediaPlayerFactory = new MediaPlayerFactory(libvlcArgs);
mediaPlayer = mediaPlayerFactory.newEmbeddedMediaPlayer(fullScreenStrategy);
//creating swing Components
Canvas canvas = new Canvas();
//setting up the video surface
CanvasVideoSurface videoSurface = mediaPlayerFactory.newVideoSurface(canvas);
mediaPlayer.setVideoSurface(videoSurface);
//adding swing components to contant pane
Container UIContainer = getContentPane();
UIContainer.add(canvas,BorderLayout.CENTER);
}
}
and this
package andromedia;
import javax.swing.JFrame;
import uk.co.caprica.vlcj.player.embedded.DefaultFullScreenStrategy;
public class MainPlayer {
public static void main(String args[])
{
JFrame mainFrame = new MediaPlayerUI("AndroMedia");
mainFrame.setVisible(true);
mainFrame.setSize(500,500);
mainFrame.setDefaultCloseOperation(3);
MediaPlayerUI.fullScreenStrategy = new DefaultFullScreenStrategy(mainFrame);
MediaPlayerUI.mediaPlayer.playMedia("E:\\Media\\flash.mp4","Volume=0");
MediaPlayerUI.mediaPlayer.setVolume(0);
System.out.println(MediaPlayerUI.mediaPlayer.getVolume());
}
}
I cant control the volume
when I print the current volume I get the value "-1"
and am getting the following runtime errors
-1
[000000000d670bd0] main vout display error: Failed to set on top
[000000000d670bd0] main vout display error: Failed to resize display
any help would be greatly appreciated
thank you .
Volume is a bit problematic with recent versions of VLC. In older versions of VLC there was not a problem.
In 2.1, it is simply not possible to set/get the volume before media playback has actually begun. As you have described, you get a value of "-1".
So you have to find some other way, like using a MediaPlayerEventListener and waiting for a media player "playing" event and even then you may need to wait for a little bit longer using e.g. by sleeping for 500ms or so before setting/getting the volume.
Clearly that's a pretty bad solution, but unfortunately that's just the way it is.
With VLC 2.2+, the situation is a little bit better. You can now set/get the volume before playback has actually begun, but if you stop the media player (pause is OK, but not stop) then you can no longer set/get the volume until you play media again.
There is a thread at the VLC forums here with the same conclusions:
https://forum.videolan.org/viewtopic.php?f=32&t=104345
So because of this issue in LibVLC, the same issue appears in vlcj with no perfectly satisfactory solution (at the moment).
In your code, you do this:
mediaPlayer.playMedia(...);
mediaPlayer.setVolume(0);
mediaPlayer.getVolume();
You need to be aware that playMedia actually starts media player asynchronously, so at the point that function returns, and you try to set the volume immediately after, the media is absolutely not guaranteed to have actually started yet and because of this issue you can't set/get the volume yet.
To summarise, there is no ideal solution available to this right now, and it will likely require a change to LibVLC unless you are prepared to live with sub-optimal workarounds.
By the way, those "main vout display error" messages are irrelevant.

Animated Splash Screen on Netbeans Platform app

Our maven/Netbeans platform application uses a custom image on startup, by replacing
Nbm-branding > core.jar > org.netbeans.core.startup > splash.gif
I tried making it an animated .gif, but only the first frame is displayed.
How would one possibly go about implementing an animated splash screen, maybe by running some JavaFX window animations?
I've seen another other SO question, but it wasn't really answered - please notice I'm asking about how to integrate a custom splash screen with my Netbeans Platform application, and not how to actually build it.
Surprisingly enough, I found out how to plug in a custom splash screen based on this post about user authentication and authorization.
Basically, one needs to write another start-up class, instead of the platform's default:
import java.lang.reflect.Method;
public class CustomStartup {
private static final String NB_MAIN_CLASS = "org.netbeans.core.startup.Main";
public static void main(String[] args) throws Exception {
// do whatever you need here (e.g. show a custom login form)
System.out.println("Hello world! I am a custom startup class");
JWindow splash = initSplash();
// once you're done with that, hand control back to NetBeans
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
Class<?> mainClass = Class.forName(NB_MAIN_CLASS, true, classloader);
Object mainObject = mainClass.newInstance();
Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
mainMethod.invoke(mainObject, (Object) args);
splash.setVisible(false);
}
}
In that class, one can create a JavaFX stage, embed it into a JWindow, and show it:
public JWindow initSplash(){
JWindow window = new JWindow();
final JFXPanel fxPanel = new JFXPanel();
window.add(fxPanel);
window.setVisible(true);
window.setLocationRelativeTo(null);
Platform.runLater(new Runnable() {
#Override
public void run() {
Scene scene = new Scene(new CustomFxSplash(), 475, 300, true);
fxPanel.setScene(scene);
}
}
return window;
}
Other things to remember are:
Suppress the original NetBeans splash screen by running your app with the --nosplash parameter.
Call your custom initialization class by running your app with the -J-Dnetbeans.mainclass=com.package.splash.CustomStartup parameter
As the link suggests this custom class has to be on the platform's initialization classpath, meaning inside the platform/core folder.
The current version of the NetBeans class that is responsible for rendering the splash screen can be viewed online here: org.netbeans.core.startup.
The culprit code that prevents the gif from animating is this line (line 546)
graphics.drawImage(image, 0, 0, null);
In order for the gif to animate the ImageObserver will have to be specified instead of being set to null and then repaint must be called when imageUpdate() is called on the ImageObserver.
An example of displaying an animated gif can be viewed here: Relationship Between Animated Gif and Image Observer
So as far as I can see you will either have to change the above NetBeans platform code and rebuild it for your application or you will have to create your own splash screen from scratch to use instead of the NetBeans one.
Hope you find this useful!

Categories

Resources