A DESCRIPTION OF THE PROBLEM :
I have 8 Mediaplayer playing at the same time. When I seek them at the same time > 50% of the time some videos hang. Sometimes (~30%) after a while they start playing again, but in slow-motion. onError is not called and getRate() = 1.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Play 8 Mediaplayer at the same time, hook them up to the same controls and seek a few times.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Player all seek to the same time.
ACTUAL -
Player hang without error message. Some will continue at some point in a very slow speed.
---------- BEGIN SOURCE ----------
package org.example;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Window;
import javafx.util.Duration;
import java.util.ArrayList;
import java.util.List;
public class MediaControlMinimal extends BorderPane {
private final List<MediaPlayer> mpList;
private Duration duration;
private boolean shouldPlay;
private int setupComplete;
private final Slider timeSlider;
private final HBox mediaBar;
private final Button playButton;
private final MediaPlayer controlMediaPlayer;
public MediaControlMinimal(List<MediaPlayer> mpList, int videoRows) {
this.mpList = mpList;
List<MediaView> mvList = new ArrayList<>(mpList.size());
Pane mvPane = new Pane() {
};
for (MediaPlayer mp : mpList) {
MediaView mediaView = new MediaView(mp);
mvList.add(mediaView);
mvPane.getChildren().add(mediaView);
}
mvPane.setStyle("-fx-background-color: black;");
setCenter(mvPane);
mediaBar = new HBox(); // 5 als param für spacing = 5, sieh zeile 247
mediaBar.setAlignment(Pos.CENTER);
mediaBar.setPadding(new Insets(5, 10, 5, 10));
BorderPane.setAlignment(mediaBar, Pos.CENTER);
playButton = new Button();
playButton.setOnAction(e -> {
shouldPlay = !shouldPlay;
if (shouldPlay) {
playAll();
} else {
pauseAll();
}
});
// Add time slider
timeSlider = new Slider();
HBox.setHgrow(timeSlider, Priority.ALWAYS);
timeSlider.setMinWidth(50);
timeSlider.setMaxWidth(Double.MAX_VALUE);
timeSlider.setOnMouseReleased(event -> {
//timeSlider.setValueChanging(true);
//timeSlider.setValue((event.getX() / timeSlider.getWidth()) * timeSlider.getMax());
//timeSlider.setValueChanging(false);
System.out.println("setOnMouseReleased");
final Duration seekTo = Duration.millis((event.getX() / timeSlider.getWidth()) * timeSlider.getMax());
for (MediaPlayer mp : mpList) {
new Thread(() -> {
mp.seek(seekTo);
}).start();
}
});
controlMediaPlayer = mpList.get(1);
controlMediaPlayer.currentTimeProperty().addListener((observable, oldVal, newVal) -> {
updateValues(controlMediaPlayer);
});
for (MediaPlayer mp : mpList) {
mp.setOnReady(() -> {
int videosPerRow = mpList.size() / videoRows;
if (setupComplete == 0) {
duration = mp.getMedia().getDuration();
timeSlider.setMax(duration.toMillis());
updateValues(mp);
final Window window = mvPane.getScene().getWindow();
final double titleHeight = window.getHeight() - mvPane.getScene().getHeight();
double windowHeight = videoRows * mp.getMedia().getHeight() + titleHeight;
if (!Main.isTransDesign) {
windowHeight += mediaBar.getHeight();
}
window.setHeight(windowHeight);
window.setWidth(videosPerRow * mp.getMedia().getWidth());
}
if (setupComplete < mpList.size()) {
final Node mpNode = mvPane.getChildren().get(mpList.indexOf(mp));
if (mpList.indexOf(mp) != 0 && mpNode.getLayoutX() == 0 && mpNode.getLayoutY() == 0) {
//fenster höhe
double xRelocate = mp.getMedia().getWidth() * (mpList.indexOf(mp) % videosPerRow);
double yRelocate = mp.getMedia().getHeight() * Math.floorDiv(mpList.indexOf(mp), videosPerRow);
mpNode.relocate(xRelocate, yRelocate);
}
++setupComplete;
}
});
mp.setCycleCount(MediaPlayer.INDEFINITE);
}
mediaBar.getChildren().add(playButton);
mediaBar.getChildren().add(timeSlider);
setBottom(mediaBar);
}
private void playAll() {
for (MediaPlayer mp : mpList) {
mp.play();
}
}
private void pauseAll() {
for (MediaPlayer mp : mpList) {
mp.pause();
}
}
protected void updateValues(MediaPlayer mp) {
if (timeSlider != null) {
Platform.runLater(() -> {
Duration currentTime = mp.getCurrentTime();
timeSlider.setDisable(duration.isUnknown());
if (!timeSlider.isDisabled() && duration.greaterThan(Duration.ZERO) && !timeSlider.isValueChanging()) {
timeSlider.setValue(currentTime.toMillis());
}
});
}
}
}
package org.example;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class EmbeddedMediaPlayer extends Application {
@Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 1586, 951);
List<MediaPlayer> mediaPlayerList = new ArrayList<>();
// create media player
for(String s : Main.MEDIA_URL){
MediaPlayer mediaPlayer = new MediaPlayer(new Media(s));
mediaPlayer.setAutoPlay(false);
mediaPlayerList.add(mediaPlayer);
}
MediaControl mediaControl = new MediaControl(mediaPlayerList, Main.VIDEO_ROWS);
scene.setRoot(mediaControl);
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void stop(){
System.exit(0);
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package org.example;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
EmbeddedMediaPlayer.main(args);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Not really a workaround, but it will make the bug reappear less often: start every seek in a new Thread.
FREQUENCY : often
I have 8 Mediaplayer playing at the same time. When I seek them at the same time > 50% of the time some videos hang. Sometimes (~30%) after a while they start playing again, but in slow-motion. onError is not called and getRate() = 1.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Play 8 Mediaplayer at the same time, hook them up to the same controls and seek a few times.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Player all seek to the same time.
ACTUAL -
Player hang without error message. Some will continue at some point in a very slow speed.
---------- BEGIN SOURCE ----------
package org.example;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Window;
import javafx.util.Duration;
import java.util.ArrayList;
import java.util.List;
public class MediaControlMinimal extends BorderPane {
private final List<MediaPlayer> mpList;
private Duration duration;
private boolean shouldPlay;
private int setupComplete;
private final Slider timeSlider;
private final HBox mediaBar;
private final Button playButton;
private final MediaPlayer controlMediaPlayer;
public MediaControlMinimal(List<MediaPlayer> mpList, int videoRows) {
this.mpList = mpList;
List<MediaView> mvList = new ArrayList<>(mpList.size());
Pane mvPane = new Pane() {
};
for (MediaPlayer mp : mpList) {
MediaView mediaView = new MediaView(mp);
mvList.add(mediaView);
mvPane.getChildren().add(mediaView);
}
mvPane.setStyle("-fx-background-color: black;");
setCenter(mvPane);
mediaBar = new HBox(); // 5 als param für spacing = 5, sieh zeile 247
mediaBar.setAlignment(Pos.CENTER);
mediaBar.setPadding(new Insets(5, 10, 5, 10));
BorderPane.setAlignment(mediaBar, Pos.CENTER);
playButton = new Button();
playButton.setOnAction(e -> {
shouldPlay = !shouldPlay;
if (shouldPlay) {
playAll();
} else {
pauseAll();
}
});
// Add time slider
timeSlider = new Slider();
HBox.setHgrow(timeSlider, Priority.ALWAYS);
timeSlider.setMinWidth(50);
timeSlider.setMaxWidth(Double.MAX_VALUE);
timeSlider.setOnMouseReleased(event -> {
//timeSlider.setValueChanging(true);
//timeSlider.setValue((event.getX() / timeSlider.getWidth()) * timeSlider.getMax());
//timeSlider.setValueChanging(false);
System.out.println("setOnMouseReleased");
final Duration seekTo = Duration.millis((event.getX() / timeSlider.getWidth()) * timeSlider.getMax());
for (MediaPlayer mp : mpList) {
new Thread(() -> {
mp.seek(seekTo);
}).start();
}
});
controlMediaPlayer = mpList.get(1);
controlMediaPlayer.currentTimeProperty().addListener((observable, oldVal, newVal) -> {
updateValues(controlMediaPlayer);
});
for (MediaPlayer mp : mpList) {
mp.setOnReady(() -> {
int videosPerRow = mpList.size() / videoRows;
if (setupComplete == 0) {
duration = mp.getMedia().getDuration();
timeSlider.setMax(duration.toMillis());
updateValues(mp);
final Window window = mvPane.getScene().getWindow();
final double titleHeight = window.getHeight() - mvPane.getScene().getHeight();
double windowHeight = videoRows * mp.getMedia().getHeight() + titleHeight;
if (!Main.isTransDesign) {
windowHeight += mediaBar.getHeight();
}
window.setHeight(windowHeight);
window.setWidth(videosPerRow * mp.getMedia().getWidth());
}
if (setupComplete < mpList.size()) {
final Node mpNode = mvPane.getChildren().get(mpList.indexOf(mp));
if (mpList.indexOf(mp) != 0 && mpNode.getLayoutX() == 0 && mpNode.getLayoutY() == 0) {
//fenster höhe
double xRelocate = mp.getMedia().getWidth() * (mpList.indexOf(mp) % videosPerRow);
double yRelocate = mp.getMedia().getHeight() * Math.floorDiv(mpList.indexOf(mp), videosPerRow);
mpNode.relocate(xRelocate, yRelocate);
}
++setupComplete;
}
});
mp.setCycleCount(MediaPlayer.INDEFINITE);
}
mediaBar.getChildren().add(playButton);
mediaBar.getChildren().add(timeSlider);
setBottom(mediaBar);
}
private void playAll() {
for (MediaPlayer mp : mpList) {
mp.play();
}
}
private void pauseAll() {
for (MediaPlayer mp : mpList) {
mp.pause();
}
}
protected void updateValues(MediaPlayer mp) {
if (timeSlider != null) {
Platform.runLater(() -> {
Duration currentTime = mp.getCurrentTime();
timeSlider.setDisable(duration.isUnknown());
if (!timeSlider.isDisabled() && duration.greaterThan(Duration.ZERO) && !timeSlider.isValueChanging()) {
timeSlider.setValue(currentTime.toMillis());
}
});
}
}
}
package org.example;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
public class EmbeddedMediaPlayer extends Application {
@Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 1586, 951);
List<MediaPlayer> mediaPlayerList = new ArrayList<>();
// create media player
for(String s : Main.MEDIA_URL){
MediaPlayer mediaPlayer = new MediaPlayer(new Media(s));
mediaPlayer.setAutoPlay(false);
mediaPlayerList.add(mediaPlayer);
}
MediaControl mediaControl = new MediaControl(mediaPlayerList, Main.VIDEO_ROWS);
scene.setRoot(mediaControl);
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void stop(){
System.exit(0);
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package org.example;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
EmbeddedMediaPlayer.main(args);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Not really a workaround, but it will make the bug reappear less often: start every seek in a new Thread.
FREQUENCY : often