首页 > 解决方案 > 一遍又一遍地播放相同的视频几个小时后,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");
                }
            }
        }
    }
}

标签: javajavafxgstreamer

解决方案


mediaPlayer.setOnEndOfMedia(() -> {
            try {
                mediaPlayer.stop();
                mediaPlayer.dispose();
                mediaPlayer = null;
                loadEvent(); ...

推荐阅读