Playing audio using JavaFX MediaPlayer in a normal Java application? - java

I need to be able to play Audio files (MP3 / Wav) in a normal Java project. I'd prefer using the new JavaFX MediaPlayer rather than JMF. I wrote some code to test this:
public void play()
{
URL thing = getClass().getResource("mysound.wav");
Media audioFile = new Media( thing.toString() );
try
{
MediaPlayer player = new MediaPlayer(audioFile);
player.play();
}
catch (Exception e)
{
System.out.println( e.getMessage() );
System.exit(0);
}
}
When I run this, I get the exception: Toolkit not initialized
I get that this has something to do with the JavaFX thread. My question is, how can I solve this? Do I need to create a JavaFX Panel just to play some audio files in the background of my normal app, or is there any other way?
Edit: Stacktrace:
java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:121)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:116)
at javafx.application.Platform.runLater(Platform.java:52)
at javafx.scene.media.MediaPlayer.init(MediaPlayer.java:445)
at javafx.scene.media.MediaPlayer.<init>(MediaPlayer.java:360)
at javaapplication6.JavaApplication6.play(JavaApplication6.java:23)
at javaapplication6.JavaApplication6.main(JavaApplication6.java:14)

For a solution with integrates a JavaFX MediaPlayer in Swing
Use a JFXPanel and be careful to only use JavaFX objects on the JavaFX thread and after the JavaFX system has been properly initialized.
JavaFX is normal Java which makes the question a bit confusing, but I guess you mean Swing.
Here's a sample audio player which is launched from Swing. The sample assumes that there are a bunch of mp3 files in the default public sample music folder for Windows 7 (C:\Users\Public\Music\Sample Music) and plays each file in turn.
JavaFXMediaPlayerLaunchedFromSwing.java
This code is responsible for creating a Swing application which, in turn, initializes the JavaFX toolkit and creates a JavaFX scene on the JavaFX application thread.
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javax.swing.*;
/**
* Example of playing all mp3 audio files in a given directory
* using a JavaFX MediaView launched from Swing
*/
public class JavaFXMediaPlayerLaunchedFromSwing {
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(() -> initFX(fxPanel));
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = new MediaSceneGenerator().createScene();
fxPanel.setScene(scene);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(
JavaFXMediaPlayerLaunchedFromSwing::initAndShowGUI
);
}
}
MediaSceneGenerator.java
Creates a JavaFX media player which sequentially plays all of the .mp3 media files in a given folder. It provides some controls for the media (play, pause, skip track, current track play progress indicator).
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.layout.VBox;
import javafx.scene.media.*;
import javafx.util.Duration;
import java.io.File;
import java.util.*;
public class MediaSceneGenerator {
private static final String MUSIC_FOLDER = "C:\\Users\\Public\\Music\\Sample Music";
private static final String MUSIC_FILE_EXTENSION = ".mp3";
private final Label currentlyPlaying = new Label();
private 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(MUSIC_FOLDER);
if (!dir.exists() || !dir.isDirectory()) {
System.out.println("Cannot find media source directory: " + dir);
Platform.exit();
return null;
}
// create some media players.
final List<MediaPlayer> players = new ArrayList<>();
for (String file : Objects.requireNonNull(dir.list((dir1, name) -> name.endsWith(MUSIC_FILE_EXTENSION))))
players.add(
createPlayer(
normalizeFileURL(dir, file)
)
);
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++) {
MediaPlayer player = players.get(i);
MediaPlayer nextPlayer = players.get((i + 1) % players.size());
player.setOnEndOfMedia(() -> {
final MediaPlayer curPlayer = mediaView.getMediaPlayer();
nextPlayer.seek(Duration.ZERO);
if (nextPlayer != curPlayer) {
curPlayer.currentTimeProperty().removeListener(progressChangeListener);
}
mediaView.setMediaPlayer(nextPlayer);
nextPlayer.play();
});
}
// allow the user to skip a track.
skip.setOnAction(actionEvent -> {
final MediaPlayer curPlayer = mediaView.getMediaPlayer();
MediaPlayer nextPlayer = players.get((players.indexOf(curPlayer) + 1) % players.size());
nextPlayer.seek(Duration.ZERO);
mediaView.setMediaPlayer(nextPlayer);
if (nextPlayer != curPlayer) {
curPlayer.currentTimeProperty().removeListener(progressChangeListener);
}
nextPlayer.play();
});
// allow the user to play or pause a track.
play.setOnAction(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(
(observableValue, oldPlayer, 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.
HBox controls = new HBox(10, skip, play, progress);
controls.setAlignment(Pos.CENTER);
VBox mediaPanel = new VBox(10, currentlyPlaying, mediaView, controls);
layout.setStyle("-fx-background-color: cornsilk; -fx-font-size: 20; -fx-padding: 20; -fx-alignment: center;");
layout.getChildren().addAll(
invisiblePause,
mediaPanel
);
progress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(progress, Priority.ALWAYS);
return new Scene(layout);
}
/**
* 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 = (observableValue, oldValue, newValue) ->
progress.setProgress(
1.0 * newPlayer.getCurrentTime().toMillis() / newPlayer.getTotalDuration().toMillis()
);
newPlayer.currentTimeProperty().addListener(progressChangeListener);
String source = getUserFriendlyMediaName(newPlayer);
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(() -> System.out.println("Media error occurred: " + player.getError()));
return player;
}
private String normalizeFileURL(File dir, String file) {
return "file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20");
}
private String getUserFriendlyMediaName(MediaPlayer newPlayer) {
String source = newPlayer.getMedia().getSource();
source = source.substring(0, source.length() - MUSIC_FILE_EXTENSION.length());
source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " ");
return source;
}
}
If you just want a native JavaFX application with a MediaPlayer and no Swing
The solution above which uses Swing answers the question asked. However, I have noted that sometimes people have picked up this answer and used it to create Java based media players even when they don't have an existing Swing application that they are embedding their application into.
If you don't have an existing Swing application, then eliminate the Swing code completely from your application and write a native JavaFX application instead. To do this, use the JavaFXMediaPlayer class below instead of the class JavaFXMediaPlayerLaunchedFromSwing from the sample above.
JavaFXMediaPlayer
import javafx.application.Application;
import javafx.stage.Stage;
public class JavaFXMediaPlayer extends Application {
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new MediaSceneGenerator().createScene());
stage.show();
}
}
Answers to follow-up questions
Will my .JAR file built via swing automatically have JavaFX added to it once I add it to the libraries in netbeans?
Note: info in this follow-up answer on packaging is likely dated now and other preferred packaging options exist at this time (e.g https://github.com/openjfx/javafx-maven-plugin).
Technically, Swing doesn't build Jar files but the jar of javafx packaging commands do.
If your app contains JavaFX, then, it's best to use the JavaFX packaging tools. Without them, you may have some deployment issues issues as the Java runtime jar (jfxrt.jar) is not automatically on the java boot classpath for jdk7u7. Users can manually add it to their runtime classpath, but it could be a bit of a pain. In future jdk versions (perhaps jdk7u10 or jdk8), jfxrt.jar will be on the classpath. Even then, use of the JavaFX packaging tools would still be recommended as it will be the best way to ensure that your deployment package will work in the most compatible way.
The SwingInterop NetBeans project is a sample NetBeans project which utilizes JavaFX deployment tools for a Swing project embedding JavaFX components. Source for SwingInterop is part of the JDK 7 and JavaFX Demos and Samples download.

Related

MediaView is not returning different snapshots

I am able to get snapshots of video when played using the following;
mediaView.snapshot(null, null);
Now I want to take snapshots with certain duration gaps like the following:
public class Main extends Application {
Media media = null;
MediaPlayer mediaPlayer = null;
MediaView mediaView = null;
public static void main(String[] args) {
launch(args);
}
public void start(final Stage primaryStage) {
primaryStage.setTitle("Video Snapshot");
media = new Media(new File("filePathTo.mp4").toURI().toString());
mediaPlayer = new MediaPlayer(media);
mediaView = new MediaView(mediaPlayer);
Pane pane = new Pane();
mediaPlayer.setOnReady(new Runnable() {
public void run() {
writeToFile(0.0);
writeToFile(1000.0);
writeToFile(10000.0);;
writeToFile(50000.0);
}
});
Scene scene = new Scene(pane, 640, 480, Color.BLACK);
primaryStage.setScene(scene);
mediaPlayer.play();
primaryStage.show();
}
private void writeToFile(Double double1) {
mediaView.getMediaPlayer().seek( Duration.millis(double1) );
WritableImage writableImage = mediaView.snapshot(null, null);
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
try {
ImageIO.write( SwingFXUtils.fromFXImage( writableImage, new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB) ), "png", byteOutput );
byteOutput.writeTo(new FileOutputStream( Paths.get(double1.toString()).toFile() + ".png" ));
} catch (IOException e) {
e.printStackTrace();
}
}
}
But now I get the same image and not different images, although the writableImage objects returned are different. Check the files 0.0.png, 1000.0.png, 10000.0.png, 50000.0.png files. All appears same. How could I get different snapshots?
Most likely, the problem is that the new pixels aren't rendered by the time you take the snapshot. You need to give JavaFX time to render the video. The following example works for me:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
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 javafx.util.Duration;
import javax.imageio.ImageIO;
public class Main extends Application {
public void start(Stage primaryStage) {
var player = new MediaPlayer(new Media(Path.of("video.mp4").toUri().toString()));
player.setAutoPlay(true);
var view = new MediaView(player);
player.setOnPlaying(() -> {
snapshotVideo(view, 0)
.thenCompose(unused -> snapshotVideo(view, 1000))
.thenCompose(unused -> snapshotVideo(view, 2000))
.thenCompose(unused -> snapshotVideo(view, 3000));
});
primaryStage.setScene(new Scene(new Pane(view), 1000, 650));
primaryStage.setTitle("Video Snapshot");
primaryStage.show();
}
private CompletableFuture<Void> snapshotVideo(MediaView view, double seekMillis) {
var future = new CompletableFuture<Void>();
view.getMediaPlayer().seek(Duration.millis(seekMillis));
Platform.runLater(() -> {
var fxImage = view.snapshot(null, null);
var bufImage = SwingFXUtils.fromFXImage(fxImage, null);
var filename = String.format("snapshot-%.0f.png", seekMillis);
try (var out = Files.newOutputStream(Path.of(filename))) {
ImageIO.write(bufImage, "png", out);
future.complete(null);
} catch (IOException ex) {
ex.printStackTrace();
future.completeExceptionally(ex);
}
});
return future;
}
}
It uses a combination of Platform#runLater(Runnable) and CompletableFuture.
It seeks to the desired time and then runs the snapshot+save code in a runLater call. This is an attempt to give JavaFX time to render the new seeked-to frame. I don't know if this is guaranteed to work. If I'm not mistaken, the JavaFX media implementation has one or more background threads for processing the audio/video. But I don't know if those threads can "fall behind". Also, it's possible that seeking far enough ahead could lead to buffering. So, you might have to handle that by listening to the status property of the MediaPlayer.
It uses CompletableFuture to make sure the next snapshot is not taken until the previous one has been taken and saved. It would probably be a good idea to move the image-saving code to a background thread. The important part, I think, is that the snapshot has been fully taken before you try to take the next one.
I also start taking these snapshots when the player is playing, not just ready. Not sure if that matters. I'm not even sure that the player needs to be playing for this to work.
And finally, the JavaFX Media API is probably not the best tool to use for this job. If I wanted frames from an MP4 video at different times, I would try to find a library that can just grab those frames straight from the file.
Thank you #Slaw for your answer. When I tried your code, it gave different results every time I ran it. The problem is definitely that the new pixels aren't rendered by the time the snapshots are taken. runLater and CompletableFuture are both providing some time for the process to render which sometimes are sufficient as maybe what happened in your system. But they are no way aware of if the process is really ready for snapshot-ing. What worked for me is that I replaced the player.setOnPlaying with the following:
player.setOnMarker(event -> {
snapshotVideo(view, event.getMarker().getValue().toMillis());
});
And also modified the snapshotVideo method in the following way:
private void snapshotVideo(MediaView view, double duration) {
var fxImage = view.snapshot(null, null);
var bufImage = SwingFXUtils.fromFXImage(fxImage, null);
var filename = String.format("snapshot-%.0f.png", duration);
try (var out = Files.newOutputStream(Path.of(filename))) {
ImageIO.write(bufImage, "png", out);
} catch (IOException ex) {
ex.printStackTrace();
}
}
What I did was removed both runLater and CompletableFuture. I am depending on Player.setOnMarker() method for assurance of the process to be ready for snapshot-ing.

JavaFX thread issues

I really do my best to not ask for help here unless i am desperate to the point of school assignment failure, being a new coder. That being said, i have spent the last 3 days trying to figure out the issue with threading. I am trying to instantiate a javafx class thats in a separate package, and keep running into the dreaded "java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = main" exception.
I have tried calling theGamePreBoard.start(new Stage()), which doesnt work, and i have also tried calling its start method during construction of that object with a new Stage() passed in during construction. Please help!!!
How can i instantiate this PreBoard() class and get it's start method to run without throwing this?
main class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package battleship.model;
import battleship.viewcon.*;
import javafx.stage.Stage;
/**
*
* #author foolishklown
*/
public class MainApp {
Player player1;
Player player2;
Board board1;
Board board2;
BattleshipGame theGame;
PreBoard theGamePreBoard;
public void go() {
theGame = new BattleshipGame();
theGamePreBoard = new PreBoard();
theGamePreBoard.start(new Stage());
System.out.println(theGamePreBoard);
theGamePreBoard.setBattleshipGame(theGame);
}
public static void main(String[] args) {
MainApp app = new MainApp();
app.go();
}
}
PreBoard class:
/*
* PreBoard object. This is the starter class for the different JavaFX stages (different windows - username screen,
* and each players window)
* After first username input, this class hides and calls on a new P1Board object
*/
package battleship.viewcon;
import battleship.model.*;
import javafx.geometry.Insets;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
/**
*
*
* #author c-dub
*/
public class PreBoard extends Application {
private boolean turn; // field to determine which players name to put into which board
private String player;
private Button hideBtn;
private Button showBtn;
private TextField userText;
private ViewCon controller;
private P1Board p1B;
private P2Board p2B;
private BattleshipGame game;
private Stage theStage;
#Override
public void start(Stage primaryStage) {
turn = false;
p1B = new P1Board();
p2B = new P2Board();
controller = new ViewCon();
controller.setp1(p1B);
controller.setp2(p2B);
controller.setPreB(this);
this.game = controller.getBattleshipGame();
primaryStage.setTitle("Battleship setup"); //Main stage (window container)
//Gridpane for using rows/columns for child node placement
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER_LEFT);
grid.setHgap(10);
grid.setVgap(5);
grid.setPadding(new Insets(100, 25, 25, 25));
// label in window
Text sceneTitle = new Text("Setup");
sceneTitle.setId("setup-text");
grid.add(sceneTitle, 0, 0, 2, 1);
// label and textfield
Label userName = new Label("Enter UserName:");
userName.setId("user-name");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
userTextField.setId("text-field");
grid.add(userTextField, 0, 2);
// button for setup, with actionListener to save player name or default if its left blank
Button setupBtn = new Button("Setup Board");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_LEFT);
hbBtn.getChildren().add(setupBtn);
grid.add(hbBtn, 0, 3);
setupBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
// determine which player name to use to pass into which player board
if(turn == false) {
String temp1 = userTextField.getText();
if(temp1.equals("")) {
player = "Player1";
} else {
player = temp1;
}
controller.setPlayer1(player);
game.setPlayer1(player);
turn = true;
Stage stage = new Stage();
p1B.start(stage);
grid.getChildren().remove(userTextField);
userText = new TextField();
userText.setId("text-field2");
grid.add(userText, 0, 2);
hideBtn.fire();
} else {
String temp2 = userText.getText();
if(temp2.equals("")) {
player = "Player2";
} else {
player = temp2;
}
controller.setPlayer2(player);
game.setPlayer2(player);
Stage stage2 = new Stage();
p2B.start(stage2);
hideBtn.fire();
}
}
});
hideBtn = new Button();
hideBtn.setId("hideBtn");
hideBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.hide();
}
});
showBtn = new Button();
showBtn.setId("showBtn");
showBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
primaryStage.show();
}
});
controller.setPreShowBtn(showBtn);
controller.setPreHideBtn(hideBtn);
// Add the entire scene into the main window(stage) after setting the scene dimensions
Scene scene = new Scene(grid, 580, 200);
primaryStage.setScene(scene);
// Attach css stylesheet
scene.getStylesheets().add(PreBoard.class.getResource("styles/PreBoardStyle.css").toExternalForm());
// Show this window(stage) upon instantiation
primaryStage.show();
}
public void setLink(ViewCon v) {
this.controller = v;
}
public static void main(String[] args) {
Application.launch(args);
}
public void setBattleshipGame(BattleshipGame b) {
this.game = b;
}
}
I don't think this has anything at all to do with threading: I don't see any reason why you would ever create another thread in this application. The part you seem to be missing is the actual life-cycle of a JavaFX application. (There's a little you could need to know about how JavaFX manages threading, but it is a bit incidental here.)
The Application class represents an entire application. Your application should typically have just one Application subclass, and one instance of that class. The instance is created for you by JavaFX when you call the static Application.launch() method (or when you execute your Application subclass from the command line, which effectively calls launch for you).
When launch is invoked, the JavaFX toolkit (including the FX Application Thread) is started. An instance of theApplication subclass is created for you, and then start(...) is invoked on that instance on the FX Application Thread.
So what that means is that the start(...) method is the entry point (startup) for your JavaFX application. Since the most common thing to do here is to display something in a window, a window (Stage) is passed into this method for your convenience: however you can ignore it and just create your own if you like.
A typical start(...) method should be quite short, and will usually just create some UI (maybe defined in another class or in an FXML file), put that UI in a scene, and display the scene in a stage. In a more complex application, you will create an instance of your model class here, create some views and controllers, give the controllers references to the model, and assemble the views.
For a simple structural example, see my answer to Java: How do I start a standalone application from the current one when both are in the same package? (which is a similar question, I think).

JavaFX video not playing

I followed some tutorials about combining JavaFX with Swing (JFrame) to play a video, however all I get is a black screen where the video is supposed to be without any actual content playing, No errors are reported either.
What am I doing wrong here and why wont the video play?
I tried several .flv videos, none of them will start playing (they do play when I open them in my browser)
I'm running jre7 and jdk1.7.0_45 on windows 8.1 N Pro with the K-lite full codec pack installed
EDIT: updated my code after the comment of jewelsea, nothing has changed, the black box still appears without content playing, the console doesn't show any text coming up
package com.example.test;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.media.Media;
import javafx.scene.media.MediaErrorEvent;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
private static void initAndShowGUI() {
// This method is invoked on the EDT thread
JFrame frame = new JFrame("Test");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setSize(640, 480);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on the JavaFX thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
private static Scene createScene() {
String source;
Media media;
MediaPlayer mediaPlayer;
MediaView mediaView = null;
try {
media = new Media("http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv");
if (media.getError() == null) {
media.setOnError(new Runnable() {
public void run() {
// Handle asynchronous error in Media object.
System.out.println("Handle asynchronous error in Media object");
}
});
try {
mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
if (mediaPlayer.getError() == null) {
mediaPlayer.setOnError(new Runnable() {
public void run() {
// Handle asynchronous error in MediaPlayer object.
System.out.println("Handle asynchronous error in MediaPlayer object");
}
});
mediaView = new MediaView(mediaPlayer);
mediaView.setOnError(new EventHandler() {
public void handle(MediaErrorEvent t) {
// Handle asynchronous error in MediaView.
System.out.println("Handle asynchronous error in MediaView: "+ t.getMediaError());
}
#Override
public void handle(Event arg0) {
// TODO Auto-generated method stub
System.out.println("Handle asynchronous error in MediaView arg0: "+arg0.toString());
}
});
} else {
// Handle synchronous error creating MediaPlayer.
System.out.println("Handle synchronous error creating MediaPlayer");
}
} catch (Exception mediaPlayerException) {
// Handle exception in MediaPlayer constructor.
System.out.println("Handle exception in MediaPlayer constructor: "+ mediaPlayerException.getMessage());
}
} else {
// Handle synchronous error creating Media.
System.out.println("Handle synchronous error creating Media");
}
} catch (Exception mediaException) {
// Handle exception in Media constructor.
System.out.println("Handle exception in Media constructor: "+mediaException.getMessage());
}
Group root = new Group();
Scene scene = SceneBuilder.create().width(640).height(480).root(root).fill(Color.WHITE).build();
if(mediaView != null) {
root.getChildren().add(mediaView);
}
return scene;
}
}
So I installed the windows media feature pack in order to get adobe premiere pro working (because it required a dll file from windows media player (which I didn't had installed because I run an N version of windows) and now the video does play for me.
I can't say with 100% confirmation the cause was not having WMP installed as the media feature pack might as well have installed something else that solved my problem, nonetheless, problem solved :)
I want to thank the other answers for trying, I really appreciate it.
Please do not mind if i am writing this answer. I know this is a very old question but this answer might help others. I am currently developing a JavaFX application which needs to execute a file depending upon its type.
My application played the video for the first time but when i clicked on another mp4 video file it didn't play.
Here is my initial code.
private void playVideo(String fileLocation) {
System.out.println("VideoProcesser Thread = " + Thread.currentThread().getName());
media = new Media(new File(fileLocation).toURI().toString());
mediaPlayer = new MediaPlayer(media);
mediaView = new MediaView(mediaPlayer);
runnable = () -> {
System.out.println("Inside runnable VideoProcesser Thread = " + Thread.currentThread().getName());
mediaPlayer.play();
};
mediaPlayer.setOnReady(runnable);
setVideoMediaStatus(PLAYING);
pane.getChildren().add(mediaView);
}
Then since the video player screen was dark, i thought the problem was with media view, so i added the following two line,
if(mediaView == null) {
mediaView = new MediaView(mediaPlayer);
}
mediaView.setMediaPlayer(mediaPlayer);
Now, when i click on different videos my application just plays fine.
Here is the complete code.
Media media;
MediaPlayer mediaPlayer;
MediaView mediaView;
private void playVideo(String fileLocation) {
System.out.println("VideoProcesser Thread = " + Thread.currentThread().getName());
media = new Media(new File(fileLocation).toURI().toString());
mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
if(mediaView == null) {
mediaView = new MediaView(mediaPlayer);
}
mediaView.setMediaPlayer(mediaPlayer);
mediaPlayer.play();
mediaPlayer.setOnError(() -> System.out.println("Current error: "+mediaPlayer.getError()));
setVideoMediaStatus(PLAYING);
pane.getChildren().add(mediaView);
}
Note that if you are using FXML to instantiate mediaView, then do not instantiate it again. Instantiating it again might make mediaView loose the reference of original node.
Refer to this post and answer by itachi,
javafx mediaview only the audio is playing
try this, it works for me:
package de.professional_webworkx.swing;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javax.swing.JFrame;
public class MyFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Create a new Frame, set title, ...
*/
public MyFrame() {
this.setTitle("Swing and JavaFX");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(1024, 768);
// create a JFXPanel
final JFXPanel jfxPanel = new JFXPanel();
// add the jfxPanel to the contentPane of the JFrame
this.getContentPane().add(jfxPanel);
this.setVisible(true);
Platform.runLater(new Runnable() {
#Override
public void run() {
jfxPanel.setScene(initScene());
}
});
}
public static final void main (String[] args) {
new MyFrame();
}
/**
* init the JFX Scene and
* #return scene
*/
private Scene initScene() {
Group root = new Group();
SceneBuilder<?> sb = SceneBuilder.create().width(640).height(400).root(root);
Media video = new Media("http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv");
MediaPlayer mediaPlayer = new MediaPlayer(video);
mediaPlayer.setAutoPlay(true);
mediaPlayer.play();
MediaView view = new MediaView(mediaPlayer);
root.getChildren().add(view);
Scene scene = sb.build();
return scene;
}
}
Patrick
I took your code and tried running it on my machine (Win7 JDK 1.7.0_25) and got the same results. Black box and no video.
I noticed you aren't setting mediaPlayer.setAutoPlay(true) so I added that call to the createScene() right before mediaPlayer is passed to MediaView. Now the playback seems to work for me.
// ... prior code omitted
// added this to OP's code
mediaPlayer.setAutoPlay(true);
mediaView = new MediaView(mediaPlayer);
mediaView.setOnError(new EventHandler() {
public void handle(MediaErrorEvent t) {
// Handle asynchronous error in MediaView.
System.out.println("Handle asynchronous error in MediaView: "+ t.getMediaError());
}
// ... additional code omitted
Edit: The autoPlay property defaults to false - you can call mediaPlayer.isAutoPlay() to check this. Without either calling mediaPlayer.setAutoPlay(true) or mediaPlayer.play() the video will never start playing.
Edit 2: I just noticed in the comments on another answer that you are having trouble playing the video outside of JavaFX. If you don't already have it installed, try downloading VLC to see if the video can play using that. I believe installing ffdshow tryouts will provide the necessary codecs to play FLV in Windows Media Player. (Although I thought all versions of K-lite codec pack included FLV support)

Opening a full web page

Is there a way of opening a full web page using Java, I have to check the time taken in opening full web page in a Java user end application, I have tried this code:
URL ur = new URL("http://www.google.com/");
HttpURLConnection yc =(HttpURLConnection) ur.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
but this gives me the source code of the url... that's useless for me!
as I need to record the time taken by a webpage to load on my desktop by making a Java application.
Everything is on client site!
Here is a JavaFX based sample:
import java.util.Date;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.concurrent.Worker.State;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.*;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
/** times the loading of a page in a WebEngine */
public class PageLoadTiming extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
final Label instructions = new Label(
"Loads a web page into a JavaFX WebEngine. " +
"The first page loaded will take a bit longer than subsequent page loads due to WebEngine intialization.\n" +
"Once a given url has been loaded, subsequent loads of the same url will be quick as url resources have been cached on the client."
);
instructions.setWrapText(true);
instructions.setStyle("-fx-font-size: 14px");
// configure some controls.
final WebEngine engine = new WebEngine();
final TextField location = new TextField("http://docs.oracle.com/javafx/2/get_started/jfxpub-get_started.htm");
final Button go = new Button("Go");
final Date start = new Date();
go.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent arg0) {
engine.load(location.getText());
start.setTime(new Date().getTime());
}
});
go.setDefaultButton(true);
final Label timeTaken = new Label();
// configure help tooltips.
go.setTooltip(new Tooltip("Start timing the load of a page at the entered location."));
location.setTooltip(new Tooltip("Enter the location whose page loading is to be timed."));
timeTaken.setTooltip(new Tooltip("Current loading state and time taken to load the last page."));
// monitor the page load status and update the time taken appropriately.
engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
#Override public void changed(ObservableValue<? extends State> state, State oldState, State newState) {
switch (newState) {
case SUCCEEDED: timeTaken.setText(((new Date().getTime()) - start.getTime()) + "ms"); break;
default: timeTaken.setText(newState.toString());
}
}
});
// layout the controls.
HBox controls = HBoxBuilder.create().spacing(10).children(new Label("Location"), location, go, timeTaken).build();
HBox.setHgrow(location, Priority.ALWAYS);
timeTaken.setMinWidth(120);
// layout the scene.
VBox layout = new VBox(10);
layout.setStyle("-fx-padding: 10; -fx-background-color: cornsilk; -fx-font-size: 20px;");
layout.getChildren().addAll(controls, instructions);
stage.setTitle("Page load timing");
stage.getIcons().add(new Image("http://icons.iconarchive.com/icons/aha-soft/perfect-time/48/Hourglass-icon.png"));
stage.setScene(new Scene(layout, 1000, 110));
stage.show();
// trigger loading the default page.
go.fire();
}
}
Yeah home is right that should do the trick. But this way is much more simpler... Although a bit erroneous it should serve fine for benchmark purposes.
JEditorPane editorPane = new JEditorPane();
editorPane.setPage(new URL("http://www.google.com"));
The scripts are still rendered on the screen if you just use this snippet, although it can be worked around I don't think you will need to bother with that since you need to just benchmark loading time... However the results may be varying very slightly since it doesn't take time to run the JavaScript.
You can use Cobra
You can use plain Swing also
You can also use JavaFX to do it like this:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.web.WebView;
public class MyWebView extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) {
final WebView wv = new WebView();
wv.getEngine().load("http://www.google.com");
primaryStage.setScene(new Scene(wv));
primaryStage.show();
}
}
To open a web page using java , try the following code :
import java.io.*;
public class b {
public static void main(String args[])throws IOException
{
String downloadURL="<url>";
java.awt.Desktop myNewBrowserDesktop = java.awt.Desktop.getDesktop();
try
{
java.net.URI myNewLocation = new java.net.URI(downloadURL);
myNewBrowserDesktop.browse(myNewLocation);
}
catch(Exception e)
{
}
}
}
This will open the web page in your default browser . As for the time taken to load part , have a look here . There are a lot of suggestions there .

Capturing image from webcam in java?

How can I continuously capture images from a webcam?
I want to experiment with object recognition (by maybe using java media framework).
I was thinking of creating two threads
one thread:
Node 1: capture live image
Node 2: save image as "1.jpg"
Node 3: wait 5 seconds
Node 4: repeat...
other thread:
Node 1: wait until image is captured
Node 2: using the "1.jpg" get colors
from every pixle
Node 3: save data in arrays
Node 4: repeat...
This JavaCV implementation works fine.
Code:
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import java.io.File;
import static org.bytedeco.opencv.global.opencv_core.cvFlip;
import static org.bytedeco.opencv.helper.opencv_imgcodecs.cvSaveImage;
public class Test implements Runnable {
final int INTERVAL = 100;///you may use interval
CanvasFrame canvas = new CanvasFrame("Web Cam");
public Test() {
canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
}
public void run() {
new File("images").mkdir();
FrameGrabber grabber = new OpenCVFrameGrabber(0); // 1 for next camera
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage img;
int i = 0;
try {
grabber.start();
while (true) {
Frame frame = grabber.grab();
img = converter.convert(frame);
//the grabbed frame will be flipped, re-flip to make it right
cvFlip(img, img, 1);// l-r = 90_degrees_steps_anti_clockwise
//save
cvSaveImage("images" + File.separator + (i++) + "-aa.jpg", img);
canvas.showImage(converter.convert(img));
Thread.sleep(INTERVAL);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Test gs = new Test();
Thread th = new Thread(gs);
th.start();
}
}
There is also post on configuration for JavaCV
You can modify the code and be able to save the images in regular interval and do rest of the processing you want.
Some time ago I've created generic Java library which can be used to take pictures with a PC webcam. The API is very simple, not overfeatured, can work standalone, but also supports additional webcam drivers like OpenIMAJ, JMF, FMJ, LTI-CIVIL, etc, and some IP cameras.
Link to the project is https://github.com/sarxos/webcam-capture
Example code (take picture and save in test.jpg):
Webcam webcam = Webcam.getDefault();
webcam.open();
BufferedImage image = webcam.getImage();
ImageIO.write(image, "JPG", new File("test.jpg"));
It is also available in Maven Central Repository or as a separate ZIP which includes all required dependencies and 3rd party JARs.
JMyron is very simple for use.
http://webcamxtra.sourceforge.net/
myron = new JMyron();
myron.start(imgw, imgh);
myron.update();
int[] img = myron.image();
Here is a similar question with some - yet unaccepted - answers. One of them mentions FMJ as a java alternative to JMF.
This kind of goes off of gt_ebuddy's answer using JavaCV, but my video output is at a much higher quality then his answer. I've also added some other random improvements (such as closing down the program when ESC and CTRL+C are pressed, and making sure to close down the resources the program uses properly).
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
public class HighRes extends JComponent implements Runnable {
private static final long serialVersionUID = 1L;
private static CanvasFrame frame = new CanvasFrame("Web Cam");
private static boolean running = false;
private static int frameWidth = 800;
private static int frameHeight = 600;
private static OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
private static BufferedImage bufImg;
public HighRes()
{
// setup key bindings
ActionMap actionMap = frame.getRootPane().getActionMap();
InputMap inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
for (Keys direction : Keys.values())
{
actionMap.put(direction.getText(), new KeyBinding(direction.getText()));
inputMap.put(direction.getKeyStroke(), direction.getText());
}
frame.getRootPane().setActionMap(actionMap);
frame.getRootPane().setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
// setup window listener for close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
stop();
}
});
}
public static void main(String... args)
{
HighRes webcam = new HighRes();
webcam.start();
}
#Override
public void run()
{
try
{
grabber.setImageWidth(frameWidth);
grabber.setImageHeight(frameHeight);
grabber.start();
while (running)
{
final IplImage cvimg = grabber.grab();
if (cvimg != null)
{
// cvFlip(cvimg, cvimg, 1); // mirror
// show image on window
bufImg = cvimg.getBufferedImage();
frame.showImage(bufImg);
}
}
grabber.stop();
grabber.release();
frame.dispose();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void start()
{
new Thread(this).start();
running = true;
}
public void stop()
{
running = false;
}
private class KeyBinding extends AbstractAction {
private static final long serialVersionUID = 1L;
public KeyBinding(String text)
{
super(text);
putValue(ACTION_COMMAND_KEY, text);
}
#Override
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if (action.equals(Keys.ESCAPE.toString()) || action.equals(Keys.CTRLC.toString())) stop();
else System.out.println("Key Binding: " + action);
}
}
}
enum Keys
{
ESCAPE("Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)),
CTRLC("Control-C", KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK)),
UP("Up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)),
DOWN("Down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)),
LEFT("Left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)),
RIGHT("Right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
private String text;
private KeyStroke keyStroke;
Keys(String text, KeyStroke keyStroke)
{
this.text = text;
this.keyStroke = keyStroke;
}
public String getText()
{
return text;
}
public KeyStroke getKeyStroke()
{
return keyStroke;
}
#Override
public String toString()
{
return text;
}
}
You can try Java Webcam SDK library also.
SDK demo applet is available at link.
I have used JMF on a videoconference application and it worked well on two laptops: one with integrated webcam and another with an old USB webcam. It requires JMF being installed and configured before-hand, but once you're done you can access the hardware via Java code fairly easily.
You can try Marvin Framework. It provides an interface to work with cameras. Moreover, it also provides a set of real-time video processing features, like object tracking and filtering.
Take a look!
Real-time Video Processing Demo:
http://www.youtube.com/watch?v=D5mBt0kRYvk
You can use the source below. Just save a frame using MarvinImageIO.saveImage() every 5 second.
Webcam video demo:
public class SimpleVideoTest extends JFrame implements Runnable{
private MarvinVideoInterface videoAdapter;
private MarvinImage image;
private MarvinImagePanel videoPanel;
public SimpleVideoTest(){
super("Simple Video Test");
videoAdapter = new MarvinJavaCVAdapter();
videoAdapter.connect(0);
videoPanel = new MarvinImagePanel();
add(videoPanel);
new Thread(this).start();
setSize(800,600);
setVisible(true);
}
#Override
public void run() {
while(true){
// Request a video frame and set into the VideoPanel
image = videoAdapter.getFrame();
videoPanel.setImage(image);
}
}
public static void main(String[] args) {
SimpleVideoTest t = new SimpleVideoTest();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
For those who just want to take a single picture:
WebcamPicture.java
public class WebcamPicture {
public static void main(String[] args) {
try{
MarvinVideoInterface videoAdapter = new MarvinJavaCVAdapter();
videoAdapter.connect(0);
MarvinImage image = videoAdapter.getFrame();
MarvinImageIO.saveImage(image, "./res/webcam_picture.jpg");
} catch(MarvinVideoInterfaceException e){
e.printStackTrace();
}
}
}
I used Webcam Capture API. You can download it from here
webcam = Webcam.getDefault();
webcam.open();
if (webcam.isOpen()) { //if web cam open
BufferedImage image = webcam.getImage();
JLabel imageLbl = new JLabel();
imageLbl.setSize(640, 480); //show captured image
imageLbl.setIcon(new ImageIcon(image));
int showConfirmDialog = JOptionPane.showConfirmDialog(null, imageLbl, "Image Viewer", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, new ImageIcon(""));
if (showConfirmDialog == JOptionPane.YES_OPTION) {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Save Image");
chooser.setFileFilter(new FileNameExtensionFilter("IMAGES ONLY", "png", "jpeg", "jpg")); //this file extentions are shown
int showSaveDialog = chooser.showSaveDialog(this);
if (showSaveDialog == 0) { //if pressed 'Save' button
String filePath = chooser.getCurrentDirectory().toString().replace("\\", "/");
String fileName = chooser.getSelectedFile().getName(); //get user entered file name to save
ImageIO.write(image, "PNG", new File(filePath + "/" + fileName + ".png"));
}
}
}
http://grack.com/downloads/school/enel619.10/report/java_media_framework.html
Using the Player with Swing
The Player can be easily used in a Swing application as well. The following code creates a Swing-based TV capture program with the video output displayed in the entire window:
import javax.media.*;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import javax.swing.event.*;
public class JMFTest extends JFrame {
Player _player;
JMFTest() {
addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
_player.stop();
_player.deallocate();
_player.close();
System.exit( 0 );
}
});
setExtent( 0, 0, 320, 260 );
JPanel panel = (JPanel)getContentPane();
panel.setLayout( new BorderLayout() );
String mediaFile = "vfw://1";
try {
MediaLocator mlr = new MediaLocator( mediaFile );
_player = Manager.createRealizedPlayer( mlr );
if (_player.getVisualComponent() != null)
panel.add("Center", _player.getVisualComponent());
if (_player.getControlPanelComponent() != null)
panel.add("South", _player.getControlPanelComponent());
}
catch (Exception e) {
System.err.println( "Got exception " + e );
}
}
public static void main(String[] args) {
JMFTest jmfTest = new JMFTest();
jmfTest.show();
}
}
Java usually doesn't like accessing hardware, so you will need a driver program of some sort, as goldenmean said. I've done this on my laptop by finding a command line program that snaps a picture. Then it's the same as goldenmean explained; you run the command line program from your java program in the takepicture() routine, and the rest of your code runs the same.
Except for the part about reading pixel values into an array, you might be better served by saving the file to BMP, which is nearly that format already, then using the standard java image libraries on it.
Using a command line program adds a dependency to your program and makes it less portable, but so was the webcam, right?
I believe the web-cam application software which comes along with the web-cam, or you native windows webcam software can be run in a batch script(windows/dos script) after turning the web cam on(i.e. if it needs an external power supply). In the bacth script , u can add appropriate delay to capture after certain time period. And keep executing the capture command in loop.
I guess this should be possible
-AD
There's a pretty nice interface for this in processing, which is kind of a pidgin java designed for graphics. It gets used in some image recognition work, such as that link.
Depending on what you need out of it, you might be able to load the video library that's used there in java, or if you're just playing around with it you might be able to get by using processing itself.
FMJ can do this, as can the supporting library it uses, LTI-CIVIL. Both are on sourceforge.
Recommand using FMJ for multimedia relatived java app.
Try using JMyron How To Use Webcam Using Java. I think using JMyron is the easiest way to access a webcam using java. I tried to use it with a 64-bit processor, but it gave me an error. It worked just fine on a 32-bit processor, though.

Categories