问题
I have a programm with 8 mediaplayer, which are controlled like one big video with a single set of controls.
I have one Slider to control the time, aka I call all MediaPlayer's seek
methods in onMouseReleased
of the slider. My Problem is, the mediaplayer hang all the time, without changing their status or calling onError
. When I put every seek
in a new Thread, these problems disappear msot of the time, but not always and I'm gettign a lot of concurrency issues.
Does anybody know the reason why the player hangs?
EDIT: Ok, here a minimal reproducible example:
Class MediaControlMinimal:
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 -> {
for (MediaPlayer mp : mpList) {
mp.seek(Duration.millis((event.getX() / timeSlider.getWidth()) * timeSlider.getMax());
}
});
controlMediaPlayer = mpList.get(1);
controlMediaPlayer.currentTimeProperty().addListener(observable -> {
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());
}
});
}
}
}
Class EmbeddedMediaPlayer
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) {
primaryStage.setTitle(Main.WINDOW_TITLE);
Group root = new Group();
Scene scene = new Scene(root, 1586, 900);
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);
}
MediaControlMinimal mediaControl = new MediaControlMinimal(mediaPlayerList, Main.VIDEO_ROWS);
scene.setRoot(mediaControl);
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void stop(){
System.out.println("Stage is closing");
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);
}
}
Class Main
package org.example;
public class Main {
public static final String[] MEDIA_URL = {
"https://video.fogodosamba.de/media/SambaReggae_Sticks.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Fundo1.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Dobra.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Fundo2.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Ansage.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Timbal.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Caixa.mp4",
"https://video.fogodosamba.de/media/SambaReggae_Repi.mp4"
};
public static final int VIDEO_ROWS = 2;
public static final String WINDOW_TITLE = "";
public static void main(String[] args) {
EmbeddedMediaPlayer.main(args);
}
}
EDIT 2:
Sometimes a video hsngs for a while, then starts up again, but plays in slow motion. No error message in onerror
, no state change and getCurrentRate
= 1.
来源:https://stackoverflow.com/questions/65064419/javafx-mediaplayers-seek-method-hangs-the-player-without-error-message-oder-st