Skip to main content
 首页 » 编程设计

javafx-2中如何使用JavaFX播放mp3片段

2024年11月01日8落叶无声

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

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 不是适合我的任务的工具吗?

请您参考如下方法:

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

现在解决方案: 您永远不应该在 JavaFX 应用程序线程上调用 Thread.sleep() 或类似方法。但就您而言,您必须在播放片段之间等待一定的时间。第一种方法是在新线程上调用 Thread.sleep() 或 TimeUnit.SECONDS.sleep(5); 并调用 Mediaplayer JFX 应用程序线程上的方法。但这无法正常工作,因为您尚未设置调用线程的“顺序”。有多种方法可以做到这一点(通过 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() ,尽管设置了新的开始结束端点,播放器仍会以某种方式重复一个步骤两次。不知道这是否是一个错误。

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