1
votes

La vidéo JavaFX bégaie après avoir lu la même vidéo encore et encore pendant quelques heures

Sur Ubuntu 18.04, j'ai une application JavaFX 13 qui lit la même vidéo encore et encore en utilisant javafx.scene.media.MediaPlayer et javafx.scene.media.MediaView. À chaque itération, il charge le MediaPlayer avec le même média via l'URL, puis le lit. Au début, la vidéo est lue en douceur, mais après environ une heure, elle commence à bégayer dans ma machine avec 8 Go de RAM et ne se produit pas (au moins dans quelques heures) dans ma machine avec 32 Go de RAM.

Étant donné que sa lecture est fluide au départ, je Je suppose que ce n'est pas un problème de codec. Comme ça empire avec le temps, je suppose que c'est une fuite de mémoire quelque part. Surveiller ma JVM à l'aide de visualvm, cela ne semble pas être une fuite de mémoire ou de thread dans mon application.

Vous trouverez ci-dessous une version allégée de mon application dans un seul fichier de classe Java. Tous les conseils seraient grandement appréciés.

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");
                }
            }
        }
    }
}


0 commentaires

3 Réponses :


0
votes

Cela semble être un problème de cycelingprocess et d'allocation de la mémoire du Mediaplayer. J'ai eu un problème similaire, malheureusement je ne sais pas pourquoi cela se produit, mais j'ai une solution de contournement, pour imiter un cycle.

Ma solution de contournement est la suivante:

    public void startPlayer(){
        mediaPlayer = new MediaPlayer(media);
        mediaView.setMediaPlayer(mediaPlayer);
        mediaPlayer.play();

        mediaPlayer.setOnEndOfMedia(()->{
                    //frees all the allocated Memory
                    mediaPlayer.dispose();
                    mediaView.setMediaPlayer(null);
                    startPlayer();
                });
    }

Cela créera un nouveau joueur à chaque fois que le cycle sera terminé.

Je ne sais pas si cela fonctionnera pour vous dans l'aspect de la fluidité du "cycle vidéo". Mais vous pouvez essayer. Peut-être que vous pouvez le faire tous les 10 cycles vidéo environ, pour obtenir de la fluidité.


2 commentaires

Ma méthode resetMediaPlayer () tente de faire la même chose au début de chaque cycle. Sauf erreur de ma part, la seule différence que je vois est que vous appelez mediaView.setMediaPlayer (null); . J'essaierai ce changement et si cela fonctionne, j'accepterai votre réponse. Merci beaucoup.


J'ai essayé le changement que vous avez gentiment suggéré mais malheureusement cela n'a fait aucune différence pour mon application. Merci beaucoup pour l'aide.



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

1 commentaires

Merci, mais votre réponse est essentiellement la même que la réponse précédente. Ma méthode resetMediaPlayer () tente de faire la même chose au début de chaque cycle et le bégaiement est toujours là. J'ai même essayé de le faire exactement comme vous l'aviez suggéré et le bégaiement est toujours là. Je pense qu'il peut y avoir un bogue dans gstreamer de javafx MediaView. Je vais déposer un bug peu de temps après la mise à jour de mon programme de test.



0
votes

J'ai essayé d'exécuter mon application avec gstreamer 1.16.2. Puisqu'aucun backport n'était disponible pour Ubuntu 18.04, j'ai exécuté mon application dans une VM avec Ubuntu 20 (dernière nuit) qui a gstreamer 1.16.2-2. La VM a 4 Go de RAM et 1 processeur. Ce sont moins de ressources que ma machine de test d'origine.

Avec gstreamer 1.16.2-2 dans Ubuntu 20, je ne vois pas de bégaiement après avoir exécuté mon test pendant 1,25 heure. Pour moi, cela confirme que le problème est dans gstream 1.14 et corrigé dans gstreamer 1.16. Merci à tous ceux qui ont essayé de vous aider.

MISE À JOUR: Ci-dessus était basé sur des tests dans une VM Ubuntu 20.04. J'ai ensuite mis à niveau ma machine de test physique vers Ubuntu 20.04.

À ma grande surprise, le bégaiement vidéo est apparu immédiatement dans mon application (sans même attendre 30 minutes comme avant). En lisant là-dessus, j'ai trouvé que certaines extensions de shell gnome peuvent provoquer un saccade vidéo. J'ai donc supprimé l'extension de shell gnome suivante:

# See what gnome shell extensions are installed
apt list --installed | grep -i extension

# Remove gnome shell extensions found
sudo apt-get remove gnome-shell-extension-appindicator gnome-shell-extension-desktop-icons gnome-shell-extension-ubuntu-dock

Après cela, j'ai redémarré mon application et le bégaiement de la vidéo a disparu. J'ai ensuite attendu 30 minutes pour voir si le bégaiement apparaissait comme avant. Le bégaiement est malheureusement perceptible. J'ai annulé cette réponse comme réponse acceptée.


0 commentaires