javafx MediaPlayer 的搜索方法无法正确搜索 1.5 小时以上的长音频文件

Seek method for javafx MediaPlayer does not seek correctly for 1.5 hr+ long audio files

我最近修复了一个错误,每当我断开蓝牙耳机时,javafx MediaPlayer 就会中断。我通过这样做解决了这个问题。

    mediaPlayer.setOnError( () -> {
            mediaPlayer = new MediaPlayer(media);
            System.out.println(durationBackup.toMillis());
            mediaPlayer.setOnPlaying(() ->{
                mediaPlayer.seek(durationBackup);
                mediaPlayer.setOnPlaying(null);
            });
            mediaPlayer.play();
    });

durationBackup 只是 MediaPlayer 崩溃前持续时间的备份。上面的代码适用于一个短的 5 分钟长的 mp3 文件,新创建的 MediaPlayer 将正确地寻找 durationBackup。然而,我随后决定用一个 1.5 小时长的 mp3 文件测试这段代码,在测试时,新创建的 MediaPlayer 无法找到 durationBackup。相反,创建的 MediaPlayer 对象从头开始播放,而不是所需的 durationBackup。

经过进一步测试,seek 方法似乎失败了,因为当我尝试从 1.5 小时长的 mp3 文件开始寻找 7 秒时,MediaPlayer 反而从头开始播放。当我使用 seek 方法从 5 分钟长的文件开始寻找 7 秒时,MediaPlayer 从开始播放 7 秒开始播放。我怀疑这与 mp3 文件的大小有关,但我似乎找不到解决办法。 seek(Duration.seconds(7)) 不仅不能处理 1.5 小时长的 mp3 文件,setStartTime(Duration.seconds(7)) 也不能处理 1.5 小时长的 mp3 文件。

如果有人能帮我解决这个问题那就太好了。下面是一个可重现的迷你示例。

SevenSecondSeekClass

package apprunner;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;

public class SevenSecondSeekClass extends Application {

    MediaPlayer mediaPlayer;

    public static void main(String[] args) throws MalformedURLException, IOException {
        launch(args);

    }

    public InvalidationListener il = new InvalidationListener() {
        public void invalidated(Observable ov) {
            //Here we just print the current time of the song
            System.out.println(mediaPlayer.getCurrentTime().toSeconds() + " seconds");
        }
    };

    @Override
    public void start(Stage stage) throws Exception {
        stage.setTitle("My");
        Button button0 = new Button("Play 7 seconds from start of 5min Song");
        Button button1 = new Button("Play 7 seconds from start of 1hr Song");
        StackPane layout = new StackPane(new VBox(button0, button1));
        Scene scene = new Scene(layout, 200, 100);
        stage.setScene(scene);
        stage.setWidth(400);
        stage.show();
        File file0 = new File("C:\Users\John Doe\OneDrive\Desktop\YourLieInAprilTest\5minsong.mp3");
        String path0 = file0.toURI().toASCIIString();
        Media media0 = new Media(path0);
        mediaPlayer = new MediaPlayer(media0);
        button0.setOnAction(new EventHandler() {
            @Override
            public void handle(Event arg0) {
                createNewPlayer(media0);
            }
        });

        File file1 = new File("C:\Users\John Doe\downloadedMusic\1andHalfHourSong.mp3");
        String path1 = file1.toURI().toASCIIString();
        Media media1 = new Media(path1);
        mediaPlayer = new MediaPlayer(media1);
        button1.setOnAction(new EventHandler() {
            @Override
            public void handle(Event arg0) {
                createNewPlayer(media1);
            }
        });
    }

    public void createNewPlayer(Media media) {
        mediaPlayer.stop();
        mediaPlayer.currentTimeProperty().removeListener(il);
        mediaPlayer = new MediaPlayer(media);
        mediaPlayer.setOnPlaying(() -> {
            mediaPlayer.seek(Duration.seconds(7));
            System.out.println("Trying to seek to 7 seconds from start of song");
            mediaPlayer.setOnPlaying(null);
        });
        mediaPlayer.currentTimeProperty().addListener(il);//This will help us print the current time of the song
        mediaPlayer.play();
    }
}

如果您想知道为什么我在 MediaPlayer 的开头使用 .seek 而不是仅使用 .setStartTime(),那是因为 .setStartTime() 会更改 .getTotalDuration 的值并且不允许转到小于开始时间设置的持续时间。我需要这些方面在我的程序中可用,以保持可用 UI。 .setStartTime() 也不适用于 1.5 小时长的 mp3 文件。

附加信息

Link to the 5 minute long Mp3 file I used to test. https://drive.google.com/file/d/1CvAafbMviQ7nvKyojnem9GK73LJsD6MJ/view?usp=sharing

Link to the 1.5 hour long mp3 file I used to test. https://drive.google.com/file/d/1KggQct1VnY18m0_4Wik5pfP4RN8-HbUT/view?usp=sharing

I am using JDK 11 and Javafx 17.0.2

System Type: 64-bit operating system, x64-based processor

JRE version: OpenJDK Runtime Environment (11.0.4+11) (build 11.0.4+11)

Java VM: OpenJDK 64-Bit Server VM (11.0.4+11, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)

Windows Edition: Windows 10 Home

我发现我可以通过将我的 mp3 文件转换为 m4a 文件来解决我的问题。 m4a 文件不再出现搜索问题。