Search code examples
javajavafxmedia-player

How to stop current thread while MediaPlayer is playing video?


Im writing program on JavaFX,which must show window,play video on it,hide window after playing and again after random time repeat this actions.I need to know how to make random delay when media player complete playing current video.My thoughts was these - if by adding scene.hide() after player.play() ,window was hiden before playback completion , follows that player works in another thread.But if i add delay via TimeUnit.SECONDS.sleep(10) after command player.play() , video playing wil started after 10s.Please explain, what occur in fact, and how to add delay after playing completion.

My code:

import java.io.File;
import java.lang.management.ManagementFactory;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.input.KeyCombination;
import java.util.concurrent.TimeUnit;
public class Main extends Application implements Runnable {
     private String Dir = System.getProperty("./");
     private Stage stage;
     private boolean fl;
     public static void main(String[] args) throws Exception{
               launch(args);
     }
     
     public void run() { //if playing is complete - hide window
         
         //System.out.printf("Media player thread is %d \n",Thread.currentThread().getId());
         this.stage.hide();
     }
     private static int randomIntBetween(int first, int last) {
         int rnd_int= (int)(first + Math.round(Math.random()*Math.abs((last-first))));
         return rnd_int;
     }
     @Override
     public void start(Stage stage) throws Exception {
         this.stage=stage;
         String[]  video_paths = {"lp.mp4","sc_1.mp4"};
         stage.setFullScreen(true);
         stage.setFullScreenExitHint("");
         stage.setFullScreenExitKeyCombination(javafx.scene.input.KeyCombination.NO_MATCH);
         while (true){
         String video_path = video_paths[randomIntBetween(0,video_paths.length-1)];//Get random video (path)
         File f = new File(video_path);
         
         Media media = new Media(f.toURI().toURL().toString());
         javafx.scene.media.MediaPlayer player = new   javafx.scene.media.MediaPlayer(media);
         MediaView viewer = new MediaView(player);
        
        //change width and height to fit video
        DoubleProperty width = viewer.fitWidthProperty();
        DoubleProperty height = viewer.fitHeightProperty();
        width.bind(Bindings.selectDouble(viewer.sceneProperty(), "width"));
        height.bind(Bindings.selectDouble(viewer.sceneProperty(), "height"));
        viewer.setPreserveRatio(true);
    
        StackPane root = new StackPane();
        root.getChildren().add(viewer);
        
        //set the Scene
        Scene scenes = new Scene(root);
        stage.setScene(scenes);
        player.setOnEndOfMedia(this);
        //System.out.printf("Main thread is %d \n",Thread.currentThread().getId());
        stage.show();
        player.play();
        //this.stage.hide();
        //TimeUnit.SECONDS.sleep(randomIntBetween(3,100); 
        break;//added for single iteration
       
    
         }
 
  }
}

My code working if i add break after player.play().But it is no solution of my problem.


Solution

  • Unfortunately, your approach is all wrong. There are major mistakes and misconceptions in your approach and some smaller improvements that could be made in your code.

    Major problems:

    1. You don't need to (and should not) create another thread to pause, use a PauseTransition.
    2. You should never sleep the JavaFX thread.
    3. You should never modify the properties of nodes in the Scene Graph or Stages from any thread other than the JavaFX thread.
    4. GUIs are event-driven, so respond to and generate events (e.g. PauseTransition.onFinished) rather than code loops.
    5. Never loop forever on the JavaFX thread - nothing will happen in the GUI.

    Other improvements:

    1. An application should only be responsible for the application lifecycle.
    2. An application should not implement runnable.
    3. To get the working directory, use the system property "user.dir".
    4. Don't write a function to get random ints in ranges use the built-in library function for that.
    5. Follow naming conventions always.
    6. Setting a no-match key and no hint for full-screen exit seems like a bad idea for most apps.
    7. Don't define variables like the misnamed Dir, which you never use.
    8. Code should be properly formatted.
    9. Bind to properties instead of the weird Bindings selection scheme you use, e.g. you could write viewer.fitWidthProperty().bind(scene.widthProperty()).
    10. But also, don't use binding for layout, use layout panes with minimal appropriate layout hints.
    11. Don't use fully qualified names in code unnecessarily, instead add the appropriate import statements.

    Related: