Play audio file with JavaFX mediaplayer from another class - java

Media player class is good. However, I can't play a mp3 file stored in another class (when mouse clicked). Could someone check my code?
package mediaplayer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.stage.Stage;
public class MediaPlayer extends Application {
private static final String MEDIA_URL = "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv";
private static String arg1;
#Override public void start(Stage stage) {
stage.setTitle("Media Player");
Group root = new Group();
Scene scene = new Scene(root,600,265);
// create media player
Media media = new Media((arg1 != null) ? arg1 : MEDIA_URL);
javafx.scene.media.MediaPlayer mediaPlayer = new javafx.scene.media.MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
MediaControl mediaControl = new MediaControl(mediaPlayer);
scene.setRoot(mediaControl);
scene.getStylesheets().add(MediaPlayer.class.getResource("mediaplayer.css").toExternalForm());
// show stage
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
if (args.length > 0) {
arg1 = args[0];
}
Application.launch(args);
}
}
This is the class I am trying to use to play my audio file:
package mediaplayer;
import java.awt.Cursor;
/**
*
* #author Yves
*/
public class LacherPrise extends javax.swing.JFrame {
/**
* Creates new form LacherPrise
*/
public LacherPrise() {
this.setVisible(true);
// définition de la taille de la fenêtre de l’éditeur
setBounds(200, 100, 800, 600);
initComponents();
}
When I run the program (on the mouseclicked below), I get these two errors:
Error no1: Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: Not yet implemented
Error no2:Exception in thread "Thread-3" java.lang.IllegalStateException: Toolkit not initialized
I would need help on how to implement Exception.
private void audio010MouseClicked(java.awt.event.MouseEvent evt) {
//getting URL to a sound file stored locally
String MEDIA_URL = "file:///C:/Users/Yves/Documents/NetBeansProjects/ExamenFinSessionJavaFX/src/RessourcesLacherPrise/Aff010.mp3";
Media media = new Media(MEDIA_URL.toString());
MediaPlayer MediaPlayer = new MediaPlayer();
MediaPlayer.play(MEDIA_URL);
}

The main problem i believe is that the JavaFX toolkit has not been initialized. Take a look at the following question:
JavaFX 2.1: Toolkit not initialized
Simply putting this at the start of your code could solve the problem:
new JFXPanel();

Related

Difficulty with URI syntax and conversion to string

My friend and I have been working on a Java project to create a simple media player using the Media, MediaPlayer, and MediaView classes. However, from the start we've had issues successfully opening the video that we're using as a test file. After many angry runtime exceptions, we finally figured out that the source of our problem was the String being passed into each object (Media needs a String that represents the File Path in a URI format). After some modifications, we found that the following URI worked on my computer to open the File:
Media m = new Media("file:///C:/Users/mewww/Google%20Drive/Java/SmartPlay/EXO-MonsterMV.mp4");
MediaPlayer mp = new MediaPlayer(m);
MediaView mv = new MediaView(mp);
However, we later tried to implement an Open method that would allow the user to choose which File (as a File object) they wanted to play. When we did this, we used the following to open the file:
File currentFile = new File(null);
FileChooser fc = new FileChooser();
fc.setTitle("Open");
currentFile = fc.showOpenDialog(null);
Media m = new Media(currentFile.toURI().toString());
MediaPlayer mp = new MediaPlayer(m);
MediaView mv = new MediaView(mp);
This started giving us runtime exceptions again and so we used a println into the console to find out what the problem was. The string being used was now two "/"s short of what it was supposed to be as:
"file:/C:/Users/mewww/Google%20Drive/Java/SmartPlay/EXO-MonsterMV.mp4"
However, even after modifying the string, we still received the same runtime error as soon as the file was selected:
Exception in Application start method
java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
We then commented the whole Open method out and went back to our original code, but continue to receive the same errors.
Our full code is available here:
SmartPlay class
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import java.io.File;
import javafx.stage.FileChooser;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.application.Platform;
public class SmartPlay extends Application {
File currentFile;
Scene scene;
#Override
public void start(Stage primary) {
primary.setTitle("SmartPlay");
selectCurrentFileToOpen();
//Player(currentFile.toURI().toString().substring(0,5)+"//"+currentFile.toURI().toString().substring(5));
Player player = new Player("file:///C:/Users/mewww/Google%20Drive/Java/SmartPlay/EXOMonsterMV.mp4");
scene = new Scene(player, 720, 480, Color.BLACK);
player.setTop(makeMenus());
primary.setScene(scene);
primary.show();
}
private MenuBar makeMenus() {
MenuBar mb = new MenuBar();
Menu fileMenu = new Menu("File");
MenuItem openItem = new MenuItem("Open...");
openItem.setOnAction(e -> {
selectCurrentFileToOpen();
scene.setRoot(new Player(currentFile.toURI()));
});
MenuItem quitItem = new MenuItem("Quit");
quitItem.setOnAction(e -> Platform.exit());
fileMenu.getItems().addAll(openItem, quitItem);
return mb;
}
public boolean selectCurrentFileToOpen() {
FileChooser fc = new FileChooser();
fc.setTitle("Open");
currentFile = fc.showOpenDialog(null);
return true;
}
public void stop() {
}
public static void main(String[] args) {
launch(args);
}
}
Player class
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import java.net.URI;
public class Player extends BorderPane {
Media m;
MediaPlayer mp;
MediaView mv;
Pane p;
MediaBar bar;
public Player(String file) {
m = new Media(file);
mp = new MediaPlayer(m);
mv = new MediaView(mp);
p = new Pane();
p.getChildren().addAll(mv);
setCenter(p);
bar = new MediaBar(mp);
setBottom(bar);
setStyle("-fx-background-color:#cccccc");
mp.play();
}
}
MediaBar class
import javafx.scene.layout.HBox;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.media.MediaPlayer;
import javafx.scene.layout.Priority;
import javafx.scene.control.Slider;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.util.Duration;
public class MediaBar extends HBox {
Slider time = new Slider();
Slider vol = new Slider();
Button playButton = new Button("Pause");
Button halfSpeed = new Button("0.5x");
Button normalSpeed = new Button("1.0x");
Button doubleSpeed = new Button("2.0x");
Label volume = new Label("Volume: ");
Label nowTime;
MediaPlayer player;
public MediaBar(MediaPlayer play) {
player = play;
setAlignment(Pos.CENTER);
setPadding(new Insets(5,10,5,10));
vol.setPrefWidth(70);
vol.setMinWidth(30);
vol.setValue(100);
nowTime = new Label(formatTime(player.getCurrentTime()) + "/" + formatTime(player.getTotalDuration()));
HBox.setHgrow(time, Priority.ALWAYS);
playButton.setPrefWidth(30);
getChildren().addAll(playButton,time,nowTime,volume,vol);
}
public static String formatTime(Duration duration) { //StackOverflow: Jon Skeet
long seconds = (long) duration.toSeconds();
long absSeconds = Math.abs(seconds);
String positive = String.format(
"%d:%02d:%02d",
//absSeconds / 3600,
(absSeconds % 3600) / 60,
absSeconds % 60);
return seconds < 0 ? "-" + positive : positive;
}
}
So I ran your code in command line and I was able to get a more specific debug error. So it seems like the time formatting you do in your MediaBar is causing the error. I don't know exactly what you are trying to do with that but the way you format the time is incorrect. If you comment it out as well as the other things you use to add the time formatting the URI path will be correct and your video should run fine. I know that for the formatting you are missing a '%02d'. As for what you are formatting I am not too sure so I cannot help you there.

Creating video player using Java

I need to create a video player using Java for my project. I have already checked many examples on the Internet. Some of them run, but do not show any screen, I can only hear the sound of the video. Please help me solve this...
I am using the below import
import javax.media.*;
EDIT:
Below is the code that i use:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.media.*;
public class MediaPlayerDemo extends JFrame
{
private Player player;
private File file;
public MediaPlayerDemo()
{
super( "Demonstrating the Java Media Player" );
JButton openFile = new JButton( "Open file to play" );
openFile.addActionListener( new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
openFile();
createPlayer();
}
});
getContentPane().add( openFile, BorderLayout.NORTH );
setSize( 300, 300 );
show();
}
private void openFile()
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = fileChooser.showOpenDialog( this );
// user clicked Cancel button on dialog
if ( result == JFileChooser.CANCEL_OPTION )
file = null;
else
file = fileChooser.getSelectedFile();
}
private void createPlayer()
{
if ( file == null )
return;
removePreviousPlayer();
try
{
// create a new player and add listener
player = Manager.createPlayer( file.toURL() );
player.addControllerListener( new EventHandler() );
player.start(); // start player
}
catch ( Exception e )
{
JOptionPane.showMessageDialog( this, "Invalid file or location", "Error loading file",
JOptionPane.ERROR_MESSAGE );
}
}
private void removePreviousPlayer()
{
if ( player == null )
return;
player.close();
Component visual = player.getVisualComponent();
Component control = player.getControlPanelComponent();
Container c = getContentPane();
if ( visual != null )
c.remove( visual );
if ( control != null )
c.remove( control );
}
public static void main(String args[])
{
MediaPlayerDemo app = new MediaPlayerDemo();
app.addWindowListener( new WindowAdapter()
{
public void windowClosing( WindowEvent e )
{
System.exit(0);
}
});
}
// inner class to handler events from media player
private class EventHandler implements ControllerListener
{
public void controllerUpdate( ControllerEvent e )
{
if ( e instanceof RealizeCompleteEvent )
{
Container c = getContentPane();
// load Visual and Control components if they exist
Component visualComponent = player.getVisualComponent();
if ( visualComponent != null )
c.add( visualComponent, BorderLayout.CENTER );
Component controlsComponent = player.getControlPanelComponent();
if ( controlsComponent != null )
c.add( controlsComponent, BorderLayout.SOUTH );
c.doLayout();
}
}
}
}
I used vlcj and it worked smoothly. It's java binding to vlcj player and the good thing that you don't have to provide any drives since vlcj already includes all of them in binary distribution.
Give it a go, there is example of already working player built for you!
Try a JavaFX Mediaplayer:
Usable Codecs:
Audio: MP3; AIFF containing uncompressed PCM; WAV containing uncompressed PCM; MPEG-4 multimedia container with Advanced Audio Coding (AAC) audio
Video: FLV containing VP6 video and MP3 audio; MPEG-4 multimedia
container with H.264/AVC (Advanced Video Coding) video compression .
Here an example from Oracle:
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.scene.media.MediaView;
import javafx.scene.media.Track;
import javafx.stage.Stage;
/**
* A sample media player which loops indefinitely over the same video
*/
public class MediaPlayer extends Application {
private static final String MEDIA_URL = "http://someserver/somedir/somefile.mp4";
private static String arg1;
#Override public void start(Stage stage) {
stage.setTitle("Media Player");
// Create media player
Media media = new Media((arg1 != null) ? arg1 : MEDIA_URL);
javafx.scene.media.MediaPlayer mediaPlayer = new javafx.scene.media.MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
mediaPlayer.setCycleCount(javafx.scene.media.MediaPlayer.INDEFINITE);
// Print track and metadata information
media.getTracks().addListener(new ListChangeListener<Track>() {
public void onChanged(Change<? extends Track> change) {
System.out.println("Track> "+change.getList());
}
});
media.getMetadata().addListener(new MapChangeListener<String,Object>() {
public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> change) {
System.out.println("Metadata> "+change.getKey()+" -> "+change.getValueAdded());
}
});
// Add media display node to the scene graph
MediaView mediaView = new MediaView(mediaPlayer);
Group root = new Group();
Scene scene = new Scene(root,800,600);
root.getChildren().add(mediaView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
if (args.length > 0) {
arg1 = args[0];
}
Application.launch(args);
}
}
https://blogs.oracle.com/javafx/entry/mpeg_4_multimedia_support_in
Here is the working code.
package New;
import java.net.URL;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class FxMediaExample2 extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Locate the media content in the CLASSPATH
URL mediaUrl = getClass().getResource("Test.mp4");
String mediaStringUrl = mediaUrl.toExternalForm();
// Create a Media
Media media = new Media(mediaStringUrl);
// Create a Media Player
final MediaPlayer player = new MediaPlayer(media);
// Automatically begin the playback
player.setAutoPlay(true);
// Create a 400X300 MediaView
MediaView mediaView = new MediaView(player);
mediaView.setFitWidth(400);
mediaView.setFitHeight(300);
mediaView.setSmooth(true);
mediaView.setLayoutX(200);
mediaView.setLayoutY(200);
// Create the DropShadow effect
DropShadow dropshadow = new DropShadow();
dropshadow.setOffsetY(5.0);
dropshadow.setOffsetX(5.0);
dropshadow.setColor(Color.RED);
mediaView.setEffect(dropshadow);
Rectangle rect4 = new Rectangle(35, 55, 95, 25);
rect4.setFill(Color.RED);
rect4.setStroke(Color.BLACK);
rect4.setStrokeWidth(1);
// Create the HBox
// HBox controlBox = new HBox(5, null, null);
// Create the VBox
VBox root = new VBox(1, mediaView);
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(95));
gridpane.setHgap(1);
gridpane.setVgap(10);
GridPane.setHalignment(rect4, HPos.CENTER);
Group grp = new Group();
gridpane.add(root, 1, 1);
grp.getChildren().add(gridpane);
// Create the Scene
Scene scene = new Scene(grp);
// Add the scene to the Stage
stage.setScene(scene);
// Set the title of the Stage
stage.setTitle("A simple Media Example");
// Display the Stage
stage.show();
}
}
Java Media Framework can be used to create multimedia applications like video and audio players.

How to pause/resume a song in javafx?

I'm making a playlist based mp3 player using javafx and I got everything working except how to pause/resume a song. I tried simply checking the player.Status()and using that but it didn't work so I stored the time of the song when pause()is clicked, in a Duration pausetime variable and it works that way but only once. What happens is: I click pause(), it works, click play(), it resumes the song but after that the pause button stops doing anything.
Btw I'm using two separate ToggleButton for pause and play because of the style I'm going for.
Here's the part of the code i'm talking about:
public void play(){
if (player != null){
player.stop();
}
if (pausebutton.isSelected()){
pausebutton.setSelected(false); //resume part
slider.setValue(pausetime.toSeconds());
play();
}
this.player = players.get(i);
player.setStartTime(pausetime);
player.play();
slide(i);
csong.setText(playlist.get(i).getName());
player.setOnEndOfMedia(new Runnable(){
#Override public void run(){
if (shuffle.isSelected()){
i = rand.nextInt(players.size() + 1);
}
else{
i++;
}
if(loop.isSelected()){
if (i == players.size()){
i = 0;
}}
list.getSelectionModel().select(i);
play();
}
});
}
public void pause(){
player.pause();
pausetime = player.getCurrentTime();
playbutton.setSelected(false);
}
I have created a very simple mp3 player, which has most (if not all) of the components said above.
It has play and pause toggle buttons, which do work ;)
It has labels updating the time elapsed for the song
It has a sliderbar, which can be used to move forward/backward. It automatically updates on song play.
Complete Code
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.text.DecimalFormat;
public class MediaPlayerSample extends Application {
private MediaPlayer player;
private final ToggleButton playButton = new ToggleButton("Play");
private final ToggleButton pauseButton = new ToggleButton("Pause");
private final ToggleGroup group = new ToggleGroup();
private final Label totalDuration = new Label();
private final Label currentDuration = new Label();
private final DecimalFormat formatter = new DecimalFormat("00.00");
private final SliderBar timeSlider = new SliderBar();
private Duration totalTime;
#Override
public void start(Stage primaryStage)
{
//Add a scene
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setStyle("-fx-background-color: ANTIQUEWHITE");
HBox playPause = new HBox(playButton, pauseButton);
HBox sliderBox = new HBox(timeSlider, currentDuration, totalDuration);
HBox.setHgrow(sliderBox, Priority.ALWAYS);
root.getChildren().addAll(sliderBox, playPause);
Scene scene = new Scene(root, 300, 100);
Media pick = new Media(getClass().getResource("/delete/abc/abc.mp3").toExternalForm());
player = new MediaPlayer(pick);
// Play the track and select the playButton
player.play();
playButton.setSelected(true);
player.currentTimeProperty().addListener(new ChangeListener<Duration>() {
#Override
public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
timeSlider
.sliderValueProperty()
.setValue(newValue.divide(totalTime.toMillis()).toMillis() * 100.0);
currentDuration.setText(String.valueOf(formatter.format(newValue.toSeconds())));
}
});
player.setOnReady(() -> {
// Set the total duration
totalTime = player.getMedia().getDuration();
totalDuration.setText(" / " + String.valueOf(formatter.format(Math.floor(totalTime.toSeconds()))));
});
// Slider Binding
timeSlider.sliderValueProperty().addListener((ov) -> {
if (timeSlider.isTheValueChanging()) {
if (null != player)
// multiply duration by percentage calculated by
// slider position
player.seek(totalTime.multiply(timeSlider
.sliderValueProperty().getValue() / 100.0));
else
timeSlider.sliderValueProperty().setValue(0);
}
});
//Applying Toggle Group to Buttons
playButton.setToggleGroup(group);
pauseButton.setToggleGroup(group);
// Action for Buttons
playButton.setOnAction(e -> {
play();
});
pauseButton.setOnAction(e -> {
pause();
});
//show the stage
primaryStage.setTitle("Media Player");
primaryStage.setScene(scene);
primaryStage.show();
}
public void play(){
player.play();
playButton.setSelected(true);
}
public void pause(){
player.pause();
playButton.setSelected(false);
}
private class SliderBar extends StackPane {
private Slider slider = new Slider();
private ProgressBar progressBar = new ProgressBar();
public SliderBar() {
getChildren().addAll(progressBar, slider);
bindValues();
}
private void bindValues(){
progressBar.prefWidthProperty().bind(slider.widthProperty());
progressBar.progressProperty().bind(slider.valueProperty().divide(100));
}
public DoubleProperty sliderValueProperty() {
return slider.valueProperty();
}
public boolean isTheValueChanging() {
return slider.isValueChanging();
}
}
public static void main(String[] args) {
launch(args);
}
}
A simple look while it plays
You can style the mediaplayer using stylesheet. You can go through JavaFX CSS Reference for advanced topic on css.
For a mediaplayer with advanced features like:
Adding songs to a Playlist
Playing songs one after another
Drag and drop songs into mediaview
and much more, you can go visit this example.

How to use JavaFX MediaPlayer correctly?

I'm writing a simple game and trying to play sounds but I can't get it to work when I create the Media object it throws IllegalArgumentException. I'm not much of a Java coder and any help will be appreciated.
Here is a sample code:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Main{
public static void main(String[] args) {
Media pick = new Media("put.mp3"); //throws here
MediaPlayer player = new MediaPlayer(pick);
player.play();
}
}
Obviously "put.mp3" exists and located in the correct directory, I checked the path using: System.out.println(System.getProperty("user.dir"));
what am I doing wrong here?
The problem is because you are trying to run JavaFX scene graph control outside of JavaFX Application thread.
Run all JavaFX scene graph nodes inside the JavaFX application thread.
You can start a JavaFX thread by extending JavaFX Application class and overriding the start() method.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Media pick = new Media("put.mp3"); // replace this with your own audio file
MediaPlayer player = new MediaPlayer(pick);
// Add a mediaView, to display the media. Its necessary !
// This mediaView is added to a Pane
MediaView mediaView = new MediaView(player);
// Add to scene
Group root = new Group(mediaView);
Scene scene = new Scene(root, 500, 200);
// Show the stage
primaryStage.setTitle("Media Player");
primaryStage.setScene(scene);
primaryStage.show();
// Play the media once the stage is shown
player.play();
}
public static void main(String[] args) {
launch(args);
}
}
Ok thanks to #ItachiUchiha insight on the matter I was able to solve my problem, It seems that any code that uses javaFX must run from within javaFX application Thread but not every program has to use javaFX API. In short what I did is start my game from within the Application.start(Stage ps) like so:
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
new Game(9,9,BasicRobot.FACING.SOUTH, 19);
}
public static void main(String[] args) throws InterruptedException {
launch();
}
}
That way the Game class and everything it creates and uses can use javaFX. To play the sounds I created a Utils class:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Utils {
public static void playSound(String fileName){
Media m = new Media("file:///" + System.getProperty("user.dir").replace('\\', '/') + "/" + fileName);
MediaPlayer player = new MediaPlayer(m);
player.play();
}
}
and now all I have to do to play a sound is call Utils.playSound("fileName.mp3") from anywhere inside my Game.
Maybe this would work:
MediaMetadataRetriever mediaMetadataRetriever1 =new MediaMetadataRetriever();
mediaMetadataRetriever1.setDataSource(getApplicationContext(), Uri.parse(myvidou_uri.toString()));
mediaPlayer1=MediaPlayer.create(getApplicationContext(),myvidou_uri);
mediaPlayer1.setDisplay(holder);
textView1.setText("info\n");

How to play mp3 files in java from a directory using a relative path in eclipse [duplicate]

This question already has answers here:
open resource with relative path in Java
(13 answers)
Closed 9 years ago.
Using the code example provided in the accepted answer of Playing audio using JavaFX MediaPlayer in a normal Java application? I am able to play mp3s from a directory on my computer when I pass a absolute path as a String to a File contructor.
My issue is that I am trying to access the mp3 files from a directory that I have imported into eclipse. I want to do this so that I can export my project as a .jar and have other people be able to use it. When I pass the relative path String ( /ProjectName/Mp3Directory ) and run it I get
Cannot find video source directory: /ProjectName/Mp3Directory
I have also tried to create a URL from the relative path, then converting that to a URI and passing it to the File constructor, but I could not get that to work either.
What can I do to get the following code to find my imported directory containing the mp3s (Mp3Directory) and sucessfully run?
package application;
import java.io.*;
import java.net.URL;
import java.util.*;
import javafx.application.Platform;
import javafx.beans.value.*;
import javafx.embed.swing.JFXPanel;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.media.*;
import javafx.util.Duration;
import javax.swing.*;
/** Example of playing all mp3 audio files in a given directory
* using a JavaFX MediaView launched from Swing
*/
public class JavaFXVideoPlayerLaunchedFromSwing {
private static void initAndShowGUI() {
// This method is invoked on Swing thread
JFrame frame = new JFrame("FX");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setBounds(200, 100, 800, 250);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
Platform.runLater(new Runnable() {
#Override public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = new SceneGenerator().createScene();
fxPanel.setScene(scene);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
initAndShowGUI();
}
});
}
}
class SceneGenerator {
final Label currentlyPlaying = new Label();
final ProgressBar progress = new ProgressBar();
private ChangeListener<Duration> progressChangeListener;
public Scene createScene() {
final StackPane layout = new StackPane();
// determine the source directory for the playlist
final File dir = new File("/ProjectName/mp3Directory");
if (!dir.exists() || !dir.isDirectory()) {
System.out.println("Cannot find video source directory: " + dir);
Platform.exit();
return null;
}
// create some media players.
final List<MediaPlayer> players = new ArrayList<MediaPlayer>();
for (String file : dir.list(new FilenameFilter() {
#Override public boolean accept(File dir, String name) {
return name.endsWith(".mp3");
}
})) players.add(createPlayer("file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20")));
if (players.isEmpty()) {
System.out.println("No audio found in " + dir);
Platform.exit();
return null;
}
// create a view to show the mediaplayers.
final MediaView mediaView = new MediaView(players.get(0));
final Button skip = new Button("Skip");
final Button play = new Button("Pause");
// play each audio file in turn.
for (int i = 0; i < players.size(); i++) {
final MediaPlayer player = players.get(i);
final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
player.setOnEndOfMedia(new Runnable() {
#Override public void run() {
player.currentTimeProperty().removeListener(progressChangeListener);
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.play();
}
});
}
// allow the user to skip a track.
skip.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
final MediaPlayer curPlayer = mediaView.getMediaPlayer();
MediaPlayer nextPlayer = players.get((players.indexOf(curPlayer) + 1) % players.size());
mediaView.setMediaPlayer(nextPlayer);
curPlayer.currentTimeProperty().removeListener(progressChangeListener);
curPlayer.stop();
nextPlayer.play();
}
});
// allow the user to play or pause a track.
play.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
if ("Pause".equals(play.getText())) {
mediaView.getMediaPlayer().pause();
play.setText("Play");
} else {
mediaView.getMediaPlayer().play();
play.setText("Pause");
}
}
});
// display the name of the currently playing track.
mediaView.mediaPlayerProperty().addListener(new ChangeListener<MediaPlayer>() {
#Override public void changed(ObservableValue<? extends MediaPlayer> observableValue, MediaPlayer oldPlayer, MediaPlayer newPlayer) {
setCurrentlyPlaying(newPlayer);
}
});
// start playing the first track.
mediaView.setMediaPlayer(players.get(0));
mediaView.getMediaPlayer().play();
setCurrentlyPlaying(mediaView.getMediaPlayer());
// silly invisible button used as a template to get the actual preferred size of the Pause button.
Button invisiblePause = new Button("Pause");
invisiblePause.setVisible(false);
play.prefHeightProperty().bind(invisiblePause.heightProperty());
play.prefWidthProperty().bind(invisiblePause.widthProperty());
// layout the scene.
layout.setStyle("-fx-background-color: cornsilk; -fx-font-size: 20; -fx-padding: 20; -fx-alignment: center;");
layout.getChildren().addAll(
invisiblePause,
VBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(
currentlyPlaying,
mediaView,
HBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(skip, play, progress).build()
).build()
);
progress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(progress, Priority.ALWAYS);
return new Scene(layout, 800, 600);
}
/** sets the currently playing label to the label of the new media player and updates the progress monitor. */
private void setCurrentlyPlaying(final MediaPlayer newPlayer) {
progress.setProgress(0);
progressChangeListener = new ChangeListener<Duration>() {
#Override public void changed(ObservableValue<? extends Duration> observableValue, Duration oldValue, Duration newValue) {
progress.setProgress(1.0 * newPlayer.getCurrentTime().toMillis() / newPlayer.getTotalDuration().toMillis());
}
};
newPlayer.currentTimeProperty().addListener(progressChangeListener);
String source = newPlayer.getMedia().getSource();
source = source.substring(0, source.length() - ".mp4".length());
source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " ");
currentlyPlaying.setText("Now Playing: " + source);
}
/** #return a MediaPlayer for the given source which will report any errors it encounters */
private MediaPlayer createPlayer(String aMediaSrc) {
System.out.println("Creating player for: " + aMediaSrc);
final MediaPlayer player = new MediaPlayer(new Media(aMediaSrc));
player.setOnError(new Runnable() {
#Override public void run() {
System.out.println("Media error occurred: " + player.getError());
}
});
return player;
}
}
Maybe try allowing the user to select the folder that contains the mp3s in it with something like this inside your createScene method:
final JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
// final File dir = new File("/ProjectName/mp3Directory");
File dir = null;
int selection = fc.showDialog(null, "Open");
if(selection == JFileChooser.APPROVE_OPTION) {
dir = fc.getSelectedFile();
} else {
System.out.print("Please select a directory to continue");
System.exit(0);
}
Relative paths shouldn't start with a slash. "/ProjectName" equates to a folder named ProjectName in the root of the current drive. So you could try "ProjectName/mp3Directory"... Although for something that will work in both Eclipse and from a runnable JAR you should get the folder in which the application is running and make a relative path from there (see the answer to Get the application's path for more information):
URL url = getClass().getResource("").toURI().toURL();
String applicationDir = url.getPath();
if(url.getProtocol().equals("jar")) {
appDir = new File(((JarURLConnection)url.openConnection()).getJarFileURL().getFile()).().getFile()).getParent();
}
String mp3Dir = appDir + "ProjectName" + System.getProperty("file.separator") + "mp3Directory";
Even though it wasn't really a direct answer to your question, I think that for an all-purpose application where you don't want to force users to put their MP3 files in a particular folder, axiopisty's suggestion to use a file chooser (in conjunction with saving the choice using a settings file or the Preferences API) would be the way to go.

Categories

Resources