java - 一遍又一遍地播放相同的视频几个小时后,JavaFX 视频卡顿
问题描述
在 Ubuntu 18.04 上,我有一个 JavaFX 13 应用程序,它使用 javafx.scene.media.MediaPlayer 和 javafx.scene.media.MediaView 一遍又一遍地播放相同的视频。在每次迭代中,它通过 url 加载具有相同媒体的 MediaPlayer,然后播放它。起初,视频播放流畅,但大约一个小时后,它在我的 8GB RAM 机器中开始出现卡顿,并且在我的 32GB RAM 机器中没有发生(至少在几个小时内)。
由于它最初播放流畅,我猜它不是编解码器问题。由于它随着时间的推移变得更糟,我猜它是某个地方的内存泄漏。使用 visualvm 监视我的 JVM 它似乎不是我的应用程序中的内存或线程泄漏。
下面是我的应用程序在单个 java 类文件中的精简版本。任何提示将非常感谢。
package javafxtest;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
public class JavaFxVideoTestApp extends Application {
private static final Logger LOGGER = LoggerFactory.getLogger(JavaFxVideoTestApp.class);
MediaPlayer mediaPlayer;
MediaView mediaView;
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(JavaFxVideoTestApp::showError);
BorderPane borderPane = new BorderPane();
Scene scene = new Scene(borderPane);
primaryStage.setScene(scene);
mediaView = new MediaView();
borderPane.setCenter(mediaView);
primaryStage.setFullScreen(true);
primaryStage.show();
loadEvent();
}
private static void showError(Thread thread, Throwable throwable) {
LOGGER.error("Unhandled error. Thread: {}", thread.getName(), throwable);
}
public void loadEvent() throws MalformedURLException, URISyntaxException {
String videoFileURI = (new URL("https://dl.dropboxusercontent.com/s/b8lyrt5r61oxxnc/job-chasing-his-illusive-dreams-dec-2017.mp4")).toURI().toString();
// Create a new MediaPlayer
resetMediaPlayer("loadEvent");
Media media = new Media(videoFileURI);
LOGGER.debug("LoadEvent new video loaded : {}", media.getSource());
mediaPlayer = new MediaPlayer(media);
mediaPlayer.setStartTime(Duration.ZERO);
mediaPlayer.errorProperty().addListener((observable, oldValue, newValue) ->
LOGGER.error(String.format("MediaPlayer error. videoFileURI: %s error: '%s'", videoFileURI, newValue)));
mediaPlayer.statusProperty().addListener((observable, oldValue, newValue) -> {
if (newValue == MediaPlayer.Status.READY) {
LOGGER.info("MediaPlayer status: Ready");
showEvent();
}
});
mediaPlayer.setCycleCount(1);
mediaPlayer.setMute(true);
mediaPlayer.setOnEndOfMedia(() -> {
try {
loadEvent();
} catch (MalformedURLException|URISyntaxException e) {
LOGGER.error("Error loading event", e);
}
});
mediaView.setMediaPlayer(mediaPlayer);
}
public void showEvent() {
if (mediaPlayer != null) {
MediaPlayer.Status status = mediaPlayer.getStatus();
if (status == MediaPlayer.Status.READY || status == MediaPlayer.Status.STOPPED) {
mediaPlayer.setStartTime(Duration.ZERO);
mediaPlayer.setStopTime(mediaPlayer.getMedia().getDuration());
mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
mediaPlayer.play();
}
} else {
LOGGER.error("showEvent video mediaplayer NULL");
}
}
private void resetMediaPlayer(String caller) {
if (mediaPlayer != null) {
LOGGER.debug("resetMediaPlayer stop. caller: {}", caller);
if ((mediaPlayer.getStatus() != MediaPlayer.Status.UNKNOWN) && (mediaPlayer.getStatus() != MediaPlayer.Status.DISPOSED)) {
try {
mediaPlayer.stop();
mediaPlayer.dispose();
mediaPlayer = null;
} catch (Exception e) {
LOGGER.error("Error while stopping and disposing media player");
}
}
}
}
}
解决方案
mediaPlayer.setOnEndOfMedia(() -> {
try {
mediaPlayer.stop();
mediaPlayer.dispose();
mediaPlayer = null;
loadEvent(); ...
推荐阅读
- python - Python中gRPC协议数据序列化和反序列化的标准方法
- jquery - 如何更改 vega 图表中的条形宽度(谷歌图表)
- firebase - 添加 Firebase 身份验证依赖项后,应用程序在启动时崩溃
- prefetch - 一旦获得许可,是否可以在 fastq 中转换 sra 文件?
- r - 将长整数转换为r中的日期和时间
- c++ - gcc 4.6.1 版与 protobuf 兼容吗?
- autodesk-forge - 删除所有模型派生属性?
- laravel - 在 Laravel 中找不到观察者
- blockchain - Hyperledger Besu 是否与 Cosmos IBC 兼容?
- networking - 如何在 SONiC OS 中找到内存缓冲区大小限制?