【问题标题】:How to play fragments of mp3 with JavaFX?如何使用 JavaFX 播放 mp3 片段?
【发布时间】:2013-12-07 12:51:57
【问题描述】:

我想开发一个以特定方式播放 mp3 文件的 Java 程序。我用 startTime 和 endTime 标记了这个文件中的一些片段。程序应该播放第一个片段,然后休眠 5 秒。然后播放第二个片段并再次睡眠。等等。我使用 JavaFX 类 MediaPlayer。程序原型如下:

import javafx.application.Application;
import javafx.stage.Stage;
import java.io.FileNotFoundException;
import java.io.IOException;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.util.concurrent.TimeUnit;

public class JavaFXMediaPlayer02 extends Application {
    @Override
    public void start(Stage stage) throws FileNotFoundException,IOException,InterruptedException {
        Media media = new Media("file:///D:/1016_00.mp3");
        MediaPlayer mediaPlayer = new MediaPlayer(media);
//Set and play the first fragment of mp3-file
        mediaPlayer.setStartTime(Duration.millis(1219.0));
        mediaPlayer.setStopTime(Duration.millis(2728.0));
        mediaPlayer.play();
        System.out.println("1st fragment played!");
        TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
        mediaPlayer.setStartTime(Duration.millis(3947.0));
        mediaPlayer.setStopTime(Duration.millis(6629.0));
        mediaPlayer.play();
        System.out.println("2nd fragment played!");
        TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
        mediaPlayer.setStartTime(Duration.millis(7453.0));
        mediaPlayer.setStopTime(Duration.millis(10704.0));
        mediaPlayer.play();
        System.out.println("3rd fragment played!");
    }
    public static void main(String[] args) {
        launch(args);
    }
}

但我只听到第三个片段。怎么了?为什么我听不到第一个和第二个片段?如何更正我的程序? JavaFX 不是适合我的任务的工具吗?

【问题讨论】:

    标签: javafx-2


    【解决方案1】:

    这里的问题在于TimeUnit.SECONDS.sleep(5); 调用。此方法将当前线程设置为睡眠状态。在您的情况下,该线程是 JavaFX 应用程序线程。这会导致整个应用程序“冻结”(如果添加一些 GUI 元素会更明显),因此会执行 mediaPlayer.play(); 命令,但由于睡眠功能而立即“冻结”。在`TimeUnit.SECONDS.sleep(5); 调用之后,您为MediaPlayer 设置新的开始和结束时间并再次执行play(),以便轨道在新的开始时间开始。这就是为什么只播放最后一个片段的原因。

    现在解决方案: 您永远不应在 JavaFX 应用程序线程上调用 Thread.sleep() 或类似方法。但是在您的情况下,您必须在播放片段之间等待一定的时间。第一种方法是在新线程上调用Thread.sleep()TimeUnit.SECONDS.sleep(5);,并在JFX 应用线程上调用Mediaplayer 方法。但这不能正常工作,因为您没有设置调用线程的“顺序”。有多种方法可以做到这一点(通过SemaphoresLocks and ConditionsJavaFX Concurrency 等等......)

    我试图通过一些快速而肮脏的编程来解决您的问题,但我遇到了mediaPlayer.setStopTime(Duration.millis()); 的问题。它似乎不适用于我的计算机,因此文件总是播放到最后。我添加了一个停止按钮来模拟自动停止。 下面的类设置新的开始和端点并播放片段。如果媒体播放器停止,它会调用 LittleMediaScheduler 类的下一个片段。

    public class LittleMediaHelper implements Runnable {
    
    public double startTime;
    public double endTime;
    public MediaPlayer player;
    public int id;
    public LittleMediaScheduler scheduler;
    
    public LittleMediaHelper(double startTime, double endTime,
            MediaPlayer player, int id) {
        this.startTime = startTime;
        this.endTime = endTime;
        this.player = player;
        this.id = id;
    }
    
    public LittleMediaScheduler getScheduler() {
        return scheduler;
    }
    
    public void setScheduler(LittleMediaScheduler scheduler) {
        this.scheduler = scheduler;
    }
    
    @Override
    public void run() {
    
        Platform.runLater(new Runnable() {
    
            @Override
            public void run() {
    
                player.setStartTime(Duration.millis(startTime));
                player.setStopTime(Duration.millis(endTime));
    
                System.out.println(player.getStartTime());
                System.out.println(player.getStopTime());
                player.play();
                player.setOnStopped(new Runnable() {
    
                    @Override
                    public void run() {
    
                        int idtmp = id + 1;
                        System.out.println("NEXT " + idtmp);
    
                        scheduler.call(idtmp);
    
                    }
                });
    
            }
        });
    
    }
    
    }
    

    这个类负责在新线程上休眠一定量,并在成功休眠后调用下一个 LittleMediaHelper 类播放功能。

    public class LittleMediaScheduler {
    private ArrayList<LittleMediaHelper> hArrL;
    private int SLEEPTIME = 2000;
    
    public LittleMediaScheduler(LittleMediaHelper... helpers) {
        this.hArrL = new ArrayList<>();
        for (LittleMediaHelper h : helpers) {
            h.setScheduler(this);
            System.out.println(h.startTime);
            this.hArrL.add(h);
        }
    
        System.out.println(hArrL.size());
    
    }
    
    public void init() {
        Thread t = new Thread(this.hArrL.get(0));
        t.start();
    }
    
    public void call(final int id) {
        Thread t = new Thread(new Task<String>() {
    
            @Override
            protected String call() throws Exception {
                Thread.sleep(SLEEPTIME);
                return null;
            }
    
            @Override
            protected void succeeded() {
                super.succeeded();
                System.out.println("Next playing...");
                if (id > LittleMediaScheduler.this.hArrL.size() - 1) {
                    return;
                }
                LittleMediaHelper next = LittleMediaScheduler.this.hArrL
                        .get(id);
                Thread nextT = new Thread(next);
                nextT.start();
            }
        });
        t.start();
    }
    
    }
    

    带有停止按钮的主类。如果没有mediaPlayer.pause(),玩家会以某种方式重复一步两次,尽管设置了新的开始结束端点。不知道是不是bug。

    public class JavaFXMediaPlayer02 extends Application {
    @Override
    public void start(Stage stage) throws FileNotFoundException, IOException,
            InterruptedException {
        Media media = new Media("file:///C:/test.mp3");
        final MediaPlayer mediaPlayer = new MediaPlayer(media);
    
        LittleMediaHelper phase1 = new LittleMediaHelper(0, 1000, mediaPlayer,
                0);
        LittleMediaHelper phase2 = new LittleMediaHelper(50000, 55000,
                mediaPlayer, 1);
        LittleMediaHelper phase3 = new LittleMediaHelper(200000, 200500,
                mediaPlayer, 2);
        LittleMediaScheduler scheduler = new LittleMediaScheduler(phase1,
                phase2, phase3);
    
        scheduler.init();
    
        Group g = new Group();
        Button b = new Button("STOP");
        b.setOnAction(new EventHandler<ActionEvent>() {
    
            @Override
            public void handle(ActionEvent arg0) {
                mediaPlayer.pause();
                mediaPlayer.stop();
            }
        });
    
        g.getChildren().add(b);
        Scene sc = new Scene(g);
        stage.setScene(sc);
        stage.show();
    
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多